1 #include "TREModel.h"
2 #include "TRESubModel.h"
3 #include "TREMainModel.h"
4 #include "TREShapeGroup.h"
5 #include "TREColoredShapeGroup.h"
6 #include "TREVertexArray.h"
7 #include "TREVertexStore.h"
8 #include "TREGL.h"
9
10 #include <TCFoundation/mystring.h>
11 #include <TCFoundation/TCMacros.h>
12
13 #ifdef WIN32
14 #if defined(_MSC_VER) && _MSC_VER >= 1400 && defined(_DEBUG)
15 #define new DEBUG_CLIENTBLOCK
16 #endif // _DEBUG
17 #endif // WIN32
18
19 // Max smooth angle == 50 (value is cos(25))
20 //#define SMOOTH_THRESHOLD 0.906307787f
21 // Max smooth angle == 80 (value is cos(40))
22 //#define SMOOTH_THRESHOLD 0.766044443f
23 // NOTE: The reason this is so high is because edge lines prevent smoothing.
24 // Max smooth angle == 150 (value is cos(75))
25 #define SMOOTH_THRESHOLD 0.258819045f
26
27 // NOTE: When a texture-mapped piece of geometry is added, it gets moved into
28 // the main model. In this case, needDupe is set to true to indicate that the
29 // piece of geometry needs to be added to the model twice; once for the texture,
30 // and once for the underlying polygon.
31 #define TEXMAP_ADD_INDEX(field, shapeGroup, shapeType) \
32 bool needDupe = false; \
33 { \
34 TexmapInfo *texmapInfo = getActiveTexmapInfo(); \
35 \
36 if (texmapInfo != NULL) \
37 { \
38 needDupe = true; \
39 int shapeSize = shapeType == TRESTriangle ? 3 : 4; \
40 TCULongArray *indices = shapeGroup->getIndices(shapeType); \
41 int index = (int)(*indices)[indices->getCount() - shapeSize]; \
42 \
43 if (shapeGroup->getBfc()) \
44 { \
45 texmapInfo->bfc.field.insert(index); \
46 } \
47 else \
48 { \
49 texmapInfo->standard.field.insert(index); \
50 } \
51 } \
52 }
53
54 #define TEXMAP_ADD_STRIP(field, shapeGroup, shapeType) \
55 bool needDupe = false; \
56 { \
57 TexmapInfo *texmapInfo = getActiveTexmapInfo(); \
58 \
59 if (texmapInfo != NULL) \
60 { \
61 needDupe = true; \
62 TCULongArray *stripCounts = \
63 shapeGroup->getStripCounts(shapeType); \
64 int stripCount = \
65 (int)(*stripCounts)[stripCounts->getCount() - 1]; \
66 TCULongArray *indices = shapeGroup->getIndices(shapeType); \
67 int index = (int)(*indices)[indices->getCount() - stripCount]; \
68 TexmapInfo::GeomInfo &geomInfo = \
69 shapeGroup->getBfc() ? texmapInfo->bfc : \
70 texmapInfo->standard; \
71 \
72 geomInfo.field.insert(index); \
73 } \
74 }
75
76
77 //00000001111111111222222222233333333334444444444555555555566666666667777777777888888888899999999990000000000111111111122222222223333333333444444444455555555556
78 //34567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
79
TREModel(void)80 TREModel::TREModel(void)
81 :m_name(NULL),
82 m_mainModel(NULL),
83 m_subModels(NULL),
84 m_unMirroredModel(NULL),
85 m_invertedModel(NULL),
86 m_sectionsPresent(0),
87 m_coloredSectionsPresent(0),
88 m_curStepIndex(0)
89 {
90 #ifdef _LEAK_DEBUG
91 strcpy(className, "TREModel");
92 #endif // _LEAK_DEBUG
93 //int i;
94
95 memset(m_shapes, 0, sizeof(m_shapes));
96 memset(m_coloredShapes, 0, sizeof(m_coloredShapes));
97 memset(m_listIDs, 0, sizeof(m_listIDs));
98 memset(m_coloredListIDs, 0, sizeof(m_coloredListIDs));
99 memset(m_texListIDs, 0, sizeof(m_texListIDs));
100 memset(m_texColoredListIDs, 0, sizeof(m_texColoredListIDs));
101 //for (i = 0; i <= TREMLast; i++)
102 //{
103 // m_shapes[i] = NULL;
104 // m_coloredShapes[i] = NULL;
105 // m_listIDs[i] = 0;
106 // m_coloredListIDs[i] = 0;
107 //}
108 m_flags.part = false;
109 m_flags.boundingBox = false;
110 m_flags.unshrunkNormals = false;
111 m_flags.unMirrored = false;
112 m_flags.inverted = false;
113 m_flags.flattened = false;
114 }
115
TREModel(const TREModel & other)116 TREModel::TREModel(const TREModel &other)
117 :m_name(copyString(other.m_name)),
118 m_mainModel(other.m_mainModel),
119 m_subModels((TRESubModelArray *)TCObject::copy(other.m_subModels)),
120 m_unMirroredModel((TREModel *)TCObject::copy(other.m_unMirroredModel)),
121 m_invertedModel((TREModel *)TCObject::copy(other.m_invertedModel)),
122 m_sectionsPresent(other.m_sectionsPresent),
123 m_coloredSectionsPresent(other.m_coloredSectionsPresent),
124 m_boundingMin(other.m_boundingMin),
125 m_boundingMax(other.m_boundingMax),
126 m_curStepIndex(other.m_curStepIndex),
127 m_stepCounts(other.m_stepCounts),
128 m_flags(other.m_flags)
129 {
130 #ifdef _LEAK_DEBUG
131 strcpy(className, "TREModel");
132 #endif // _LEAK_DEBUG
133 int i;
134
135 for (i = 0; i <= TREMLast; i++)
136 {
137 m_shapes[i] = (TREShapeGroup *)TCObject::copy(other.m_shapes[i]);
138 m_coloredShapes[i] =
139 (TREColoredShapeGroup *)TCObject::copy(other.m_coloredShapes[i]);
140 //m_listIDs[i] = 0;
141 //m_coloredListIDs[i] = 0;
142 }
143 memset(m_listIDs, 0, sizeof(m_listIDs));
144 memset(m_coloredListIDs, 0, sizeof(m_coloredListIDs));
145 memset(m_texListIDs, 0, sizeof(m_texListIDs));
146 memset(m_texColoredListIDs, 0, sizeof(m_texColoredListIDs));
147 }
148
TREModel(const TREModel & other,bool shallow)149 TREModel::TREModel(const TREModel &other, bool shallow)
150 :m_name(copyString(other.m_name)),
151 m_mainModel(other.m_mainModel),
152 m_subModels(shallow ? NULL :
153 (TRESubModelArray *)TCObject::copy(other.m_subModels)),
154 m_unMirroredModel(shallow ? NULL :
155 (TREModel *)TCObject::copy(other.m_unMirroredModel)),
156 m_invertedModel(shallow ? NULL :
157 (TREModel *)TCObject::copy(other.m_invertedModel)),
158 m_sectionsPresent(other.m_sectionsPresent),
159 m_coloredSectionsPresent(other.m_coloredSectionsPresent),
160 m_boundingMin(other.m_boundingMin),
161 m_boundingMax(other.m_boundingMax),
162 m_curStepIndex(other.m_curStepIndex),
163 m_stepCounts(other.m_stepCounts),
164 m_flags(other.m_flags)
165 {
166 #ifdef _LEAK_DEBUG
167 strcpy(className, "TREModel");
168 #endif // _LEAK_DEBUG
169 int i;
170
171 for (i = 0; i <= TREMLast; i++)
172 {
173 m_shapes[i] = (TREShapeGroup *)TCObject::copy(other.m_shapes[i]);
174 m_coloredShapes[i] =
175 (TREColoredShapeGroup *)TCObject::copy(other.m_coloredShapes[i]);
176 //m_listIDs[i] = 0;
177 //m_coloredListIDs[i] = 0;
178 }
179 memset(m_listIDs, 0, sizeof(m_listIDs));
180 memset(m_coloredListIDs, 0, sizeof(m_coloredListIDs));
181 memset(m_texListIDs, 0, sizeof(m_texListIDs));
182 memset(m_texColoredListIDs, 0, sizeof(m_texColoredListIDs));
183 }
184
~TREModel(void)185 TREModel::~TREModel(void)
186 {
187 }
188
dealloc(void)189 void TREModel::dealloc(void)
190 {
191 int i;
192
193 delete[] m_name;
194 // Don't release m_mainModel
195 TCObject::release(m_subModels);
196 if (!m_flags.unMirrored)
197 {
198 //if (m_unMirroredModel != NULL)
199 //{
200 // // The following points back to us, and since we're being deallocated
201 // // right now, we don't want it to deallocate us.
202 // m_unMirroredModel->m_unMirroredModel = NULL;
203 //}
204 TCObject::release(m_unMirroredModel);
205 }
206 m_unMirroredModel = NULL;
207 if (!m_flags.inverted)
208 {
209 //if (m_invertedModel != NULL)
210 //{
211 // // The following points back to us, and since we're being deallocated
212 // // right now, we don't want it to deallocate us.
213 // m_invertedModel->m_invertedModel = NULL;
214 //}
215 TCObject::release(m_invertedModel);
216 }
217 m_invertedModel = NULL;
218 uncompile(false);
219 for (i = 0; i <= TREMLast; i++)
220 {
221 TCObject::release(m_shapes[i]);
222 TCObject::release(m_coloredShapes[i]);
223 }
224 TCObject::dealloc();
225 }
226
copy(void) const227 TCObject *TREModel::copy(void) const
228 {
229 return new TREModel(*this);
230 }
231
shallowCopy(void)232 TREModel *TREModel::shallowCopy(void)
233 {
234 return new TREModel(*this, true);
235 }
236
getUnMirroredModel(void)237 TREModel *TREModel::getUnMirroredModel(void)
238 {
239 if (m_unMirroredModel == NULL)
240 {
241 m_unMirroredModel = shallowCopy();
242 m_unMirroredModel->unMirror(this);
243 }
244 return m_unMirroredModel;
245 }
246
getInvertedModel(void)247 TREModel *TREModel::getInvertedModel(void)
248 {
249 if (m_invertedModel == NULL)
250 {
251 m_invertedModel = shallowCopy();
252 m_invertedModel->invert(this);
253 }
254 return m_invertedModel;
255 }
256
unMirror(TREModel * originalModel)257 void TREModel::unMirror(TREModel *originalModel)
258 {
259 int i;
260
261 m_unMirroredModel = originalModel;
262 m_flags.unMirrored = true;
263 if (m_unMirroredModel->m_invertedModel != NULL)
264 {
265 m_invertedModel = m_unMirroredModel->m_invertedModel->m_unMirroredModel;
266 if (m_invertedModel != NULL)
267 {
268 m_invertedModel->m_invertedModel = this;
269 if (m_flags.inverted)
270 {
271 retain();
272 }
273 else
274 {
275 m_invertedModel->retain();
276 }
277 }
278 }
279 if (originalModel->m_subModels)
280 {
281 int count;
282
283 count = originalModel->m_subModels->getCount();
284 m_subModels = new TRESubModelArray(count);
285 for (i = 0; i < count; i++)
286 {
287 TRESubModel *subModel =
288 (*originalModel->m_subModels)[i]->getUnMirroredSubModel();
289
290 m_subModels->addObject(subModel);
291 }
292 }
293 for (i = 0; i <= TREMLast; i++)
294 {
295 if (!isLineSection(i))
296 {
297 TREShapeGroup *shapeGroup = m_shapes[i];
298 TREColoredShapeGroup *coloredShapeGroup = m_coloredShapes[i];
299
300 if (shapeGroup)
301 {
302 shapeGroup->unMirror();
303 }
304 if (coloredShapeGroup)
305 {
306 coloredShapeGroup->unMirror();
307 }
308 }
309 }
310 }
311
invert(TREModel * originalModel)312 void TREModel::invert(TREModel *originalModel)
313 {
314 int i;
315
316 m_invertedModel = originalModel;
317 m_flags.inverted = true;
318 if (m_invertedModel->m_unMirroredModel != NULL)
319 {
320 m_unMirroredModel = m_invertedModel->m_unMirroredModel->m_invertedModel;
321 if (m_unMirroredModel != NULL)
322 {
323 m_unMirroredModel->m_unMirroredModel = this;
324 if (m_flags.unMirrored)
325 {
326 retain();
327 }
328 else
329 {
330 m_unMirroredModel->retain();
331 }
332 }
333 }
334 if (originalModel->m_subModels)
335 {
336 int count;
337
338 count = originalModel->m_subModels->getCount();
339 m_subModels = new TRESubModelArray(count);
340 for (i = 0; i < count; i++)
341 {
342 TRESubModel *subModel =
343 (*originalModel->m_subModels)[i]->getInvertedSubModel();
344
345 m_subModels->addObject(subModel);
346 }
347 }
348 for (i = 0; i <= TREMLast; i++)
349 {
350 if (!isLineSection(i))
351 {
352 TREShapeGroup *shapeGroup = m_shapes[i];
353 TREColoredShapeGroup *coloredShapeGroup = m_coloredShapes[i];
354
355 if (shapeGroup)
356 {
357 shapeGroup->invert();
358 }
359 if (coloredShapeGroup)
360 {
361 coloredShapeGroup->invert();
362 }
363 }
364 }
365 }
366
setName(const char * name)367 void TREModel::setName(const char *name)
368 {
369 delete[] m_name;
370 m_name = copyString(name);
371 }
372
getListIDs(bool colored,bool skipTexmapped)373 GLuint *TREModel::getListIDs(bool colored, bool skipTexmapped)
374 {
375 skipTexmapped = false;
376 if (skipTexmapped)
377 {
378 if (colored)
379 {
380 return m_texColoredListIDs;
381 }
382 else
383 {
384 return m_texListIDs;
385 }
386 }
387 else
388 {
389 if (colored)
390 {
391 return m_coloredListIDs;
392 }
393 else
394 {
395 return m_listIDs;
396 }
397 }
398 }
399
compile(TREMSection section,bool colored,bool nonUniform,bool skipTexmapped)400 void TREModel::compile(
401 TREMSection section,
402 bool colored,
403 bool nonUniform /*= false*/,
404 bool skipTexmapped /*= false*/)
405 {
406 skipTexmapped = false;
407 GLuint *listIDs = getListIDs(colored, skipTexmapped);
408
409 if (!listIDs[section] && isSectionPresent(section, colored))
410 {
411 if (m_subModels != NULL)
412 {
413 int i;
414 int count = m_subModels->getCount();
415
416 for (i = 0; i < count; i++)
417 {
418 TRESubModel *subModel = (*m_subModels)[i];
419 bool subSkipTexmapped = skipTexmapped;
420
421 if (subModel->getTransferredFlag())
422 {
423 subSkipTexmapped = true;
424 }
425 subModel->getEffectiveModel()->compile(section, colored,
426 nonUniform | subModel->getNonUniformFlag(),
427 subSkipTexmapped);
428 }
429 }
430 if (m_mainModel->getCompileAllFlag() ||
431 (m_flags.part && m_mainModel->getCompilePartsFlag()))
432 {
433 GLuint listID = glGenLists(1);
434
435 glNewList(listID, GL_COMPILE);
436 draw(section, colored, false, nonUniform, skipTexmapped);
437 glEndList();
438 listIDs[section] = listID;
439 // debugPrintf("U Standard <<%s>> %d %d\n", m_name, m_flags.unMirrored,
440 // m_flags.inverted);
441 }
442 }
443 }
444
draw(TREMSection section)445 void TREModel::draw(TREMSection section)
446 {
447 draw(section, false);
448 }
449
checkGLError(char * msg)450 void TREModel::checkGLError(char *msg)
451 {
452 GLenum errorCode;
453
454 while ((errorCode = glGetError()) != GL_NO_ERROR)
455 {
456 const char* errorString;// = interpretGLError(errorCode);
457
458 switch (errorCode)
459 {
460 case GL_INVALID_ENUM:
461 errorString = "GL_INVALID_ENUM";
462 break;
463 case GL_INVALID_VALUE:
464 errorString = "GL_INVALID_VALUE";
465 break;
466 case GL_INVALID_OPERATION:
467 errorString = "GL_INVALID_OPERATION";
468 break;
469 case GL_STACK_OVERFLOW:
470 errorString = "GL_STACK_OVERFLOW";
471 break;
472 case GL_STACK_UNDERFLOW:
473 errorString = "GL_STACK_UNDERFLOW";
474 break;
475 case GL_OUT_OF_MEMORY:
476 errorString = "GL_OUT_OF_MEMORY";
477 break;
478 default:
479 errorString = "Unknown Error";
480 break;
481 }
482 #ifdef _DEBUG
483 debugPrintf("%s: %s\n", msg, errorString);
484 #else // _DEBUG
485 debugPrintf(3, "%s: %s\n", msg, errorString);
486 #endif // _DEBUG
487 // reportError("OpenGL error:\n%s: %s\n", LDMEOpenGL, msg, errorString);
488 }
489 }
490
draw(TREMSection section,bool colored,bool subModelsOnly,bool nonUniform,bool skipTexmapped)491 void TREModel::draw(
492 TREMSection section,
493 bool colored,
494 bool subModelsOnly /*= false*/,
495 bool nonUniform /*= false*/,
496 bool skipTexmapped /*= false*/)
497 {
498 skipTexmapped = false;
499 GLuint listID = getListIDs(colored, skipTexmapped)[section];
500
501 if (listID && !subModelsOnly &&
502 (this != m_mainModel || m_mainModel->onLastStep()))
503 {
504 // Note that subModelsOnly gets set when the current color is
505 // transparent. In that case, we don't want to draw our geometry,
506 // because transparent geometry gets drawn elsewhere. However, we do
507 // want to draw any sub-models, because some of them not be
508 // transparent.
509 glCallList(listID);
510 }
511 else if (isSectionPresent(section, colored))
512 {
513 if (!subModelsOnly)
514 {
515 TREShapeGroup *shapeGroup;
516
517 if (colored)
518 {
519 shapeGroup = m_coloredShapes[section];
520 }
521 else
522 {
523 shapeGroup = m_shapes[section];
524 }
525 if (isLineSection(section))
526 {
527 if (shapeGroup)
528 {
529 shapeGroup->drawLines();
530 }
531 }
532 else if (section == TREMConditionalLines)
533 {
534 if (shapeGroup)
535 {
536 shapeGroup->drawConditionalLines();
537 }
538 }
539 else
540 {
541 if (m_flags.part && isFlattened())
542 {
543 setGlNormalize(nonUniform);
544 }
545 else
546 {
547 setGlNormalize(true);
548 }
549 if (shapeGroup)
550 {
551 shapeGroup->draw(skipTexmapped);
552 }
553 }
554 }
555 if (m_subModels)
556 {
557 int i;
558 int count = m_subModels->getCount();
559 int step = m_mainModel->getStep();
560
561 if (!m_mainModel->onLastStep() &&
562 m_stepCounts.size() > (size_t)step)
563 {
564 count = std::min(m_stepCounts[step], count);
565 }
566 for (i = 0; i < count; i++)
567 {
568 TRESubModel *subModel = (*m_subModels)[i];
569 bool subSkipTexmapped = skipTexmapped;
570
571 if (subModel->getTransferredFlag())
572 {
573 subSkipTexmapped = true;
574 }
575 if (subModel)
576 {
577 subModel->draw(section, colored, subModelsOnly,
578 nonUniform, subSkipTexmapped);
579 }
580 }
581 }
582 }
583 }
584
drawColored(TREMSection section)585 void TREModel::drawColored(TREMSection section)
586 {
587 draw(section, true);
588 }
589
setup(TREMSection section)590 void TREModel::setup(TREMSection section)
591 {
592 if (!m_shapes[section])
593 {
594 TREShapeGroup *shapeGroup = new TREShapeGroup;
595
596 shapeGroup->setModel(this);
597 if (section == TREMStud || section == TREMStudBFC)
598 {
599 shapeGroup->setVertexStore(m_mainModel->getStudVertexStore());
600 }
601 else
602 {
603 shapeGroup->setVertexStore(m_mainModel->getVertexStore());
604 }
605 shapeGroup->setBfc(section == TREMBFC || section == TREMStudBFC);
606 // No need to release previous, since we determined it is NULL.
607 m_shapes[section] = shapeGroup;
608 // Don't release shapeGroup, becase m_shapes isn't a TCObjectArray.
609 }
610 }
611
setupColored(TREMSection section)612 void TREModel::setupColored(TREMSection section)
613 {
614 if (!m_coloredShapes[section])
615 {
616 TREColoredShapeGroup *shapeGroup = new TREColoredShapeGroup;
617
618 shapeGroup->setModel(this);
619 if (section == TREMStud || section == TREMStudBFC)
620 {
621 shapeGroup->setVertexStore(
622 m_mainModel->getColoredStudVertexStore());
623 }
624 else
625 {
626 shapeGroup->setVertexStore(m_mainModel->getColoredVertexStore());
627 }
628 shapeGroup->setBfc(section == TREMBFC || section == TREMStudBFC);
629 // No need to release previous, since we determined it is NULL.
630 m_coloredShapes[section] = shapeGroup;
631 // Don't release shapeGroup, becase m_shapes isn't a TCObjectArray.
632 }
633 }
634
setupStandard(void)635 void TREModel::setupStandard(void)
636 {
637 setup(TREMStandard);
638 }
639
setupStud(void)640 void TREModel::setupStud(void)
641 {
642 setup(TREMStud);
643 }
644
setupStudBFC(void)645 void TREModel::setupStudBFC(void)
646 {
647 setup(TREMStudBFC);
648 }
649
setupLines(void)650 void TREModel::setupLines(void)
651 {
652 setup(TREMLines);
653 }
654
setupBFC(void)655 void TREModel::setupBFC(void)
656 {
657 setup(TREMBFC);
658 }
659
setupEdges(void)660 void TREModel::setupEdges(void)
661 {
662 setup(TREMEdgeLines);
663 }
664
setupConditional(void)665 void TREModel::setupConditional(void)
666 {
667 setup(TREMConditionalLines);
668 }
669
setupColored(void)670 void TREModel::setupColored(void)
671 {
672 setupColored(TREMStandard);
673 }
674
setupColoredStud(void)675 void TREModel::setupColoredStud(void)
676 {
677 setupColored(TREMStud);
678 }
679
setupColoredStudBFC(void)680 void TREModel::setupColoredStudBFC(void)
681 {
682 setupColored(TREMStudBFC);
683 }
684
setupColoredLines(void)685 void TREModel::setupColoredLines(void)
686 {
687 setupColored(TREMLines);
688 }
689
setupColoredBFC(void)690 void TREModel::setupColoredBFC(void)
691 {
692 setupColored(TREMBFC);
693 }
694
setupColoredEdges(void)695 void TREModel::setupColoredEdges(void)
696 {
697 setupColored(TREMEdgeLines);
698 }
699
setupColoredConditional(void)700 void TREModel::setupColoredConditional(void)
701 {
702 setupColored(TREMConditionalLines);
703 }
704
addLine(TCULong color,const TCVector * vertices)705 void TREModel::addLine(TCULong color, const TCVector *vertices)
706 {
707 setupColoredLines();
708 m_coloredShapes[TREMLines]->addLine(color, vertices);
709 }
710
addLine(const TCVector * vertices)711 void TREModel::addLine(const TCVector *vertices)
712 {
713 setupLines();
714 m_shapes[TREMLines]->addLine(vertices);
715 }
716
addConditionalLine(const TCVector * vertices,const TCVector * controlPoints,TCULong color)717 void TREModel::addConditionalLine(
718 const TCVector *vertices,
719 const TCVector *controlPoints,
720 TCULong color)
721 {
722 // Note a color of 0 would have an alpha of 0, which would make it
723 // invisible. LDModelParser needs to be smart enough to ignore geometry
724 // that's invisible.
725 if (color == 0)
726 {
727 setup(TREMConditionalLines);
728 m_shapes[TREMConditionalLines]->addConditionalLine(vertices,
729 controlPoints);
730 }
731 else
732 {
733 setupColored(TREMConditionalLines);
734 m_coloredShapes[TREMConditionalLines]->addConditionalLine(color,
735 vertices, controlPoints);
736 }
737 }
738
addEdgeLine(const TCVector * vertices,TCULong color)739 void TREModel::addEdgeLine(const TCVector *vertices, TCULong color)
740 {
741 if (color == 0)
742 {
743 setupEdges();
744 m_shapes[TREMEdgeLines]->addLine(vertices);
745 }
746 else
747 {
748 setupColoredEdges();
749 m_coloredShapes[TREMEdgeLines]->addLine(color, vertices);
750 }
751 }
752
addTriangle(TCULong color,const TCVector * vertices)753 void TREModel::addTriangle(TCULong color, const TCVector *vertices)
754 {
755 setupColored();
756 m_coloredShapes[TREMStandard]->addTriangle(color, vertices);
757 TEXMAP_ADD_INDEX(colored.triangles, m_coloredShapes[TREMStandard],
758 TRESTriangle);
759 if (needDupe)
760 {
761 m_coloredShapes[TREMStandard]->addTriangle(color, vertices);
762 }
763 //TEXMAP_INCREMENT(false, colored.triangleCount);
764 }
765
addTriangle(TCULong color,const TCVector * vertices,const TCVector * normals)766 void TREModel::addTriangle(
767 TCULong color,
768 const TCVector *vertices,
769 const TCVector *normals)
770 {
771 setupColored();
772 m_coloredShapes[TREMStandard]->addTriangle(color, vertices, normals);
773 TEXMAP_ADD_INDEX(colored.triangles, m_coloredShapes[TREMStandard],
774 TRESTriangle);
775 if (needDupe)
776 {
777 m_coloredShapes[TREMStandard]->addTriangle(color, vertices, normals);
778 }
779 //TEXMAP_INCREMENT(false, colored.triangleCount);
780 }
781
addTriangle(const TCVector * vertices)782 void TREModel::addTriangle(const TCVector *vertices)
783 {
784 setupStandard();
785 m_shapes[TREMStandard]->addTriangle(vertices);
786 TEXMAP_ADD_INDEX(standard.triangles, m_shapes[TREMStandard], TRESTriangle);
787 if (needDupe)
788 {
789 m_shapes[TREMStandard]->addTriangle(vertices);
790 }
791 //TEXMAP_INCREMENT(false, standard.triangleCount);
792 }
793
addTriangle(const TCVector * vertices,const TCVector * normals)794 void TREModel::addTriangle(const TCVector *vertices, const TCVector *normals)
795 {
796 setupStandard();
797 m_shapes[TREMStandard]->addTriangle(vertices, normals);
798 TEXMAP_ADD_INDEX(standard.triangles, m_shapes[TREMStandard], TRESTriangle);
799 if (needDupe)
800 {
801 m_shapes[TREMStandard]->addTriangle(vertices, normals);
802 }
803 //TEXMAP_INCREMENT(false, standard.triangleCount);
804 }
805
addBFCTriangle(TCULong color,const TCVector * vertices)806 void TREModel::addBFCTriangle(TCULong color, const TCVector *vertices)
807 {
808 setupColoredBFC();
809 m_coloredShapes[TREMBFC]->addTriangle(color, vertices);
810 TEXMAP_ADD_INDEX(colored.triangles, m_coloredShapes[TREMBFC], TRESTriangle);
811 if (needDupe)
812 {
813 m_coloredShapes[TREMBFC]->addTriangle(color, vertices);
814 }
815 //TEXMAP_INCREMENT(true, colored.triangleCount);
816 }
817
addBFCTriangle(TCULong color,const TCVector * vertices,const TCVector * normals)818 void TREModel::addBFCTriangle(
819 TCULong color,
820 const TCVector *vertices,
821 const TCVector *normals)
822 {
823 setupColoredBFC();
824 m_coloredShapes[TREMBFC]->addTriangle(color, vertices, normals);
825 TEXMAP_ADD_INDEX(colored.triangles, m_coloredShapes[TREMBFC], TRESTriangle);
826 if (needDupe)
827 {
828 m_coloredShapes[TREMBFC]->addTriangle(color, vertices, normals);
829 }
830 //TEXMAP_INCREMENT(true, colored.triangleCount);
831 }
832
addBFCTriangle(const TCVector * vertices)833 void TREModel::addBFCTriangle(const TCVector *vertices)
834 {
835 setupBFC();
836 m_shapes[TREMBFC]->addTriangle(vertices);
837 TEXMAP_ADD_INDEX(standard.triangles, m_shapes[TREMBFC], TRESTriangle);
838 if (needDupe)
839 {
840 m_shapes[TREMBFC]->addTriangle(vertices);
841 }
842 //TEXMAP_INCREMENT(true, standard.triangleCount);
843 }
844
addBFCTriangle(const TCVector * vertices,const TCVector * normals)845 void TREModel::addBFCTriangle(const TCVector *vertices, const TCVector *normals)
846 {
847 setupBFC();
848 m_shapes[TREMBFC]->addTriangle(vertices, normals);
849 TEXMAP_ADD_INDEX(standard.triangles, m_shapes[TREMBFC], TRESTriangle);
850 if (needDupe)
851 {
852 m_shapes[TREMBFC]->addTriangle(vertices, normals);
853 }
854 //TEXMAP_INCREMENT(true, standard.triangleCount);
855 }
856
getActiveTexmapInfo(void)857 TREModel::TexmapInfo *TREModel::getActiveTexmapInfo(void)
858 {
859 const std::string *activeTextureFilename =
860 m_mainModel->getActiveTextureFilename();
861 if (activeTextureFilename != NULL)
862 {
863 if (m_texmapInfos.size() > 0)
864 {
865 TexmapInfo &texmapInfo = m_texmapInfos.back();
866
867 if (texmapInfo.filename == *activeTextureFilename)
868 {
869 return &texmapInfo;
870 }
871 }
872 }
873 return NULL;
874 }
875
addQuad(TCULong color,const TCVector * vertices)876 void TREModel::addQuad(TCULong color, const TCVector *vertices)
877 {
878 setupColored();
879 m_coloredShapes[TREMStandard]->addQuad(color, vertices);
880 TEXMAP_ADD_INDEX(colored.quads, m_coloredShapes[TREMStandard], TRESQuad);
881 if (needDupe)
882 {
883 m_coloredShapes[TREMStandard]->addQuad(color, vertices);
884 }
885 //TEXMAP_INCREMENT(false, colored.quadCount);
886 }
887
addQuad(const TCVector * vertices)888 void TREModel::addQuad(const TCVector *vertices)
889 {
890 setupStandard();
891 m_shapes[TREMStandard]->addQuad(vertices);
892 TEXMAP_ADD_INDEX(standard.quads, m_shapes[TREMStandard], TRESQuad);
893 if (needDupe)
894 {
895 m_shapes[TREMStandard]->addQuad(vertices);
896 }
897 //TEXMAP_INCREMENT(false, standard.quadCount);
898 }
899
addBFCQuad(const TCVector * vertices)900 void TREModel::addBFCQuad(const TCVector *vertices)
901 {
902 setupBFC();
903 m_shapes[TREMBFC]->addQuad(vertices);
904 TEXMAP_ADD_INDEX(standard.quads, m_shapes[TREMBFC], TRESQuad);
905 if (needDupe)
906 {
907 m_shapes[TREMBFC]->addQuad(vertices);
908 }
909 //TEXMAP_INCREMENT(true, standard.quadCount);
910 }
911
addBFCQuad(TCULong color,const TCVector * vertices)912 void TREModel::addBFCQuad(TCULong color, const TCVector *vertices)
913 {
914 setupColoredBFC();
915 m_coloredShapes[TREMBFC]->addQuad(color, vertices);
916 TEXMAP_ADD_INDEX(colored.quads, m_coloredShapes[TREMBFC], TRESQuad);
917 if (needDupe)
918 {
919 m_coloredShapes[TREMBFC]->addQuad(color, vertices);
920 }
921 //TEXMAP_INCREMENT(true, colored.quadCount);
922 }
923
triangleStripToTriangle(int index,const TCVector * stripVertices,const TCVector * stripNormals,TCVector * triangleVertices,TCVector * triangleNormals)924 void TREModel::triangleStripToTriangle(
925 int index,
926 const TCVector *stripVertices,
927 const TCVector *stripNormals,
928 TCVector *triangleVertices,
929 TCVector *triangleNormals)
930 {
931 int ofs1 = 1;
932 int ofs2 = 2;
933
934 if (index % 2)
935 {
936 ofs1 = 2;
937 ofs2 = 1;
938 }
939 triangleVertices[0] = stripVertices[index];
940 triangleVertices[1] = stripVertices[index + ofs1];
941 triangleVertices[2] = stripVertices[index + ofs2];
942 triangleNormals[0] = stripNormals[index];
943 triangleNormals[1] = stripNormals[index + ofs1];
944 triangleNormals[2] = stripNormals[index + ofs2];
945 }
946
quadStripToQuad(int index,const TCVector * stripVertices,const TCVector * stripNormals,TCVector * quadVertices,TCVector * quadNormals)947 void TREModel::quadStripToQuad(
948 int index,
949 const TCVector *stripVertices,
950 const TCVector *stripNormals,
951 TCVector *quadVertices,
952 TCVector *quadNormals)
953 {
954 quadVertices[0] = stripVertices[index];
955 quadVertices[1] = stripVertices[index + 1];
956 quadVertices[2] = stripVertices[index + 3];
957 quadVertices[3] = stripVertices[index + 2];
958 quadNormals[0] = stripNormals[index];
959 quadNormals[1] = stripNormals[index + 1];
960 quadNormals[2] = stripNormals[index + 3];
961 quadNormals[3] = stripNormals[index + 2];
962 }
963
addQuadStrip(const TCVector * vertices,const TCVector * normals,int count,bool flat)964 void TREModel::addQuadStrip(
965 const TCVector *vertices,
966 const TCVector *normals,
967 int count,
968 bool flat)
969 {
970 setupStandard();
971 addQuadStrip(m_shapes[TREMStandard], vertices, normals, count, flat);
972 }
973
addTriangleStrip(const TCVector * vertices,const TCVector * normals,int count,bool flat)974 void TREModel::addTriangleStrip(
975 const TCVector *vertices,
976 const TCVector *normals,
977 int count,
978 bool flat)
979 {
980 setupStandard();
981 addTriangleStrip(m_shapes[TREMStandard], vertices, normals, count, flat);
982 }
983
addQuadStrip(TREShapeGroup * shapeGroup,const TCVector * vertices,const TCVector * normals,int count,bool flat)984 void TREModel::addQuadStrip(TREShapeGroup *shapeGroup, const TCVector *vertices,
985 const TCVector *normals, int count, bool flat)
986 {
987 if (m_mainModel->getUseQuadStripsFlag() && (!flat ||
988 m_mainModel->getUseFlatStripsFlag()))
989 {
990 shapeGroup->addQuadStrip(vertices, normals, count);
991 TEXMAP_ADD_STRIP(standard.quadStrips, shapeGroup, TRESQuadStrip);
992 if (needDupe)
993 {
994 shapeGroup->addQuadStrip(vertices, normals, count);
995 }
996 }
997 else
998 {
999 int i;
1000 TCVector quadVertices[4];
1001 TCVector quadNormals[4];
1002
1003 for (i = 0; i < count - 3; i += 2)
1004 {
1005 quadStripToQuad(i, vertices, normals, quadVertices, quadNormals);
1006 shapeGroup->addQuad(quadVertices, quadNormals);
1007 }
1008 }
1009 }
1010
addBFCQuadStrip(const TCVector * vertices,const TCVector * normals,int count,bool flat)1011 void TREModel::addBFCQuadStrip(
1012 const TCVector *vertices,
1013 const TCVector *normals,
1014 int count,
1015 bool flat)
1016 {
1017 setupBFC();
1018 addQuadStrip(m_shapes[TREMBFC], vertices, normals, count, flat);
1019 }
1020
addQuadStrip(TCULong color,const TCVector * vertices,const TCVector * normals,int count,bool flat)1021 void TREModel::addQuadStrip(TCULong color, const TCVector *vertices,
1022 const TCVector *normals, int count, bool flat)
1023 {
1024 setupColored();
1025 addQuadStrip(m_coloredShapes[TREMStandard], color, vertices, normals,
1026 count, flat);
1027 }
1028
addTriangleStrip(TREShapeGroup * shapeGroup,const TCVector * vertices,const TCVector * normals,int count,bool flat)1029 void TREModel::addTriangleStrip(
1030 TREShapeGroup *shapeGroup,
1031 const TCVector *vertices,
1032 const TCVector *normals,
1033 int count,
1034 bool flat)
1035 {
1036 if (m_mainModel->getUseTriStripsFlag() && (!flat ||
1037 m_mainModel->getUseFlatStripsFlag()))
1038 {
1039 shapeGroup->addTriangleStrip(vertices, normals, count);
1040 TEXMAP_ADD_STRIP(standard.triStrips, shapeGroup, TRESTriangleStrip);
1041 if (needDupe)
1042 {
1043 shapeGroup->addTriangleStrip(vertices, normals, count);
1044 }
1045 }
1046 else
1047 {
1048 int i;
1049 TCVector triangleVertices[3];
1050 TCVector triangleNormals[3];
1051
1052 for (i = 0; i < count - 2; i++)
1053 {
1054 triangleStripToTriangle(i, vertices, normals, triangleVertices,
1055 triangleNormals);
1056 shapeGroup->addTriangle(triangleVertices, triangleNormals);
1057 TEXMAP_ADD_INDEX(standard.triangles, shapeGroup, TRESTriangle);
1058 if (needDupe)
1059 {
1060 shapeGroup->addTriangle(triangleVertices, triangleNormals);
1061 }
1062 //TEXMAP_INCREMENT(shapeGroup == m_shapes[TREMBFC],
1063 // standard.triangleCount);
1064 }
1065 }
1066 }
1067
addQuadStrip(TREColoredShapeGroup * shapeGroup,TCULong color,const TCVector * vertices,const TCVector * normals,int count,bool flat)1068 void TREModel::addQuadStrip(
1069 TREColoredShapeGroup *shapeGroup,
1070 TCULong color,
1071 const TCVector *vertices,
1072 const TCVector *normals,
1073 int count,
1074 bool flat)
1075 {
1076 if (m_mainModel->getUseQuadStripsFlag() && (!flat ||
1077 m_mainModel->getUseFlatStripsFlag()))
1078 {
1079 shapeGroup->addQuadStrip(color, vertices, normals, count);
1080 TEXMAP_ADD_STRIP(colored.quadStrips, shapeGroup, TRESQuadStrip);
1081 if (needDupe)
1082 {
1083 shapeGroup->addQuadStrip(color, vertices, normals, count);
1084 }
1085 }
1086 else
1087 {
1088 int i;
1089 TCVector quadVertices[4];
1090 TCVector quadNormals[4];
1091
1092 for (i = 0; i < count - 3; i += 2)
1093 {
1094 quadStripToQuad(i, vertices, normals, quadVertices, quadNormals);
1095 shapeGroup->addQuad(color, quadVertices, quadNormals);
1096 TEXMAP_ADD_INDEX(standard.quads, shapeGroup, TRESQuad);
1097 if (needDupe)
1098 {
1099 shapeGroup->addQuad(color, quadVertices, quadNormals);
1100 }
1101 //TEXMAP_INCREMENT(shapeGroup == m_shapes[TREMBFC],
1102 // standard.quadCount);
1103 }
1104 }
1105 }
1106
addBFCQuadStrip(TCULong color,const TCVector * vertices,const TCVector * normals,int count,bool flat)1107 void TREModel::addBFCQuadStrip(TCULong color, const TCVector *vertices,
1108 const TCVector *normals, int count, bool flat)
1109 {
1110 setupColoredBFC();
1111 addQuadStrip(m_coloredShapes[TREMBFC], color, vertices, normals, count,
1112 flat);
1113 }
1114
addBFCTriangleStrip(const TCVector * vertices,const TCVector * normals,int count,bool flat)1115 void TREModel::addBFCTriangleStrip(
1116 const TCVector *vertices,
1117 const TCVector *normals,
1118 int count,
1119 bool flat)
1120 {
1121 setupBFC();
1122 addTriangleStrip(m_shapes[TREMBFC], vertices, normals, count, flat);
1123 }
1124
triangleFanToTriangle(int index,const TCVector * fanVertices,const TCVector * fanNormals,const TCVector * fanTextureCoords,TCVector * triangleVertices,TCVector * triangleNormals,TCVector * triangleTextureCoords)1125 void TREModel::triangleFanToTriangle(
1126 int index,
1127 const TCVector *fanVertices,
1128 const TCVector *fanNormals,
1129 const TCVector *fanTextureCoords,
1130 TCVector *triangleVertices,
1131 TCVector *triangleNormals,
1132 TCVector *triangleTextureCoords)
1133 {
1134 triangleVertices[0] = fanVertices[0];
1135 triangleVertices[1] = fanVertices[index];
1136 triangleVertices[2] = fanVertices[index + 1];
1137 triangleNormals[0] = fanNormals[0];
1138 triangleNormals[1] = fanNormals[index];
1139 triangleNormals[2] = fanNormals[index + 1];
1140 if (fanTextureCoords)
1141 {
1142 triangleTextureCoords[0] = fanTextureCoords[0];
1143 triangleTextureCoords[1] = fanTextureCoords[index];
1144 triangleTextureCoords[2] = fanTextureCoords[index + 1];
1145 }
1146 }
1147
addTriangleFan(const TCVector * vertices,const TCVector * normals,const TCVector * textureCoords,int count,bool flat)1148 void TREModel::addTriangleFan(
1149 const TCVector *vertices,
1150 const TCVector *normals,
1151 const TCVector *textureCoords,
1152 int count,
1153 bool flat)
1154 {
1155 TREShapeGroup *shapeGroup;
1156
1157 if (textureCoords)
1158 {
1159 setupStud();
1160 shapeGroup = m_shapes[TREMStud];
1161 }
1162 else
1163 {
1164 setupStandard();
1165 shapeGroup = m_shapes[TREMStandard];
1166 }
1167 addTriangleFan(shapeGroup, vertices, normals, textureCoords, count, flat);
1168 }
1169
addTriangleFan(TREShapeGroup * shapeGroup,const TCVector * vertices,const TCVector * normals,const TCVector * textureCoords,int count,bool flat)1170 void TREModel::addTriangleFan(
1171 TREShapeGroup *shapeGroup,
1172 const TCVector *vertices,
1173 const TCVector *normals,
1174 const TCVector *textureCoords,
1175 int count,
1176 bool flat)
1177 {
1178 if (m_mainModel->getUseTriFansFlag() && (!flat ||
1179 m_mainModel->getUseFlatStripsFlag()))
1180 {
1181 if (textureCoords)
1182 {
1183 shapeGroup->addTriangleFan(vertices, normals, textureCoords, count);
1184 }
1185 else
1186 {
1187 shapeGroup->addTriangleFan(vertices, normals, count);
1188 }
1189 }
1190 else
1191 {
1192 int i;
1193 TCVector triangleVertices[3];
1194 TCVector triangleNormals[3];
1195 TCVector triangleTextureCoords[3];
1196
1197 for (i = 1; i < count - 1; i++)
1198 {
1199 triangleFanToTriangle(i, vertices, normals, textureCoords,
1200 triangleVertices, triangleNormals, triangleTextureCoords);
1201 if (textureCoords)
1202 {
1203 shapeGroup->addTriangle(triangleVertices, triangleNormals,
1204 triangleTextureCoords);
1205 }
1206 else
1207 {
1208 shapeGroup->addTriangle(triangleVertices, triangleNormals);
1209 }
1210 }
1211 }
1212 }
1213
addBFCTriangleFan(const TCVector * vertices,const TCVector * normals,const TCVector * textureCoords,int count,bool flat)1214 void TREModel::addBFCTriangleFan(
1215 const TCVector *vertices,
1216 const TCVector *normals,
1217 const TCVector *textureCoords,
1218 int count,
1219 bool flat)
1220 {
1221 TREShapeGroup *shapeGroup;
1222
1223 if (textureCoords)
1224 {
1225 setupStudBFC();
1226 shapeGroup = m_shapes[TREMStudBFC];
1227 }
1228 else
1229 {
1230 setupBFC();
1231 shapeGroup = m_shapes[TREMBFC];
1232 }
1233 addTriangleFan(shapeGroup, vertices, normals, textureCoords, count, flat);
1234 }
1235
addTriangleFan(TCULong color,const TCVector * vertices,const TCVector * normals,int count,bool flat)1236 void TREModel::addTriangleFan(TCULong color, const TCVector *vertices,
1237 const TCVector *normals, int count, bool flat)
1238 {
1239 setupColored();
1240 addTriangleFan(m_coloredShapes[TREMStandard], color, vertices, normals,
1241 count, flat);
1242 }
1243
addTriangleFan(TREColoredShapeGroup * shapeGroup,TCULong color,const TCVector * vertices,const TCVector * normals,int count,bool flat)1244 void TREModel::addTriangleFan(
1245 TREColoredShapeGroup *shapeGroup,
1246 TCULong color,
1247 const TCVector *vertices,
1248 const TCVector *normals,
1249 int count,
1250 bool flat)
1251 {
1252 if (m_mainModel->getUseStripsFlag() && (!flat ||
1253 m_mainModel->getUseFlatStripsFlag()))
1254 {
1255 shapeGroup->addTriangleFan(color, vertices, normals, count);
1256 }
1257 else
1258 {
1259 int i;
1260 TCVector triangleVertices[3];
1261 TCVector triangleNormals[3];
1262
1263 for (i = 1; i < count - 1; i++)
1264 {
1265 triangleFanToTriangle(i, vertices, normals, NULL, triangleVertices,
1266 triangleNormals, NULL);
1267 shapeGroup->addTriangle(color, triangleVertices, triangleNormals);
1268 }
1269 }
1270 }
1271
addBFCTriangleFan(TCULong color,const TCVector * vertices,const TCVector * normals,int count,bool flat)1272 void TREModel::addBFCTriangleFan(TCULong color, const TCVector *vertices,
1273 const TCVector *normals, int count, bool flat)
1274 {
1275 setupColoredBFC();
1276 addTriangleFan(m_coloredShapes[TREMBFC], color, vertices, normals, count,
1277 flat);
1278 }
1279
addSubModel(const TCFloat * matrix,TREModel * model,bool invert)1280 TRESubModel *TREModel::addSubModel(
1281 const TCFloat *matrix,
1282 TREModel *model,
1283 bool invert)
1284 {
1285 TRESubModel *subModel = new TRESubModel;
1286 TexmapInfo *texmapInfo = getActiveTexmapInfo();
1287
1288 if (!m_subModels)
1289 {
1290 m_subModels = new TRESubModelArray;
1291 }
1292 subModel->setMatrix(matrix);
1293 subModel->setModel(model);
1294 subModel->setBFCInvertFlag(invert);
1295 m_subModels->addObject(subModel);
1296 subModel->release();
1297 if (texmapInfo != NULL)
1298 {
1299 texmapInfo->subModelCount++;
1300 }
1301 return subModel;
1302 }
1303
addSubModel(TCULong color,TCULong edgeColor,const TCFloat * matrix,TREModel * model,bool invert)1304 TRESubModel *TREModel::addSubModel(
1305 TCULong color,
1306 TCULong edgeColor,
1307 const TCFloat *matrix,
1308 TREModel *model,
1309 bool invert)
1310 {
1311 TRESubModel *subModel = addSubModel(matrix, model, invert);
1312
1313 subModel->setColor(color, edgeColor);
1314 return subModel;
1315 }
1316
smooth(void)1317 void TREModel::smooth(void)
1318 {
1319 TREConditionalMap conditionalMap;
1320 TREEdgeMap edgeMap;
1321 TRENormalInfoArray *normalInfos = new TRENormalInfoArray;
1322
1323 fillEdgeMap(edgeMap);
1324 fillConditionalMap(conditionalMap, edgeMap);
1325 calcShapeNormals(conditionalMap, normalInfos, TRESTriangle);
1326 calcShapeNormals(conditionalMap, normalInfos, TRESQuad);
1327 finishShapeNormals(conditionalMap);
1328 applyShapeNormals(normalInfos);
1329 normalInfos->release();
1330 }
1331
finishShapeNormals(TREConditionalMap & conditionalMap)1332 void TREModel::finishShapeNormals(TREConditionalMap &conditionalMap)
1333 {
1334 TREConditionalMap::iterator it = conditionalMap.begin();
1335
1336 while (it != conditionalMap.end())
1337 {
1338 TRESmoother &smoother0 = it->second;
1339
1340 smoother0.finish();
1341 it++;
1342 }
1343 }
1344
applyShapeNormals(TRENormalInfoArray * normalInfos)1345 void TREModel::applyShapeNormals(TRENormalInfoArray *normalInfos)
1346 {
1347 int i;
1348 int infoCount = normalInfos->getCount();
1349 TCVector normal;
1350 TCVector vertexNormal;
1351
1352 for (i = 0; i < infoCount; i++)
1353 {
1354 TRENormalInfo *normalInfo = (*normalInfos)[i];
1355 TREVertexArray *normals = normalInfo->m_normals;
1356 TRESmoother *smoother = normalInfo->m_smoother;
1357 TREVertex &vertex = normals->vertexAtIndex(normalInfo->m_normalIndex);
1358
1359 vertexNormal = TCVector(vertex.v);
1360 normal = smoother->getNormal(normalInfo->m_smootherIndex);
1361 if (TRESmoother::shouldFlipNormal(normal, TCVector(vertex.v)))
1362 {
1363 normal *= -1.0f;
1364 }
1365 // The following number is the cos of n degrees, where n is half of the
1366 // maximum smoothing angle. (See SMOOTH_THRESHOLD definition for
1367 // current value. I don't want to calculate it on the fly.
1368 // We only want to apply this normal if the difference between it an the
1369 // original normal is less than SMOOTH_THRESHOLD degrees. If the normal
1370 // only applies to two faces, then the faces have to be less than
1371 // SMOOTH_THRESHOLD * 2 degrees apart for this to happen. Note that
1372 // low-res studs have 45-degree angles between the faces, so
1373 // SMOOTH_THRESHOLD ideally needs to be cos of at least 25 in order to
1374 // have a little leeway.
1375 if (normal.dot(vertexNormal) > SMOOTH_THRESHOLD)
1376 {
1377 memcpy(vertex.v, (const TCFloat *)normal, 3 * sizeof(TCFloat));
1378 }
1379 }
1380 }
1381
calcShapeNormals(TREConditionalMap & conditionalMap,TRENormalInfoArray * normalInfos,TREShapeType shapeType)1382 void TREModel::calcShapeNormals(TREConditionalMap &conditionalMap,
1383 TRENormalInfoArray *normalInfos,
1384 TREShapeType shapeType)
1385 {
1386 calcShapeNormals(conditionalMap, normalInfos, TREMStandard, shapeType);
1387 calcShapeNormals(conditionalMap, normalInfos, TREMBFC, shapeType);
1388 }
1389
calcShapeNormals(TREConditionalMap & conditionalMap,TRENormalInfoArray * normalInfos,TREMSection section,TREShapeType shapeType)1390 void TREModel::calcShapeNormals(TREConditionalMap &conditionalMap,
1391 TRENormalInfoArray *normalInfos,
1392 TREMSection section, TREShapeType shapeType)
1393 {
1394 calcShapeNormals(conditionalMap, normalInfos, m_shapes[section], shapeType);
1395 calcShapeNormals(conditionalMap, normalInfos, m_coloredShapes[section],
1396 shapeType);
1397 }
1398
1399 /*
1400 This function causes all the smoothed normals to be calculated. It doesn't
1401 actually apply them, but calculates their values, and records them so that they
1402 can be later applied to the actual geometry.
1403 */
calcShapeNormals(TREConditionalMap & conditionalMap,TRENormalInfoArray * normalInfos,TREShapeGroup * shapeGroup,TREShapeType shapeType)1404 void TREModel::calcShapeNormals(TREConditionalMap &conditionalMap,
1405 TRENormalInfoArray *normalInfos,
1406 TREShapeGroup *shapeGroup,
1407 TREShapeType shapeType)
1408 {
1409 if (shapeGroup)
1410 {
1411 TCULongArray *indices = shapeGroup->getIndices(shapeType);
1412
1413 if (indices)
1414 {
1415 int i, j;
1416 int count = indices->getCount();
1417 int shapeSize = 3;
1418 TREVertexArray *vertices =
1419 shapeGroup->getVertexStore()->getVertices();
1420 TREVertexArray *normals =
1421 shapeGroup->getVertexStore()->getNormals();
1422
1423 if (shapeType == TRESQuad)
1424 {
1425 shapeSize = 4;
1426 }
1427 for (i = 0; i < count; i += shapeSize)
1428 {
1429 for (j = 0; j < shapeSize; j++)
1430 {
1431 // Process the smooth edge between points i + j and
1432 // i + j + 1 (with wrap-around based on shapeSize). Pass
1433 // i + j + 2 (with wrap-around) in to allow multiple
1434 // continuous shapes that all share one point to all get
1435 // smoothed together.
1436 processSmoothEdge(conditionalMap, normalInfos, vertices,
1437 normals, (*indices)[i + j],
1438 (*indices)[i + ((j + 1) % shapeSize)],
1439 (*indices)[i + ((j + 2) % shapeSize)]);
1440 }
1441 }
1442 }
1443 }
1444 }
1445
1446 /*
1447 This function looks for a conditional line between the points at index0 and
1448 index1, and also between index1 and index2. If it finds one between index0 and
1449 index1, it considers that edge to be smooth, and adds the surface normal
1450 associated with the point at index0 to the surface normal stored in the
1451 TRESmoother associated with each of the two points at the ends of the
1452 conditional line. If it finds the second conditional line, it adds that line to
1453 the TGLSmoother associated with index1. Smoothers that are associated with
1454 each other will later be smoothed together.
1455 */
processSmoothEdge(TREConditionalMap & conditionalMap,TRENormalInfoArray * normalInfos,const TREVertexArray * vertices,TREVertexArray * normals,int index0,int index1,int index2)1456 void TREModel::processSmoothEdge(TREConditionalMap &conditionalMap,
1457 TRENormalInfoArray *normalInfos,
1458 const TREVertexArray *vertices,
1459 TREVertexArray *normals, int index0,
1460 int index1, int index2)
1461 {
1462 TRESmoother *smoother0 = NULL;
1463 int line0Index = getConditionalLine(conditionalMap,
1464 vertices->vertexAtIndex(index0), vertices->vertexAtIndex(index1),
1465 smoother0);
1466
1467 if (line0Index >= 0)
1468 {
1469 // line0Index is the index in smoother0 of the condtional line that goes
1470 // between the points at index0 and index1. Note that smoother has
1471 // been initialized to point to the smoother associated with the point
1472 // at index0.
1473 TRESmoother *smoother1 = NULL;
1474 int line1Index = getConditionalLine(conditionalMap,
1475 vertices->vertexAtIndex(index1), vertices->vertexAtIndex(index0),
1476 smoother1);
1477
1478 if (smoother1)
1479 {
1480 // If we found the first conditional line (line0Index >= 0), then we
1481 // should always get smoother1, since smoother1 just corresponds to
1482 // the point at the other end of the conditional line. Since we
1483 // found a conditional line, and all of them are inserted keyed off
1484 // of both ends, smoother1 should always be non-NULL if line0Index
1485 // >= 0.
1486 const TCVector &normal0 =
1487 TCVector(normals->vertexAtIndex(index0).v);
1488 TRENormalInfo *normalInfo;
1489 // Check to see if there is conditional line between the points at
1490 // index1 and index2. Note that by passing smoother1 into
1491 // getConditionalLine with a value already set, it uses that
1492 // smoother, and skips the lookup. If line2Index comes out >= 0,
1493 // the point will be marked as shared between the two conditionals,
1494 // so that it will be smoothed betwen them.
1495 int line2Index = getConditionalLine(conditionalMap,
1496 vertices->vertexAtIndex(index1),
1497 vertices->vertexAtIndex(index2), smoother1);
1498
1499 // Check to see if the normal for index0 is more than 90 degrees
1500 // away from the running total normal stored in smoother0. Note
1501 // that each conditional line gets its own normal unless two are
1502 // merged together below.
1503 if (TRESmoother::shouldFlipNormal(smoother0->getNormal(line0Index),
1504 normal0))
1505 {
1506 // Subtract shape's normal from the running total, since it is
1507 // more than 90 degrees off.
1508 smoother0->getNormal(line0Index) -= normal0;
1509 }
1510 else
1511 {
1512 // Add shape's normal to the running total.
1513 smoother0->getNormal(line0Index) += normal0;
1514 }
1515 normalInfo = new TRENormalInfo;
1516 normalInfo->m_normals = normals;
1517 normalInfo->m_normalIndex = index0;
1518 normalInfo->m_smoother = smoother0;
1519 normalInfo->m_smootherIndex = line0Index;
1520 normalInfos->addObject(normalInfo);
1521 normalInfo->release();
1522 if (line1Index >= 0)
1523 {
1524 // This should always be the case.
1525 const TCVector &normal1 =
1526 TCVector(normals->vertexAtIndex(index1).v);
1527
1528 // Check to see if the normal for index1 is more than 90 degrees
1529 // away from the running total normal stored in smoother1. Note
1530 // that each conditional line gets its own normal unless two are
1531 // merged together below.
1532 if (TRESmoother::shouldFlipNormal(smoother1->getNormal(
1533 line1Index), normal1))
1534 {
1535 // Subtract shape's normal from the running total, since it
1536 // is more than 90 degrees off.
1537 smoother1->getNormal(line1Index) -= normal1;
1538 }
1539 else
1540 {
1541 // Add shape's normal to the running total.
1542 smoother1->getNormal(line1Index) += normal1;
1543 }
1544 normalInfo = new TRENormalInfo;
1545 normalInfo->m_normals = normals;
1546 normalInfo->m_normalIndex = index1;
1547 normalInfo->m_smoother = smoother1;
1548 normalInfo->m_smootherIndex = line1Index;
1549 normalInfos->addObject(normalInfo);
1550 normalInfo->release();
1551 }
1552 if (line2Index >= 0)
1553 {
1554 smoother1->markShared(line1Index, line2Index);
1555 }
1556 }
1557 }
1558 }
1559
1560 /*
1561 This functions finds a conditional line in conditionalMap that goes from vertex0
1562 to vertex1, and returns its index if it exists. Returns -1 otherwise. Also,
1563 sets smoother equal to the TRESmoother that goes with point0 in conditionalMap
1564 in order to speed up processing in the function that calls us.
1565 */
getConditionalLine(TREConditionalMap & conditionalMap,const TREVertex point0,const TREVertex point1,TRESmoother * & smoother)1566 int TREModel::getConditionalLine(TREConditionalMap &conditionalMap,
1567 const TREVertex point0, const TREVertex point1,
1568 TRESmoother *&smoother)
1569 {
1570 int i;
1571 int count;
1572
1573 if (!smoother)
1574 {
1575 TREVertexKey pointKey(point0);
1576 TREConditionalMap::iterator it = conditionalMap.find(pointKey);
1577
1578 if (it == conditionalMap.end())
1579 {
1580 return -1;
1581 }
1582 else
1583 {
1584 smoother = &(*it).second;
1585 }
1586 }
1587 count = smoother->getVertexCount();
1588 for (i = 0; i < count; i++)
1589 {
1590 // Note that by definition point0 will match the start point of the
1591 // smoother, so there's no need to check.
1592 if (smoother->getVertex(i).approxEquals(point1, 0.01f))
1593 {
1594 return i;
1595 }
1596 }
1597 return -1;
1598 }
1599
1600 /*
1601 This function fills edgeMap with all the edge lines, checking the points at each
1602 end of each conditional line, and then creating an entry for the smaller point,
1603 inserting the other point into the set of points that is the value. When looking
1604 up points later, the smaller point is always used as the key for the lookup.
1605 */
fillEdgeMap(TREEdgeMap & edgeMap)1606 void TREModel::fillEdgeMap(TREEdgeMap &edgeMap)
1607 {
1608 fillEdgeMap(edgeMap, m_shapes[TREMEdgeLines]);
1609 fillEdgeMap(edgeMap, m_coloredShapes[TREMEdgeLines]);
1610 }
1611
fillEdgeMap(TREEdgeMap & edgeMap,TREShapeGroup * shapeGroup)1612 void TREModel::fillEdgeMap(TREEdgeMap &edgeMap, TREShapeGroup *shapeGroup)
1613 {
1614 if (shapeGroup)
1615 {
1616 TCULongArray *indices = shapeGroup->getIndices(TRESLine);
1617
1618 if (indices)
1619 {
1620 int i;
1621 int count = indices->getCount();
1622 TREVertexArray *vertices =
1623 shapeGroup->getVertexStore()->getVertices();
1624
1625 // Note there are 2 indices per edge line; hence the += 2.
1626 for (i = 0; i < count; i += 2)
1627 {
1628 int index0 = (*indices)[i];
1629 int index1 = (*indices)[i + 1];
1630 const TREVertex &vertex0 = vertices->vertexAtIndex(index0);
1631 const TREVertex &vertex1 = vertices->vertexAtIndex(index1);
1632 TREVertexKey vertex0Key(vertex0);
1633 TREVertexKey vertex1Key(vertex1);
1634
1635 if (vertex0Key < vertex1Key)
1636 {
1637 edgeMap[vertex0Key].insert(vertex1Key);
1638 }
1639 else if (vertex1Key < vertex0Key)
1640 {
1641 edgeMap[vertex1Key].insert(vertex0Key);
1642 }
1643 else
1644 {
1645 TCVector length = TCVector(vertex0.v) - TCVector(vertex1.v);
1646
1647 debugPrintf(2, "Edge too short to map: %f.\n",
1648 length.length());
1649 }
1650 }
1651 }
1652 }
1653 }
1654
findEdge(const TREEdgeMap & edgeMap,const TREVertexKey & vertex0Key,const TREVertexKey & vertex1Key)1655 bool TREModel::findEdge(const TREEdgeMap& edgeMap,
1656 const TREVertexKey& vertex0Key,
1657 const TREVertexKey& vertex1Key)
1658 {
1659 if (vertex1Key < vertex0Key)
1660 {
1661 // edgeMap only contains keys for the lesser of each vertex pair.
1662 return findEdge(edgeMap, vertex1Key, vertex0Key);
1663 }
1664 else
1665 {
1666 TREEdgeMap::const_iterator it0 = edgeMap.find(vertex0Key);
1667 if (it0 != edgeMap.end())
1668 {
1669 TREVertexKeySet::const_iterator it1 = it0->second.find(vertex1Key);
1670 if (it1 != it0->second.end()) {
1671 return true;
1672 }
1673 }
1674 }
1675 return false;
1676 }
1677
1678 /*
1679 This function fills conditionalMap with all the conditional lines, using the
1680 points at each end of each conditional line as keys in the tree. This means
1681 that each conditional line will go into the tree twice.
1682 */
fillConditionalMap(TREConditionalMap & conditionalMap,const TREEdgeMap & edgeMap)1683 void TREModel::fillConditionalMap(TREConditionalMap &conditionalMap,
1684 const TREEdgeMap& edgeMap)
1685 {
1686 fillConditionalMap(conditionalMap, edgeMap, m_shapes[TREMConditionalLines]);
1687 fillConditionalMap(conditionalMap, edgeMap,
1688 m_coloredShapes[TREMConditionalLines]);
1689 }
1690
fillConditionalMap(TREConditionalMap & conditionalMap,const TREEdgeMap & edgeMap,TREShapeGroup * shapeGroup)1691 void TREModel::fillConditionalMap(TREConditionalMap &conditionalMap,
1692 const TREEdgeMap& edgeMap,
1693 TREShapeGroup *shapeGroup)
1694 {
1695 if (shapeGroup)
1696 {
1697 TCULongArray *indices = shapeGroup->getIndices(TRESConditionalLine);
1698
1699 if (indices)
1700 {
1701 int i;
1702 int count = indices->getCount();
1703 TREVertexArray *vertices =
1704 shapeGroup->getVertexStore()->getVertices();
1705
1706 // Note there are 2 indices per conditional line; hence the += 2.
1707 for (i = 0; i < count; i += 2)
1708 {
1709 int index0 = (*indices)[i];
1710 int index1 = (*indices)[i + 1];
1711 const TREVertex &vertex0 = vertices->vertexAtIndex(index0);
1712 const TREVertex &vertex1 = vertices->vertexAtIndex(index1);
1713 TREVertexKey vertex0Key(vertex0);
1714 TREVertexKey vertex1Key(vertex1);
1715
1716 if (vertex0Key < vertex1Key || vertex1Key < vertex0Key)
1717 {
1718 if (findEdge(edgeMap, vertex0Key, vertex1Key))
1719 {
1720 // Ignore conditional lines that overlap edge lines.
1721 continue;
1722 }
1723 // Add the conditional line to the map using its first point
1724 // as the key in the map.
1725 addConditionalPoint(conditionalMap, vertices, index0,
1726 index1, vertex0Key);
1727 // Add the conditional line to the map using its second point
1728 // as the key in the map.
1729 addConditionalPoint(conditionalMap, vertices, index1,
1730 index0, vertex1Key);
1731 }
1732 else
1733 {
1734 TCVector length = TCVector(vertex0.v) - TCVector(vertex1.v);
1735
1736 debugPrintf(2, "Conditional too short to map: %f.\n",
1737 length.length());
1738 }
1739 }
1740 }
1741 }
1742 }
1743
1744 /*
1745 This function adds the line between index0 and index1 to conditionalMap, using
1746 the point at index0 as its key in the map.
1747 */
addConditionalPoint(TREConditionalMap & conditionalMap,const TREVertexArray * vertices,int index0,int index1,const TREVertexKey & vertexKey)1748 void TREModel::addConditionalPoint(TREConditionalMap &conditionalMap,
1749 const TREVertexArray *vertices, int index0,
1750 int index1, const TREVertexKey &vertexKey)
1751 {
1752 TREConditionalMap::iterator it = conditionalMap.find(vertexKey);
1753
1754 if (it == conditionalMap.end())
1755 {
1756 // Note that this would probably be more clear if we used the []
1757 // operator of map. However, that would require extra lookups, and
1758 // we're trying to keep the lookups to a minimum.
1759 TREConditionalMap::value_type newValue(vertexKey,
1760 TRESmoother(vertices->vertexAtIndex(index0)));
1761
1762 // The insert function returns a pair, where the first of the pair is
1763 // an iterator pointing to the newly inserted item, and the second of
1764 // the pair is a boolean saying whether or not an insertion occurred.
1765 // Since we got here, we know the item doesn't already exist, so we
1766 // really don't care about the second of the pair.
1767 it = conditionalMap.insert(newValue).first;
1768 }
1769 // If the item didn't originally exist, it gets set during insertion above.
1770 // If the item did exist, it's set in the find() call. Note that not all
1771 // the vertices that match are necessarily equal. However, this won't
1772 // effect the results.
1773 (*it).second.addVertex(vertices->vertexAtIndex(index1));
1774 }
1775
scaleConditionalControlPoint(int index,int cpIndex,TREVertexArray * vertices)1776 void TREModel::scaleConditionalControlPoint(
1777 int index,
1778 int cpIndex,
1779 TREVertexArray *vertices)
1780 {
1781 const TREVertex &vertex = (*vertices)[index];
1782 TREVertex &cpVertex = (*vertices)[cpIndex];
1783 TCVector p1(vertex.v[0], vertex.v[1], vertex.v[2]);
1784 TCVector p2(cpVertex.v[0], cpVertex.v[1], cpVertex.v[2]);
1785 TCVector delta = p2 - p1;
1786
1787 p2 = p1 + delta / delta.length();
1788 cpVertex.v[0] = p2[0];
1789 cpVertex.v[1] = p2[1];
1790 cpVertex.v[2] = p2[2];
1791 }
1792
scaleConditionalControlPoints(TREShapeGroup * shapeGroup)1793 void TREModel::scaleConditionalControlPoints(TREShapeGroup *shapeGroup)
1794 {
1795 // If a conditional line's control points are outside the view frustum
1796 // while the conditional line itself is inside, it sometimes gets drawn
1797 // when it's not supposed to be. This doesn't really fix that problem, but
1798 // by pulling the control points closer to the line, it makes it much less
1799 // likely to occur.
1800 if (shapeGroup != NULL)
1801 {
1802 TCULongArray *indices = shapeGroup->getIndices(TRESConditionalLine);
1803 TCULongArray *cpIndices = shapeGroup->getControlPointIndices();
1804 TREVertexArray *vertices = shapeGroup->getVertexStore()->getVertices();
1805
1806 if (indices != NULL && cpIndices != NULL)
1807 {
1808 for (int i = 0; i < indices->getCount(); i += 2)
1809 {
1810 scaleConditionalControlPoint((*indices)[i], (*cpIndices)[i],
1811 vertices);
1812 scaleConditionalControlPoint((*indices)[i], (*cpIndices)[i + 1],
1813 vertices);
1814 }
1815 }
1816 }
1817 }
1818
flatten(void)1819 void TREModel::flatten(void)
1820 {
1821 if (m_subModels && m_subModels->getCount() &&
1822 !m_mainModel->getShowAllConditionalFlag())
1823 {
1824 flatten(this, TCVector::getIdentityMatrix(), 0, false, 0, false, false);
1825 if (m_subModels)
1826 {
1827 m_subModels->removeAll();
1828 }
1829 scaleConditionalControlPoints(m_shapes[TREMConditionalLines]);
1830 scaleConditionalControlPoints(m_coloredShapes[TREMConditionalLines]);
1831 m_flags.flattened = true;
1832 }
1833 }
1834
flatten(TREModel * model,const TCFloat * matrix,TCULong color,bool colorSet,TCULong edgeColor,bool edgeColorSet,bool includeShapes,bool skipTexmapped)1835 void TREModel::flatten(
1836 TREModel *model,
1837 const TCFloat *matrix,
1838 TCULong color,
1839 bool colorSet,
1840 TCULong edgeColor,
1841 bool edgeColorSet,
1842 bool includeShapes,
1843 bool skipTexmapped /*= false*/)
1844 {
1845 skipTexmapped = false;
1846 TRESubModelArray *subModels = model->m_subModels;
1847
1848 if (includeShapes)
1849 {
1850 int i;
1851
1852 for (i = 0; i <= TREMLast; i++)
1853 {
1854 TREShapeGroup *otherShapeGroup = model->m_shapes[i];
1855 TREColoredShapeGroup *otherColoredShapeGroup =
1856 model->m_coloredShapes[i];
1857
1858 if (otherShapeGroup)
1859 {
1860 bool actualColorSet = colorSet;
1861 TCULong actualColor = color;
1862
1863 if (i == TREMEdgeLines || i == TREMConditionalLines)
1864 {
1865 actualColorSet = edgeColorSet;
1866 actualColor = edgeColor;
1867 }
1868 if (actualColorSet)
1869 {
1870 TREColoredShapeGroup *coloredShapeGroup;
1871
1872 setupColored((TREMSection)i);
1873 coloredShapeGroup = m_coloredShapes[i];
1874 coloredShapeGroup->getVertexStore()->setupColored();
1875 if (i == TREMStud || i == TREMStudBFC)
1876 {
1877 coloredShapeGroup->getVertexStore()->setupTextured();
1878 }
1879 coloredShapeGroup->flatten(otherShapeGroup, matrix,
1880 actualColor, true, skipTexmapped);
1881 }
1882 else
1883 {
1884 TREShapeGroup *shapeGroup;
1885
1886 setup((TREMSection)i);
1887 shapeGroup = m_shapes[i];
1888 if (i == TREMStud || i == TREMStudBFC)
1889 {
1890 shapeGroup->getVertexStore()->setupTextured();
1891 }
1892 shapeGroup->flatten(otherShapeGroup, matrix, 0, false,
1893 skipTexmapped);
1894 }
1895 }
1896 if (otherColoredShapeGroup)
1897 {
1898 setupColored((TREMSection)i);
1899 m_coloredShapes[i]->flatten(otherColoredShapeGroup, matrix, 0,
1900 false, skipTexmapped);
1901 }
1902 }
1903 }
1904 if (subModels)
1905 {
1906 int i;
1907 int count = subModels->getCount();
1908 TCFloat newMatrix[16];
1909
1910 for (i = 0; i < count; i++)
1911 {
1912 TRESubModel *subModel = (*subModels)[i];
1913 bool subSkipTexmapped = skipTexmapped;
1914
1915 // Note: when curve smoothing is enabled, texmapped geometry is
1916 // removed while the updated normals are being transferred. It
1917 // cannot be removed here during the flatten, because then it won't
1918 // be smoothed.
1919 if (subModel->getTransferredFlag() &&
1920 !m_mainModel->getSmoothCurvesFlag())
1921 {
1922 subSkipTexmapped = true;
1923 }
1924 TCVector::multMatrix(matrix, subModel->getMatrix(), newMatrix);
1925 if (subModel->isColorSet())
1926 {
1927 flatten(subModel->getEffectiveModel(), newMatrix,
1928 htonl(subModel->getColor()), true,
1929 htonl(subModel->getEdgeColor()), true, true,
1930 subSkipTexmapped);
1931 }
1932 else
1933 {
1934 flatten(subModel->getEffectiveModel(), newMatrix, color,
1935 colorSet, edgeColor, edgeColorSet, true,
1936 subSkipTexmapped);
1937 }
1938 }
1939 }
1940 }
1941
setGlNormalize(bool value)1942 void TREModel::setGlNormalize(bool value)
1943 {
1944 if (value)
1945 {
1946 // Note: GL_RESCALE_NORMAL doesn't seem to work.
1947 glEnable(GL_NORMALIZE);
1948 }
1949 else
1950 {
1951 glDisable(GL_NORMALIZE);
1952 }
1953 }
1954
addSlopedCylinder(const TCVector & center,TCFloat radius,TCFloat height,int numSegments,int usedSegments,bool bfc)1955 void TREModel::addSlopedCylinder(const TCVector& center, TCFloat radius,
1956 TCFloat height, int numSegments,
1957 int usedSegments, bool bfc)
1958 {
1959 int vertexCount;
1960 TCVector *points;
1961 TCVector *normals;
1962 int i;
1963 TCVector top = center;
1964 TCVector normal = TCVector(0.0f, 1.0f, 0.0f);
1965
1966 if (usedSegments == -1)
1967 {
1968 usedSegments = numSegments;
1969 }
1970 vertexCount = usedSegments * 2 + 2;
1971 points = new TCVector[vertexCount];
1972 normals = new TCVector[vertexCount];
1973 for (i = 0; i <= usedSegments; i++)
1974 {
1975 TCFloat angle;
1976
1977 angle = 2.0f * (TCFloat)M_PI / numSegments * i;
1978 setCirclePoint(angle, radius, center, points[i * 2]);
1979 top[1] =
1980 center.get(1) + height - ((height / radius) * points[i * 2][0]);
1981 setCirclePoint(angle, radius, top, points[i * 2 + 1]);
1982 if (height == 0.0f)
1983 {
1984 normals[i * 2] = normal;
1985 normals[i * 2 + 1] = normal;
1986 }
1987 else
1988 {
1989 normals[i * 2] = (points[i * 2] - center).normalize();
1990 normals[i * 2 + 1] =
1991 (points[i * 2 + 1] - top).normalize();
1992 }
1993 }
1994 if (bfc)
1995 {
1996 addBFCQuadStrip(points, normals, vertexCount);
1997 }
1998 else
1999 {
2000 addQuadStrip(points, normals, vertexCount);
2001 }
2002 if (shouldLoadConditionalLines() && !fEq(height, 0.0f))
2003 {
2004 addOpenConeConditionals(points, numSegments, usedSegments);
2005 }
2006 delete[] points;
2007 delete[] normals;
2008 }
2009
addSlopedCylinder2(const TCVector & center,TCFloat radius,TCFloat height,int numSegments,int usedSegments,bool bfc)2010 void TREModel::addSlopedCylinder2(const TCVector& center, TCFloat radius,
2011 TCFloat height, int numSegments,
2012 int usedSegments, bool bfc)
2013 {
2014 int vertexCount;
2015 TCVector *points;
2016 TCVector *normals;
2017 int i;
2018 TCVector top = center;
2019 TCVector normal = TCVector(0.0f, 1.0f, 0.0f);
2020
2021 if (usedSegments == -1)
2022 {
2023 usedSegments = numSegments;
2024 }
2025 vertexCount = usedSegments * 2 + 2;
2026 points = new TCVector[vertexCount];
2027 normals = new TCVector[vertexCount];
2028 for (i = 0; i <= usedSegments; i++)
2029 {
2030 TCFloat angle;
2031
2032 angle = 2.0f * (TCFloat)M_PI / numSegments * i + (TCFloat)M_PI / 2.0f;
2033 setCirclePoint(angle, radius, center, points[i * 2]);
2034 top[1] = myabs(points[i * 2][0]);
2035 setCirclePoint(angle, radius, top, points[i * 2 + 1]);
2036 if (height == 0.0f)
2037 {
2038 normals[i * 2] = normal;
2039 normals[i * 2 + 1] = normal;
2040 }
2041 else
2042 {
2043 normals[i * 2] = (points[i * 2] - center).normalize();
2044 normals[i * 2 + 1] =
2045 (points[i * 2 + 1] - top).normalize();
2046 }
2047 }
2048 if (bfc)
2049 {
2050 addBFCQuadStrip(points, normals, vertexCount);
2051 }
2052 else
2053 {
2054 addQuadStrip(points, normals, vertexCount);
2055 }
2056 if (shouldLoadConditionalLines() && !fEq(height, 0.0f))
2057 {
2058 addSlopedCylinder2Conditionals(points, numSegments, usedSegments);
2059 }
2060 delete[] points;
2061 delete[] normals;
2062 }
2063
addCylinder(const TCVector & center,TCFloat radius,TCFloat height,int numSegments,int usedSegments,bool bfc,TCULong color,TCULong edgeColor)2064 void TREModel::addCylinder(
2065 const TCVector& center,
2066 TCFloat radius,
2067 TCFloat height,
2068 int numSegments,
2069 int usedSegments,
2070 bool bfc,
2071 TCULong color,
2072 TCULong edgeColor)
2073 {
2074 addOpenCone(center, radius, radius, height, numSegments, usedSegments, bfc,
2075 color, edgeColor);
2076 }
2077
addStudDisc(const TCVector & center,TCFloat radius,int numSegments,int usedSegments,bool bfc)2078 void TREModel::addStudDisc(const TCVector ¢er, TCFloat radius,
2079 int numSegments, int usedSegments, bool bfc)
2080 {
2081 addDisc(center, radius, numSegments, usedSegments, bfc,
2082 m_mainModel->getStudLogoFlag());
2083 }
2084
genStudTextureCoords(TCVector * textureCoords,int vertexCount)2085 void TREModel::genStudTextureCoords(TCVector *textureCoords, int vertexCount)
2086 {
2087 int i;
2088 TCVector p1;
2089 TCVector offset = TCVector(0.5f, 0.5f, 0.0f);
2090 int numSegments = vertexCount - 2;
2091
2092 textureCoords[0] = TCVector(0.5f, 0.5f, 0.0f);
2093 for (i = 1; i < vertexCount; i++)
2094 {
2095 TCFloat x, z;
2096 TCFloat angle;
2097
2098 angle = 2.0f * (TCFloat)M_PI / numSegments * (i - 1);
2099 x = (TCFloat)cos(angle) * 0.5f;
2100 z = (TCFloat)sin(angle) * 0.5f;
2101 p1[0] = z;
2102 p1[1] = x;
2103 p1 += offset;
2104 p1[1] = 1.0f - p1[1];
2105 textureCoords[i] = p1;
2106 }
2107 }
2108
addChrd(const TCVector & center,TCFloat radius,int numSegments,int usedSegments,bool bfc)2109 void TREModel::addChrd(const TCVector ¢er, TCFloat radius, int numSegments,
2110 int usedSegments, bool bfc)
2111 {
2112 int vertexCount;
2113 TCVector *points;
2114 TCVector *normals;
2115 int i;
2116 TCVector normal = TCVector(0.0f, -1.0f, 0.0f);
2117
2118 if (usedSegments == -1)
2119 {
2120 usedSegments = numSegments;
2121 }
2122 vertexCount = usedSegments + 1;
2123 points = new TCVector[vertexCount];
2124 normals = new TCVector[vertexCount];
2125 for (i = 0; i <= usedSegments; i++)
2126 {
2127 TCFloat angle;
2128
2129 angle = 2.0f * (TCFloat)M_PI / numSegments * i;
2130 setCirclePoint(angle, radius, center, points[i]);
2131 normals[i] = normal;
2132 }
2133 if (bfc)
2134 {
2135 addBFCTriangleFan(points, normals, NULL, vertexCount, true);
2136 }
2137 else
2138 {
2139 addTriangleFan(points, normals, NULL, vertexCount, true);
2140 }
2141 delete[] points;
2142 delete[] normals;
2143 }
2144
addDisc(const TCVector & center,TCFloat radius,int numSegments,int usedSegments,bool bfc,bool stud)2145 void TREModel::addDisc(const TCVector ¢er, TCFloat radius, int numSegments,
2146 int usedSegments, bool bfc, bool stud)
2147 {
2148 int vertexCount;
2149 TCVector *points;
2150 TCVector *normals;
2151 TCVector *textureCoords = NULL;
2152 int i;
2153 TCVector normal = TCVector(0.0f, -1.0f, 0.0f);
2154
2155 if (usedSegments == -1)
2156 {
2157 usedSegments = numSegments;
2158 }
2159 vertexCount = usedSegments + 2;
2160 points = new TCVector[vertexCount];
2161 normals = new TCVector[vertexCount];
2162 points[0] = center;
2163 normals[0] = normal;
2164 for (i = 0; i <= usedSegments; i++)
2165 {
2166 TCFloat angle;
2167
2168 angle = 2.0f * (TCFloat)M_PI / numSegments * i;
2169 setCirclePoint(angle, radius, center, points[i + 1]);
2170 normals[i + 1] = normal;
2171 }
2172 if (stud && TREMainModel::getStudTextures())
2173 {
2174 textureCoords = new TCVector[vertexCount];
2175 genStudTextureCoords(textureCoords, vertexCount);
2176 }
2177 if (bfc)
2178 {
2179 addBFCTriangleFan(points, normals, textureCoords, vertexCount, true);
2180 }
2181 else
2182 {
2183 addTriangleFan(points, normals, textureCoords, vertexCount, true);
2184 }
2185 delete[] points;
2186 delete[] normals;
2187 delete[] textureCoords;
2188 }
2189
addNotDisc(const TCVector & center,TCFloat radius,int numSegments,int usedSegments,bool bfc)2190 void TREModel::addNotDisc(
2191 const TCVector ¢er,
2192 TCFloat radius,
2193 int numSegments,
2194 int usedSegments,
2195 bool bfc)
2196 {
2197 int quarter = numSegments / 4;
2198 int numQuarters;
2199 int i, j;
2200 TCVector normal = TCVector(0.0f, -1.0f, 0.0f);
2201 TCVector p1;
2202
2203 if (usedSegments == -1)
2204 {
2205 usedSegments = numSegments;
2206 }
2207 numQuarters = (usedSegments + quarter - 1) / quarter;
2208 for (i = 0; i < numQuarters; i++)
2209 {
2210 TCVector *points;
2211 TCVector *normals;
2212 int vertexCount;
2213 int quarterSegments = quarter;
2214 TCFloat zMult = 1.0f;
2215 TCFloat xMult = 1.0f;
2216
2217 if (i >= 2)
2218 {
2219 zMult = -1.0f;
2220 }
2221 if (i == 1 || i == 2)
2222 {
2223 xMult = -1.0f;
2224 }
2225 if (i == numQuarters - 1)
2226 {
2227 quarterSegments = usedSegments % quarter;
2228 if (!quarterSegments)
2229 {
2230 quarterSegments = quarter;
2231 }
2232 }
2233 vertexCount = quarterSegments + 2;
2234 points = new TCVector[vertexCount];
2235 normals = new TCVector[vertexCount];
2236 points[0] = center + TCVector(xMult * radius, 0.0f, zMult * radius);
2237 normals[0] = normal;
2238 for (j = 0; j <= quarterSegments; j++)
2239 {
2240 TCFloat x, z;
2241 TCFloat angle;
2242
2243 angle = 2.0f * (TCFloat)M_PI / numSegments * (j + i * quarter);
2244 x = radius * (TCFloat)cos(angle);
2245 z = radius * (TCFloat)sin(angle);
2246 p1[0] = center.get(0) + x;
2247 p1[2] = center.get(2) + z;
2248 p1[1] = center.get(1);
2249 points[quarterSegments - j + 1] = p1;
2250 normals[quarterSegments - j + 1] = normal;
2251 }
2252 if (bfc)
2253 {
2254 addBFCTriangleFan(points, normals, NULL, vertexCount, true);
2255 }
2256 else
2257 {
2258 addTriangleFan(points, normals, NULL, vertexCount, true);
2259 }
2260 delete[] points;
2261 delete[] normals;
2262 }
2263 }
2264
addTangent(const TCVector & center,TCFloat radius,int numSegments,int usedSegments,bool bfc)2265 void TREModel::addTangent(
2266 const TCVector ¢er,
2267 TCFloat radius,
2268 int numSegments,
2269 int usedSegments,
2270 bool bfc)
2271 {
2272 int quarter = numSegments / 4;
2273 int trianglesPerChunk = quarter / 4;
2274 int numQuarters;
2275 int i, j;
2276
2277 if (usedSegments == -1)
2278 {
2279 usedSegments = numSegments;
2280 }
2281 numQuarters = (usedSegments + quarter - 1) / quarter;
2282 TCVector points[3];
2283 TCVector normals[3] =
2284 {
2285 TCVector(0.0f, -1.0f, 0.0f),
2286 TCVector(0.0f, -1.0f, 0.0f),
2287 TCVector(0.0f, -1.0f, 0.0f)
2288 };
2289 for (i = 0; i < numQuarters; i++)
2290 {
2291 int quarterSegments = quarter;
2292 TCFloat zMult = 1.0f;
2293 TCFloat xMult = 1.0f;
2294
2295 if (i >= 2)
2296 {
2297 zMult = -1.0f;
2298 }
2299 if (i == 1 || i == 2)
2300 {
2301 xMult = -1.0f;
2302 }
2303 TCVector corners[4] =
2304 {
2305 TCVector(1.0 * xMult, 0.0, 0.1989 * zMult),
2306 TCVector(0.8478 * xMult, 0.0, 0.5665 * zMult),
2307 TCVector(0.5665 * xMult, 0.0, 0.8478 * zMult),
2308 TCVector(0.1989 * xMult, 0.0, 1.0 * zMult)
2309 };
2310 if (i == numQuarters - 1)
2311 {
2312 quarterSegments = usedSegments % quarter;
2313 if (!quarterSegments)
2314 {
2315 quarterSegments = quarter;
2316 }
2317 }
2318 for (j = 0; j < quarterSegments; j++)
2319 {
2320 points[0] = center + corners[j / trianglesPerChunk];
2321 TCFloat x, z;
2322 TCFloat angle;
2323 int angleIndex1 = j + 1;
2324 int angleIndex2 = j;
2325
2326 if (i == 1 || i == 3)
2327 {
2328 angleIndex1 = quarterSegments - j;
2329 angleIndex2 = quarterSegments - j - 1;
2330 }
2331 angle = 2.0f * (TCFloat)M_PI / numSegments * (angleIndex1 + i * quarter);
2332 x = radius * (TCFloat)cos(angle);
2333 z = radius * (TCFloat)sin(angle);
2334 points[1][0] = center.get(0) + x;
2335 points[1][2] = center.get(2) + z;
2336 points[1][1] = center.get(1);
2337 angle = 2.0f * (TCFloat)M_PI / numSegments * (angleIndex2 + i * quarter);
2338 x = radius * (TCFloat)cos(angle);
2339 z = radius * (TCFloat)sin(angle);
2340 points[2][0] = center.get(0) + x;
2341 points[2][2] = center.get(2) + z;
2342 points[2][1] = center.get(1);
2343 if (bfc)
2344 {
2345 addBFCTriangle(points, normals);
2346 }
2347 else
2348 {
2349 addTriangle(points, normals);
2350 }
2351 }
2352 }
2353 }
2354
setCirclePoint(TCFloat angle,TCFloat radius,const TCVector & center,TCVector & point)2355 void TREModel::setCirclePoint(
2356 TCFloat angle,
2357 TCFloat radius,
2358 const TCVector& center,
2359 TCVector& point)
2360 {
2361 TCFloat x1, z1;
2362
2363 x1 = radius * (TCFloat)cos(angle);
2364 z1 = radius * (TCFloat)sin(angle);
2365 point[0] = center.get(0) + x1;
2366 point[1] = center.get(1);
2367 point[2] = center.get(2) + z1;
2368 }
2369
addCone(const TCVector & center,TCFloat radius,TCFloat height,int numSegments,int usedSegments,bool bfc,TCULong color,TCULong edgeColor)2370 void TREModel::addCone(
2371 const TCVector ¢er,
2372 TCFloat radius,
2373 TCFloat height,
2374 int numSegments,
2375 int usedSegments,
2376 bool bfc,
2377 TCULong color,
2378 TCULong edgeColor)
2379 {
2380 int i;
2381 TCVector top = center;
2382 TCVector p1, p2, p3;
2383 TCVector linePoints[2];
2384 TCVector controlPoints[2];
2385 TCVector *points = new TCVector[3];
2386 TCVector *normals = new TCVector[3];
2387 TCVector tri0Cross;
2388 TCVector tri1Cross;
2389 TCVector tri2Cross;
2390 int axis1 = 2;
2391
2392 if (usedSegments == -1)
2393 {
2394 usedSegments = numSegments;
2395 }
2396 top[1] += height;
2397 points[2] = top;
2398 for (i = 0; i < usedSegments; i++)
2399 {
2400 TCFloat angle0, angle1, angle2, angle3;
2401
2402 angle0 = 2.0f * (TCFloat)M_PI / numSegments * (i - 1);
2403 angle1 = 2.0f * (TCFloat)M_PI / numSegments * i;
2404 angle2 = 2.0f * (TCFloat)M_PI / numSegments * (i + 1);
2405 angle3 = 2.0f * (TCFloat)M_PI / numSegments * (i + 2);
2406 setCirclePoint(angle1, radius, center, p1);
2407 setCirclePoint(angle2, radius, center, p2);
2408 points[0] = p2;
2409 points[1] = p1;
2410 if (i == 0)
2411 {
2412 setCirclePoint(angle0, radius, center, p3);
2413 tri0Cross = (p3 - top) * (p3 - p1);
2414 tri1Cross = (p1 - top) * (p1 - p2);
2415 if (shouldLoadConditionalLines())
2416 {
2417 linePoints[0] = p1;
2418 linePoints[1] = top;
2419 controlPoints[0] = p1;
2420 controlPoints[0][axis1] -= 1.0f;
2421 controlPoints[1] = p2;
2422 addConditionalLine(linePoints, controlPoints, edgeColor);
2423 }
2424 }
2425 else
2426 {
2427 tri0Cross = tri1Cross;
2428 tri1Cross = tri2Cross;
2429 }
2430 normals[1] = tri1Cross + tri0Cross;
2431 normals[1].normalize();
2432 setCirclePoint(angle3, radius, center, p3);
2433 if (shouldLoadConditionalLines())
2434 {
2435 linePoints[0] = p2;
2436 linePoints[1] = top;
2437 controlPoints[0] = p1;
2438 if (i == usedSegments - 1)
2439 {
2440 controlPoints[1] = p2;
2441 calcTangentControlPoint(controlPoints[1], i + 1, numSegments);
2442 }
2443 else
2444 {
2445 controlPoints[1] = p3;
2446 }
2447 addConditionalLine(linePoints, controlPoints, edgeColor);
2448 }
2449 tri2Cross = (p2 - top) * (p2 - p3);
2450 normals[0] = tri2Cross + tri1Cross;
2451 normals[0].normalize();
2452 normals[2] = tri1Cross;
2453 normals[2].normalize();
2454 if (bfc)
2455 {
2456 if (color == 0)
2457 {
2458 addBFCTriangle(points, normals);
2459 }
2460 else
2461 {
2462 addBFCTriangle(color, points, normals);
2463 }
2464 }
2465 else
2466 {
2467 if (color == 0)
2468 {
2469 addTriangle(points, normals);
2470 }
2471 else
2472 {
2473 addTriangle(color, points, normals);
2474 }
2475 }
2476 }
2477 delete[] points;
2478 delete[] normals;
2479 }
2480
calcIntersection(int i,int j,int num,TCVector * zeroXPoints,TCVector * zeroYPoints,TCVector * zeroZPoints)2481 TCVector TREModel::calcIntersection(int i, int j, int num,
2482 TCVector* zeroXPoints,
2483 TCVector* zeroYPoints,
2484 TCVector* zeroZPoints)
2485 {
2486 TCVector temp1, temp2, temp3, temp4, temp5, temp6;
2487 TCVector p1, p2, p3;
2488
2489 if (i + j == num)
2490 {
2491 return zeroXPoints[j];
2492 }
2493 else if (i == 0)
2494 {
2495 return zeroZPoints[num - j];
2496 }
2497 else if (j == 0)
2498 {
2499 return zeroYPoints[i];
2500 }
2501 temp1 = zeroYPoints[i];
2502 temp2 = zeroXPoints[num - i];
2503 temp3 = zeroZPoints[num - j];
2504 temp4 = zeroXPoints[j];
2505 temp5 = zeroYPoints[i + j];
2506 temp6 = zeroZPoints[num - i - j];
2507 return (temp1 + temp2 + temp3 + temp4 + temp5 + temp6 -
2508 zeroXPoints[0] - zeroYPoints[0] - zeroZPoints[0]) / 9.0f;
2509 }
2510
addTorusIO(bool inner,const TCVector & center,TCFloat yRadius,TCFloat xzRadius,int numSegments,int usedSegments,int minorSegments,bool bfc)2511 void TREModel::addTorusIO(bool inner, const TCVector& center, TCFloat yRadius,
2512 TCFloat xzRadius, int numSegments, int usedSegments,
2513 int minorSegments, bool bfc)
2514 {
2515 int i, j;
2516 TCVector p1, p2;
2517 TCVector top = center;
2518 int ySegments = minorSegments / 4;
2519 TCVector *points;
2520 TCVector *stripPoints;
2521 TCVector *stripNormals;
2522 int spot;
2523 int stripSize = (ySegments + 1) * 2;
2524
2525 points = new TCVector[(ySegments + 1) * (usedSegments + 1)];
2526 stripPoints = new TCVector[stripSize];
2527 stripNormals = new TCVector[stripSize];
2528 for (i = 0; i <= usedSegments; i++)
2529 {
2530 TCFloat xzAngle; // Angle in the xz plane
2531
2532 xzAngle = 2.0f * (TCFloat)M_PI / numSegments * i;
2533 for (j = 0; j <= ySegments; j++)
2534 {
2535 TCFloat yAngle; // Angle above the xz plane
2536 TCFloat currentRadius;
2537
2538 if (inner)
2539 {
2540 yAngle = (TCFloat)M_PI - 2.0f * (TCFloat)M_PI /
2541 minorSegments * j;
2542 }
2543 else
2544 {
2545 yAngle = 2.0f * (TCFloat)M_PI / minorSegments * j;
2546 }
2547 top[1] = xzRadius * (TCFloat)sin(yAngle) + center.get(1);
2548 currentRadius = xzRadius * (TCFloat)cos(yAngle) + yRadius;
2549 setCirclePoint(xzAngle, currentRadius, top, p1);
2550 points[i * (ySegments + 1) + j] = p1;
2551 }
2552 }
2553 top = center;
2554 for (i = 0; i < usedSegments; i++)
2555 {
2556 TCFloat xzAngle; // Angle in the xz plane
2557 int ofs1 = 1;
2558 int ofs2 = 0;
2559
2560 if (inner)
2561 {
2562 ofs1 = 0;
2563 ofs2 = 1;
2564 }
2565
2566 xzAngle = 2.0f * (TCFloat)M_PI / numSegments * (i + ofs2);
2567 setCirclePoint(xzAngle, yRadius, top, p1);
2568 xzAngle = 2.0f * (TCFloat)M_PI / numSegments * (i + ofs1);
2569 setCirclePoint(xzAngle, yRadius, top, p2);
2570 spot = 0;
2571 for (j = 0; j <= ySegments; j++)
2572 {
2573 stripPoints[spot] = points[(i + ofs1) * (ySegments + 1) + j];
2574 stripNormals[spot] = (stripPoints[spot] - p2).normalize();
2575 spot++;
2576 stripPoints[spot] = points[(i + ofs2) * (ySegments + 1) + j];
2577 stripNormals[spot] = (stripPoints[spot] - p1).normalize();
2578 spot++;
2579 }
2580 if (m_mainModel->getSmoothCurvesFlag())
2581 {
2582 m_mainModel->setDisableStrips(true);
2583 }
2584 if (bfc)
2585 {
2586 addBFCQuadStrip(stripPoints, stripNormals, stripSize);
2587 }
2588 else
2589 {
2590 addQuadStrip(stripPoints, stripNormals, stripSize);
2591 }
2592 m_mainModel->setDisableStrips(false);
2593 }
2594 if (shouldLoadConditionalLines())
2595 {
2596 addTorusIOConditionals(inner, points, numSegments, usedSegments,
2597 minorSegments, center, yRadius, xzRadius);
2598 }
2599 delete[] stripPoints;
2600 delete[] stripNormals;
2601 delete[] points;
2602 }
2603
addTorusIOConditionals(bool inner,TCVector * points,int numSegments,int usedSegments,int minorSegments,const TCVector & center,TCFloat radius,TCFloat height)2604 void TREModel::addTorusIOConditionals(bool inner, TCVector *points,
2605 int numSegments, int usedSegments,
2606 int minorSegments, const TCVector& center,
2607 TCFloat radius, TCFloat height)
2608 {
2609 int i, j;
2610 TCVector p1, p2, p3, p4;
2611 TCVector top = center;
2612 top[1] = height;
2613 int ySegments = minorSegments / 4;
2614
2615 if ((inner && height > 0.0f) || (!inner && height < 0.0f))
2616 {
2617 radius += 0.1f;
2618 }
2619 else
2620 {
2621 radius -= 0.1f;
2622 }
2623 for (i = 0; i <= usedSegments; i++)
2624 {
2625 for (j = 0; j < ySegments; j++)
2626 {
2627 p1 = points[i * (ySegments + 1) + j];
2628 p2 = points[i * (ySegments + 1) + j + 1];
2629 if (i == 0)
2630 {
2631 p3 = p1;
2632 p3[2] -= 0.1f;
2633 }
2634 else
2635 {
2636 p3 = points[(i - 1) * (ySegments + 1) + j];
2637 }
2638 if (i == usedSegments)
2639 {
2640 p4 = p1;
2641 calcTangentControlPoint(p4, i, numSegments);
2642 }
2643 else
2644 {
2645 p4 = points[(i + 1) * (ySegments + 1) + j];
2646 }
2647 addConditionalLine(p1, p2, p3, p4);
2648 }
2649 }
2650 for (i = 0; i < usedSegments; i++)
2651 {
2652 for (j = 0; j <= ySegments; j++)
2653 {
2654 p1 = points[i * (ySegments + 1) + j];
2655 p2 = points[(i + 1) * (ySegments + 1) + j];
2656 if (j == 0)
2657 {
2658 p3 = p1;
2659 if (height > 0.0f)
2660 {
2661 p3[1] -= 0.1f;
2662 }
2663 else
2664 {
2665 p3[1] += 0.1f;
2666 }
2667 }
2668 else
2669 {
2670 p3 = points[i * (ySegments + 1) + (j - 1)];
2671 }
2672 if (j == ySegments)
2673 {
2674 TCFloat angle = 2.0f * (TCFloat)M_PI / numSegments * i;
2675
2676 setCirclePoint(angle, radius, top, p4);
2677 p4[1] = height;
2678 }
2679 else
2680 {
2681 p4 = points[i * (ySegments + 1) + (j + 1)];
2682 }
2683 addConditionalLine(p1, p2, p3, p4);
2684 }
2685 }
2686 }
2687
addEighthSphere(const TCVector & center,TCFloat radius,int numSegments,bool bfc)2688 void TREModel::addEighthSphere(const TCVector& center, TCFloat radius,
2689 int numSegments, bool bfc)
2690 {
2691 TCVector* zeroXPoints;
2692 TCVector* zeroYPoints;
2693 TCVector* zeroZPoints;
2694 int usedSegments = numSegments / 4;
2695 int i, j;
2696 TCVector p1, p2, p3;
2697 TCVector *spherePoints = NULL;
2698 int numMainPoints = (usedSegments + 1) * (usedSegments + 1) - 1;
2699 int mainSpot = 0;
2700 bool shouldLoadConditionals = shouldLoadConditionalLines();
2701
2702 if (shouldLoadConditionals)
2703 {
2704 spherePoints = new TCVector[numMainPoints];
2705 }
2706 zeroXPoints = new TCVector[usedSegments + 1];
2707 zeroYPoints = new TCVector[usedSegments + 1];
2708 zeroZPoints = new TCVector[usedSegments + 1];
2709 for (i = 0; i <= usedSegments; i++)
2710 {
2711 TCFloat angle = 2.0f * (TCFloat)M_PI / numSegments * i;
2712
2713 zeroYPoints[i][0] = 1.0f / ((TCFloat)tan(angle) + 1);
2714 zeroYPoints[i][1] = 0.0f;
2715 zeroYPoints[i][2] = 1.0f - zeroYPoints[i][0];
2716 zeroZPoints[i] = zeroYPoints[i].rearrange(2, 0, 1);
2717 zeroXPoints[i] = zeroYPoints[i].rearrange(1, 2, 0);
2718 zeroXPoints[i] += center;
2719 zeroYPoints[i] += center;
2720 zeroZPoints[i] += center;
2721 }
2722 for (j = 0; j < usedSegments; j++)
2723 {
2724 int stripCount = usedSegments - j;
2725 int stripSpot = 0;
2726 TCVector *points = new TCVector[stripCount * 2 + 1];
2727 TCVector *normals = new TCVector[stripCount * 2 + 1];
2728
2729 for (i = 0; i < stripCount; i++)
2730 {
2731 if (i == 0)
2732 {
2733 p1 = calcIntersection(i, j, usedSegments, zeroXPoints,
2734 zeroYPoints, zeroZPoints);
2735 p1 *= radius / p1.length();
2736 normals[stripSpot] = (p1 - center).normalize();
2737 points[stripSpot++] = p1;
2738 if (shouldLoadConditionals)
2739 {
2740 spherePoints[mainSpot++] = p1;
2741 }
2742 }
2743 p2 = calcIntersection(i, j + 1, usedSegments, zeroXPoints,
2744 zeroYPoints, zeroZPoints);
2745 p2 *= radius / p2.length();
2746 p3 = calcIntersection(i + 1, j, usedSegments, zeroXPoints,
2747 zeroYPoints, zeroZPoints);
2748 p3 *= radius / p3.length();
2749 normals[stripSpot] = (p2 - center).normalize();
2750 points[stripSpot++] = p2;
2751 normals[stripSpot] = (p3 - center).normalize();
2752 points[stripSpot++] = p3;
2753 if (shouldLoadConditionals)
2754 {
2755 spherePoints[mainSpot++] = p2;
2756 spherePoints[mainSpot++] = p3;
2757 }
2758 }
2759 if (m_mainModel->getSmoothCurvesFlag())
2760 {
2761 m_mainModel->setDisableStrips(true);
2762 }
2763 if (bfc)
2764 {
2765 addBFCTriangleStrip(points, normals, stripSpot);
2766 }
2767 else
2768 {
2769 addTriangleStrip(points, normals, stripSpot);
2770 }
2771 m_mainModel->setDisableStrips(false);
2772 delete[] points;
2773 delete[] normals;
2774 }
2775 if (shouldLoadConditionals)
2776 {
2777 addEighthSphereConditionals(spherePoints, numSegments);
2778 }
2779 delete[] spherePoints;
2780 delete[] zeroXPoints;
2781 delete[] zeroYPoints;
2782 delete[] zeroZPoints;
2783 }
2784
addConditionalLine(const TCVector & p1,const TCVector & p2,const TCVector & c1,const TCVector & c2)2785 void TREModel::addConditionalLine(const TCVector &p1, const TCVector &p2,
2786 const TCVector &c1, const TCVector &c2)
2787 {
2788 TCVector points[2];
2789 TCVector conditionalPoints[2];
2790
2791 points[0] = p1;
2792 points[1] = p2;
2793 conditionalPoints[0] = c1;
2794 conditionalPoints[1] = c2;
2795 addConditionalLine(points, conditionalPoints);
2796 }
2797
addEighthSphereConditionals(TCVector * points,int numSegments)2798 void TREModel::addEighthSphereConditionals(TCVector *points, int numSegments)
2799 {
2800 int usedSegments = numSegments / 4;
2801 int i, j;
2802 TCVector p1, p2, p3, p4;
2803 TCVector circlePoint;
2804 int mainSpot = 0;
2805
2806 for (j = 0; j < usedSegments; j++)
2807 {
2808 int stripCount = usedSegments - j;
2809
2810 for (i = 0; i < stripCount; i++)
2811 {
2812 if (i > 0)
2813 {
2814 p3 = points[mainSpot - 1];
2815 }
2816 else
2817 {
2818 if (j > 0)
2819 {
2820 p3 = points[mainSpot];
2821 p3[2] -= 0.1f;
2822 }
2823 else
2824 {
2825 p3 = points[mainSpot];
2826 p3[2] -= 0.1f;
2827 }
2828 }
2829 p4 = points[mainSpot + 2];
2830 p1 = points[mainSpot];
2831 p2 = points[mainSpot + 1];
2832 addConditionalLine(p1, p2, p3, p4);
2833 p3 = p1;
2834 p1 = p2;
2835 p2 = p4;
2836 if (i < stripCount - 1)
2837 {
2838 p4 = points[mainSpot + 3];
2839 }
2840 else
2841 {
2842 p4 = points[mainSpot + 1];
2843 p4[0] -= 0.1f;
2844 }
2845 addConditionalLine(p1, p2, p3, p4);
2846 p1 = points[mainSpot];
2847 p2 = points[mainSpot + 2];
2848 p3 = points[mainSpot + 1];
2849 if (j == 0)
2850 {
2851 p4 = points[mainSpot];
2852 p4[1] -= 0.1f;
2853 }
2854 else
2855 {
2856 p4 = points[sphereIndex(i * 2 + 2, j - 1, usedSegments)];
2857 }
2858 addConditionalLine(p1, p2, p3, p4);
2859 mainSpot += 2;
2860 }
2861 mainSpot++;
2862 }
2863 }
2864
sphereIndex(int i,int j,int usedSegments)2865 int TREModel::sphereIndex(int i, int j, int usedSegments)
2866 {
2867 int retVal = 0;
2868 int k;
2869
2870 for (k = 0; k < j; k++)
2871 {
2872 int rowSize = usedSegments - k;
2873
2874 retVal += rowSize * 2 + 1;
2875 }
2876 return retVal + i;
2877 }
2878
addOpenCone(const TCVector & center,TCFloat radius1,TCFloat radius2,TCFloat height,int numSegments,int usedSegments,bool bfc,TCULong color,TCULong edgeColor)2879 void TREModel::addOpenCone(
2880 const TCVector& center,
2881 TCFloat radius1,
2882 TCFloat radius2,
2883 TCFloat height,
2884 int numSegments,
2885 int usedSegments,
2886 bool bfc,
2887 TCULong color,
2888 TCULong edgeColor)
2889 {
2890 if (usedSegments == -1)
2891 {
2892 usedSegments = numSegments;
2893 }
2894 if (radius1 == 0.0f)
2895 {
2896 addCone(center, radius2, height, numSegments, usedSegments, bfc);
2897 }
2898 else if (radius2 == 0.0f)
2899 {
2900 addCone(center, radius1, height, numSegments, usedSegments, bfc);
2901 }
2902 else
2903 {
2904 int vertexCount = usedSegments * 2 + 2;
2905 TCVector *points = new TCVector[vertexCount];
2906 TCVector *normals = new TCVector[vertexCount];
2907 int i;
2908 TCVector top = center;
2909 TCVector normal = TCVector(0.0f, -1.0f, 0.0f);
2910 TCVector topNormalPoint;
2911 TCVector normalPoint;
2912 TCFloat normalAdjust = 1.0f;
2913
2914 if (height < 0.0f)
2915 {
2916 normalAdjust = -1.0f;
2917 }
2918 top[1] += height;
2919 if (height)
2920 {
2921 topNormalPoint = top - normal * radius2 * (radius2 - radius1) /
2922 height;
2923 normalPoint = center - normal * radius1 * (radius2 - radius1) /
2924 height;
2925 }
2926 for (i = 0; i <= usedSegments; i++)
2927 {
2928 TCFloat angle;
2929
2930 angle = 2.0f * (TCFloat)M_PI / numSegments * i;
2931 setCirclePoint(angle, radius1, center, points[i * 2]);
2932 setCirclePoint(angle, radius2, top, points[i * 2 + 1]);
2933 if (height == 0.0f)
2934 {
2935 normals[i * 2] = normal;
2936 normals[i * 2 + 1] = normal;
2937 }
2938 else
2939 {
2940 normals[i * 2] = (points[i * 2] - normalPoint).normalize() *
2941 normalAdjust;
2942 normals[i * 2 + 1] =
2943 (points[i * 2 + 1] - topNormalPoint).normalize() *
2944 normalAdjust;
2945 }
2946 }
2947 if (m_mainModel->getSmoothCurvesFlag())
2948 {
2949 m_mainModel->setDisableStrips(true);
2950 }
2951 if (bfc)
2952 {
2953 if (color == 0)
2954 {
2955 addBFCQuadStrip(points, normals, vertexCount, height == 0.0f);
2956 }
2957 else
2958 {
2959 addBFCQuadStrip(color, points, normals, vertexCount,
2960 height == 0.0f);
2961 }
2962 }
2963 else
2964 {
2965 if (color == 0)
2966 {
2967 addQuadStrip(points, normals, vertexCount, height == 0.0f);
2968 }
2969 else
2970 {
2971 addQuadStrip(color, points, normals, vertexCount,
2972 height == 0.0f);
2973 }
2974 }
2975 m_mainModel->setDisableStrips(false);
2976 if (shouldLoadConditionalLines() && !fEq(height, 0.0f))
2977 {
2978 addOpenConeConditionals(points, numSegments, usedSegments,
2979 edgeColor);
2980 }
2981 delete[] points;
2982 delete[] normals;
2983 }
2984 }
2985
calcTangentControlPoint(TCVector & controlPoint,int index,int numSegments)2986 void TREModel::calcTangentControlPoint(TCVector &controlPoint, int index,
2987 int numSegments)
2988 {
2989 // The next control point needs to form a tangent with the circle from the
2990 // last point on the circle. On input, controlPoint starts as the last
2991 // point on the circle.
2992 TCFloat angle;
2993
2994 // First, calculate the angle for the last point on the circle.
2995 angle = 2.0f * (TCFloat)M_PI / numSegments * index;
2996 // Next, add 90 degrees to that to get the tangent angle
2997 angle += (TCFloat)deg2rad(90);
2998 controlPoint[0] += (TCFloat)cos(angle) * 0.1f;
2999 controlPoint[2] += (TCFloat)sin(angle) * 0.1f;
3000 }
3001
addOpenConeConditionals(TCVector * points,int numSegments,int usedSegments,TCULong color)3002 void TREModel::addOpenConeConditionals(
3003 TCVector *points,
3004 int numSegments,
3005 int usedSegments,
3006 TCULong color)
3007 {
3008 int i;
3009 TCVector controlPoints[2];
3010 TCVector *p1;
3011 TCVector *p2;
3012
3013 for (i = 0; i <= usedSegments; i++)
3014 {
3015 p1 = &points[i * 2];
3016 p2 = &points[i * 2 + 1];
3017 if (*p1 == *p2)
3018 {
3019 continue;
3020 }
3021 if (i == 0)
3022 {
3023 if (numSegments == usedSegments)
3024 {
3025 controlPoints[0] = points[numSegments * 2 - 2];
3026 }
3027 else
3028 {
3029 controlPoints[0] = *p1;
3030 controlPoints[0][2] -= 1.0f;
3031 }
3032 }
3033 else
3034 {
3035 controlPoints[0] = points[(i - 1) * 2];
3036 }
3037 if (i == usedSegments)
3038 {
3039 if (numSegments == usedSegments)
3040 {
3041 // No need to repeat the last one if it's a closed surface.
3042 return;
3043 }
3044 else
3045 {
3046 controlPoints[1] = *p1;
3047 calcTangentControlPoint(controlPoints[1], i, numSegments);
3048 }
3049 }
3050 else
3051 {
3052 controlPoints[1] = points[(i + 1) * 2];
3053 }
3054 addConditionalLine(p1, controlPoints, color);
3055 }
3056 }
3057
addSlopedCylinder2Conditionals(TCVector * points,int numSegments,int usedSegments)3058 void TREModel::addSlopedCylinder2Conditionals(TCVector *points,
3059 int numSegments, int usedSegments)
3060 {
3061 int i;
3062 TCVector linePoints[2];
3063 TCVector controlPoints[2];
3064 TCVector *p1;
3065 TCVector *p2;
3066
3067 for (i = 1; i <= usedSegments; i++)
3068 {
3069 linePoints[0] = points[i * 2];
3070 linePoints[1] = points[i * 2 + 1];
3071 p1 = &linePoints[0];
3072 p2 = &linePoints[1];
3073 if (p1 == p2)
3074 {
3075 continue;
3076 }
3077 controlPoints[0] = points[(i - 1) * 2];
3078 if (i == usedSegments)
3079 {
3080 if (numSegments == usedSegments)
3081 {
3082 controlPoints[1] = points[2];
3083 }
3084 else
3085 {
3086 controlPoints[1] = *p1;
3087 // This primitive starts at a different angle, so we want the
3088 // tangent that is 90 degrees further around vs. what would
3089 // normally be the tangent for the given index, so add
3090 // numSegments / 4 to do the calculation for 90 degrees further.
3091 calcTangentControlPoint(controlPoints[1], i + numSegments / 4,
3092 numSegments);
3093 }
3094 }
3095 else
3096 {
3097 controlPoints[1] = points[(i + 1) * 2];
3098 }
3099 addConditionalLine(linePoints, controlPoints);
3100 }
3101 }
3102
addCircularEdge(const TCVector & center,TCFloat radius,int numSegments,int usedSegments,TCULong color)3103 void TREModel::addCircularEdge(
3104 const TCVector& center,
3105 TCFloat radius,
3106 int numSegments,
3107 int usedSegments,
3108 TCULong color)
3109 {
3110 int i;
3111 TCVector p1;
3112 TCVector *allPoints;
3113 TCVector points[2];
3114
3115 if (usedSegments == -1)
3116 {
3117 usedSegments = numSegments;
3118 }
3119 allPoints = new TCVector[usedSegments + 1];
3120 for (i = 0; i <= usedSegments; i++)
3121 {
3122 TCFloat x, z;
3123 TCFloat angle;
3124
3125 angle = 2.0f * (TCFloat)M_PI / numSegments * i;
3126 x = radius * (TCFloat)cos(angle);
3127 z = radius * (TCFloat)sin(angle);
3128 p1[0] = center.get(0) + x;
3129 p1[2] = center.get(2) + z;
3130 p1[1] = center.get(1);
3131 allPoints[i] = p1;
3132 }
3133 for (i = 0; i < usedSegments; i++)
3134 {
3135 points[0] = allPoints[i];
3136 points[1] = allPoints[i + 1];
3137 addEdgeLine(points, color);
3138 }
3139 delete[] allPoints;
3140 }
3141
addRing(const TCVector & center,TCFloat radius1,TCFloat radius2,int numSegments,int usedSegments,bool bfc)3142 void TREModel::addRing(const TCVector& center, TCFloat radius1, TCFloat radius2,
3143 int numSegments, int usedSegments, bool bfc)
3144 {
3145 addOpenCone(center, radius1, radius2, 0.0f, numSegments, usedSegments,
3146 bfc);
3147 }
3148
calculateBoundingBox(void)3149 void TREModel::calculateBoundingBox(void)
3150 {
3151 if (!m_flags.boundingBox)
3152 {
3153 m_boundingMin[0] = 1e10f;
3154 m_boundingMin[1] = 1e10f;
3155 m_boundingMin[2] = 1e10f;
3156 m_boundingMax[0] = -1e10f;
3157 m_boundingMax[1] = -1e10f;
3158 m_boundingMax[2] = -1e10f;
3159 scanPoints(this,
3160 (TREScanPointCallback)&TREModel::scanBoundingBoxPoint,
3161 TCVector::getIdentityMatrix());
3162 m_flags.boundingBox = true;
3163 }
3164 }
3165
scanPoints(TCObject * scanner,TREScanPointCallback scanPointCallback,const TCFloat * matrix)3166 void TREModel::scanPoints(TCObject *scanner,
3167 TREScanPointCallback scanPointCallback,
3168 const TCFloat *matrix)
3169 {
3170 int i;
3171
3172 for (i = 0; i <= TREMLast; i++)
3173 {
3174 TREShapeGroup *shapeGroup = m_shapes[i];
3175
3176 if (shapeGroup)
3177 {
3178 shapeGroup->scanPoints(scanner, scanPointCallback, matrix);
3179 }
3180 shapeGroup = m_coloredShapes[i];
3181 if (shapeGroup)
3182 {
3183 shapeGroup->scanPoints(scanner, scanPointCallback, matrix);
3184 }
3185 }
3186 if (m_subModels)
3187 {
3188 int count = m_subModels->getCount();
3189
3190 for (i = 0; i < count; i++)
3191 {
3192 (*m_subModels)[i]->scanPoints(scanner, scanPointCallback, matrix);
3193 }
3194 }
3195 }
3196
unshrinkNormals(const TCFloat * matrix,const TCFloat * unshrinkMatrix)3197 void TREModel::unshrinkNormals(
3198 const TCFloat *matrix,
3199 const TCFloat *unshrinkMatrix)
3200 {
3201 int i;
3202
3203 for (i = 0; i <= TREMLast; i++)
3204 {
3205 if (!isLineSection(i))
3206 {
3207 TREShapeGroup *shapeGroup = m_shapes[i];
3208
3209 if (shapeGroup)
3210 {
3211 shapeGroup->unshrinkNormals(matrix, unshrinkMatrix);
3212 }
3213 shapeGroup = m_coloredShapes[i];
3214 if (shapeGroup)
3215 {
3216 shapeGroup->unshrinkNormals(matrix, unshrinkMatrix);
3217 }
3218 }
3219 }
3220 if (m_subModels)
3221 {
3222 int count = m_subModels->getCount();
3223
3224 for (i = 0; i < count; i++)
3225 {
3226 (*m_subModels)[i]->unshrinkNormals(matrix, unshrinkMatrix);
3227 }
3228 }
3229 }
3230
getBoundingBox(TCVector & min,TCVector & max)3231 void TREModel::getBoundingBox(TCVector& min, TCVector& max)
3232 {
3233 if (!m_flags.boundingBox)
3234 {
3235 calculateBoundingBox();
3236 }
3237 min = m_boundingMin;
3238 max = m_boundingMax;
3239 }
3240
scanBoundingBoxPoint(const TCVector & point)3241 void TREModel::scanBoundingBoxPoint(const TCVector &point)
3242 {
3243 if (point.get(0) < m_boundingMin[0])
3244 {
3245 m_boundingMin[0] = point.get(0);
3246 }
3247 if (point.get(1) < m_boundingMin[1])
3248 {
3249 m_boundingMin[1] = point.get(1);
3250 }
3251 if (point.get(2) < m_boundingMin[2])
3252 {
3253 m_boundingMin[2] = point.get(2);
3254 }
3255 if (point.get(0) > m_boundingMax[0])
3256 {
3257 m_boundingMax[0] = point.get(0);
3258 }
3259 if (point.get(1) > m_boundingMax[1])
3260 {
3261 m_boundingMax[1] = point.get(1);
3262 }
3263 if (point.get(2) > m_boundingMax[2])
3264 {
3265 m_boundingMax[2] = point.get(2);
3266 }
3267 }
3268
3269 // When you shrink a part, all the normals end up getting lengthened by an
3270 // amount that is based on their direction and the magnitude of the shrinkage
3271 // matrix. If that isn't adjusted for, then all normals have to be normalized
3272 // by OpenGL, which slows things down. This functions shortens all the normals
3273 // in a part by the appropriate amount based on the shrinkage matrix. Then when
3274 // the part is drawn with the shrinkage matrix, they automatically get adjusted
3275 // back to being unit length, and we don't have to force OpenGL to normalize
3276 // them.
3277 //
3278 // Note: At first glance, this would appear to mess up parts that are mirror
3279 // images of each other. Since one part will reference the other with a mirror
3280 // matrix, it makes it possible to shrink the normals twice. However, since
3281 // all parts get flattenned, and the flatenning process re-normalizes the
3282 // normals to be unit lenght, everything is fine. If it ever becomes desirable
3283 // to allow parts not to be flattened, things will get more complicated.
unshrinkNormals(const TCFloat * scaleMatrix)3284 void TREModel::unshrinkNormals(const TCFloat *scaleMatrix)
3285 {
3286 // If the same part is referenced twice in a model, we'll get here twice.
3287 // We only want to adjust the normals once, or we'll be in trouble, so
3288 // record the fact that the normals have been adjusted.
3289 if (!m_flags.unshrunkNormals)
3290 {
3291 unshrinkNormals(TCVector::getIdentityMatrix(), scaleMatrix);
3292 m_flags.unshrunkNormals = true;
3293 }
3294 }
3295
setSectionPresent(TREMSection section,bool colored)3296 void TREModel::setSectionPresent(TREMSection section, bool colored)
3297 {
3298 TCULong bit = 1 << section;
3299
3300 if (colored)
3301 {
3302 m_coloredSectionsPresent |= bit;
3303 }
3304 else
3305 {
3306 m_sectionsPresent |= bit;
3307 }
3308 }
3309
isSectionPresent(TREMSection section,bool colored)3310 bool TREModel::isSectionPresent(TREMSection section, bool colored)
3311 {
3312 TCULong bit = 1 << section;
3313
3314 if (colored)
3315 {
3316 return (m_coloredSectionsPresent & bit) != 0;
3317 }
3318 else
3319 {
3320 return (m_sectionsPresent & bit) != 0;
3321 }
3322 }
3323
checkShapeGroupPresent(TREShapeGroup * shapeGroup,TREMSection section,bool colored)3324 bool TREModel::checkShapeGroupPresent(TREShapeGroup *shapeGroup,
3325 TREMSection section, bool colored)
3326 {
3327 if (shapeGroup)
3328 {
3329 setSectionPresent(section, colored);
3330 }
3331 if (m_subModels)
3332 {
3333 int i;
3334 int count = m_subModels->getCount();
3335
3336 for (i = 0; i < count; i++)
3337 {
3338 if ((*m_subModels)[i]->getEffectiveModel()->
3339 checkSectionPresent(section, colored))
3340 {
3341 setSectionPresent(section, colored);
3342 }
3343 }
3344 }
3345 return isSectionPresent(section, colored);
3346 }
3347
checkSectionPresent(TREMSection section,bool colored)3348 bool TREModel::checkSectionPresent(TREMSection section, bool colored)
3349 {
3350 if (colored)
3351 {
3352 return checkShapeGroupPresent(m_coloredShapes[section], section,
3353 true);
3354 }
3355 else
3356 {
3357 return checkShapeGroupPresent(m_shapes[section], section, false);
3358 }
3359 }
3360
checkSectionPresent(TREMSection section)3361 bool TREModel::checkSectionPresent(TREMSection section)
3362 {
3363 return checkSectionPresent(section, false);
3364 }
3365
checkColoredSectionPresent(TREMSection section)3366 bool TREModel::checkColoredSectionPresent(TREMSection section)
3367 {
3368 return checkSectionPresent(section, true);
3369 }
3370
3371 // Note: static method
uncompileListID(GLuint & listID)3372 void TREModel::uncompileListID(GLuint &listID)
3373 {
3374 if (listID)
3375 {
3376 glDeleteLists(listID, 1);
3377 listID = 0;
3378 }
3379 }
3380
uncompile(bool includeSubModels)3381 void TREModel::uncompile(bool includeSubModels /*= true*/)
3382 {
3383 int i;
3384
3385 for (i = 0; i <= TREMLast; i++)
3386 {
3387 uncompileListID(m_listIDs[i]);
3388 uncompileListID(m_coloredListIDs[i]);
3389 uncompileListID(m_texListIDs[i]);
3390 uncompileListID(m_texColoredListIDs[i]);
3391 }
3392 if (m_subModels && includeSubModels)
3393 {
3394 int count = m_subModels->getCount();
3395
3396 for (i = 0; i < count; i++)
3397 {
3398 (*m_subModels)[i]->getEffectiveModel()->uncompile();
3399 }
3400 }
3401 }
3402
cleanupTransfer(TREShapeGroup::TRESTransferType type,TREMSection section)3403 void TREModel::cleanupTransfer(
3404 TREShapeGroup::TRESTransferType type,
3405 TREMSection section)
3406 {
3407 if (type == TREShapeGroup::TTTexmapped)
3408 {
3409 return;
3410 }
3411 if (m_shapes[section] != NULL)
3412 {
3413 m_shapes[section]->cleanupTransfer();
3414 }
3415 if (m_coloredShapes[section] != NULL)
3416 {
3417 m_coloredShapes[section]->cleanupTransfer();
3418 }
3419 if (m_subModels)
3420 {
3421 int i;
3422 int count = m_subModels->getCount();
3423
3424 for (i = 0; i < count; i++)
3425 {
3426 (*m_subModels)[i]->getModel()->cleanupTransfer(type, section);
3427 }
3428 //for (i = count - 1; i >= 0; i--)
3429 //{
3430 // if ((*m_subModels)[i]->getTransferredFlag())
3431 // {
3432 // m_subModels->removeObjectAtIndex(i);
3433 // }
3434 //}
3435 }
3436 }
3437
transferColored(TREShapeGroup::TRESTransferType type,TREMSection section,const TCFloat * matrix,bool bfcInvert)3438 void TREModel::transferColored(
3439 TREShapeGroup::TRESTransferType type,
3440 TREMSection section,
3441 const TCFloat *matrix,
3442 bool bfcInvert)
3443 {
3444 TREColoredShapeGroup *shapeGroup = m_coloredShapes[section];
3445
3446 if (shapeGroup)
3447 {
3448 shapeGroup->transferColored(type, matrix, bfcInvert);
3449 }
3450 transferColoredSubModels(type, section, matrix, bfcInvert);
3451 }
3452
transferColoredSubModels(TREShapeGroup::TRESTransferType type,TREMSection section,const TCFloat * matrix,bool bfcInvert)3453 void TREModel::transferColoredSubModels(
3454 TREShapeGroup::TRESTransferType type,
3455 TREMSection section,
3456 const TCFloat *matrix,
3457 bool bfcInvert)
3458 {
3459 if (m_subModels != NULL)
3460 {
3461 int i;
3462 int count = m_subModels->getCount();
3463 TexmapInfoList::const_iterator it;
3464 const TexmapInfo *texmapInfo = NULL;
3465 bool texmapActive = false;
3466
3467 if (type == TREShapeGroup::TTTexmapped)
3468 {
3469 it = m_texmapInfos.begin();
3470 if (it != m_texmapInfos.end())
3471 {
3472 texmapInfo = &*it;
3473 }
3474 }
3475 for (i = 0; i < count; i++)
3476 {
3477 texmapActive = false;
3478 if (type == TREShapeGroup::TTTexmapped &&
3479 !m_mainModel->getModelTexmapTransferFlag())
3480 {
3481 if (texmapInfo != NULL && i >= texmapInfo->subModelOffset &&
3482 i < texmapInfo->subModelOffset + texmapInfo->subModelCount)
3483 {
3484 texmapActive = true;
3485 m_mainModel->setTransferTexmapInfo(*texmapInfo,
3486 section == TREMBFC, matrix);
3487 m_mainModel->setModelTexmapTransferFlag(true);
3488 }
3489 }
3490 (*m_subModels)[i]->transferColored(type, section, matrix,
3491 bfcInvert);
3492 if (texmapActive)
3493 {
3494 //(*m_subModels)[i]->setTransferredFlag(true);
3495 m_mainModel->setModelTexmapTransferFlag(false);
3496 if (i == texmapInfo->subModelOffset + texmapInfo->subModelCount
3497 - 1)
3498 {
3499 it++;
3500 if (it != m_texmapInfos.end())
3501 {
3502 texmapInfo = &*it;
3503 }
3504 else
3505 {
3506 texmapInfo = NULL;
3507 }
3508 }
3509 }
3510 }
3511 }
3512 }
3513
transfer(TREShapeGroup::TRESTransferType type,TCULong color,TREMSection section,const TCFloat * matrix,bool bfcInvert)3514 void TREModel::transfer(
3515 TREShapeGroup::TRESTransferType type,
3516 TCULong color,
3517 TREMSection section,
3518 const TCFloat *matrix,
3519 bool bfcInvert)
3520 {
3521 TREShapeGroup *shapeGroup = m_shapes[section];
3522
3523 if (shapeGroup)
3524 {
3525 shapeGroup->transfer(type, color, matrix, bfcInvert);
3526 }
3527 transferSubModels(type, color, section, matrix, bfcInvert);
3528 }
3529
transferSubModels(TREShapeGroup::TRESTransferType type,TCULong color,TREMSection section,const TCFloat * matrix,bool bfcInvert)3530 void TREModel::transferSubModels(
3531 TREShapeGroup::TRESTransferType type,
3532 TCULong color,
3533 TREMSection section,
3534 const TCFloat *matrix,
3535 bool bfcInvert /*= false*/)
3536 {
3537 if (m_subModels != NULL)
3538 {
3539 int i;
3540 int count = m_subModels->getCount();
3541 TexmapInfoList::const_iterator it;
3542 const TexmapInfo *texmapInfo = NULL;
3543 bool texmapActive = false;
3544
3545 if (type == TREShapeGroup::TTTexmapped)
3546 {
3547 it = m_texmapInfos.begin();
3548 while (it != m_texmapInfos.end() && it->subModelCount == 0)
3549 {
3550 it++;
3551 }
3552 if (it != m_texmapInfos.end())
3553 {
3554 texmapInfo = &*it;
3555 }
3556 }
3557 for (i = 0; i < count; i++)
3558 {
3559 if (this == m_mainModel)
3560 {
3561 m_mainModel->updateModelTransferStep(i);
3562 }
3563 texmapActive = false;
3564 if (type == TREShapeGroup::TTTexmapped &&
3565 !m_mainModel->getModelTexmapTransferFlag())
3566 {
3567 if (texmapInfo != NULL && i >= texmapInfo->subModelOffset &&
3568 i < texmapInfo->subModelOffset + texmapInfo->subModelCount)
3569 {
3570 texmapActive = true;
3571 m_mainModel->setTransferTexmapInfo(*texmapInfo,
3572 section == TREMBFC, matrix);
3573 m_mainModel->setModelTexmapTransferFlag(true);
3574 }
3575 }
3576 (*m_subModels)[i]->transfer(type, color, section, matrix,
3577 bfcInvert);
3578 if (type == TREShapeGroup::TTTexmapped && this == m_mainModel)
3579 {
3580 (*m_subModels)[i]->transferColored(type, section, matrix,
3581 bfcInvert);
3582 }
3583 if (texmapActive)
3584 {
3585 //(*m_subModels)[i]->setTransferredFlag(true);
3586 m_mainModel->setModelTexmapTransferFlag(false);
3587 if (i == texmapInfo->subModelOffset + texmapInfo->subModelCount
3588 - 1)
3589 {
3590 it++;
3591 while (it != m_texmapInfos.end() && it->subModelCount == 0)
3592 {
3593 it++;
3594 }
3595 if (it != m_texmapInfos.end())
3596 {
3597 texmapInfo = &*it;
3598 }
3599 else
3600 {
3601 texmapInfo = NULL;
3602 }
3603 }
3604 }
3605 }
3606 }
3607 }
3608
shouldLoadConditionalLines(void)3609 bool TREModel::shouldLoadConditionalLines(void)
3610 {
3611 return m_mainModel->shouldLoadConditionalLines();
3612 }
3613
findLights(void)3614 void TREModel::findLights(void)
3615 {
3616 TCFloat matrix[16];
3617
3618 TCVector::initIdentityMatrix(matrix);
3619 findLights(matrix);
3620 }
3621
findLights(float * matrix)3622 void TREModel::findLights(float *matrix)
3623 {
3624 if (m_subModels)
3625 {
3626 int i;
3627 int count = m_subModels->getCount();
3628 TCFloat newMatrix[16];
3629 TCVector origin;
3630
3631 for (i = 0; i < count; i++)
3632 {
3633 TRESubModel *subModel = (*m_subModels)[i];
3634
3635 TCVector::multMatrix(matrix, subModel->getMatrix(), newMatrix);
3636 if (subModel->getLightFlag())
3637 {
3638 m_mainModel->addLight(origin.transformPoint(newMatrix),
3639 subModel->getColor());
3640 }
3641 else
3642 {
3643 subModel->getModel()->findLights(newMatrix);
3644 }
3645 }
3646 }
3647 }
3648
flattenNonUniform(void)3649 void TREModel::flattenNonUniform(void)
3650 {
3651 if (m_subModels)
3652 {
3653 int i;
3654 int count = m_subModels->getCount();
3655 TCFloat determinant;
3656
3657 for (i = count - 1; i >= 0; i--)
3658 {
3659 TRESubModel *subModel = (*m_subModels)[i];
3660 TREModel *newModel = subModel->getEffectiveModel();
3661
3662 determinant = TCVector::determinant(subModel->getOriginalMatrix());
3663 if (!fEq(determinant, 1.0) && !fEq(determinant, -1.0))
3664 {
3665 if (subModel->isColorSet())
3666 {
3667 flatten(newModel, subModel->getMatrix(),
3668 htonl(subModel->getColor()), true,
3669 htonl(subModel->getEdgeColor()), true, true);
3670 }
3671 else
3672 {
3673 flatten(newModel, subModel->getMatrix(), 0, false,
3674 0, false, true);
3675 }
3676 m_subModels->removeObjectAtIndex(i);
3677 debugPrintf("Flattened non-uniform sub-model: %g.\n",
3678 determinant);
3679 if (this == m_mainModel)
3680 {
3681 for (int j = (int)m_stepCounts.size() - 1; j >= 0; j--)
3682 {
3683 if (m_stepCounts[j] > i)
3684 {
3685 m_stepCounts[j]--;
3686 }
3687 else
3688 {
3689 break;
3690 }
3691 }
3692 }
3693 }
3694 else
3695 {
3696 if (subModel->isColorSet())
3697 {
3698 newModel->flattenNonUniform();
3699 }
3700 else
3701 {
3702 newModel->flattenNonUniform();
3703 }
3704 }
3705 }
3706 }
3707 }
3708
removeConditionals(void)3709 void TREModel::removeConditionals(void)
3710 {
3711 if (this != m_mainModel)
3712 {
3713 TREShapeGroup *shapeGroup = m_shapes[TREMConditionalLines];
3714 TREColoredShapeGroup *coloredShapeGroup =
3715 m_coloredShapes[TREMConditionalLines];
3716
3717 if (shapeGroup)
3718 {
3719 shapeGroup->release();
3720 m_shapes[TREMConditionalLines] = NULL;
3721 }
3722 if (coloredShapeGroup)
3723 {
3724 coloredShapeGroup->release();
3725 m_coloredShapes[TREMConditionalLines] = NULL;
3726 }
3727 }
3728 if (m_subModels)
3729 {
3730 int count = m_subModels->getCount();
3731
3732 for (int i = 0; i < count; i++)
3733 {
3734 TRESubModel *subModel = (*m_subModels)[i];
3735
3736 subModel->getEffectiveModel()->removeConditionals();
3737 }
3738 }
3739 }
3740
flattenConditionals(const TCFloat * matrix,TCULong edgeColor,bool edgeColorSet)3741 void TREModel::flattenConditionals(
3742 const TCFloat *matrix,
3743 TCULong edgeColor,
3744 bool edgeColorSet)
3745 {
3746 if (this != m_mainModel)
3747 {
3748 TREShapeGroup *shapeGroup = m_shapes[TREMConditionalLines];
3749 TREColoredShapeGroup *coloredShapeGroup =
3750 m_coloredShapes[TREMConditionalLines];
3751
3752 if (shapeGroup)
3753 {
3754 if (edgeColorSet)
3755 {
3756 TREShapeGroup *mainColoredShapeGroup =
3757 m_mainModel->m_coloredShapes[TREMConditionalLines];
3758
3759 mainColoredShapeGroup->flatten(shapeGroup, matrix, edgeColor,
3760 true);
3761 }
3762 else
3763 {
3764 TREShapeGroup *mainShapeGroup =
3765 m_mainModel->m_shapes[TREMConditionalLines];
3766
3767 mainShapeGroup->flatten(shapeGroup, matrix, 0, false);
3768 }
3769 }
3770 if (coloredShapeGroup)
3771 {
3772 TREShapeGroup *mainColoredShapeGroup =
3773 m_mainModel->m_coloredShapes[TREMConditionalLines];
3774
3775 mainColoredShapeGroup->flatten(coloredShapeGroup, matrix, 0, false);
3776 }
3777 }
3778 if (m_subModels)
3779 {
3780 int count = m_subModels->getCount();
3781 TCFloat newMatrix[16];
3782
3783 for (int i = 0; i < count; i++)
3784 {
3785 TRESubModel *subModel = (*m_subModels)[i];
3786
3787 if (this == m_mainModel)
3788 {
3789 m_mainModel->updateModelTransferStep(i, true);
3790 }
3791 TCVector::multMatrix(matrix, subModel->getMatrix(), newMatrix);
3792 if (subModel->isColorSet())
3793 {
3794 subModel->getEffectiveModel()->flattenConditionals(newMatrix,
3795 htonl(subModel->getEdgeColor()), true);
3796 }
3797 else
3798 {
3799 subModel->getEffectiveModel()->flattenConditionals(newMatrix,
3800 edgeColor, edgeColorSet);
3801 }
3802 }
3803 }
3804 }
3805
getAlertSender(void)3806 TCObject *TREModel::getAlertSender(void)
3807 {
3808 return m_mainModel->getAlertSender();
3809 }
3810
printStlTriangle(FILE * file,TREVertexArray * vertices,TCULongArray * indices,int ix,int i0,int i1,int i2,const TCFloat * matrix,float scale)3811 void TREModel::printStlTriangle(
3812 FILE *file,
3813 TREVertexArray *vertices,
3814 TCULongArray *indices,
3815 int ix,
3816 int i0,
3817 int i1,
3818 int i2,
3819 const TCFloat *matrix,
3820 float scale)
3821 {
3822 int ip[3];
3823 ip[0]=i0; ip[1]=i1; ip[2]=i2;
3824
3825 fprintf(file, " facet normal %f %f %f\n", 0.0, 0.0, 0.0);
3826 fprintf(file, " outer loop\n");
3827 for (int i = 0; i < 3; i++)
3828 {
3829 int index = (*indices)[ix + ip[i]];
3830 const TREVertex &treVertex = (*vertices)[index];
3831 TCVector vector(treVertex.v[0], treVertex.v[1], treVertex.v[2]);
3832
3833 vector = vector.transformPoint(matrix);
3834 fprintf(file, " vertex %f %f %f\n", vector[0] * scale,
3835 vector[1] * scale, vector[2] * scale);
3836 }
3837 fprintf(file, " endloop\n");
3838 fprintf(file, " endfacet\n");
3839 }
3840
saveSTL(FILE * file,float scale)3841 void TREModel::saveSTL(FILE *file, float scale)
3842 {
3843 fprintf(file, "solid MYSOLID created by LDView, original data in %s\n",
3844 m_name);
3845 saveSTL(file, TCVector::getIdentityMatrix(), scale);
3846 fprintf(file, "endsolid MYSOLID\n");
3847 }
3848
printStlStrips(FILE * file,TREShapeGroup * shapeGroup,TREShapeType shapeType,const TCFloat * matrix,float scale)3849 void TREModel::printStlStrips(
3850 FILE *file,
3851 TREShapeGroup *shapeGroup,
3852 TREShapeType shapeType,
3853 const TCFloat *matrix,
3854 float scale)
3855 {
3856 TCULongArray *indices = shapeGroup->getIndices(shapeType, false);
3857 TCULongArray *stripCounts = shapeGroup->getStripCounts(shapeType, false);
3858 TREVertexArray *vertices = shapeGroup->getVertexStore()->getVertices();
3859 int stripMargin = 2;
3860 int stripInc = 1;
3861
3862 if (shapeType == TRESQuadStrip)
3863 {
3864 stripMargin = 3;
3865 stripInc = 2;
3866 }
3867 if (indices != NULL && stripCounts != NULL)
3868 {
3869 int numStrips = stripCounts->getCount();
3870
3871 if (numStrips > 0)
3872 {
3873 int ofs = 0;
3874
3875 for (int j = 0; j < numStrips; j++)
3876 {
3877 int stripCount = (*stripCounts)[j];
3878
3879 for (int k = 0; k < stripCount - stripMargin; k += stripInc)
3880 {
3881 switch (shapeType)
3882 {
3883 case TRESTriangleStrip:
3884 if (k % 2 == 0)
3885 {
3886 printStlTriangle(file, vertices, indices,
3887 ofs + k, 0, 1, 2, matrix, scale);
3888 }
3889 else
3890 {
3891 printStlTriangle(file, vertices, indices,
3892 ofs + k, 0, 2, 1, matrix, scale);
3893 }
3894 break;
3895 case TRESTriangleFan:
3896 printStlTriangle(file, vertices, indices,
3897 ofs, 0, k + 1, k + 2, matrix, scale);
3898 break;
3899 case TRESQuadStrip:
3900 printStlTriangle(file, vertices, indices,
3901 ofs + k, 0, 1, 2, matrix, scale);
3902 printStlTriangle(file, vertices, indices,
3903 ofs + k, 1, 2, 3, matrix, scale);
3904 break;
3905 default:
3906 // Get rid of gcc warnings.
3907 break;
3908 }
3909 }
3910 ofs += stripCount;
3911 }
3912 }
3913 }
3914 }
3915
saveSTLShapes(TREShapeGroup * shapes[],FILE * file,const TCFloat * matrix,float scale)3916 void TREModel::saveSTLShapes(
3917 TREShapeGroup *shapes[],
3918 FILE *file,
3919 const TCFloat *matrix,
3920 float scale)
3921 {
3922 for (int i = 0; i <= TREMLast; i++)
3923 {
3924 TREShapeGroup *shape = shapes[i];
3925
3926 if (shape != NULL)
3927 {
3928 TCULongArray *indices =
3929 shape->getIndices(TRESTriangle, false);
3930 TREVertexStore *vertexStore = shape->getVertexStore();
3931
3932 if (indices != NULL)
3933 {
3934 TREVertexArray *vertices = vertexStore->getVertices();
3935 int count = indices->getCount();
3936
3937 for ( int p = 0; p < count; p+=3 )
3938 {
3939 printStlTriangle(file, vertices, indices, p, 0, 1, 2,
3940 matrix, scale);
3941 }
3942 }
3943 indices = shape->getIndices(TRESQuad, false);
3944 if (indices != NULL)
3945 {
3946 TREVertexArray *vertices = vertexStore->getVertices();
3947 int count = indices->getCount();
3948
3949 for ( int p = 0; p < count; p+=4 )
3950 {
3951 printStlTriangle(file, vertices, indices, p, 0, 1, 2,
3952 matrix, scale);
3953 printStlTriangle(file, vertices, indices, p, 0, 2, 3,
3954 matrix, scale);
3955 }
3956 }
3957 printStlStrips(file, shape, TRESTriangleStrip, matrix, scale);
3958 printStlStrips(file, shape, TRESTriangleFan, matrix, scale);
3959 printStlStrips(file, shape, TRESQuadStrip, matrix, scale);
3960 }
3961 }
3962 }
3963
saveSTL(FILE * file,const TCFloat * matrix,float scale)3964 void TREModel::saveSTL(FILE *file, const TCFloat *matrix, float scale)
3965 {
3966 saveSTLShapes(m_shapes, file, matrix, scale);
3967 saveSTLShapes((TREShapeGroup **)m_coloredShapes, file, matrix, scale);
3968 if (m_subModels != NULL)
3969 {
3970 for (int i = 0; i < m_subModels->getCount(); i++)
3971 {
3972 TRESubModel *subModel = (*m_subModels)[i];
3973 TCFloat newMatrix[16];
3974
3975 TCVector::multMatrix(matrix, subModel->getMatrix(), newMatrix);
3976 subModel->getEffectiveModel()->saveSTL(file, newMatrix, scale);
3977 }
3978 }
3979 }
3980
nextStep(void)3981 void TREModel::nextStep(void)
3982 {
3983 // Don't do anything.
3984 }
3985
getShapeCount(TREMSection section,TREShapeType shapeType,bool colored)3986 int TREModel::getShapeCount(
3987 TREMSection section,
3988 TREShapeType shapeType,
3989 bool colored)
3990 {
3991 TREShapeGroup *shapes;
3992
3993 if (colored)
3994 {
3995 shapes = m_coloredShapes[section];
3996 }
3997 else
3998 {
3999 shapes = m_shapes[section];
4000 }
4001 if (shapes != NULL)
4002 {
4003 TCULongArray *indices = shapes->getIndices(shapeType);
4004
4005 if (indices != NULL)
4006 {
4007 int size = 1;
4008
4009 switch (shapeType)
4010 {
4011 case TRESTriangle:
4012 size = 3;
4013 break;
4014 case TRESQuad:
4015 size = 4;
4016 break;
4017 default:
4018 // Get rid of warning.
4019 break;
4020 }
4021 return indices->getCount() / size;
4022 }
4023 }
4024 return 0;
4025 }
4026
startTexture(int type,const std::string & filename,TCImage * image,const TCVector * points,const TCFloat * extra)4027 void TREModel::startTexture(
4028 int type,
4029 const std::string &filename,
4030 TCImage *image,
4031 const TCVector *points,
4032 const TCFloat *extra)
4033 {
4034 TexmapInfo info((TexmapType)type, filename, points, extra);
4035
4036 if (this != m_mainModel)
4037 {
4038 m_mainModel->startTexture(filename, image);
4039 }
4040 //info.standard.standard.triangleOffset = getShapeCount(TREMStandard,
4041 // TRESTriangle, false);
4042 //info.standard.colored.triangleOffset = getShapeCount(TREMStandard,
4043 // TRESTriangle, true);
4044 //info.bfc.standard.triangleOffset = getShapeCount(TREMBFC, TRESTriangle,
4045 // false);
4046 //info.bfc.colored.triangleOffset = getShapeCount(TREMBFC, TRESTriangle,
4047 // true);
4048 //info.standard.standard.quadOffset = getShapeCount(TREMStandard,
4049 // TRESQuad, false);
4050 //info.standard.colored.quadOffset = getShapeCount(TREMStandard,
4051 // TRESQuad, true);
4052 //info.bfc.standard.quadOffset = getShapeCount(TREMBFC, TRESQuad, false);
4053 //info.bfc.colored.quadOffset = getShapeCount(TREMBFC, TRESQuad, true);
4054 info.subModelOffset = getSubModelCount();
4055 m_texmapInfos.push_back(info);
4056 }
4057
endTexture(void)4058 bool TREModel::endTexture(void)
4059 {
4060 return m_mainModel->endTexture();
4061 }
4062
disableTexmaps(void)4063 void TREModel::disableTexmaps(void)
4064 {
4065 glDisable(GL_TEXTURE_GEN_S);
4066 glDisable(GL_TEXTURE_GEN_T);
4067 glDisable(GL_TEXTURE_2D);
4068 }
4069
activateTexmap(const TexmapInfo & texmapInfo)4070 void TREModel::activateTexmap(const TexmapInfo &texmapInfo)
4071 {
4072 GLuint textureID = m_mainModel->getTexmapTextureID(texmapInfo.filename);
4073
4074 if (textureID == 0)
4075 {
4076 return;
4077 }
4078 glEnable(GL_TEXTURE_2D);
4079 glBindTexture(GL_TEXTURE_2D, textureID);
4080 if (texmapInfo.type == TTPlanar)
4081 {
4082 const TCVector *points = texmapInfo.points;
4083
4084 TCVector point = points[0];
4085 TCVector normal = points[1] - point;
4086 double length = normal.length();
4087 double scale = 1.0;
4088 normal /= (TCFloat)length; // Normalize normal
4089 double planeCoefficients[4];
4090 planeCoefficients[0] = (normal[0] * scale) / length;
4091 planeCoefficients[1] = (normal[1] * scale) / length;
4092 planeCoefficients[2] = (normal[2] * scale) / length;
4093 planeCoefficients[3] = -(normal.dot(point) * scale) / length;
4094
4095 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
4096 glTexGendv(GL_S, GL_OBJECT_PLANE, planeCoefficients);
4097 glEnable(GL_TEXTURE_GEN_S);
4098
4099 normal = points[2] - point;
4100 length = normal.length();
4101 normal /= (TCFloat)length; // Normalize normal
4102 planeCoefficients[0] = (normal[0] * scale) / length;
4103 planeCoefficients[1] = (normal[1] * scale) / length;
4104 planeCoefficients[2] = (normal[2] * scale) / length;
4105 planeCoefficients[3] = -(normal.dot(point) * scale) / length;
4106
4107 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
4108 glTexGendv(GL_T, GL_OBJECT_PLANE, planeCoefficients);
4109 glEnable(GL_TEXTURE_GEN_T);
4110 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
4111 m_mainModel->getTexClampMode());
4112 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
4113 m_mainModel->getTexClampMode());
4114 }
4115 else
4116 {
4117 glDisable(GL_TEXTURE_GEN_S);
4118 glDisable(GL_TEXTURE_GEN_T);
4119 if (texmapInfo.type == TTCylindrical || texmapInfo.type == TTSpherical)
4120 {
4121 GLint sClamp = m_mainModel->getTexClampMode();
4122 if (texmapInfo.sAngleIs360)
4123 {
4124 sClamp = GL_REPEAT;
4125 }
4126 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, sClamp);
4127 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
4128 m_mainModel->getTexClampMode());
4129 }
4130 }
4131 }
4132
getSubModelCount(void) const4133 int TREModel::getSubModelCount(void) const
4134 {
4135 if (m_subModels != NULL)
4136 {
4137 return m_subModels->getCount();
4138 }
4139 else
4140 {
4141 return 0;
4142 }
4143 }
4144
finishPart(void)4145 void TREModel::finishPart(void)
4146 {
4147 if (m_mainModel->getFlattenPartsFlag())
4148 {
4149 flatten();
4150 }
4151 if (m_mainModel->getSmoothCurvesFlag())
4152 {
4153 smooth();
4154 }
4155 }
4156
shrinkParts(void)4157 void TREModel::shrinkParts(void)
4158 {
4159 if (!isPart())
4160 {
4161 if (m_subModels != NULL)
4162 {
4163 for (int i = 0; i < m_subModels->getCount(); i++)
4164 {
4165 TRESubModel *subModel = (*m_subModels)[i];
4166 TREModel *model = subModel->getModel();
4167
4168 if (model->isPart())
4169 {
4170 // Note: if we even get here, then
4171 // m_mainModel->getSeamWidth() is non-zero.
4172 if (!model->getNoShrinkFlag())
4173 {
4174 subModel->shrink(m_mainModel->getSeamWidth());
4175 }
4176 }
4177 else
4178 {
4179 model->shrinkParts();
4180 }
4181 }
4182 }
4183 }}
4184
finishParts(void)4185 void TREModel::finishParts(void)
4186 {
4187 if (isPart())
4188 {
4189 finishPart();
4190 }
4191 else
4192 {
4193 if (m_subModels != NULL)
4194 {
4195 for (int i = 0; i < m_subModels->getCount(); i++)
4196 {
4197 TRESubModel *subModel = (*m_subModels)[i];
4198 TREModel *model = subModel->getModel();
4199
4200 if (model->isPart())
4201 {
4202 model->finishPart();
4203 }
4204 else
4205 {
4206 model->finishParts();
4207 }
4208 }
4209 }
4210 }
4211 }
4212
TexmapInfo(void)4213 TREModel::TexmapInfo::TexmapInfo(void)
4214 : type(TTPlanar)
4215 , cylHeight(0.0)
4216 , sAngle(0.0)
4217 , tAngle(0.0)
4218 , sAngleIs360(false)
4219 , subModelOffset(0)
4220 , subModelCount(0)
4221 {
4222 }
4223
TexmapInfo(TexmapType type,const std::string & filename,const TCVector * otherPoints,const TCFloat * extra)4224 TREModel::TexmapInfo::TexmapInfo(
4225 TexmapType type,
4226 const std::string &filename,
4227 const TCVector *otherPoints,
4228 const TCFloat *extra)
4229 : type(type)
4230 , filename(filename)
4231 , cylHeight(0.0)
4232 , sAngle(0.0)
4233 , tAngle(0.0)
4234 , sAngleIs360(false)
4235 , subModelOffset(0)
4236 , subModelCount(0)
4237 {
4238 copyPoints(otherPoints);
4239 if (type == TTCylindrical)
4240 {
4241 calcCylFields();
4242 sAngle = deg2rad(extra[0]);
4243 sAngleIs360 = extra[0] >= 360 || extra[0] <= -360;
4244 }
4245 else if (type == TTSpherical)
4246 {
4247 calcSphereFields();
4248 sAngle = deg2rad(extra[0]);
4249 sAngleIs360 = extra[0] >= 360 || extra[0] <= -360;
4250 tAngle = deg2rad(extra[1]);
4251 }
4252 }
4253
texmapEquals(const TexmapInfo & other)4254 bool TREModel::TexmapInfo::texmapEquals(const TexmapInfo &other)
4255 {
4256 return type == other.type &&
4257 points[0] == other.points[0] &&
4258 points[1] == other.points[1] &&
4259 points[2] == other.points[2] &&
4260 sAngle == other.sAngle &&
4261 tAngle == other.tAngle &&
4262 cylHeight == other.cylHeight &&
4263 filename == other.filename;
4264 }
4265
copyPoints(const TCVector * otherPoints)4266 void TREModel::TexmapInfo::copyPoints(const TCVector *otherPoints)
4267 {
4268 points[0] = otherPoints[0];
4269 points[1] = otherPoints[1];
4270 points[2] = otherPoints[2];
4271 }
4272
transform(const TCFloat * matrix)4273 void TREModel::TexmapInfo::transform(const TCFloat* matrix)
4274 {
4275 if (matrix != NULL)
4276 {
4277 for (size_t i = 0; i < 3; i++)
4278 {
4279 points[i] = points[i].transformPoint(matrix);
4280 }
4281 if (type == TTCylindrical)
4282 {
4283 calcCylFields();
4284 }
4285 else if (type == TTSpherical)
4286 {
4287 calcSphereFields();
4288 }
4289 }
4290 }
4291
calcCylFields(void)4292 void TREModel::TexmapInfo::calcCylFields(void)
4293 {
4294 a = points[0];
4295 TCVector b = points[1];
4296 normal = a - b;
4297 cylHeight = normal.length();
4298 normal /= cylHeight;
4299 dir = cylDirectionFrom(points[2]);
4300 }
4301
calcSphereFields(void)4302 void TREModel::TexmapInfo::calcSphereFields(void)
4303 {
4304 a = points[0];
4305 normal = -((points[0] - points[1]) * (points[2] - points[1])).normalize();
4306 normal2 = (normal * (points[1] - a)).normalize();
4307 dir = (points[1] - points[0]).normalize();
4308 }
4309
cylDirectionFrom(const TCVector & point)4310 TCVector TREModel::TexmapInfo::cylDirectionFrom(const TCVector& point)
4311 {
4312 return directionFrom(point, normal);
4313 }
4314
directionFrom(const TCVector & point,const TCVector & norm)4315 TCVector TREModel::TexmapInfo::directionFrom(
4316 const TCVector& point,
4317 const TCVector& norm)
4318 {
4319 TCVector ap = point - a;
4320 TCVector proj = a + ap.dot(norm) / norm.dot(norm) * norm;
4321 TCVector dir = point - proj;
4322 return dir.normalize();
4323 }
4324
distanceToPlane(const TCVector & point,const TCVector & planePoint,const TCVector & planeNormal)4325 TCFloat TREModel::TexmapInfo::distanceToPlane(
4326 const TCVector& point,
4327 const TCVector& planePoint,
4328 const TCVector& planeNormal)
4329 {
4330 return planeNormal.dot(planePoint - point);
4331 }
4332
calcTextureCoords(const TCVector * ppoints,TCVector * textureCoords)4333 void TREModel::TexmapInfo::calcTextureCoords(
4334 const TCVector* ppoints,
4335 TCVector* textureCoords)
4336 {
4337 if (type == TTCylindrical)
4338 {
4339 calcCylTextureCoords(ppoints, textureCoords);
4340 }
4341 else if (type == TTSpherical)
4342 {
4343 calcSphereTextureCoords(ppoints, textureCoords);
4344 }
4345 }
4346
calcSAngle(const TCVector & point,bool isFirst,TCVector & baseDir,TCFloat & baseAngle)4347 TCFloat TREModel::TexmapInfo::calcSAngle(
4348 const TCVector& point,
4349 bool isFirst,
4350 TCVector& baseDir,
4351 TCFloat& baseAngle)
4352 {
4353 TCFloat curAngle;
4354 if (isFirst)
4355 {
4356 baseDir = cylDirectionFrom(point);
4357 curAngle = atan2((dir * baseDir).dot(normal), baseDir.dot(dir));
4358 }
4359 else
4360 {
4361 TCVector curDir = cylDirectionFrom(point);
4362 curAngle = atan2((baseDir * curDir).dot(normal), curDir.dot(baseDir)) +
4363 baseAngle;
4364 }
4365 if (isFirst)
4366 {
4367 baseAngle = curAngle;
4368 }
4369 return curAngle;
4370 }
4371
calcCylTextureCoords(const TCVector * ppoints,TCVector * textureCoords)4372 void TREModel::TexmapInfo::calcCylTextureCoords(
4373 const TCVector* ppoints,
4374 TCVector* textureCoords)
4375 {
4376 TCVector baseDir;
4377 TCFloat baseAngle = 0.0;
4378 for (size_t i = 0; i < 3; ++i)
4379 {
4380 const TCVector& point(ppoints[i]);
4381 TCVector& tc(textureCoords[i]);
4382 tc[0] = 0.5 + calcSAngle(point, i == 0, baseDir, baseAngle) / sAngle;
4383 tc[1] = distanceToPlane(point, a, normal) / cylHeight;
4384 }
4385 }
4386
4387
calcSphereTextureCoords(const TCVector * ppoints,TCVector * textureCoords)4388 void TREModel::TexmapInfo::calcSphereTextureCoords(
4389 const TCVector* ppoints,
4390 TCVector* textureCoords)
4391 {
4392 TCVector baseDir;
4393 TCFloat baseAngle = 0.0;
4394 std::vector<size_t> poleIndices;
4395 TCFloat uSum = 0.0;
4396 for (size_t i = 0; i < 3; ++i)
4397 {
4398 const TCVector& point(ppoints[i]);
4399 TCVector& tc(textureCoords[i]);
4400 TCVector pointDir = (point - a).normalize();
4401 bool northPole = pointDir.approxEquals(normal, 1e-05);
4402 bool southPole = false;
4403 if (!northPole)
4404 {
4405 southPole = pointDir.approxEquals(-normal, 1e-05);
4406 }
4407 TCFloat pointSAngle = 0.0;
4408 TCFloat pointTAngle;
4409 if (northPole || southPole)
4410 {
4411 poleIndices.push_back(i);
4412 if (northPole)
4413 {
4414 pointTAngle = -M_PI_2;
4415 }
4416 else
4417 {
4418 pointTAngle = M_PI_2;
4419 }
4420 }
4421 else
4422 {
4423 pointSAngle = calcSAngle(point, i == 0, baseDir, baseAngle);
4424 uSum += pointSAngle;
4425 TCFloat theta = -pointSAngle;
4426 // Rotate pointDir around normal until it's at 0 longitude.
4427 TCVector refPointDir = (pointDir * cos(theta) +
4428 (normal * pointDir) * sin(theta) + normal *
4429 normal.dot(pointDir) * (1.0 - cos(theta))).normalize();
4430 pointTAngle = atan2((dir * refPointDir).dot(normal2),
4431 refPointDir.dot(dir));
4432 }
4433 tc[0] = 0.5 + pointSAngle / sAngle;
4434 tc[1] = 0.5 + pointTAngle / tAngle;
4435 }
4436 if (!poleIndices.empty() && poleIndices.size() < 3)
4437 {
4438 TCFloat uAverage = 0.5 + uSum / (3 - poleIndices.size()) / sAngle;
4439 for (size_t i = 0; i < poleIndices.size(); ++i)
4440 {
4441 TCVector& tc(textureCoords[poleIndices[i]]);
4442 tc[0] = uAverage;
4443 }
4444 }
4445 }
4446