1 /***************************************************************************
2 editgraphobj.cpp - An editable graphics object
3 -------------------
4 begin : wo apr 16 2003
5 copyright : (C) 2003 by CJP
6 email : cornware-cjp@users.sourceforge.net
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include <GL/gl.h>
19 #include <cstdio> //for sscanf
20 #include <cmath> //for fabs
21
22 #include "load3ds.h"
23 #include "loadglt.h"
24 #include "loadlwo.h"
25 #include "loadobj.h"
26 #include "loadraw.h"
27 #include "glbfile.h"
28
29 #include "editgraphobj.h"
30 #include "datafile.h"
31
CEditGraphObj()32 CEditGraphObj::CEditGraphObj()
33 {
34 m_ObjList = m_ObjListRef = 0;
35 isRendered = false;
36 }
37
~CEditGraphObj()38 CEditGraphObj::~CEditGraphObj()
39 {
40 if(isRendered)
41 {
42 glDeleteLists(m_ObjList, 1);
43 glDeleteLists(m_ObjListRef, 1);
44 }
45 }
46
loadGLBFile(CString filename)47 bool CEditGraphObj::loadGLBFile(CString filename)
48 {
49 CGLBFile f;
50 if(!f.load(filename)) return false;
51
52 clear();
53 for(unsigned int p=0; p < f.m_Primitives.size(); p++)
54 {
55 m_Primitives.push_back(CPrimitive());
56 CPrimitive &pr2 = m_Primitives.back();
57 CGLBFile::SPrimitive &pr1 = f.m_Primitives[p];
58
59 pr2.m_Name = pr1.Name;
60 pr2.m_Type = CPrimitive::VertexArray;
61
62 pr2.m_Material.LODs = "";
63 if(pr1.material.LODs & 1) pr2.m_Material.LODs += '1';
64 if(pr1.material.LODs & 2) pr2.m_Material.LODs += '2';
65 if(pr1.material.LODs & 4) pr2.m_Material.LODs += '3';
66 if(pr1.material.LODs & 8) pr2.m_Material.LODs += '4';
67 if(pr1.material.LODs & 16) pr2.m_Material.LODs += 'c';
68 if(pr1.material.LODs & 32) pr2.m_Material.LODs += 's';
69 pr2.m_Material.texture = pr1.material.Texture;
70 pr2.m_Material.modulationColor = pr1.material.ModulationColor;
71 pr2.m_Material.replacementColor = pr1.material.ReplacementColor;
72 pr2.m_Material.opacity = pr1.material.Opacity;
73 pr2.m_Material.reflectance = pr1.material.Reflectance;
74 pr2.m_Material.emissivity = pr1.material.Emissivity;
75
76 pr2.m_Animation.rotationEnabled = (pr1.animation.AnimationFlags & 0x1) != 0;
77 pr2.m_Animation.rotationOrigin = pr1.animation.rotationOrigin;
78 pr2.m_Animation.rotationVelocity = pr1.animation.rotationVelocity;
79
80 for(unsigned int v=0; v < pr1.vertex.size(); v++)
81 {
82 CVertex vt2;
83 CGLBFile::SVertex &vt1 = pr1.vertex[v];
84
85 vt2.pos = vt1.pos;
86 vt2.nor = vt1.nor;
87 vt2.tex = vt1.tex;
88
89 pr2.m_Vertex.push_back(vt2);
90 }
91
92 pr2.m_Index = pr1.index;
93 }
94
95 return true;
96 }
97
loadGLTFile(CString filename)98 bool CEditGraphObj::loadGLTFile(CString filename)
99 {
100 return loadGLT(filename, *this);
101 }
102
loadRAWFile(CString filename)103 bool CEditGraphObj::loadRAWFile(CString filename)
104 {
105 return loadRAW(filename, *this);
106 }
107
load3DSFile(CString filename)108 bool CEditGraphObj::load3DSFile(CString filename)
109 {
110 return load3DS(filename, *this);
111 }
112
loadLWOFile(CString filename)113 bool CEditGraphObj::loadLWOFile(CString filename)
114 {
115 return loadLWO(filename, *this);
116 }
117
loadOBJFile(CString filename)118 bool CEditGraphObj::loadOBJFile(CString filename)
119 {
120 return loadOBJ(filename, *this);
121 }
122
merge(const CEditGraphObj & obj,const CString & lods)123 void CEditGraphObj::merge(const CEditGraphObj &obj, const CString &lods)
124 {
125 //merge 2 objects
126 //if objects have equal names, then they are placed together
127 //and the new one gets the suffix of the LODS
128
129 //calculate CG position
130 CVector CG1, CG2;
131 unsigned int num1 = 0, num2 = 0;
132 for(unsigned int i=0; i < obj.m_Primitives.size(); i++)
133 for(unsigned int j=0; j < obj.m_Primitives[i].m_Vertex.size(); j++)
134 {
135 CG2 += obj.m_Primitives[i].m_Vertex[j].pos;
136 num2++;
137 }
138 CG2 /= num2;
139
140 for(unsigned int i=0; i < m_Primitives.size(); i++)
141 for(unsigned int j=0; j < m_Primitives[i].m_Vertex.size(); j++)
142 {
143 CG1 += m_Primitives[i].m_Vertex[j].pos;
144 num1++;
145 }
146 CG1 /= num1;
147
148 for(unsigned int i=0; i < obj.m_Primitives.size(); i++)
149 {
150 CPrimitive thePrimitive = obj.m_Primitives[i];
151
152 //Correct CG position
153 thePrimitive.m_Material.LODs = lods;
154 for(unsigned int j=0; j < thePrimitive.m_Vertex.size(); j++)
155 thePrimitive.m_Vertex[j].pos += CG1 - CG2;
156
157 int match = -1;
158 for(unsigned int j=0; j < m_Primitives.size(); j++)
159 if(m_Primitives[j].m_Name == thePrimitive.m_Name)
160 {match = j; break;}
161
162 if(match < 0) //no match: just add it to the end
163 {
164 m_Primitives.push_back(thePrimitive);
165 continue;
166 }
167
168 //there is a match
169 thePrimitive.m_Name = thePrimitive.m_Name + "_" + lods;
170
171 //set the color
172 for(unsigned int j=0; j < thePrimitive.m_Vertex.size(); j++)
173 {
174 thePrimitive.m_Vertex[j].col = m_Primitives[match].m_Vertex[0].col;
175 thePrimitive.m_Vertex[j].opacity = m_Primitives[match].m_Vertex[0].opacity;
176 thePrimitive.m_Vertex[j].reflectance = m_Primitives[match].m_Vertex[0].reflectance;
177 }
178
179 m_Primitives.insert(m_Primitives.begin() + match, thePrimitive);
180
181 }
182 }
183
clear()184 void CEditGraphObj::clear()
185 {
186 m_Primitives.clear();
187 }
188
saveGLTFile(const CString & filename)189 void CEditGraphObj::saveGLTFile(const CString &filename)
190 {
191 CDataFile f(filename, true);
192 f.writel("#CornWare UltimateStunts graphics file");
193 f.writel("#created by the stunts3dedit editor");
194 f.writel("");
195 f.writel("Lod 1234c");
196 f.writel("Normal 0,1,0");
197 f.writel("Color 1,1,1");
198 f.writel("Opacity 1");
199 f.writel("Reflectance 0");
200
201 //State variables:
202 CVertex state;
203 state.pos = CVector(0,0,0);
204 state.nor = CVector(0,1,0);
205 state.col = CVector(1,1,1);
206 state.opacity = 1.0;
207 state.reflectance = 0.0;
208 state.tex = CVector(0,0,0);
209 int texid = -1;
210 CString name = "default-name";
211 CString LODs = "1234c";
212
213 for(unsigned int i=0; i<m_Primitives.size(); i++)
214 {
215 CPrimitive &pr = m_Primitives[i];
216
217 f.writel(""); //two empty lines
218 f.writel("");
219 if(!(pr.m_Name == name))
220 {
221 name = pr.m_Name;
222 f.writel("#Tedit-name " + name);
223 }
224 if(!(pr.m_Material.LODs == LODs))
225 {
226 LODs = pr.m_Material.LODs;
227 f.writel("Lod " + LODs);
228
229 //rewrite the entire state (set the current state totally invalid)
230 //TODO: more efficient
231 texid = -2;
232 state.col = state.nor = state.tex = CVector(2,2,2);
233 state.opacity = state.reflectance = 2;
234 }
235 if(!(pr.m_Material.texture == texid))
236 {
237 texid = pr.m_Material.texture;
238 if(texid < 0)
239 f.writel("Notex");
240 else
241 f.writel(CString("Texture ") + texid);
242 }
243
244 f.writel("VertexArray");
245 f.writel(CString("Color ") + pr.m_Material.modulationColor);
246 f.writel(CString("Opacity ") + pr.m_Material.opacity);
247 f.writel(CString("ReplacementColor ") + pr.m_Material.replacementColor);
248 f.writel(CString("Reflectance ") + pr.m_Material.reflectance);
249 f.writel(CString("Emissivity ") + pr.m_Material.emissivity);
250
251 if(pr.m_Animation.rotationEnabled)
252 {
253 f.writel(CString("RotationAnimation ") +
254 pr.m_Animation.rotationOrigin + ";" +
255 pr.m_Animation.rotationVelocity);
256 }
257
258 for(unsigned int j=0; j<pr.m_Vertex.size(); j++)
259 {
260 CVertex &vt = pr.m_Vertex[j];
261
262 //normal
263 if((vt.nor-state.nor).abs2() > 0.0001)
264 {
265 f.writel(CString("Normal ")+vt.nor.x+", "+vt.nor.y+", "+vt.nor.z);
266 state.nor = vt.nor;
267 }
268
269 //texcoord
270 if((vt.tex-state.tex).abs2() > 0.000001)
271 {
272 f.writel(CString("TexCoord ")+vt.tex.x+", "+vt.tex.y);
273 state.tex = vt.tex;
274 }
275
276 //vertex
277 f.writel(CString("Vertex ")+vt.pos.x+", "+vt.pos.y+", "+vt.pos.z);
278 }
279 for(unsigned int j=0; j<pr.m_Index.size(); j++)
280 f.writel(CString("Index ") + pr.m_Index[j]);
281
282 f.writel("End");
283 }
284
285 }
286
saveGLBFile(const CString & filename)287 void CEditGraphObj::saveGLBFile(const CString &filename)
288 {
289 CGLBFile f;
290
291 for(unsigned int p=0; p < m_Primitives.size(); p++)
292 {
293 CPrimitive &pr1 = m_Primitives[p];
294 f.m_Primitives.push_back(CGLBFile::SPrimitive());
295 CGLBFile::SPrimitive &pr2 = f.m_Primitives.back();
296
297 pr2.Name = pr1.m_Name;
298
299 //Animation
300 pr2.animation.AnimationFlags = 0;
301 if(pr1.m_Animation.rotationEnabled) pr2.animation.AnimationFlags |= 0x1;
302 pr2.animation.rotationOrigin = pr1.m_Animation.rotationOrigin;
303 pr2.animation.rotationVelocity = pr1.m_Animation.rotationVelocity;
304
305 //Material
306 pr2.material.LODs = 0;
307 if(pr1.m_Material.LODs.inStr('1') >= 0) pr2.material.LODs += 1;
308 if(pr1.m_Material.LODs.inStr('2') >= 0) pr2.material.LODs += 2;
309 if(pr1.m_Material.LODs.inStr('3') >= 0) pr2.material.LODs += 4;
310 if(pr1.m_Material.LODs.inStr('4') >= 0) pr2.material.LODs += 8;
311 if(pr1.m_Material.LODs.inStr('c') >= 0) pr2.material.LODs += 16;
312 if(pr1.m_Material.LODs.inStr('s') >= 0) pr2.material.LODs += 32;
313 pr2.material.Emissivity = pr1.m_Material.emissivity;
314 pr2.material.ModulationColor = pr1.m_Material.modulationColor;
315 pr2.material.Opacity = pr1.m_Material.opacity;
316 pr2.material.Reflectance = pr1.m_Material.reflectance;
317 pr2.material.ReplacementColor = pr1.m_Material.replacementColor;
318 pr2.material.Texture = pr1.m_Material.texture;
319
320 //Vertices
321 for(unsigned int v=0; v < pr1.m_Vertex.size(); v++)
322 {
323 CGLBFile::SVertex vt2;
324 CVertex &vt1 = pr1.m_Vertex[v];
325
326 vt2.pos = vt1.pos;
327 vt2.nor = vt1.nor;
328 vt2.tex = vt1.tex;
329
330 pr2.vertex.push_back(vt2);
331 }
332
333 //Indices
334 pr2.index = pr1.m_Index;
335 }
336
337 f.save(filename);
338 }
339
convertToVertexArrays()340 void CEditGraphObj::convertToVertexArrays()
341 {
342 for(unsigned int p=0; p < m_Primitives.size(); p++)
343 {
344 CPrimitive &pr = m_Primitives[p];
345
346 pr.m_Material.modulationColor = pr.m_Vertex[0].col;
347 pr.m_Material.opacity = pr.m_Vertex[0].opacity;
348 pr.m_Material.reflectance = pr.m_Vertex[0].reflectance;
349 if(pr.m_Material.texture >= 0)
350 {
351 pr.m_Material.replacementColor = m_MatArray[pr.m_Material.texture]->getColor();
352 pr.m_Material.replacementColor.x *= pr.m_Material.modulationColor.x;
353 pr.m_Material.replacementColor.y *= pr.m_Material.modulationColor.y;
354 pr.m_Material.replacementColor.z *= pr.m_Material.modulationColor.z;
355 }
356 else
357 {pr.m_Material.replacementColor = pr.m_Material.modulationColor;}
358 pr.m_Material.emissivity = 0;
359
360 unsigned int maxIndex = pr.m_Vertex.size() - 1;
361 unsigned int writeIndex = 0;
362 unsigned int readIndex = 0;
363
364 switch(pr.m_Type)
365 {
366 case CPrimitive::VertexArray:
367 writeIndex = maxIndex+1;
368 break;
369
370 case CPrimitive::Triangles:
371 for(readIndex=0; readIndex <= maxIndex; readIndex++)
372 {
373 CVertex v = pr.m_Vertex[readIndex];
374 pr.m_Index.push_back(findOrAdd(pr, v, writeIndex));
375 }
376 break;
377
378 case CPrimitive::Quads:
379 for(readIndex=0; readIndex <= maxIndex; readIndex+= 4)
380 {
381 CVertex v1 = pr.m_Vertex[readIndex];
382 CVertex v2 = pr.m_Vertex[readIndex+1];
383 CVertex v3 = pr.m_Vertex[readIndex+2];
384 CVertex v4 = pr.m_Vertex[readIndex+3];
385
386 unsigned int index1 = findOrAdd(pr, v1, writeIndex);
387 unsigned int index2 = findOrAdd(pr, v2, writeIndex);
388 unsigned int index3 = findOrAdd(pr, v3, writeIndex);
389 unsigned int index4 = findOrAdd(pr, v4, writeIndex);
390
391 pr.m_Index.push_back(index1);
392 pr.m_Index.push_back(index2);
393 pr.m_Index.push_back(index3);
394 pr.m_Index.push_back(index1);
395 pr.m_Index.push_back(index3);
396 pr.m_Index.push_back(index4);
397 }
398 break;
399
400 case CPrimitive::TriangleStrip:
401 case CPrimitive::QuadStrip:
402 {
403 if(maxIndex < 2) break;
404 unsigned int index1 = 0;
405 unsigned int index2 = 1;
406 writeIndex = 2;
407 bool even = false;
408 for(readIndex=2; readIndex <= maxIndex; readIndex++)
409 {
410 CVertex v3 = pr.m_Vertex[readIndex];
411
412 unsigned int index3 = findOrAdd(pr, v3, writeIndex);
413
414 if(even)
415 {
416 pr.m_Index.push_back(index3);
417 pr.m_Index.push_back(index2);
418 pr.m_Index.push_back(index1);
419 }
420 else
421 {
422 pr.m_Index.push_back(index1);
423 pr.m_Index.push_back(index2);
424 pr.m_Index.push_back(index3);
425 }
426
427 index1 = index2;
428 index2 = index3;
429 even = !even;
430 }
431 break;
432 }
433
434 case CPrimitive::Polygon:
435 {
436 if(maxIndex < 2) break;
437 unsigned int index1 = 1;
438 writeIndex = 2;
439 for(readIndex=2; readIndex <= maxIndex; readIndex++)
440 {
441 CVertex v2 = pr.m_Vertex[readIndex];
442
443 unsigned int index2 = findOrAdd(pr, v2, writeIndex);
444
445 pr.m_Index.push_back(0);
446 pr.m_Index.push_back(index1);
447 pr.m_Index.push_back(index2);
448
449 index1 = index2;
450 }
451 break;
452 }
453
454 }
455
456 pr.m_Vertex.resize(writeIndex);
457 printf("Object %s reduced from %d to %d vertices\n",
458 pr.m_Name.c_str(), maxIndex+1, writeIndex);
459
460 pr.m_Type = CPrimitive::VertexArray;
461 }
462 }
463
findOrAdd(CPrimitive & pr,const CVertex & v,unsigned int & writeIndex)464 unsigned int CEditGraphObj::findOrAdd(CPrimitive &pr, const CVertex &v, unsigned int &writeIndex)
465 {
466 int found = -1;
467 for(unsigned int i=0; i < writeIndex; i++)
468 if(isEqual(pr.m_Vertex[i], v))
469 {found = i; break;}
470
471 if(found < 0)
472 {
473 pr.m_Vertex[writeIndex] = v;
474 writeIndex++;
475 return writeIndex - 1;
476 }
477
478 return (unsigned int)found;
479 }
480
isEqual(const CVertex & v1,const CVertex & v2)481 bool CEditGraphObj::isEqual(const CVertex &v1, const CVertex &v2)
482 {
483 return
484 (v1.pos - v2.pos).abs() < 0.001 &&
485 (v1.nor - v2.nor).abs() < 0.001 &&
486 (v1.col - v2.col).abs() < 0.001 &&
487 (v1.tex - v2.tex).abs() < 0.0001 &&
488 fabs(v1.opacity - v2.opacity) < 0.01 &&
489 fabs(v1.reflectance - v2.reflectance) < 0.01;
490 }
491
render(const CString & visibleLODs)492 void CEditGraphObj::render(const CString &visibleLODs)
493 {
494 //delete existing list
495 if(isRendered)
496 {
497 printf("Deleting old model...\n");
498 glDeleteLists(m_ObjList, 1);
499 glDeleteLists(m_ObjListRef, 1);
500 }
501
502 printf("Generating model...\n");
503
504 //Normal model
505 m_ObjList = glGenLists(1);
506 glNewList(m_ObjList, GL_COMPILE);
507
508 for(unsigned int i=0; i<m_Primitives.size(); i++)
509 {
510 CPrimitive &pr = m_Primitives[i];
511
512 CString LODs = pr.m_Material.LODs;
513 bool doit = false;
514 for(unsigned int j=0; j < LODs.length(); j++)
515 if(visibleLODs.inStr( (LODs[j]) ) >= 0)
516 {doit = true; break;}
517 if(!doit) continue;
518
519 //Standard colors
520 m_OpacityState = pr.m_Material.opacity;
521 m_ColorState = pr.m_Material.modulationColor;
522
523 //Apply texture
524 if(pr.m_Material.texture < 0)
525 { //no texture
526 glDisable(GL_TEXTURE_2D);
527 }
528 else if(
529 m_MatArray[pr.m_Material.texture]->getSizeX(1) <= 4 ||
530 m_MatArray[pr.m_Material.texture]->getSizeY(1) <= 4)
531 { //too small texture
532 glDisable(GL_TEXTURE_2D);
533 m_ColorState.x *= pr.m_Material.replacementColor.x;
534 m_ColorState.y *= pr.m_Material.replacementColor.y;
535 m_ColorState.z *= pr.m_Material.replacementColor.z;
536 }
537 else
538 { //a good texture
539 glEnable(GL_TEXTURE_2D);
540 m_MatArray[pr.m_Material.texture]->draw(1);
541 }
542
543 //Set the color
544 setMaterialColor();
545
546 glBegin(GL_TRIANGLES);
547 for(unsigned int k=0; k<pr.m_Index.size(); k++)
548 {
549 unsigned int j = pr.m_Index[k];
550 CVertex &vt = pr.m_Vertex[j];
551 CVector &nor = vt.nor;
552 glNormal3f(nor.x, nor.y, nor.z);
553 CVector &tex = vt.tex;
554 glTexCoord2f(tex.x, tex.y);
555 CVector &pos = vt.pos;
556 glVertex3f(pos.x, pos.y, pos.z);
557 }
558 glEnd();
559
560 //Rotation axis
561 if(pr.m_Animation.rotationEnabled)
562 {
563 CVector p1 = pr.m_Animation.rotationOrigin;
564 CVector p2 = p1 + pr.m_Animation.rotationVelocity;
565
566 glDisable(GL_TEXTURE_2D);
567 glDisable(GL_LIGHTING);
568 glColor4f(0,1,1,1);
569
570 glBegin(GL_LINES);
571 glVertex3f(p1.x, p1.y, p1.z);
572 glVertex3f(p2.x, p2.y, p2.z);
573 glEnd();
574
575 glColor4f(1,1,1,1);
576 glEnable(GL_LIGHTING);
577 }
578 }
579
580 glEndList();
581
582 //Reflection model
583 m_ObjListRef = glGenLists(1);
584 glNewList(m_ObjListRef, GL_COMPILE);
585
586 m_ColorState = CVector(1,1,1);
587 for(unsigned int i=0; i<m_Primitives.size(); i++)
588 {
589 CPrimitive &pr = m_Primitives[i];
590 if(pr.m_Material.LODs.inStr('1') < 0) continue; //reflection model = LOD 1
591
592 if(pr.m_Type == CPrimitive::VertexArray)
593 {
594 m_OpacityState = pr.m_Material.reflectance;
595 setMaterialColor();
596
597 glBegin(GL_TRIANGLES);
598 for(unsigned int k=0; k<pr.m_Index.size(); k++)
599 {
600 unsigned int j = pr.m_Index[k];
601 CVertex &vt = pr.m_Vertex[j];
602 CVector &nor = vt.nor;
603 glNormal3f(nor.x, nor.y, nor.z);
604 CVector &pos = vt.pos;
605 glVertex3f(pos.x, pos.y, pos.z);
606 }
607 glEnd();
608 }
609 else
610 {
611 glBegin(pr.m_Type);
612 for(unsigned int j=0; j<pr.m_Vertex.size(); j++)
613 {
614 CVertex &vt = pr.m_Vertex[j];
615 CVector &nor = vt.nor;
616 glNormal3f(nor.x, nor.y, nor.z);
617 m_OpacityState = vt.reflectance;
618 setMaterialColor();
619 CVector &pos = vt.pos;
620 glVertex3f(pos.x, pos.y, pos.z);
621 }
622 glEnd();
623 }
624 }
625
626 glEndList();
627
628
629 isRendered = true;
630 }
631
draw() const632 void CEditGraphObj::draw() const
633 {
634 glCallList(m_ObjList);
635 }
636
drawRef() const637 void CEditGraphObj::drawRef() const
638 {
639 glCallList(m_ObjListRef);
640 }
641
setMaterialColor()642 void CEditGraphObj::setMaterialColor()
643 {
644 float kleur[] = {m_ColorState.x, m_ColorState.y, m_ColorState.z, m_OpacityState};
645 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, kleur);
646 }
647