1 /******************************************************************************
2 * NmFileIO.cpp -- File IO routines for normal mapper.
3 ******************************************************************************
5 ******************************************************************************
6 * (C) 2000 ATI Research, Inc. All rights reserved.
7 ******************************************************************************/
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 ////////////////////////////////////////////////////////////////////
35 NmWriteTriangles (FILE* fp
, int numTris
, NmRawTriangle
* tris
)
37 // Write out header information
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";
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";
57 // Write the number of triangles.
58 if (fwrite (&numTris
, sizeof (int), 1, fp
) != 1)
60 cerr
<< "Unable to write number of triangles\n";
64 // Write the triangles.
65 if (fwrite (tris
, sizeof(NmRawTriangle
), numTris
, fp
) != (unsigned)numTris
)
67 cerr
<< "Unable to write triangles\n";
71 } // end NmWriteTriangles
73 ////////////////////////////////////////////////////////////////////
74 // Read a block of triangles from the file
75 ////////////////////////////////////////////////////////////////////
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";
87 cerr
<< "No triangles found in file\n";
91 // Allocate space for triangles
92 (*tris
) = new NmRawTriangle
[(*numTris
)];
95 cerr
<< "Unable to allocate space for " << (*tris
) << " triangles\n";
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";
107 perror ("Read Triangles");
111 cerr
<< "End of file!\n";
121 ////////////////////////////////////////////////////////////////////
122 // Read a block of triangles from the file
123 ////////////////////////////////////////////////////////////////////
125 NmReadTriangles (FILE* fp
, int* numTris
, NmRawTriangle
** tris
)
130 // Read chunk header.
131 if (fread (&header
, sizeof (NmHeader
), 1, fp
) != 1)
133 cerr
<< "Unable to read header\n";
137 // Check if it's the NMF chunk
138 if (strncmp (header
.hdr
, NMF_HEADER_TAG
, 4) == 0)
142 // Read chunk header.
143 if (fread (&header
, sizeof (NmHeader
), 1, fp
) != 1)
145 cerr
<< "Unable to read header\n";
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
);
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";
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";
176 cerr
<< "No NMF data found in file\n";
178 } // end NmReadTriangles
180 ////////////////////////////////////////////////////////////////////
181 // Converts an older (pre chunk) NMF file into the current format
182 ////////////////////////////////////////////////////////////////////
184 NmConvertFile (FILE* fpIn
, FILE* fpOut
)
188 if (!NmReadTriangleChunk (fpIn
, &numTris
, &tris
))
190 cerr
<< "Unable to read input file\n";
193 if (!NmWriteTriangles (fpOut
, numTris
, tris
))
195 cerr
<< "Unable to write output file\n";
201 ////////////////////////////////////////////////////////////////////
202 // Compute tangent space for the given triangle list
203 ////////////////////////////////////////////////////////////////////
205 NmComputeTangents (int numTris
, NmRawTriangle
* tris
, NmRawTangentSpace
** tan
)
208 if ((numTris
== 0) || (tris
== NULL
) || (tan
== NULL
))
213 // First we need to allocate up the tangent space storage
214 (*tan
) = new NmRawTangentSpace
[numTris
];
220 // Cheat and use the double version to compute then convert into floats
221 NmRawTangentSpaceD
* tanD
;
222 if (!NmComputeTangentsD(numTris
, tris
, &tanD
))
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
);
243 } // end NmComputeTangents
245 //==========================================================================
246 // Normalize a vector
247 //==========================================================================
249 NormalizeD (double v
[3])
251 double len
= sqrt((v
[0]*v
[0])+(v
[1]*v
[1])+(v
[2]*v
[2]));
266 //==========================================================================
267 // Calculates the dot product of two vectors.
268 //==========================================================================
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 //=============================================================================
281 NmCompareD (NmTangentPointD
* v0
, NmTangentPointD
* v1
)
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
])
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
])
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
])
334 double t0
[3] = {v0
->tangent
[0], v0
->tangent
[1], v0
->tangent
[2]};
336 double t1
[3] = {v1
->tangent
[0], v1
->tangent
[1], v1
->tangent
[2]};
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
])
355 double b0
[3] = {v0
->binormal
[0], v0
->binormal
[1], v0
->binormal
[2]};
357 double b1
[3] = {v1
->binormal
[0], v1
->binormal
[1], v1
->binormal
[2]};
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
])
377 //=============================================================================
378 // Compare the values
379 //=============================================================================
381 NmCompareWithTexD (NmTangentPointD
* v0
, NmTangentPointD
* v1
)
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
])
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
])
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
])
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
])
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
])
469 //=============================================================================
470 // Compare the values
471 //=============================================================================
473 NmCompareNoTexD (NmTangentPointD
* v0
, NmTangentPointD
* v1
)
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
])
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
])
509 double t0
[3] = {v0
->tangent
[0], v0
->tangent
[1], v0
->tangent
[2]};
511 double t1
[3] = {v1
->tangent
[0], v1
->tangent
[1], v1
->tangent
[2]};
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
])
530 double b0
[3] = {v0
->binormal
[0], v0
->binormal
[1], v0
->binormal
[2]};
532 double b1
[3] = {v1
->binormal
[0], v1
->binormal
[1], v1
->binormal
[2]};
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
])
552 //=============================================================================
553 // Binary traversal function
554 //=============================================================================
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.
570 mid
= low
+ ((high
- low
) >> 1);
575 *result
= compare (value
, &(data
[indices
[mid
]]));
580 else if (*result
< 0)
589 nextMid
= low
+ ((high
- low
) >> 1);
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); \
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
673 bool DcTangentSpace(float* v1
, float* v2
, float* v3
,
674 float* t1
, float* t2
, float* t3
,
675 double* normal
, double *tangent
, double *binormal
)
683 tanSpaceVert verts
[3];
684 tanSpaceVert tempVert
;
687 double tempVector
[3];
689 //===================================//
690 // make sure the arguments are valid //
691 //===================================//
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])
736 if (verts
[0].t
[1] < verts
[2].t
[1])
742 if (verts
[1].t
[1] < verts
[2].t
[1])
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
)
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])
813 if (verts
[0].t
[0] < verts
[2].t
[0])
819 if (verts
[1].t
[0] < verts
[2].t
[0])
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
)
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
);
879 return DC_INVALID_ARG
;
885 ////////////////////////////////////////////////////////////////////
886 // Compute tangent space for the given triangle
887 ////////////////////////////////////////////////////////////////////
889 ComputeTangentVectorsD (NmRawTriangle
* pgon
, int idx
,
890 double tan
[3], double norm
[3], double binorm
[3])
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)
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 ////////////////////////////////////////////////////////////////////
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
;
927 ComputeTangentVectorsD (tri
, v
, point
->tangent
, norm
, point
->binormal
);
931 ////////////////////////////////////////////////////////////////////
932 // Copy data into a point structure
933 ////////////////////////////////////////////////////////////////////
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
;
955 ////////////////////////////////////////////////////////////////////
956 // Insert a point and get it's index.
957 ////////////////////////////////////////////////////////////////////
959 NmInsertD (NmRawTriangle
* tri
, int v
, int* num
, int* sortIndex
,
960 NmTangentPointD
* point
)
962 // Make sure we have some stuff to check.
966 // Copy point into available slot.
967 NmTangentPointD
* pt
= &(point
[(*num
)]);
968 NmCopyPointD (tri
, v
, pt
);
973 int pos
= NmIndexBinaryTraverseD (pt
, point
, sortIndex
, (*num
),
974 &compValue
, NmCompareNoTexD
);
976 int pos
= NmIndexBinaryTraverseD (pt
, point
, sortIndex
, (*num
),
977 &compValue
, NmCompareD
);
980 // Now see if we need to insert.
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
995 memmove (&(sortIndex
[pos
+ 1]), &(sortIndex
[pos
]),
996 ((*num
) - pos
) * sizeof(int));
998 sortIndex
[pos
] = (*num
);
1001 else // we are appending after this index
1004 if (pos
< ((*num
) - 1))
1006 memmove(&(sortIndex
[pos
+ 2]), &(sortIndex
[pos
+ 1]),
1007 ((*num
) - pos
- 1) * sizeof(int));
1009 sortIndex
[pos
+ 1] = (*num
);
1014 { // First point just add it into our list.
1015 NmCopyPointD (tri
, v
, &(point
[(*num
)]));
1016 sortIndex
[(*num
)] = 0;
1024 ////////////////////////////////////////////////////////////////////
1025 // Insert a point and get it's index.
1026 ////////////////////////////////////////////////////////////////////
1028 NmInsertForVBD (NmRawTriangle
* tri
, NmRawTangentSpaceD
* tan
,
1029 int v
, int* num
, int* sortIndex
, NmTangentPointD
* point
)
1031 // Make sure we have some stuff to check.
1035 // Copy point into available slot.
1036 NmTangentPointD
* pt
= &(point
[(*num
)]);
1037 NmCopyPointTangentD (tri
, tan
, v
, pt
);
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
1048 memmove (&(sortIndex
[pos
+ 1]), &(sortIndex
[pos
]),
1049 ((*num
) - pos
) * sizeof(int));
1051 sortIndex
[pos
] = (*num
);
1054 else // we are appending after this index
1057 if (pos
< ((*num
) - 1))
1059 memmove(&(sortIndex
[pos
+ 2]), &(sortIndex
[pos
+ 1]),
1060 ((*num
) - pos
- 1) * sizeof(int));
1062 sortIndex
[pos
+ 1] = (*num
);
1067 { // First point just add it into our list.
1068 NmCopyPointTangentD (tri
, tan
, v
, &(point
[(*num
)]));
1069 sortIndex
[(*num
)] = 0;
1076 ////////////////////////////////////////////////////////////////////
1077 // Compute tangent space for the given triangle list
1078 ////////////////////////////////////////////////////////////////////
1080 NmComputeTangentsD (int numTris
, NmRawTriangle
* tris
, NmRawTangentSpaceD
** tan
)
1083 if ((numTris
== 0) || (tris
== NULL
) || (tan
== NULL
))
1088 // First we need to allocate up the tangent space storage
1089 (*tan
) = new NmRawTangentSpaceD
[numTris
];
1095 // Allocate storage structures
1096 NmIndex
* index
= new NmIndex
[numTris
];
1101 int* sortIndex
= new int [numTris
*3]; // Brute force it
1102 NmTangentPointD
* point
= new NmTangentPointD
[numTris
*3]; // Brute force it
1108 // Now go through finding matching vertices and computing tangents.
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];
1149 delete [] sortIndex
;
1154 } // end NmComputeTangent
1156 ////////////////////////////////////////////////////////////////////
1157 // Turn raw triangles into vertex/index buffers.
1158 ////////////////////////////////////////////////////////////////////
1160 NmCreateVertexBuffers (int numTris
, NmRawTriangle
* tris
,
1161 int* numVerts
, NmTangentPointD
** verts
,
1165 if ((numTris
== 0) || (tris
== NULL
) || (verts
== NULL
) ||
1172 // First compute tangents
1173 NmRawTangentSpaceD
* tan
;
1174 if (!NmComputeTangentsD (numTris
, tris
, &tan
))
1180 // Allocate storage structures
1181 (*indices
) = new NmIndex
[numTris
];
1182 if ((*indices
) == NULL
)
1186 NmIndex
* index
= (*indices
);
1187 int* sortIndex
= new int [numTris
*3]; // Brute force it
1188 if (sortIndex
== NULL
)
1192 (*verts
) = new NmTangentPointD
[numTris
*3]; // Brute force it
1193 if ((*verts
) == NULL
)
1197 NmTangentPointD
* point
= (*verts
);
1199 // Now go through finding unique vertices.
1202 for (i
= 0; i
< numTris
; i
++)
1204 for (int j
= 0; j
< 3; j
++)
1207 index
[i
].idx
[j
] = NmInsertForVBD (&tris
[i
], &tan
[i
], j
, &count
,
1210 index
[i
].idx
[j
] = NmInsertD (&tris
[i
], j
, &count
, sortIndex
, point
);
1214 (*numVerts
) = count
;
1216 // Next we renormalize
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
);
1233 delete [] sortIndex
;
1238 } // end of NmCreateVertexBuffers