1 /******************************************************************************
2
3 @File PVRTVertex.cpp
4
5 @Title PVRTVertex
6
7 @Version
8
9 @Copyright Copyright (c) Imagination Technologies Limited.
10
11 @Platform ANSI compatible
12
13 @Description Utility functions which process vertices.
14
15 ******************************************************************************/
16
17 /****************************************************************************
18 ** Includes
19 ****************************************************************************/
20 #include "PVRTGlobal.h"
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "PVRTFixedPoint.h"
26 #include "PVRTMatrix.h"
27 #include "PVRTVertex.h"
28
29 /****************************************************************************
30 ** Defines
31 ****************************************************************************/
32
33 /****************************************************************************
34 ** Macros
35 ****************************************************************************/
36 #define MAX_VERTEX_OUT (3*nVtxNum)
37
38 /****************************************************************************
39 ** Structures
40 ****************************************************************************/
41
42 /****************************************************************************
43 ** Constants
44 ****************************************************************************/
45
46 /****************************************************************************
47 ** Local function definitions
48 ****************************************************************************/
49
50 /*****************************************************************************
51 ** Functions
52 *****************************************************************************/
53
54 /*!***************************************************************************
55 @Function PVRTVertexRead
56 @Output pV
57 @Input pData
58 @Input eType
59 @Input nCnt
60 @Description Read a vector
61 *****************************************************************************/
PVRTVertexRead(PVRTVECTOR4f * const pV,const void * const pData,const EPVRTDataType eType,const int nCnt)62 void PVRTVertexRead(
63 PVRTVECTOR4f * const pV,
64 const void * const pData,
65 const EPVRTDataType eType,
66 const int nCnt)
67 {
68 int i;
69 float *pOut = (float*)pV;
70
71 pV->x = 0;
72 pV->y = 0;
73 pV->z = 0;
74 pV->w = 1;
75
76 switch(eType)
77 {
78 default:
79 _ASSERT(false);
80 break;
81
82 case EPODDataFloat:
83 for(i = 0; i < nCnt; ++i)
84 pOut[i] = ((float*)pData)[i];
85 break;
86
87 case EPODDataFixed16_16:
88 for(i = 0; i < nCnt; ++i)
89 pOut[i] = ((int*)pData)[i] * 1.0f / (float)(1 << 16);
90 break;
91
92 case EPODDataInt:
93 for(i = 0; i < nCnt; ++i)
94 pOut[i] = (float)((int*)pData)[i];
95 break;
96
97 case EPODDataUnsignedInt:
98 for(i = 0; i < nCnt; ++i)
99 pOut[i] = (float)((unsigned int*)pData)[i];
100 break;
101
102 case EPODDataByte:
103 for(i = 0; i < nCnt; ++i)
104 pOut[i] = (float)((char*)pData)[i];
105 break;
106
107 case EPODDataByteNorm:
108 for(i = 0; i < nCnt; ++i)
109 pOut[i] = (float)((char*)pData)[i] / (float)((1 << 7)-1);
110 break;
111
112 case EPODDataUnsignedByte:
113 for(i = 0; i < nCnt; ++i)
114 pOut[i] = (float)((unsigned char*)pData)[i];
115 break;
116
117 case EPODDataUnsignedByteNorm:
118 for(i = 0; i < nCnt; ++i)
119 pOut[i] = (float)((unsigned char*)pData)[i] / (float)((1 << 8)-1);
120 break;
121
122 case EPODDataShort:
123 for(i = 0; i < nCnt; ++i)
124 pOut[i] = (float)((short*)pData)[i];
125 break;
126
127 case EPODDataShortNorm:
128 for(i = 0; i < nCnt; ++i)
129 pOut[i] = (float)((short*)pData)[i] / (float)((1 << 15)-1);
130 break;
131
132 case EPODDataUnsignedShort:
133 for(i = 0; i < nCnt; ++i)
134 pOut[i] = (float)((unsigned short*)pData)[i];
135 break;
136
137 case EPODDataUnsignedShortNorm:
138 for(i = 0; i < nCnt; ++i)
139 pOut[i] = (float)((unsigned short*)pData)[i] / (float)((1 << 16)-1);
140 break;
141
142 case EPODDataRGBA:
143 {
144 unsigned int dwVal = *(unsigned int*)pData;
145 unsigned char v[4];
146
147 v[0] = (unsigned char) (dwVal >> 24);
148 v[1] = (unsigned char) (dwVal >> 16);
149 v[2] = (unsigned char) (dwVal >> 8);
150 v[3] = (unsigned char) (dwVal >> 0);
151
152 for(i = 0; i < 4; ++i)
153 pOut[i] = 1.0f / 255.0f * (float)v[i];
154 }
155 break;
156
157 case EPODDataABGR:
158 {
159 unsigned int dwVal = *(unsigned int*)pData;
160 unsigned char v[4];
161
162 v[0] = (unsigned char) (dwVal >> 0);
163 v[1] = (unsigned char) (dwVal >> 8);
164 v[2] = (unsigned char) (dwVal >> 16);
165 v[3] = (unsigned char) (dwVal >> 24);
166
167 for(i = 0; i < 4; ++i)
168 pOut[i] = 1.0f / 255.0f * (float)v[i];
169 }
170 break;
171
172 case EPODDataARGB:
173 case EPODDataD3DCOLOR:
174 {
175 unsigned int dwVal = *(unsigned int*)pData;
176 unsigned char v[4];
177
178 v[0] = (unsigned char) (dwVal >> 16);
179 v[1] = (unsigned char) (dwVal >> 8);
180 v[2] = (unsigned char) (dwVal >> 0);
181 v[3] = (unsigned char) (dwVal >> 24);
182
183 for(i = 0; i < 4; ++i)
184 pOut[i] = 1.0f / 255.0f * (float)v[i];
185 }
186 break;
187
188 case EPODDataUBYTE4:
189 {
190 unsigned int dwVal = *(unsigned int*)pData;
191 unsigned char v[4];
192
193 v[0] = (unsigned char) (dwVal >> 0);
194 v[1] = (unsigned char) (dwVal >> 8);
195 v[2] = (unsigned char) (dwVal >> 16);
196 v[3] = (unsigned char) (dwVal >> 24);
197
198 for(i = 0; i < 4; ++i)
199 pOut[i] = v[i];
200 }
201 break;
202
203 case EPODDataDEC3N:
204 {
205 int dwVal = *(int*)pData;
206 int v[4];
207
208 v[0] = (dwVal << 22) >> 22;
209 v[1] = (dwVal << 12) >> 22;
210 v[2] = (dwVal << 2) >> 22;
211 v[3] = 0;
212
213 for(i = 0; i < 3; ++i)
214 pOut[i] = (float)v[i] * (1.0f / 511.0f);
215 }
216 break;
217 }
218 }
219
220 /*!***************************************************************************
221 @Function PVRTVertexRead
222 @Output pV
223 @Input pData
224 @Input eType
225 @Description Read an int
226 *****************************************************************************/
PVRTVertexRead(unsigned int * const pV,const void * const pData,const EPVRTDataType eType)227 void PVRTVertexRead(
228 unsigned int * const pV,
229 const void * const pData,
230 const EPVRTDataType eType)
231 {
232 switch(eType)
233 {
234 default:
235 _ASSERT(false);
236 break;
237
238 case EPODDataUnsignedShort:
239 *pV = *(unsigned short*)pData;
240 break;
241
242 case EPODDataUnsignedInt:
243 *pV = *(unsigned int*)pData;
244 break;
245 }
246 }
247
248 /*!***************************************************************************
249 @Function PVRTVertexWrite
250 @Output pOut
251 @Input eType
252 @Input nCnt
253 @Input pV
254 @Description Write a vector
255 *****************************************************************************/
PVRTVertexWrite(void * const pOut,const EPVRTDataType eType,const int nCnt,const PVRTVECTOR4f * const pV)256 void PVRTVertexWrite(
257 void * const pOut,
258 const EPVRTDataType eType,
259 const int nCnt,
260 const PVRTVECTOR4f * const pV)
261 {
262 int i;
263 float *pData = (float*)pV;
264
265 switch(eType)
266 {
267 default:
268 _ASSERT(false);
269 break;
270
271 case EPODDataDEC3N:
272 {
273 int v[3];
274
275 for(i = 0; i < nCnt; ++i)
276 {
277 v[i] = (int)(pData[i] * 511.0f);
278 v[i] = PVRT_CLAMP(v[i], -511, 511);
279 v[i] &= 0x000003ff;
280 }
281
282 for(; i < 3; ++i)
283 {
284 v[i] = 0;
285 }
286
287 *(unsigned int*)pOut = (v[0] << 0) | (v[1] << 10) | (v[2] << 20);
288 }
289 break;
290
291 case EPODDataARGB:
292 case EPODDataD3DCOLOR:
293 {
294 unsigned char v[4];
295
296 for(i = 0; i < nCnt; ++i)
297 v[i] = (unsigned char)PVRT_CLAMP(pData[i] * 255.0f, 0.0f, 255.0f);
298
299 for(; i < 4; ++i)
300 v[i] = 0;
301
302 *(unsigned int*)pOut = (v[3] << 24) | (v[0] << 16) | (v[1] << 8) | v[2];
303 }
304 break;
305
306 case EPODDataRGBA:
307 {
308 unsigned char v[4];
309
310 for(i = 0; i < nCnt; ++i)
311 v[i] = (unsigned char)PVRT_CLAMP(pData[i] * 255.0f, 0.0f, 255.0f);
312
313 for(; i < 4; ++i)
314 v[i] = 0;
315
316 *(unsigned int*)pOut = (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3];
317 }
318 break;
319
320 case EPODDataABGR:
321 {
322 unsigned char v[4];
323
324 for(i = 0; i < nCnt; ++i)
325 v[i] = (unsigned char)PVRT_CLAMP(pData[i] * 255.0f, 0.0f, 255.0f);
326
327 for(; i < 4; ++i)
328 v[i] = 0;
329
330 *(unsigned int*)pOut = (v[3] << 24) | (v[2] << 16) | (v[1] << 8) | v[0];
331 }
332 break;
333
334 case EPODDataUBYTE4:
335 {
336 unsigned char v[4];
337
338 for(i = 0; i < nCnt; ++i)
339 v[i] = (unsigned char)PVRT_CLAMP(pData[i], 0.0f, 255.0f);
340
341 for(; i < 4; ++i)
342 v[i] = 0;
343
344 *(unsigned int*)pOut = (v[3] << 24) | (v[2] << 16) | (v[1] << 8) | v[0];
345 }
346 break;
347
348 case EPODDataFloat:
349 for(i = 0; i < nCnt; ++i)
350 ((float*)pOut)[i] = pData[i];
351 break;
352
353 case EPODDataFixed16_16:
354 for(i = 0; i < nCnt; ++i)
355 ((int*)pOut)[i] = (int)(pData[i] * (float)(1 << 16));
356 break;
357
358 case EPODDataInt:
359 for(i = 0; i < nCnt; ++i)
360 ((int*)pOut)[i] = (int)pData[i];
361 break;
362
363 case EPODDataUnsignedInt:
364 for(i = 0; i < nCnt; ++i)
365 ((unsigned int*)pOut)[i] = (unsigned int)pData[i];
366 break;
367
368 case EPODDataByte:
369 for(i = 0; i < nCnt; ++i)
370 ((char*)pOut)[i] = (char)pData[i];
371 break;
372
373 case EPODDataByteNorm:
374 for(i = 0; i < nCnt; ++i)
375 ((char*)pOut)[i] = (char)(pData[i] * (float)((1 << 7)-1));
376 break;
377
378 case EPODDataUnsignedByte:
379 for(i = 0; i < nCnt; ++i)
380 ((unsigned char*)pOut)[i] = (unsigned char)pData[i];
381 break;
382
383 case EPODDataUnsignedByteNorm:
384 for(i = 0; i < nCnt; ++i)
385 ((char*)pOut)[i] = (unsigned char)(pData[i] * (float)((1 << 8)-1));
386 break;
387
388 case EPODDataShort:
389 for(i = 0; i < nCnt; ++i)
390 ((short*)pOut)[i] = (short)pData[i];
391 break;
392
393 case EPODDataShortNorm:
394 for(i = 0; i < nCnt; ++i)
395 ((short*)pOut)[i] = (short)(pData[i] * (float)((1 << 15)-1));
396 break;
397
398 case EPODDataUnsignedShort:
399 for(i = 0; i < nCnt; ++i)
400 ((unsigned short*)pOut)[i] = (unsigned short)pData[i];
401 break;
402
403 case EPODDataUnsignedShortNorm:
404 for(i = 0; i < nCnt; ++i)
405 ((unsigned short*)pOut)[i] = (unsigned short)(pData[i] * (float)((1 << 16)-1));
406 break;
407 }
408 }
409
410 /*!***************************************************************************
411 @Function PVRTVertexWrite
412 @Output pOut
413 @Input eType
414 @Input V
415 @Description Write an int
416 *****************************************************************************/
PVRTVertexWrite(void * const pOut,const EPVRTDataType eType,const unsigned int V)417 void PVRTVertexWrite(
418 void * const pOut,
419 const EPVRTDataType eType,
420 const unsigned int V)
421 {
422 switch(eType)
423 {
424 default:
425 _ASSERT(false);
426 break;
427
428 case EPODDataUnsignedShort:
429 *(unsigned short*)pOut = (unsigned short) V;
430 break;
431
432 case EPODDataUnsignedInt:
433 *(unsigned int*)pOut = V;
434 break;
435 }
436 }
437
438 /*!***************************************************************************
439 @Function PVRTVertexTangentBitangent
440 @Output pvTan
441 @Output pvBin
442 @Input pvNor
443 @Input pfPosA
444 @Input pfPosB
445 @Input pfPosC
446 @Input pfTexA
447 @Input pfTexB
448 @Input pfTexC
449 @Description Calculates the tangent and bitangent vectors for
450 vertex 'A' of the triangle defined by the 3 supplied
451 3D position coordinates (pfPosA) and 2D texture
452 coordinates (pfTexA).
453 *****************************************************************************/
PVRTVertexTangentBitangent(PVRTVECTOR3f * const pvTan,PVRTVECTOR3f * const pvBin,const PVRTVECTOR3f * const pvNor,const float * const pfPosA,const float * const pfPosB,const float * const pfPosC,const float * const pfTexA,const float * const pfTexB,const float * const pfTexC)454 void PVRTVertexTangentBitangent(
455 PVRTVECTOR3f * const pvTan,
456 PVRTVECTOR3f * const pvBin,
457 const PVRTVECTOR3f * const pvNor,
458 const float * const pfPosA,
459 const float * const pfPosB,
460 const float * const pfPosC,
461 const float * const pfTexA,
462 const float * const pfTexB,
463 const float * const pfTexC)
464 {
465 PVRTVECTOR3f BaseVector1, BaseVector2, AlignedVector;
466
467 if(PVRTMatrixVec3DotProductF(*pvNor, *pvNor) == 0)
468 {
469 pvTan->x = 0;
470 pvTan->y = 0;
471 pvTan->z = 0;
472 pvBin->x = 0;
473 pvBin->y = 0;
474 pvBin->z = 0;
475 return;
476 }
477
478 /* BaseVectors are A-B and A-C. */
479 BaseVector1.x = pfPosB[0] - pfPosA[0];
480 BaseVector1.y = pfPosB[1] - pfPosA[1];
481 BaseVector1.z = pfPosB[2] - pfPosA[2];
482
483 BaseVector2.x = pfPosC[0] - pfPosA[0];
484 BaseVector2.y = pfPosC[1] - pfPosA[1];
485 BaseVector2.z = pfPosC[2] - pfPosA[2];
486
487 if (pfTexB[0]==pfTexA[0] && pfTexC[0]==pfTexA[0])
488 {
489 // Degenerate tri
490 // _ASSERT(0);
491 pvTan->x = 0;
492 pvTan->y = 0;
493 pvTan->z = 0;
494 pvBin->x = 0;
495 pvBin->y = 0;
496 pvBin->z = 0;
497 }
498 else
499 {
500 /* Calc the vector that follows the V direction (it is not the tangent vector)*/
501 if(pfTexB[0]==pfTexA[0]) {
502 AlignedVector = BaseVector1;
503 if((pfTexB[1] - pfTexA[1]) < 0) {
504 AlignedVector.x = -AlignedVector.x;
505 AlignedVector.y = -AlignedVector.y;
506 AlignedVector.z = -AlignedVector.z;
507 }
508 } else if(pfTexC[0]==pfTexA[0]) {
509 AlignedVector = BaseVector2;
510 if((pfTexC[1] - pfTexA[1]) < 0) {
511 AlignedVector.x = -AlignedVector.x;
512 AlignedVector.y = -AlignedVector.y;
513 AlignedVector.z = -AlignedVector.z;
514 }
515 } else {
516 float fFac;
517
518 fFac = -(pfTexB[0] - pfTexA[0]) / (pfTexC[0] - pfTexA[0]);
519
520 /* This is the vector that follows the V direction (it is not the tangent vector)*/
521 AlignedVector.x = BaseVector1.x + BaseVector2.x * fFac;
522 AlignedVector.y = BaseVector1.y + BaseVector2.y * fFac;
523 AlignedVector.z = BaseVector1.z + BaseVector2.z * fFac;
524
525 if(((pfTexB[1] - pfTexA[1]) + (pfTexC[1] - pfTexA[1]) * fFac) < 0) {
526 AlignedVector.x = -AlignedVector.x;
527 AlignedVector.y = -AlignedVector.y;
528 AlignedVector.z = -AlignedVector.z;
529 }
530 }
531
532 PVRTMatrixVec3NormalizeF(AlignedVector, AlignedVector);
533
534 /* The Tangent vector is perpendicular to the plane defined by vAlignedVector and the Normal. */
535 PVRTMatrixVec3CrossProductF(*pvTan, *pvNor, AlignedVector);
536
537 /* The Bitangent vector is the vector perpendicular to the Normal and Tangent (and
538 that follows the vAlignedVector direction) */
539 PVRTMatrixVec3CrossProductF(*pvBin, *pvTan, *pvNor);
540
541 _ASSERT(PVRTMatrixVec3DotProductF(*pvBin, AlignedVector) > 0.0f);
542
543 // Worry about wrapping; this is esentially a 2D cross product on texture coords
544 if((pfTexC[0]-pfTexA[0])*(pfTexB[1]-pfTexA[1]) < (pfTexC[1]-pfTexA[1])*(pfTexB[0]-pfTexA[0])) {
545 pvTan->x = -pvTan->x;
546 pvTan->y = -pvTan->y;
547 pvTan->z = -pvTan->z;
548 }
549
550 /* Normalize results */
551 PVRTMatrixVec3NormalizeF(*pvTan, *pvTan);
552 PVRTMatrixVec3NormalizeF(*pvBin, *pvBin);
553
554 _ASSERT(PVRTMatrixVec3DotProductF(*pvNor, *pvNor) > 0.9f);
555 _ASSERT(PVRTMatrixVec3DotProductF(*pvTan, *pvTan) > 0.9f);
556 _ASSERT(PVRTMatrixVec3DotProductF(*pvBin, *pvBin) > 0.9f);
557 }
558 }
559
560 /*!***************************************************************************
561 @Function PVRTVertexGenerateTangentSpace
562 @Output pnVtxNumOut Output vertex count
563 @Output pVtxOut Output vertices (program must free() this)
564 @Modified pui32Idx input AND output; index array for triangle list
565 @Input nVtxNum Input vertex count
566 @Input pVtx Input vertices
567 @Input nStride Size of a vertex (in bytes)
568 @Input nOffsetPos Offset in bytes to the vertex position
569 @Input eTypePos Data type of the position
570 @Input nOffsetNor Offset in bytes to the vertex normal
571 @Input eTypeNor Data type of the normal
572 @Input nOffsetTex Offset in bytes to the vertex texture coordinate to use
573 @Input eTypeTex Data type of the texture coordinate
574 @Input nOffsetTan Offset in bytes to the vertex tangent
575 @Input eTypeTan Data type of the tangent
576 @Input nOffsetBin Offset in bytes to the vertex bitangent
577 @Input eTypeBin Data type of the bitangent
578 @Input nTriNum Number of triangles
579 @Input fSplitDifference Split a vertex if the DP3 of tangents/bitangents are below this (range -1..1)
580 @Return PVR_FAIL if there was a problem.
581 @Description Calculates the tangent space for all supplied vertices.
582 Writes tangent and bitangent vectors to the output
583 vertices, copies all other elements from input vertices.
584 Will split vertices if necessary - i.e. if two triangles
585 sharing a vertex want to assign it different
586 tangent-space matrices. The decision whether to split
587 uses fSplitDifference - of the DP3 of two desired
588 tangents or two desired bitangents is higher than this,
589 the vertex will be split.
590 *****************************************************************************/
PVRTVertexGenerateTangentSpace(unsigned int * const pnVtxNumOut,char ** const pVtxOut,unsigned int * const pui32Idx,const unsigned int nVtxNum,const char * const pVtx,const unsigned int nStride,const unsigned int nOffsetPos,EPVRTDataType eTypePos,const unsigned int nOffsetNor,EPVRTDataType eTypeNor,const unsigned int nOffsetTex,EPVRTDataType eTypeTex,const unsigned int nOffsetTan,EPVRTDataType eTypeTan,const unsigned int nOffsetBin,EPVRTDataType eTypeBin,const unsigned int nTriNum,const float fSplitDifference)591 EPVRTError PVRTVertexGenerateTangentSpace(
592 unsigned int * const pnVtxNumOut,
593 char ** const pVtxOut,
594 unsigned int * const pui32Idx,
595 const unsigned int nVtxNum,
596 const char * const pVtx,
597 const unsigned int nStride,
598 const unsigned int nOffsetPos,
599 EPVRTDataType eTypePos,
600 const unsigned int nOffsetNor,
601 EPVRTDataType eTypeNor,
602 const unsigned int nOffsetTex,
603 EPVRTDataType eTypeTex,
604 const unsigned int nOffsetTan,
605 EPVRTDataType eTypeTan,
606 const unsigned int nOffsetBin,
607 EPVRTDataType eTypeBin,
608 const unsigned int nTriNum,
609 const float fSplitDifference)
610 {
611 const int cnMaxSharedVtx = 32;
612 struct SVtxData
613 {
614 int n; // Number of items in following arrays, AKA number of tris using this vtx
615 PVRTVECTOR3f pvTan[cnMaxSharedVtx]; // Tangent (one per triangle referencing this vtx)
616 PVRTVECTOR3f pvBin[cnMaxSharedVtx]; // Bitangent (one per triangle referencing this vtx)
617 int pnTri[cnMaxSharedVtx]; // Triangle index (one per triangle referencing this vtx)
618 };
619 SVtxData *psVtxData; // Array of desired tangent spaces per vertex
620 SVtxData *psTSpass; // Array of *different* tangent spaces desired for current vertex
621 unsigned int nTSpassLen;
622 SVtxData *psVtx, *psCmp;
623 unsigned int nVert, nCurr, i, j; // Loop counters
624 unsigned int nIdx0, nIdx1, nIdx2;
625 float pfPos0[4], pfPos1[4], pfPos2[4];
626 float pfTex0[4], pfTex1[4], pfTex2[4];
627 float pfNor0[4], pfNor1[4], pfNor2[4];
628 unsigned int *pui32IdxNew; // New index array, this will be copied over the input array
629
630 // Initialise the outputs
631 *pnVtxNumOut = 0;
632 *pVtxOut = (char*)malloc(MAX_VERTEX_OUT * nStride);
633 if(!*pVtxOut)
634 {
635 return PVR_FAIL;
636 }
637
638 // Allocate some work space
639 pui32IdxNew = (unsigned int*)calloc(nTriNum * 3, sizeof(*pui32IdxNew));
640 _ASSERT(pui32IdxNew);
641 psVtxData = (SVtxData*)calloc(nVtxNum, sizeof(*psVtxData));
642 _ASSERT(psVtxData);
643 psTSpass = (SVtxData*)calloc(cnMaxSharedVtx, sizeof(*psTSpass));
644 _ASSERT(psTSpass);
645 if(!pui32IdxNew || !psVtxData || !psTSpass)
646 {
647 free(pui32IdxNew);
648 free(psVtxData);
649 free(psTSpass);
650 return PVR_FAIL;
651 }
652
653 for(nCurr = 0; nCurr < nTriNum; ++nCurr) {
654 nIdx0 = pui32Idx[3*nCurr+0];
655 nIdx1 = pui32Idx[3*nCurr+1];
656 nIdx2 = pui32Idx[3*nCurr+2];
657
658 _ASSERT(nIdx0 < nVtxNum);
659 _ASSERT(nIdx1 < nVtxNum);
660 _ASSERT(nIdx2 < nVtxNum);
661
662 if(nIdx0 == nIdx1 || nIdx1 == nIdx2 || nIdx0 == nIdx2) {
663 _RPT0(_CRT_WARN,"GenerateTangentSpace(): Degenerate triangle found.\n");
664 return PVR_FAIL;
665 }
666
667 if(
668 psVtxData[nIdx0].n >= cnMaxSharedVtx ||
669 psVtxData[nIdx1].n >= cnMaxSharedVtx ||
670 psVtxData[nIdx2].n >= cnMaxSharedVtx)
671 {
672 _RPT0(_CRT_WARN,"GenerateTangentSpace(): Too many tris sharing a vtx.\n");
673 return PVR_FAIL;
674 }
675
676 PVRTVertexRead((PVRTVECTOR4f*) &pfPos0[0], (char*)&pVtx[nIdx0 * nStride] + nOffsetPos, eTypePos, 3);
677 PVRTVertexRead((PVRTVECTOR4f*) &pfPos1[0], (char*)&pVtx[nIdx1 * nStride] + nOffsetPos, eTypePos, 3);
678 PVRTVertexRead((PVRTVECTOR4f*) &pfPos2[0], (char*)&pVtx[nIdx2 * nStride] + nOffsetPos, eTypePos, 3);
679
680 PVRTVertexRead((PVRTVECTOR4f*) &pfNor0[0], (char*)&pVtx[nIdx0 * nStride] + nOffsetNor, eTypeNor, 3);
681 PVRTVertexRead((PVRTVECTOR4f*) &pfNor1[0], (char*)&pVtx[nIdx1 * nStride] + nOffsetNor, eTypeNor, 3);
682 PVRTVertexRead((PVRTVECTOR4f*) &pfNor2[0], (char*)&pVtx[nIdx2 * nStride] + nOffsetNor, eTypeNor, 3);
683
684 PVRTVertexRead((PVRTVECTOR4f*) &pfTex0[0], (char*)&pVtx[nIdx0 * nStride] + nOffsetTex, eTypeTex, 3);
685 PVRTVertexRead((PVRTVECTOR4f*) &pfTex1[0], (char*)&pVtx[nIdx1 * nStride] + nOffsetTex, eTypeTex, 3);
686 PVRTVertexRead((PVRTVECTOR4f*) &pfTex2[0], (char*)&pVtx[nIdx2 * nStride] + nOffsetTex, eTypeTex, 3);
687
688 PVRTVertexTangentBitangent(
689 &psVtxData[nIdx0].pvTan[psVtxData[nIdx0].n],
690 &psVtxData[nIdx0].pvBin[psVtxData[nIdx0].n],
691 (PVRTVECTOR3f*) &pfNor0[0],
692 pfPos0, pfPos1, pfPos2,
693 pfTex0, pfTex1, pfTex2);
694
695 PVRTVertexTangentBitangent(
696 &psVtxData[nIdx1].pvTan[psVtxData[nIdx1].n],
697 &psVtxData[nIdx1].pvBin[psVtxData[nIdx1].n],
698 (PVRTVECTOR3f*) &pfNor1[0],
699 pfPos1, pfPos2, pfPos0,
700 pfTex1, pfTex2, pfTex0);
701
702 PVRTVertexTangentBitangent(
703 &psVtxData[nIdx2].pvTan[psVtxData[nIdx2].n],
704 &psVtxData[nIdx2].pvBin[psVtxData[nIdx2].n],
705 (PVRTVECTOR3f*) &pfNor2[0],
706 pfPos2, pfPos0, pfPos1,
707 pfTex2, pfTex0, pfTex1);
708
709 psVtxData[nIdx0].pnTri[psVtxData[nIdx0].n] = nCurr;
710 psVtxData[nIdx1].pnTri[psVtxData[nIdx1].n] = nCurr;
711 psVtxData[nIdx2].pnTri[psVtxData[nIdx2].n] = nCurr;
712
713 ++psVtxData[nIdx0].n;
714 ++psVtxData[nIdx1].n;
715 ++psVtxData[nIdx2].n;
716 }
717
718 // Now let's go through the vertices calculating avg tangent-spaces; create new vertices if necessary
719 for(nVert = 0; nVert < nVtxNum; ++nVert) {
720 psVtx = &psVtxData[nVert];
721
722 // Start out with no output vertices required for this input vertex
723 nTSpassLen = 0;
724
725 // Run through each desired tangent space for this vertex
726 for(nCurr = 0; nCurr < (unsigned int) psVtx->n; ++nCurr) {
727 // Run through the possible vertices we can share with to see if we match
728 for(i = 0; i < nTSpassLen; ++i) {
729 psCmp = &psTSpass[i];
730
731 // Check all the shared vertices which match
732 for(j = 0; j < (unsigned int) psCmp->n; ++j) {
733 if(PVRTMatrixVec3DotProductF(psVtx->pvTan[nCurr], psCmp->pvTan[j]) < fSplitDifference)
734 break;
735 if(PVRTMatrixVec3DotProductF(psVtx->pvBin[nCurr], psCmp->pvBin[j]) < fSplitDifference)
736 break;
737 }
738
739 // Did all the existing vertices match?
740 if(j == (unsigned int) psCmp->n) {
741 // Yes, so add to list
742 _ASSERT(psCmp->n < cnMaxSharedVtx);
743 psCmp->pvTan[psCmp->n] = psVtx->pvTan[nCurr];
744 psCmp->pvBin[psCmp->n] = psVtx->pvBin[nCurr];
745 psCmp->pnTri[psCmp->n] = psVtx->pnTri[nCurr];
746 ++psCmp->n;
747 break;
748 }
749 }
750
751 if(i == nTSpassLen) {
752 // We never found another matching matrix, so let's add this as a different one
753 _ASSERT(nTSpassLen < cnMaxSharedVtx);
754 psTSpass[nTSpassLen].pvTan[0] = psVtx->pvTan[nCurr];
755 psTSpass[nTSpassLen].pvBin[0] = psVtx->pvBin[nCurr];
756 psTSpass[nTSpassLen].pnTri[0] = psVtx->pnTri[nCurr];
757 psTSpass[nTSpassLen].n = 1;
758 ++nTSpassLen;
759 }
760 }
761
762 // OK, now we have 'nTSpassLen' different desired matrices, so we need to add that many to output
763 _ASSERT(nTSpassLen >= 1);
764 for(nCurr = 0; nCurr < nTSpassLen; ++nCurr) {
765 psVtx = &psTSpass[nCurr];
766
767 memset(&pfPos0, 0, sizeof(pfPos0));
768 memset(&pfPos1, 0, sizeof(pfPos1));
769
770 for(i = 0; i < (unsigned int) psVtx->n; ++i) {
771 // Sum the tangent & bitangents, so we can average them
772 pfPos0[0] += psVtx->pvTan[i].x;
773 pfPos0[1] += psVtx->pvTan[i].y;
774 pfPos0[2] += psVtx->pvTan[i].z;
775
776 pfPos1[0] += psVtx->pvBin[i].x;
777 pfPos1[1] += psVtx->pvBin[i].y;
778 pfPos1[2] += psVtx->pvBin[i].z;
779
780 // Update triangle indices to use this vtx
781 if(pui32Idx[3 * psVtx->pnTri[i] + 0] == nVert) {
782 pui32IdxNew[3 * psVtx->pnTri[i] + 0] = *pnVtxNumOut;
783
784 } else if(pui32Idx[3 * psVtx->pnTri[i] + 1] == nVert) {
785 pui32IdxNew[3 * psVtx->pnTri[i] + 1] = *pnVtxNumOut;
786
787 } else if(pui32Idx[3 * psVtx->pnTri[i] + 2] == nVert) {
788 pui32IdxNew[3 * psVtx->pnTri[i] + 2] = *pnVtxNumOut;
789
790 } else {
791 _ASSERT(0);
792 }
793 }
794
795 PVRTMatrixVec3NormalizeF(*(PVRTVECTOR3f*) &pfPos0[0], *(PVRTVECTOR3f*) &pfPos0[0]);
796 PVRTMatrixVec3NormalizeF(*(PVRTVECTOR3f*) &pfPos1[0], *(PVRTVECTOR3f*) &pfPos1[0]);
797
798 if(*pnVtxNumOut >= MAX_VERTEX_OUT) {
799 _RPT0(_CRT_WARN,"PVRTVertexGenerateTangentSpace() ran out of working space! (Too many split vertices)\n");
800 return PVR_FAIL;
801 }
802
803 memcpy(&(*pVtxOut)[(*pnVtxNumOut) * nStride], &pVtx[nVert*nStride], nStride);
804 PVRTVertexWrite((char*)&(*pVtxOut)[(*pnVtxNumOut) * nStride] + nOffsetTan, eTypeTan, 3, (PVRTVECTOR4f*) &pfPos0[0]);
805 PVRTVertexWrite((char*)&(*pVtxOut)[(*pnVtxNumOut) * nStride] + nOffsetBin, eTypeBin, 3, (PVRTVECTOR4f*) &pfPos1[0]);
806
807 ++*pnVtxNumOut;
808 }
809 }
810
811 FREE(psTSpass);
812 FREE(psVtxData);
813
814 *pVtxOut = (char*)realloc(*pVtxOut, *pnVtxNumOut * nStride);
815 _ASSERT(*pVtxOut);
816
817 memcpy(pui32Idx, pui32IdxNew, nTriNum * 3 * sizeof(*pui32IdxNew));
818 FREE(pui32IdxNew);
819
820 _RPT3(_CRT_WARN, "GenerateTangentSpace(): %d tris, %d vtx in, %d vtx out\n", nTriNum, nVtxNum, *pnVtxNumOut);
821 _ASSERT(*pnVtxNumOut >= nVtxNum);
822
823 return PVR_SUCCESS;
824 }
825
826 /*****************************************************************************
827 End of file (PVRTVertex.cpp)
828 *****************************************************************************/
829
830