2 Copyright (c) Microsoft Corporation
4 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
5 associated documentation files (the "Software"), to deal in the Software without restriction,
6 including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 subject to the following conditions:
10 The above copyright notice and this permission notice shall be included in all copies or substantial
11 portions of the Software.
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
14 NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
15 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
16 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
17 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 #include "tessellator.hpp"
21 // #include <math.h> // ceil
23 //#include <windows.h> // Just used for some commented out debug stat printing.
24 //#include <strsafe.h> // Ditto.
25 #define min(x,y) (x < y ? x : y)
26 #define max(x,y) (x > y ? x : y)
28 //=================================================================================================================================
29 // Some D3D Compliant Float Math (reference rasterizer implements these in RefALU class)
30 //=================================================================================================================================
32 //---------------------------------------------------------------------------------------------------------------------------------
34 //---------------------------------------------------------------------------------------------------------------------------------
37 static const int exponentMask
= 0x7f800000;
38 static const int mantissaMask
= 0x007fffff;
40 return ( ( ( u
& exponentMask
) == exponentMask
) && ( u
& mantissaMask
) ); // NaN
43 //---------------------------------------------------------------------------------------------------------------------------------
45 //---------------------------------------------------------------------------------------------------------------------------------
46 float flush( float a
)
48 static const int minNormalizedFloat
= 0x00800000;
49 static const int signBit
= 0x80000000;
50 static const int signBitComplement
= 0x7fffffff;
51 int b
= (*(int*)&a
) & signBitComplement
; // fabs()
52 if( b
< minNormalizedFloat
) // UINT comparison. NaN/INF do test false here
54 b
= signBit
& (*(int*)&a
);
60 //---------------------------------------------------------------------------------------------------------------------------------
62 //---------------------------------------------------------------------------------------------------------------------------------
63 float fmin( float a
, float b
)
65 float _a
= flush( a
);
66 float _b
= flush( b
);
71 else if( ( _a
== 0 ) && ( _b
== 0 ) )
73 return ( (*(int*)&_a
) & 0x80000000 ) ? a
: b
;
75 return _a
< _b
? a
: b
;
78 //---------------------------------------------------------------------------------------------------------------------------------
80 //---------------------------------------------------------------------------------------------------------------------------------
81 float fmax( float a
, float b
)
83 float _a
= flush( a
);
84 float _b
= flush( b
);
90 else if( ( _a
== 0 ) && ( _b
== 0 ) )
92 return ( (*(int*)&_b
) & 0x80000000 ) ? a
: b
;
94 return _a
>= _b
? a
: b
;
97 //=================================================================================================================================
99 //=================================================================================================================================
101 //-----------------------------------------------------------------------------------------------------------------------------
104 // Convert 32-bit float to 32-bit fixed point integer, using only
105 // integer arithmetic + bitwise operations.
107 // c_uIBits: UINT8 : Width of i (aka. integer bits)
108 // c_uFBits: UINT8 : Width of f (aka. fractional bits)
109 // c_bSigned: bool : Whether the integer bits are a 2's complement signed value
110 // input: float : All values valid.
111 // output: INT32 : At most 24 bits from LSB are meaningful, depending
112 // on the fixed point bit representation chosen (see
113 // below). Extra bits are sign extended from the most
116 //-----------------------------------------------------------------------------------------------------------------------------
118 typedef unsigned char UINT8
;
120 template< const UINT8 c_uIBits
, const UINT8 c_uFBits
, const bool c_bSigned
>
121 INT32
floatToIDotF( const float& input
)
123 // ------------------------------------------------------------------------
124 // output fixed point format
131 // f fractional part of the number, an unsigned
132 // value with _fxpFracBitCount bits (defined below)
136 // i integer part of the number, a 2's complement
137 // value with _fxpIntBitCount bits (defined below)
139 // [sign-extend] MSB of i conditionally replicated
141 // ------------------------------------------------------------------------
142 // Define fixed point bit counts
145 // Commenting out C_ASSERT below to minimise #includes:
146 // C_ASSERT( 2 <= c_uIBits && c_uIBits <= 32 && c_uFBits <= 32 && c_uIBits + c_uFBits <= 32 );
148 // Define most negative and most positive fixed point values
149 const INT32 c_iMinResult
= (c_bSigned
? INT32( -1 ) << (c_uIBits
+ c_uFBits
- 1) : 0);
150 const INT32 c_iMaxResult
= ~c_iMinResult
;
152 // ------------------------------------------------------------------------
153 // constant float properties
154 // ------------------------------------------------------------------------
155 const UINT8 _fltMantissaBitCount
= 23;
156 const UINT8 _fltExponentBitCount
= 8;
157 const INT32 _fltExponentBias
= (INT32( 1 ) << (_fltExponentBitCount
- 1)) - 1;
158 const INT32 _fltHiddenBit
= INT32( 1 ) << _fltMantissaBitCount
;
159 const INT32 _fltMantissaMask
= _fltHiddenBit
- 1;
160 const INT32 _fltExponentMask
= ((INT32( 1 ) << _fltExponentBitCount
) - 1) << _fltMantissaBitCount
;
161 const INT32 _fltSignBit
= INT32( 1 ) << (_fltExponentBitCount
+ _fltMantissaBitCount
);
163 // ------------------------------------------------------------------------
164 // define min and max values as floats (clamp to these bounds)
165 // ------------------------------------------------------------------------
166 INT32 _fxpMaxPosValueFloat
;
167 INT32 _fxpMaxNegValueFloat
;
171 // The maximum positive fixed point value is 2^(i-1) - 2^(-f).
172 // The following constructs the floating point bit pattern for this value,
173 // as long as i >= 2.
174 _fxpMaxPosValueFloat
= (_fltExponentBias
+ c_uIBits
- 1) <<_fltMantissaBitCount
;
175 const INT32 iShift
= _fltMantissaBitCount
+ 2 - c_uIBits
- c_uFBits
;
178 // assert( iShift < 32 );
179 #pragma warning( suppress : 4293 )
180 _fxpMaxPosValueFloat
-= INT32( 1 ) << iShift
;
183 // The maximum negative fixed point value is -2^(i-1).
184 // The following constructs the floating point bit pattern for this value,
185 // as long as i >= 2.
186 // We need this number without the sign bit
187 _fxpMaxNegValueFloat
= (_fltExponentBias
+ c_uIBits
- 1) << _fltMantissaBitCount
;
191 // The maximum positive fixed point value is 2^(i) - 2^(-f).
192 // The following constructs the floating point bit pattern for this value,
193 // as long as i >= 2.
194 _fxpMaxPosValueFloat
= (_fltExponentBias
+ c_uIBits
) <<_fltMantissaBitCount
;
195 const INT32 iShift
= _fltMantissaBitCount
+ 1 - c_uIBits
- c_uFBits
;
198 // assert( iShift < 32 );
199 #pragma warning( suppress : 4293 )
200 _fxpMaxPosValueFloat
-= INT32( 1 ) << iShift
;
203 // The maximum negative fixed point value is 0.
204 _fxpMaxNegValueFloat
= 0;
207 // ------------------------------------------------------------------------
208 // float -> fixed conversion
209 // ------------------------------------------------------------------------
211 // ------------------------------------------------------------------------
212 // examine input float
213 // ------------------------------------------------------------------------
214 INT32 output
= *(INT32
*)&input
;
215 INT32 unbiasedExponent
= ((output
& _fltExponentMask
) >> _fltMantissaBitCount
) - _fltExponentBias
;
216 INT32 isNegative
= output
& _fltSignBit
;
218 // ------------------------------------------------------------------------
220 // ------------------------------------------------------------------------
221 if (unbiasedExponent
== (_fltExponentBias
+ 1) && (output
& _fltMantissaMask
))
226 // ------------------------------------------------------------------------
227 // too large positive
228 // ------------------------------------------------------------------------
229 else if (!isNegative
&& output
>= _fxpMaxPosValueFloat
) // integer compare
231 output
= c_iMaxResult
;
233 // ------------------------------------------------------------------------
234 // too large negative
235 // ------------------------------------------------------------------------
237 else if (isNegative
&& (output
& ~_fltSignBit
) >= _fxpMaxNegValueFloat
)
239 output
= c_iMinResult
;
241 // ------------------------------------------------------------------------
243 // ------------------------------------------------------------------------
244 else if (unbiasedExponent
< -c_uFBits
- 1)
249 // ------------------------------------------------------------------------
251 // ------------------------------------------------------------------------
254 // copy mantissa, add hidden bit
255 output
= (output
& _fltMantissaMask
) | _fltHiddenBit
;
257 INT32 extraBits
= _fltMantissaBitCount
- c_uFBits
- unbiasedExponent
;
260 // 2's complement if negative
263 output
= ~output
+ 1;
266 // From the range checks that led here, it is known that
267 // unbiasedExponent < c_uIBits. So, at most:
268 // (a) unbiasedExponent == c_uIBits - 1.
270 // From compile validation above, it is known that
271 // c_uIBits + c_uFBits <= _fltMantissaBitCount + 1).
273 // (b) _fltMantissaBitCount == _fxtIntBitCount + c_uFBits - 1
275 // Substituting (a) and (b) into extraBits calculation above:
276 // extraBits >= (_fxtIntBitCount + c_uFBits - 1)
277 // - c_uFBits - (c_uIBits - 1)
280 // Thus we only have to worry about shifting right by 0 or more
281 // bits to get the decimal to the right place, and never have
284 INT32 LSB
= 1 << extraBits
; // last bit being kept
285 INT32 extraBitsMask
= LSB
- 1;
286 INT32 half
= LSB
>> 1; // round bias
288 // round to nearest-even at LSB
289 if ((output
& LSB
) || (output
& extraBitsMask
) > half
)
294 // shift off the extra bits (sign extending)
295 output
>>= extraBits
;
299 output
<<= -extraBits
;
301 // 2's complement if negative
304 output
= ~output
+ 1;
310 //-----------------------------------------------------------------------------------------------------------------------------
312 #define FXP_INTEGER_BITS 15
313 #define FXP_FRACTION_BITS 16
314 #define FXP_FRACTION_MASK 0x0000ffff
315 #define FXP_INTEGER_MASK 0x7fff0000
316 #define FXP_THREE (3<<FXP_FRACTION_BITS)
317 #define FXP_ONE (1<<FXP_FRACTION_BITS)
318 #define FXP_ONE_THIRD 0x00005555
319 #define FXP_TWO_THIRDS 0x0000aaaa
320 #define FXP_ONE_HALF 0x00008000
322 #define FXP_MAX_INPUT_TESS_FACTOR_BEFORE_TRIPLE_AVERAGE 0x55540000 // 1/3 of max fixed point number - 1. Numbers less than
323 // or equal to this allows avg. reduction on a tri patch
324 // including rounding.
326 #define FXP_MAX_INPUT_TESS_FACTOR_BEFORE_PAIR_AVERAGE 0x7FFF0000 // 1/2 of max fixed point number - 1. Numbers less than
327 // or equal to this allows avg. reduction on a quad patch
328 // including rounding.
330 static const FXP s_fixedReciprocal
[D3D11_TESSELLATOR_MAX_TESSELLATION_FACTOR
+1] =
332 0xffffffff, // 1/0 is the first entry (unused)
333 0x10000, 0x8000, 0x5555, 0x4000,
334 0x3333, 0x2aab, 0x2492, 0x2000,
335 0x1c72, 0x199a, 0x1746, 0x1555,
336 0x13b1, 0x1249, 0x1111, 0x1000,
337 0xf0f, 0xe39, 0xd79, 0xccd,
338 0xc31, 0xba3, 0xb21, 0xaab,
339 0xa3d, 0x9d9, 0x97b, 0x925,
340 0x8d4, 0x889, 0x842, 0x800,
341 0x7c2, 0x788, 0x750, 0x71c,
342 0x6eb, 0x6bd, 0x690, 0x666,
343 0x63e, 0x618, 0x5f4, 0x5d1,
344 0x5b0, 0x591, 0x572, 0x555,
345 0x539, 0x51f, 0x505, 0x4ec,
346 0x4d5, 0x4be, 0x4a8, 0x492,
347 0x47e, 0x46a, 0x457, 0x444,
348 0x432, 0x421, 0x410, 0x400, // 1/64 is the last entry
351 #define FLOAT_THREE 3.0f
352 #define FLOAT_ONE 1.0f
354 //---------------------------------------------------------------------------------------------------------------------------------
356 //---------------------------------------------------------------------------------------------------------------------------------
357 FXP
floatToFixed(const float& input
)
359 return floatToIDotF
< FXP_INTEGER_BITS
, FXP_FRACTION_BITS
, /*bSigned*/false >( input
);
362 //---------------------------------------------------------------------------------------------------------------------------------
364 //---------------------------------------------------------------------------------------------------------------------------------
365 float fixedToFloat(const FXP
& input
)
367 // not worrying about denorm flushing the float operations (the DX spec behavior for div), since the numbers will not be that small during tessellation.
368 return ((float)(input
>>FXP_FRACTION_BITS
) + (float)(input
&FXP_FRACTION_MASK
)/(1<<FXP_FRACTION_BITS
));
371 //---------------------------------------------------------------------------------------------------------------------------------
373 //---------------------------------------------------------------------------------------------------------------------------------
374 bool isEven(const float& input
)
376 return (((int)input
) & 1) ? false : true;
379 //---------------------------------------------------------------------------------------------------------------------------------
381 //---------------------------------------------------------------------------------------------------------------------------------
382 FXP
fxpCeil(const FXP
& input
)
384 if( input
& FXP_FRACTION_MASK
)
386 return (input
& FXP_INTEGER_MASK
) + FXP_ONE
;
391 //---------------------------------------------------------------------------------------------------------------------------------
393 //---------------------------------------------------------------------------------------------------------------------------------
394 FXP
fxpFloor(const FXP
& input
)
396 return (input
& FXP_INTEGER_MASK
);
399 //=================================================================================================================================
401 //=================================================================================================================================
403 //---------------------------------------------------------------------------------------------------------------------------------
404 // CHWTessellator::CHWTessellator
405 //---------------------------------------------------------------------------------------------------------------------------------
406 CHWTessellator::CHWTessellator()
412 m_bUsingPatchedIndices
= false;
413 m_bUsingPatchedIndices2
= false;
414 #ifdef ALLOW_XBOX_360_COMPARISON
415 m_bXBox360Mode
= false;
418 //---------------------------------------------------------------------------------------------------------------------------------
419 // CHWTessellator::~CHWTessellator
420 //---------------------------------------------------------------------------------------------------------------------------------
421 CHWTessellator::~CHWTessellator()
427 //---------------------------------------------------------------------------------------------------------------------------------
428 // CHWTessellator::Init
430 //---------------------------------------------------------------------------------------------------------------------------------
431 void CHWTessellator::Init(
432 D3D11_TESSELLATOR_PARTITIONING partitioning
,
433 D3D11_TESSELLATOR_OUTPUT_PRIMITIVE outputPrimitive
)
437 m_Point
= new DOMAIN_POINT
[MAX_POINT_COUNT
];
441 m_Index
= new int[MAX_INDEX_COUNT
];
443 m_partitioning
= partitioning
;
444 m_originalPartitioning
= partitioning
;
445 switch( partitioning
)
447 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
450 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
451 m_parity
= TESSELLATOR_PARITY_ODD
;
453 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
454 m_parity
= TESSELLATOR_PARITY_EVEN
;
457 m_originalParity
= m_parity
;
458 m_outputPrimitive
= outputPrimitive
;
462 //---------------------------------------------------------------------------------------------------------------------------------
463 // CHWTessellator::TessellateQuadDomain
465 //---------------------------------------------------------------------------------------------------------------------------------
466 void CHWTessellator::TessellateQuadDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
467 float insideTessFactor_U
, float insideTessFactor_V
)
469 PROCESSED_TESS_FACTORS_QUAD processedTessFactors
;
470 QuadProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Ueq1
,tessFactor_Veq1
,insideTessFactor_U
,insideTessFactor_V
,processedTessFactors
);
472 if( processedTessFactors
.bPatchCulled
)
478 else if( processedTessFactors
.bJustDoMinimumTessFactor
)
480 DefinePoint(/*U*/0,/*V*/0,/*pointStorageOffset*/0);
481 DefinePoint(/*U*/FXP_ONE
,/*V*/0,/*pointStorageOffset*/1);
482 DefinePoint(/*U*/FXP_ONE
,/*V*/FXP_ONE
,/*pointStorageOffset*/2);
483 DefinePoint(/*U*/0,/*V*/FXP_ONE
,/*pointStorageOffset*/3);
486 switch(m_outputPrimitive
)
488 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CW
:
489 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CCW
:
490 // function orients them CCW if needed
491 DefineClockwiseTriangle(0,1,3,/*indexStorageOffset*/0);
492 DefineClockwiseTriangle(1,2,3,/*indexStorageOffset*/3);
495 case D3D11_TESSELLATOR_OUTPUT_POINT
:
498 case D3D11_TESSELLATOR_OUTPUT_LINE
:
499 DumpAllPointsAsInOrderLineList();
505 QuadGeneratePoints(processedTessFactors
);
507 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
512 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_LINE
)
514 DumpAllPointsAsInOrderLineList();
518 QuadGenerateConnectivity(processedTessFactors
); // can be done in parallel to QuadGeneratePoints()
521 //---------------------------------------------------------------------------------------------------------------------------------
522 // CHWTessellator::QuadProcessTessFactors
523 //---------------------------------------------------------------------------------------------------------------------------------
524 void CHWTessellator::QuadProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
525 float insideTessFactor_U
, float insideTessFactor_V
, PROCESSED_TESS_FACTORS_QUAD
& processedTessFactors
)
527 // Is the patch culled?
528 if( !(tessFactor_Ueq0
> 0) || // NaN will pass
529 !(tessFactor_Veq0
> 0) ||
530 !(tessFactor_Ueq1
> 0) ||
531 !(tessFactor_Veq1
> 0) )
533 processedTessFactors
.bPatchCulled
= true;
538 processedTessFactors
.bPatchCulled
= false;
541 // Clamp edge TessFactors
542 float lowerBound
, upperBound
;
543 switch(m_originalPartitioning
)
545 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
546 case D3D11_TESSELLATOR_PARTITIONING_POW2
: // don�t care about pow2 distinction for validation, just treat as integer
547 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
548 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
551 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
552 lowerBound
= D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
;
553 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
556 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
557 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
558 upperBound
= D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
;
562 tessFactor_Ueq0
= fmin( upperBound
, fmax( lowerBound
, tessFactor_Ueq0
) );
563 tessFactor_Veq0
= fmin( upperBound
, fmax( lowerBound
, tessFactor_Veq0
) );
564 tessFactor_Ueq1
= fmin( upperBound
, fmax( lowerBound
, tessFactor_Ueq1
) );
565 tessFactor_Veq1
= fmin( upperBound
, fmax( lowerBound
, tessFactor_Veq1
) );
567 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
569 tessFactor_Ueq0
= ceil(tessFactor_Ueq0
);
570 tessFactor_Veq0
= ceil(tessFactor_Veq0
);
571 tessFactor_Ueq1
= ceil(tessFactor_Ueq1
);
572 tessFactor_Veq1
= ceil(tessFactor_Veq1
);
575 // Clamp inside TessFactors
576 if(D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
== m_originalPartitioning
)
578 #define EPSILON 0.0000152587890625f // 2^(-16), min positive fixed point fraction
579 #define MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON (D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON/2)
580 // If any TessFactor will end up > 1 after floatToFixed conversion later,
581 // then force the inside TessFactors to be > 1 so there is a picture frame.
582 if( (tessFactor_Ueq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
583 (tessFactor_Veq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
584 (tessFactor_Ueq1
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
585 (tessFactor_Veq1
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
586 (insideTessFactor_U
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
587 (insideTessFactor_V
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) )
589 // Force picture frame
590 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
+ EPSILON
;
594 insideTessFactor_U
= fmin( upperBound
, fmax( lowerBound
, insideTessFactor_U
) );
595 insideTessFactor_V
= fmin( upperBound
, fmax( lowerBound
, insideTessFactor_V
) );
596 // Note the above clamps map NaN to lowerBound
599 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
601 insideTessFactor_U
= ceil(insideTessFactor_U
);
602 insideTessFactor_V
= ceil(insideTessFactor_V
);
605 // Reset our vertex and index buffers. We have enough storage for the max tessFactor.
609 // Process tessFactors
610 float outsideTessFactor
[QUAD_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Ueq1
, tessFactor_Veq1
};
611 float insideTessFactor
[QUAD_AXES
] = {insideTessFactor_U
,insideTessFactor_V
};
613 if( HWIntegerPartitioning() )
615 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
617 int edgeEven
= isEven(outsideTessFactor
[edge
]);
618 processedTessFactors
.outsideTessFactorParity
[edge
] = edgeEven
? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
620 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
622 processedTessFactors
.insideTessFactorParity
[axis
] =
623 (isEven(insideTessFactor
[axis
]) || (FLOAT_ONE
== insideTessFactor
[axis
]) )
624 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
629 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
631 processedTessFactors
.outsideTessFactorParity
[edge
] = m_originalParity
;
633 processedTessFactors
.insideTessFactorParity
[U
] = processedTessFactors
.insideTessFactorParity
[V
] = m_originalParity
;
636 // Save fixed point TessFactors
637 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
639 processedTessFactors
.outsideTessFactor
[edge
] = floatToFixed(outsideTessFactor
[edge
]);
641 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
643 processedTessFactors
.insideTessFactor
[axis
] = floatToFixed(insideTessFactor
[axis
]);
646 if( HWIntegerPartitioning() || Odd() )
648 // Special case if all TessFactors are 1
649 if( (FXP_ONE
== processedTessFactors
.insideTessFactor
[U
]) &&
650 (FXP_ONE
== processedTessFactors
.insideTessFactor
[V
]) &&
651 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Ueq0
]) &&
652 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Veq0
]) &&
653 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Ueq1
]) &&
654 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Veq1
]) )
656 processedTessFactors
.bJustDoMinimumTessFactor
= true;
660 processedTessFactors
.bJustDoMinimumTessFactor
= false;
662 // Compute TessFactor-specific metadata
663 for(int edge
= 0; edge
< QUAD_EDGES
; edge
++ )
665 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
666 ComputeTessFactorContext(processedTessFactors
.outsideTessFactor
[edge
], processedTessFactors
.outsideTessFactorCtx
[edge
]);
669 for(int axis
= 0; axis
< QUAD_AXES
; axis
++)
671 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[axis
]);
672 ComputeTessFactorContext(processedTessFactors
.insideTessFactor
[axis
], processedTessFactors
.insideTessFactorCtx
[axis
]);
675 // Compute some initial data.
677 // outside edge offsets and storage
678 for(int edge
= 0; edge
< QUAD_EDGES
; edge
++ )
680 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
681 processedTessFactors
.numPointsForOutsideEdge
[edge
] = NumPointsForTessFactor(processedTessFactors
.outsideTessFactor
[edge
]);
682 m_NumPoints
+= processedTessFactors
.numPointsForOutsideEdge
[edge
];
686 // inside edge offsets
687 for(int axis
= 0; axis
< QUAD_AXES
; axis
++)
689 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[axis
]);
690 processedTessFactors
.numPointsForInsideTessFactor
[axis
] = NumPointsForTessFactor(processedTessFactors
.insideTessFactor
[axis
]);
691 int pointCountMin
= ( TESSELLATOR_PARITY_ODD
== processedTessFactors
.insideTessFactorParity
[axis
] ) ? 4 : 3;
692 // max() allows degenerate transition regions when inside TessFactor == 1
693 processedTessFactors
.numPointsForInsideTessFactor
[axis
] = max(pointCountMin
,processedTessFactors
.numPointsForInsideTessFactor
[axis
]);
696 processedTessFactors
.insideEdgePointBaseOffset
= m_NumPoints
;
698 // inside storage, including interior edges above
699 int numInteriorPoints
= (processedTessFactors
.numPointsForInsideTessFactor
[U
] - 2)*(processedTessFactors
.numPointsForInsideTessFactor
[V
]-2);
700 m_NumPoints
+= numInteriorPoints
;
703 //---------------------------------------------------------------------------------------------------------------------------------
704 // CHWTessellator::QuadGeneratePoints
705 //---------------------------------------------------------------------------------------------------------------------------------
706 void CHWTessellator::QuadGeneratePoints( const PROCESSED_TESS_FACTORS_QUAD
& processedTessFactors
)
708 // Generate exterior ring edge points, clockwise from top-left
711 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
713 int parity
= edge
&0x1;
715 int endPoint
= processedTessFactors
.numPointsForOutsideEdge
[edge
] - 1;
716 for(int p
= startPoint
; p
< endPoint
; p
++,pointOffset
++) // don't include end, since next edge starts with it.
719 int q
= ((edge
==1)||(edge
==2)) ? p
: endPoint
- p
; // reverse order
720 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
721 PlacePointIn1D(processedTessFactors
.outsideTessFactorCtx
[edge
],q
,fxpParam
);
724 DefinePoint(/*U*/fxpParam
,
725 /*V*/(edge
== 3) ? FXP_ONE
: 0,
726 /*pointStorageOffset*/pointOffset
);
730 DefinePoint(/*U*/(edge
== 2) ? FXP_ONE
: 0,
732 /*pointStorageOffset*/pointOffset
);
737 // Generate interior ring points, clockwise from (U==0,V==1) (bottom-left) spiralling toward center
738 static const int startRing
= 1;
739 int minNumPointsForTessFactor
= min(processedTessFactors
.numPointsForInsideTessFactor
[U
],processedTessFactors
.numPointsForInsideTessFactor
[V
]);
740 int numRings
= (minNumPointsForTessFactor
>> 1); // note for even tess we aren't counting center point here.
741 for(int ring
= startRing
; ring
< numRings
; ring
++)
743 int startPoint
= ring
;
744 int endPoint
[QUAD_AXES
] = {processedTessFactors
.numPointsForInsideTessFactor
[U
] - 1 - startPoint
,
745 processedTessFactors
.numPointsForInsideTessFactor
[V
] - 1 - startPoint
};
747 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
749 int parity
[QUAD_AXES
] = {edge
&0x1,((edge
+1)&0x1)};
750 int perpendicularAxisPoint
= (edge
< 2) ? startPoint
: endPoint
[parity
[0]];
752 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[parity
[0]]);
753 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[parity
[0]],perpendicularAxisPoint
,fxpPerpParam
);
754 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[parity
[1]]);
755 for(int p
= startPoint
; p
< endPoint
[parity
[1]]; p
++, pointOffset
++) // don't include end: next edge starts with it.
758 int q
= ((edge
== 1)||(edge
==2)) ? p
: endPoint
[parity
[1]] - (p
- startPoint
);
759 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[parity
[1]],q
,fxpParam
);
762 DefinePoint(/*U*/fxpPerpParam
,
764 /*pointStorageOffset*/pointOffset
);
768 DefinePoint(/*U*/fxpParam
,
770 /*pointStorageOffset*/pointOffset
);
775 // For even tessellation, the inner "ring" is degenerate - a row of points
776 if( (processedTessFactors
.numPointsForInsideTessFactor
[U
] > processedTessFactors
.numPointsForInsideTessFactor
[V
]) &&
777 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
]) )
779 int startPoint
= numRings
;
780 int endPoint
= processedTessFactors
.numPointsForInsideTessFactor
[U
] - 1 - startPoint
;
781 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[U
]);
782 for( int p
= startPoint
; p
<= endPoint
; p
++, pointOffset
++ )
785 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[U
],p
,fxpParam
);
786 DefinePoint(/*U*/fxpParam
,
787 /*V*/FXP_ONE_HALF
, // middle
788 /*pointStorageOffset*/pointOffset
);
791 else if( (processedTessFactors
.numPointsForInsideTessFactor
[V
] >= processedTessFactors
.numPointsForInsideTessFactor
[U
]) &&
792 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[U
]) )
794 int startPoint
= numRings
;
797 endPoint
= processedTessFactors
.numPointsForInsideTessFactor
[V
] - 1 - startPoint
;
798 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[V
]);
799 for( int p
= endPoint
; p
>= startPoint
; p
--, pointOffset
++ )
801 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[V
],p
,fxpParam
);
802 DefinePoint(/*U*/FXP_ONE_HALF
, // middle
804 /*pointStorageOffset*/pointOffset
);
808 //---------------------------------------------------------------------------------------------------------------------------------
809 // CHWTessellator::QuadGenerateConnectivity
810 //---------------------------------------------------------------------------------------------------------------------------------
811 void CHWTessellator::QuadGenerateConnectivity( const PROCESSED_TESS_FACTORS_QUAD
& processedTessFactors
)
813 // Generate primitives for all the concentric rings, one side at a time for each ring
814 static const int startRing
= 1;
815 int numPointRowsToCenter
[QUAD_AXES
] = {((processedTessFactors
.numPointsForInsideTessFactor
[U
]+1) >> 1),
816 ((processedTessFactors
.numPointsForInsideTessFactor
[V
]+1) >> 1)}; // +1 is so even tess includes the center point
817 int numRings
= min(numPointRowsToCenter
[U
],numPointRowsToCenter
[V
]);
818 int degeneratePointRing
[QUAD_AXES
] = { // Even partitioning causes degenerate row of points,
819 // which results in exceptions to the point ordering conventions
820 // when travelling around the rings counterclockwise.
821 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
]) ? numPointRowsToCenter
[V
] - 1 : -1,
822 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[U
]) ? numPointRowsToCenter
[U
] - 1 : -1 };
824 const TESS_FACTOR_CONTEXT
* outsideTessFactorCtx
[QUAD_EDGES
] = {&processedTessFactors
.outsideTessFactorCtx
[Ueq0
],
825 &processedTessFactors
.outsideTessFactorCtx
[Veq0
],
826 &processedTessFactors
.outsideTessFactorCtx
[Ueq1
],
827 &processedTessFactors
.outsideTessFactorCtx
[Veq1
]};
828 TESSELLATOR_PARITY outsideTessFactorParity
[QUAD_EDGES
] = {processedTessFactors
.outsideTessFactorParity
[Ueq0
],
829 processedTessFactors
.outsideTessFactorParity
[Veq0
],
830 processedTessFactors
.outsideTessFactorParity
[Ueq1
],
831 processedTessFactors
.outsideTessFactorParity
[Veq1
]};
832 int numPointsForOutsideEdge
[QUAD_EDGES
] = {processedTessFactors
.numPointsForOutsideEdge
[Ueq0
],
833 processedTessFactors
.numPointsForOutsideEdge
[Veq0
],
834 processedTessFactors
.numPointsForOutsideEdge
[Ueq1
],
835 processedTessFactors
.numPointsForOutsideEdge
[Veq1
]};
837 int insideEdgePointBaseOffset
= processedTessFactors
.insideEdgePointBaseOffset
;
838 int outsideEdgePointBaseOffset
= 0;
840 for(int ring
= startRing
; ring
< numRings
; ring
++)
842 int numPointsForInsideEdge
[QUAD_AXES
] = {processedTessFactors
.numPointsForInsideTessFactor
[U
] - 2*ring
,
843 processedTessFactors
.numPointsForInsideTessFactor
[V
] - 2*ring
};
845 int edge0InsidePointBaseOffset
= insideEdgePointBaseOffset
;
846 int edge0OutsidePointBaseOffset
= outsideEdgePointBaseOffset
;
848 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
850 int parity
= (edge
+1)&0x1;
852 int numTriangles
= numPointsForInsideEdge
[parity
] + numPointsForOutsideEdge
[edge
] - 2;
853 int insideBaseOffset
;
854 int outsideBaseOffset
;
855 if( edge
== 3 ) // We need to patch the indexing so Stitch() can think it sees
856 // 2 sequentially increasing rows of points, even though we have wrapped around
857 // to the end of the inner and outer ring's points, so the last point is really
858 // the first point for the ring.
859 // We make it so that when Stitch() calls AddIndex(), that function
860 // will do any necessary index adjustment.
862 if( ring
== degeneratePointRing
[parity
] )
864 m_IndexPatchContext2
.baseIndexToInvert
= insideEdgePointBaseOffset
+ 1;
865 m_IndexPatchContext2
.cornerCaseBadValue
= outsideEdgePointBaseOffset
+ numPointsForOutsideEdge
[edge
] - 1;
866 m_IndexPatchContext2
.cornerCaseReplacementValue
= edge0OutsidePointBaseOffset
;
867 m_IndexPatchContext2
.indexInversionEndPoint
= (m_IndexPatchContext2
.baseIndexToInvert
<< 1) - 1;
868 insideBaseOffset
= m_IndexPatchContext2
.baseIndexToInvert
;
869 outsideBaseOffset
= outsideEdgePointBaseOffset
;
870 SetUsingPatchedIndices2(true);
874 m_IndexPatchContext
.insidePointIndexDeltaToRealValue
= insideEdgePointBaseOffset
;
875 m_IndexPatchContext
.insidePointIndexBadValue
= numPointsForInsideEdge
[parity
] - 1;
876 m_IndexPatchContext
.insidePointIndexReplacementValue
= edge0InsidePointBaseOffset
;
877 m_IndexPatchContext
.outsidePointIndexPatchBase
= m_IndexPatchContext
.insidePointIndexBadValue
+1; // past inside patched index range
878 m_IndexPatchContext
.outsidePointIndexDeltaToRealValue
= outsideEdgePointBaseOffset
879 - m_IndexPatchContext
.outsidePointIndexPatchBase
;
880 m_IndexPatchContext
.outsidePointIndexBadValue
= m_IndexPatchContext
.outsidePointIndexPatchBase
881 + numPointsForOutsideEdge
[edge
] - 1;
882 m_IndexPatchContext
.outsidePointIndexReplacementValue
= edge0OutsidePointBaseOffset
;
884 insideBaseOffset
= 0;
885 outsideBaseOffset
= m_IndexPatchContext
.outsidePointIndexPatchBase
;
886 SetUsingPatchedIndices(true);
889 else if( (edge
== 2) && (ring
== degeneratePointRing
[parity
]) )
891 m_IndexPatchContext2
.baseIndexToInvert
= insideEdgePointBaseOffset
;
892 m_IndexPatchContext2
.cornerCaseBadValue
= -1; // unused
893 m_IndexPatchContext2
.cornerCaseReplacementValue
= -1; // unused
894 m_IndexPatchContext2
.indexInversionEndPoint
= m_IndexPatchContext2
.baseIndexToInvert
<< 1;
895 insideBaseOffset
= m_IndexPatchContext2
.baseIndexToInvert
;
896 outsideBaseOffset
= outsideEdgePointBaseOffset
;
897 SetUsingPatchedIndices2(true);
901 insideBaseOffset
= insideEdgePointBaseOffset
;
902 outsideBaseOffset
= outsideEdgePointBaseOffset
;
904 if( ring
== startRing
)
906 StitchTransition(/*baseIndexOffset: */m_NumIndices
,
907 insideBaseOffset
,processedTessFactors
.insideTessFactorCtx
[parity
].numHalfTessFactorPoints
,processedTessFactors
.insideTessFactorParity
[parity
],
908 outsideBaseOffset
,outsideTessFactorCtx
[edge
]->numHalfTessFactorPoints
,outsideTessFactorParity
[edge
]);
912 StitchRegular(/*bTrapezoid*/true, DIAGONALS_MIRRORED
,
913 /*baseIndexOffset: */m_NumIndices
,
914 numPointsForInsideEdge
[parity
],
915 insideBaseOffset
,outsideBaseOffset
);
917 SetUsingPatchedIndices(false);
918 SetUsingPatchedIndices2(false);
919 m_NumIndices
+= numTriangles
*3;
920 outsideEdgePointBaseOffset
+= numPointsForOutsideEdge
[edge
] - 1;
921 if( (edge
== 2) && (ring
== degeneratePointRing
[parity
]) )
923 insideEdgePointBaseOffset
-= numPointsForInsideEdge
[parity
] - 1;
927 insideEdgePointBaseOffset
+= numPointsForInsideEdge
[parity
] - 1;
929 numPointsForOutsideEdge
[edge
] = numPointsForInsideEdge
[parity
];
931 if( startRing
== ring
)
933 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
935 outsideTessFactorCtx
[edge
] = &processedTessFactors
.insideTessFactorCtx
[edge
&1];
936 outsideTessFactorParity
[edge
] = processedTessFactors
.insideTessFactorParity
[edge
&1];
941 // Triangulate center - a row of quads if odd
942 // This triangulation may be producing diagonals that are asymmetric about
943 // the center of the patch in this region.
944 if( (processedTessFactors
.numPointsForInsideTessFactor
[U
] > processedTessFactors
.numPointsForInsideTessFactor
[V
]) &&
945 (TESSELLATOR_PARITY_ODD
== processedTessFactors
.insideTessFactorParity
[V
] ) )
947 SetUsingPatchedIndices2(true);
948 int stripNumQuads
= (((processedTessFactors
.numPointsForInsideTessFactor
[U
]>>1) - (processedTessFactors
.numPointsForInsideTessFactor
[V
]>>1))<<1)+
949 ((TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[U
] ) ? 2 : 1);
950 m_IndexPatchContext2
.baseIndexToInvert
= outsideEdgePointBaseOffset
+ stripNumQuads
+ 2;
951 m_IndexPatchContext2
.cornerCaseBadValue
= m_IndexPatchContext2
.baseIndexToInvert
;
952 m_IndexPatchContext2
.cornerCaseReplacementValue
= outsideEdgePointBaseOffset
;
953 m_IndexPatchContext2
.indexInversionEndPoint
= m_IndexPatchContext2
.baseIndexToInvert
+
954 m_IndexPatchContext2
.baseIndexToInvert
+ stripNumQuads
;
955 StitchRegular(/*bTrapezoid*/false,DIAGONALS_INSIDE_TO_OUTSIDE
,
956 /*baseIndexOffset: */m_NumIndices
, /*numInsideEdgePoints:*/stripNumQuads
+1,
957 /*insideEdgePointBaseOffset*/m_IndexPatchContext2
.baseIndexToInvert
,
958 outsideEdgePointBaseOffset
+1);
959 SetUsingPatchedIndices2(false);
960 m_NumIndices
+= stripNumQuads
*6;
962 else if((processedTessFactors
.numPointsForInsideTessFactor
[V
] >= processedTessFactors
.numPointsForInsideTessFactor
[U
]) &&
963 (TESSELLATOR_PARITY_ODD
== processedTessFactors
.insideTessFactorParity
[U
]) )
965 SetUsingPatchedIndices2(true);
966 int stripNumQuads
= (((processedTessFactors
.numPointsForInsideTessFactor
[V
]>>1) - (processedTessFactors
.numPointsForInsideTessFactor
[U
]>>1))<<1)+
967 ((TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
] ) ? 2 : 1);
968 m_IndexPatchContext2
.baseIndexToInvert
= outsideEdgePointBaseOffset
+ stripNumQuads
+ 1;
969 m_IndexPatchContext2
.cornerCaseBadValue
= -1; // unused
970 m_IndexPatchContext2
.indexInversionEndPoint
= m_IndexPatchContext2
.baseIndexToInvert
+
971 m_IndexPatchContext2
.baseIndexToInvert
+ stripNumQuads
;
972 DIAGONALS diag
= (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
]) ?
973 DIAGONALS_INSIDE_TO_OUTSIDE
: DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE
;
974 StitchRegular(/*bTrapezoid*/false,diag
,
975 /*baseIndexOffset: */m_NumIndices
, /*numInsideEdgePoints:*/stripNumQuads
+1,
976 /*insideEdgePointBaseOffset*/m_IndexPatchContext2
.baseIndexToInvert
,
977 outsideEdgePointBaseOffset
);
978 SetUsingPatchedIndices2(false);
979 m_NumIndices
+= stripNumQuads
*6;
983 //---------------------------------------------------------------------------------------------------------------------------------
984 // CHWTessellator::TessellateTriDomain
986 //---------------------------------------------------------------------------------------------------------------------------------
987 void CHWTessellator::TessellateTriDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
988 float insideTessFactor
)
990 PROCESSED_TESS_FACTORS_TRI processedTessFactors
;
991 TriProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Weq0
,insideTessFactor
,processedTessFactors
);
993 if( processedTessFactors
.bPatchCulled
)
999 else if( processedTessFactors
.bJustDoMinimumTessFactor
)
1001 DefinePoint(/*U*/0,/*V*/FXP_ONE
,/*pointStorageOffset*/0); //V=1 (beginning of Ueq0 edge VW)
1002 DefinePoint(/*U*/0,/*V*/0,/*pointStorageOffset*/1); //W=1 (beginning of Veq0 edge WU)
1003 DefinePoint(/*U*/FXP_ONE
,/*V*/0,/*pointStorageOffset*/2); //U=1 (beginning of Weq0 edge UV)
1006 switch(m_outputPrimitive
)
1008 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CW
:
1009 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CCW
:
1010 // function orients them CCW if needed
1011 DefineClockwiseTriangle(0,1,2,/*indexStorageBaseOffset*/m_NumIndices
);
1014 case D3D11_TESSELLATOR_OUTPUT_POINT
:
1017 case D3D11_TESSELLATOR_OUTPUT_LINE
:
1018 DumpAllPointsAsInOrderLineList();
1024 TriGeneratePoints(processedTessFactors
);
1026 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
1031 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_LINE
)
1033 DumpAllPointsAsInOrderLineList();
1037 TriGenerateConnectivity(processedTessFactors
); // can be done in parallel to TriGeneratePoints()
1040 //---------------------------------------------------------------------------------------------------------------------------------
1041 // CHWTessellator::TriProcessTessFactors
1042 //---------------------------------------------------------------------------------------------------------------------------------
1043 void CHWTessellator::TriProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
1044 float insideTessFactor
, PROCESSED_TESS_FACTORS_TRI
& processedTessFactors
)
1046 // Is the patch culled?
1047 if( !(tessFactor_Ueq0
> 0) || // NaN will pass
1048 !(tessFactor_Veq0
> 0) ||
1049 !(tessFactor_Weq0
> 0) )
1051 processedTessFactors
.bPatchCulled
= true;
1056 processedTessFactors
.bPatchCulled
= false;
1059 // Clamp edge TessFactors
1060 float lowerBound
, upperBound
;
1061 switch(m_originalPartitioning
)
1063 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
1064 case D3D11_TESSELLATOR_PARTITIONING_POW2
: // don�t care about pow2 distinction for validation, just treat as integer
1065 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1066 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1069 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
1070 lowerBound
= D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
;
1071 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1074 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
1075 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1076 upperBound
= D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
;
1080 tessFactor_Ueq0
= fmin( upperBound
, fmax( lowerBound
, tessFactor_Ueq0
) );
1081 tessFactor_Veq0
= fmin( upperBound
, fmax( lowerBound
, tessFactor_Veq0
) );
1082 tessFactor_Weq0
= fmin( upperBound
, fmax( lowerBound
, tessFactor_Weq0
) );
1084 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
1086 tessFactor_Ueq0
= ceil(tessFactor_Ueq0
);
1087 tessFactor_Veq0
= ceil(tessFactor_Veq0
);
1088 tessFactor_Weq0
= ceil(tessFactor_Weq0
);
1091 // Clamp inside TessFactors
1092 if(D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
== m_originalPartitioning
)
1094 if( (tessFactor_Ueq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
1095 (tessFactor_Veq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
1096 (tessFactor_Weq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
))
1097 // Don't need the same check for insideTessFactor for tri patches,
1098 // since there is only one insideTessFactor, as opposed to quad
1099 // patches which have 2 insideTessFactors.
1101 // Force picture frame
1102 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
+ EPSILON
;
1106 insideTessFactor
= fmin( upperBound
, fmax( lowerBound
, insideTessFactor
) );
1107 // Note the above clamps map NaN to lowerBound
1109 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
1111 insideTessFactor
= ceil(insideTessFactor
);
1114 // Reset our vertex and index buffers. We have enough storage for the max tessFactor.
1118 // Process tessFactors
1119 float outsideTessFactor
[TRI_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Weq0
};
1121 if( HWIntegerPartitioning() )
1123 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
1125 int edgeEven
= isEven(outsideTessFactor
[edge
]);
1126 processedTessFactors
.outsideTessFactorParity
[edge
] = edgeEven
? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1128 processedTessFactors
.insideTessFactorParity
= (isEven(insideTessFactor
) || (FLOAT_ONE
== insideTessFactor
))
1129 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1133 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
1135 processedTessFactors
.outsideTessFactorParity
[edge
] = m_originalParity
;
1137 processedTessFactors
.insideTessFactorParity
= m_originalParity
;
1140 // Save fixed point TessFactors
1141 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
1143 processedTessFactors
.outsideTessFactor
[edge
] = floatToFixed(outsideTessFactor
[edge
]);
1145 processedTessFactors
.insideTessFactor
= floatToFixed(insideTessFactor
);
1147 if( HWIntegerPartitioning() || Odd() )
1149 // Special case if all TessFactors are 1
1150 if( (FXP_ONE
== processedTessFactors
.insideTessFactor
) &&
1151 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Ueq0
]) &&
1152 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Veq0
]) &&
1153 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Weq0
]) )
1155 processedTessFactors
.bJustDoMinimumTessFactor
= true;
1159 processedTessFactors
.bJustDoMinimumTessFactor
= false;
1161 // Compute per-TessFactor metadata
1162 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1164 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
1165 ComputeTessFactorContext(processedTessFactors
.outsideTessFactor
[edge
], processedTessFactors
.outsideTessFactorCtx
[edge
]);
1167 SetTessellationParity(processedTessFactors
.insideTessFactorParity
);
1168 ComputeTessFactorContext(processedTessFactors
.insideTessFactor
, processedTessFactors
.insideTessFactorCtx
);
1170 // Compute some initial data.
1172 // outside edge offsets and storage
1173 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1175 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
1176 processedTessFactors
.numPointsForOutsideEdge
[edge
] = NumPointsForTessFactor(processedTessFactors
.outsideTessFactor
[edge
]);
1177 m_NumPoints
+= processedTessFactors
.numPointsForOutsideEdge
[edge
];
1181 // inside edge offsets
1182 SetTessellationParity(processedTessFactors
.insideTessFactorParity
);
1183 processedTessFactors
.numPointsForInsideTessFactor
= NumPointsForTessFactor(processedTessFactors
.insideTessFactor
);
1185 int pointCountMin
= Odd() ? 4 : 3;
1186 // max() allows degenerate transition regions when inside TessFactor == 1
1187 processedTessFactors
.numPointsForInsideTessFactor
= max(pointCountMin
,processedTessFactors
.numPointsForInsideTessFactor
);
1190 processedTessFactors
.insideEdgePointBaseOffset
= m_NumPoints
;
1192 // inside storage, including interior edges above
1194 int numInteriorRings
= (processedTessFactors
.numPointsForInsideTessFactor
>> 1) - 1;
1195 int numInteriorPoints
;
1198 numInteriorPoints
= TRI_EDGES
*(numInteriorRings
*(numInteriorRings
+1) - numInteriorRings
);
1202 numInteriorPoints
= TRI_EDGES
*(numInteriorRings
*(numInteriorRings
+1)) + 1;
1204 m_NumPoints
+= numInteriorPoints
;
1209 //---------------------------------------------------------------------------------------------------------------------------------
1210 // CHWTessellator::TriGeneratePoints
1211 //---------------------------------------------------------------------------------------------------------------------------------
1212 void CHWTessellator::TriGeneratePoints( const PROCESSED_TESS_FACTORS_TRI
& processedTessFactors
)
1214 // Generate exterior ring edge points, clockwise starting from point V (VW, the U==0 edge)
1215 int pointOffset
= 0;
1217 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1219 int parity
= edge
&0x1;
1221 int endPoint
= processedTessFactors
.numPointsForOutsideEdge
[edge
] - 1;
1222 for(int p
= startPoint
; p
< endPoint
; p
++, pointOffset
++) // don't include end, since next edge starts with it.
1225 int q
= (parity
) ? p
: endPoint
- p
; // whether to reverse point order given we are defining V or U (W implicit):
1226 // edge0, VW, has V decreasing, so reverse 1D points below
1227 // edge1, WU, has U increasing, so don't reverse 1D points below
1228 // edge2, UV, has U decreasing, so reverse 1D points below
1229 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
1230 PlacePointIn1D(processedTessFactors
.outsideTessFactorCtx
[edge
],q
,fxpParam
);
1235 /*pointStorageOffset*/pointOffset
);
1239 DefinePoint(/*U*/fxpParam
,
1240 /*V*/(edge
== 2) ? FXP_ONE
- fxpParam
: 0,
1241 /*pointStorageOffset*/pointOffset
);
1246 // Generate interior ring points, clockwise spiralling in
1247 SetTessellationParity(processedTessFactors
.insideTessFactorParity
);
1248 static const int startRing
= 1;
1249 int numRings
= (processedTessFactors
.numPointsForInsideTessFactor
>> 1);
1250 for(int ring
= startRing
; ring
< numRings
; ring
++)
1252 int startPoint
= ring
;
1253 int endPoint
= processedTessFactors
.numPointsForInsideTessFactor
- 1 - startPoint
;
1255 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1257 int parity
= edge
&0x1;
1258 int perpendicularAxisPoint
= startPoint
;
1260 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
,perpendicularAxisPoint
,fxpPerpParam
);
1261 fxpPerpParam
*= FXP_TWO_THIRDS
; // Map location to the right size in barycentric space.
1262 // I (amarp) can draw a picture to explain.
1263 // We know this fixed point math won't over/underflow
1264 fxpPerpParam
= (fxpPerpParam
+FXP_ONE_HALF
/*round*/)>>FXP_FRACTION_BITS
; // get back to n.16
1265 for(int p
= startPoint
; p
< endPoint
; p
++, pointOffset
++) // don't include end: next edge starts with it.
1268 int q
= (parity
) ? p
: endPoint
- (p
- startPoint
); // whether to reverse point given we are defining V or U (W implicit):
1269 // edge0, VW, has V decreasing, so reverse 1D points below
1270 // edge1, WU, has U increasing, so don't reverse 1D points below
1271 // edge2, UV, has U decreasing, so reverse 1D points below
1272 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
,q
,fxpParam
);
1273 // edge0 VW, has perpendicular parameter U constant
1274 // edge1 WU, has perpendicular parameter V constant
1275 // edge2 UV, has perpendicular parameter W constant
1276 const unsigned int deriv
= 2; // reciprocal is the rate of change of edge-parallel parameters as they are pushed into the triangle
1280 DefinePoint(/*U*/fxpPerpParam
,
1281 /*V*/fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
, // we know this fixed point math won't over/underflow
1282 /*pointStorageOffset*/pointOffset
);
1285 DefinePoint(/*U*/fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
,// we know this fixed point math won't over/underflow
1287 /*pointStorageOffset*/pointOffset
);
1290 DefinePoint(/*U*/fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
,// we know this fixed point math won't over/underflow
1291 /*V*/FXP_ONE
- (fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
) - fxpPerpParam
,// we know this fixed point math won't over/underflow
1292 /*pointStorageOffset*/pointOffset
);
1300 // Last point is the point at the center.
1301 DefinePoint(/*U*/FXP_ONE_THIRD
,
1303 /*pointStorageOffset*/pointOffset
);
1306 //---------------------------------------------------------------------------------------------------------------------------------
1307 // CHWTessellator::TriGenerateConnectivity
1308 //---------------------------------------------------------------------------------------------------------------------------------
1309 void CHWTessellator::TriGenerateConnectivity( const PROCESSED_TESS_FACTORS_TRI
& processedTessFactors
)
1311 // Generate primitives for all the concentric rings, one side at a time for each ring
1312 static const int startRing
= 1;
1313 int numRings
= ((processedTessFactors
.numPointsForInsideTessFactor
+1) >> 1); // +1 is so even tess includes the center point, which we want to now
1314 const TESS_FACTOR_CONTEXT
* outsideTessFactorCtx
[TRI_EDGES
] = {&processedTessFactors
.outsideTessFactorCtx
[Ueq0
],
1315 &processedTessFactors
.outsideTessFactorCtx
[Veq0
],
1316 &processedTessFactors
.outsideTessFactorCtx
[Weq0
]};
1317 TESSELLATOR_PARITY outsideTessFactorParity
[TRI_EDGES
] = {processedTessFactors
.outsideTessFactorParity
[Ueq0
],
1318 processedTessFactors
.outsideTessFactorParity
[Veq0
],
1319 processedTessFactors
.outsideTessFactorParity
[Weq0
]};
1320 int numPointsForOutsideEdge
[TRI_EDGES
] = {processedTessFactors
.numPointsForOutsideEdge
[Ueq0
],
1321 processedTessFactors
.numPointsForOutsideEdge
[Veq0
],
1322 processedTessFactors
.numPointsForOutsideEdge
[Weq0
]};
1324 int insideEdgePointBaseOffset
= processedTessFactors
.insideEdgePointBaseOffset
;
1325 int outsideEdgePointBaseOffset
= 0;
1327 for(int ring
= startRing
; ring
< numRings
; ring
++)
1329 int numPointsForInsideEdge
= processedTessFactors
.numPointsForInsideTessFactor
- 2*ring
;
1330 int edge0InsidePointBaseOffset
= insideEdgePointBaseOffset
;
1331 int edge0OutsidePointBaseOffset
= outsideEdgePointBaseOffset
;
1332 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1334 int numTriangles
= numPointsForInsideEdge
+ numPointsForOutsideEdge
[edge
] - 2;
1336 int insideBaseOffset
;
1337 int outsideBaseOffset
;
1340 m_IndexPatchContext
.insidePointIndexDeltaToRealValue
= insideEdgePointBaseOffset
;
1341 m_IndexPatchContext
.insidePointIndexBadValue
= numPointsForInsideEdge
- 1;
1342 m_IndexPatchContext
.insidePointIndexReplacementValue
= edge0InsidePointBaseOffset
;
1343 m_IndexPatchContext
.outsidePointIndexPatchBase
= m_IndexPatchContext
.insidePointIndexBadValue
+1; // past inside patched index range
1344 m_IndexPatchContext
.outsidePointIndexDeltaToRealValue
= outsideEdgePointBaseOffset
1345 - m_IndexPatchContext
.outsidePointIndexPatchBase
;
1346 m_IndexPatchContext
.outsidePointIndexBadValue
= m_IndexPatchContext
.outsidePointIndexPatchBase
1347 + numPointsForOutsideEdge
[edge
] - 1;
1348 m_IndexPatchContext
.outsidePointIndexReplacementValue
= edge0OutsidePointBaseOffset
;
1349 SetUsingPatchedIndices(true);
1350 insideBaseOffset
= 0;
1351 outsideBaseOffset
= m_IndexPatchContext
.outsidePointIndexPatchBase
;
1355 insideBaseOffset
= insideEdgePointBaseOffset
;
1356 outsideBaseOffset
= outsideEdgePointBaseOffset
;
1358 if( ring
== startRing
)
1360 StitchTransition(/*baseIndexOffset: */m_NumIndices
,
1361 insideBaseOffset
,processedTessFactors
.insideTessFactorCtx
.numHalfTessFactorPoints
,processedTessFactors
.insideTessFactorParity
,
1362 outsideBaseOffset
,outsideTessFactorCtx
[edge
]->numHalfTessFactorPoints
,outsideTessFactorParity
[edge
]);
1366 StitchRegular(/*bTrapezoid*/true, DIAGONALS_MIRRORED
,
1367 /*baseIndexOffset: */m_NumIndices
,
1368 numPointsForInsideEdge
,
1369 insideBaseOffset
,outsideBaseOffset
);
1373 SetUsingPatchedIndices(false);
1375 m_NumIndices
+= numTriangles
*3;
1376 outsideEdgePointBaseOffset
+= numPointsForOutsideEdge
[edge
] - 1;
1377 insideEdgePointBaseOffset
+= numPointsForInsideEdge
- 1;
1378 numPointsForOutsideEdge
[edge
] = numPointsForInsideEdge
;
1380 if( startRing
== ring
)
1382 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1384 outsideTessFactorCtx
[edge
] = &processedTessFactors
.insideTessFactorCtx
;
1385 outsideTessFactorParity
[edge
] = processedTessFactors
.insideTessFactorParity
;
1391 // Triangulate center (a single triangle)
1392 DefineClockwiseTriangle(outsideEdgePointBaseOffset
, outsideEdgePointBaseOffset
+1, outsideEdgePointBaseOffset
+2,
1398 //---------------------------------------------------------------------------------------------------------------------------------
1399 // CHWTessellator::TessellateIsoLineDomain
1401 //---------------------------------------------------------------------------------------------------------------------------------
1402 void CHWTessellator::TessellateIsoLineDomain( float TessFactor_V_LineDensity
, float TessFactor_U_LineDetail
)
1404 PROCESSED_TESS_FACTORS_ISOLINE processedTessFactors
;
1405 IsoLineProcessTessFactors(TessFactor_V_LineDensity
,TessFactor_U_LineDetail
,processedTessFactors
);
1406 if( processedTessFactors
.bPatchCulled
)
1412 IsoLineGeneratePoints(processedTessFactors
);
1413 IsoLineGenerateConnectivity(processedTessFactors
); // can be done in parallel to IsoLineGeneratePoints
1416 //---------------------------------------------------------------------------------------------------------------------------------
1417 // CHWTessellator::IsoLineProcessTessFactors
1418 //---------------------------------------------------------------------------------------------------------------------------------
1419 void CHWTessellator::IsoLineProcessTessFactors( float TessFactor_V_LineDensity
, float TessFactor_U_LineDetail
,
1420 PROCESSED_TESS_FACTORS_ISOLINE
& processedTessFactors
)
1422 // Is the patch culled?
1423 if( !(TessFactor_V_LineDensity
> 0) || // NaN will pass
1424 !(TessFactor_U_LineDetail
> 0) )
1426 processedTessFactors
.bPatchCulled
= true;
1431 processedTessFactors
.bPatchCulled
= false;
1434 // Clamp edge TessFactors
1435 float lowerBound
, upperBound
;
1436 switch(m_originalPartitioning
)
1438 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
1439 case D3D11_TESSELLATOR_PARTITIONING_POW2
: // don�t care about pow2 distinction for validation, just treat as integer
1440 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1441 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1444 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
1445 lowerBound
= D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
;
1446 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1449 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
1450 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1451 upperBound
= D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
;
1455 TessFactor_V_LineDensity
= fmin( D3D11_TESSELLATOR_MAX_ISOLINE_DENSITY_TESSELLATION_FACTOR
,
1456 fmax( D3D11_TESSELLATOR_MIN_ISOLINE_DENSITY_TESSELLATION_FACTOR
, TessFactor_V_LineDensity
) );
1457 TessFactor_U_LineDetail
= fmin( upperBound
, fmax( lowerBound
, TessFactor_U_LineDetail
) );
1459 // Reset our vertex and index buffers. We have enough storage for the max tessFactor.
1463 // Process tessFactors
1464 if( HWIntegerPartitioning() )
1466 TessFactor_U_LineDetail
= ceil(TessFactor_U_LineDetail
);
1467 processedTessFactors
.lineDetailParity
= isEven(TessFactor_U_LineDetail
) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1471 processedTessFactors
.lineDetailParity
= m_originalParity
;
1474 FXP fxpTessFactor_U_LineDetail
= floatToFixed(TessFactor_U_LineDetail
);
1476 SetTessellationParity(processedTessFactors
.lineDetailParity
);
1478 ComputeTessFactorContext(fxpTessFactor_U_LineDetail
, processedTessFactors
.lineDetailTessFactorCtx
);
1479 processedTessFactors
.numPointsPerLine
= NumPointsForTessFactor(fxpTessFactor_U_LineDetail
);
1481 OverridePartitioning(D3D11_TESSELLATOR_PARTITIONING_INTEGER
);
1483 TessFactor_V_LineDensity
= ceil(TessFactor_V_LineDensity
);
1484 processedTessFactors
.lineDensityParity
= isEven(TessFactor_V_LineDensity
) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1485 SetTessellationParity(processedTessFactors
.lineDensityParity
);
1486 FXP fxpTessFactor_V_LineDensity
= floatToFixed(TessFactor_V_LineDensity
);
1487 ComputeTessFactorContext(fxpTessFactor_V_LineDensity
, processedTessFactors
.lineDensityTessFactorCtx
);
1489 processedTessFactors
.numLines
= NumPointsForTessFactor(fxpTessFactor_V_LineDensity
) - 1; // don't draw last line at V == 1.
1491 RestorePartitioning();
1493 // Compute some initial data.
1495 // outside edge offsets
1496 m_NumPoints
= processedTessFactors
.numPointsPerLine
* processedTessFactors
.numLines
;
1497 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
1499 m_NumIndices
= m_NumPoints
;
1503 m_NumIndices
= processedTessFactors
.numLines
*(processedTessFactors
.numPointsPerLine
-1)*2;
1507 //---------------------------------------------------------------------------------------------------------------------------------
1508 // CHWTessellator::IsoLineGeneratePoints
1509 //---------------------------------------------------------------------------------------------------------------------------------
1510 void CHWTessellator::IsoLineGeneratePoints( const PROCESSED_TESS_FACTORS_ISOLINE
& processedTessFactors
)
1512 int line
, pointOffset
;
1513 for(line
= 0, pointOffset
= 0; line
< processedTessFactors
.numLines
; line
++)
1515 for(int point
= 0; point
< processedTessFactors
.numPointsPerLine
; point
++)
1518 SetTessellationParity(processedTessFactors
.lineDensityParity
);
1519 PlacePointIn1D(processedTessFactors
.lineDensityTessFactorCtx
,line
,fxpV
);
1521 SetTessellationParity(processedTessFactors
.lineDetailParity
);
1522 PlacePointIn1D(processedTessFactors
.lineDetailTessFactorCtx
,point
,fxpU
);
1524 DefinePoint(fxpU
,fxpV
,pointOffset
++);
1529 //---------------------------------------------------------------------------------------------------------------------------------
1530 // CHWTessellator::IsoLineGenerateConnectivity
1531 //---------------------------------------------------------------------------------------------------------------------------------
1532 void CHWTessellator::IsoLineGenerateConnectivity( const PROCESSED_TESS_FACTORS_ISOLINE
& processedTessFactors
)
1534 int line
, pointOffset
, indexOffset
;
1535 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
1537 for(line
= 0, pointOffset
= 0, indexOffset
= 0; line
< processedTessFactors
.numLines
; line
++)
1539 for(int point
= 0; point
< processedTessFactors
.numPointsPerLine
; point
++)
1541 DefineIndex(pointOffset
++,indexOffset
++);
1547 for(line
= 0, pointOffset
= 0, indexOffset
= 0; line
< processedTessFactors
.numLines
; line
++)
1549 for(int point
= 0; point
< processedTessFactors
.numPointsPerLine
; point
++)
1553 DefineIndex(pointOffset
-1,indexOffset
++);
1554 DefineIndex(pointOffset
,indexOffset
++);
1562 //---------------------------------------------------------------------------------------------------------------------------------
1563 // CHWTessellator::GetPointCount
1565 //---------------------------------------------------------------------------------------------------------------------------------
1566 int CHWTessellator::GetPointCount()
1571 //---------------------------------------------------------------------------------------------------------------------------------
1572 // CHWTessellator::GetIndexCount()
1574 //---------------------------------------------------------------------------------------------------------------------------------
1575 int CHWTessellator::GetIndexCount()
1577 return m_NumIndices
;
1580 //---------------------------------------------------------------------------------------------------------------------------------
1581 // CHWTessellator::GetPoints()
1583 //---------------------------------------------------------------------------------------------------------------------------------
1584 DOMAIN_POINT
* CHWTessellator::GetPoints()
1588 //---------------------------------------------------------------------------------------------------------------------------------
1589 // CHWTessellator::GetIndices()
1591 //---------------------------------------------------------------------------------------------------------------------------------
1592 int* CHWTessellator::GetIndices()
1597 //---------------------------------------------------------------------------------------------------------------------------------
1598 // CHWTessellator::DefinePoint()
1599 //---------------------------------------------------------------------------------------------------------------------------------
1600 int CHWTessellator::DefinePoint(FXP fxpU
, FXP fxpV
, int pointStorageOffset
)
1603 // StringCchPrintf(foo,80,L"off:%d, uv=(%f,%f)\n",pointStorageOffset,fixedToFloat(fxpU),fixedToFloat(fxpV));
1604 // OutputDebugString(foo);
1605 m_Point
[pointStorageOffset
].u
= fixedToFloat(fxpU
);
1606 m_Point
[pointStorageOffset
].v
= fixedToFloat(fxpV
);
1607 return pointStorageOffset
;
1610 //---------------------------------------------------------------------------------------------------------------------------------
1611 // CHWTessellator::DefineIndex()
1612 //--------------------------------------------------------------------------------------------------------------------------------
1613 void CHWTessellator::DefineIndex(int index
, int indexStorageOffset
)
1615 index
= PatchIndexValue(index
);
1617 // StringCchPrintf(foo,80,L"off:%d, idx=%d, uv=(%f,%f)\n",indexStorageOffset,index,m_Point[index].u,m_Point[index].v);
1618 // OutputDebugString(foo);
1619 m_Index
[indexStorageOffset
] = index
;
1622 //---------------------------------------------------------------------------------------------------------------------------------
1623 // CHWTessellator::DefineClockwiseTriangle()
1624 //---------------------------------------------------------------------------------------------------------------------------------
1625 void CHWTessellator::DefineClockwiseTriangle(int index0
, int index1
, int index2
, int indexStorageBaseOffset
)
1627 // inputs a clockwise triangle, stores a CW or CCW triangle depending on the state
1628 DefineIndex(index0
,indexStorageBaseOffset
);
1629 bool bWantClockwise
= (m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CW
) ? true : false;
1630 if( bWantClockwise
)
1632 DefineIndex(index1
,indexStorageBaseOffset
+1);
1633 DefineIndex(index2
,indexStorageBaseOffset
+2);
1637 DefineIndex(index2
,indexStorageBaseOffset
+1);
1638 DefineIndex(index1
,indexStorageBaseOffset
+2);
1642 //---------------------------------------------------------------------------------------------------------------------------------
1643 // CHWTessellator::DumpAllPoints()
1644 //---------------------------------------------------------------------------------------------------------------------------------
1645 void CHWTessellator::DumpAllPoints()
1647 for( int p
= 0; p
< m_NumPoints
; p
++ )
1649 DefineIndex(p
,m_NumIndices
++);
1653 //---------------------------------------------------------------------------------------------------------------------------------
1654 // CHWTessellator::DumpAllPointsAsInOrderLineList()
1655 //---------------------------------------------------------------------------------------------------------------------------------
1656 void CHWTessellator::DumpAllPointsAsInOrderLineList()
1658 for( int p
= 1; p
< m_NumPoints
; p
++ )
1660 DefineIndex(p
-1,m_NumIndices
++);
1661 DefineIndex(p
,m_NumIndices
++);
1665 //---------------------------------------------------------------------------------------------------------------------------------
1667 //---------------------------------------------------------------------------------------------------------------------------------
1668 int RemoveMSB(int val
)
1671 if( val
<= 0x0000ffff ) { check
= ( val
<= 0x000000ff ) ? 0x00000080 : 0x00008000; }
1672 else { check
= ( val
<= 0x00ffffff ) ? 0x00800000 : 0x80000000; }
1673 for( int i
= 0; i
< 8; i
++, check
>>= 1 ) { if( val
& check
) return (val
& ~check
); }
1676 //---------------------------------------------------------------------------------------------------------------------------------
1678 //---------------------------------------------------------------------------------------------------------------------------------
1682 if( val
<= 0x0000ffff ) { check
= ( val
<= 0x000000ff ) ? 0x00000080 : 0x00008000; }
1683 else { check
= ( val
<= 0x00ffffff ) ? 0x00800000 : 0x80000000; }
1684 for( int i
= 0; i
< 8; i
++, check
>>= 1 ) { if( val
& check
) return check
; }
1688 //---------------------------------------------------------------------------------------------------------------------------------
1689 // CHWTessellator::CleanseParameter()
1690 //---------------------------------------------------------------------------------------------------------------------------------
1691 /* NOTHING TO DO FOR FIXED POINT ARITHMETIC!
1692 void CHWTessellator::CleanseParameter(float& parameter)
1694 // Clean up [0..1] parameter to guarantee that (1 - (1 - parameter)) == parameter.
1695 parameter = 1.0f - parameter;
1696 parameter = 1.0f - parameter;
1700 //---------------------------------------------------------------------------------------------------------------------------------
1701 // CHWTessellator::NumPointsForTessFactor()
1702 //---------------------------------------------------------------------------------------------------------------------------------
1703 int CHWTessellator::NumPointsForTessFactor( FXP fxpTessFactor
)
1708 numPoints
= (fxpCeil(FXP_ONE_HALF
+ (fxpTessFactor
+1/*round*/)/2)*2)>>FXP_FRACTION_BITS
;
1712 numPoints
= ((fxpCeil((fxpTessFactor
+1/*round*/)/2)*2)>>FXP_FRACTION_BITS
)+1;
1717 //---------------------------------------------------------------------------------------------------------------------------------
1718 // CHWTessellator::ComputeTessFactorContext()
1719 //---------------------------------------------------------------------------------------------------------------------------------
1720 void CHWTessellator::ComputeTessFactorContext( FXP fxpTessFactor
, TESS_FACTOR_CONTEXT
& TessFactorCtx
)
1722 FXP fxpHalfTessFactor
= (fxpTessFactor
+1/*round*/)/2;
1723 if( Odd() || (fxpHalfTessFactor
== FXP_ONE_HALF
)) // fxpHalfTessFactor == 1/2 if TessFactor is 1, but we're pretending we are even.
1725 fxpHalfTessFactor
+= FXP_ONE_HALF
;
1727 FXP fxpFloorHalfTessFactor
= fxpFloor(fxpHalfTessFactor
);
1728 FXP fxpCeilHalfTessFactor
= fxpCeil(fxpHalfTessFactor
);
1729 TessFactorCtx
.fxpHalfTessFactorFraction
= fxpHalfTessFactor
- fxpFloorHalfTessFactor
;
1730 //CleanseParameter(TessFactorCtx.fxpHalfTessFactorFraction);
1731 TessFactorCtx
.numHalfTessFactorPoints
= (fxpCeilHalfTessFactor
>>FXP_FRACTION_BITS
); // for EVEN, we don't include the point always fixed at the midpoint of the TessFactor
1732 if( fxpCeilHalfTessFactor
== fxpFloorHalfTessFactor
)
1734 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= /*pick value to cause this to be ignored*/ TessFactorCtx
.numHalfTessFactorPoints
+1;
1738 if( fxpFloorHalfTessFactor
== FXP_ONE
)
1740 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= 0;
1744 #ifdef ALLOW_XBOX_360_COMPARISON
1745 if( m_bXBox360Mode
)
1746 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= TessFactorCtx
.numHalfTessFactorPoints
-2;
1749 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= (RemoveMSB((fxpFloorHalfTessFactor
>>FXP_FRACTION_BITS
)-1)<<1) + 1;
1754 #ifdef ALLOW_XBOX_360_COMPARISON
1755 if( m_bXBox360Mode
)
1756 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= TessFactorCtx
.numHalfTessFactorPoints
-1;
1759 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= (RemoveMSB(fxpFloorHalfTessFactor
>>FXP_FRACTION_BITS
)<<1) + 1;
1761 int numFloorSegments
= (fxpFloorHalfTessFactor
* 2)>>FXP_FRACTION_BITS
;
1762 int numCeilSegments
= (fxpCeilHalfTessFactor
* 2)>>FXP_FRACTION_BITS
;
1765 numFloorSegments
-= 1;
1766 numCeilSegments
-= 1;
1768 TessFactorCtx
.fxpInvNumSegmentsOnFloorTessFactor
= s_fixedReciprocal
[numFloorSegments
];
1769 TessFactorCtx
.fxpInvNumSegmentsOnCeilTessFactor
= s_fixedReciprocal
[numCeilSegments
];
1772 //---------------------------------------------------------------------------------------------------------------------------------
1773 // CHWTessellator::PlacePointIn1D()
1774 //---------------------------------------------------------------------------------------------------------------------------------
1775 void CHWTessellator::PlacePointIn1D( const TESS_FACTOR_CONTEXT
& TessFactorCtx
, int point
, FXP
& fxpLocation
)
1778 if( point
>= TessFactorCtx
.numHalfTessFactorPoints
)
1780 point
= (TessFactorCtx
.numHalfTessFactorPoints
<< 1) - point
;
1791 if( point
== TessFactorCtx
.numHalfTessFactorPoints
)
1793 fxpLocation
= FXP_ONE_HALF
; // special casing middle since 16 bit fixed math below can't reproduce 0.5 exactly
1796 unsigned int indexOnCeilHalfTessFactor
= point
;
1797 unsigned int indexOnFloorHalfTessFactor
= indexOnCeilHalfTessFactor
;
1798 if( point
> TessFactorCtx
.splitPointOnFloorHalfTessFactor
)
1800 indexOnFloorHalfTessFactor
-= 1;
1802 // For the fixed point multiplies below, we know the results are <= 16 bits because
1803 // the locations on the halfTessFactor are <= half the number of segments for the total TessFactor.
1804 // So a number divided by a number that is at least twice as big will give
1805 // a result no bigger than 0.5 (which in fixed point is 16 bits in our case)
1806 FXP fxpLocationOnFloorHalfTessFactor
= indexOnFloorHalfTessFactor
* TessFactorCtx
.fxpInvNumSegmentsOnFloorTessFactor
;
1807 FXP fxpLocationOnCeilHalfTessFactor
= indexOnCeilHalfTessFactor
* TessFactorCtx
.fxpInvNumSegmentsOnCeilTessFactor
;
1809 // Since we know the numbers calculated above are <= fixed point 0.5, and the equation
1810 // below is just lerping between two values <= fixed point 0.5 (0x00008000), then we know
1811 // that the final result before shifting by 16 bits is no larger than 0x80000000. Once we
1812 // shift that down by 16, we get the result of lerping 2 numbers <= 0.5, which is obviously
1813 // at most 0.5 (0x00008000)
1814 fxpLocation
= fxpLocationOnFloorHalfTessFactor
* (FXP_ONE
- TessFactorCtx
.fxpHalfTessFactorFraction
) +
1815 fxpLocationOnCeilHalfTessFactor
* (TessFactorCtx
.fxpHalfTessFactorFraction
);
1816 fxpLocation
= (fxpLocation
+ FXP_ONE_HALF
/*round*/) >> FXP_FRACTION_BITS
; // get back to n.16
1817 /* Commenting out floating point version. Note the parameter cleansing it does is not needed in fixed point.
1819 location = 1.0f - location; // complement produces cleansed result.
1821 CleanseParameter(location);
1825 fxpLocation
= FXP_ONE
- fxpLocation
;
1829 //---------------------------------------------------------------------------------------------------------------------------------
1830 // CHWTessellator::StitchRegular
1831 //---------------------------------------------------------------------------------------------------------------------------------
1832 void CHWTessellator::StitchRegular(bool bTrapezoid
,DIAGONALS diagonals
,
1833 int baseIndexOffset
, int numInsideEdgePoints
,
1834 int insideEdgePointBaseOffset
, int outsideEdgePointBaseOffset
)
1836 int insidePoint
= insideEdgePointBaseOffset
;
1837 int outsidePoint
= outsideEdgePointBaseOffset
;
1840 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1841 baseIndexOffset
+= 3; outsidePoint
++;
1846 case DIAGONALS_INSIDE_TO_OUTSIDE
:
1847 // Diagonals pointing from inside edge forward towards outside edge
1848 for( p
= 0; p
< numInsideEdgePoints
-1; p
++ )
1850 DefineClockwiseTriangle(insidePoint
,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
1851 baseIndexOffset
+= 3;
1853 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1854 baseIndexOffset
+= 3;
1855 insidePoint
++; outsidePoint
++;
1858 case DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE
: // Assumes ODD tessellation
1859 // Diagonals pointing from outside edge forward towards inside edge
1862 for( p
= 0; p
< numInsideEdgePoints
/2-1; p
++ )
1864 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1865 baseIndexOffset
+= 3;
1866 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1867 baseIndexOffset
+= 3;
1868 insidePoint
++; outsidePoint
++;
1872 DefineClockwiseTriangle(outsidePoint
,insidePoint
+1,insidePoint
,baseIndexOffset
);
1873 baseIndexOffset
+= 3;
1874 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1875 baseIndexOffset
+= 3;
1876 insidePoint
++; outsidePoint
++; p
+=2;
1879 for( ; p
< numInsideEdgePoints
; p
++ )
1881 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1882 baseIndexOffset
+= 3;
1883 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1884 baseIndexOffset
+= 3;
1885 insidePoint
++; outsidePoint
++;
1888 case DIAGONALS_MIRRORED
:
1889 // First half, diagonals pointing from outside of outside edge to inside of inside edge
1890 for( p
= 0; p
< numInsideEdgePoints
/2; p
++ )
1892 DefineClockwiseTriangle(outsidePoint
,insidePoint
+1,insidePoint
,baseIndexOffset
);
1893 baseIndexOffset
+= 3;
1894 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1895 baseIndexOffset
+= 3;
1896 insidePoint
++; outsidePoint
++;
1898 // Second half, diagonals pointing from inside of inside edge to outside of outside edge
1899 for( ; p
< numInsideEdgePoints
-1; p
++ )
1901 DefineClockwiseTriangle(insidePoint
,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
1902 baseIndexOffset
+= 3;
1903 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1904 baseIndexOffset
+= 3;
1905 insidePoint
++; outsidePoint
++;
1911 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1912 baseIndexOffset
+= 3;
1916 //---------------------------------------------------------------------------------------------------------------------------------
1917 // CHWTessellator::StitchTransition()
1918 //---------------------------------------------------------------------------------------------------------------------------------
1919 void CHWTessellator::StitchTransition(int baseIndexOffset
,
1920 int insideEdgePointBaseOffset
, int insideNumHalfTessFactorPoints
,
1921 TESSELLATOR_PARITY insideEdgeTessFactorParity
,
1922 int outsideEdgePointBaseOffset
, int outsideNumHalfTessFactorPoints
,
1923 TESSELLATOR_PARITY outsideTessFactorParity
1927 #ifdef ALLOW_XBOX_360_COMPARISON
1928 // Tables to assist in the stitching of 2 rows of points having arbitrary TessFactors.
1929 // The stitching order is governed by Ruler Function vertex split ordering (see external documentation).
1931 // The contents of the finalPointPositionTable are where vertex i [0..32] ends up on the half-edge
1932 // at the max tessellation amount given ruler-function split order.
1933 // Recall the other half of an edge is mirrored, so we only need to deal with one half.
1934 // This table is used to decide when to advance a point on the interior or exterior.
1935 // It supports odd TessFactor up to 65 and even TessFactor up to 64.
1936 static const int _finalPointPositionTable
[33] =
1937 { 0, 32, 16, 8, 17, 4, 18, 9, 19, 2, 20, 10, 21, 5, 22, 11, 23,
1938 1, 24, 12, 25, 6, 26, 13, 27, 3, 28, 14, 29, 7, 30, 15, 31 };
1939 // The loopStart and loopEnd tables below just provide optimal loop bounds for the
1940 // stitching algorithm further below, for any given halfTssFactor.
1941 // There is probably a better way to encode this...
1943 // loopStart[halfTessFactor] encodes the FIRST entry other that [0] in finalPointPositionTable[] above which is
1944 // less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
1945 static const int _loopStart
[33] =
1946 {1,1,17,9,9,5,5,5,5,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
1947 // loopStart[halfTessFactor] encodes the LAST entry in finalPointPositionTable[] above which is
1948 // less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
1949 static const int _loopEnd
[33] =
1950 {0,0,17,17,25,25,25,25,29,29,29,29,29,29,29,29,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,32};
1951 const int* finalPointPositionTable
;
1952 const int* loopStart
;
1954 if( m_bXBox360Mode
)
1956 // The XBox360 vertex introduction order is always from the center of the edge.
1957 // So the final positions of points on the half-edge are this trivial table.
1958 static const int XBOXfinalPointPositionTable
[33] =
1959 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
1960 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 };
1961 // loopStart and loopEnd (meaning described above) also become trivial for XBox360 splitting.
1962 static const int XBOXloopStart
[33] =
1963 {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
1964 static const int XBOXloopEnd
[33] =
1965 {0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
1967 finalPointPositionTable
= XBOXfinalPointPositionTable
;
1968 loopStart
= XBOXloopStart
;
1969 loopEnd
= XBOXloopEnd
;
1973 finalPointPositionTable
= _finalPointPositionTable
;
1974 loopStart
= _loopStart
;
1978 // Tables to assist in the stitching of 2 rows of points having arbitrary TessFactors.
1979 // The stitching order is governed by Ruler Function vertex split ordering (see external documentation).
1981 // The contents of the finalPointPositionTable are where vertex i [0..33] ends up on the half-edge
1982 // at the max tessellation amount given ruler-function split order.
1983 // Recall the other half of an edge is mirrored, so we only need to deal with one half.
1984 // This table is used to decide when to advance a point on the interior or exterior.
1985 // It supports odd TessFactor up to 65 and even TessFactor up to 64.
1986 static const int finalPointPositionTable
[33] =
1987 { 0, 32, 16, 8, 17, 4, 18, 9, 19, 2, 20, 10, 21, 5, 22, 11, 23,
1988 1, 24, 12, 25, 6, 26, 13, 27, 3, 28, 14, 29, 7, 30, 15, 31 };
1990 // The loopStart and loopEnd tables below just provide optimal loop bounds for the
1991 // stitching algorithm further below, for any given halfTssFactor.
1992 // There is probably a better way to encode this...
1994 // loopStart[halfTessFactor] encodes the FIRST entry in finalPointPositionTable[] above which is
1995 // less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
1996 static const int loopStart
[33] =
1997 {1,1,17,9,9,5,5,5,5,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
1998 // loopStart[halfTessFactor] encodes the LAST entry in finalPointPositionTable[] above which is
1999 // less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
2000 static const int loopEnd
[33] =
2001 {0,0,17,17,25,25,25,25,29,29,29,29,29,29,29,29,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,32};
2003 if( TESSELLATOR_PARITY_ODD
== insideEdgeTessFactorParity
)
2005 insideNumHalfTessFactorPoints
-= 1;
2007 if( TESSELLATOR_PARITY_ODD
== outsideTessFactorParity
)
2009 outsideNumHalfTessFactorPoints
-= 1;
2012 int outsidePoint
= outsideEdgePointBaseOffset
;
2013 int insidePoint
= insideEdgePointBaseOffset
;
2015 // iStart,iEnd are a small optimization so the loop below doesn't have to go from 0 up to 31
2016 int iStart
= min(loopStart
[insideNumHalfTessFactorPoints
],loopStart
[outsideNumHalfTessFactorPoints
]);
2017 int iEnd
= max(loopEnd
[insideNumHalfTessFactorPoints
],loopEnd
[outsideNumHalfTessFactorPoints
]);
2019 if( finalPointPositionTable
[0] < outsideNumHalfTessFactorPoints
) // since we dont' start the loop at 0 below, we need a special case.
2022 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2023 baseIndexOffset
+= 3; outsidePoint
++;
2026 for(int i
= iStart
; i
<= iEnd
; i
++)
2028 if( /*(i>0) && <-- not needed since iStart is never 0*/(finalPointPositionTable
[i
] < insideNumHalfTessFactorPoints
))
2031 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2032 baseIndexOffset
+= 3; insidePoint
++;
2034 if((finalPointPositionTable
[i
] < outsideNumHalfTessFactorPoints
))
2037 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2038 baseIndexOffset
+= 3; outsidePoint
++;
2042 if( (insideEdgeTessFactorParity
!= outsideTessFactorParity
) || (insideEdgeTessFactorParity
== TESSELLATOR_PARITY_ODD
))
2044 if( insideEdgeTessFactorParity
== outsideTessFactorParity
)
2046 // Quad in the middle
2047 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2048 baseIndexOffset
+= 3;
2049 DefineClockwiseTriangle(insidePoint
+1,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
2050 baseIndexOffset
+= 3;
2054 else if( TESSELLATOR_PARITY_EVEN
== insideEdgeTessFactorParity
)
2056 // Triangle pointing inside
2057 DefineClockwiseTriangle(insidePoint
,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
2058 baseIndexOffset
+= 3;
2063 // Triangle pointing outside
2064 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2065 baseIndexOffset
+= 3;
2070 // Walk second half.
2071 for(int i
= iEnd
; i
>= iStart
; i
--)
2073 if((finalPointPositionTable
[i
] < outsideNumHalfTessFactorPoints
))
2076 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2077 baseIndexOffset
+= 3; outsidePoint
++;
2079 if( /*(i>0) && <-- not needed since iStart is never 0*/ (finalPointPositionTable
[i
] < insideNumHalfTessFactorPoints
))
2082 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2083 baseIndexOffset
+= 3; insidePoint
++;
2086 // Below case is not needed if we didn't optimize loop above and made it run from 31 down to 0.
2087 if((finalPointPositionTable
[0] < outsideNumHalfTessFactorPoints
))
2089 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2090 baseIndexOffset
+= 3; outsidePoint
++;
2094 //---------------------------------------------------------------------------------------------------------------------------------
2095 // CHWTessellator::PatchIndexValue()
2096 //--------------------------------------------------------------------------------------------------------------------------------
2097 int CHWTessellator::PatchIndexValue(int index
)
2099 if( m_bUsingPatchedIndices
)
2101 if( index
>= m_IndexPatchContext
.outsidePointIndexPatchBase
) // assumed remapped outide indices are > remapped inside vertices
2103 if( index
== m_IndexPatchContext
.outsidePointIndexBadValue
)
2104 index
= m_IndexPatchContext
.outsidePointIndexReplacementValue
;
2106 index
+= m_IndexPatchContext
.outsidePointIndexDeltaToRealValue
;
2110 if( index
== m_IndexPatchContext
.insidePointIndexBadValue
)
2111 index
= m_IndexPatchContext
.insidePointIndexReplacementValue
;
2113 index
+= m_IndexPatchContext
.insidePointIndexDeltaToRealValue
;
2116 else if( m_bUsingPatchedIndices2
)
2118 if( index
>= m_IndexPatchContext2
.baseIndexToInvert
)
2120 if( index
== m_IndexPatchContext2
.cornerCaseBadValue
)
2122 index
= m_IndexPatchContext2
.cornerCaseReplacementValue
;
2126 index
= m_IndexPatchContext2
.indexInversionEndPoint
- index
;
2129 else if( index
== m_IndexPatchContext2
.cornerCaseBadValue
)
2131 index
= m_IndexPatchContext2
.cornerCaseReplacementValue
;
2138 //=================================================================================================================================
2140 //=================================================================================================================================
2142 //---------------------------------------------------------------------------------------------------------------------------------
2143 // CHLSLTessellator::CHLSLTessellator
2144 //---------------------------------------------------------------------------------------------------------------------------------
2145 CHLSLTessellator::CHLSLTessellator()
2147 m_LastComputedTessFactors
[0] = m_LastComputedTessFactors
[1] = m_LastComputedTessFactors
[2] =
2148 m_LastComputedTessFactors
[3] = m_LastComputedTessFactors
[4] = m_LastComputedTessFactors
[5] = 0;
2151 //---------------------------------------------------------------------------------------------------------------------------------
2152 // CHLSLTessellator::Init
2154 //---------------------------------------------------------------------------------------------------------------------------------
2155 void CHLSLTessellator::Init(
2156 D3D11_TESSELLATOR_PARTITIONING partitioning
,
2157 D3D11_TESSELLATOR_REDUCTION insideTessFactorReduction
,
2158 D3D11_TESSELLATOR_QUAD_REDUCTION_AXIS quadInsideTessFactorReductionAxis
,
2159 D3D11_TESSELLATOR_OUTPUT_PRIMITIVE outputPrimitive
)
2161 CHWTessellator::Init(partitioning
,outputPrimitive
);
2162 m_LastComputedTessFactors
[0] = m_LastComputedTessFactors
[1] = m_LastComputedTessFactors
[2] =
2163 m_LastComputedTessFactors
[3] = m_LastComputedTessFactors
[4] = m_LastComputedTessFactors
[5] = 0;
2164 m_partitioning
= partitioning
;
2165 m_originalPartitioning
= partitioning
;
2166 switch( partitioning
)
2168 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
2171 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
2172 m_parity
= TESSELLATOR_PARITY_ODD
;
2174 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
2175 m_parity
= TESSELLATOR_PARITY_EVEN
;
2178 m_originalParity
= m_parity
;
2179 m_outputPrimitive
= outputPrimitive
;
2180 m_insideTessFactorReduction
= insideTessFactorReduction
;
2181 m_quadInsideTessFactorReductionAxis
= quadInsideTessFactorReductionAxis
;
2183 //---------------------------------------------------------------------------------------------------------------------------------
2184 // CHLSLTessellator::TessellateQuadDomain
2186 //---------------------------------------------------------------------------------------------------------------------------------
2187 void CHLSLTessellator::TessellateQuadDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
2188 float insideTessFactorScaleU
, float insideTessFactorScaleV
)
2190 QuadHLSLProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Ueq1
,tessFactor_Veq1
,insideTessFactorScaleU
,insideTessFactorScaleV
);
2192 CHWTessellator::TessellateQuadDomain(m_LastComputedTessFactors
[0],m_LastComputedTessFactors
[1],m_LastComputedTessFactors
[2],m_LastComputedTessFactors
[3],
2193 m_LastComputedTessFactors
[4],m_LastComputedTessFactors
[5]);
2196 //---------------------------------------------------------------------------------------------------------------------------------
2197 // CHLSLTessellator::QuadHLSLProcessTessFactors
2198 //---------------------------------------------------------------------------------------------------------------------------------
2199 void CHLSLTessellator::QuadHLSLProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
2200 float insideTessFactorScaleU
, float insideTessFactorScaleV
)
2202 if( !(tessFactor_Ueq0
> 0) ||// NaN will pass
2203 !(tessFactor_Veq0
> 0) ||
2204 !(tessFactor_Ueq1
> 0) ||
2205 !(tessFactor_Veq1
> 0) )
2207 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2208 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2209 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Ueq1
;
2210 m_LastUnRoundedComputedTessFactors
[3] = tessFactor_Veq1
;
2211 m_LastUnRoundedComputedTessFactors
[4] = 0;
2212 m_LastUnRoundedComputedTessFactors
[5] = 0;
2213 m_LastComputedTessFactors
[0] =
2214 m_LastComputedTessFactors
[1] =
2215 m_LastComputedTessFactors
[2] =
2216 m_LastComputedTessFactors
[3] =
2217 m_LastComputedTessFactors
[4] =
2218 m_LastComputedTessFactors
[5] = 0;
2222 CleanupFloatTessFactor(tessFactor_Ueq0
);// clamp to [1.0f..INF], NaN->1.0f
2223 CleanupFloatTessFactor(tessFactor_Veq0
);
2224 CleanupFloatTessFactor(tessFactor_Ueq1
);
2225 CleanupFloatTessFactor(tessFactor_Veq1
);
2227 // Save off tessFactors so they can be returned to app
2228 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2229 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2230 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Ueq1
;
2231 m_LastUnRoundedComputedTessFactors
[3] = tessFactor_Veq1
;
2233 // Process outside tessFactors
2234 float outsideTessFactor
[QUAD_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Ueq1
, tessFactor_Veq1
};
2236 TESSELLATOR_PARITY insideTessFactorParity
[QUAD_AXES
], outsideTessFactorParity
[QUAD_EDGES
];
2237 if( Pow2Partitioning() || IntegerPartitioning() )
2239 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
2241 RoundUpTessFactor(outsideTessFactor
[edge
]);
2242 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2243 int edgeEven
= isEven(outsideTessFactor
[edge
]);
2244 outsideTessFactorParity
[edge
] = edgeEven
? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2249 SetTessellationParity(m_originalParity
); // ClampTessFactor needs it
2250 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
2252 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2253 outsideTessFactorParity
[edge
] = m_originalParity
;
2257 // Compute inside TessFactors
2258 float insideTessFactor
[QUAD_AXES
];
2259 if( m_quadInsideTessFactorReductionAxis
== D3D11_TESSELLATOR_QUAD_REDUCTION_1_AXIS
)
2261 switch( m_insideTessFactorReduction
)
2263 case D3D11_TESSELLATOR_REDUCTION_MIN
:
2264 insideTessFactor
[U
] = fmin(fmin(tessFactor_Veq0
,tessFactor_Veq1
),fmin(tessFactor_Ueq0
,tessFactor_Ueq1
));
2266 case D3D11_TESSELLATOR_REDUCTION_MAX
:
2267 insideTessFactor
[U
] = fmax(fmax(tessFactor_Veq0
,tessFactor_Veq1
),fmax(tessFactor_Ueq0
,tessFactor_Ueq1
));
2269 case D3D11_TESSELLATOR_REDUCTION_AVERAGE
:
2270 insideTessFactor
[U
] = (tessFactor_Veq0
+ tessFactor_Veq1
+ tessFactor_Ueq0
+ tessFactor_Ueq1
) / 4;
2273 // Scale inside tessFactor based on user scale factor.
2275 ClampFloatTessFactorScale(insideTessFactorScaleU
); // clamp scale value to [0..1], NaN->0
2276 insideTessFactor
[U
] = insideTessFactor
[U
]*insideTessFactorScaleU
;
2278 // Compute inside parity
2279 if( Pow2Partitioning() || IntegerPartitioning() )
2281 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction + scale result that is based on unbounded user input
2282 m_LastUnRoundedComputedTessFactors
[4] = m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2283 RoundUpTessFactor(insideTessFactor
[U
]);
2284 insideTessFactorParity
[U
] =
2285 insideTessFactorParity
[V
] =
2286 (isEven(insideTessFactor
[U
]) || (FLOAT_ONE
== insideTessFactor
[U
]) )
2287 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2291 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction + scale result that is based on unbounded user input
2292 m_LastUnRoundedComputedTessFactors
[4] = m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2293 // no parity changes for fractional tessellation - just use what the user requested
2294 insideTessFactorParity
[U
] = insideTessFactorParity
[V
] = m_originalParity
;
2297 // To prevent snapping on edges, the "picture frame" comes
2298 // in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2299 if( (TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[U
]) &&
2300 (insideTessFactor
[U
] < FLOAT_THREE
) )
2302 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2304 insideTessFactor
[U
] = fmin(FLOAT_THREE
,fmax(fmax(tessFactor_Veq0
,tessFactor_Veq1
),fmax(tessFactor_Ueq0
,tessFactor_Ueq1
)));
2308 insideTessFactor
[U
] = fmin(FLOAT_THREE
,(tessFactor_Veq0
+ tessFactor_Veq1
+ tessFactor_Ueq0
+ tessFactor_Ueq1
) / 4);
2310 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction result that is based on unbounded user input
2311 m_LastUnRoundedComputedTessFactors
[4] = m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2312 if( IntegerPartitioning())
2314 RoundUpTessFactor(insideTessFactor
[U
]);
2315 insideTessFactorParity
[U
] =
2316 insideTessFactorParity
[V
] = isEven(insideTessFactor
[U
]) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2319 insideTessFactor
[V
] = insideTessFactor
[U
];
2323 switch( m_insideTessFactorReduction
)
2325 case D3D11_TESSELLATOR_REDUCTION_MIN
:
2326 insideTessFactor
[U
] = fmin(tessFactor_Veq0
,tessFactor_Veq1
);
2327 insideTessFactor
[V
] = fmin(tessFactor_Ueq0
,tessFactor_Ueq1
);
2329 case D3D11_TESSELLATOR_REDUCTION_MAX
:
2330 insideTessFactor
[U
] = fmax(tessFactor_Veq0
,tessFactor_Veq1
);
2331 insideTessFactor
[V
] = fmax(tessFactor_Ueq0
,tessFactor_Ueq1
);
2333 case D3D11_TESSELLATOR_REDUCTION_AVERAGE
:
2334 insideTessFactor
[U
] = (tessFactor_Veq0
+ tessFactor_Veq1
) / 2;
2335 insideTessFactor
[V
] = (tessFactor_Ueq0
+ tessFactor_Ueq1
) / 2;
2338 // Scale inside tessFactors based on user scale factor.
2340 ClampFloatTessFactorScale(insideTessFactorScaleU
); // clamp scale value to [0..1], NaN->0
2341 ClampFloatTessFactorScale(insideTessFactorScaleV
);
2342 insideTessFactor
[U
] = insideTessFactor
[U
]*insideTessFactorScaleU
;
2343 insideTessFactor
[V
] = insideTessFactor
[V
]*insideTessFactorScaleV
;
2345 // Compute inside parity
2346 if( Pow2Partitioning() || IntegerPartitioning() )
2348 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
2350 ClampTessFactor(insideTessFactor
[axis
]); // clamp reduction + scale result that is based on unbounded user input
2351 m_LastUnRoundedComputedTessFactors
[4+axis
] = insideTessFactor
[axis
]; // Save off TessFactors so they can be returned to app
2352 RoundUpTessFactor(insideTessFactor
[axis
]);
2353 insideTessFactorParity
[axis
] =
2354 (isEven(insideTessFactor
[axis
]) || (FLOAT_ONE
== insideTessFactor
[axis
]) )
2355 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2360 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction + scale result that is based on unbounded user input
2361 ClampTessFactor(insideTessFactor
[V
]); // clamp reduction + scale result that is based on unbounded user input
2362 m_LastUnRoundedComputedTessFactors
[4] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2363 m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[V
]; // Save off TessFactors so they can be returned to app
2364 // no parity changes for fractional tessellation - just use what the user requested
2365 insideTessFactorParity
[U
] = insideTessFactorParity
[V
] = m_originalParity
;
2368 // To prevent snapping on edges, the "picture frame" comes
2369 // in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2370 if( (TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[U
]) &&
2371 (insideTessFactor
[U
] < FLOAT_THREE
) )
2373 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2375 insideTessFactor
[U
] = fmin(FLOAT_THREE
,fmax(tessFactor_Veq0
,tessFactor_Veq1
));
2379 insideTessFactor
[U
] = fmin(FLOAT_THREE
,(tessFactor_Veq0
+ tessFactor_Veq1
) / 2);
2381 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction result that is based on unbounded user input
2382 m_LastUnRoundedComputedTessFactors
[4] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2383 if( IntegerPartitioning())
2385 RoundUpTessFactor(insideTessFactor
[U
]);
2386 insideTessFactorParity
[U
] = isEven(insideTessFactor
[U
]) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2390 if( (TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[V
]) &&
2391 (insideTessFactor
[V
] < FLOAT_THREE
) )
2393 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2395 insideTessFactor
[V
] = fmin(FLOAT_THREE
,fmax(tessFactor_Ueq0
,tessFactor_Ueq1
));
2399 insideTessFactor
[V
] = fmin(FLOAT_THREE
,(tessFactor_Ueq0
+ tessFactor_Ueq1
) / 2);
2401 ClampTessFactor(insideTessFactor
[V
]);// clamp reduction result that is based on unbounded user input
2402 m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[V
]; // Save off TessFactors so they can be returned to app
2403 if( IntegerPartitioning())
2405 RoundUpTessFactor(insideTessFactor
[V
]);
2406 insideTessFactorParity
[V
] = isEven(insideTessFactor
[V
]) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2410 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
2412 if( TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[axis
] )
2414 // Ensure the first ring ("picture frame") interpolates in on all sides
2415 // as much as the side with the minimum TessFactor. Prevents snapping to edge.
2416 if( (insideTessFactor
[axis
] < FLOAT_THREE
) && (insideTessFactor
[axis
] < insideTessFactor
[(axis
+1)&0x1]))
2418 insideTessFactor
[axis
] = fmin(insideTessFactor
[(axis
+1)&0x1],FLOAT_THREE
);
2419 m_LastUnRoundedComputedTessFactors
[4+axis
] = insideTessFactor
[axis
]; // Save off TessFactors so they can be returned to app
2425 // Save off TessFactors so they can be returned to app
2426 m_LastComputedTessFactors
[0] = outsideTessFactor
[Ueq0
];
2427 m_LastComputedTessFactors
[1] = outsideTessFactor
[Veq0
];
2428 m_LastComputedTessFactors
[2] = outsideTessFactor
[Ueq1
];
2429 m_LastComputedTessFactors
[3] = outsideTessFactor
[Veq1
];
2430 m_LastComputedTessFactors
[4] = insideTessFactor
[U
];
2431 m_LastComputedTessFactors
[5] = insideTessFactor
[V
];
2434 //---------------------------------------------------------------------------------------------------------------------------------
2435 // CHLSLTessellator::TessellateTriDomain
2437 //---------------------------------------------------------------------------------------------------------------------------------
2438 void CHLSLTessellator::TessellateTriDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
2439 float insideTessFactorScale
)
2441 TriHLSLProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Weq0
,insideTessFactorScale
);
2443 CHWTessellator::TessellateTriDomain(m_LastComputedTessFactors
[0],m_LastComputedTessFactors
[1],m_LastComputedTessFactors
[2],m_LastComputedTessFactors
[3]);
2446 //---------------------------------------------------------------------------------------------------------------------------------
2447 // CHLSLTessellator::TriHLSLProcessTessFactors
2448 //---------------------------------------------------------------------------------------------------------------------------------
2449 void CHLSLTessellator::TriHLSLProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
2450 float insideTessFactorScale
)
2452 if( !(tessFactor_Ueq0
> 0) || // NaN will pass
2453 !(tessFactor_Veq0
> 0) ||
2454 !(tessFactor_Weq0
> 0) )
2456 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2457 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2458 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Weq0
;
2459 m_LastUnRoundedComputedTessFactors
[3] =
2460 m_LastComputedTessFactors
[0] =
2461 m_LastComputedTessFactors
[1] =
2462 m_LastComputedTessFactors
[2] =
2463 m_LastComputedTessFactors
[3] = 0;
2467 CleanupFloatTessFactor(tessFactor_Ueq0
); // clamp to [1.0f..INF], NaN->1.0f
2468 CleanupFloatTessFactor(tessFactor_Veq0
);
2469 CleanupFloatTessFactor(tessFactor_Weq0
);
2471 // Save off TessFactors so they can be returned to app
2472 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2473 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2474 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Weq0
;
2476 // Process outside TessFactors
2477 float outsideTessFactor
[TRI_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Weq0
};
2479 if( Pow2Partitioning() || IntegerPartitioning() )
2481 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
2483 RoundUpTessFactor(outsideTessFactor
[edge
]); // for pow2 this rounds to pow2
2484 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2489 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
2491 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2495 // Compute inside TessFactor
2496 float insideTessFactor
;
2497 switch( m_insideTessFactorReduction
)
2499 case D3D11_TESSELLATOR_REDUCTION_MIN
:
2500 insideTessFactor
= fmin(fmin(tessFactor_Ueq0
,tessFactor_Veq0
),tessFactor_Weq0
);
2502 case D3D11_TESSELLATOR_REDUCTION_MAX
:
2503 insideTessFactor
= fmax(fmax(tessFactor_Ueq0
,tessFactor_Veq0
),tessFactor_Weq0
);
2505 case D3D11_TESSELLATOR_REDUCTION_AVERAGE
:
2506 insideTessFactor
= (tessFactor_Ueq0
+ tessFactor_Veq0
+ tessFactor_Weq0
) / 3;
2510 // Scale inside TessFactor based on user scale factor.
2511 ClampFloatTessFactorScale(insideTessFactorScale
); // clamp scale value to [0..1], NaN->0
2512 insideTessFactor
= insideTessFactor
*fmin(FLOAT_ONE
,insideTessFactorScale
);
2514 ClampTessFactor(insideTessFactor
); // clamp reduction + scale result that is based on unbounded user input
2515 m_LastUnRoundedComputedTessFactors
[3] = insideTessFactor
;// Save off TessFactors so they can be returned to app
2516 TESSELLATOR_PARITY parity
;
2517 if( Pow2Partitioning() || IntegerPartitioning() )
2519 RoundUpTessFactor(insideTessFactor
);
2520 parity
= (isEven(insideTessFactor
) || (FLOAT_ONE
== insideTessFactor
))
2521 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2525 parity
= m_originalParity
;
2528 if( (TESSELLATOR_PARITY_ODD
== parity
) &&
2529 (insideTessFactor
< FLOAT_THREE
))
2531 // To prevent snapping on edges, the "picture frame" comes
2532 // in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2533 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2535 insideTessFactor
= fmin(FLOAT_THREE
,fmax(tessFactor_Ueq0
,fmax(tessFactor_Veq0
,tessFactor_Weq0
)));
2539 insideTessFactor
= fmin(FLOAT_THREE
,(tessFactor_Ueq0
+ tessFactor_Veq0
+ tessFactor_Weq0
) / 3);
2541 ClampTessFactor(insideTessFactor
); // clamp reduction result that is based on unbounded user input
2542 m_LastUnRoundedComputedTessFactors
[3] = insideTessFactor
;// Save off TessFactors so they can be returned to app
2543 if( IntegerPartitioning())
2545 RoundUpTessFactor(insideTessFactor
);
2549 // Save off TessFactors so they can be returned to app
2550 m_LastComputedTessFactors
[0] = outsideTessFactor
[Ueq0
];
2551 m_LastComputedTessFactors
[1] = outsideTessFactor
[Veq0
];
2552 m_LastComputedTessFactors
[2] = outsideTessFactor
[Weq0
];
2553 m_LastComputedTessFactors
[3] = insideTessFactor
;
2556 //---------------------------------------------------------------------------------------------------------------------------------
2557 // CHLSLTessellator::TessellateIsoLineDomain
2559 //---------------------------------------------------------------------------------------------------------------------------------
2560 void CHLSLTessellator::TessellateIsoLineDomain( float TessFactor_U_LineDetail
, float TessFactor_V_LineDensity
)
2562 IsoLineHLSLProcessTessFactors(TessFactor_V_LineDensity
,TessFactor_U_LineDetail
);
2563 CHWTessellator::TessellateIsoLineDomain(m_LastComputedTessFactors
[0],m_LastComputedTessFactors
[1]);
2566 //---------------------------------------------------------------------------------------------------------------------------------
2567 // CHLSLTessellator::IsoLineHLSLProcessTessFactors
2568 //---------------------------------------------------------------------------------------------------------------------------------
2569 void CHLSLTessellator::IsoLineHLSLProcessTessFactors( float TessFactor_V_LineDensity
, float TessFactor_U_LineDetail
)
2571 if( !(TessFactor_V_LineDensity
> 0) || // NaN will pass
2572 !(TessFactor_U_LineDetail
> 0) )
2574 m_LastUnRoundedComputedTessFactors
[0] = TessFactor_V_LineDensity
;
2575 m_LastUnRoundedComputedTessFactors
[1] = TessFactor_U_LineDetail
;
2576 m_LastComputedTessFactors
[0] =
2577 m_LastComputedTessFactors
[1] = 0;
2581 CleanupFloatTessFactor(TessFactor_V_LineDensity
); // clamp to [1.0f..INF], NaN->1.0f
2582 CleanupFloatTessFactor(TessFactor_U_LineDetail
); // clamp to [1.0f..INF], NaN->1.0f
2584 ClampTessFactor(TessFactor_U_LineDetail
); // clamp unbounded user input based on tessellation mode
2586 m_LastUnRoundedComputedTessFactors
[1] = TessFactor_U_LineDetail
; // Save off TessFactors so they can be returned to app
2588 TESSELLATOR_PARITY parity
;
2589 if(Pow2Partitioning()||IntegerPartitioning())
2591 RoundUpTessFactor(TessFactor_U_LineDetail
);
2592 parity
= isEven(TessFactor_U_LineDetail
) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2596 parity
= m_originalParity
;
2599 FXP fxpTessFactor_U_LineDetail
= floatToFixed(TessFactor_U_LineDetail
);
2601 OverridePartitioning(D3D11_TESSELLATOR_PARTITIONING_INTEGER
);
2603 ClampTessFactor(TessFactor_V_LineDensity
); // Clamp unbounded user input to integer
2604 m_LastUnRoundedComputedTessFactors
[0] = TessFactor_V_LineDensity
; // Save off TessFactors so they can be returned to app
2606 RoundUpTessFactor(TessFactor_V_LineDensity
);
2608 RestorePartitioning();
2610 // Save off TessFactors so they can be returned to app
2611 m_LastComputedTessFactors
[0] = TessFactor_V_LineDensity
;
2612 m_LastComputedTessFactors
[1] = TessFactor_U_LineDetail
;
2615 //---------------------------------------------------------------------------------------------------------------------------------
2616 // CHLSLTessellator::ClampTessFactor()
2617 //---------------------------------------------------------------------------------------------------------------------------------
2618 void CHLSLTessellator::ClampTessFactor(float& TessFactor
)
2620 if( Pow2Partitioning() )
2622 TessFactor
= fmin( D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
, fmax( TessFactor
, D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
) );
2624 else if( IntegerPartitioning() )
2626 TessFactor
= fmin( D3D11_TESSELLATOR_MAX_TESSELLATION_FACTOR
, fmax( TessFactor
, D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
) );
2630 TessFactor
= fmin( D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
, fmax( TessFactor
, D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
) );
2634 TessFactor
= fmin( D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
, fmax( TessFactor
, D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
) );
2638 //---------------------------------------------------------------------------------------------------------------------------------
2639 // CHLSLTessellator::CleanupFloatTessFactor()
2640 //---------------------------------------------------------------------------------------------------------------------------------
2641 static const int exponentMask
= 0x7f800000;
2642 static const int mantissaMask
= 0x007fffff;
2643 void CHLSLTessellator::CleanupFloatTessFactor(float& input
)
2645 // If input is < 1.0f or NaN, clamp to 1.0f.
2646 // In other words, clamp input to [1.0f...+INF]
2647 int bits
= *(int*)&input
;
2648 if( ( ( ( bits
& exponentMask
) == exponentMask
) && ( bits
& mantissaMask
) ) ||// nan?
2655 //---------------------------------------------------------------------------------------------------------------------------------
2656 // CHLSLTessellator::ClampFloatTessFactorScale()
2657 //---------------------------------------------------------------------------------------------------------------------------------
2658 void CHLSLTessellator::ClampFloatTessFactorScale(float& input
)
2660 // If input is < 0.0f or NaN, clamp to 0.0f. > 1 clamps to 1.
2661 // In other words, clamp input to [0.0f...1.0f]
2662 int bits
= *(int*)&input
;
2663 if( ( ( ( bits
& exponentMask
) == exponentMask
) && ( bits
& mantissaMask
) ) ||// nan?
2668 else if( input
> 1 )
2674 //---------------------------------------------------------------------------------------------------------------------------------
2675 // CHLSLTessellator::RoundUpTessFactor()
2676 //---------------------------------------------------------------------------------------------------------------------------------
2677 static const int exponentLSB
= 0x00800000;
2678 void CHLSLTessellator::RoundUpTessFactor(float& TessFactor
)
2680 // Assume TessFactor is in [1.0f..+INF]
2681 if( Pow2Partitioning() )
2683 int bits
= *(int*)&TessFactor
;
2684 if( bits
& mantissaMask
)
2686 *(int*)&TessFactor
= (bits
& exponentMask
) + exponentLSB
;
2689 else if( IntegerPartitioning() )
2691 TessFactor
= ceil(TessFactor
);