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 #if defined(__MINGW32__) || defined(__MINGW64__)
23 #elif defined(_WIN32) || defined(_WIN64)
24 #include <math.h> // ceil
28 //#include <windows.h> // Just used for some commented out debug stat printing.
29 //#include <strsafe.h> // Ditto.
30 #define min(x,y) (x < y ? x : y)
31 #define max(x,y) (x > y ? x : y)
33 //=================================================================================================================================
34 // Some D3D Compliant Float Math (reference rasterizer implements these in RefALU class)
35 //=================================================================================================================================
37 //---------------------------------------------------------------------------------------------------------------------------------
39 //---------------------------------------------------------------------------------------------------------------------------------
46 static bool tess_isNaN( float a
)
48 static const int exponentMask
= 0x7f800000;
49 static const int mantissaMask
= 0x007fffff;
52 return ( ( ( fiu
.i
& exponentMask
) == exponentMask
) && ( fiu
.i
& mantissaMask
) ); // NaN
55 //---------------------------------------------------------------------------------------------------------------------------------
57 //---------------------------------------------------------------------------------------------------------------------------------
58 static float tess_flush( float a
)
60 static const int minNormalizedFloat
= 0x00800000;
61 static const int signBit
= 0x80000000;
62 static const int signBitComplement
= 0x7fffffff;
65 int b
= fiu
.i
& signBitComplement
; // fabs()
66 if( b
< minNormalizedFloat
) // UINT comparison. NaN/INF do test false here
68 b
= signBit
& (fiu
.i
);
75 //---------------------------------------------------------------------------------------------------------------------------------
77 //---------------------------------------------------------------------------------------------------------------------------------
78 static float tess_fmin( float a
, float b
)
80 float _a
= tess_flush( a
);
81 float _b
= tess_flush( b
);
82 if( tess_isNaN( _b
) )
86 else if( ( _a
== 0 ) && ( _b
== 0 ) )
90 return ( fiu
.i
& 0x80000000 ) ? a
: b
;
92 return _a
< _b
? a
: b
;
95 //---------------------------------------------------------------------------------------------------------------------------------
97 //---------------------------------------------------------------------------------------------------------------------------------
98 static float tess_fmax( float a
, float b
)
100 float _a
= tess_flush( a
);
101 float _b
= tess_flush( b
);
103 if( tess_isNaN( _b
) )
107 else if( ( _a
== 0 ) && ( _b
== 0 ) )
111 return ( fiu
.i
& 0x80000000 ) ? a
: b
;
113 return _a
>= _b
? a
: b
;
116 //=================================================================================================================================
118 //=================================================================================================================================
120 //-----------------------------------------------------------------------------------------------------------------------------
123 // Convert 32-bit float to 32-bit fixed point integer, using only
124 // integer arithmetic + bitwise operations.
126 // c_uIBits: UINT8 : Width of i (aka. integer bits)
127 // c_uFBits: UINT8 : Width of f (aka. fractional bits)
128 // c_bSigned: bool : Whether the integer bits are a 2's complement signed value
129 // input: float : All values valid.
130 // output: INT32 : At most 24 bits from LSB are meaningful, depending
131 // on the fixed point bit representation chosen (see
132 // below). Extra bits are sign extended from the most
135 //-----------------------------------------------------------------------------------------------------------------------------
137 typedef unsigned char UINT8
;
139 template< const UINT8 c_uIBits
, const UINT8 c_uFBits
, const bool c_bSigned
>
140 INT32
floatToIDotF( const float& input
)
142 // ------------------------------------------------------------------------
143 // output fixed point format
150 // f fractional part of the number, an unsigned
151 // value with _fxpFracBitCount bits (defined below)
155 // i integer part of the number, a 2's complement
156 // value with _fxpIntBitCount bits (defined below)
158 // [sign-extend] MSB of i conditionally replicated
160 // ------------------------------------------------------------------------
161 // Define fixed point bit counts
164 // Commenting out C_ASSERT below to minimise #includes:
165 // C_ASSERT( 2 <= c_uIBits && c_uIBits <= 32 && c_uFBits <= 32 && c_uIBits + c_uFBits <= 32 );
167 // Define most negative and most positive fixed point values
168 const INT32 c_iMinResult
= (c_bSigned
? INT32( -1 ) << (c_uIBits
+ c_uFBits
- 1) : 0);
169 const INT32 c_iMaxResult
= ~c_iMinResult
;
171 // ------------------------------------------------------------------------
172 // constant float properties
173 // ------------------------------------------------------------------------
174 const UINT8 _fltMantissaBitCount
= 23;
175 const UINT8 _fltExponentBitCount
= 8;
176 const INT32 _fltExponentBias
= (INT32( 1 ) << (_fltExponentBitCount
- 1)) - 1;
177 const INT32 _fltHiddenBit
= INT32( 1 ) << _fltMantissaBitCount
;
178 const INT32 _fltMantissaMask
= _fltHiddenBit
- 1;
179 const INT32 _fltExponentMask
= ((INT32( 1 ) << _fltExponentBitCount
) - 1) << _fltMantissaBitCount
;
180 const INT32 _fltSignBit
= INT32( 1 ) << (_fltExponentBitCount
+ _fltMantissaBitCount
);
182 // ------------------------------------------------------------------------
183 // define min and max values as floats (clamp to these bounds)
184 // ------------------------------------------------------------------------
185 INT32 _fxpMaxPosValueFloat
;
186 INT32 _fxpMaxNegValueFloat
;
190 // The maximum positive fixed point value is 2^(i-1) - 2^(-f).
191 // The following constructs the floating point bit pattern for this value,
192 // as long as i >= 2.
193 _fxpMaxPosValueFloat
= (_fltExponentBias
+ c_uIBits
- 1) <<_fltMantissaBitCount
;
194 const INT32 iShift
= _fltMantissaBitCount
+ 2 - c_uIBits
- c_uFBits
;
197 // assert( iShift < 32 );
198 #if defined(_WIN32) || defined(_WIN64)
199 #pragma warning( suppress : 4293 )
201 _fxpMaxPosValueFloat
-= INT32( 1 ) << iShift
;
204 // The maximum negative fixed point value is -2^(i-1).
205 // The following constructs the floating point bit pattern for this value,
206 // as long as i >= 2.
207 // We need this number without the sign bit
208 _fxpMaxNegValueFloat
= (_fltExponentBias
+ c_uIBits
- 1) << _fltMantissaBitCount
;
212 // The maximum positive fixed point value is 2^(i) - 2^(-f).
213 // The following constructs the floating point bit pattern for this value,
214 // as long as i >= 2.
215 _fxpMaxPosValueFloat
= (_fltExponentBias
+ c_uIBits
) <<_fltMantissaBitCount
;
216 const INT32 iShift
= _fltMantissaBitCount
+ 1 - c_uIBits
- c_uFBits
;
219 // assert( iShift < 32 );
220 #if defined(_WIN32) || defined(_WIN64)
221 #pragma warning( suppress : 4293 )
223 _fxpMaxPosValueFloat
-= INT32( 1 ) << iShift
;
226 // The maximum negative fixed point value is 0.
227 _fxpMaxNegValueFloat
= 0;
230 // ------------------------------------------------------------------------
231 // float -> fixed conversion
232 // ------------------------------------------------------------------------
234 // ------------------------------------------------------------------------
235 // examine input float
236 // ------------------------------------------------------------------------
237 INT32 output
= *(INT32
*)&input
;
238 INT32 unbiasedExponent
= ((output
& _fltExponentMask
) >> _fltMantissaBitCount
) - _fltExponentBias
;
239 INT32 isNegative
= output
& _fltSignBit
;
241 // ------------------------------------------------------------------------
243 // ------------------------------------------------------------------------
244 if (unbiasedExponent
== (_fltExponentBias
+ 1) && (output
& _fltMantissaMask
))
249 // ------------------------------------------------------------------------
250 // too large positive
251 // ------------------------------------------------------------------------
252 else if (!isNegative
&& output
>= _fxpMaxPosValueFloat
) // integer compare
254 output
= c_iMaxResult
;
256 // ------------------------------------------------------------------------
257 // too large negative
258 // ------------------------------------------------------------------------
260 else if (isNegative
&& (output
& ~_fltSignBit
) >= _fxpMaxNegValueFloat
)
262 output
= c_iMinResult
;
264 // ------------------------------------------------------------------------
266 // ------------------------------------------------------------------------
267 else if (unbiasedExponent
< -c_uFBits
- 1)
272 // ------------------------------------------------------------------------
274 // ------------------------------------------------------------------------
277 // copy mantissa, add hidden bit
278 output
= (output
& _fltMantissaMask
) | _fltHiddenBit
;
280 INT32 extraBits
= _fltMantissaBitCount
- c_uFBits
- unbiasedExponent
;
283 // 2's complement if negative
286 output
= ~output
+ 1;
289 // From the range checks that led here, it is known that
290 // unbiasedExponent < c_uIBits. So, at most:
291 // (a) unbiasedExponent == c_uIBits - 1.
293 // From compile validation above, it is known that
294 // c_uIBits + c_uFBits <= _fltMantissaBitCount + 1).
296 // (b) _fltMantissaBitCount == _fxtIntBitCount + c_uFBits - 1
298 // Substituting (a) and (b) into extraBits calculation above:
299 // extraBits >= (_fxtIntBitCount + c_uFBits - 1)
300 // - c_uFBits - (c_uIBits - 1)
303 // Thus we only have to worry about shifting right by 0 or more
304 // bits to get the decimal to the right place, and never have
307 INT32 LSB
= 1 << extraBits
; // last bit being kept
308 INT32 extraBitsMask
= LSB
- 1;
309 INT32 half
= LSB
>> 1; // round bias
311 // round to nearest-even at LSB
312 if ((output
& LSB
) || (output
& extraBitsMask
) > half
)
317 // shift off the extra bits (sign extending)
318 output
>>= extraBits
;
322 output
<<= -extraBits
;
324 // 2's complement if negative
327 output
= ~output
+ 1;
333 //-----------------------------------------------------------------------------------------------------------------------------
335 #define FXP_INTEGER_BITS 15
336 #define FXP_FRACTION_BITS 16
337 #define FXP_FRACTION_MASK 0x0000ffff
338 #define FXP_INTEGER_MASK 0x7fff0000
339 #define FXP_THREE (3<<FXP_FRACTION_BITS)
340 #define FXP_ONE (1<<FXP_FRACTION_BITS)
341 #define FXP_ONE_THIRD 0x00005555
342 #define FXP_TWO_THIRDS 0x0000aaaa
343 #define FXP_ONE_HALF 0x00008000
345 #define FXP_MAX_INPUT_TESS_FACTOR_BEFORE_TRIPLE_AVERAGE 0x55540000 // 1/3 of max fixed point number - 1. Numbers less than
346 // or equal to this allows avg. reduction on a tri patch
347 // including rounding.
349 #define FXP_MAX_INPUT_TESS_FACTOR_BEFORE_PAIR_AVERAGE 0x7FFF0000 // 1/2 of max fixed point number - 1. Numbers less than
350 // or equal to this allows avg. reduction on a quad patch
351 // including rounding.
353 static const FXP s_fixedReciprocal
[D3D11_TESSELLATOR_MAX_TESSELLATION_FACTOR
+1] =
355 0xffffffff, // 1/0 is the first entry (unused)
356 0x10000, 0x8000, 0x5555, 0x4000,
357 0x3333, 0x2aab, 0x2492, 0x2000,
358 0x1c72, 0x199a, 0x1746, 0x1555,
359 0x13b1, 0x1249, 0x1111, 0x1000,
360 0xf0f, 0xe39, 0xd79, 0xccd,
361 0xc31, 0xba3, 0xb21, 0xaab,
362 0xa3d, 0x9d9, 0x97b, 0x925,
363 0x8d4, 0x889, 0x842, 0x800,
364 0x7c2, 0x788, 0x750, 0x71c,
365 0x6eb, 0x6bd, 0x690, 0x666,
366 0x63e, 0x618, 0x5f4, 0x5d1,
367 0x5b0, 0x591, 0x572, 0x555,
368 0x539, 0x51f, 0x505, 0x4ec,
369 0x4d5, 0x4be, 0x4a8, 0x492,
370 0x47e, 0x46a, 0x457, 0x444,
371 0x432, 0x421, 0x410, 0x400, // 1/64 is the last entry
374 #define FLOAT_THREE 3.0f
375 #define FLOAT_ONE 1.0f
377 //---------------------------------------------------------------------------------------------------------------------------------
379 //---------------------------------------------------------------------------------------------------------------------------------
380 FXP
floatToFixed(const float& input
)
382 return floatToIDotF
< FXP_INTEGER_BITS
, FXP_FRACTION_BITS
, /*bSigned*/false >( input
);
385 //---------------------------------------------------------------------------------------------------------------------------------
387 //---------------------------------------------------------------------------------------------------------------------------------
388 float fixedToFloat(const FXP
& input
)
390 // not worrying about denorm flushing the float operations (the DX spec behavior for div), since the numbers will not be that small during tessellation.
391 return ((float)(input
>>FXP_FRACTION_BITS
) + (float)(input
&FXP_FRACTION_MASK
)/(1<<FXP_FRACTION_BITS
));
394 //---------------------------------------------------------------------------------------------------------------------------------
396 //---------------------------------------------------------------------------------------------------------------------------------
397 bool isEven(const float& input
)
399 return (((int)input
) & 1) ? false : true;
402 //---------------------------------------------------------------------------------------------------------------------------------
404 //---------------------------------------------------------------------------------------------------------------------------------
405 FXP
fxpCeil(const FXP
& input
)
407 if( input
& FXP_FRACTION_MASK
)
409 return (input
& FXP_INTEGER_MASK
) + FXP_ONE
;
414 //---------------------------------------------------------------------------------------------------------------------------------
416 //---------------------------------------------------------------------------------------------------------------------------------
417 FXP
fxpFloor(const FXP
& input
)
419 return (input
& FXP_INTEGER_MASK
);
422 //=================================================================================================================================
424 //=================================================================================================================================
426 //---------------------------------------------------------------------------------------------------------------------------------
427 // CHWTessellator::CHWTessellator
428 //---------------------------------------------------------------------------------------------------------------------------------
429 CHWTessellator::CHWTessellator()
435 m_bUsingPatchedIndices
= false;
436 m_bUsingPatchedIndices2
= false;
437 #ifdef ALLOW_XBOX_360_COMPARISON
438 m_bXBox360Mode
= false;
441 //---------------------------------------------------------------------------------------------------------------------------------
442 // CHWTessellator::~CHWTessellator
443 //---------------------------------------------------------------------------------------------------------------------------------
444 CHWTessellator::~CHWTessellator()
450 //---------------------------------------------------------------------------------------------------------------------------------
451 // CHWTessellator::Init
453 //---------------------------------------------------------------------------------------------------------------------------------
454 void CHWTessellator::Init(
455 D3D11_TESSELLATOR_PARTITIONING partitioning
,
456 D3D11_TESSELLATOR_OUTPUT_PRIMITIVE outputPrimitive
)
460 m_Point
= new DOMAIN_POINT
[MAX_POINT_COUNT
];
464 m_Index
= new int[MAX_INDEX_COUNT
];
466 m_partitioning
= partitioning
;
467 m_originalPartitioning
= partitioning
;
468 switch( partitioning
)
470 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
473 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
474 m_parity
= TESSELLATOR_PARITY_ODD
;
476 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
477 m_parity
= TESSELLATOR_PARITY_EVEN
;
480 m_originalParity
= m_parity
;
481 m_outputPrimitive
= outputPrimitive
;
485 //---------------------------------------------------------------------------------------------------------------------------------
486 // CHWTessellator::TessellateQuadDomain
488 //---------------------------------------------------------------------------------------------------------------------------------
489 void CHWTessellator::TessellateQuadDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
490 float insideTessFactor_U
, float insideTessFactor_V
)
492 PROCESSED_TESS_FACTORS_QUAD processedTessFactors
;
493 QuadProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Ueq1
,tessFactor_Veq1
,insideTessFactor_U
,insideTessFactor_V
,processedTessFactors
);
495 if( processedTessFactors
.bPatchCulled
)
501 else if( processedTessFactors
.bJustDoMinimumTessFactor
)
503 DefinePoint(/*U*/0,/*V*/0,/*pointStorageOffset*/0);
504 DefinePoint(/*U*/FXP_ONE
,/*V*/0,/*pointStorageOffset*/1);
505 DefinePoint(/*U*/FXP_ONE
,/*V*/FXP_ONE
,/*pointStorageOffset*/2);
506 DefinePoint(/*U*/0,/*V*/FXP_ONE
,/*pointStorageOffset*/3);
509 switch(m_outputPrimitive
)
511 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CW
:
512 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CCW
:
513 // function orients them CCW if needed
514 DefineClockwiseTriangle(0,1,3,/*indexStorageOffset*/0);
515 DefineClockwiseTriangle(1,2,3,/*indexStorageOffset*/3);
518 case D3D11_TESSELLATOR_OUTPUT_POINT
:
521 case D3D11_TESSELLATOR_OUTPUT_LINE
:
522 DumpAllPointsAsInOrderLineList();
528 QuadGeneratePoints(processedTessFactors
);
530 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
535 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_LINE
)
537 DumpAllPointsAsInOrderLineList();
541 QuadGenerateConnectivity(processedTessFactors
); // can be done in parallel to QuadGeneratePoints()
544 //---------------------------------------------------------------------------------------------------------------------------------
545 // CHWTessellator::QuadProcessTessFactors
546 //---------------------------------------------------------------------------------------------------------------------------------
547 void CHWTessellator::QuadProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
548 float insideTessFactor_U
, float insideTessFactor_V
, PROCESSED_TESS_FACTORS_QUAD
& processedTessFactors
)
550 // Is the patch culled?
551 if( !(tessFactor_Ueq0
> 0) || // NaN will pass
552 !(tessFactor_Veq0
> 0) ||
553 !(tessFactor_Ueq1
> 0) ||
554 !(tessFactor_Veq1
> 0) )
556 processedTessFactors
.bPatchCulled
= true;
561 processedTessFactors
.bPatchCulled
= false;
564 // Clamp edge TessFactors
565 float lowerBound
= 0.0, upperBound
= 0.0;
566 switch(m_originalPartitioning
)
568 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
569 case D3D11_TESSELLATOR_PARTITIONING_POW2
: // don�t care about pow2 distinction for validation, just treat as integer
570 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
571 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
574 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
575 lowerBound
= D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
;
576 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
579 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
580 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
581 upperBound
= D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
;
585 tessFactor_Ueq0
= tess_fmin( upperBound
, tess_fmax( lowerBound
, tessFactor_Ueq0
) );
586 tessFactor_Veq0
= tess_fmin( upperBound
, tess_fmax( lowerBound
, tessFactor_Veq0
) );
587 tessFactor_Ueq1
= tess_fmin( upperBound
, tess_fmax( lowerBound
, tessFactor_Ueq1
) );
588 tessFactor_Veq1
= tess_fmin( upperBound
, tess_fmax( lowerBound
, tessFactor_Veq1
) );
590 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
592 tessFactor_Ueq0
= ceil(tessFactor_Ueq0
);
593 tessFactor_Veq0
= ceil(tessFactor_Veq0
);
594 tessFactor_Ueq1
= ceil(tessFactor_Ueq1
);
595 tessFactor_Veq1
= ceil(tessFactor_Veq1
);
598 // Clamp inside TessFactors
599 if(D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
== m_originalPartitioning
)
601 #define EPSILON 0.0000152587890625f // 2^(-16), min positive fixed point fraction
602 #define MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON (D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON/2)
603 // If any TessFactor will end up > 1 after floatToFixed conversion later,
604 // then force the inside TessFactors to be > 1 so there is a picture frame.
605 if( (tessFactor_Ueq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
606 (tessFactor_Veq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
607 (tessFactor_Ueq1
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
608 (tessFactor_Veq1
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
609 (insideTessFactor_U
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
610 (insideTessFactor_V
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) )
612 // Force picture frame
613 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
+ EPSILON
;
617 insideTessFactor_U
= tess_fmin( upperBound
, tess_fmax( lowerBound
, insideTessFactor_U
) );
618 insideTessFactor_V
= tess_fmin( upperBound
, tess_fmax( lowerBound
, insideTessFactor_V
) );
619 // Note the above clamps map NaN to lowerBound
622 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
624 insideTessFactor_U
= ceil(insideTessFactor_U
);
625 insideTessFactor_V
= ceil(insideTessFactor_V
);
628 // Reset our vertex and index buffers. We have enough storage for the max tessFactor.
632 // Process tessFactors
633 float outsideTessFactor
[QUAD_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Ueq1
, tessFactor_Veq1
};
634 float insideTessFactor
[QUAD_AXES
] = {insideTessFactor_U
,insideTessFactor_V
};
636 if( HWIntegerPartitioning() )
638 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
640 int edgeEven
= isEven(outsideTessFactor
[edge
]);
641 processedTessFactors
.outsideTessFactorParity
[edge
] = edgeEven
? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
643 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
645 processedTessFactors
.insideTessFactorParity
[axis
] =
646 (isEven(insideTessFactor
[axis
]) || (FLOAT_ONE
== insideTessFactor
[axis
]) )
647 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
652 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
654 processedTessFactors
.outsideTessFactorParity
[edge
] = m_originalParity
;
656 processedTessFactors
.insideTessFactorParity
[U
] = processedTessFactors
.insideTessFactorParity
[V
] = m_originalParity
;
659 // Save fixed point TessFactors
660 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
662 processedTessFactors
.outsideTessFactor
[edge
] = floatToFixed(outsideTessFactor
[edge
]);
664 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
666 processedTessFactors
.insideTessFactor
[axis
] = floatToFixed(insideTessFactor
[axis
]);
669 if( HWIntegerPartitioning() || Odd() )
671 // Special case if all TessFactors are 1
672 if( (FXP_ONE
== processedTessFactors
.insideTessFactor
[U
]) &&
673 (FXP_ONE
== processedTessFactors
.insideTessFactor
[V
]) &&
674 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Ueq0
]) &&
675 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Veq0
]) &&
676 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Ueq1
]) &&
677 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Veq1
]) )
679 processedTessFactors
.bJustDoMinimumTessFactor
= true;
683 processedTessFactors
.bJustDoMinimumTessFactor
= false;
685 // Compute TessFactor-specific metadata
686 for(int edge
= 0; edge
< QUAD_EDGES
; edge
++ )
688 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
689 ComputeTessFactorContext(processedTessFactors
.outsideTessFactor
[edge
], processedTessFactors
.outsideTessFactorCtx
[edge
]);
692 for(int axis
= 0; axis
< QUAD_AXES
; axis
++)
694 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[axis
]);
695 ComputeTessFactorContext(processedTessFactors
.insideTessFactor
[axis
], processedTessFactors
.insideTessFactorCtx
[axis
]);
698 // Compute some initial data.
700 // outside edge offsets and storage
701 for(int edge
= 0; edge
< QUAD_EDGES
; edge
++ )
703 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
704 processedTessFactors
.numPointsForOutsideEdge
[edge
] = NumPointsForTessFactor(processedTessFactors
.outsideTessFactor
[edge
]);
705 m_NumPoints
+= processedTessFactors
.numPointsForOutsideEdge
[edge
];
709 // inside edge offsets
710 for(int axis
= 0; axis
< QUAD_AXES
; axis
++)
712 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[axis
]);
713 processedTessFactors
.numPointsForInsideTessFactor
[axis
] = NumPointsForTessFactor(processedTessFactors
.insideTessFactor
[axis
]);
714 int pointCountMin
= ( TESSELLATOR_PARITY_ODD
== processedTessFactors
.insideTessFactorParity
[axis
] ) ? 4 : 3;
715 // max() allows degenerate transition regions when inside TessFactor == 1
716 processedTessFactors
.numPointsForInsideTessFactor
[axis
] = max(pointCountMin
,processedTessFactors
.numPointsForInsideTessFactor
[axis
]);
719 processedTessFactors
.insideEdgePointBaseOffset
= m_NumPoints
;
721 // inside storage, including interior edges above
722 int numInteriorPoints
= (processedTessFactors
.numPointsForInsideTessFactor
[U
] - 2)*(processedTessFactors
.numPointsForInsideTessFactor
[V
]-2);
723 m_NumPoints
+= numInteriorPoints
;
726 //---------------------------------------------------------------------------------------------------------------------------------
727 // CHWTessellator::QuadGeneratePoints
728 //---------------------------------------------------------------------------------------------------------------------------------
729 void CHWTessellator::QuadGeneratePoints( const PROCESSED_TESS_FACTORS_QUAD
& processedTessFactors
)
731 // Generate exterior ring edge points, clockwise from top-left
734 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
736 int parity
= edge
&0x1;
738 int endPoint
= processedTessFactors
.numPointsForOutsideEdge
[edge
] - 1;
739 for(int p
= startPoint
; p
< endPoint
; p
++,pointOffset
++) // don't include end, since next edge starts with it.
742 int q
= ((edge
==1)||(edge
==2)) ? p
: endPoint
- p
; // reverse order
743 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
744 PlacePointIn1D(processedTessFactors
.outsideTessFactorCtx
[edge
],q
,fxpParam
);
747 DefinePoint(/*U*/fxpParam
,
748 /*V*/(edge
== 3) ? FXP_ONE
: 0,
749 /*pointStorageOffset*/pointOffset
);
753 DefinePoint(/*U*/(edge
== 2) ? FXP_ONE
: 0,
755 /*pointStorageOffset*/pointOffset
);
760 // Generate interior ring points, clockwise from (U==0,V==1) (bottom-left) spiralling toward center
761 static const int startRing
= 1;
762 int minNumPointsForTessFactor
= min(processedTessFactors
.numPointsForInsideTessFactor
[U
],processedTessFactors
.numPointsForInsideTessFactor
[V
]);
763 int numRings
= (minNumPointsForTessFactor
>> 1); // note for even tess we aren't counting center point here.
764 for(int ring
= startRing
; ring
< numRings
; ring
++)
766 int startPoint
= ring
;
767 int endPoint
[QUAD_AXES
] = {processedTessFactors
.numPointsForInsideTessFactor
[U
] - 1 - startPoint
,
768 processedTessFactors
.numPointsForInsideTessFactor
[V
] - 1 - startPoint
};
770 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
772 int parity
[QUAD_AXES
] = {edge
&0x1,((edge
+1)&0x1)};
773 int perpendicularAxisPoint
= (edge
< 2) ? startPoint
: endPoint
[parity
[0]];
775 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[parity
[0]]);
776 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[parity
[0]],perpendicularAxisPoint
,fxpPerpParam
);
777 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[parity
[1]]);
778 for(int p
= startPoint
; p
< endPoint
[parity
[1]]; p
++, pointOffset
++) // don't include end: next edge starts with it.
781 int q
= ((edge
== 1)||(edge
==2)) ? p
: endPoint
[parity
[1]] - (p
- startPoint
);
782 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[parity
[1]],q
,fxpParam
);
785 DefinePoint(/*U*/fxpPerpParam
,
787 /*pointStorageOffset*/pointOffset
);
791 DefinePoint(/*U*/fxpParam
,
793 /*pointStorageOffset*/pointOffset
);
798 // For even tessellation, the inner "ring" is degenerate - a row of points
799 if( (processedTessFactors
.numPointsForInsideTessFactor
[U
] > processedTessFactors
.numPointsForInsideTessFactor
[V
]) &&
800 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
]) )
802 int startPoint
= numRings
;
803 int endPoint
= processedTessFactors
.numPointsForInsideTessFactor
[U
] - 1 - startPoint
;
804 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[U
]);
805 for( int p
= startPoint
; p
<= endPoint
; p
++, pointOffset
++ )
808 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[U
],p
,fxpParam
);
809 DefinePoint(/*U*/fxpParam
,
810 /*V*/FXP_ONE_HALF
, // middle
811 /*pointStorageOffset*/pointOffset
);
814 else if( (processedTessFactors
.numPointsForInsideTessFactor
[V
] >= processedTessFactors
.numPointsForInsideTessFactor
[U
]) &&
815 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[U
]) )
817 int startPoint
= numRings
;
820 endPoint
= processedTessFactors
.numPointsForInsideTessFactor
[V
] - 1 - startPoint
;
821 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[V
]);
822 for( int p
= endPoint
; p
>= startPoint
; p
--, pointOffset
++ )
824 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[V
],p
,fxpParam
);
825 DefinePoint(/*U*/FXP_ONE_HALF
, // middle
827 /*pointStorageOffset*/pointOffset
);
831 //---------------------------------------------------------------------------------------------------------------------------------
832 // CHWTessellator::QuadGenerateConnectivity
833 //---------------------------------------------------------------------------------------------------------------------------------
834 void CHWTessellator::QuadGenerateConnectivity( const PROCESSED_TESS_FACTORS_QUAD
& processedTessFactors
)
836 // Generate primitives for all the concentric rings, one side at a time for each ring
837 static const int startRing
= 1;
838 int numPointRowsToCenter
[QUAD_AXES
] = {((processedTessFactors
.numPointsForInsideTessFactor
[U
]+1) >> 1),
839 ((processedTessFactors
.numPointsForInsideTessFactor
[V
]+1) >> 1)}; // +1 is so even tess includes the center point
840 int numRings
= min(numPointRowsToCenter
[U
],numPointRowsToCenter
[V
]);
841 int degeneratePointRing
[QUAD_AXES
] = { // Even partitioning causes degenerate row of points,
842 // which results in exceptions to the point ordering conventions
843 // when travelling around the rings counterclockwise.
844 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
]) ? numPointRowsToCenter
[V
] - 1 : -1,
845 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[U
]) ? numPointRowsToCenter
[U
] - 1 : -1 };
847 const TESS_FACTOR_CONTEXT
* outsideTessFactorCtx
[QUAD_EDGES
] = {&processedTessFactors
.outsideTessFactorCtx
[Ueq0
],
848 &processedTessFactors
.outsideTessFactorCtx
[Veq0
],
849 &processedTessFactors
.outsideTessFactorCtx
[Ueq1
],
850 &processedTessFactors
.outsideTessFactorCtx
[Veq1
]};
851 TESSELLATOR_PARITY outsideTessFactorParity
[QUAD_EDGES
] = {processedTessFactors
.outsideTessFactorParity
[Ueq0
],
852 processedTessFactors
.outsideTessFactorParity
[Veq0
],
853 processedTessFactors
.outsideTessFactorParity
[Ueq1
],
854 processedTessFactors
.outsideTessFactorParity
[Veq1
]};
855 int numPointsForOutsideEdge
[QUAD_EDGES
] = {processedTessFactors
.numPointsForOutsideEdge
[Ueq0
],
856 processedTessFactors
.numPointsForOutsideEdge
[Veq0
],
857 processedTessFactors
.numPointsForOutsideEdge
[Ueq1
],
858 processedTessFactors
.numPointsForOutsideEdge
[Veq1
]};
860 int insideEdgePointBaseOffset
= processedTessFactors
.insideEdgePointBaseOffset
;
861 int outsideEdgePointBaseOffset
= 0;
863 for(int ring
= startRing
; ring
< numRings
; ring
++)
865 int numPointsForInsideEdge
[QUAD_AXES
] = {processedTessFactors
.numPointsForInsideTessFactor
[U
] - 2*ring
,
866 processedTessFactors
.numPointsForInsideTessFactor
[V
] - 2*ring
};
868 int edge0InsidePointBaseOffset
= insideEdgePointBaseOffset
;
869 int edge0OutsidePointBaseOffset
= outsideEdgePointBaseOffset
;
871 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
873 int parity
= (edge
+1)&0x1;
875 int numTriangles
= numPointsForInsideEdge
[parity
] + numPointsForOutsideEdge
[edge
] - 2;
876 int insideBaseOffset
;
877 int outsideBaseOffset
;
878 if( edge
== 3 ) // We need to patch the indexing so Stitch() can think it sees
879 // 2 sequentially increasing rows of points, even though we have wrapped around
880 // to the end of the inner and outer ring's points, so the last point is really
881 // the first point for the ring.
882 // We make it so that when Stitch() calls AddIndex(), that function
883 // will do any necessary index adjustment.
885 if( ring
== degeneratePointRing
[parity
] )
887 m_IndexPatchContext2
.baseIndexToInvert
= insideEdgePointBaseOffset
+ 1;
888 m_IndexPatchContext2
.cornerCaseBadValue
= outsideEdgePointBaseOffset
+ numPointsForOutsideEdge
[edge
] - 1;
889 m_IndexPatchContext2
.cornerCaseReplacementValue
= edge0OutsidePointBaseOffset
;
890 m_IndexPatchContext2
.indexInversionEndPoint
= (m_IndexPatchContext2
.baseIndexToInvert
<< 1) - 1;
891 insideBaseOffset
= m_IndexPatchContext2
.baseIndexToInvert
;
892 outsideBaseOffset
= outsideEdgePointBaseOffset
;
893 SetUsingPatchedIndices2(true);
897 m_IndexPatchContext
.insidePointIndexDeltaToRealValue
= insideEdgePointBaseOffset
;
898 m_IndexPatchContext
.insidePointIndexBadValue
= numPointsForInsideEdge
[parity
] - 1;
899 m_IndexPatchContext
.insidePointIndexReplacementValue
= edge0InsidePointBaseOffset
;
900 m_IndexPatchContext
.outsidePointIndexPatchBase
= m_IndexPatchContext
.insidePointIndexBadValue
+1; // past inside patched index range
901 m_IndexPatchContext
.outsidePointIndexDeltaToRealValue
= outsideEdgePointBaseOffset
902 - m_IndexPatchContext
.outsidePointIndexPatchBase
;
903 m_IndexPatchContext
.outsidePointIndexBadValue
= m_IndexPatchContext
.outsidePointIndexPatchBase
904 + numPointsForOutsideEdge
[edge
] - 1;
905 m_IndexPatchContext
.outsidePointIndexReplacementValue
= edge0OutsidePointBaseOffset
;
907 insideBaseOffset
= 0;
908 outsideBaseOffset
= m_IndexPatchContext
.outsidePointIndexPatchBase
;
909 SetUsingPatchedIndices(true);
912 else if( (edge
== 2) && (ring
== degeneratePointRing
[parity
]) )
914 m_IndexPatchContext2
.baseIndexToInvert
= insideEdgePointBaseOffset
;
915 m_IndexPatchContext2
.cornerCaseBadValue
= -1; // unused
916 m_IndexPatchContext2
.cornerCaseReplacementValue
= -1; // unused
917 m_IndexPatchContext2
.indexInversionEndPoint
= m_IndexPatchContext2
.baseIndexToInvert
<< 1;
918 insideBaseOffset
= m_IndexPatchContext2
.baseIndexToInvert
;
919 outsideBaseOffset
= outsideEdgePointBaseOffset
;
920 SetUsingPatchedIndices2(true);
924 insideBaseOffset
= insideEdgePointBaseOffset
;
925 outsideBaseOffset
= outsideEdgePointBaseOffset
;
927 if( ring
== startRing
)
929 StitchTransition(/*baseIndexOffset: */m_NumIndices
,
930 insideBaseOffset
,processedTessFactors
.insideTessFactorCtx
[parity
].numHalfTessFactorPoints
,processedTessFactors
.insideTessFactorParity
[parity
],
931 outsideBaseOffset
,outsideTessFactorCtx
[edge
]->numHalfTessFactorPoints
,outsideTessFactorParity
[edge
]);
935 StitchRegular(/*bTrapezoid*/true, DIAGONALS_MIRRORED
,
936 /*baseIndexOffset: */m_NumIndices
,
937 numPointsForInsideEdge
[parity
],
938 insideBaseOffset
,outsideBaseOffset
);
940 SetUsingPatchedIndices(false);
941 SetUsingPatchedIndices2(false);
942 m_NumIndices
+= numTriangles
*3;
943 outsideEdgePointBaseOffset
+= numPointsForOutsideEdge
[edge
] - 1;
944 if( (edge
== 2) && (ring
== degeneratePointRing
[parity
]) )
946 insideEdgePointBaseOffset
-= numPointsForInsideEdge
[parity
] - 1;
950 insideEdgePointBaseOffset
+= numPointsForInsideEdge
[parity
] - 1;
952 numPointsForOutsideEdge
[edge
] = numPointsForInsideEdge
[parity
];
954 if( startRing
== ring
)
956 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
958 outsideTessFactorCtx
[edge
] = &processedTessFactors
.insideTessFactorCtx
[edge
&1];
959 outsideTessFactorParity
[edge
] = processedTessFactors
.insideTessFactorParity
[edge
&1];
964 // Triangulate center - a row of quads if odd
965 // This triangulation may be producing diagonals that are asymmetric about
966 // the center of the patch in this region.
967 if( (processedTessFactors
.numPointsForInsideTessFactor
[U
] > processedTessFactors
.numPointsForInsideTessFactor
[V
]) &&
968 (TESSELLATOR_PARITY_ODD
== processedTessFactors
.insideTessFactorParity
[V
] ) )
970 SetUsingPatchedIndices2(true);
971 int stripNumQuads
= (((processedTessFactors
.numPointsForInsideTessFactor
[U
]>>1) - (processedTessFactors
.numPointsForInsideTessFactor
[V
]>>1))<<1)+
972 ((TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[U
] ) ? 2 : 1);
973 m_IndexPatchContext2
.baseIndexToInvert
= outsideEdgePointBaseOffset
+ stripNumQuads
+ 2;
974 m_IndexPatchContext2
.cornerCaseBadValue
= m_IndexPatchContext2
.baseIndexToInvert
;
975 m_IndexPatchContext2
.cornerCaseReplacementValue
= outsideEdgePointBaseOffset
;
976 m_IndexPatchContext2
.indexInversionEndPoint
= m_IndexPatchContext2
.baseIndexToInvert
+
977 m_IndexPatchContext2
.baseIndexToInvert
+ stripNumQuads
;
978 StitchRegular(/*bTrapezoid*/false,DIAGONALS_INSIDE_TO_OUTSIDE
,
979 /*baseIndexOffset: */m_NumIndices
, /*numInsideEdgePoints:*/stripNumQuads
+1,
980 /*insideEdgePointBaseOffset*/m_IndexPatchContext2
.baseIndexToInvert
,
981 outsideEdgePointBaseOffset
+1);
982 SetUsingPatchedIndices2(false);
983 m_NumIndices
+= stripNumQuads
*6;
985 else if((processedTessFactors
.numPointsForInsideTessFactor
[V
] >= processedTessFactors
.numPointsForInsideTessFactor
[U
]) &&
986 (TESSELLATOR_PARITY_ODD
== processedTessFactors
.insideTessFactorParity
[U
]) )
988 SetUsingPatchedIndices2(true);
989 int stripNumQuads
= (((processedTessFactors
.numPointsForInsideTessFactor
[V
]>>1) - (processedTessFactors
.numPointsForInsideTessFactor
[U
]>>1))<<1)+
990 ((TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
] ) ? 2 : 1);
991 m_IndexPatchContext2
.baseIndexToInvert
= outsideEdgePointBaseOffset
+ stripNumQuads
+ 1;
992 m_IndexPatchContext2
.cornerCaseBadValue
= -1; // unused
993 m_IndexPatchContext2
.indexInversionEndPoint
= m_IndexPatchContext2
.baseIndexToInvert
+
994 m_IndexPatchContext2
.baseIndexToInvert
+ stripNumQuads
;
995 DIAGONALS diag
= (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
]) ?
996 DIAGONALS_INSIDE_TO_OUTSIDE
: DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE
;
997 StitchRegular(/*bTrapezoid*/false,diag
,
998 /*baseIndexOffset: */m_NumIndices
, /*numInsideEdgePoints:*/stripNumQuads
+1,
999 /*insideEdgePointBaseOffset*/m_IndexPatchContext2
.baseIndexToInvert
,
1000 outsideEdgePointBaseOffset
);
1001 SetUsingPatchedIndices2(false);
1002 m_NumIndices
+= stripNumQuads
*6;
1006 //---------------------------------------------------------------------------------------------------------------------------------
1007 // CHWTessellator::TessellateTriDomain
1009 //---------------------------------------------------------------------------------------------------------------------------------
1010 void CHWTessellator::TessellateTriDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
1011 float insideTessFactor
)
1013 PROCESSED_TESS_FACTORS_TRI processedTessFactors
;
1014 TriProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Weq0
,insideTessFactor
,processedTessFactors
);
1016 if( processedTessFactors
.bPatchCulled
)
1022 else if( processedTessFactors
.bJustDoMinimumTessFactor
)
1024 DefinePoint(/*U*/0,/*V*/FXP_ONE
,/*pointStorageOffset*/0); //V=1 (beginning of Ueq0 edge VW)
1025 DefinePoint(/*U*/0,/*V*/0,/*pointStorageOffset*/1); //W=1 (beginning of Veq0 edge WU)
1026 DefinePoint(/*U*/FXP_ONE
,/*V*/0,/*pointStorageOffset*/2); //U=1 (beginning of Weq0 edge UV)
1029 switch(m_outputPrimitive
)
1031 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CW
:
1032 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CCW
:
1033 // function orients them CCW if needed
1034 DefineClockwiseTriangle(0,1,2,/*indexStorageBaseOffset*/m_NumIndices
);
1037 case D3D11_TESSELLATOR_OUTPUT_POINT
:
1040 case D3D11_TESSELLATOR_OUTPUT_LINE
:
1041 DumpAllPointsAsInOrderLineList();
1047 TriGeneratePoints(processedTessFactors
);
1049 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
1054 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_LINE
)
1056 DumpAllPointsAsInOrderLineList();
1060 TriGenerateConnectivity(processedTessFactors
); // can be done in parallel to TriGeneratePoints()
1063 //---------------------------------------------------------------------------------------------------------------------------------
1064 // CHWTessellator::TriProcessTessFactors
1065 //---------------------------------------------------------------------------------------------------------------------------------
1066 void CHWTessellator::TriProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
1067 float insideTessFactor
, PROCESSED_TESS_FACTORS_TRI
& processedTessFactors
)
1069 // Is the patch culled?
1070 if( !(tessFactor_Ueq0
> 0) || // NaN will pass
1071 !(tessFactor_Veq0
> 0) ||
1072 !(tessFactor_Weq0
> 0) )
1074 processedTessFactors
.bPatchCulled
= true;
1079 processedTessFactors
.bPatchCulled
= false;
1082 // Clamp edge TessFactors
1083 float lowerBound
= 0.0, upperBound
= 0.0;
1084 switch(m_originalPartitioning
)
1086 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
1087 case D3D11_TESSELLATOR_PARTITIONING_POW2
: // don�t care about pow2 distinction for validation, just treat as integer
1088 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1089 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1092 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
1093 lowerBound
= D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
;
1094 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1097 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
1098 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1099 upperBound
= D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
;
1103 tessFactor_Ueq0
= tess_fmin( upperBound
, tess_fmax( lowerBound
, tessFactor_Ueq0
) );
1104 tessFactor_Veq0
= tess_fmin( upperBound
, tess_fmax( lowerBound
, tessFactor_Veq0
) );
1105 tessFactor_Weq0
= tess_fmin( upperBound
, tess_fmax( lowerBound
, tessFactor_Weq0
) );
1107 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
1109 tessFactor_Ueq0
= ceil(tessFactor_Ueq0
);
1110 tessFactor_Veq0
= ceil(tessFactor_Veq0
);
1111 tessFactor_Weq0
= ceil(tessFactor_Weq0
);
1114 // Clamp inside TessFactors
1115 if(D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
== m_originalPartitioning
)
1117 if( (tessFactor_Ueq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
1118 (tessFactor_Veq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
1119 (tessFactor_Weq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
))
1120 // Don't need the same check for insideTessFactor for tri patches,
1121 // since there is only one insideTessFactor, as opposed to quad
1122 // patches which have 2 insideTessFactors.
1124 // Force picture frame
1125 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
+ EPSILON
;
1129 insideTessFactor
= tess_fmin( upperBound
, tess_fmax( lowerBound
, insideTessFactor
) );
1130 // Note the above clamps map NaN to lowerBound
1132 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
1134 insideTessFactor
= ceil(insideTessFactor
);
1137 // Reset our vertex and index buffers. We have enough storage for the max tessFactor.
1141 // Process tessFactors
1142 float outsideTessFactor
[TRI_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Weq0
};
1144 if( HWIntegerPartitioning() )
1146 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
1148 int edgeEven
= isEven(outsideTessFactor
[edge
]);
1149 processedTessFactors
.outsideTessFactorParity
[edge
] = edgeEven
? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1151 processedTessFactors
.insideTessFactorParity
= (isEven(insideTessFactor
) || (FLOAT_ONE
== insideTessFactor
))
1152 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1156 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
1158 processedTessFactors
.outsideTessFactorParity
[edge
] = m_originalParity
;
1160 processedTessFactors
.insideTessFactorParity
= m_originalParity
;
1163 // Save fixed point TessFactors
1164 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
1166 processedTessFactors
.outsideTessFactor
[edge
] = floatToFixed(outsideTessFactor
[edge
]);
1168 processedTessFactors
.insideTessFactor
= floatToFixed(insideTessFactor
);
1170 if( HWIntegerPartitioning() || Odd() )
1172 // Special case if all TessFactors are 1
1173 if( (FXP_ONE
== processedTessFactors
.insideTessFactor
) &&
1174 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Ueq0
]) &&
1175 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Veq0
]) &&
1176 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Weq0
]) )
1178 processedTessFactors
.bJustDoMinimumTessFactor
= true;
1182 processedTessFactors
.bJustDoMinimumTessFactor
= false;
1184 // Compute per-TessFactor metadata
1185 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1187 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
1188 ComputeTessFactorContext(processedTessFactors
.outsideTessFactor
[edge
], processedTessFactors
.outsideTessFactorCtx
[edge
]);
1190 SetTessellationParity(processedTessFactors
.insideTessFactorParity
);
1191 ComputeTessFactorContext(processedTessFactors
.insideTessFactor
, processedTessFactors
.insideTessFactorCtx
);
1193 // Compute some initial data.
1195 // outside edge offsets and storage
1196 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1198 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
1199 processedTessFactors
.numPointsForOutsideEdge
[edge
] = NumPointsForTessFactor(processedTessFactors
.outsideTessFactor
[edge
]);
1200 m_NumPoints
+= processedTessFactors
.numPointsForOutsideEdge
[edge
];
1204 // inside edge offsets
1205 SetTessellationParity(processedTessFactors
.insideTessFactorParity
);
1206 processedTessFactors
.numPointsForInsideTessFactor
= NumPointsForTessFactor(processedTessFactors
.insideTessFactor
);
1208 int pointCountMin
= Odd() ? 4 : 3;
1209 // max() allows degenerate transition regions when inside TessFactor == 1
1210 processedTessFactors
.numPointsForInsideTessFactor
= max(pointCountMin
,processedTessFactors
.numPointsForInsideTessFactor
);
1213 processedTessFactors
.insideEdgePointBaseOffset
= m_NumPoints
;
1215 // inside storage, including interior edges above
1217 int numInteriorRings
= (processedTessFactors
.numPointsForInsideTessFactor
>> 1) - 1;
1218 int numInteriorPoints
;
1221 numInteriorPoints
= TRI_EDGES
*(numInteriorRings
*(numInteriorRings
+1) - numInteriorRings
);
1225 numInteriorPoints
= TRI_EDGES
*(numInteriorRings
*(numInteriorRings
+1)) + 1;
1227 m_NumPoints
+= numInteriorPoints
;
1232 //---------------------------------------------------------------------------------------------------------------------------------
1233 // CHWTessellator::TriGeneratePoints
1234 //---------------------------------------------------------------------------------------------------------------------------------
1235 void CHWTessellator::TriGeneratePoints( const PROCESSED_TESS_FACTORS_TRI
& processedTessFactors
)
1237 // Generate exterior ring edge points, clockwise starting from point V (VW, the U==0 edge)
1238 int pointOffset
= 0;
1240 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1242 int parity
= edge
&0x1;
1244 int endPoint
= processedTessFactors
.numPointsForOutsideEdge
[edge
] - 1;
1245 for(int p
= startPoint
; p
< endPoint
; p
++, pointOffset
++) // don't include end, since next edge starts with it.
1248 int q
= (parity
) ? p
: endPoint
- p
; // whether to reverse point order given we are defining V or U (W implicit):
1249 // edge0, VW, has V decreasing, so reverse 1D points below
1250 // edge1, WU, has U increasing, so don't reverse 1D points below
1251 // edge2, UV, has U decreasing, so reverse 1D points below
1252 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
1253 PlacePointIn1D(processedTessFactors
.outsideTessFactorCtx
[edge
],q
,fxpParam
);
1258 /*pointStorageOffset*/pointOffset
);
1262 DefinePoint(/*U*/fxpParam
,
1263 /*V*/(edge
== 2) ? FXP_ONE
- fxpParam
: 0,
1264 /*pointStorageOffset*/pointOffset
);
1269 // Generate interior ring points, clockwise spiralling in
1270 SetTessellationParity(processedTessFactors
.insideTessFactorParity
);
1271 static const int startRing
= 1;
1272 int numRings
= (processedTessFactors
.numPointsForInsideTessFactor
>> 1);
1273 for(int ring
= startRing
; ring
< numRings
; ring
++)
1275 int startPoint
= ring
;
1276 int endPoint
= processedTessFactors
.numPointsForInsideTessFactor
- 1 - startPoint
;
1278 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1280 int parity
= edge
&0x1;
1281 int perpendicularAxisPoint
= startPoint
;
1283 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
,perpendicularAxisPoint
,fxpPerpParam
);
1284 fxpPerpParam
*= FXP_TWO_THIRDS
; // Map location to the right size in barycentric space.
1285 // I (amarp) can draw a picture to explain.
1286 // We know this fixed point math won't over/underflow
1287 fxpPerpParam
= (fxpPerpParam
+FXP_ONE_HALF
/*round*/)>>FXP_FRACTION_BITS
; // get back to n.16
1288 for(int p
= startPoint
; p
< endPoint
; p
++, pointOffset
++) // don't include end: next edge starts with it.
1291 int q
= (parity
) ? p
: endPoint
- (p
- startPoint
); // whether to reverse point given we are defining V or U (W implicit):
1292 // edge0, VW, has V decreasing, so reverse 1D points below
1293 // edge1, WU, has U increasing, so don't reverse 1D points below
1294 // edge2, UV, has U decreasing, so reverse 1D points below
1295 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
,q
,fxpParam
);
1296 // edge0 VW, has perpendicular parameter U constant
1297 // edge1 WU, has perpendicular parameter V constant
1298 // edge2 UV, has perpendicular parameter W constant
1299 const unsigned int deriv
= 2; // reciprocal is the rate of change of edge-parallel parameters as they are pushed into the triangle
1303 DefinePoint(/*U*/fxpPerpParam
,
1304 /*V*/fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
, // we know this fixed point math won't over/underflow
1305 /*pointStorageOffset*/pointOffset
);
1308 DefinePoint(/*U*/fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
,// we know this fixed point math won't over/underflow
1310 /*pointStorageOffset*/pointOffset
);
1313 DefinePoint(/*U*/fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
,// we know this fixed point math won't over/underflow
1314 /*V*/FXP_ONE
- (fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
) - fxpPerpParam
,// we know this fixed point math won't over/underflow
1315 /*pointStorageOffset*/pointOffset
);
1323 // Last point is the point at the center.
1324 DefinePoint(/*U*/FXP_ONE_THIRD
,
1326 /*pointStorageOffset*/pointOffset
);
1329 //---------------------------------------------------------------------------------------------------------------------------------
1330 // CHWTessellator::TriGenerateConnectivity
1331 //---------------------------------------------------------------------------------------------------------------------------------
1332 void CHWTessellator::TriGenerateConnectivity( const PROCESSED_TESS_FACTORS_TRI
& processedTessFactors
)
1334 // Generate primitives for all the concentric rings, one side at a time for each ring
1335 static const int startRing
= 1;
1336 int numRings
= ((processedTessFactors
.numPointsForInsideTessFactor
+1) >> 1); // +1 is so even tess includes the center point, which we want to now
1337 const TESS_FACTOR_CONTEXT
* outsideTessFactorCtx
[TRI_EDGES
] = {&processedTessFactors
.outsideTessFactorCtx
[Ueq0
],
1338 &processedTessFactors
.outsideTessFactorCtx
[Veq0
],
1339 &processedTessFactors
.outsideTessFactorCtx
[Weq0
]};
1340 TESSELLATOR_PARITY outsideTessFactorParity
[TRI_EDGES
] = {processedTessFactors
.outsideTessFactorParity
[Ueq0
],
1341 processedTessFactors
.outsideTessFactorParity
[Veq0
],
1342 processedTessFactors
.outsideTessFactorParity
[Weq0
]};
1343 int numPointsForOutsideEdge
[TRI_EDGES
] = {processedTessFactors
.numPointsForOutsideEdge
[Ueq0
],
1344 processedTessFactors
.numPointsForOutsideEdge
[Veq0
],
1345 processedTessFactors
.numPointsForOutsideEdge
[Weq0
]};
1347 int insideEdgePointBaseOffset
= processedTessFactors
.insideEdgePointBaseOffset
;
1348 int outsideEdgePointBaseOffset
= 0;
1350 for(int ring
= startRing
; ring
< numRings
; ring
++)
1352 int numPointsForInsideEdge
= processedTessFactors
.numPointsForInsideTessFactor
- 2*ring
;
1353 int edge0InsidePointBaseOffset
= insideEdgePointBaseOffset
;
1354 int edge0OutsidePointBaseOffset
= outsideEdgePointBaseOffset
;
1355 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1357 int numTriangles
= numPointsForInsideEdge
+ numPointsForOutsideEdge
[edge
] - 2;
1359 int insideBaseOffset
;
1360 int outsideBaseOffset
;
1363 m_IndexPatchContext
.insidePointIndexDeltaToRealValue
= insideEdgePointBaseOffset
;
1364 m_IndexPatchContext
.insidePointIndexBadValue
= numPointsForInsideEdge
- 1;
1365 m_IndexPatchContext
.insidePointIndexReplacementValue
= edge0InsidePointBaseOffset
;
1366 m_IndexPatchContext
.outsidePointIndexPatchBase
= m_IndexPatchContext
.insidePointIndexBadValue
+1; // past inside patched index range
1367 m_IndexPatchContext
.outsidePointIndexDeltaToRealValue
= outsideEdgePointBaseOffset
1368 - m_IndexPatchContext
.outsidePointIndexPatchBase
;
1369 m_IndexPatchContext
.outsidePointIndexBadValue
= m_IndexPatchContext
.outsidePointIndexPatchBase
1370 + numPointsForOutsideEdge
[edge
] - 1;
1371 m_IndexPatchContext
.outsidePointIndexReplacementValue
= edge0OutsidePointBaseOffset
;
1372 SetUsingPatchedIndices(true);
1373 insideBaseOffset
= 0;
1374 outsideBaseOffset
= m_IndexPatchContext
.outsidePointIndexPatchBase
;
1378 insideBaseOffset
= insideEdgePointBaseOffset
;
1379 outsideBaseOffset
= outsideEdgePointBaseOffset
;
1381 if( ring
== startRing
)
1383 StitchTransition(/*baseIndexOffset: */m_NumIndices
,
1384 insideBaseOffset
,processedTessFactors
.insideTessFactorCtx
.numHalfTessFactorPoints
,processedTessFactors
.insideTessFactorParity
,
1385 outsideBaseOffset
,outsideTessFactorCtx
[edge
]->numHalfTessFactorPoints
,outsideTessFactorParity
[edge
]);
1389 StitchRegular(/*bTrapezoid*/true, DIAGONALS_MIRRORED
,
1390 /*baseIndexOffset: */m_NumIndices
,
1391 numPointsForInsideEdge
,
1392 insideBaseOffset
,outsideBaseOffset
);
1396 SetUsingPatchedIndices(false);
1398 m_NumIndices
+= numTriangles
*3;
1399 outsideEdgePointBaseOffset
+= numPointsForOutsideEdge
[edge
] - 1;
1400 insideEdgePointBaseOffset
+= numPointsForInsideEdge
- 1;
1401 numPointsForOutsideEdge
[edge
] = numPointsForInsideEdge
;
1403 if( startRing
== ring
)
1405 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1407 outsideTessFactorCtx
[edge
] = &processedTessFactors
.insideTessFactorCtx
;
1408 outsideTessFactorParity
[edge
] = processedTessFactors
.insideTessFactorParity
;
1414 // Triangulate center (a single triangle)
1415 DefineClockwiseTriangle(outsideEdgePointBaseOffset
, outsideEdgePointBaseOffset
+1, outsideEdgePointBaseOffset
+2,
1421 //---------------------------------------------------------------------------------------------------------------------------------
1422 // CHWTessellator::TessellateIsoLineDomain
1424 //---------------------------------------------------------------------------------------------------------------------------------
1425 void CHWTessellator::TessellateIsoLineDomain( float TessFactor_V_LineDensity
, float TessFactor_U_LineDetail
)
1427 PROCESSED_TESS_FACTORS_ISOLINE processedTessFactors
;
1428 IsoLineProcessTessFactors(TessFactor_V_LineDensity
,TessFactor_U_LineDetail
,processedTessFactors
);
1429 if( processedTessFactors
.bPatchCulled
)
1435 IsoLineGeneratePoints(processedTessFactors
);
1436 IsoLineGenerateConnectivity(processedTessFactors
); // can be done in parallel to IsoLineGeneratePoints
1439 //---------------------------------------------------------------------------------------------------------------------------------
1440 // CHWTessellator::IsoLineProcessTessFactors
1441 //---------------------------------------------------------------------------------------------------------------------------------
1442 void CHWTessellator::IsoLineProcessTessFactors( float TessFactor_V_LineDensity
, float TessFactor_U_LineDetail
,
1443 PROCESSED_TESS_FACTORS_ISOLINE
& processedTessFactors
)
1445 // Is the patch culled?
1446 if( !(TessFactor_V_LineDensity
> 0) || // NaN will pass
1447 !(TessFactor_U_LineDetail
> 0) )
1449 processedTessFactors
.bPatchCulled
= true;
1454 processedTessFactors
.bPatchCulled
= false;
1457 // Clamp edge TessFactors
1458 float lowerBound
= 0.0, upperBound
= 0.0;
1459 switch(m_originalPartitioning
)
1461 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
1462 case D3D11_TESSELLATOR_PARTITIONING_POW2
: // don�t care about pow2 distinction for validation, just treat as integer
1463 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1464 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1467 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
1468 lowerBound
= D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
;
1469 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1472 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
1473 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1474 upperBound
= D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
;
1478 TessFactor_V_LineDensity
= tess_fmin( D3D11_TESSELLATOR_MAX_ISOLINE_DENSITY_TESSELLATION_FACTOR
,
1479 tess_fmax( D3D11_TESSELLATOR_MIN_ISOLINE_DENSITY_TESSELLATION_FACTOR
, TessFactor_V_LineDensity
) );
1480 TessFactor_U_LineDetail
= tess_fmin( upperBound
, tess_fmax( lowerBound
, TessFactor_U_LineDetail
) );
1482 // Reset our vertex and index buffers. We have enough storage for the max tessFactor.
1486 // Process tessFactors
1487 if( HWIntegerPartitioning() )
1489 TessFactor_U_LineDetail
= ceil(TessFactor_U_LineDetail
);
1490 processedTessFactors
.lineDetailParity
= isEven(TessFactor_U_LineDetail
) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1494 processedTessFactors
.lineDetailParity
= m_originalParity
;
1497 FXP fxpTessFactor_U_LineDetail
= floatToFixed(TessFactor_U_LineDetail
);
1499 SetTessellationParity(processedTessFactors
.lineDetailParity
);
1501 ComputeTessFactorContext(fxpTessFactor_U_LineDetail
, processedTessFactors
.lineDetailTessFactorCtx
);
1502 processedTessFactors
.numPointsPerLine
= NumPointsForTessFactor(fxpTessFactor_U_LineDetail
);
1504 OverridePartitioning(D3D11_TESSELLATOR_PARTITIONING_INTEGER
);
1506 TessFactor_V_LineDensity
= ceil(TessFactor_V_LineDensity
);
1507 processedTessFactors
.lineDensityParity
= isEven(TessFactor_V_LineDensity
) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1508 SetTessellationParity(processedTessFactors
.lineDensityParity
);
1509 FXP fxpTessFactor_V_LineDensity
= floatToFixed(TessFactor_V_LineDensity
);
1510 ComputeTessFactorContext(fxpTessFactor_V_LineDensity
, processedTessFactors
.lineDensityTessFactorCtx
);
1512 processedTessFactors
.numLines
= NumPointsForTessFactor(fxpTessFactor_V_LineDensity
) - 1; // don't draw last line at V == 1.
1514 RestorePartitioning();
1516 // Compute some initial data.
1518 // outside edge offsets
1519 m_NumPoints
= processedTessFactors
.numPointsPerLine
* processedTessFactors
.numLines
;
1520 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
1522 m_NumIndices
= m_NumPoints
;
1526 m_NumIndices
= processedTessFactors
.numLines
*(processedTessFactors
.numPointsPerLine
-1)*2;
1530 //---------------------------------------------------------------------------------------------------------------------------------
1531 // CHWTessellator::IsoLineGeneratePoints
1532 //---------------------------------------------------------------------------------------------------------------------------------
1533 void CHWTessellator::IsoLineGeneratePoints( const PROCESSED_TESS_FACTORS_ISOLINE
& processedTessFactors
)
1535 int line
, pointOffset
;
1536 for(line
= 0, pointOffset
= 0; line
< processedTessFactors
.numLines
; line
++)
1538 for(int point
= 0; point
< processedTessFactors
.numPointsPerLine
; point
++)
1541 SetTessellationParity(processedTessFactors
.lineDensityParity
);
1542 PlacePointIn1D(processedTessFactors
.lineDensityTessFactorCtx
,line
,fxpV
);
1544 SetTessellationParity(processedTessFactors
.lineDetailParity
);
1545 PlacePointIn1D(processedTessFactors
.lineDetailTessFactorCtx
,point
,fxpU
);
1547 DefinePoint(fxpU
,fxpV
,pointOffset
++);
1552 //---------------------------------------------------------------------------------------------------------------------------------
1553 // CHWTessellator::IsoLineGenerateConnectivity
1554 //---------------------------------------------------------------------------------------------------------------------------------
1555 void CHWTessellator::IsoLineGenerateConnectivity( const PROCESSED_TESS_FACTORS_ISOLINE
& processedTessFactors
)
1557 int line
, pointOffset
, indexOffset
;
1558 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
1560 for(line
= 0, pointOffset
= 0, indexOffset
= 0; line
< processedTessFactors
.numLines
; line
++)
1562 for(int point
= 0; point
< processedTessFactors
.numPointsPerLine
; point
++)
1564 DefineIndex(pointOffset
++,indexOffset
++);
1570 for(line
= 0, pointOffset
= 0, indexOffset
= 0; line
< processedTessFactors
.numLines
; line
++)
1572 for(int point
= 0; point
< processedTessFactors
.numPointsPerLine
; point
++)
1576 DefineIndex(pointOffset
-1,indexOffset
++);
1577 DefineIndex(pointOffset
,indexOffset
++);
1585 //---------------------------------------------------------------------------------------------------------------------------------
1586 // CHWTessellator::GetPointCount
1588 //---------------------------------------------------------------------------------------------------------------------------------
1589 int CHWTessellator::GetPointCount()
1594 //---------------------------------------------------------------------------------------------------------------------------------
1595 // CHWTessellator::GetIndexCount()
1597 //---------------------------------------------------------------------------------------------------------------------------------
1598 int CHWTessellator::GetIndexCount()
1600 return m_NumIndices
;
1603 //---------------------------------------------------------------------------------------------------------------------------------
1604 // CHWTessellator::GetPoints()
1606 //---------------------------------------------------------------------------------------------------------------------------------
1607 DOMAIN_POINT
* CHWTessellator::GetPoints()
1611 //---------------------------------------------------------------------------------------------------------------------------------
1612 // CHWTessellator::GetIndices()
1614 //---------------------------------------------------------------------------------------------------------------------------------
1615 int* CHWTessellator::GetIndices()
1620 //---------------------------------------------------------------------------------------------------------------------------------
1621 // CHWTessellator::DefinePoint()
1622 //---------------------------------------------------------------------------------------------------------------------------------
1623 int CHWTessellator::DefinePoint(FXP fxpU
, FXP fxpV
, int pointStorageOffset
)
1626 // StringCchPrintf(foo,80,L"off:%d, uv=(%f,%f)\n",pointStorageOffset,fixedToFloat(fxpU),fixedToFloat(fxpV));
1627 // OutputDebugString(foo);
1628 m_Point
[pointStorageOffset
].u
= fixedToFloat(fxpU
);
1629 m_Point
[pointStorageOffset
].v
= fixedToFloat(fxpV
);
1630 return pointStorageOffset
;
1633 //---------------------------------------------------------------------------------------------------------------------------------
1634 // CHWTessellator::DefineIndex()
1635 //--------------------------------------------------------------------------------------------------------------------------------
1636 void CHWTessellator::DefineIndex(int index
, int indexStorageOffset
)
1638 index
= PatchIndexValue(index
);
1640 // StringCchPrintf(foo,80,L"off:%d, idx=%d, uv=(%f,%f)\n",indexStorageOffset,index,m_Point[index].u,m_Point[index].v);
1641 // OutputDebugString(foo);
1642 m_Index
[indexStorageOffset
] = index
;
1645 //---------------------------------------------------------------------------------------------------------------------------------
1646 // CHWTessellator::DefineClockwiseTriangle()
1647 //---------------------------------------------------------------------------------------------------------------------------------
1648 void CHWTessellator::DefineClockwiseTriangle(int index0
, int index1
, int index2
, int indexStorageBaseOffset
)
1650 // inputs a clockwise triangle, stores a CW or CCW triangle depending on the state
1651 DefineIndex(index0
,indexStorageBaseOffset
);
1652 bool bWantClockwise
= (m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CW
) ? true : false;
1653 if( bWantClockwise
)
1655 DefineIndex(index1
,indexStorageBaseOffset
+1);
1656 DefineIndex(index2
,indexStorageBaseOffset
+2);
1660 DefineIndex(index2
,indexStorageBaseOffset
+1);
1661 DefineIndex(index1
,indexStorageBaseOffset
+2);
1665 //---------------------------------------------------------------------------------------------------------------------------------
1666 // CHWTessellator::DumpAllPoints()
1667 //---------------------------------------------------------------------------------------------------------------------------------
1668 void CHWTessellator::DumpAllPoints()
1670 for( int p
= 0; p
< m_NumPoints
; p
++ )
1672 DefineIndex(p
,m_NumIndices
++);
1676 //---------------------------------------------------------------------------------------------------------------------------------
1677 // CHWTessellator::DumpAllPointsAsInOrderLineList()
1678 //---------------------------------------------------------------------------------------------------------------------------------
1679 void CHWTessellator::DumpAllPointsAsInOrderLineList()
1681 for( int p
= 1; p
< m_NumPoints
; p
++ )
1683 DefineIndex(p
-1,m_NumIndices
++);
1684 DefineIndex(p
,m_NumIndices
++);
1688 //---------------------------------------------------------------------------------------------------------------------------------
1690 //---------------------------------------------------------------------------------------------------------------------------------
1691 int RemoveMSB(int val
)
1694 if( val
<= 0x0000ffff ) { check
= ( val
<= 0x000000ff ) ? 0x00000080 : 0x00008000; }
1695 else { check
= ( val
<= 0x00ffffff ) ? 0x00800000 : 0x80000000; }
1696 for( int i
= 0; i
< 8; i
++, check
>>= 1 ) { if( val
& check
) return (val
& ~check
); }
1699 //---------------------------------------------------------------------------------------------------------------------------------
1701 //---------------------------------------------------------------------------------------------------------------------------------
1705 if( val
<= 0x0000ffff ) { check
= ( val
<= 0x000000ff ) ? 0x00000080 : 0x00008000; }
1706 else { check
= ( val
<= 0x00ffffff ) ? 0x00800000 : 0x80000000; }
1707 for( int i
= 0; i
< 8; i
++, check
>>= 1 ) { if( val
& check
) return check
; }
1711 //---------------------------------------------------------------------------------------------------------------------------------
1712 // CHWTessellator::CleanseParameter()
1713 //---------------------------------------------------------------------------------------------------------------------------------
1714 /* NOTHING TO DO FOR FIXED POINT ARITHMETIC!
1715 void CHWTessellator::CleanseParameter(float& parameter)
1717 // Clean up [0..1] parameter to guarantee that (1 - (1 - parameter)) == parameter.
1718 parameter = 1.0f - parameter;
1719 parameter = 1.0f - parameter;
1723 //---------------------------------------------------------------------------------------------------------------------------------
1724 // CHWTessellator::NumPointsForTessFactor()
1725 //---------------------------------------------------------------------------------------------------------------------------------
1726 int CHWTessellator::NumPointsForTessFactor( FXP fxpTessFactor
)
1731 numPoints
= (fxpCeil(FXP_ONE_HALF
+ (fxpTessFactor
+1/*round*/)/2)*2)>>FXP_FRACTION_BITS
;
1735 numPoints
= ((fxpCeil((fxpTessFactor
+1/*round*/)/2)*2)>>FXP_FRACTION_BITS
)+1;
1740 //---------------------------------------------------------------------------------------------------------------------------------
1741 // CHWTessellator::ComputeTessFactorContext()
1742 //---------------------------------------------------------------------------------------------------------------------------------
1743 void CHWTessellator::ComputeTessFactorContext( FXP fxpTessFactor
, TESS_FACTOR_CONTEXT
& TessFactorCtx
)
1745 FXP fxpHalfTessFactor
= (fxpTessFactor
+1/*round*/)/2;
1746 if( Odd() || (fxpHalfTessFactor
== FXP_ONE_HALF
)) // fxpHalfTessFactor == 1/2 if TessFactor is 1, but we're pretending we are even.
1748 fxpHalfTessFactor
+= FXP_ONE_HALF
;
1750 FXP fxpFloorHalfTessFactor
= fxpFloor(fxpHalfTessFactor
);
1751 FXP fxpCeilHalfTessFactor
= fxpCeil(fxpHalfTessFactor
);
1752 TessFactorCtx
.fxpHalfTessFactorFraction
= fxpHalfTessFactor
- fxpFloorHalfTessFactor
;
1753 //CleanseParameter(TessFactorCtx.fxpHalfTessFactorFraction);
1754 TessFactorCtx
.numHalfTessFactorPoints
= (fxpCeilHalfTessFactor
>>FXP_FRACTION_BITS
); // for EVEN, we don't include the point always fixed at the midpoint of the TessFactor
1755 if( fxpCeilHalfTessFactor
== fxpFloorHalfTessFactor
)
1757 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= /*pick value to cause this to be ignored*/ TessFactorCtx
.numHalfTessFactorPoints
+1;
1761 if( fxpFloorHalfTessFactor
== FXP_ONE
)
1763 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= 0;
1767 #ifdef ALLOW_XBOX_360_COMPARISON
1768 if( m_bXBox360Mode
)
1769 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= TessFactorCtx
.numHalfTessFactorPoints
-2;
1772 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= (RemoveMSB((fxpFloorHalfTessFactor
>>FXP_FRACTION_BITS
)-1)<<1) + 1;
1777 #ifdef ALLOW_XBOX_360_COMPARISON
1778 if( m_bXBox360Mode
)
1779 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= TessFactorCtx
.numHalfTessFactorPoints
-1;
1782 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= (RemoveMSB(fxpFloorHalfTessFactor
>>FXP_FRACTION_BITS
)<<1) + 1;
1784 int numFloorSegments
= (fxpFloorHalfTessFactor
* 2)>>FXP_FRACTION_BITS
;
1785 int numCeilSegments
= (fxpCeilHalfTessFactor
* 2)>>FXP_FRACTION_BITS
;
1788 numFloorSegments
-= 1;
1789 numCeilSegments
-= 1;
1791 TessFactorCtx
.fxpInvNumSegmentsOnFloorTessFactor
= s_fixedReciprocal
[numFloorSegments
];
1792 TessFactorCtx
.fxpInvNumSegmentsOnCeilTessFactor
= s_fixedReciprocal
[numCeilSegments
];
1795 //---------------------------------------------------------------------------------------------------------------------------------
1796 // CHWTessellator::PlacePointIn1D()
1797 //---------------------------------------------------------------------------------------------------------------------------------
1798 void CHWTessellator::PlacePointIn1D( const TESS_FACTOR_CONTEXT
& TessFactorCtx
, int point
, FXP
& fxpLocation
)
1801 if( point
>= TessFactorCtx
.numHalfTessFactorPoints
)
1803 point
= (TessFactorCtx
.numHalfTessFactorPoints
<< 1) - point
;
1814 if( point
== TessFactorCtx
.numHalfTessFactorPoints
)
1816 fxpLocation
= FXP_ONE_HALF
; // special casing middle since 16 bit fixed math below can't reproduce 0.5 exactly
1819 unsigned int indexOnCeilHalfTessFactor
= point
;
1820 unsigned int indexOnFloorHalfTessFactor
= indexOnCeilHalfTessFactor
;
1821 if( point
> TessFactorCtx
.splitPointOnFloorHalfTessFactor
)
1823 indexOnFloorHalfTessFactor
-= 1;
1825 // For the fixed point multiplies below, we know the results are <= 16 bits because
1826 // the locations on the halfTessFactor are <= half the number of segments for the total TessFactor.
1827 // So a number divided by a number that is at least twice as big will give
1828 // a result no bigger than 0.5 (which in fixed point is 16 bits in our case)
1829 FXP fxpLocationOnFloorHalfTessFactor
= indexOnFloorHalfTessFactor
* TessFactorCtx
.fxpInvNumSegmentsOnFloorTessFactor
;
1830 FXP fxpLocationOnCeilHalfTessFactor
= indexOnCeilHalfTessFactor
* TessFactorCtx
.fxpInvNumSegmentsOnCeilTessFactor
;
1832 // Since we know the numbers calculated above are <= fixed point 0.5, and the equation
1833 // below is just lerping between two values <= fixed point 0.5 (0x00008000), then we know
1834 // that the final result before shifting by 16 bits is no larger than 0x80000000. Once we
1835 // shift that down by 16, we get the result of lerping 2 numbers <= 0.5, which is obviously
1836 // at most 0.5 (0x00008000)
1837 fxpLocation
= fxpLocationOnFloorHalfTessFactor
* (FXP_ONE
- TessFactorCtx
.fxpHalfTessFactorFraction
) +
1838 fxpLocationOnCeilHalfTessFactor
* (TessFactorCtx
.fxpHalfTessFactorFraction
);
1839 fxpLocation
= (fxpLocation
+ FXP_ONE_HALF
/*round*/) >> FXP_FRACTION_BITS
; // get back to n.16
1840 /* Commenting out floating point version. Note the parameter cleansing it does is not needed in fixed point.
1842 location = 1.0f - location; // complement produces cleansed result.
1844 CleanseParameter(location);
1848 fxpLocation
= FXP_ONE
- fxpLocation
;
1852 //---------------------------------------------------------------------------------------------------------------------------------
1853 // CHWTessellator::StitchRegular
1854 //---------------------------------------------------------------------------------------------------------------------------------
1855 void CHWTessellator::StitchRegular(bool bTrapezoid
,DIAGONALS diagonals
,
1856 int baseIndexOffset
, int numInsideEdgePoints
,
1857 int insideEdgePointBaseOffset
, int outsideEdgePointBaseOffset
)
1859 int insidePoint
= insideEdgePointBaseOffset
;
1860 int outsidePoint
= outsideEdgePointBaseOffset
;
1863 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1864 baseIndexOffset
+= 3; outsidePoint
++;
1869 case DIAGONALS_INSIDE_TO_OUTSIDE
:
1870 // Diagonals pointing from inside edge forward towards outside edge
1871 for( p
= 0; p
< numInsideEdgePoints
-1; p
++ )
1873 DefineClockwiseTriangle(insidePoint
,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
1874 baseIndexOffset
+= 3;
1876 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1877 baseIndexOffset
+= 3;
1878 insidePoint
++; outsidePoint
++;
1881 case DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE
: // Assumes ODD tessellation
1882 // Diagonals pointing from outside edge forward towards inside edge
1885 for( p
= 0; p
< numInsideEdgePoints
/2-1; p
++ )
1887 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1888 baseIndexOffset
+= 3;
1889 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1890 baseIndexOffset
+= 3;
1891 insidePoint
++; outsidePoint
++;
1895 DefineClockwiseTriangle(outsidePoint
,insidePoint
+1,insidePoint
,baseIndexOffset
);
1896 baseIndexOffset
+= 3;
1897 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1898 baseIndexOffset
+= 3;
1899 insidePoint
++; outsidePoint
++; p
+=2;
1902 for( ; p
< numInsideEdgePoints
; p
++ )
1904 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1905 baseIndexOffset
+= 3;
1906 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1907 baseIndexOffset
+= 3;
1908 insidePoint
++; outsidePoint
++;
1911 case DIAGONALS_MIRRORED
:
1912 // First half, diagonals pointing from outside of outside edge to inside of inside edge
1913 for( p
= 0; p
< numInsideEdgePoints
/2; p
++ )
1915 DefineClockwiseTriangle(outsidePoint
,insidePoint
+1,insidePoint
,baseIndexOffset
);
1916 baseIndexOffset
+= 3;
1917 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1918 baseIndexOffset
+= 3;
1919 insidePoint
++; outsidePoint
++;
1921 // Second half, diagonals pointing from inside of inside edge to outside of outside edge
1922 for( ; p
< numInsideEdgePoints
-1; p
++ )
1924 DefineClockwiseTriangle(insidePoint
,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
1925 baseIndexOffset
+= 3;
1926 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1927 baseIndexOffset
+= 3;
1928 insidePoint
++; outsidePoint
++;
1934 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1935 baseIndexOffset
+= 3;
1939 //---------------------------------------------------------------------------------------------------------------------------------
1940 // CHWTessellator::StitchTransition()
1941 //---------------------------------------------------------------------------------------------------------------------------------
1942 void CHWTessellator::StitchTransition(int baseIndexOffset
,
1943 int insideEdgePointBaseOffset
, int insideNumHalfTessFactorPoints
,
1944 TESSELLATOR_PARITY insideEdgeTessFactorParity
,
1945 int outsideEdgePointBaseOffset
, int outsideNumHalfTessFactorPoints
,
1946 TESSELLATOR_PARITY outsideTessFactorParity
1950 #ifdef ALLOW_XBOX_360_COMPARISON
1951 // Tables to assist in the stitching of 2 rows of points having arbitrary TessFactors.
1952 // The stitching order is governed by Ruler Function vertex split ordering (see external documentation).
1954 // The contents of the finalPointPositionTable are where vertex i [0..32] ends up on the half-edge
1955 // at the max tessellation amount given ruler-function split order.
1956 // Recall the other half of an edge is mirrored, so we only need to deal with one half.
1957 // This table is used to decide when to advance a point on the interior or exterior.
1958 // It supports odd TessFactor up to 65 and even TessFactor up to 64.
1959 static const int _finalPointPositionTable
[33] =
1960 { 0, 32, 16, 8, 17, 4, 18, 9, 19, 2, 20, 10, 21, 5, 22, 11, 23,
1961 1, 24, 12, 25, 6, 26, 13, 27, 3, 28, 14, 29, 7, 30, 15, 31 };
1962 // The loopStart and loopEnd tables below just provide optimal loop bounds for the
1963 // stitching algorithm further below, for any given halfTssFactor.
1964 // There is probably a better way to encode this...
1966 // loopStart[halfTessFactor] encodes the FIRST entry other that [0] in finalPointPositionTable[] above which is
1967 // less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
1968 static const int _loopStart
[33] =
1969 {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};
1970 // loopStart[halfTessFactor] encodes the LAST entry in finalPointPositionTable[] above which is
1971 // less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
1972 static const int _loopEnd
[33] =
1973 {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};
1974 const int* finalPointPositionTable
;
1975 const int* loopStart
;
1977 if( m_bXBox360Mode
)
1979 // The XBox360 vertex introduction order is always from the center of the edge.
1980 // So the final positions of points on the half-edge are this trivial table.
1981 static const int XBOXfinalPointPositionTable
[33] =
1982 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
1983 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 };
1984 // loopStart and loopEnd (meaning described above) also become trivial for XBox360 splitting.
1985 static const int XBOXloopStart
[33] =
1986 {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};
1987 static const int XBOXloopEnd
[33] =
1988 {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};
1990 finalPointPositionTable
= XBOXfinalPointPositionTable
;
1991 loopStart
= XBOXloopStart
;
1992 loopEnd
= XBOXloopEnd
;
1996 finalPointPositionTable
= _finalPointPositionTable
;
1997 loopStart
= _loopStart
;
2001 // Tables to assist in the stitching of 2 rows of points having arbitrary TessFactors.
2002 // The stitching order is governed by Ruler Function vertex split ordering (see external documentation).
2004 // The contents of the finalPointPositionTable are where vertex i [0..33] ends up on the half-edge
2005 // at the max tessellation amount given ruler-function split order.
2006 // Recall the other half of an edge is mirrored, so we only need to deal with one half.
2007 // This table is used to decide when to advance a point on the interior or exterior.
2008 // It supports odd TessFactor up to 65 and even TessFactor up to 64.
2009 static const int finalPointPositionTable
[33] =
2010 { 0, 32, 16, 8, 17, 4, 18, 9, 19, 2, 20, 10, 21, 5, 22, 11, 23,
2011 1, 24, 12, 25, 6, 26, 13, 27, 3, 28, 14, 29, 7, 30, 15, 31 };
2013 // The loopStart and loopEnd tables below just provide optimal loop bounds for the
2014 // stitching algorithm further below, for any given halfTssFactor.
2015 // There is probably a better way to encode this...
2017 // loopStart[halfTessFactor] encodes the FIRST entry in finalPointPositionTable[] above which is
2018 // less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
2019 static const int loopStart
[33] =
2020 {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};
2021 // loopStart[halfTessFactor] encodes the LAST entry in finalPointPositionTable[] above which is
2022 // less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
2023 static const int loopEnd
[33] =
2024 {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};
2026 if( TESSELLATOR_PARITY_ODD
== insideEdgeTessFactorParity
)
2028 insideNumHalfTessFactorPoints
-= 1;
2030 if( TESSELLATOR_PARITY_ODD
== outsideTessFactorParity
)
2032 outsideNumHalfTessFactorPoints
-= 1;
2035 int outsidePoint
= outsideEdgePointBaseOffset
;
2036 int insidePoint
= insideEdgePointBaseOffset
;
2038 // iStart,iEnd are a small optimization so the loop below doesn't have to go from 0 up to 31
2039 int iStart
= min(loopStart
[insideNumHalfTessFactorPoints
],loopStart
[outsideNumHalfTessFactorPoints
]);
2040 int iEnd
= max(loopEnd
[insideNumHalfTessFactorPoints
],loopEnd
[outsideNumHalfTessFactorPoints
]);
2042 if( finalPointPositionTable
[0] < outsideNumHalfTessFactorPoints
) // since we dont' start the loop at 0 below, we need a special case.
2045 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2046 baseIndexOffset
+= 3; outsidePoint
++;
2049 for(int i
= iStart
; i
<= iEnd
; i
++)
2051 if( /*(i>0) && <-- not needed since iStart is never 0*/(finalPointPositionTable
[i
] < insideNumHalfTessFactorPoints
))
2054 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2055 baseIndexOffset
+= 3; insidePoint
++;
2057 if((finalPointPositionTable
[i
] < outsideNumHalfTessFactorPoints
))
2060 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2061 baseIndexOffset
+= 3; outsidePoint
++;
2065 if( (insideEdgeTessFactorParity
!= outsideTessFactorParity
) || (insideEdgeTessFactorParity
== TESSELLATOR_PARITY_ODD
))
2067 if( insideEdgeTessFactorParity
== outsideTessFactorParity
)
2069 // Quad in the middle
2070 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2071 baseIndexOffset
+= 3;
2072 DefineClockwiseTriangle(insidePoint
+1,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
2073 baseIndexOffset
+= 3;
2077 else if( TESSELLATOR_PARITY_EVEN
== insideEdgeTessFactorParity
)
2079 // Triangle pointing inside
2080 DefineClockwiseTriangle(insidePoint
,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
2081 baseIndexOffset
+= 3;
2086 // Triangle pointing outside
2087 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2088 baseIndexOffset
+= 3;
2093 // Walk second half.
2094 for(int i
= iEnd
; i
>= iStart
; i
--)
2096 if((finalPointPositionTable
[i
] < outsideNumHalfTessFactorPoints
))
2099 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2100 baseIndexOffset
+= 3; outsidePoint
++;
2102 if( /*(i>0) && <-- not needed since iStart is never 0*/ (finalPointPositionTable
[i
] < insideNumHalfTessFactorPoints
))
2105 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2106 baseIndexOffset
+= 3; insidePoint
++;
2109 // Below case is not needed if we didn't optimize loop above and made it run from 31 down to 0.
2110 if((finalPointPositionTable
[0] < outsideNumHalfTessFactorPoints
))
2112 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2113 baseIndexOffset
+= 3; outsidePoint
++;
2117 //---------------------------------------------------------------------------------------------------------------------------------
2118 // CHWTessellator::PatchIndexValue()
2119 //--------------------------------------------------------------------------------------------------------------------------------
2120 int CHWTessellator::PatchIndexValue(int index
)
2122 if( m_bUsingPatchedIndices
)
2124 if( index
>= m_IndexPatchContext
.outsidePointIndexPatchBase
) // assumed remapped outide indices are > remapped inside vertices
2126 if( index
== m_IndexPatchContext
.outsidePointIndexBadValue
)
2127 index
= m_IndexPatchContext
.outsidePointIndexReplacementValue
;
2129 index
+= m_IndexPatchContext
.outsidePointIndexDeltaToRealValue
;
2133 if( index
== m_IndexPatchContext
.insidePointIndexBadValue
)
2134 index
= m_IndexPatchContext
.insidePointIndexReplacementValue
;
2136 index
+= m_IndexPatchContext
.insidePointIndexDeltaToRealValue
;
2139 else if( m_bUsingPatchedIndices2
)
2141 if( index
>= m_IndexPatchContext2
.baseIndexToInvert
)
2143 if( index
== m_IndexPatchContext2
.cornerCaseBadValue
)
2145 index
= m_IndexPatchContext2
.cornerCaseReplacementValue
;
2149 index
= m_IndexPatchContext2
.indexInversionEndPoint
- index
;
2152 else if( index
== m_IndexPatchContext2
.cornerCaseBadValue
)
2154 index
= m_IndexPatchContext2
.cornerCaseReplacementValue
;
2161 //=================================================================================================================================
2163 //=================================================================================================================================
2165 //---------------------------------------------------------------------------------------------------------------------------------
2166 // CHLSLTessellator::CHLSLTessellator
2167 //---------------------------------------------------------------------------------------------------------------------------------
2168 CHLSLTessellator::CHLSLTessellator()
2170 m_LastComputedTessFactors
[0] = m_LastComputedTessFactors
[1] = m_LastComputedTessFactors
[2] =
2171 m_LastComputedTessFactors
[3] = m_LastComputedTessFactors
[4] = m_LastComputedTessFactors
[5] = 0;
2174 //---------------------------------------------------------------------------------------------------------------------------------
2175 // CHLSLTessellator::Init
2177 //---------------------------------------------------------------------------------------------------------------------------------
2178 void CHLSLTessellator::Init(
2179 D3D11_TESSELLATOR_PARTITIONING partitioning
,
2180 D3D11_TESSELLATOR_REDUCTION insideTessFactorReduction
,
2181 D3D11_TESSELLATOR_QUAD_REDUCTION_AXIS quadInsideTessFactorReductionAxis
,
2182 D3D11_TESSELLATOR_OUTPUT_PRIMITIVE outputPrimitive
)
2184 CHWTessellator::Init(partitioning
,outputPrimitive
);
2185 m_LastComputedTessFactors
[0] = m_LastComputedTessFactors
[1] = m_LastComputedTessFactors
[2] =
2186 m_LastComputedTessFactors
[3] = m_LastComputedTessFactors
[4] = m_LastComputedTessFactors
[5] = 0;
2187 m_partitioning
= partitioning
;
2188 m_originalPartitioning
= partitioning
;
2189 switch( partitioning
)
2191 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
2194 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
2195 m_parity
= TESSELLATOR_PARITY_ODD
;
2197 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
2198 m_parity
= TESSELLATOR_PARITY_EVEN
;
2201 m_originalParity
= m_parity
;
2202 m_outputPrimitive
= outputPrimitive
;
2203 m_insideTessFactorReduction
= insideTessFactorReduction
;
2204 m_quadInsideTessFactorReductionAxis
= quadInsideTessFactorReductionAxis
;
2206 //---------------------------------------------------------------------------------------------------------------------------------
2207 // CHLSLTessellator::TessellateQuadDomain
2209 //---------------------------------------------------------------------------------------------------------------------------------
2210 void CHLSLTessellator::TessellateQuadDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
2211 float insideTessFactorScaleU
, float insideTessFactorScaleV
)
2213 QuadHLSLProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Ueq1
,tessFactor_Veq1
,insideTessFactorScaleU
,insideTessFactorScaleV
);
2215 CHWTessellator::TessellateQuadDomain(m_LastComputedTessFactors
[0],m_LastComputedTessFactors
[1],m_LastComputedTessFactors
[2],m_LastComputedTessFactors
[3],
2216 m_LastComputedTessFactors
[4],m_LastComputedTessFactors
[5]);
2219 //---------------------------------------------------------------------------------------------------------------------------------
2220 // CHLSLTessellator::QuadHLSLProcessTessFactors
2221 //---------------------------------------------------------------------------------------------------------------------------------
2222 void CHLSLTessellator::QuadHLSLProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
2223 float insideTessFactorScaleU
, float insideTessFactorScaleV
)
2225 if( !(tessFactor_Ueq0
> 0) ||// NaN will pass
2226 !(tessFactor_Veq0
> 0) ||
2227 !(tessFactor_Ueq1
> 0) ||
2228 !(tessFactor_Veq1
> 0) )
2230 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2231 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2232 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Ueq1
;
2233 m_LastUnRoundedComputedTessFactors
[3] = tessFactor_Veq1
;
2234 m_LastUnRoundedComputedTessFactors
[4] = 0;
2235 m_LastUnRoundedComputedTessFactors
[5] = 0;
2236 m_LastComputedTessFactors
[0] =
2237 m_LastComputedTessFactors
[1] =
2238 m_LastComputedTessFactors
[2] =
2239 m_LastComputedTessFactors
[3] =
2240 m_LastComputedTessFactors
[4] =
2241 m_LastComputedTessFactors
[5] = 0;
2245 CleanupFloatTessFactor(tessFactor_Ueq0
);// clamp to [1.0f..INF], NaN->1.0f
2246 CleanupFloatTessFactor(tessFactor_Veq0
);
2247 CleanupFloatTessFactor(tessFactor_Ueq1
);
2248 CleanupFloatTessFactor(tessFactor_Veq1
);
2250 // Save off tessFactors so they can be returned to app
2251 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2252 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2253 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Ueq1
;
2254 m_LastUnRoundedComputedTessFactors
[3] = tessFactor_Veq1
;
2256 // Process outside tessFactors
2257 float outsideTessFactor
[QUAD_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Ueq1
, tessFactor_Veq1
};
2259 TESSELLATOR_PARITY insideTessFactorParity
[QUAD_AXES
];
2260 if( Pow2Partitioning() || IntegerPartitioning() )
2262 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
2264 RoundUpTessFactor(outsideTessFactor
[edge
]);
2265 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2270 SetTessellationParity(m_originalParity
); // ClampTessFactor needs it
2271 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
2273 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2277 // Compute inside TessFactors
2278 float insideTessFactor
[QUAD_AXES
];
2279 if( m_quadInsideTessFactorReductionAxis
== D3D11_TESSELLATOR_QUAD_REDUCTION_1_AXIS
)
2281 switch( m_insideTessFactorReduction
)
2283 case D3D11_TESSELLATOR_REDUCTION_MIN
:
2284 insideTessFactor
[U
] = tess_fmin(tess_fmin(tessFactor_Veq0
,tessFactor_Veq1
),tess_fmin(tessFactor_Ueq0
,tessFactor_Ueq1
));
2286 case D3D11_TESSELLATOR_REDUCTION_MAX
:
2287 insideTessFactor
[U
] = tess_fmax(tess_fmax(tessFactor_Veq0
,tessFactor_Veq1
),tess_fmax(tessFactor_Ueq0
,tessFactor_Ueq1
));
2289 case D3D11_TESSELLATOR_REDUCTION_AVERAGE
:
2290 insideTessFactor
[U
] = (tessFactor_Veq0
+ tessFactor_Veq1
+ tessFactor_Ueq0
+ tessFactor_Ueq1
) / 4;
2293 // Scale inside tessFactor based on user scale factor.
2295 ClampFloatTessFactorScale(insideTessFactorScaleU
); // clamp scale value to [0..1], NaN->0
2296 insideTessFactor
[U
] = insideTessFactor
[U
]*insideTessFactorScaleU
;
2298 // Compute inside parity
2299 if( Pow2Partitioning() || IntegerPartitioning() )
2301 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction + scale result that is based on unbounded user input
2302 m_LastUnRoundedComputedTessFactors
[4] = m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2303 RoundUpTessFactor(insideTessFactor
[U
]);
2304 insideTessFactorParity
[U
] =
2305 insideTessFactorParity
[V
] =
2306 (isEven(insideTessFactor
[U
]) || (FLOAT_ONE
== insideTessFactor
[U
]) )
2307 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2311 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction + scale result that is based on unbounded user input
2312 m_LastUnRoundedComputedTessFactors
[4] = m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2313 // no parity changes for fractional tessellation - just use what the user requested
2314 insideTessFactorParity
[U
] = insideTessFactorParity
[V
] = m_originalParity
;
2317 // To prevent snapping on edges, the "picture frame" comes
2318 // in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2319 if( (TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[U
]) &&
2320 (insideTessFactor
[U
] < FLOAT_THREE
) )
2322 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2324 insideTessFactor
[U
] = tess_fmin(FLOAT_THREE
,tess_fmax(tess_fmax(tessFactor_Veq0
,tessFactor_Veq1
),tess_fmax(tessFactor_Ueq0
,tessFactor_Ueq1
)));
2328 insideTessFactor
[U
] = tess_fmin(FLOAT_THREE
,(tessFactor_Veq0
+ tessFactor_Veq1
+ tessFactor_Ueq0
+ tessFactor_Ueq1
) / 4);
2330 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction result that is based on unbounded user input
2331 m_LastUnRoundedComputedTessFactors
[4] = m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2332 if( IntegerPartitioning())
2334 RoundUpTessFactor(insideTessFactor
[U
]);
2335 insideTessFactorParity
[U
] =
2336 insideTessFactorParity
[V
] = isEven(insideTessFactor
[U
]) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2339 insideTessFactor
[V
] = insideTessFactor
[U
];
2343 switch( m_insideTessFactorReduction
)
2345 case D3D11_TESSELLATOR_REDUCTION_MIN
:
2346 insideTessFactor
[U
] = tess_fmin(tessFactor_Veq0
,tessFactor_Veq1
);
2347 insideTessFactor
[V
] = tess_fmin(tessFactor_Ueq0
,tessFactor_Ueq1
);
2349 case D3D11_TESSELLATOR_REDUCTION_MAX
:
2350 insideTessFactor
[U
] = tess_fmax(tessFactor_Veq0
,tessFactor_Veq1
);
2351 insideTessFactor
[V
] = tess_fmax(tessFactor_Ueq0
,tessFactor_Ueq1
);
2353 case D3D11_TESSELLATOR_REDUCTION_AVERAGE
:
2354 insideTessFactor
[U
] = (tessFactor_Veq0
+ tessFactor_Veq1
) / 2;
2355 insideTessFactor
[V
] = (tessFactor_Ueq0
+ tessFactor_Ueq1
) / 2;
2358 // Scale inside tessFactors based on user scale factor.
2360 ClampFloatTessFactorScale(insideTessFactorScaleU
); // clamp scale value to [0..1], NaN->0
2361 ClampFloatTessFactorScale(insideTessFactorScaleV
);
2362 insideTessFactor
[U
] = insideTessFactor
[U
]*insideTessFactorScaleU
;
2363 insideTessFactor
[V
] = insideTessFactor
[V
]*insideTessFactorScaleV
;
2365 // Compute inside parity
2366 if( Pow2Partitioning() || IntegerPartitioning() )
2368 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
2370 ClampTessFactor(insideTessFactor
[axis
]); // clamp reduction + scale result that is based on unbounded user input
2371 m_LastUnRoundedComputedTessFactors
[4+axis
] = insideTessFactor
[axis
]; // Save off TessFactors so they can be returned to app
2372 RoundUpTessFactor(insideTessFactor
[axis
]);
2373 insideTessFactorParity
[axis
] =
2374 (isEven(insideTessFactor
[axis
]) || (FLOAT_ONE
== insideTessFactor
[axis
]) )
2375 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2380 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction + scale result that is based on unbounded user input
2381 ClampTessFactor(insideTessFactor
[V
]); // clamp reduction + scale 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 m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[V
]; // Save off TessFactors so they can be returned to app
2384 // no parity changes for fractional tessellation - just use what the user requested
2385 insideTessFactorParity
[U
] = insideTessFactorParity
[V
] = m_originalParity
;
2388 // To prevent snapping on edges, the "picture frame" comes
2389 // in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2390 if( (TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[U
]) &&
2391 (insideTessFactor
[U
] < FLOAT_THREE
) )
2393 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2395 insideTessFactor
[U
] = tess_fmin(FLOAT_THREE
,tess_fmax(tessFactor_Veq0
,tessFactor_Veq1
));
2399 insideTessFactor
[U
] = tess_fmin(FLOAT_THREE
,(tessFactor_Veq0
+ tessFactor_Veq1
) / 2);
2401 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction result that is based on unbounded user input
2402 m_LastUnRoundedComputedTessFactors
[4] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2403 if( IntegerPartitioning())
2405 RoundUpTessFactor(insideTessFactor
[U
]);
2406 insideTessFactorParity
[U
] = isEven(insideTessFactor
[U
]) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2410 if( (TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[V
]) &&
2411 (insideTessFactor
[V
] < FLOAT_THREE
) )
2413 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2415 insideTessFactor
[V
] = tess_fmin(FLOAT_THREE
,tess_fmax(tessFactor_Ueq0
,tessFactor_Ueq1
));
2419 insideTessFactor
[V
] = tess_fmin(FLOAT_THREE
,(tessFactor_Ueq0
+ tessFactor_Ueq1
) / 2);
2421 ClampTessFactor(insideTessFactor
[V
]);// clamp reduction result that is based on unbounded user input
2422 m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[V
]; // Save off TessFactors so they can be returned to app
2423 if( IntegerPartitioning())
2425 RoundUpTessFactor(insideTessFactor
[V
]);
2426 insideTessFactorParity
[V
] = isEven(insideTessFactor
[V
]) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2430 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
2432 if( TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[axis
] )
2434 // Ensure the first ring ("picture frame") interpolates in on all sides
2435 // as much as the side with the minimum TessFactor. Prevents snapping to edge.
2436 if( (insideTessFactor
[axis
] < FLOAT_THREE
) && (insideTessFactor
[axis
] < insideTessFactor
[(axis
+1)&0x1]))
2438 insideTessFactor
[axis
] = tess_fmin(insideTessFactor
[(axis
+1)&0x1],FLOAT_THREE
);
2439 m_LastUnRoundedComputedTessFactors
[4+axis
] = insideTessFactor
[axis
]; // Save off TessFactors so they can be returned to app
2445 // Save off TessFactors so they can be returned to app
2446 m_LastComputedTessFactors
[0] = outsideTessFactor
[Ueq0
];
2447 m_LastComputedTessFactors
[1] = outsideTessFactor
[Veq0
];
2448 m_LastComputedTessFactors
[2] = outsideTessFactor
[Ueq1
];
2449 m_LastComputedTessFactors
[3] = outsideTessFactor
[Veq1
];
2450 m_LastComputedTessFactors
[4] = insideTessFactor
[U
];
2451 m_LastComputedTessFactors
[5] = insideTessFactor
[V
];
2454 //---------------------------------------------------------------------------------------------------------------------------------
2455 // CHLSLTessellator::TessellateTriDomain
2457 //---------------------------------------------------------------------------------------------------------------------------------
2458 void CHLSLTessellator::TessellateTriDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
2459 float insideTessFactorScale
)
2461 TriHLSLProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Weq0
,insideTessFactorScale
);
2463 CHWTessellator::TessellateTriDomain(m_LastComputedTessFactors
[0],m_LastComputedTessFactors
[1],m_LastComputedTessFactors
[2],m_LastComputedTessFactors
[3]);
2466 //---------------------------------------------------------------------------------------------------------------------------------
2467 // CHLSLTessellator::TriHLSLProcessTessFactors
2468 //---------------------------------------------------------------------------------------------------------------------------------
2469 void CHLSLTessellator::TriHLSLProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
2470 float insideTessFactorScale
)
2472 if( !(tessFactor_Ueq0
> 0) || // NaN will pass
2473 !(tessFactor_Veq0
> 0) ||
2474 !(tessFactor_Weq0
> 0) )
2476 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2477 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2478 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Weq0
;
2479 m_LastUnRoundedComputedTessFactors
[3] =
2480 m_LastComputedTessFactors
[0] =
2481 m_LastComputedTessFactors
[1] =
2482 m_LastComputedTessFactors
[2] =
2483 m_LastComputedTessFactors
[3] = 0;
2487 CleanupFloatTessFactor(tessFactor_Ueq0
); // clamp to [1.0f..INF], NaN->1.0f
2488 CleanupFloatTessFactor(tessFactor_Veq0
);
2489 CleanupFloatTessFactor(tessFactor_Weq0
);
2491 // Save off TessFactors so they can be returned to app
2492 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2493 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2494 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Weq0
;
2496 // Process outside TessFactors
2497 float outsideTessFactor
[TRI_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Weq0
};
2499 if( Pow2Partitioning() || IntegerPartitioning() )
2501 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
2503 RoundUpTessFactor(outsideTessFactor
[edge
]); // for pow2 this rounds to pow2
2504 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2509 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
2511 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2515 // Compute inside TessFactor
2516 float insideTessFactor
;
2517 switch( m_insideTessFactorReduction
)
2519 case D3D11_TESSELLATOR_REDUCTION_MIN
:
2520 insideTessFactor
= tess_fmin(tess_fmin(tessFactor_Ueq0
,tessFactor_Veq0
),tessFactor_Weq0
);
2522 case D3D11_TESSELLATOR_REDUCTION_MAX
:
2523 insideTessFactor
= tess_fmax(tess_fmax(tessFactor_Ueq0
,tessFactor_Veq0
),tessFactor_Weq0
);
2525 case D3D11_TESSELLATOR_REDUCTION_AVERAGE
:
2526 insideTessFactor
= (tessFactor_Ueq0
+ tessFactor_Veq0
+ tessFactor_Weq0
) / 3;
2530 // Scale inside TessFactor based on user scale factor.
2531 ClampFloatTessFactorScale(insideTessFactorScale
); // clamp scale value to [0..1], NaN->0
2532 insideTessFactor
= insideTessFactor
*tess_fmin(FLOAT_ONE
,insideTessFactorScale
);
2534 ClampTessFactor(insideTessFactor
); // clamp reduction + scale result that is based on unbounded user input
2535 m_LastUnRoundedComputedTessFactors
[3] = insideTessFactor
;// Save off TessFactors so they can be returned to app
2536 TESSELLATOR_PARITY parity
;
2537 if( Pow2Partitioning() || IntegerPartitioning() )
2539 RoundUpTessFactor(insideTessFactor
);
2540 parity
= (isEven(insideTessFactor
) || (FLOAT_ONE
== insideTessFactor
))
2541 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2545 parity
= m_originalParity
;
2548 if( (TESSELLATOR_PARITY_ODD
== parity
) &&
2549 (insideTessFactor
< FLOAT_THREE
))
2551 // To prevent snapping on edges, the "picture frame" comes
2552 // in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2553 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2555 insideTessFactor
= tess_fmin(FLOAT_THREE
,tess_fmax(tessFactor_Ueq0
,tess_fmax(tessFactor_Veq0
,tessFactor_Weq0
)));
2559 insideTessFactor
= tess_fmin(FLOAT_THREE
,(tessFactor_Ueq0
+ tessFactor_Veq0
+ tessFactor_Weq0
) / 3);
2561 ClampTessFactor(insideTessFactor
); // clamp reduction result that is based on unbounded user input
2562 m_LastUnRoundedComputedTessFactors
[3] = insideTessFactor
;// Save off TessFactors so they can be returned to app
2563 if( IntegerPartitioning())
2565 RoundUpTessFactor(insideTessFactor
);
2569 // Save off TessFactors so they can be returned to app
2570 m_LastComputedTessFactors
[0] = outsideTessFactor
[Ueq0
];
2571 m_LastComputedTessFactors
[1] = outsideTessFactor
[Veq0
];
2572 m_LastComputedTessFactors
[2] = outsideTessFactor
[Weq0
];
2573 m_LastComputedTessFactors
[3] = insideTessFactor
;
2576 //---------------------------------------------------------------------------------------------------------------------------------
2577 // CHLSLTessellator::TessellateIsoLineDomain
2579 //---------------------------------------------------------------------------------------------------------------------------------
2580 void CHLSLTessellator::TessellateIsoLineDomain( float TessFactor_U_LineDetail
, float TessFactor_V_LineDensity
)
2582 IsoLineHLSLProcessTessFactors(TessFactor_V_LineDensity
,TessFactor_U_LineDetail
);
2583 CHWTessellator::TessellateIsoLineDomain(m_LastComputedTessFactors
[0],m_LastComputedTessFactors
[1]);
2586 //---------------------------------------------------------------------------------------------------------------------------------
2587 // CHLSLTessellator::IsoLineHLSLProcessTessFactors
2588 //---------------------------------------------------------------------------------------------------------------------------------
2589 void CHLSLTessellator::IsoLineHLSLProcessTessFactors( float TessFactor_V_LineDensity
, float TessFactor_U_LineDetail
)
2591 if( !(TessFactor_V_LineDensity
> 0) || // NaN will pass
2592 !(TessFactor_U_LineDetail
> 0) )
2594 m_LastUnRoundedComputedTessFactors
[0] = TessFactor_V_LineDensity
;
2595 m_LastUnRoundedComputedTessFactors
[1] = TessFactor_U_LineDetail
;
2596 m_LastComputedTessFactors
[0] =
2597 m_LastComputedTessFactors
[1] = 0;
2601 CleanupFloatTessFactor(TessFactor_V_LineDensity
); // clamp to [1.0f..INF], NaN->1.0f
2602 CleanupFloatTessFactor(TessFactor_U_LineDetail
); // clamp to [1.0f..INF], NaN->1.0f
2604 ClampTessFactor(TessFactor_U_LineDetail
); // clamp unbounded user input based on tessellation mode
2606 m_LastUnRoundedComputedTessFactors
[1] = TessFactor_U_LineDetail
; // Save off TessFactors so they can be returned to app
2608 if(Pow2Partitioning()||IntegerPartitioning())
2610 RoundUpTessFactor(TessFactor_U_LineDetail
);
2613 OverridePartitioning(D3D11_TESSELLATOR_PARTITIONING_INTEGER
);
2615 ClampTessFactor(TessFactor_V_LineDensity
); // Clamp unbounded user input to integer
2616 m_LastUnRoundedComputedTessFactors
[0] = TessFactor_V_LineDensity
; // Save off TessFactors so they can be returned to app
2618 RoundUpTessFactor(TessFactor_V_LineDensity
);
2620 RestorePartitioning();
2622 // Save off TessFactors so they can be returned to app
2623 m_LastComputedTessFactors
[0] = TessFactor_V_LineDensity
;
2624 m_LastComputedTessFactors
[1] = TessFactor_U_LineDetail
;
2627 //---------------------------------------------------------------------------------------------------------------------------------
2628 // CHLSLTessellator::ClampTessFactor()
2629 //---------------------------------------------------------------------------------------------------------------------------------
2630 void CHLSLTessellator::ClampTessFactor(float& TessFactor
)
2632 if( Pow2Partitioning() )
2634 TessFactor
= tess_fmin( D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
, tess_fmax( TessFactor
, D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
) );
2636 else if( IntegerPartitioning() )
2638 TessFactor
= tess_fmin( D3D11_TESSELLATOR_MAX_TESSELLATION_FACTOR
, tess_fmax( TessFactor
, D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
) );
2642 TessFactor
= tess_fmin( D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
, tess_fmax( TessFactor
, D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
) );
2646 TessFactor
= tess_fmin( D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
, tess_fmax( TessFactor
, D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
) );
2650 //---------------------------------------------------------------------------------------------------------------------------------
2651 // CHLSLTessellator::CleanupFloatTessFactor()
2652 //---------------------------------------------------------------------------------------------------------------------------------
2653 static const int exponentMask
= 0x7f800000;
2654 static const int mantissaMask
= 0x007fffff;
2655 void CHLSLTessellator::CleanupFloatTessFactor(float& input
)
2657 // If input is < 1.0f or NaN, clamp to 1.0f.
2658 // In other words, clamp input to [1.0f...+INF]
2659 int bits
= *(int*)&input
;
2660 if( ( ( ( bits
& exponentMask
) == exponentMask
) && ( bits
& mantissaMask
) ) ||// nan?
2667 //---------------------------------------------------------------------------------------------------------------------------------
2668 // CHLSLTessellator::ClampFloatTessFactorScale()
2669 //---------------------------------------------------------------------------------------------------------------------------------
2670 void CHLSLTessellator::ClampFloatTessFactorScale(float& input
)
2672 // If input is < 0.0f or NaN, clamp to 0.0f. > 1 clamps to 1.
2673 // In other words, clamp input to [0.0f...1.0f]
2674 int bits
= *(int*)&input
;
2675 if( ( ( ( bits
& exponentMask
) == exponentMask
) && ( bits
& mantissaMask
) ) ||// nan?
2680 else if( input
> 1 )
2686 //---------------------------------------------------------------------------------------------------------------------------------
2687 // CHLSLTessellator::RoundUpTessFactor()
2688 //---------------------------------------------------------------------------------------------------------------------------------
2689 static const int exponentLSB
= 0x00800000;
2690 void CHLSLTessellator::RoundUpTessFactor(float& TessFactor
)
2692 // Assume TessFactor is in [1.0f..+INF]
2693 if( Pow2Partitioning() )
2695 int bits
= *(int*)&TessFactor
;
2696 if( bits
& mantissaMask
)
2698 *(int*)&TessFactor
= (bits
& exponentMask
) + exponentLSB
;
2701 else if( IntegerPartitioning() )
2703 TessFactor
= ceil(TessFactor
);