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