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 &center, 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 &center, 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 &center, 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 &center,
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 &center,
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 &center,
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