1 /*
2 
3 	Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4 	and the "Aleph One" developers.
5 
6 	This program is free software; you can redistribute it and/or modify
7 	it under the terms of the GNU General Public License as published by
8 	the Free Software Foundation; either version 3 of the License, or
9 	(at your option) any later version.
10 
11 	This program is distributed in the hope that it will be useful,
12 	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 	GNU General Public License for more details.
15 
16 	This license is contained in the file "COPYING",
17 	which is included with this source code; it is available online at
18 	http://www.gnu.org/licenses/gpl.html
19 
20 	3D-Model Object Storage Functions
21 
22 	By Loren Petrich, July 8, 2001
23 */
24 
25 #include <string.h>
26 #include <math.h>
27 
28 #include "VecOps.h"
29 #include "cseries.h"
30 #include "world.h"
31 
32 #ifdef HAVE_OPENGL
33 
34 #ifdef __WIN32__
35 #include <windows.h>
36 #endif
37 
38 #include "Model3D.h"
39 
40 #ifdef HAVE_OPENGL
41 #include "OGL_Headers.h"
42 #endif
43 
44 /* Need Sgl* macros */
45 #include "OGL_Setup.h"
46 
47 // Bone-stack and transformation-matrix locally-used arrays;
48 // the matrices have dimensions (output coords)(input-coord multipliers + offset for output)
49 static vector<Model3D_Transform> BoneMatrices;
50 static vector<size_t> BoneStack;
51 
52 
53 // Find transform of point (source and dest must be different arrays)
TransformPoint(GLfloat * Dest,GLfloat * Src,Model3D_Transform & T)54 inline void TransformPoint(GLfloat *Dest, GLfloat *Src, Model3D_Transform& T)
55 {
56 	for (int ic=0; ic<3; ic++)
57 	{
58 		GLfloat *Row = T.M[ic];
59 		Dest[ic] = ScalarProd(Src,Row) + Row[3];
60 	}
61 }
62 
63 // Like above, but a vector, such as a normal (source and dest must be different arrays)
TransformVector(GLfloat * Dest,GLfloat * Src,Model3D_Transform & T)64 inline void TransformVector(GLfloat *Dest, GLfloat *Src, Model3D_Transform& T)
65 {
66 	for (int ic=0; ic<3; ic++)
67 	{
68 		GLfloat *Row = T.M[ic];
69 		Dest[ic] = ScalarProd(Src,Row);
70 	}
71 }
72 
73 // Bone and Frame (positions, angles) -> Transform Matrix
74 static void FindFrameTransform(Model3D_Transform& T,
75 	Model3D_Frame& Frame, GLfloat MixFrac, Model3D_Frame& AddlFrame);
76 static void FindBoneTransform(Model3D_Transform& T, Model3D_Bone& Bone,
77 	Model3D_Frame& Frame, GLfloat MixFrac, Model3D_Frame& AddlFrame);
78 
79 // Res = A * B, in that order
80 static void TMatMultiply(Model3D_Transform& Res, Model3D_Transform& A, Model3D_Transform& B);
81 
82 
83 // Trig-function conversion:
84 const GLfloat TrigNorm = GLfloat(1)/GLfloat(TRIG_MAGNITUDE);
85 
86 
87 // Erase everything
Clear()88 void Model3D::Clear()
89 {
90 	Positions.clear();
91 	TxtrCoords.clear();
92 	Normals.clear();
93 	Colors.clear();
94 	VtxSrcIndices.clear();
95 	VtxSources.clear();
96 	NormSources.clear();
97 	InverseVSIndices.clear();
98 	InvVSIPointers.clear();
99 	Bones.clear();
100 	VertIndices.clear();
101 	Frames.clear();
102 	SeqFrames.clear();
103 	SeqFrmPointers.clear();
104 	FindBoundingBox();
105 }
106 
107 // Normalize an individual normal; return whether the normal had a nonzero length
NormalizeNormal(GLfloat * Normal)108 static bool NormalizeNormal(GLfloat *Normal)
109 {
110 	GLfloat NormalSqr =
111 		Normal[0]*Normal[0] + Normal[1]*Normal[1] + Normal[2]*Normal[2];
112 
113 	if (NormalSqr <= 0) return false;
114 
115 	GLfloat NormalRecip = (GLfloat)(1/sqrt(NormalSqr));
116 
117 	Normal[0] *= NormalRecip;
118 	Normal[1] *= NormalRecip;
119 	Normal[2] *= NormalRecip;
120 
121 	return true;
122 }
123 
124 // Flagged vector for per-polygon and per-vertex normals;
125 // the flag is "true" for nonzero vectors and vectors meant to be used
126 struct FlaggedVector
127 {
128 	GLfloat Vec[3];
129 	bool Flag;
130 };
131 
CalculateTangents()132 void Model3D::CalculateTangents()
133 {
134 	Tangents.resize(Positions.size() * 4 / 3);
135 
136 	bool generate_normals = false;
137 	if(Normals.size() != Positions.size()) {
138 		Normals.resize(Positions.size());
139 		memset(NormBase(), 0, sizeof(GLfloat)*Normals.size());
140 		generate_normals = true;
141 	}
142 
143 	for(GLushort i = 0; i < VertIndices.size(); i+= 3) {
144 		GLushort a = VertIndices[i];
145 		GLushort b = VertIndices[i+1];
146 		GLushort c = VertIndices[i+2];
147 
148 		vertex3 v1(PosBase()+3*a);
149 		vertex3 v2(PosBase()+3*b);
150 		vertex3 v3(PosBase()+3*c);
151 
152 		vertex2 w1(0, 0);
153 		vertex2 w2(0, 0);
154 		vertex2 w3(0, 0);
155 		if (TxtrCoords.size()) {
156 			w1 = vertex2(TCBase()+2*a);
157 			w2 = vertex2(TCBase()+2*b);
158 			w3 = vertex2(TCBase()+2*c);
159 		}
160 
161 		float x1 = v2[0] - v1[0];
162 		float x2 = v3[0] - v1[0];
163 		float y1 = v2[1] - v1[1];
164 		float y2 = v3[1] - v1[1];
165 		float z1 = v2[2] - v1[2];
166 		float z2 = v3[2] - v1[2];
167 
168 		float s1 = w2[0] - w1[0];
169 		float s2 = w3[0] - w1[0];
170 		float t1 = w2[1] - w1[1];
171 		float t2 = w3[1] - w1[1];
172 
173 		float r = 1.0f / (s1 * t2 - s2 * t1);
174 		vec3 T((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
175 			   (t2 * z1 - t1 * z2) * r);
176 		vec3 B((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
177 			   (s1 * z2 - s2 * z1) * r);
178 		if ((s1 * t2 - s2 * t1) == 0.0) {
179 			T = (v3 - v1).norm();
180 			B = (v2 - v1).norm();
181 		}
182 
183 		vec3 N = (v3-v1).cross(v2-v1);
184 		if (!generate_normals) {
185 			N = vec3(NormBase()+3*a) + vec3(NormBase()+3*b) + vec3(NormBase()+3*c);
186 		}
187 
188 		if(N.dot(N) < 0.001) {
189 			N = vec3(0.0,0.0,0.0);
190 			if (generate_normals) {
191 				VecCopy(N.p(), NormBase()+3*a);
192 				VecCopy(N.p(), NormBase()+3*b);
193 				VecCopy(N.p(), NormBase()+3*c);
194 			}
195 
196 			vec4 t(0.0,0.0,0.0,0.0);
197 			Tangents[a] = vec4(t);
198 			Tangents[b] = vec4(t);
199 			Tangents[c] = vec4(t);
200 		} else {
201 			N = N.norm();
202 			assert(N.dot(N) < 1.001);
203 
204 			if (generate_normals) {
205 				VecCopy(N.p(), NormBase()+3*a);
206 				VecCopy(N.p(), NormBase()+3*b);
207 				VecCopy(N.p(), NormBase()+3*c);
208 			}
209 
210 			float sign = (N.cross(T)).dot(B) < 0.0 ? -1.0 : 1.0;
211 			vec4 t = (T - N * N.dot(T)).norm();
212 			t[3] = sign;
213 
214 			Tangents[a] = vec4(t);
215 			Tangents[b] = vec4(t);
216 			Tangents[c] = vec4(t);
217 		}
218 	}
219 }
220 
221 
222 // Normalize the normals
AdjustNormals(int NormalType,float SmoothThreshold)223 void Model3D::AdjustNormals(int NormalType, float SmoothThreshold)
224 {
225 	// Copy in normal sources for processing
226 	if (!NormSources.empty())
227 	{
228 		Normals.resize(NormSources.size());
229 		objlist_copy(NormBase(),NormSrcBase(),NormSources.size());
230 	}
231 
232 	// Which kind of special processing?
233 	switch(NormalType)
234 	{
235 	case None:
236 		Normals.clear();
237 		break;
238 
239 	case Original:
240 	case Reversed:
241 	default:
242 		// Normalize
243 		for (unsigned k=0; k<Normals.size()/3; k++)
244 			NormalizeNormal(&Normals[3*k]);
245 		break;
246 
247 	case ClockwiseSide:
248 	case CounterclockwiseSide:
249 		// The really interesting stuff
250 		{
251 			// First, create a list of per-polygon normals
252 			size_t NumPolys = NumVI()/3;
253 			vector<FlaggedVector> PerPolygonNormalList(NumPolys);
254 
255 			GLushort *IndxPtr = VIBase();
256 			for (unsigned k=0; k<NumPolys; k++)
257 			{
258 				// The three vertices:
259 				GLfloat *P0 = &Positions[3*(*(IndxPtr++))];
260 				GLfloat *P1 = &Positions[3*(*(IndxPtr++))];
261 				GLfloat *P2 = &Positions[3*(*(IndxPtr++))];
262 				// The two in-polygon vectors:
263 				GLfloat P01[3];
264 				P01[0] = P1[0] - P0[0];
265 				P01[1] = P1[1] - P0[1];
266 				P01[2] = P1[2] - P0[2];
267 				GLfloat P02[3];
268 				P02[0] = P2[0] - P0[0];
269 				P02[1] = P2[1] - P0[1];
270 				P02[2] = P2[2] - P0[2];
271 				// Those vectors' normal:
272 				FlaggedVector& PPN = PerPolygonNormalList[k];
273 				PPN.Vec[0] = P01[1]*P02[2] - P01[2]*P02[1];
274 				PPN.Vec[1] = P01[2]*P02[0] - P01[0]*P02[2];
275 				PPN.Vec[2] = P01[0]*P02[1] - P01[1]*P02[0];
276 				PPN.Flag = NormalizeNormal(PPN.Vec);
277 			}
278 
279 			// Create a list of per-vertex normals
280 			size_t NumVerts = Positions.size()/3;
281 			vector<FlaggedVector> PerVertexNormalList(NumVerts);
282 			objlist_clear(&PerVertexNormalList[0],NumVerts);
283 			IndxPtr = VIBase();
284 			for (unsigned k=0; k<NumPolys; k++)
285 			{
286 				FlaggedVector& PPN = PerPolygonNormalList[k];
287 				for (unsigned c=0; c<3; c++)
288 				{
289 					GLushort VertIndx = *(IndxPtr++);
290 					GLfloat *V = PerVertexNormalList[VertIndx].Vec;
291 					*(V++) += PPN.Vec[0];
292 					*(V++) += PPN.Vec[1];
293 					*(V++) += PPN.Vec[2];
294 				}
295 			}
296 
297 			// Normalize the per-vertex normals
298 			for (unsigned k=0; k<NumVerts; k++)
299 			{
300 				FlaggedVector& PVN = PerVertexNormalList[k];
301 				PVN.Flag = NormalizeNormal(PVN.Vec);
302 			}
303 
304 			// Find the variance of each of the per-vertex normals;
305 			// use that to decide whether to keep them unsplit;
306 			// this also needs counting up the number of polygons per vertex.
307 			vector<GLfloat> Variances(NumVerts);
308 			objlist_clear(&Variances[0],NumVerts);
309 			vector<short> NumPolysPerVert(NumVerts);
310 			objlist_clear(&NumPolysPerVert[0],NumVerts);
311 			IndxPtr = VIBase();
312 			for (unsigned k=0; k<NumPolys; k++)
313 			{
314 				FlaggedVector& PPN = PerPolygonNormalList[k];
315 				for (unsigned c=0; c<3; c++)
316 				{
317 					GLushort VertIndx = *(IndxPtr++);
318 					FlaggedVector& PVN = PerVertexNormalList[VertIndx];
319 					if (PVN.Flag)
320 					{
321 						GLfloat *V = PVN.Vec;
322 						GLfloat D0 = *(V++) - PPN.Vec[0];
323 						GLfloat D1 = *(V++) - PPN.Vec[1];
324 						GLfloat D2 = *(V++) - PPN.Vec[2];
325 						Variances[VertIndx] += (D0*D0 + D1*D1 + D2*D2);
326 						NumPolysPerVert[VertIndx]++;
327 					}
328 				}
329 			}
330 
331 			// Decide whether to split each vertex;
332 			// if the flag is "true", a vertex is not to be split
333 			for (unsigned k=0; k<NumVerts; k++)
334 			{
335 				// Vertices without contributions will automatically have
336 				// their flags be false, as a result of NormalizeNormal()
337 				unsigned NumVertPolys = NumPolysPerVert[k];
338 				if (NumVertPolys > 0 && PerVertexNormalList[k].Flag)
339 					PerVertexNormalList[k].Flag =
340 						sqrt(Variances[k]/NumVertPolys) <= SmoothThreshold;
341 			}
342 
343 			// The vertex flags are now set for whether to use that vertex's normal;
344 			// re-count the number of polygons per vertex.
345 			// Use NONE for unsplit ones
346 			objlist_clear(&NumPolysPerVert[0],NumVerts);
347 			IndxPtr = VIBase();
348 			for (unsigned k=0; k<NumPolys; k++)
349 			{
350 				for (unsigned c=0; c<3; c++)
351 				{
352 					GLushort VertIndx = *(IndxPtr++);
353 					FlaggedVector& PVN = PerVertexNormalList[VertIndx];
354 					if (PVN.Flag)
355 						NumPolysPerVert[VertIndx] = NONE;
356 					else
357 						NumPolysPerVert[VertIndx]++;
358 				}
359 			}
360 
361 			// Construct a polygon-association list; this will indicate
362 			// which polygons are associated with each of the resulting instances
363 			// of a split vertex (unsplit: NONE).
364 			// NumPolysPerVert will be recycled as a counter list,
365 			// after being used to construct a cumulative index-in-list array.
366 			// Finding that list will be used to find how many new vertices there are.
367 			vector<short> IndicesInList(NumVerts);
368 			short IndxInList = 0;
369 			for (unsigned k=0; k<NumVerts; k++)
370 			{
371 				IndicesInList[k] = IndxInList;
372 				FlaggedVector& PVN = PerVertexNormalList[k];
373 				IndxInList += PVN.Flag ? 1 : NumPolysPerVert[k];
374 			}
375 			GLushort NewNumVerts = IndxInList;
376 			vector<short> VertexPolygons(NewNumVerts);
377 			objlist_clear(&NumPolysPerVert[0],NumVerts);
378 
379 			// In creating that list, also remap the triangles' vertices
380 			GLushort *VIPtr = VIBase();
381 			for (unsigned k=0; k<NumPolys; k++)
382 			{
383 				for (unsigned c=0; c<3; c++)
384 				{
385 					GLushort VertIndx = *VIPtr;
386 					GLushort NewVertIndx = IndicesInList[VertIndx];
387 					FlaggedVector& PVN = PerVertexNormalList[VertIndx];
388 					if (PVN.Flag)
389 					{
390 						NumPolysPerVert[VertIndx] = NONE;
391 						VertexPolygons[NewVertIndx] = NONE;
392 					}
393 					else
394 					{
395 						NewVertIndx += (NumPolysPerVert[VertIndx]++);
396 						VertexPolygons[NewVertIndx] = k;
397 					}
398 					*VIPtr = NewVertIndx;
399 					VIPtr++;
400 				}
401 			}
402 
403 			// Split the vertices
404 			vector<GLfloat> NewPositions(3*NewNumVerts);
405 			vector<GLfloat> NewTxtrCoords;
406 			vector<GLfloat> NewNormals(3*NewNumVerts);
407 			vector<GLfloat> NewColors;
408 			vector<GLushort> NewVtxSrcIndices;
409 
410 			bool TCPresent = !TxtrCoords.empty();
411 			if (TCPresent) NewTxtrCoords.resize(2*NewNumVerts);
412 
413 			bool ColPresent = !Colors.empty();
414 			if (ColPresent) NewColors.resize(3*NewNumVerts);
415 
416 			bool VSPresent = !VtxSrcIndices.empty();
417 			if (VSPresent) NewVtxSrcIndices.resize(NewNumVerts);
418 
419 			// Use marching pointers to speed up the copy-over
420 			GLfloat *OldP = &Positions[0];
421 			GLfloat *NewP = &NewPositions[0];
422 			GLfloat *OldT = &TxtrCoords[0];
423 			GLfloat *NewT = &NewTxtrCoords[0];
424 			GLfloat *OldC = &Colors[0];
425 			GLfloat *NewC = &NewColors[0];
426 			GLushort *OldS = &VtxSrcIndices[0];
427 			GLushort *NewS = &NewVtxSrcIndices[0];
428 			GLfloat *NewN = &NewNormals[0];
429 			for (unsigned k=0; k<NumVerts; k++)
430 			{
431 				FlaggedVector& PVN = PerVertexNormalList[k];
432 				unsigned NumVertPolys = PVN.Flag ? 1 : NumPolysPerVert[k];
433 				for (unsigned c=0; c<NumVertPolys; c++)
434 				{
435 					GLfloat *OldPP = OldP;
436 					*(NewP++) = *(OldPP++);
437 					*(NewP++) = *(OldPP++);
438 					*(NewP++) = *(OldPP++);
439 				}
440 				if (TCPresent)
441 				{
442 					for (unsigned c=0; c<NumVertPolys; c++)
443 					{
444 						GLfloat *OldTP = OldT;
445 						*(NewT++) = *(OldTP++);
446 						*(NewT++) = *(OldTP++);
447 					}
448 				}
449 				if (ColPresent)
450 				{
451 					for (unsigned c=0; c<NumVertPolys; c++)
452 					{
453 						GLfloat *OldCP = OldC;
454 						*(NewC++) = *(OldCP++);
455 						*(NewC++) = *(OldCP++);
456 						*(NewC++) = *(OldCP++);
457 					}
458 				}
459 				if (VSPresent)
460 				{
461 					for (unsigned c=0; c<NumVertPolys; c++)
462 						*(NewS++) = *OldS;
463 				}
464 				if (PVN.Flag)
465 				{
466 					GLfloat *VP = PVN.Vec;
467 					*(NewN++) = *(VP++);
468 					*(NewN++) = *(VP++);
469 					*(NewN++) = *(VP++);
470 				}
471 				else
472 				{
473 					// A reference so that the incrementing can work on it
474 					short& IndxInList = IndicesInList[k];
475 					for (unsigned c=0; c<NumVertPolys; c++)
476 					{
477 						GLfloat *VP = PerPolygonNormalList[VertexPolygons[IndxInList++]].Vec;
478 						*(NewN++) = *(VP++);
479 						*(NewN++) = *(VP++);
480 						*(NewN++) = *(VP++);
481 					}
482 				}
483 
484 				// Advance!
485 				OldP += 3;
486 				if (TCPresent)
487 					OldT += 2;
488 				if (ColPresent)
489 					OldC += 3;
490 				if (VSPresent)
491 					OldS++;
492 
493 			}
494 			assert(OldP == &Positions[3*NumVerts]);
495 			assert(NewP == &NewPositions[3*NewNumVerts]);
496 			if (TCPresent)
497 			{
498 				assert(OldT == &TxtrCoords[2*NumVerts]);
499 				assert(NewT == &NewTxtrCoords[2*NewNumVerts]);
500 			}
501 			if (ColPresent)
502 			{
503 				assert(OldC == &Colors[3*NumVerts]);
504 				assert(NewC == &NewColors[3*NewNumVerts]);
505 			}
506 			if (VSPresent)
507 			{
508 				assert(OldS == &VtxSrcIndices[NumVerts]);
509 				assert(NewS == &NewVtxSrcIndices[NewNumVerts]);
510 			}
511 			assert(NewN == &NewNormals[3*NewNumVerts]);
512 
513 			// Accept the new vectors
514 			Positions.swap(NewPositions);
515 			TxtrCoords.swap(NewTxtrCoords);
516 			Normals.swap(NewNormals);
517 			Colors.swap(NewColors);
518 			VtxSrcIndices.swap(NewVtxSrcIndices);
519 		}
520 		break;
521 	}
522 
523 	// Now flip
524 	switch(NormalType)
525 	{
526 	case Reversed:
527 	case CounterclockwiseSide:
528 		{
529 			GLfloat *NormalPtr = NormBase();
530 			for (unsigned k=0; k<Normals.size(); k++)
531 				*(NormalPtr++) *= -1;
532 		}
533 	}
534 
535 	// Copy back out to the normal sources;
536 	// do the copying out if the vertices have sources,
537 	// which is the case for boned models.
538 	if (!VtxSources.empty())
539 	{
540 		size_t NormSize = Normals.size();
541 		if (NormSize > 0)
542 		{
543 			NormSources.resize(NormSize);
544 			objlist_copy(NormSrcBase(),NormBase(),NormSize);
545 		}
546 		else
547 			NormSources.clear();
548 	}
549 	else
550 		NormSources.clear();
551 }
552 
553 
554 // From the position data
FindBoundingBox()555 void Model3D::FindBoundingBox()
556 {
557 	size_t NumVertices = Positions.size()/3;
558 	if (NumVertices > 0)
559 	{
560 		// Find the min and max of the positions:
561 		VecCopy(&Positions[0],BoundingBox[0]);
562 		VecCopy(&Positions[0],BoundingBox[1]);
563 		for (size_t i=1; i<NumVertices; i++)
564 		{
565 			GLfloat *Pos = &Positions[3*i];
566 			for (int ib=0; ib<3; ib++)
567 			{
568 				BoundingBox[0][ib] = MIN(BoundingBox[0][ib],Pos[ib]);
569 				BoundingBox[1][ib] = MAX(BoundingBox[1][ib],Pos[ib]);
570 			}
571 		}
572 	}
573 	else
574 	{
575 		// Clear the bounding box
576 		objlist_clear(BoundingBox[0],3);
577 		objlist_clear(BoundingBox[1],3);
578 	}
579 }
580 
581 
582 #if 0
583 // For debugging
584 void Model3D::RenderBoundingBox(const GLfloat *EdgeColor, const GLfloat *DiagonalColor)
585 {
586 	GLfloat BBoxVertices[8][3];
587 
588 	// Binary-number arrangement of expanded vertices:
589 	for (int i1=0; i1<2; i1++)
590 		for (int i2=0; i2<2; i2++)
591 			for (int i3=0; i3<2; i3++)
592 			{
593 				int Indx = 4*i1 + 2*i2 + i3;
594 				BBoxVertices[Indx][0] = BoundingBox[i1][0];
595 				BBoxVertices[Indx][1] = BoundingBox[i2][1];
596 				BBoxVertices[Indx][2] = BoundingBox[i3][2];
597 			}
598 
599 	glDisable(GL_TEXTURE_2D);
600 	glDisableClientState(GL_COLOR_ARRAY);
601 	glEnableClientState(GL_VERTEX_ARRAY);
602 	glVertexPointer(3,GL_FLOAT,0,BBoxVertices[0]);
603 
604 	if (EdgeColor)
605 	{
606 		SglColor3fv(EdgeColor);
607 		const int NumEdgeVerts = 24;
608 		const unsigned short EdgeVerts[NumEdgeVerts] = {
609 			0,1,
610 			1,3,
611 			3,2,
612 			2,0,
613 
614 			0,4,
615 			1,5,
616 			2,6,
617 			3,7,
618 
619 			4,5,
620 			5,7,
621 			7,6,
622 			6,4
623 		};
624 		glDrawElements(GL_LINES,NumEdgeVerts,GL_UNSIGNED_SHORT,EdgeVerts);
625 	}
626 
627 	if (DiagonalColor)
628 	{
629 		SglColor3fv(DiagonalColor);
630 		const int NumDiagVerts = 24;
631 		const unsigned short DiagVerts[NumDiagVerts] = {
632 			0,3,
633 			1,2,
634 
635 			0,5,
636 			1,4,
637 
638 			1,7,
639 			3,5,
640 
641 			3,6,
642 			2,7,
643 
644 			2,4,
645 			0,6,
646 
647 			4,7,
648 			5,6
649 		};
650 		glDrawElements(GL_LINES,NumDiagVerts,GL_UNSIGNED_SHORT,DiagVerts);
651 	}
652 }
653 #endif
654 
BuildTrigTables()655 void Model3D::BuildTrigTables()
656 {
657 	build_trig_tables();
658 }
659 
660 
BuildInverseVSIndices()661 void Model3D::BuildInverseVSIndices()
662 {
663 	if (VtxSrcIndices.empty()) return;
664 
665 	InverseVSIndices.resize(VtxSrcIndices.size());
666 	InvVSIPointers.resize(VtxSources.size()+1);		// One extra member
667 
668 	// Use the pointers as temporary storage for the count
669 	objlist_clear(InvVSIPtrBase(),InvVSIPointers.size());
670 	for (vector<GLushort>::iterator VSI_Iter = VtxSrcIndices.begin();
671 		VSI_Iter < VtxSrcIndices.end();
672 		VSI_Iter++)
673 			InvVSIPointers[*VSI_Iter]++;
674 
675 	// Find the positions from the counts
676 	GLushort PtrSum = 0;
677 	for (vector<GLushort>::iterator IVP_Iter = InvVSIPointers.begin();
678 		IVP_Iter < InvVSIPointers.end();
679 		IVP_Iter++)
680 		{
681 			GLushort NewPtrSum = PtrSum + *IVP_Iter;
682 			*IVP_Iter = PtrSum;
683 			PtrSum = NewPtrSum;
684 		}
685 
686 	// Place the inverse indices
687 	for (unsigned k = 0; k<VtxSrcIndices.size(); k++)
688 		InverseVSIndices[InvVSIPointers[VtxSrcIndices[k]]++] = k;
689 
690 	// Push the pointer values forward in the list
691 	// since they'd become their next values in it.
692 	// The reverse iteration is necessary to avoid overwriting
693 	for (vector<GLushort>::iterator IVP_Iter = InvVSIPointers.end()-1;
694 		IVP_Iter > InvVSIPointers.begin();
695 		IVP_Iter--)
696 		{
697 			*IVP_Iter = *(IVP_Iter - 1);
698 		}
699 	InvVSIPointers[0] = 0;
700 }
701 
702 
703 // Neutral case: returns whether vertex-source data was used (present in animated models)
FindPositions_Neutral(bool UseModelTransform)704 bool Model3D::FindPositions_Neutral(bool UseModelTransform)
705 {
706 	// Positions already there
707 	if (VtxSrcIndices.empty()) return false;
708 
709 	// Straight copy of the vertices:
710 
711 	size_t NumVertices = VtxSrcIndices.size();
712 	Positions.resize(3*NumVertices);
713 
714 	GLfloat *PP = PosBase();
715 	GLushort *IP = VtxSIBase();
716 
717 	size_t NumVtxSources = VtxSources.size();
718 
719 	if (UseModelTransform)
720 	{
721 		for (size_t k=0; k<NumVertices; k++, IP++, PP+=3)
722 		{
723 			size_t VSIndex = *IP;
724 			if (VSIndex >= 0 && VSIndex < NumVtxSources)
725 			{
726 				Model3D_VertexSource& VS = VtxSources[VSIndex];
727 				TransformPoint(PP,VS.Position,TransformPos);
728 			}
729 			else
730 			{
731 				GLfloat VP[3] = {0,0,0};
732 				TransformPoint(PP,VP,TransformPos);
733 			}
734 		}
735 	}
736 	else
737 	{
738 		for (size_t k=0; k<NumVertices; k++, IP++)
739 		{
740 			size_t VSIndex = *IP;
741 			if (VSIndex >= 0 && VSIndex < NumVtxSources)
742 			{
743 				Model3D_VertexSource& VS = VtxSources[VSIndex];
744 				GLfloat *VP = VS.Position;
745 				*(PP++) = *(VP++);
746 				*(PP++) = *(VP++);
747 				*(PP++) = *(VP++);
748 			}
749 			else
750 			{
751 				*(PP++) = 0;
752 				*(PP++) = 0;
753 				*(PP++) = 0;
754 			}
755 		}
756 	}
757 
758 	// Copy in the normals
759 	Normals.resize(NormSources.size());
760 
761 	if (UseModelTransform)
762 	{
763 		GLfloat *NormPtr = NormBase();
764 		GLfloat *NormBasePtr = NormSrcBase();
765 		size_t NumNorms = NormSources.size()/3;
766 		for (size_t k=0; k<NumNorms; k++, NormPtr+=3, NormBasePtr+=3)
767 		{
768 			TransformVector(NormPtr, NormBasePtr, TransformNorm);
769 		}
770 	}
771 	else
772 	{
773 		objlist_copy(NormBase(),NormSrcBase(),NormSources.size());
774 	}
775 
776 	return true;
777 }
778 
779 // Frame case
FindPositions_Frame(bool UseModelTransform,GLshort FrameIndex,GLfloat MixFrac,GLshort AddlFrameIndex)780 bool Model3D::FindPositions_Frame(bool UseModelTransform,
781 	GLshort FrameIndex, GLfloat MixFrac, GLshort AddlFrameIndex)
782 {
783 	// Bad inputs: do nothing and return false
784 
785 	if (Frames.empty()) return false;
786 
787 	size_t NumBones = Bones.size();
788 	if (FrameIndex < 0 || NumBones*FrameIndex >= Frames.size()) return false;
789 
790 	if (InverseVSIndices.empty()) BuildInverseVSIndices();
791 
792 	size_t NumVertices = VtxSrcIndices.size();
793 	Positions.resize(3*NumVertices);
794 
795 	// Set sizes:
796 	BoneMatrices.resize(NumBones);
797 	BoneStack.resize(NumBones);
798 
799 	// Find which frame; remember that frame data comes in [NumBones] sets
800 	Model3D_Frame *FramePtr = &Frames[NumBones*FrameIndex];
801 	Model3D_Frame *AddlFramePtr = &Frames[NumBones*AddlFrameIndex];
802 
803 	// Find the individual-bone transformation matrices:
804 	for (size_t ib=0; ib<NumBones; ib++)
805 		FindBoneTransform(BoneMatrices[ib],Bones[ib],
806 			FramePtr[ib],MixFrac,AddlFramePtr[ib]);
807 
808 	// Find the cumulative-bone transformation matrices:
809 	int StackIndx = -1;
810 	size_t Parent = UNONE;
811 	for (unsigned int ib=0; ib<NumBones; ib++)
812 	{
813 		Model3D_Bone& Bone = Bones[ib];
814 
815 		// Do the pop-push with the stack
816 		// to get the bone's parent bone
817 		if (TEST_FLAG(Bone.Flags,Model3D_Bone::Pop))
818 		{
819 			if (StackIndx >= 0)
820 				Parent = BoneStack[StackIndx--];
821 			else
822 				Parent = UNONE;
823 		}
824 		if (TEST_FLAG(Bone.Flags,Model3D_Bone::Push))
825 		{
826 			StackIndx = MAX(StackIndx,-1);
827 			BoneStack[++StackIndx] = Parent;
828 		}
829 
830 		// Do the transform!
831 		if (Parent != UNONE)
832 		{
833 			Model3D_Transform Res;
834 			TMatMultiply(Res,BoneMatrices[Parent],BoneMatrices[ib]);
835 			obj_copy(BoneMatrices[ib],Res);
836 		}
837 
838 		// Default: parent of next bone is current bone
839 		Parent = ib;
840 	}
841 
842 	bool NormalsPresent = !NormSources.empty();
843 	if (NormalsPresent) Normals.resize(NormSources.size());
844 
845 	for (unsigned ivs=0; ivs<VtxSources.size(); ivs++)
846 	{
847 		Model3D_VertexSource& VS = VtxSources[ivs];
848 		GLfloat Position[3];
849 
850 		if (VS.Bone0 >= 0)
851 		{
852 			Model3D_Transform& T0 = BoneMatrices[VS.Bone0];
853 			TransformPoint(Position,VS.Position,T0);
854 
855 			if (NormalsPresent)
856 			{
857 				for (int iv=InvVSIPointers[ivs]; iv<InvVSIPointers[ivs+1]; iv++)
858 				{
859 					int Indx = 3*InverseVSIndices[iv];
860 					TransformVector(NormBase() + Indx, NormSrcBase() + Indx, T0);
861 				}
862 			}
863 
864 			GLfloat Blend = VS.Blend;
865 			if (VS.Bone1 >= 0 && Blend != 0)
866 			{
867 				Model3D_Transform& T1 = BoneMatrices[VS.Bone1];
868 				GLfloat PosExtra[3];
869 				GLfloat PosDiff[3];
870 				TransformPoint(PosExtra,VS.Position,T1);
871 				VecSub(PosExtra,Position,PosDiff);
872 				VecScalarMultTo(PosDiff,Blend);
873 				VecAddTo(Position,PosDiff);
874 
875 				if (NormalsPresent)
876 				{
877 					for (int iv=InvVSIPointers[ivs]; iv<InvVSIPointers[ivs+1]; iv++)
878 					{
879 						int Indx = 3*InverseVSIndices[iv];
880 						GLfloat NormExtra[3];
881 						GLfloat NormDiff[3];
882 						GLfloat *OrigNorm = NormSrcBase() + Indx;
883 						GLfloat *Norm = NormBase() + Indx;
884 						TransformVector(NormExtra,OrigNorm,T1);
885 						VecSub(NormExtra,Norm,NormDiff);
886 						VecScalarMultTo(NormDiff,Blend);
887 						VecAddTo(Norm,NormDiff);
888 					}
889 				}
890 			}
891 		}
892 		else	// The assumed root bone (identity transformation)
893 		{
894 			VecCopy(VS.Position,Position);
895 			if (NormalsPresent)
896 			{
897 				for (int iv=InvVSIPointers[ivs]; iv<InvVSIPointers[ivs+1]; iv++)
898 				{
899 					int Indx = 3*InverseVSIndices[iv];
900 					VecCopy(NormSrcBase() + Indx, NormBase() + Indx);
901 				}
902 			}
903 		}
904 
905 		// Copy found position into vertex array!
906 		for (int iv=InvVSIPointers[ivs]; iv<InvVSIPointers[ivs+1]; iv++)
907 			VecCopy(Position,PosBase() + 3*InverseVSIndices[iv]);
908 	}
909 
910 	if (UseModelTransform)
911 	{
912 		GLfloat *PP = PosBase();
913 		for (size_t k=0; k<Positions.size()/3; k++, PP+=3)
914 		{
915 			GLfloat Position[3];
916 			TransformPoint(Position,PP,TransformPos);
917 			VecCopy(Position,PP);
918 		}
919 		GLfloat *NP = NormBase();
920 		for (size_t k=0; k<Normals.size()/3; k++, NP+=3)
921 		{
922 			GLfloat Normal[3];
923 			TransformVector(Normal,NP,TransformNorm);
924 			VecCopy(Normal,NP);
925 		}
926 	}
927 
928 	return true;
929 }
930 
931 // Returns 0 for out-of-range sequence
NumSeqFrames(GLshort SeqIndex)932 GLshort Model3D::NumSeqFrames(GLshort SeqIndex)
933 {
934 	if (SeqFrmPointers.empty()) return 0;
935 	if ((SeqIndex < 0) || (SeqIndex >= GLshort(SeqFrmPointers.size()))) return 0;
936 
937 	return (SeqFrmPointers[SeqIndex+1] - SeqFrmPointers[SeqIndex]);
938 }
939 
FindPositions_Sequence(bool UseModelTransform,GLshort SeqIndex,GLshort FrameIndex,GLfloat MixFrac,GLshort AddlFrameIndex)940 bool Model3D::FindPositions_Sequence(bool UseModelTransform, GLshort SeqIndex,
941 	GLshort FrameIndex, GLfloat MixFrac, GLshort AddlFrameIndex)
942 {
943 	// Bad inputs: do nothing and return false
944 
945 	GLshort NumSF = NumSeqFrames(SeqIndex);
946 	if (NumSF <= 0) return false;
947 
948 	if (FrameIndex < 0 || FrameIndex >= NumSF) return false;
949 
950 	Model3D_Transform TSF;
951 
952 	Model3D_SeqFrame& SF = SeqFrames[SeqFrmPointers[SeqIndex] + FrameIndex];
953 
954 	if (MixFrac != 0 && AddlFrameIndex != FrameIndex)
955 	{
956 		if (AddlFrameIndex < 0 || AddlFrameIndex >= NumSF) return false;
957 
958 		Model3D_SeqFrame& ASF = SeqFrames[SeqFrmPointers[SeqIndex] + AddlFrameIndex];
959 		FindFrameTransform(TSF,SF,MixFrac,ASF);
960 
961 		if (!FindPositions_Frame(false,SF.Frame,MixFrac,ASF.Frame)) return false;
962 	}
963 	else
964 	{
965 		if (!FindPositions_Frame(false,SF.Frame)) return false;
966 		FindFrameTransform(TSF,SF,0,SF);
967 	}
968 
969 	Model3D_Transform TTot;
970 	if (UseModelTransform)
971 		TMatMultiply(TTot,TransformPos,TSF);
972 	else
973 		obj_copy(TTot,TSF);
974 
975 	size_t NumVerts = Positions.size()/3;
976 	GLfloat *Pos = PosBase();
977 	for (size_t iv=0; iv<NumVerts; iv++)
978 	{
979 		GLfloat NewPos[3];
980 		TransformPoint(NewPos,Pos,TTot);
981 		VecCopy(NewPos,Pos);
982 		Pos += 3;
983 	}
984 
985 	bool NormalsPresent = !NormSources.empty();
986 	if (NormalsPresent)
987 	{
988 		// OK, since the bones don't change bulk
989 		if (UseModelTransform)
990 			TMatMultiply(TTot,TransformNorm,TSF);
991 		else
992 			obj_copy(TTot,TSF);
993 
994 		GLfloat *Norm = NormBase();
995 		for (size_t iv=0; iv<NumVerts; iv++)
996 		{
997 			GLfloat NewNorm[3];
998 			TransformVector(NewNorm,Norm,TTot);
999 			VecCopy(NewNorm,Norm);
1000 			Norm += 3;
1001 		}
1002 	}
1003 
1004 	return true;
1005 }
1006 
1007 
Identity()1008 void Model3D_Transform::Identity()
1009 {
1010 	obj_clear(*this);
1011 	M[0][0] = M[1][1] = M[2][2] = 1;
1012 }
1013 
1014 
InterpolateAngle(int16 Angle,GLfloat MixFrac,int16 AddlAngle)1015 static int16 InterpolateAngle(int16 Angle, GLfloat MixFrac, int16 AddlAngle)
1016 {
1017 	if (MixFrac != 0 && AddlAngle != Angle)
1018 	{
1019 		int16 AngleDiff = NORMALIZE_ANGLE(AddlAngle - Angle);
1020 		if (AngleDiff >= HALF_CIRCLE) AngleDiff -= FULL_CIRCLE;
1021 		Angle += int16(MixFrac*AngleDiff);
1022 	}
1023 	return NORMALIZE_ANGLE(Angle);
1024 }
1025 
1026 
1027 // Bone and Frame (positions, angles) -> Transform Matrix
FindFrameTransform(Model3D_Transform & T,Model3D_Frame & Frame,GLfloat MixFrac,Model3D_Frame & AddlFrame)1028 static void FindFrameTransform(Model3D_Transform& T,
1029 	Model3D_Frame& Frame, GLfloat MixFrac, Model3D_Frame& AddlFrame)
1030 {
1031 	T.Identity();
1032 
1033 	// First, do rotations:
1034 	short Angle;
1035 
1036 	// Right-to-left; in the right order for Dim3 (and Tomb Raider)
1037 
1038 	// Z:
1039 	Angle = InterpolateAngle(Frame.Angles[2],MixFrac,AddlFrame.Angles[2]);
1040 
1041 	if (Angle != 0)
1042 	{
1043 		GLfloat C = TrigNorm*cosine_table[Angle];
1044 		GLfloat S = TrigNorm*sine_table[Angle];
1045 
1046 		for (int ic=0; ic<3; ic++)
1047 		{
1048 			GLfloat X = T.M[0][ic];
1049 			GLfloat Y = T.M[1][ic];
1050 			GLfloat XR = X*C - Y*S;
1051 			GLfloat YR = X*S + Y*C;
1052 			T.M[0][ic] = XR;
1053 			T.M[1][ic] = YR;
1054 		}
1055 	}
1056 
1057 	// X:
1058 	Angle = InterpolateAngle(Frame.Angles[0],MixFrac,AddlFrame.Angles[0]);
1059 
1060 	if (Angle != 0)
1061 	{
1062 		GLfloat C = TrigNorm*cosine_table[Angle];
1063 		GLfloat S = TrigNorm*sine_table[Angle];
1064 
1065 		for (int ic=0; ic<3; ic++)
1066 		{
1067 			GLfloat X = T.M[1][ic];
1068 			GLfloat Y = T.M[2][ic];
1069 			GLfloat XR = X*C - Y*S;
1070 			GLfloat YR = X*S + Y*C;
1071 			T.M[1][ic] = XR;
1072 			T.M[2][ic] = YR;
1073 		}
1074 	}
1075 
1076 	// Y:
1077 	Angle = InterpolateAngle(Frame.Angles[1],MixFrac,AddlFrame.Angles[1]);
1078 
1079 	if (Angle != 0)
1080 	{
1081 		GLfloat C = TrigNorm*cosine_table[Angle];
1082 		GLfloat S = TrigNorm*sine_table[Angle];
1083 
1084 		for (int ic=0; ic<3; ic++)
1085 		{
1086 			GLfloat X = T.M[2][ic];
1087 			GLfloat Y = T.M[0][ic];
1088 			GLfloat XR = X*C - Y*S;
1089 			GLfloat YR = X*S + Y*C;
1090 			T.M[2][ic] = XR;
1091 			T.M[0][ic] = YR;
1092 		}
1093 	}
1094 
1095 	// Set up overall translate:
1096 	GLfloat *FrameOfst = Frame.Offset;
1097 	if (MixFrac != 0)
1098 	{
1099 		GLfloat *AddlFrameOfst = AddlFrame.Offset;
1100 		for (int ic=0; ic<3; ic++)
1101 			T.M[ic][3] = FrameOfst[ic] + MixFrac*(AddlFrameOfst[ic]-FrameOfst[ic]);
1102 	}
1103 	else
1104 	{
1105 	for (int ic=0; ic<3; ic++)
1106 		T.M[ic][3] = FrameOfst[ic];
1107 	}
1108 }
1109 
FindBoneTransform(Model3D_Transform & T,Model3D_Bone & Bone,Model3D_Frame & Frame,GLfloat MixFrac,Model3D_Frame & AddlFrame)1110 static void FindBoneTransform(Model3D_Transform& T, Model3D_Bone& Bone,
1111 	Model3D_Frame& Frame, GLfloat MixFrac, Model3D_Frame& AddlFrame)
1112 {
1113 	FindFrameTransform(T,Frame,MixFrac,AddlFrame);
1114 
1115 	// Set up overall translate:
1116 	GLfloat *BonePos = Bone.Position;
1117 	for (int ic=0; ic<3; ic++)
1118 		T.M[ic][3] += BonePos[ic] - ScalarProd(T.M[ic],BonePos);
1119 }
1120 
1121 
1122 // Res = A * B, in that order
TMatMultiply(Model3D_Transform & Res,Model3D_Transform & A,Model3D_Transform & B)1123 static void TMatMultiply(Model3D_Transform& Res, Model3D_Transform& A, Model3D_Transform& B)
1124 {
1125 	// Multiply the rotation parts
1126 	for (int i=0; i<3; i++)
1127 		for (int j=0; j<3; j++)
1128 		{
1129 			GLfloat Sum = 0;
1130 			for (int k=0; k<3; k++)
1131 				Sum += A.M[i][k]*B.M[k][j];
1132 
1133 			Res.M[i][j] = Sum;
1134 		}
1135 
1136 	// Now the translation part
1137 	for (int i=0; i<3; i++)
1138 	{
1139 		GLfloat Sum = 0;
1140 		for (int k=0; k<3; k++)
1141 			Sum += A.M[i][k]*B.M[k][3];
1142 
1143 		Res.M[i][3] = A.M[i][3] + Sum;
1144 	}
1145 }
1146 
1147 
1148 #endif // def HAVE_OPENGL
1149