openal and fontft memleak fixes from keltar
[fegdk.git] / tools / fgp / NmFileIO.cpp
blob91f4deb4caa38df147ecfdacdb635f4a05dccde1
1 /******************************************************************************
2 * NmFileIO.cpp -- File IO routines for normal mapper.
3 ******************************************************************************
4 $Header$
5 ******************************************************************************
6 * (C) 2000 ATI Research, Inc. All rights reserved.
7 ******************************************************************************/
8 #include <fegdk/pch.h>
9 #include <stdarg.h>
10 #include <stdlib.h>
11 #include <iostream>
12 #include <fstream>
13 #include <string.h>
14 #include <math.h>
16 #include "NmFileIO.h"
18 using namespace std;
20 //#define NEW_WAY
22 #define EPSILON 1.0e-7
23 static const double ATI_VERT_TINY = EPSILON;
24 static const double ATI_NORM_TINY = EPSILON;
25 static const double ATI_TEX_TINY = EPSILON;
26 static const double ATI_TAN_ANGLE = 0.3;
28 // Compare function definition
29 typedef int (* PFNNMCOMPARED)(NmTangentPointD* v0, NmTangentPointD* v1);
31 ////////////////////////////////////////////////////////////////////
32 // Write a block of triangles to the file
33 ////////////////////////////////////////////////////////////////////
34 bool
35 NmWriteTriangles (FILE* fp, int numTris, NmRawTriangle* tris)
37 // Write out header information
38 NmHeader header;
39 strncpy (header.hdr, NMF_HEADER_TAG, 4);
40 header.size = sizeof (NmHeader) + sizeof (int) +
41 (sizeof(NmRawTriangle) * numTris);
42 if (fwrite (&header, sizeof (NmHeader), 1, fp) != 1)
44 cerr << "Unable to write NMF header\n";
45 return false;
48 // Write out out triangle chunk header
49 strncpy (header.hdr, NMF_TRIANGLE_TAG, 4);
50 header.size = sizeof (int) + sizeof(NmRawTriangle) * numTris;
51 if (fwrite (&header, sizeof (NmHeader), 1, fp) != 1)
53 cerr << "Unable to write triangle header\n";
54 return false;
57 // Write the number of triangles.
58 if (fwrite (&numTris, sizeof (int), 1, fp) != 1)
60 cerr << "Unable to write number of triangles\n";
61 return false;
64 // Write the triangles.
65 if (fwrite (tris, sizeof(NmRawTriangle), numTris, fp) != (unsigned)numTris)
67 cerr << "Unable to write triangles\n";
68 return false;
70 return true;
71 } // end NmWriteTriangles
73 ////////////////////////////////////////////////////////////////////
74 // Read a block of triangles from the file
75 ////////////////////////////////////////////////////////////////////
76 bool
77 NmReadTriangleChunk (FILE* fp, int* numTris, NmRawTriangle** tris)
79 // Read the number of triangles.
80 if (fread (numTris, sizeof (int), 1, fp) != 1)
82 cerr << "Unable to read number of triangles\n";
83 return false;
85 if ((*numTris) < 1)
87 cerr << "No triangles found in file\n";
88 return false;
91 // Allocate space for triangles
92 (*tris) = new NmRawTriangle [(*numTris)];
93 if ((*tris) == NULL)
95 cerr << "Unable to allocate space for " << (*tris) << " triangles\n";
96 return false;
99 // Now read the triangles into the allocated space.
100 if (fread ((*tris), sizeof (NmRawTriangle), (*numTris), fp) !=
101 (unsigned)(*numTris))
103 cerr << "Unable to read triangles\n";
104 #ifdef _DEBUG
105 if (ferror (fp))
107 perror ("Read Triangles");
109 else if (feof (fp))
111 cerr << "End of file!\n";
113 #endif
114 return false;
117 // success
118 return true;
121 ////////////////////////////////////////////////////////////////////
122 // Read a block of triangles from the file
123 ////////////////////////////////////////////////////////////////////
124 bool
125 NmReadTriangles (FILE* fp, int* numTris, NmRawTriangle** tris)
127 NmHeader header;
128 while (!feof (fp))
130 // Read chunk header.
131 if (fread (&header, sizeof (NmHeader), 1, fp) != 1)
133 cerr << "Unable to read header\n";
134 return false;
137 // Check if it's the NMF chunk
138 if (strncmp (header.hdr, NMF_HEADER_TAG, 4) == 0)
140 while (!feof (fp))
142 // Read chunk header.
143 if (fread (&header, sizeof (NmHeader), 1, fp) != 1)
145 cerr << "Unable to read header\n";
146 return false;
149 // Check if it's the trianlge chunk we are looking for.
150 if (strncmp (header.hdr, NMF_TRIANGLE_TAG, 4) == 0)
152 // We can currently on handle one triangle chunk.
153 return NmReadTriangleChunk (fp, numTris, tris);
155 else
157 // Skip over chunk since it's not what we want.
158 if (fseek (fp, header.size, SEEK_CUR) != 0)
160 cerr << "Chunk size doesn't match file size\n";
161 return false;
166 else
168 // Skip over chunk since it's not what we want.
169 if (fseek (fp, header.size, SEEK_CUR) != 0)
171 cerr << "Chunk size doesn't match file size\n";
172 return false;
176 cerr << "No NMF data found in file\n";
177 return false;
178 } // end NmReadTriangles
180 ////////////////////////////////////////////////////////////////////
181 // Converts an older (pre chunk) NMF file into the current format
182 ////////////////////////////////////////////////////////////////////
183 bool
184 NmConvertFile (FILE* fpIn, FILE* fpOut)
186 int numTris;
187 NmRawTriangle* tris;
188 if (!NmReadTriangleChunk (fpIn, &numTris, &tris))
190 cerr << "Unable to read input file\n";
191 return false;
193 if (!NmWriteTriangles (fpOut, numTris, tris))
195 cerr << "Unable to write output file\n";
196 return false;
198 return true;
201 ////////////////////////////////////////////////////////////////////
202 // Compute tangent space for the given triangle list
203 ////////////////////////////////////////////////////////////////////
204 bool
205 NmComputeTangents (int numTris, NmRawTriangle* tris, NmRawTangentSpace** tan)
207 // Check inputs
208 if ((numTris == 0) || (tris == NULL) || (tan == NULL))
210 return false;
213 // First we need to allocate up the tangent space storage
214 (*tan) = new NmRawTangentSpace [numTris];
215 if ((*tan) == NULL)
217 return false;
220 // Cheat and use the double version to compute then convert into floats
221 NmRawTangentSpaceD* tanD;
222 if (!NmComputeTangentsD(numTris, tris, &tanD))
224 return false;
227 // Now find tangent space
229 for (int i = 0; i < numTris; i++)
231 for (int j = 0; j < 3; j++)
233 (*tan)[i].tangent[j].x = (float)(tanD[i].tangent[j].x);
234 (*tan)[i].tangent[j].y = (float)(tanD[i].tangent[j].y);
235 (*tan)[i].tangent[j].z = (float)(tanD[i].tangent[j].z);
236 (*tan)[i].binormal[j].x = (float)(tanD[i].binormal[j].x);
237 (*tan)[i].binormal[j].y = (float)(tanD[i].binormal[j].y);
238 (*tan)[i].binormal[j].z = (float)(tanD[i].binormal[j].z);
241 delete [] tanD;
242 return true;
243 } // end NmComputeTangents
245 //==========================================================================
246 // Normalize a vector
247 //==========================================================================
248 static inline void
249 NormalizeD (double v[3])
251 double len = sqrt((v[0]*v[0])+(v[1]*v[1])+(v[2]*v[2]));
252 if (len < EPSILON)
254 v[0] = 1.0;
255 v[1] = 0.0;
256 v[2] = 0.0;
258 else
260 v[0] = v[0]/len;
261 v[1] = v[1]/len;
262 v[2] = v[2]/len;
266 //==========================================================================
267 // Calculates the dot product of two vectors.
268 //==========================================================================
269 static inline double
270 DotProduct3D (double vectorA[3], double vectorB[3])
272 return( (vectorA[0] * vectorB[0]) + (vectorA[1] * vectorB[1]) +
273 (vectorA[2] * vectorB[2]) );
274 } // end of DotProduct
277 //=============================================================================
278 // Compare the values
279 //=============================================================================
280 static int
281 NmCompareD (NmTangentPointD* v0, NmTangentPointD* v1)
283 int i;
284 // Positions.
285 for (i = 0; i < 3; i++)
287 if (fabs(v0->vertex[i] - v1->vertex[i]) > ATI_VERT_TINY)
289 if (v0->vertex[i] > v1->vertex[i])
291 return -1;
293 else
295 return 1;
300 // Normal
301 for (i = 0; i < 3; i++)
303 if (fabs(v0->normal[i] - v1->normal[i]) > ATI_NORM_TINY)
305 if (v0->normal[i] > v1->normal[i])
307 return -1;
309 else
311 return 1;
316 // Texture Coordinates.
317 for (i = 0; i < 2; i++)
319 if (fabs(v0->uv[i] - v1->uv[i]) > ATI_TEX_TINY)
321 if (v0->uv[i] > v1->uv[i])
323 return -1;
325 else
327 return 1;
333 // Tangent
334 double t0[3] = {v0->tangent[0], v0->tangent[1], v0->tangent[2]};
335 NormalizeD (t0);
336 double t1[3] = {v1->tangent[0], v1->tangent[1], v1->tangent[2]};
337 NormalizeD (t1);
338 double dp3 = DotProduct3D (t0, t1);
339 if (dp3 < ATI_TAN_ANGLE)
341 for (int i = 0; i < 3; i++)
343 if (v0->tangent[i] > v1->tangent[i])
345 return -1;
347 else
349 return 1;
354 // Binormal
355 double b0[3] = {v0->binormal[0], v0->binormal[1], v0->binormal[2]};
356 NormalizeD (b0);
357 double b1[3] = {v1->binormal[0], v1->binormal[1], v1->binormal[2]};
358 NormalizeD (b1);
359 dp3 = DotProduct3D (b0, b1);
360 if (dp3 < ATI_TAN_ANGLE)
362 for (int i = 0; i < 3; i++)
364 if (v0->binormal[i] > v1->binormal[i])
366 return -1;
368 else
370 return 1;
374 return 0;
377 //=============================================================================
378 // Compare the values
379 //=============================================================================
380 static int
381 NmCompareWithTexD (NmTangentPointD* v0, NmTangentPointD* v1)
383 int i;
384 // Positions.
385 for (i = 0; i < 3; i++)
387 if (fabs(v0->vertex[i] - v1->vertex[i]) > ATI_VERT_TINY)
389 if (v0->vertex[i] > v1->vertex[i])
391 return -1;
393 else
395 return 1;
400 // Normal
401 for (i = 0; i < 3; i++)
403 if (fabs(v0->normal[i] - v1->normal[i]) > ATI_NORM_TINY)
405 if (v0->normal[i] > v1->normal[i])
407 return -1;
409 else
411 return 1;
416 // Texture Coordinates.
417 for (i = 0; i < 2; i++)
419 if (fabs(v0->uv[i] - v1->uv[i]) > ATI_TEX_TINY)
421 if (v0->uv[i] > v1->uv[i])
423 return -1;
425 else
427 return 1;
433 // Tangent
434 for (i = 0; i < 3; i++)
436 if (fabs(v0->tangent[i] - v1->tangent[i]) > ATI_NORM_TINY)
438 if (v0->tangent[i] > v1->tangent[i])
440 return -1;
442 else
444 return 1;
449 // Binormal
450 for (i = 0; i < 3; i++)
452 if (fabs(v0->binormal[i] - v1->binormal[i]) > ATI_NORM_TINY)
454 if (v0->binormal[i] > v1->binormal[i])
456 return -1;
458 else
460 return 1;
465 // Matches
466 return 0;
469 //=============================================================================
470 // Compare the values
471 //=============================================================================
472 static int
473 NmCompareNoTexD (NmTangentPointD* v0, NmTangentPointD* v1)
475 int i;
476 // Positions.
477 for (i = 0; i < 3; i++)
479 if (fabs(v0->vertex[i] - v1->vertex[i]) > ATI_VERT_TINY)
481 if (v0->vertex[i] > v1->vertex[i])
483 return -1;
485 else
487 return 1;
492 // Normal
493 for (i = 0; i < 3; i++)
495 if (fabs(v0->normal[i] - v1->normal[i]) > ATI_NORM_TINY)
497 if (v0->normal[i] > v1->normal[i])
499 return -1;
501 else
503 return 1;
508 // Tangent
509 double t0[3] = {v0->tangent[0], v0->tangent[1], v0->tangent[2]};
510 NormalizeD (t0);
511 double t1[3] = {v1->tangent[0], v1->tangent[1], v1->tangent[2]};
512 NormalizeD (t1);
513 double dp3 = DotProduct3D (t0, t1);
514 if (dp3 < ATI_TAN_ANGLE)
516 for (int i = 0; i < 3; i++)
518 if (v0->tangent[i] > v1->tangent[i])
520 return -1;
522 else
524 return 1;
529 // Binormal
530 double b0[3] = {v0->binormal[0], v0->binormal[1], v0->binormal[2]};
531 NormalizeD (b0);
532 double b1[3] = {v1->binormal[0], v1->binormal[1], v1->binormal[2]};
533 NormalizeD (b1);
534 dp3 = DotProduct3D (b0, b1);
535 if (dp3 < ATI_TAN_ANGLE)
537 for (int i = 0; i < 3; i++)
539 if (v0->binormal[i] > v1->binormal[i])
541 return -1;
543 else
545 return 1;
549 return 0;
552 //=============================================================================
553 // Binary traversal function
554 //=============================================================================
555 static int
556 NmIndexBinaryTraverseD (NmTangentPointD* value, // The reference element
557 NmTangentPointD* data,// pointer to the indexed data
558 int* indices, // pointer index
559 int count, // number of items in the array
560 int* result, // The result of the last compare
561 PFNNMCOMPARED compare) // Compare function.
563 int high;
564 int low;
565 int mid;
566 int nextMid;
568 high = count;
569 low = 0;
570 mid = low + ((high - low) >> 1);
571 *result = -1;
573 while (low != high)
575 *result = compare (value, &(data[indices[mid]]));
576 if (*result == 0)
578 break;
580 else if (*result < 0)
582 high = mid;
584 else
586 low = mid;
589 nextMid = low + ((high - low) >> 1);
590 if (mid == nextMid)
592 break;
595 mid = nextMid;
598 return mid;
601 #define DcVec2Add(r, a, b) ((r)[0] = (a)[0] + (b)[0], (r)[1] = (a)[1] + (b)[1])
602 #define DcVec2AddTo(a, b) ((a)[0] += (b)[0], (a)[1] += (b)[1])
603 #define DcVec2AddScalar(r, a, b) ((r)[0] = (a)[0] + (b), (r)[1] = (a)[1] + (b))
604 #define DcVec2AddScalarTo(a, b) ((a)[0] += (b), (a)[1] += (b))
605 #define DcVec2Copy(a, b) ((b)[0] = (a)[0], (b)[1] += (a)[1])
606 #define DcVec2Divide(r, a, b) ((r)[0] = (a)[0] / (b)[0], (r)[1] = (a)[1] / (b)[1])
607 #define DcVec2DivideBy(a, b) ((a)[0] /= (b)[0], (a)[1] /= (b)[1])
608 #define DcVec2DivideByScalar(v, s) ((v)[0] /= s, (v)[1] /= s)
609 #define DcVec2DivideScalar(r, v, s) ((r)[0] = (v)[0] / s, (r)[1] = (v)[1] / s)
610 #define DcVec2MidPoint(c, a, b) ((r)[0] = (b)[0] + ((a)[0] - (b)[0]) * 0.5f, (r)[1] = (b)[1] + ((a)[1] - (b)[1]) * 0.5f)
611 #define DcVec2Mult(a, b, c) ((c)[0] = (a)[0] * (b)[0], (c)[1] = (a)[1] * (b)[1])
612 #define DcVec2MultBy(a, b) ((a)[0] *= (b)[0], (a)[1] *= (b)[1])
613 #define DcVec2MultByScalar(v, s) ((v)[0] *= s, (v)[1] *= s)
614 #define DcVec2MultScalar(r, v, s) ((r)[0] = (v)[0] * s, (r)[1] = (v)[1] * s)
615 #define DcVec2Mad(r, a, b, c) ((r)[0] = (a)[0] * (b)[0] + (c)[0], (r)[1] = (a)[1] * (b)[1] + (c)[1])
616 #define DcVec2Negate(a, b) ((b)[0] = -(a)[0], (b)[1] = -(a)[1])
617 #define DcVec2Scale(r, v, s) ((r)[0] = (v)[0] * s, (r)[1] = (v)[1] * s)
618 #define DcVec2ScaleBy(v, s) ((v)[0] *= s, (v)[1] *= s)
619 #define DcVec2Set(v, x, y) ((v)[0] = x, (v)[1] = y)
620 #define DcVec2Subtract(r, a, b) ((r)[0] = (a)[0] - (b)[0], (r)[1] = (a)[1] - (b)[1])
621 #define DcVec2SubtractFrom(a, b) ((a)[0] -= (b)[0], (a)[1] -= (b)[1])
622 #define DcVec2Magnitude(v) ( sqrtf((v)[0] * (v)[0] + (v)[1] * (v)[1]))
623 #define DcVec2MagnitudeDouble(v) ( sqrt((v)[0] * (v)[0] + (v)[1] * (v)[1]))
624 #define DcVec2NormalizeDouble(v) { double __mag = 1.0 / DcVec2MagnitudeDouble(v); \
625 (v)[0] *= __mag; (v)[1] *= __mag; }
626 #define DcVec2Normalize(v) { float __mag = 1.0f / (float)DcVec2Magnitude(v); \
627 (v)[0] *= __mag; (v)[1] *= __mag; }
630 #define DcVecAdd(r, a, b) ((r)[0] = (a)[0] + (b)[0], (r)[1] = (a)[1] + (b)[1], (r)[2] = (a)[2] + (b)[2])
631 #define DcVecAddTo(a, b) ((a)[0] += (b)[0], (a)[1] += (b)[1], (a)[2] += (b)[2])
632 #define DcVecAddScalar(r, a, b) ((r)[0] = (a)[0] + (b), (r)[1] = (a)[1] + (b), (r)[2] = (a)[2] + (b))
633 #define DcVecAddScalarTo(a, b) ((a)[0] += (b), (a)[1] += (b), (a)[2] += (b))
634 #define DcVecCopy(a, b) ((b)[0] = (a)[0], (b)[1] += (a)[1], (b)[2] += (a)[2])
635 #define DcVecCross(r, a, b) ((r)[0] = (a)[1] * (b)[2] - (a)[2] * (b)[1], (r)[1] = (a)[2] * (b)[0] - (a)[0] * (b)[2], (r)[2] = (a)[0] * (b)[1] - (a)[1] * (b)[0])
636 #define DcVecDivide(r, a, b) ((r)[0] = (a)[0] / (b)[0], (r)[1] = (a)[1] / (b)[1], (r)[2] = (a)[2] / (b)[2])
637 #define DcVecDivideBy(a, b) ((a)[0] /= (b)[0], (a)[1] /= (b)[1], (a)[2] /= (b)[2])
638 #define DcVecDivideByScalar(v, s) ((v)[0] /= s, (v)[1] /= s, (v)[2] /= s)
639 #define DcVecDivideScalar(r, v, s) ((r)[0] = (v)[0] / s, (r)[1] = (v)[1] / s, (r)[2] = v[2] / s)
640 #define DcVecMidPoint(c, a, b) ((r)[0] = (b)[0] + ((a)[0] - (b)[0]) * 0.5f, (r)[1] = (b)[1] + ((a)[1] - (b)[1]) * 0.5f, (r)[2] = (b)[2] + ((a)[2] - (b)[2]) * 0.5f)
641 #define DcVecMult(a, b, c) ((c)[0] = (a)[0] * (b)[0], (c)[1] = (a)[1] * (b)[1], (c)[2] = (a)[2] * (b)[2])
642 #define DcVecMultBy(a, b) ((a)[0] *= (b)[0], (a)[1] *= (b)[1], (a)[2] *= (b)[2])
643 #define DcVecMultByScalar(v, s) ((v)[0] *= s, (v)[1] *= s, (v)[2] *= s)
644 #define DcVecMultScalar(r, v, s) ((r)[0] = (v)[0] * s, (r)[1] = (v)[1] * s, (r)[2] = v[2] * s)
645 #define DcVecMad(r, a, b, c) ((r)[0] = (a)[0] * (b)[0] + (c)[0], (r)[1] = (a)[1] * (b)[1] + (c)[1], (r)[2] = (a)[2] * (b)[2] + (c)[2])
646 #define DcVecNegate(a) ((a)[0] = -(a)[0], (a)[1] = -(a)[1], (a)[2] = -(a)[2])
647 #define DcVecScale(r, v, s) ((r)[0] = (v)[0] * s, (r)[1] = (v)[1] * s, (r)[2] = v[2] * s)
648 #define DcVecScaleBy(v, s) ((v)[0] *= s, (v)[1] *= s, (v)[2] *= s)
649 #define DcVecSet(v, x, y, z) ((v)[0] = x, (v)[1] = y, (v)[2] = z)
650 #define DcVecSubtract(r, a, b) ((r)[0] = (a)[0] - (b)[0], (r)[1] = (a)[1] - (b)[1], (r)[2] = (a)[2] - (b)[2])
651 #define DcVecSubtractFrom(a, b) ((a)[0] -= (b)[0], (a)[1] -= (b)[1], (a)[2] -= (b)[2])
652 #define DcVecMagnitude(v) ( sqrtf((v)[0] * (v)[0] + (v)[1] * (v)[1] + (v)[2] * (v)[2]))
653 #define DcVecMagnitudeDouble(v) ( sqrt((v)[0] * (v)[0] + (v)[1] * (v)[1] + (v)[2] * (v)[2]))
654 #define DcVecNormalizeDouble(v,def) { double __mag = DcVecMagnitudeDouble(v); \
655 if (__mag < EPSILON) {(v)[0] = (def)[0]; (v)[1] = (def)[1]; (v)[2] = (def)[2];} else \
656 {__mag = 1.0/__mag;(v)[0] *= __mag; (v)[1] *= __mag; (v)[2] *= __mag;} }
657 #define DcVecNormalize(v) { float __mag = 1.0f / (float)DcVecMagnitude(v); \
658 (v)[0] *= __mag; (v)[1] *= __mag; (v)[2] *= __mag; }
659 #define DcVecLineLength(a, b) ( sqrtf(((a)[0] - (b)[0]) * ((a)[0] - (b)[0]) + \
660 ((a)[1] - (b)[1]) * ((a)[1] - (b)[1]) + \
661 ((a)[2] - (b)[2]) * ((a)[2] - (b)[2])))
662 #define DcVecLerp(r, a, b, c) { DcVecSubtract(r, b, a); \
663 DcVecMultByScalar(r, c); \
664 DcVecAddTo(r, a); }
666 #define DcVecDotProduct(a, b) ((a)[0] * (b)[0] + (a)[1] * (b)[1] + (a)[2] * (b)[2])
667 #define DcVecDot4(a, b) ((a)[0] * (b)[0] + (a)[1] * (b)[1] + (a)[2] * (b)[2] + (a)[3] * (b)[3])
668 #define DcVecDot3(a, b) ((a)[0] * (b)[0] + (a)[1] * (b)[1] + (a)[2] * (b)[2])
670 #define DC_INVALID_ARG false
671 #define DC_OK true
673 bool DcTangentSpace(float* v1, float* v2, float* v3,
674 float* t1, float* t2, float* t3,
675 double* normal, double *tangent, double *binormal)
677 typedef struct
679 double v[3];
680 double t[2];
681 } tanSpaceVert;
683 tanSpaceVert verts[3];
684 tanSpaceVert tempVert;
685 double dot;
686 double interp;
687 double tempVector[3];
689 //===================================//
690 // make sure the arguments are valid //
691 //===================================//
692 if ((v1 != NULL) &&
693 (v2 != NULL) &&
694 (v3 != NULL) &&
695 (t1 != NULL) &&
696 (t2 != NULL) &&
697 (t3 != NULL) &&
698 (normal != NULL) &&
699 (tangent != NULL) &&
700 (binormal != NULL))
702 //========================================//
703 // fill in the tangent space vertex array //
704 //========================================//
705 verts[0].v[0] = v1[0];
706 verts[0].v[1] = v1[1];
707 verts[0].v[2] = v1[2];
708 verts[0].t[0] = t1[0];
709 verts[0].t[1] = t1[1];
711 verts[1].v[0] = v2[0];
712 verts[1].v[1] = v2[1];
713 verts[1].v[2] = v2[2];
714 verts[1].t[0] = t2[0];
715 verts[1].t[1] = t2[1];
717 verts[2].v[0] = v3[0];
718 verts[2].v[1] = v3[1];
719 verts[2].v[2] = v3[2];
720 verts[2].t[0] = t3[0];
721 verts[2].t[1] = t3[1];
723 //============================//
724 // compute the tangent vector //
725 //============================//
727 //=======================================================//
728 // sort the vertices based on their t texture coordinate //
729 //=======================================================//
730 if (verts[0].t[1] < verts[1].t[1])
732 tempVert = verts[0];
733 verts[0] = verts[1];
734 verts[1] = tempVert;
736 if (verts[0].t[1] < verts[2].t[1])
738 tempVert = verts[0];
739 verts[0] = verts[2];
740 verts[2] = tempVert;
742 if (verts[1].t[1] < verts[2].t[1])
744 tempVert = verts[1];
745 verts[1] = verts[2];
746 verts[2] = tempVert;
749 //=======================================================================//
750 // compute the parametric offset along edge02 to the middle t coordinate //
751 //=======================================================================//
752 if (fabs((verts[2].t[1] - verts[0].t[1])) < EPSILON)
754 interp = 1.0;
756 else
758 interp = (verts[1].t[1] - verts[0].t[1]) / (verts[2].t[1] - verts[0].t[1]);
761 //============================================================================//
762 // use the interpolation paramter to compute the vertex position along edge02 //
763 // that coresponds to the same t coordinate as v[1] //
764 //============================================================================//
765 DcVecLerp(tempVector, verts[0].v, verts[2].v, interp);
767 //========================================//
768 // compute the interpolated s coord value //
769 //========================================//
770 interp = verts[0].t[0] + (verts[2].t[0] - verts[0].t[0]) * interp;
772 //===========================================================================//
773 // the tangent vector is the ray from the middle vertex to the lerped vertex //
774 //===========================================================================//
775 DcVecSubtract(tangent, tempVector, verts[1].v);
777 //=====================================================//
778 // make sure the tangent points in the right direction //
779 //=====================================================//
780 if (interp < verts[1].t[0])
782 DcVecNegate(tangent);
785 //=============================================================//
786 // make sure the tangent vector is perpendicular to the normal //
787 //=============================================================//
788 dot = DcVecDot3(normal, tangent);
789 tangent[0] = tangent[0] - normal[0] * dot;
790 tangent[1] = tangent[1] - normal[1] * dot;
791 tangent[2] = tangent[2] - normal[2] * dot;
793 //==============================//
794 // normalize the tangent vector //
795 //==============================//
796 static double defTan[3] = {1.0, 0.0, 0.0};
797 DcVecNormalizeDouble(tangent, defTan);
800 //=============================//
801 // compute the binormal vector //
802 //=============================//
804 //=======================================================//
805 // sort the vertices based on their s texture coordinate //
806 //=======================================================//
807 if (verts[0].t[0] < verts[1].t[0])
809 tempVert = verts[0];
810 verts[0] = verts[1];
811 verts[1] = tempVert;
813 if (verts[0].t[0] < verts[2].t[0])
815 tempVert = verts[0];
816 verts[0] = verts[2];
817 verts[2] = tempVert;
819 if (verts[1].t[0] < verts[2].t[0])
821 tempVert = verts[1];
822 verts[1] = verts[2];
823 verts[2] = tempVert;
826 //=======================================================================//
827 // compute the parametric offset along edge02 to the middle s coordinate //
828 //=======================================================================//
829 if (fabs((verts[2].t[0] - verts[0].t[0])) < EPSILON)
831 interp = 1.0;
833 else
835 interp = (verts[1].t[0] - verts[0].t[0]) / (verts[2].t[0] - verts[0].t[0]);
838 //============================================================================//
839 // use the interpolation paramter to compute the vertex position along edge02 //
840 // that coresponds to the same t coordinate as v[1] //
841 //============================================================================//
842 DcVecLerp(tempVector, verts[0].v, verts[2].v, interp);
844 //========================================//
845 // compute the interpolated t coord value //
846 //========================================//
847 interp = verts[0].t[1] + (verts[2].t[1] - verts[0].t[1]) * interp;
849 //============================================================================//
850 // the binormal vector is the ray from the middle vertex to the lerped vertex //
851 //============================================================================//
852 DcVecSubtract(binormal, tempVector, verts[1].v);
854 //======================================================//
855 // make sure the binormal points in the right direction //
856 //======================================================//
857 if (interp < verts[1].t[1])
859 DcVecNegate(binormal);
862 //==============================================================//
863 // make sure the binormal vector is perpendicular to the normal //
864 //==============================================================//
865 dot = DcVecDot3(normal, binormal);
866 binormal[0] = binormal[0] - normal[0] * dot;
867 binormal[1] = binormal[1] - normal[1] * dot;
868 binormal[2] = binormal[2] - normal[2] * dot;
870 //===============================//
871 // normalize the binormal vector //
872 //===============================//
873 static double defBi[3] = {0.0, 0.0, 1.0};
874 DcVecNormalizeDouble(binormal, defBi);
877 else
879 return DC_INVALID_ARG;
882 return DC_OK;
885 ////////////////////////////////////////////////////////////////////
886 // Compute tangent space for the given triangle
887 ////////////////////////////////////////////////////////////////////
888 static void
889 ComputeTangentVectorsD (NmRawTriangle* pgon, int idx,
890 double tan[3], double norm[3], double binorm[3])
892 // Clear outputs.
893 tan[0] = 1.0; tan[1] = 0.0; tan[2] = 0.0;
894 binorm[0] = 0.0; binorm[1] = 0.0; binorm[2] = 1.0;
895 norm[0] = pgon->norm[idx].x;
896 norm[1] = pgon->norm[idx].y;
897 norm[2] = pgon->norm[idx].z;
899 // Make sure we have valid data.
900 if (pgon->texCoord[0].u == 0.0 &&
901 pgon->texCoord[1].u == 0.0 &&
902 pgon->texCoord[2].u == 0.0)
904 return;
907 DcTangentSpace(pgon->vert[0].v, pgon->vert[1].v, pgon->vert[2].v,
908 pgon->texCoord[0].uv, pgon->texCoord[1].uv,
909 pgon->texCoord[2].uv, norm, tan, binorm);
910 } // end ComputeTangentVectors
912 ////////////////////////////////////////////////////////////////////
913 // Copy data into a point structure
914 ////////////////////////////////////////////////////////////////////
915 static void
916 NmCopyPointD (NmRawTriangle* tri, int v, NmTangentPointD* point)
918 point->vertex[0] = tri->vert[v].x;
919 point->vertex[1] = tri->vert[v].y;
920 point->vertex[2] = tri->vert[v].z;
921 point->normal[0] = tri->norm[v].x;
922 point->normal[1] = tri->norm[v].y;
923 point->normal[2] = tri->norm[v].z;
924 point->uv[0] = tri->texCoord[v].u;
925 point->uv[1] = tri->texCoord[v].v;
926 double norm[3];
927 ComputeTangentVectorsD (tri, v, point->tangent, norm, point->binormal);
928 point->count = 1;
931 ////////////////////////////////////////////////////////////////////
932 // Copy data into a point structure
933 ////////////////////////////////////////////////////////////////////
934 static void
935 NmCopyPointTangentD (NmRawTriangle* tri, NmRawTangentSpaceD* tan,
936 int v, NmTangentPointD* point)
938 point->vertex[0] = tri->vert[v].x;
939 point->vertex[1] = tri->vert[v].y;
940 point->vertex[2] = tri->vert[v].z;
941 point->normal[0] = tri->norm[v].x;
942 point->normal[1] = tri->norm[v].y;
943 point->normal[2] = tri->norm[v].z;
944 point->uv[0] = tri->texCoord[v].u;
945 point->uv[1] = tri->texCoord[v].v;
946 point->tangent[0] = tan->tangent[v].x;
947 point->tangent[1] = tan->tangent[v].y;
948 point->tangent[2] = tan->tangent[v].z;
949 point->binormal[0] = tan->binormal[v].x;
950 point->binormal[1] = tan->binormal[v].y;
951 point->binormal[2] = tan->binormal[v].z;
952 point->count = 1;
955 ////////////////////////////////////////////////////////////////////
956 // Insert a point and get it's index.
957 ////////////////////////////////////////////////////////////////////
958 static int
959 NmInsertD (NmRawTriangle* tri, int v, int* num, int* sortIndex,
960 NmTangentPointD* point)
962 // Make sure we have some stuff to check.
963 int ret = 0;
964 if ((*num) > 0)
966 // Copy point into available slot.
967 NmTangentPointD* pt = &(point[(*num)]);
968 NmCopyPointD (tri, v, pt);
970 // Search for it.
971 int compValue;
972 #ifdef NEW_WAY
973 int pos = NmIndexBinaryTraverseD (pt, point, sortIndex, (*num),
974 &compValue, NmCompareNoTexD);
975 #else
976 int pos = NmIndexBinaryTraverseD (pt, point, sortIndex, (*num),
977 &compValue, NmCompareD);
978 #endif
980 // Now see if we need to insert.
981 if (compValue == 0)
983 point[sortIndex[pos]].tangent[0] += pt->tangent[0];
984 point[sortIndex[pos]].tangent[1] += pt->tangent[1];
985 point[sortIndex[pos]].tangent[2] += pt->tangent[2];
986 point[sortIndex[pos]].binormal[0] += pt->binormal[0];
987 point[sortIndex[pos]].binormal[1] += pt->binormal[1];
988 point[sortIndex[pos]].binormal[2] += pt->binormal[2];
989 point[sortIndex[pos]].count++;
990 ret = sortIndex[pos];
992 else if (compValue < 0) // we are inserting before this index
994 ret = (*num);
995 memmove (&(sortIndex[pos + 1]), &(sortIndex[pos]),
996 ((*num) - pos) * sizeof(int));
998 sortIndex[pos] = (*num);
999 (*num)++;
1001 else // we are appending after this index
1003 ret = (*num);
1004 if (pos < ((*num) - 1))
1006 memmove(&(sortIndex[pos + 2]), &(sortIndex[pos + 1]),
1007 ((*num) - pos - 1) * sizeof(int));
1009 sortIndex[pos + 1] = (*num);
1010 (*num)++;
1013 else
1014 { // First point just add it into our list.
1015 NmCopyPointD (tri, v, &(point[(*num)]));
1016 sortIndex[(*num)] = 0;
1017 ret = (*num);
1018 (*num)++;
1020 return ret;
1024 ////////////////////////////////////////////////////////////////////
1025 // Insert a point and get it's index.
1026 ////////////////////////////////////////////////////////////////////
1027 static int
1028 NmInsertForVBD (NmRawTriangle* tri, NmRawTangentSpaceD* tan,
1029 int v, int* num, int* sortIndex, NmTangentPointD* point)
1031 // Make sure we have some stuff to check.
1032 int ret = 0;
1033 if ((*num) > 0)
1035 // Copy point into available slot.
1036 NmTangentPointD* pt = &(point[(*num)]);
1037 NmCopyPointTangentD (tri, tan, v, pt);
1039 // Search for it.
1040 int compValue;
1041 int pos = NmIndexBinaryTraverseD (pt, point, sortIndex, (*num),
1042 &compValue, NmCompareWithTexD);
1044 // Now see if we need to insert.
1045 if (compValue < 0) // we are inserting before this index
1047 ret = (*num);
1048 memmove (&(sortIndex[pos + 1]), &(sortIndex[pos]),
1049 ((*num) - pos) * sizeof(int));
1051 sortIndex[pos] = (*num);
1052 (*num)++;
1054 else // we are appending after this index
1056 ret = (*num);
1057 if (pos < ((*num) - 1))
1059 memmove(&(sortIndex[pos + 2]), &(sortIndex[pos + 1]),
1060 ((*num) - pos - 1) * sizeof(int));
1062 sortIndex[pos + 1] = (*num);
1063 (*num)++;
1066 else
1067 { // First point just add it into our list.
1068 NmCopyPointTangentD (tri, tan, v, &(point[(*num)]));
1069 sortIndex[(*num)] = 0;
1070 ret = (*num);
1071 (*num)++;
1073 return ret;
1076 ////////////////////////////////////////////////////////////////////
1077 // Compute tangent space for the given triangle list
1078 ////////////////////////////////////////////////////////////////////
1079 bool
1080 NmComputeTangentsD (int numTris, NmRawTriangle* tris, NmRawTangentSpaceD** tan)
1082 // Check inputs
1083 if ((numTris == 0) || (tris == NULL) || (tan == NULL))
1085 return false;
1088 // First we need to allocate up the tangent space storage
1089 (*tan) = new NmRawTangentSpaceD [numTris];
1090 if ((*tan) == NULL)
1092 return false;
1095 // Allocate storage structures
1096 NmIndex* index = new NmIndex [numTris];
1097 if (index == NULL)
1099 return false;
1101 int* sortIndex = new int [numTris*3]; // Brute force it
1102 NmTangentPointD* point = new NmTangentPointD [numTris*3]; // Brute force it
1103 if (point == NULL)
1105 return false;
1108 // Now go through finding matching vertices and computing tangents.
1109 int count = 0;
1110 int i;
1111 for (i = 0; i < numTris; i++)
1113 for (int j = 0; j < 3; j++)
1115 index[i].idx[j] = NmInsertD (&tris[i], j, &count, sortIndex, point);
1119 // Next we renormalize
1120 for (i = 0; i < count; i++)
1122 point[i].tangent[0] = point[i].tangent[0]/(double)point[i].count;
1123 point[i].tangent[1] = point[i].tangent[1]/(double)point[i].count;
1124 point[i].tangent[2] = point[i].tangent[2]/(double)point[i].count;
1125 NormalizeD (point[i].tangent);
1127 point[i].binormal[0] = point[i].binormal[0]/(double)point[i].count;
1128 point[i].binormal[1] = point[i].binormal[1]/(double)point[i].count;
1129 point[i].binormal[2] = point[i].binormal[2]/(double)point[i].count;
1130 NormalizeD (point[i].binormal);
1133 // Copy tangent data into structures
1134 for (i = 0; i < numTris; i++)
1136 for (int j = 0; j < 3; j++)
1138 (*tan)[i].tangent[j].x = point[index[i].idx[j]].tangent[0];
1139 (*tan)[i].tangent[j].y = point[index[i].idx[j]].tangent[1];
1140 (*tan)[i].tangent[j].z = point[index[i].idx[j]].tangent[2];
1141 (*tan)[i].binormal[j].x = point[index[i].idx[j]].binormal[0];
1142 (*tan)[i].binormal[j].y = point[index[i].idx[j]].binormal[1];
1143 (*tan)[i].binormal[j].z = point[index[i].idx[j]].binormal[2];
1147 // Clean up
1148 delete [] index;
1149 delete [] sortIndex;
1150 delete [] point;
1152 // Success!
1153 return true;
1154 } // end NmComputeTangent
1156 ////////////////////////////////////////////////////////////////////
1157 // Turn raw triangles into vertex/index buffers.
1158 ////////////////////////////////////////////////////////////////////
1159 bool
1160 NmCreateVertexBuffers (int numTris, NmRawTriangle* tris,
1161 int* numVerts, NmTangentPointD** verts,
1162 NmIndex** indices)
1164 // Check inputs
1165 if ((numTris == 0) || (tris == NULL) || (verts == NULL) ||
1166 (indices == NULL))
1168 return false;
1171 #ifdef NEW_WAY
1172 // First compute tangents
1173 NmRawTangentSpaceD* tan;
1174 if (!NmComputeTangentsD (numTris, tris, &tan))
1176 return false;
1178 #endif
1180 // Allocate storage structures
1181 (*indices) = new NmIndex [numTris];
1182 if ((*indices) == NULL)
1184 return false;
1186 NmIndex* index = (*indices);
1187 int* sortIndex = new int [numTris*3]; // Brute force it
1188 if (sortIndex == NULL)
1190 return false;
1192 (*verts) = new NmTangentPointD [numTris*3]; // Brute force it
1193 if ((*verts) == NULL)
1195 return false;
1197 NmTangentPointD* point = (*verts);
1199 // Now go through finding unique vertices.
1200 int count = 0;
1201 int i;
1202 for (i = 0; i < numTris; i++)
1204 for (int j = 0; j < 3; j++)
1206 #ifdef NEW_WAY
1207 index[i].idx[j] = NmInsertForVBD (&tris[i], &tan[i], j, &count,
1208 sortIndex, point);
1209 #else
1210 index[i].idx[j] = NmInsertD (&tris[i], j, &count, sortIndex, point);
1211 #endif
1214 (*numVerts) = count;
1216 // Next we renormalize
1217 #ifndef NEW_WAY
1218 for (i = 0; i < count; i++)
1220 point[i].tangent[0] = point[i].tangent[0]/(double)point[i].count;
1221 point[i].tangent[1] = point[i].tangent[1]/(double)point[i].count;
1222 point[i].tangent[2] = point[i].tangent[2]/(double)point[i].count;
1223 NormalizeD (point[i].tangent);
1225 point[i].binormal[0] = point[i].binormal[0]/(double)point[i].count;
1226 point[i].binormal[1] = point[i].binormal[1]/(double)point[i].count;
1227 point[i].binormal[2] = point[i].binormal[2]/(double)point[i].count;
1228 NormalizeD (point[i].binormal);
1230 #endif
1232 // Success!
1233 delete [] sortIndex;
1234 #ifdef NEW_WAY
1235 delete [] tan;
1236 #endif
1237 return true;
1238 } // end of NmCreateVertexBuffers