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(_WIN32) || defined(_WIN64)
22 #include <math.h> // ceil
26 //#include <windows.h> // Just used for some commented out debug stat printing.
27 //#include <strsafe.h> // Ditto.
28 #define min(x,y) (x < y ? x : y)
29 #define max(x,y) (x > y ? x : y)
31 //=================================================================================================================================
32 // Some D3D Compliant Float Math (reference rasterizer implements these in RefALU class)
33 //=================================================================================================================================
35 //---------------------------------------------------------------------------------------------------------------------------------
37 //---------------------------------------------------------------------------------------------------------------------------------
40 static const int exponentMask
= 0x7f800000;
41 static const int mantissaMask
= 0x007fffff;
43 return ( ( ( u
& exponentMask
) == exponentMask
) && ( u
& mantissaMask
) ); // NaN
46 //---------------------------------------------------------------------------------------------------------------------------------
48 //---------------------------------------------------------------------------------------------------------------------------------
49 float flush( float a
)
51 static const int minNormalizedFloat
= 0x00800000;
52 static const int signBit
= 0x80000000;
53 static const int signBitComplement
= 0x7fffffff;
54 int b
= (*(int*)&a
) & signBitComplement
; // fabs()
55 if( b
< minNormalizedFloat
) // UINT comparison. NaN/INF do test false here
57 b
= signBit
& (*(int*)&a
);
63 //---------------------------------------------------------------------------------------------------------------------------------
65 //---------------------------------------------------------------------------------------------------------------------------------
66 float fmin( float a
, float b
)
68 float _a
= flush( a
);
69 float _b
= flush( b
);
74 else if( ( _a
== 0 ) && ( _b
== 0 ) )
76 return ( (*(int*)&_a
) & 0x80000000 ) ? a
: b
;
78 return _a
< _b
? a
: b
;
81 //---------------------------------------------------------------------------------------------------------------------------------
83 //---------------------------------------------------------------------------------------------------------------------------------
84 float fmax( float a
, float b
)
86 float _a
= flush( a
);
87 float _b
= flush( b
);
93 else if( ( _a
== 0 ) && ( _b
== 0 ) )
95 return ( (*(int*)&_b
) & 0x80000000 ) ? a
: b
;
97 return _a
>= _b
? a
: b
;
100 //=================================================================================================================================
102 //=================================================================================================================================
104 //-----------------------------------------------------------------------------------------------------------------------------
107 // Convert 32-bit float to 32-bit fixed point integer, using only
108 // integer arithmetic + bitwise operations.
110 // c_uIBits: UINT8 : Width of i (aka. integer bits)
111 // c_uFBits: UINT8 : Width of f (aka. fractional bits)
112 // c_bSigned: bool : Whether the integer bits are a 2's complement signed value
113 // input: float : All values valid.
114 // output: INT32 : At most 24 bits from LSB are meaningful, depending
115 // on the fixed point bit representation chosen (see
116 // below). Extra bits are sign extended from the most
119 //-----------------------------------------------------------------------------------------------------------------------------
121 typedef unsigned char UINT8
;
123 template< const UINT8 c_uIBits
, const UINT8 c_uFBits
, const bool c_bSigned
>
124 INT32
floatToIDotF( const float& input
)
126 // ------------------------------------------------------------------------
127 // output fixed point format
134 // f fractional part of the number, an unsigned
135 // value with _fxpFracBitCount bits (defined below)
139 // i integer part of the number, a 2's complement
140 // value with _fxpIntBitCount bits (defined below)
142 // [sign-extend] MSB of i conditionally replicated
144 // ------------------------------------------------------------------------
145 // Define fixed point bit counts
148 // Commenting out C_ASSERT below to minimise #includes:
149 // C_ASSERT( 2 <= c_uIBits && c_uIBits <= 32 && c_uFBits <= 32 && c_uIBits + c_uFBits <= 32 );
151 // Define most negative and most positive fixed point values
152 const INT32 c_iMinResult
= (c_bSigned
? INT32( -1 ) << (c_uIBits
+ c_uFBits
- 1) : 0);
153 const INT32 c_iMaxResult
= ~c_iMinResult
;
155 // ------------------------------------------------------------------------
156 // constant float properties
157 // ------------------------------------------------------------------------
158 const UINT8 _fltMantissaBitCount
= 23;
159 const UINT8 _fltExponentBitCount
= 8;
160 const INT32 _fltExponentBias
= (INT32( 1 ) << (_fltExponentBitCount
- 1)) - 1;
161 const INT32 _fltHiddenBit
= INT32( 1 ) << _fltMantissaBitCount
;
162 const INT32 _fltMantissaMask
= _fltHiddenBit
- 1;
163 const INT32 _fltExponentMask
= ((INT32( 1 ) << _fltExponentBitCount
) - 1) << _fltMantissaBitCount
;
164 const INT32 _fltSignBit
= INT32( 1 ) << (_fltExponentBitCount
+ _fltMantissaBitCount
);
166 // ------------------------------------------------------------------------
167 // define min and max values as floats (clamp to these bounds)
168 // ------------------------------------------------------------------------
169 INT32 _fxpMaxPosValueFloat
;
170 INT32 _fxpMaxNegValueFloat
;
174 // The maximum positive fixed point value is 2^(i-1) - 2^(-f).
175 // The following constructs the floating point bit pattern for this value,
176 // as long as i >= 2.
177 _fxpMaxPosValueFloat
= (_fltExponentBias
+ c_uIBits
- 1) <<_fltMantissaBitCount
;
178 const INT32 iShift
= _fltMantissaBitCount
+ 2 - c_uIBits
- c_uFBits
;
181 // assert( iShift < 32 );
182 #pragma warning( suppress : 4293 )
183 _fxpMaxPosValueFloat
-= INT32( 1 ) << iShift
;
186 // The maximum negative fixed point value is -2^(i-1).
187 // The following constructs the floating point bit pattern for this value,
188 // as long as i >= 2.
189 // We need this number without the sign bit
190 _fxpMaxNegValueFloat
= (_fltExponentBias
+ c_uIBits
- 1) << _fltMantissaBitCount
;
194 // The maximum positive fixed point value is 2^(i) - 2^(-f).
195 // The following constructs the floating point bit pattern for this value,
196 // as long as i >= 2.
197 _fxpMaxPosValueFloat
= (_fltExponentBias
+ c_uIBits
) <<_fltMantissaBitCount
;
198 const INT32 iShift
= _fltMantissaBitCount
+ 1 - c_uIBits
- c_uFBits
;
201 // assert( iShift < 32 );
202 #pragma warning( suppress : 4293 )
203 _fxpMaxPosValueFloat
-= INT32( 1 ) << iShift
;
206 // The maximum negative fixed point value is 0.
207 _fxpMaxNegValueFloat
= 0;
210 // ------------------------------------------------------------------------
211 // float -> fixed conversion
212 // ------------------------------------------------------------------------
214 // ------------------------------------------------------------------------
215 // examine input float
216 // ------------------------------------------------------------------------
217 INT32 output
= *(INT32
*)&input
;
218 INT32 unbiasedExponent
= ((output
& _fltExponentMask
) >> _fltMantissaBitCount
) - _fltExponentBias
;
219 INT32 isNegative
= output
& _fltSignBit
;
221 // ------------------------------------------------------------------------
223 // ------------------------------------------------------------------------
224 if (unbiasedExponent
== (_fltExponentBias
+ 1) && (output
& _fltMantissaMask
))
229 // ------------------------------------------------------------------------
230 // too large positive
231 // ------------------------------------------------------------------------
232 else if (!isNegative
&& output
>= _fxpMaxPosValueFloat
) // integer compare
234 output
= c_iMaxResult
;
236 // ------------------------------------------------------------------------
237 // too large negative
238 // ------------------------------------------------------------------------
240 else if (isNegative
&& (output
& ~_fltSignBit
) >= _fxpMaxNegValueFloat
)
242 output
= c_iMinResult
;
244 // ------------------------------------------------------------------------
246 // ------------------------------------------------------------------------
247 else if (unbiasedExponent
< -c_uFBits
- 1)
252 // ------------------------------------------------------------------------
254 // ------------------------------------------------------------------------
257 // copy mantissa, add hidden bit
258 output
= (output
& _fltMantissaMask
) | _fltHiddenBit
;
260 INT32 extraBits
= _fltMantissaBitCount
- c_uFBits
- unbiasedExponent
;
263 // 2's complement if negative
266 output
= ~output
+ 1;
269 // From the range checks that led here, it is known that
270 // unbiasedExponent < c_uIBits. So, at most:
271 // (a) unbiasedExponent == c_uIBits - 1.
273 // From compile validation above, it is known that
274 // c_uIBits + c_uFBits <= _fltMantissaBitCount + 1).
276 // (b) _fltMantissaBitCount == _fxtIntBitCount + c_uFBits - 1
278 // Substituting (a) and (b) into extraBits calculation above:
279 // extraBits >= (_fxtIntBitCount + c_uFBits - 1)
280 // - c_uFBits - (c_uIBits - 1)
283 // Thus we only have to worry about shifting right by 0 or more
284 // bits to get the decimal to the right place, and never have
287 INT32 LSB
= 1 << extraBits
; // last bit being kept
288 INT32 extraBitsMask
= LSB
- 1;
289 INT32 half
= LSB
>> 1; // round bias
291 // round to nearest-even at LSB
292 if ((output
& LSB
) || (output
& extraBitsMask
) > half
)
297 // shift off the extra bits (sign extending)
298 output
>>= extraBits
;
302 output
<<= -extraBits
;
304 // 2's complement if negative
307 output
= ~output
+ 1;
313 //-----------------------------------------------------------------------------------------------------------------------------
315 #define FXP_INTEGER_BITS 15
316 #define FXP_FRACTION_BITS 16
317 #define FXP_FRACTION_MASK 0x0000ffff
318 #define FXP_INTEGER_MASK 0x7fff0000
319 #define FXP_THREE (3<<FXP_FRACTION_BITS)
320 #define FXP_ONE (1<<FXP_FRACTION_BITS)
321 #define FXP_ONE_THIRD 0x00005555
322 #define FXP_TWO_THIRDS 0x0000aaaa
323 #define FXP_ONE_HALF 0x00008000
325 #define FXP_MAX_INPUT_TESS_FACTOR_BEFORE_TRIPLE_AVERAGE 0x55540000 // 1/3 of max fixed point number - 1. Numbers less than
326 // or equal to this allows avg. reduction on a tri patch
327 // including rounding.
329 #define FXP_MAX_INPUT_TESS_FACTOR_BEFORE_PAIR_AVERAGE 0x7FFF0000 // 1/2 of max fixed point number - 1. Numbers less than
330 // or equal to this allows avg. reduction on a quad patch
331 // including rounding.
333 static const FXP s_fixedReciprocal
[D3D11_TESSELLATOR_MAX_TESSELLATION_FACTOR
+1] =
335 0xffffffff, // 1/0 is the first entry (unused)
336 0x10000, 0x8000, 0x5555, 0x4000,
337 0x3333, 0x2aab, 0x2492, 0x2000,
338 0x1c72, 0x199a, 0x1746, 0x1555,
339 0x13b1, 0x1249, 0x1111, 0x1000,
340 0xf0f, 0xe39, 0xd79, 0xccd,
341 0xc31, 0xba3, 0xb21, 0xaab,
342 0xa3d, 0x9d9, 0x97b, 0x925,
343 0x8d4, 0x889, 0x842, 0x800,
344 0x7c2, 0x788, 0x750, 0x71c,
345 0x6eb, 0x6bd, 0x690, 0x666,
346 0x63e, 0x618, 0x5f4, 0x5d1,
347 0x5b0, 0x591, 0x572, 0x555,
348 0x539, 0x51f, 0x505, 0x4ec,
349 0x4d5, 0x4be, 0x4a8, 0x492,
350 0x47e, 0x46a, 0x457, 0x444,
351 0x432, 0x421, 0x410, 0x400, // 1/64 is the last entry
354 #define FLOAT_THREE 3.0f
355 #define FLOAT_ONE 1.0f
357 //---------------------------------------------------------------------------------------------------------------------------------
359 //---------------------------------------------------------------------------------------------------------------------------------
360 FXP
floatToFixed(const float& input
)
362 return floatToIDotF
< FXP_INTEGER_BITS
, FXP_FRACTION_BITS
, /*bSigned*/false >( input
);
365 //---------------------------------------------------------------------------------------------------------------------------------
367 //---------------------------------------------------------------------------------------------------------------------------------
368 float fixedToFloat(const FXP
& input
)
370 // not worrying about denorm flushing the float operations (the DX spec behavior for div), since the numbers will not be that small during tessellation.
371 return ((float)(input
>>FXP_FRACTION_BITS
) + (float)(input
&FXP_FRACTION_MASK
)/(1<<FXP_FRACTION_BITS
));
374 //---------------------------------------------------------------------------------------------------------------------------------
376 //---------------------------------------------------------------------------------------------------------------------------------
377 bool isEven(const float& input
)
379 return (((int)input
) & 1) ? false : true;
382 //---------------------------------------------------------------------------------------------------------------------------------
384 //---------------------------------------------------------------------------------------------------------------------------------
385 FXP
fxpCeil(const FXP
& input
)
387 if( input
& FXP_FRACTION_MASK
)
389 return (input
& FXP_INTEGER_MASK
) + FXP_ONE
;
394 //---------------------------------------------------------------------------------------------------------------------------------
396 //---------------------------------------------------------------------------------------------------------------------------------
397 FXP
fxpFloor(const FXP
& input
)
399 return (input
& FXP_INTEGER_MASK
);
402 //=================================================================================================================================
404 //=================================================================================================================================
406 //---------------------------------------------------------------------------------------------------------------------------------
407 // CHWTessellator::CHWTessellator
408 //---------------------------------------------------------------------------------------------------------------------------------
409 CHWTessellator::CHWTessellator()
415 m_bUsingPatchedIndices
= false;
416 m_bUsingPatchedIndices2
= false;
417 #ifdef ALLOW_XBOX_360_COMPARISON
418 m_bXBox360Mode
= false;
421 //---------------------------------------------------------------------------------------------------------------------------------
422 // CHWTessellator::~CHWTessellator
423 //---------------------------------------------------------------------------------------------------------------------------------
424 CHWTessellator::~CHWTessellator()
430 //---------------------------------------------------------------------------------------------------------------------------------
431 // CHWTessellator::Init
433 //---------------------------------------------------------------------------------------------------------------------------------
434 void CHWTessellator::Init(
435 D3D11_TESSELLATOR_PARTITIONING partitioning
,
436 D3D11_TESSELLATOR_OUTPUT_PRIMITIVE outputPrimitive
)
440 m_Point
= new DOMAIN_POINT
[MAX_POINT_COUNT
];
444 m_Index
= new int[MAX_INDEX_COUNT
];
446 m_partitioning
= partitioning
;
447 m_originalPartitioning
= partitioning
;
448 switch( partitioning
)
450 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
453 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
454 m_parity
= TESSELLATOR_PARITY_ODD
;
456 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
457 m_parity
= TESSELLATOR_PARITY_EVEN
;
460 m_originalParity
= m_parity
;
461 m_outputPrimitive
= outputPrimitive
;
465 //---------------------------------------------------------------------------------------------------------------------------------
466 // CHWTessellator::TessellateQuadDomain
468 //---------------------------------------------------------------------------------------------------------------------------------
469 void CHWTessellator::TessellateQuadDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
470 float insideTessFactor_U
, float insideTessFactor_V
)
472 PROCESSED_TESS_FACTORS_QUAD processedTessFactors
;
473 QuadProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Ueq1
,tessFactor_Veq1
,insideTessFactor_U
,insideTessFactor_V
,processedTessFactors
);
475 if( processedTessFactors
.bPatchCulled
)
481 else if( processedTessFactors
.bJustDoMinimumTessFactor
)
483 DefinePoint(/*U*/0,/*V*/0,/*pointStorageOffset*/0);
484 DefinePoint(/*U*/FXP_ONE
,/*V*/0,/*pointStorageOffset*/1);
485 DefinePoint(/*U*/FXP_ONE
,/*V*/FXP_ONE
,/*pointStorageOffset*/2);
486 DefinePoint(/*U*/0,/*V*/FXP_ONE
,/*pointStorageOffset*/3);
489 switch(m_outputPrimitive
)
491 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CW
:
492 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CCW
:
493 // function orients them CCW if needed
494 DefineClockwiseTriangle(0,1,3,/*indexStorageOffset*/0);
495 DefineClockwiseTriangle(1,2,3,/*indexStorageOffset*/3);
498 case D3D11_TESSELLATOR_OUTPUT_POINT
:
501 case D3D11_TESSELLATOR_OUTPUT_LINE
:
502 DumpAllPointsAsInOrderLineList();
508 QuadGeneratePoints(processedTessFactors
);
510 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
515 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_LINE
)
517 DumpAllPointsAsInOrderLineList();
521 QuadGenerateConnectivity(processedTessFactors
); // can be done in parallel to QuadGeneratePoints()
524 //---------------------------------------------------------------------------------------------------------------------------------
525 // CHWTessellator::QuadProcessTessFactors
526 //---------------------------------------------------------------------------------------------------------------------------------
527 void CHWTessellator::QuadProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
528 float insideTessFactor_U
, float insideTessFactor_V
, PROCESSED_TESS_FACTORS_QUAD
& processedTessFactors
)
530 // Is the patch culled?
531 if( !(tessFactor_Ueq0
> 0) || // NaN will pass
532 !(tessFactor_Veq0
> 0) ||
533 !(tessFactor_Ueq1
> 0) ||
534 !(tessFactor_Veq1
> 0) )
536 processedTessFactors
.bPatchCulled
= true;
541 processedTessFactors
.bPatchCulled
= false;
544 // Clamp edge TessFactors
545 float lowerBound
, upperBound
;
546 switch(m_originalPartitioning
)
548 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
549 case D3D11_TESSELLATOR_PARTITIONING_POW2
: // don�t care about pow2 distinction for validation, just treat as integer
550 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
551 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
554 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
555 lowerBound
= D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
;
556 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
559 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
560 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
561 upperBound
= D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
;
565 tessFactor_Ueq0
= fmin( upperBound
, fmax( lowerBound
, tessFactor_Ueq0
) );
566 tessFactor_Veq0
= fmin( upperBound
, fmax( lowerBound
, tessFactor_Veq0
) );
567 tessFactor_Ueq1
= fmin( upperBound
, fmax( lowerBound
, tessFactor_Ueq1
) );
568 tessFactor_Veq1
= fmin( upperBound
, fmax( lowerBound
, tessFactor_Veq1
) );
570 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
572 tessFactor_Ueq0
= ceil(tessFactor_Ueq0
);
573 tessFactor_Veq0
= ceil(tessFactor_Veq0
);
574 tessFactor_Ueq1
= ceil(tessFactor_Ueq1
);
575 tessFactor_Veq1
= ceil(tessFactor_Veq1
);
578 // Clamp inside TessFactors
579 if(D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
== m_originalPartitioning
)
581 #define EPSILON 0.0000152587890625f // 2^(-16), min positive fixed point fraction
582 #define MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON (D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON/2)
583 // If any TessFactor will end up > 1 after floatToFixed conversion later,
584 // then force the inside TessFactors to be > 1 so there is a picture frame.
585 if( (tessFactor_Ueq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
586 (tessFactor_Veq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
587 (tessFactor_Ueq1
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
588 (tessFactor_Veq1
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
589 (insideTessFactor_U
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
590 (insideTessFactor_V
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) )
592 // Force picture frame
593 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
+ EPSILON
;
597 insideTessFactor_U
= fmin( upperBound
, fmax( lowerBound
, insideTessFactor_U
) );
598 insideTessFactor_V
= fmin( upperBound
, fmax( lowerBound
, insideTessFactor_V
) );
599 // Note the above clamps map NaN to lowerBound
602 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
604 insideTessFactor_U
= ceil(insideTessFactor_U
);
605 insideTessFactor_V
= ceil(insideTessFactor_V
);
608 // Reset our vertex and index buffers. We have enough storage for the max tessFactor.
612 // Process tessFactors
613 float outsideTessFactor
[QUAD_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Ueq1
, tessFactor_Veq1
};
614 float insideTessFactor
[QUAD_AXES
] = {insideTessFactor_U
,insideTessFactor_V
};
616 if( HWIntegerPartitioning() )
618 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
620 int edgeEven
= isEven(outsideTessFactor
[edge
]);
621 processedTessFactors
.outsideTessFactorParity
[edge
] = edgeEven
? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
623 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
625 processedTessFactors
.insideTessFactorParity
[axis
] =
626 (isEven(insideTessFactor
[axis
]) || (FLOAT_ONE
== insideTessFactor
[axis
]) )
627 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
632 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
634 processedTessFactors
.outsideTessFactorParity
[edge
] = m_originalParity
;
636 processedTessFactors
.insideTessFactorParity
[U
] = processedTessFactors
.insideTessFactorParity
[V
] = m_originalParity
;
639 // Save fixed point TessFactors
640 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
642 processedTessFactors
.outsideTessFactor
[edge
] = floatToFixed(outsideTessFactor
[edge
]);
644 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
646 processedTessFactors
.insideTessFactor
[axis
] = floatToFixed(insideTessFactor
[axis
]);
649 if( HWIntegerPartitioning() || Odd() )
651 // Special case if all TessFactors are 1
652 if( (FXP_ONE
== processedTessFactors
.insideTessFactor
[U
]) &&
653 (FXP_ONE
== processedTessFactors
.insideTessFactor
[V
]) &&
654 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Ueq0
]) &&
655 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Veq0
]) &&
656 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Ueq1
]) &&
657 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Veq1
]) )
659 processedTessFactors
.bJustDoMinimumTessFactor
= true;
663 processedTessFactors
.bJustDoMinimumTessFactor
= false;
665 // Compute TessFactor-specific metadata
666 for(int edge
= 0; edge
< QUAD_EDGES
; edge
++ )
668 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
669 ComputeTessFactorContext(processedTessFactors
.outsideTessFactor
[edge
], processedTessFactors
.outsideTessFactorCtx
[edge
]);
672 for(int axis
= 0; axis
< QUAD_AXES
; axis
++)
674 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[axis
]);
675 ComputeTessFactorContext(processedTessFactors
.insideTessFactor
[axis
], processedTessFactors
.insideTessFactorCtx
[axis
]);
678 // Compute some initial data.
680 // outside edge offsets and storage
681 for(int edge
= 0; edge
< QUAD_EDGES
; edge
++ )
683 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
684 processedTessFactors
.numPointsForOutsideEdge
[edge
] = NumPointsForTessFactor(processedTessFactors
.outsideTessFactor
[edge
]);
685 m_NumPoints
+= processedTessFactors
.numPointsForOutsideEdge
[edge
];
689 // inside edge offsets
690 for(int axis
= 0; axis
< QUAD_AXES
; axis
++)
692 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[axis
]);
693 processedTessFactors
.numPointsForInsideTessFactor
[axis
] = NumPointsForTessFactor(processedTessFactors
.insideTessFactor
[axis
]);
694 int pointCountMin
= ( TESSELLATOR_PARITY_ODD
== processedTessFactors
.insideTessFactorParity
[axis
] ) ? 4 : 3;
695 // max() allows degenerate transition regions when inside TessFactor == 1
696 processedTessFactors
.numPointsForInsideTessFactor
[axis
] = max(pointCountMin
,processedTessFactors
.numPointsForInsideTessFactor
[axis
]);
699 processedTessFactors
.insideEdgePointBaseOffset
= m_NumPoints
;
701 // inside storage, including interior edges above
702 int numInteriorPoints
= (processedTessFactors
.numPointsForInsideTessFactor
[U
] - 2)*(processedTessFactors
.numPointsForInsideTessFactor
[V
]-2);
703 m_NumPoints
+= numInteriorPoints
;
706 //---------------------------------------------------------------------------------------------------------------------------------
707 // CHWTessellator::QuadGeneratePoints
708 //---------------------------------------------------------------------------------------------------------------------------------
709 void CHWTessellator::QuadGeneratePoints( const PROCESSED_TESS_FACTORS_QUAD
& processedTessFactors
)
711 // Generate exterior ring edge points, clockwise from top-left
714 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
716 int parity
= edge
&0x1;
718 int endPoint
= processedTessFactors
.numPointsForOutsideEdge
[edge
] - 1;
719 for(int p
= startPoint
; p
< endPoint
; p
++,pointOffset
++) // don't include end, since next edge starts with it.
722 int q
= ((edge
==1)||(edge
==2)) ? p
: endPoint
- p
; // reverse order
723 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
724 PlacePointIn1D(processedTessFactors
.outsideTessFactorCtx
[edge
],q
,fxpParam
);
727 DefinePoint(/*U*/fxpParam
,
728 /*V*/(edge
== 3) ? FXP_ONE
: 0,
729 /*pointStorageOffset*/pointOffset
);
733 DefinePoint(/*U*/(edge
== 2) ? FXP_ONE
: 0,
735 /*pointStorageOffset*/pointOffset
);
740 // Generate interior ring points, clockwise from (U==0,V==1) (bottom-left) spiralling toward center
741 static const int startRing
= 1;
742 int minNumPointsForTessFactor
= min(processedTessFactors
.numPointsForInsideTessFactor
[U
],processedTessFactors
.numPointsForInsideTessFactor
[V
]);
743 int numRings
= (minNumPointsForTessFactor
>> 1); // note for even tess we aren't counting center point here.
744 for(int ring
= startRing
; ring
< numRings
; ring
++)
746 int startPoint
= ring
;
747 int endPoint
[QUAD_AXES
] = {processedTessFactors
.numPointsForInsideTessFactor
[U
] - 1 - startPoint
,
748 processedTessFactors
.numPointsForInsideTessFactor
[V
] - 1 - startPoint
};
750 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
752 int parity
[QUAD_AXES
] = {edge
&0x1,((edge
+1)&0x1)};
753 int perpendicularAxisPoint
= (edge
< 2) ? startPoint
: endPoint
[parity
[0]];
755 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[parity
[0]]);
756 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[parity
[0]],perpendicularAxisPoint
,fxpPerpParam
);
757 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[parity
[1]]);
758 for(int p
= startPoint
; p
< endPoint
[parity
[1]]; p
++, pointOffset
++) // don't include end: next edge starts with it.
761 int q
= ((edge
== 1)||(edge
==2)) ? p
: endPoint
[parity
[1]] - (p
- startPoint
);
762 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[parity
[1]],q
,fxpParam
);
765 DefinePoint(/*U*/fxpPerpParam
,
767 /*pointStorageOffset*/pointOffset
);
771 DefinePoint(/*U*/fxpParam
,
773 /*pointStorageOffset*/pointOffset
);
778 // For even tessellation, the inner "ring" is degenerate - a row of points
779 if( (processedTessFactors
.numPointsForInsideTessFactor
[U
] > processedTessFactors
.numPointsForInsideTessFactor
[V
]) &&
780 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
]) )
782 int startPoint
= numRings
;
783 int endPoint
= processedTessFactors
.numPointsForInsideTessFactor
[U
] - 1 - startPoint
;
784 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[U
]);
785 for( int p
= startPoint
; p
<= endPoint
; p
++, pointOffset
++ )
788 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[U
],p
,fxpParam
);
789 DefinePoint(/*U*/fxpParam
,
790 /*V*/FXP_ONE_HALF
, // middle
791 /*pointStorageOffset*/pointOffset
);
794 else if( (processedTessFactors
.numPointsForInsideTessFactor
[V
] >= processedTessFactors
.numPointsForInsideTessFactor
[U
]) &&
795 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[U
]) )
797 int startPoint
= numRings
;
800 endPoint
= processedTessFactors
.numPointsForInsideTessFactor
[V
] - 1 - startPoint
;
801 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[V
]);
802 for( int p
= endPoint
; p
>= startPoint
; p
--, pointOffset
++ )
804 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[V
],p
,fxpParam
);
805 DefinePoint(/*U*/FXP_ONE_HALF
, // middle
807 /*pointStorageOffset*/pointOffset
);
811 //---------------------------------------------------------------------------------------------------------------------------------
812 // CHWTessellator::QuadGenerateConnectivity
813 //---------------------------------------------------------------------------------------------------------------------------------
814 void CHWTessellator::QuadGenerateConnectivity( const PROCESSED_TESS_FACTORS_QUAD
& processedTessFactors
)
816 // Generate primitives for all the concentric rings, one side at a time for each ring
817 static const int startRing
= 1;
818 int numPointRowsToCenter
[QUAD_AXES
] = {((processedTessFactors
.numPointsForInsideTessFactor
[U
]+1) >> 1),
819 ((processedTessFactors
.numPointsForInsideTessFactor
[V
]+1) >> 1)}; // +1 is so even tess includes the center point
820 int numRings
= min(numPointRowsToCenter
[U
],numPointRowsToCenter
[V
]);
821 int degeneratePointRing
[QUAD_AXES
] = { // Even partitioning causes degenerate row of points,
822 // which results in exceptions to the point ordering conventions
823 // when travelling around the rings counterclockwise.
824 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
]) ? numPointRowsToCenter
[V
] - 1 : -1,
825 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[U
]) ? numPointRowsToCenter
[U
] - 1 : -1 };
827 const TESS_FACTOR_CONTEXT
* outsideTessFactorCtx
[QUAD_EDGES
] = {&processedTessFactors
.outsideTessFactorCtx
[Ueq0
],
828 &processedTessFactors
.outsideTessFactorCtx
[Veq0
],
829 &processedTessFactors
.outsideTessFactorCtx
[Ueq1
],
830 &processedTessFactors
.outsideTessFactorCtx
[Veq1
]};
831 TESSELLATOR_PARITY outsideTessFactorParity
[QUAD_EDGES
] = {processedTessFactors
.outsideTessFactorParity
[Ueq0
],
832 processedTessFactors
.outsideTessFactorParity
[Veq0
],
833 processedTessFactors
.outsideTessFactorParity
[Ueq1
],
834 processedTessFactors
.outsideTessFactorParity
[Veq1
]};
835 int numPointsForOutsideEdge
[QUAD_EDGES
] = {processedTessFactors
.numPointsForOutsideEdge
[Ueq0
],
836 processedTessFactors
.numPointsForOutsideEdge
[Veq0
],
837 processedTessFactors
.numPointsForOutsideEdge
[Ueq1
],
838 processedTessFactors
.numPointsForOutsideEdge
[Veq1
]};
840 int insideEdgePointBaseOffset
= processedTessFactors
.insideEdgePointBaseOffset
;
841 int outsideEdgePointBaseOffset
= 0;
843 for(int ring
= startRing
; ring
< numRings
; ring
++)
845 int numPointsForInsideEdge
[QUAD_AXES
] = {processedTessFactors
.numPointsForInsideTessFactor
[U
] - 2*ring
,
846 processedTessFactors
.numPointsForInsideTessFactor
[V
] - 2*ring
};
848 int edge0InsidePointBaseOffset
= insideEdgePointBaseOffset
;
849 int edge0OutsidePointBaseOffset
= outsideEdgePointBaseOffset
;
851 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
853 int parity
= (edge
+1)&0x1;
855 int numTriangles
= numPointsForInsideEdge
[parity
] + numPointsForOutsideEdge
[edge
] - 2;
856 int insideBaseOffset
;
857 int outsideBaseOffset
;
858 if( edge
== 3 ) // We need to patch the indexing so Stitch() can think it sees
859 // 2 sequentially increasing rows of points, even though we have wrapped around
860 // to the end of the inner and outer ring's points, so the last point is really
861 // the first point for the ring.
862 // We make it so that when Stitch() calls AddIndex(), that function
863 // will do any necessary index adjustment.
865 if( ring
== degeneratePointRing
[parity
] )
867 m_IndexPatchContext2
.baseIndexToInvert
= insideEdgePointBaseOffset
+ 1;
868 m_IndexPatchContext2
.cornerCaseBadValue
= outsideEdgePointBaseOffset
+ numPointsForOutsideEdge
[edge
] - 1;
869 m_IndexPatchContext2
.cornerCaseReplacementValue
= edge0OutsidePointBaseOffset
;
870 m_IndexPatchContext2
.indexInversionEndPoint
= (m_IndexPatchContext2
.baseIndexToInvert
<< 1) - 1;
871 insideBaseOffset
= m_IndexPatchContext2
.baseIndexToInvert
;
872 outsideBaseOffset
= outsideEdgePointBaseOffset
;
873 SetUsingPatchedIndices2(true);
877 m_IndexPatchContext
.insidePointIndexDeltaToRealValue
= insideEdgePointBaseOffset
;
878 m_IndexPatchContext
.insidePointIndexBadValue
= numPointsForInsideEdge
[parity
] - 1;
879 m_IndexPatchContext
.insidePointIndexReplacementValue
= edge0InsidePointBaseOffset
;
880 m_IndexPatchContext
.outsidePointIndexPatchBase
= m_IndexPatchContext
.insidePointIndexBadValue
+1; // past inside patched index range
881 m_IndexPatchContext
.outsidePointIndexDeltaToRealValue
= outsideEdgePointBaseOffset
882 - m_IndexPatchContext
.outsidePointIndexPatchBase
;
883 m_IndexPatchContext
.outsidePointIndexBadValue
= m_IndexPatchContext
.outsidePointIndexPatchBase
884 + numPointsForOutsideEdge
[edge
] - 1;
885 m_IndexPatchContext
.outsidePointIndexReplacementValue
= edge0OutsidePointBaseOffset
;
887 insideBaseOffset
= 0;
888 outsideBaseOffset
= m_IndexPatchContext
.outsidePointIndexPatchBase
;
889 SetUsingPatchedIndices(true);
892 else if( (edge
== 2) && (ring
== degeneratePointRing
[parity
]) )
894 m_IndexPatchContext2
.baseIndexToInvert
= insideEdgePointBaseOffset
;
895 m_IndexPatchContext2
.cornerCaseBadValue
= -1; // unused
896 m_IndexPatchContext2
.cornerCaseReplacementValue
= -1; // unused
897 m_IndexPatchContext2
.indexInversionEndPoint
= m_IndexPatchContext2
.baseIndexToInvert
<< 1;
898 insideBaseOffset
= m_IndexPatchContext2
.baseIndexToInvert
;
899 outsideBaseOffset
= outsideEdgePointBaseOffset
;
900 SetUsingPatchedIndices2(true);
904 insideBaseOffset
= insideEdgePointBaseOffset
;
905 outsideBaseOffset
= outsideEdgePointBaseOffset
;
907 if( ring
== startRing
)
909 StitchTransition(/*baseIndexOffset: */m_NumIndices
,
910 insideBaseOffset
,processedTessFactors
.insideTessFactorCtx
[parity
].numHalfTessFactorPoints
,processedTessFactors
.insideTessFactorParity
[parity
],
911 outsideBaseOffset
,outsideTessFactorCtx
[edge
]->numHalfTessFactorPoints
,outsideTessFactorParity
[edge
]);
915 StitchRegular(/*bTrapezoid*/true, DIAGONALS_MIRRORED
,
916 /*baseIndexOffset: */m_NumIndices
,
917 numPointsForInsideEdge
[parity
],
918 insideBaseOffset
,outsideBaseOffset
);
920 SetUsingPatchedIndices(false);
921 SetUsingPatchedIndices2(false);
922 m_NumIndices
+= numTriangles
*3;
923 outsideEdgePointBaseOffset
+= numPointsForOutsideEdge
[edge
] - 1;
924 if( (edge
== 2) && (ring
== degeneratePointRing
[parity
]) )
926 insideEdgePointBaseOffset
-= numPointsForInsideEdge
[parity
] - 1;
930 insideEdgePointBaseOffset
+= numPointsForInsideEdge
[parity
] - 1;
932 numPointsForOutsideEdge
[edge
] = numPointsForInsideEdge
[parity
];
934 if( startRing
== ring
)
936 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
938 outsideTessFactorCtx
[edge
] = &processedTessFactors
.insideTessFactorCtx
[edge
&1];
939 outsideTessFactorParity
[edge
] = processedTessFactors
.insideTessFactorParity
[edge
&1];
944 // Triangulate center - a row of quads if odd
945 // This triangulation may be producing diagonals that are asymmetric about
946 // the center of the patch in this region.
947 if( (processedTessFactors
.numPointsForInsideTessFactor
[U
] > processedTessFactors
.numPointsForInsideTessFactor
[V
]) &&
948 (TESSELLATOR_PARITY_ODD
== processedTessFactors
.insideTessFactorParity
[V
] ) )
950 SetUsingPatchedIndices2(true);
951 int stripNumQuads
= (((processedTessFactors
.numPointsForInsideTessFactor
[U
]>>1) - (processedTessFactors
.numPointsForInsideTessFactor
[V
]>>1))<<1)+
952 ((TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[U
] ) ? 2 : 1);
953 m_IndexPatchContext2
.baseIndexToInvert
= outsideEdgePointBaseOffset
+ stripNumQuads
+ 2;
954 m_IndexPatchContext2
.cornerCaseBadValue
= m_IndexPatchContext2
.baseIndexToInvert
;
955 m_IndexPatchContext2
.cornerCaseReplacementValue
= outsideEdgePointBaseOffset
;
956 m_IndexPatchContext2
.indexInversionEndPoint
= m_IndexPatchContext2
.baseIndexToInvert
+
957 m_IndexPatchContext2
.baseIndexToInvert
+ stripNumQuads
;
958 StitchRegular(/*bTrapezoid*/false,DIAGONALS_INSIDE_TO_OUTSIDE
,
959 /*baseIndexOffset: */m_NumIndices
, /*numInsideEdgePoints:*/stripNumQuads
+1,
960 /*insideEdgePointBaseOffset*/m_IndexPatchContext2
.baseIndexToInvert
,
961 outsideEdgePointBaseOffset
+1);
962 SetUsingPatchedIndices2(false);
963 m_NumIndices
+= stripNumQuads
*6;
965 else if((processedTessFactors
.numPointsForInsideTessFactor
[V
] >= processedTessFactors
.numPointsForInsideTessFactor
[U
]) &&
966 (TESSELLATOR_PARITY_ODD
== processedTessFactors
.insideTessFactorParity
[U
]) )
968 SetUsingPatchedIndices2(true);
969 int stripNumQuads
= (((processedTessFactors
.numPointsForInsideTessFactor
[V
]>>1) - (processedTessFactors
.numPointsForInsideTessFactor
[U
]>>1))<<1)+
970 ((TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
] ) ? 2 : 1);
971 m_IndexPatchContext2
.baseIndexToInvert
= outsideEdgePointBaseOffset
+ stripNumQuads
+ 1;
972 m_IndexPatchContext2
.cornerCaseBadValue
= -1; // unused
973 m_IndexPatchContext2
.indexInversionEndPoint
= m_IndexPatchContext2
.baseIndexToInvert
+
974 m_IndexPatchContext2
.baseIndexToInvert
+ stripNumQuads
;
975 DIAGONALS diag
= (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
]) ?
976 DIAGONALS_INSIDE_TO_OUTSIDE
: DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE
;
977 StitchRegular(/*bTrapezoid*/false,diag
,
978 /*baseIndexOffset: */m_NumIndices
, /*numInsideEdgePoints:*/stripNumQuads
+1,
979 /*insideEdgePointBaseOffset*/m_IndexPatchContext2
.baseIndexToInvert
,
980 outsideEdgePointBaseOffset
);
981 SetUsingPatchedIndices2(false);
982 m_NumIndices
+= stripNumQuads
*6;
986 //---------------------------------------------------------------------------------------------------------------------------------
987 // CHWTessellator::TessellateTriDomain
989 //---------------------------------------------------------------------------------------------------------------------------------
990 void CHWTessellator::TessellateTriDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
991 float insideTessFactor
)
993 PROCESSED_TESS_FACTORS_TRI processedTessFactors
;
994 TriProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Weq0
,insideTessFactor
,processedTessFactors
);
996 if( processedTessFactors
.bPatchCulled
)
1002 else if( processedTessFactors
.bJustDoMinimumTessFactor
)
1004 DefinePoint(/*U*/0,/*V*/FXP_ONE
,/*pointStorageOffset*/0); //V=1 (beginning of Ueq0 edge VW)
1005 DefinePoint(/*U*/0,/*V*/0,/*pointStorageOffset*/1); //W=1 (beginning of Veq0 edge WU)
1006 DefinePoint(/*U*/FXP_ONE
,/*V*/0,/*pointStorageOffset*/2); //U=1 (beginning of Weq0 edge UV)
1009 switch(m_outputPrimitive
)
1011 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CW
:
1012 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CCW
:
1013 // function orients them CCW if needed
1014 DefineClockwiseTriangle(0,1,2,/*indexStorageBaseOffset*/m_NumIndices
);
1017 case D3D11_TESSELLATOR_OUTPUT_POINT
:
1020 case D3D11_TESSELLATOR_OUTPUT_LINE
:
1021 DumpAllPointsAsInOrderLineList();
1027 TriGeneratePoints(processedTessFactors
);
1029 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
1034 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_LINE
)
1036 DumpAllPointsAsInOrderLineList();
1040 TriGenerateConnectivity(processedTessFactors
); // can be done in parallel to TriGeneratePoints()
1043 //---------------------------------------------------------------------------------------------------------------------------------
1044 // CHWTessellator::TriProcessTessFactors
1045 //---------------------------------------------------------------------------------------------------------------------------------
1046 void CHWTessellator::TriProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
1047 float insideTessFactor
, PROCESSED_TESS_FACTORS_TRI
& processedTessFactors
)
1049 // Is the patch culled?
1050 if( !(tessFactor_Ueq0
> 0) || // NaN will pass
1051 !(tessFactor_Veq0
> 0) ||
1052 !(tessFactor_Weq0
> 0) )
1054 processedTessFactors
.bPatchCulled
= true;
1059 processedTessFactors
.bPatchCulled
= false;
1062 // Clamp edge TessFactors
1063 float lowerBound
, upperBound
;
1064 switch(m_originalPartitioning
)
1066 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
1067 case D3D11_TESSELLATOR_PARTITIONING_POW2
: // don�t care about pow2 distinction for validation, just treat as integer
1068 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1069 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1072 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
1073 lowerBound
= D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
;
1074 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1077 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
1078 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1079 upperBound
= D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
;
1083 tessFactor_Ueq0
= fmin( upperBound
, fmax( lowerBound
, tessFactor_Ueq0
) );
1084 tessFactor_Veq0
= fmin( upperBound
, fmax( lowerBound
, tessFactor_Veq0
) );
1085 tessFactor_Weq0
= fmin( upperBound
, fmax( lowerBound
, tessFactor_Weq0
) );
1087 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
1089 tessFactor_Ueq0
= ceil(tessFactor_Ueq0
);
1090 tessFactor_Veq0
= ceil(tessFactor_Veq0
);
1091 tessFactor_Weq0
= ceil(tessFactor_Weq0
);
1094 // Clamp inside TessFactors
1095 if(D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
== m_originalPartitioning
)
1097 if( (tessFactor_Ueq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
1098 (tessFactor_Veq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
1099 (tessFactor_Weq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
))
1100 // Don't need the same check for insideTessFactor for tri patches,
1101 // since there is only one insideTessFactor, as opposed to quad
1102 // patches which have 2 insideTessFactors.
1104 // Force picture frame
1105 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
+ EPSILON
;
1109 insideTessFactor
= fmin( upperBound
, fmax( lowerBound
, insideTessFactor
) );
1110 // Note the above clamps map NaN to lowerBound
1112 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
1114 insideTessFactor
= ceil(insideTessFactor
);
1117 // Reset our vertex and index buffers. We have enough storage for the max tessFactor.
1121 // Process tessFactors
1122 float outsideTessFactor
[TRI_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Weq0
};
1124 if( HWIntegerPartitioning() )
1126 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
1128 int edgeEven
= isEven(outsideTessFactor
[edge
]);
1129 processedTessFactors
.outsideTessFactorParity
[edge
] = edgeEven
? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1131 processedTessFactors
.insideTessFactorParity
= (isEven(insideTessFactor
) || (FLOAT_ONE
== insideTessFactor
))
1132 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1136 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
1138 processedTessFactors
.outsideTessFactorParity
[edge
] = m_originalParity
;
1140 processedTessFactors
.insideTessFactorParity
= m_originalParity
;
1143 // Save fixed point TessFactors
1144 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
1146 processedTessFactors
.outsideTessFactor
[edge
] = floatToFixed(outsideTessFactor
[edge
]);
1148 processedTessFactors
.insideTessFactor
= floatToFixed(insideTessFactor
);
1150 if( HWIntegerPartitioning() || Odd() )
1152 // Special case if all TessFactors are 1
1153 if( (FXP_ONE
== processedTessFactors
.insideTessFactor
) &&
1154 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Ueq0
]) &&
1155 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Veq0
]) &&
1156 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Weq0
]) )
1158 processedTessFactors
.bJustDoMinimumTessFactor
= true;
1162 processedTessFactors
.bJustDoMinimumTessFactor
= false;
1164 // Compute per-TessFactor metadata
1165 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1167 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
1168 ComputeTessFactorContext(processedTessFactors
.outsideTessFactor
[edge
], processedTessFactors
.outsideTessFactorCtx
[edge
]);
1170 SetTessellationParity(processedTessFactors
.insideTessFactorParity
);
1171 ComputeTessFactorContext(processedTessFactors
.insideTessFactor
, processedTessFactors
.insideTessFactorCtx
);
1173 // Compute some initial data.
1175 // outside edge offsets and storage
1176 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1178 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
1179 processedTessFactors
.numPointsForOutsideEdge
[edge
] = NumPointsForTessFactor(processedTessFactors
.outsideTessFactor
[edge
]);
1180 m_NumPoints
+= processedTessFactors
.numPointsForOutsideEdge
[edge
];
1184 // inside edge offsets
1185 SetTessellationParity(processedTessFactors
.insideTessFactorParity
);
1186 processedTessFactors
.numPointsForInsideTessFactor
= NumPointsForTessFactor(processedTessFactors
.insideTessFactor
);
1188 int pointCountMin
= Odd() ? 4 : 3;
1189 // max() allows degenerate transition regions when inside TessFactor == 1
1190 processedTessFactors
.numPointsForInsideTessFactor
= max(pointCountMin
,processedTessFactors
.numPointsForInsideTessFactor
);
1193 processedTessFactors
.insideEdgePointBaseOffset
= m_NumPoints
;
1195 // inside storage, including interior edges above
1197 int numInteriorRings
= (processedTessFactors
.numPointsForInsideTessFactor
>> 1) - 1;
1198 int numInteriorPoints
;
1201 numInteriorPoints
= TRI_EDGES
*(numInteriorRings
*(numInteriorRings
+1) - numInteriorRings
);
1205 numInteriorPoints
= TRI_EDGES
*(numInteriorRings
*(numInteriorRings
+1)) + 1;
1207 m_NumPoints
+= numInteriorPoints
;
1212 //---------------------------------------------------------------------------------------------------------------------------------
1213 // CHWTessellator::TriGeneratePoints
1214 //---------------------------------------------------------------------------------------------------------------------------------
1215 void CHWTessellator::TriGeneratePoints( const PROCESSED_TESS_FACTORS_TRI
& processedTessFactors
)
1217 // Generate exterior ring edge points, clockwise starting from point V (VW, the U==0 edge)
1218 int pointOffset
= 0;
1220 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1222 int parity
= edge
&0x1;
1224 int endPoint
= processedTessFactors
.numPointsForOutsideEdge
[edge
] - 1;
1225 for(int p
= startPoint
; p
< endPoint
; p
++, pointOffset
++) // don't include end, since next edge starts with it.
1228 int q
= (parity
) ? p
: endPoint
- p
; // whether to reverse point order given we are defining V or U (W implicit):
1229 // edge0, VW, has V decreasing, so reverse 1D points below
1230 // edge1, WU, has U increasing, so don't reverse 1D points below
1231 // edge2, UV, has U decreasing, so reverse 1D points below
1232 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
1233 PlacePointIn1D(processedTessFactors
.outsideTessFactorCtx
[edge
],q
,fxpParam
);
1238 /*pointStorageOffset*/pointOffset
);
1242 DefinePoint(/*U*/fxpParam
,
1243 /*V*/(edge
== 2) ? FXP_ONE
- fxpParam
: 0,
1244 /*pointStorageOffset*/pointOffset
);
1249 // Generate interior ring points, clockwise spiralling in
1250 SetTessellationParity(processedTessFactors
.insideTessFactorParity
);
1251 static const int startRing
= 1;
1252 int numRings
= (processedTessFactors
.numPointsForInsideTessFactor
>> 1);
1253 for(int ring
= startRing
; ring
< numRings
; ring
++)
1255 int startPoint
= ring
;
1256 int endPoint
= processedTessFactors
.numPointsForInsideTessFactor
- 1 - startPoint
;
1258 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1260 int parity
= edge
&0x1;
1261 int perpendicularAxisPoint
= startPoint
;
1263 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
,perpendicularAxisPoint
,fxpPerpParam
);
1264 fxpPerpParam
*= FXP_TWO_THIRDS
; // Map location to the right size in barycentric space.
1265 // I (amarp) can draw a picture to explain.
1266 // We know this fixed point math won't over/underflow
1267 fxpPerpParam
= (fxpPerpParam
+FXP_ONE_HALF
/*round*/)>>FXP_FRACTION_BITS
; // get back to n.16
1268 for(int p
= startPoint
; p
< endPoint
; p
++, pointOffset
++) // don't include end: next edge starts with it.
1271 int q
= (parity
) ? p
: endPoint
- (p
- startPoint
); // whether to reverse point given we are defining V or U (W implicit):
1272 // edge0, VW, has V decreasing, so reverse 1D points below
1273 // edge1, WU, has U increasing, so don't reverse 1D points below
1274 // edge2, UV, has U decreasing, so reverse 1D points below
1275 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
,q
,fxpParam
);
1276 // edge0 VW, has perpendicular parameter U constant
1277 // edge1 WU, has perpendicular parameter V constant
1278 // edge2 UV, has perpendicular parameter W constant
1279 const unsigned int deriv
= 2; // reciprocal is the rate of change of edge-parallel parameters as they are pushed into the triangle
1283 DefinePoint(/*U*/fxpPerpParam
,
1284 /*V*/fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
, // we know this fixed point math won't over/underflow
1285 /*pointStorageOffset*/pointOffset
);
1288 DefinePoint(/*U*/fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
,// we know this fixed point math won't over/underflow
1290 /*pointStorageOffset*/pointOffset
);
1293 DefinePoint(/*U*/fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
,// we know this fixed point math won't over/underflow
1294 /*V*/FXP_ONE
- (fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
) - fxpPerpParam
,// we know this fixed point math won't over/underflow
1295 /*pointStorageOffset*/pointOffset
);
1303 // Last point is the point at the center.
1304 DefinePoint(/*U*/FXP_ONE_THIRD
,
1306 /*pointStorageOffset*/pointOffset
);
1309 //---------------------------------------------------------------------------------------------------------------------------------
1310 // CHWTessellator::TriGenerateConnectivity
1311 //---------------------------------------------------------------------------------------------------------------------------------
1312 void CHWTessellator::TriGenerateConnectivity( const PROCESSED_TESS_FACTORS_TRI
& processedTessFactors
)
1314 // Generate primitives for all the concentric rings, one side at a time for each ring
1315 static const int startRing
= 1;
1316 int numRings
= ((processedTessFactors
.numPointsForInsideTessFactor
+1) >> 1); // +1 is so even tess includes the center point, which we want to now
1317 const TESS_FACTOR_CONTEXT
* outsideTessFactorCtx
[TRI_EDGES
] = {&processedTessFactors
.outsideTessFactorCtx
[Ueq0
],
1318 &processedTessFactors
.outsideTessFactorCtx
[Veq0
],
1319 &processedTessFactors
.outsideTessFactorCtx
[Weq0
]};
1320 TESSELLATOR_PARITY outsideTessFactorParity
[TRI_EDGES
] = {processedTessFactors
.outsideTessFactorParity
[Ueq0
],
1321 processedTessFactors
.outsideTessFactorParity
[Veq0
],
1322 processedTessFactors
.outsideTessFactorParity
[Weq0
]};
1323 int numPointsForOutsideEdge
[TRI_EDGES
] = {processedTessFactors
.numPointsForOutsideEdge
[Ueq0
],
1324 processedTessFactors
.numPointsForOutsideEdge
[Veq0
],
1325 processedTessFactors
.numPointsForOutsideEdge
[Weq0
]};
1327 int insideEdgePointBaseOffset
= processedTessFactors
.insideEdgePointBaseOffset
;
1328 int outsideEdgePointBaseOffset
= 0;
1330 for(int ring
= startRing
; ring
< numRings
; ring
++)
1332 int numPointsForInsideEdge
= processedTessFactors
.numPointsForInsideTessFactor
- 2*ring
;
1333 int edge0InsidePointBaseOffset
= insideEdgePointBaseOffset
;
1334 int edge0OutsidePointBaseOffset
= outsideEdgePointBaseOffset
;
1335 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1337 int numTriangles
= numPointsForInsideEdge
+ numPointsForOutsideEdge
[edge
] - 2;
1339 int insideBaseOffset
;
1340 int outsideBaseOffset
;
1343 m_IndexPatchContext
.insidePointIndexDeltaToRealValue
= insideEdgePointBaseOffset
;
1344 m_IndexPatchContext
.insidePointIndexBadValue
= numPointsForInsideEdge
- 1;
1345 m_IndexPatchContext
.insidePointIndexReplacementValue
= edge0InsidePointBaseOffset
;
1346 m_IndexPatchContext
.outsidePointIndexPatchBase
= m_IndexPatchContext
.insidePointIndexBadValue
+1; // past inside patched index range
1347 m_IndexPatchContext
.outsidePointIndexDeltaToRealValue
= outsideEdgePointBaseOffset
1348 - m_IndexPatchContext
.outsidePointIndexPatchBase
;
1349 m_IndexPatchContext
.outsidePointIndexBadValue
= m_IndexPatchContext
.outsidePointIndexPatchBase
1350 + numPointsForOutsideEdge
[edge
] - 1;
1351 m_IndexPatchContext
.outsidePointIndexReplacementValue
= edge0OutsidePointBaseOffset
;
1352 SetUsingPatchedIndices(true);
1353 insideBaseOffset
= 0;
1354 outsideBaseOffset
= m_IndexPatchContext
.outsidePointIndexPatchBase
;
1358 insideBaseOffset
= insideEdgePointBaseOffset
;
1359 outsideBaseOffset
= outsideEdgePointBaseOffset
;
1361 if( ring
== startRing
)
1363 StitchTransition(/*baseIndexOffset: */m_NumIndices
,
1364 insideBaseOffset
,processedTessFactors
.insideTessFactorCtx
.numHalfTessFactorPoints
,processedTessFactors
.insideTessFactorParity
,
1365 outsideBaseOffset
,outsideTessFactorCtx
[edge
]->numHalfTessFactorPoints
,outsideTessFactorParity
[edge
]);
1369 StitchRegular(/*bTrapezoid*/true, DIAGONALS_MIRRORED
,
1370 /*baseIndexOffset: */m_NumIndices
,
1371 numPointsForInsideEdge
,
1372 insideBaseOffset
,outsideBaseOffset
);
1376 SetUsingPatchedIndices(false);
1378 m_NumIndices
+= numTriangles
*3;
1379 outsideEdgePointBaseOffset
+= numPointsForOutsideEdge
[edge
] - 1;
1380 insideEdgePointBaseOffset
+= numPointsForInsideEdge
- 1;
1381 numPointsForOutsideEdge
[edge
] = numPointsForInsideEdge
;
1383 if( startRing
== ring
)
1385 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1387 outsideTessFactorCtx
[edge
] = &processedTessFactors
.insideTessFactorCtx
;
1388 outsideTessFactorParity
[edge
] = processedTessFactors
.insideTessFactorParity
;
1394 // Triangulate center (a single triangle)
1395 DefineClockwiseTriangle(outsideEdgePointBaseOffset
, outsideEdgePointBaseOffset
+1, outsideEdgePointBaseOffset
+2,
1401 //---------------------------------------------------------------------------------------------------------------------------------
1402 // CHWTessellator::TessellateIsoLineDomain
1404 //---------------------------------------------------------------------------------------------------------------------------------
1405 void CHWTessellator::TessellateIsoLineDomain( float TessFactor_V_LineDensity
, float TessFactor_U_LineDetail
)
1407 PROCESSED_TESS_FACTORS_ISOLINE processedTessFactors
;
1408 IsoLineProcessTessFactors(TessFactor_V_LineDensity
,TessFactor_U_LineDetail
,processedTessFactors
);
1409 if( processedTessFactors
.bPatchCulled
)
1415 IsoLineGeneratePoints(processedTessFactors
);
1416 IsoLineGenerateConnectivity(processedTessFactors
); // can be done in parallel to IsoLineGeneratePoints
1419 //---------------------------------------------------------------------------------------------------------------------------------
1420 // CHWTessellator::IsoLineProcessTessFactors
1421 //---------------------------------------------------------------------------------------------------------------------------------
1422 void CHWTessellator::IsoLineProcessTessFactors( float TessFactor_V_LineDensity
, float TessFactor_U_LineDetail
,
1423 PROCESSED_TESS_FACTORS_ISOLINE
& processedTessFactors
)
1425 // Is the patch culled?
1426 if( !(TessFactor_V_LineDensity
> 0) || // NaN will pass
1427 !(TessFactor_U_LineDetail
> 0) )
1429 processedTessFactors
.bPatchCulled
= true;
1434 processedTessFactors
.bPatchCulled
= false;
1437 // Clamp edge TessFactors
1438 float lowerBound
, upperBound
;
1439 switch(m_originalPartitioning
)
1441 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
1442 case D3D11_TESSELLATOR_PARTITIONING_POW2
: // don�t care about pow2 distinction for validation, just treat as integer
1443 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1444 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1447 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
1448 lowerBound
= D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
;
1449 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1452 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
1453 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1454 upperBound
= D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
;
1458 TessFactor_V_LineDensity
= fmin( D3D11_TESSELLATOR_MAX_ISOLINE_DENSITY_TESSELLATION_FACTOR
,
1459 fmax( D3D11_TESSELLATOR_MIN_ISOLINE_DENSITY_TESSELLATION_FACTOR
, TessFactor_V_LineDensity
) );
1460 TessFactor_U_LineDetail
= fmin( upperBound
, fmax( lowerBound
, TessFactor_U_LineDetail
) );
1462 // Reset our vertex and index buffers. We have enough storage for the max tessFactor.
1466 // Process tessFactors
1467 if( HWIntegerPartitioning() )
1469 TessFactor_U_LineDetail
= ceil(TessFactor_U_LineDetail
);
1470 processedTessFactors
.lineDetailParity
= isEven(TessFactor_U_LineDetail
) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1474 processedTessFactors
.lineDetailParity
= m_originalParity
;
1477 FXP fxpTessFactor_U_LineDetail
= floatToFixed(TessFactor_U_LineDetail
);
1479 SetTessellationParity(processedTessFactors
.lineDetailParity
);
1481 ComputeTessFactorContext(fxpTessFactor_U_LineDetail
, processedTessFactors
.lineDetailTessFactorCtx
);
1482 processedTessFactors
.numPointsPerLine
= NumPointsForTessFactor(fxpTessFactor_U_LineDetail
);
1484 OverridePartitioning(D3D11_TESSELLATOR_PARTITIONING_INTEGER
);
1486 TessFactor_V_LineDensity
= ceil(TessFactor_V_LineDensity
);
1487 processedTessFactors
.lineDensityParity
= isEven(TessFactor_V_LineDensity
) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1488 SetTessellationParity(processedTessFactors
.lineDensityParity
);
1489 FXP fxpTessFactor_V_LineDensity
= floatToFixed(TessFactor_V_LineDensity
);
1490 ComputeTessFactorContext(fxpTessFactor_V_LineDensity
, processedTessFactors
.lineDensityTessFactorCtx
);
1492 processedTessFactors
.numLines
= NumPointsForTessFactor(fxpTessFactor_V_LineDensity
) - 1; // don't draw last line at V == 1.
1494 RestorePartitioning();
1496 // Compute some initial data.
1498 // outside edge offsets
1499 m_NumPoints
= processedTessFactors
.numPointsPerLine
* processedTessFactors
.numLines
;
1500 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
1502 m_NumIndices
= m_NumPoints
;
1506 m_NumIndices
= processedTessFactors
.numLines
*(processedTessFactors
.numPointsPerLine
-1)*2;
1510 //---------------------------------------------------------------------------------------------------------------------------------
1511 // CHWTessellator::IsoLineGeneratePoints
1512 //---------------------------------------------------------------------------------------------------------------------------------
1513 void CHWTessellator::IsoLineGeneratePoints( const PROCESSED_TESS_FACTORS_ISOLINE
& processedTessFactors
)
1515 int line
, pointOffset
;
1516 for(line
= 0, pointOffset
= 0; line
< processedTessFactors
.numLines
; line
++)
1518 for(int point
= 0; point
< processedTessFactors
.numPointsPerLine
; point
++)
1521 SetTessellationParity(processedTessFactors
.lineDensityParity
);
1522 PlacePointIn1D(processedTessFactors
.lineDensityTessFactorCtx
,line
,fxpV
);
1524 SetTessellationParity(processedTessFactors
.lineDetailParity
);
1525 PlacePointIn1D(processedTessFactors
.lineDetailTessFactorCtx
,point
,fxpU
);
1527 DefinePoint(fxpU
,fxpV
,pointOffset
++);
1532 //---------------------------------------------------------------------------------------------------------------------------------
1533 // CHWTessellator::IsoLineGenerateConnectivity
1534 //---------------------------------------------------------------------------------------------------------------------------------
1535 void CHWTessellator::IsoLineGenerateConnectivity( const PROCESSED_TESS_FACTORS_ISOLINE
& processedTessFactors
)
1537 int line
, pointOffset
, indexOffset
;
1538 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
1540 for(line
= 0, pointOffset
= 0, indexOffset
= 0; line
< processedTessFactors
.numLines
; line
++)
1542 for(int point
= 0; point
< processedTessFactors
.numPointsPerLine
; point
++)
1544 DefineIndex(pointOffset
++,indexOffset
++);
1550 for(line
= 0, pointOffset
= 0, indexOffset
= 0; line
< processedTessFactors
.numLines
; line
++)
1552 for(int point
= 0; point
< processedTessFactors
.numPointsPerLine
; point
++)
1556 DefineIndex(pointOffset
-1,indexOffset
++);
1557 DefineIndex(pointOffset
,indexOffset
++);
1565 //---------------------------------------------------------------------------------------------------------------------------------
1566 // CHWTessellator::GetPointCount
1568 //---------------------------------------------------------------------------------------------------------------------------------
1569 int CHWTessellator::GetPointCount()
1574 //---------------------------------------------------------------------------------------------------------------------------------
1575 // CHWTessellator::GetIndexCount()
1577 //---------------------------------------------------------------------------------------------------------------------------------
1578 int CHWTessellator::GetIndexCount()
1580 return m_NumIndices
;
1583 //---------------------------------------------------------------------------------------------------------------------------------
1584 // CHWTessellator::GetPoints()
1586 //---------------------------------------------------------------------------------------------------------------------------------
1587 DOMAIN_POINT
* CHWTessellator::GetPoints()
1591 //---------------------------------------------------------------------------------------------------------------------------------
1592 // CHWTessellator::GetIndices()
1594 //---------------------------------------------------------------------------------------------------------------------------------
1595 int* CHWTessellator::GetIndices()
1600 //---------------------------------------------------------------------------------------------------------------------------------
1601 // CHWTessellator::DefinePoint()
1602 //---------------------------------------------------------------------------------------------------------------------------------
1603 int CHWTessellator::DefinePoint(FXP fxpU
, FXP fxpV
, int pointStorageOffset
)
1606 // StringCchPrintf(foo,80,L"off:%d, uv=(%f,%f)\n",pointStorageOffset,fixedToFloat(fxpU),fixedToFloat(fxpV));
1607 // OutputDebugString(foo);
1608 m_Point
[pointStorageOffset
].u
= fixedToFloat(fxpU
);
1609 m_Point
[pointStorageOffset
].v
= fixedToFloat(fxpV
);
1610 return pointStorageOffset
;
1613 //---------------------------------------------------------------------------------------------------------------------------------
1614 // CHWTessellator::DefineIndex()
1615 //--------------------------------------------------------------------------------------------------------------------------------
1616 void CHWTessellator::DefineIndex(int index
, int indexStorageOffset
)
1618 index
= PatchIndexValue(index
);
1620 // StringCchPrintf(foo,80,L"off:%d, idx=%d, uv=(%f,%f)\n",indexStorageOffset,index,m_Point[index].u,m_Point[index].v);
1621 // OutputDebugString(foo);
1622 m_Index
[indexStorageOffset
] = index
;
1625 //---------------------------------------------------------------------------------------------------------------------------------
1626 // CHWTessellator::DefineClockwiseTriangle()
1627 //---------------------------------------------------------------------------------------------------------------------------------
1628 void CHWTessellator::DefineClockwiseTriangle(int index0
, int index1
, int index2
, int indexStorageBaseOffset
)
1630 // inputs a clockwise triangle, stores a CW or CCW triangle depending on the state
1631 DefineIndex(index0
,indexStorageBaseOffset
);
1632 bool bWantClockwise
= (m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CW
) ? true : false;
1633 if( bWantClockwise
)
1635 DefineIndex(index1
,indexStorageBaseOffset
+1);
1636 DefineIndex(index2
,indexStorageBaseOffset
+2);
1640 DefineIndex(index2
,indexStorageBaseOffset
+1);
1641 DefineIndex(index1
,indexStorageBaseOffset
+2);
1645 //---------------------------------------------------------------------------------------------------------------------------------
1646 // CHWTessellator::DumpAllPoints()
1647 //---------------------------------------------------------------------------------------------------------------------------------
1648 void CHWTessellator::DumpAllPoints()
1650 for( int p
= 0; p
< m_NumPoints
; p
++ )
1652 DefineIndex(p
,m_NumIndices
++);
1656 //---------------------------------------------------------------------------------------------------------------------------------
1657 // CHWTessellator::DumpAllPointsAsInOrderLineList()
1658 //---------------------------------------------------------------------------------------------------------------------------------
1659 void CHWTessellator::DumpAllPointsAsInOrderLineList()
1661 for( int p
= 1; p
< m_NumPoints
; p
++ )
1663 DefineIndex(p
-1,m_NumIndices
++);
1664 DefineIndex(p
,m_NumIndices
++);
1668 //---------------------------------------------------------------------------------------------------------------------------------
1670 //---------------------------------------------------------------------------------------------------------------------------------
1671 int RemoveMSB(int val
)
1674 if( val
<= 0x0000ffff ) { check
= ( val
<= 0x000000ff ) ? 0x00000080 : 0x00008000; }
1675 else { check
= ( val
<= 0x00ffffff ) ? 0x00800000 : 0x80000000; }
1676 for( int i
= 0; i
< 8; i
++, check
>>= 1 ) { if( val
& check
) return (val
& ~check
); }
1679 //---------------------------------------------------------------------------------------------------------------------------------
1681 //---------------------------------------------------------------------------------------------------------------------------------
1685 if( val
<= 0x0000ffff ) { check
= ( val
<= 0x000000ff ) ? 0x00000080 : 0x00008000; }
1686 else { check
= ( val
<= 0x00ffffff ) ? 0x00800000 : 0x80000000; }
1687 for( int i
= 0; i
< 8; i
++, check
>>= 1 ) { if( val
& check
) return check
; }
1691 //---------------------------------------------------------------------------------------------------------------------------------
1692 // CHWTessellator::CleanseParameter()
1693 //---------------------------------------------------------------------------------------------------------------------------------
1694 /* NOTHING TO DO FOR FIXED POINT ARITHMETIC!
1695 void CHWTessellator::CleanseParameter(float& parameter)
1697 // Clean up [0..1] parameter to guarantee that (1 - (1 - parameter)) == parameter.
1698 parameter = 1.0f - parameter;
1699 parameter = 1.0f - parameter;
1703 //---------------------------------------------------------------------------------------------------------------------------------
1704 // CHWTessellator::NumPointsForTessFactor()
1705 //---------------------------------------------------------------------------------------------------------------------------------
1706 int CHWTessellator::NumPointsForTessFactor( FXP fxpTessFactor
)
1711 numPoints
= (fxpCeil(FXP_ONE_HALF
+ (fxpTessFactor
+1/*round*/)/2)*2)>>FXP_FRACTION_BITS
;
1715 numPoints
= ((fxpCeil((fxpTessFactor
+1/*round*/)/2)*2)>>FXP_FRACTION_BITS
)+1;
1720 //---------------------------------------------------------------------------------------------------------------------------------
1721 // CHWTessellator::ComputeTessFactorContext()
1722 //---------------------------------------------------------------------------------------------------------------------------------
1723 void CHWTessellator::ComputeTessFactorContext( FXP fxpTessFactor
, TESS_FACTOR_CONTEXT
& TessFactorCtx
)
1725 FXP fxpHalfTessFactor
= (fxpTessFactor
+1/*round*/)/2;
1726 if( Odd() || (fxpHalfTessFactor
== FXP_ONE_HALF
)) // fxpHalfTessFactor == 1/2 if TessFactor is 1, but we're pretending we are even.
1728 fxpHalfTessFactor
+= FXP_ONE_HALF
;
1730 FXP fxpFloorHalfTessFactor
= fxpFloor(fxpHalfTessFactor
);
1731 FXP fxpCeilHalfTessFactor
= fxpCeil(fxpHalfTessFactor
);
1732 TessFactorCtx
.fxpHalfTessFactorFraction
= fxpHalfTessFactor
- fxpFloorHalfTessFactor
;
1733 //CleanseParameter(TessFactorCtx.fxpHalfTessFactorFraction);
1734 TessFactorCtx
.numHalfTessFactorPoints
= (fxpCeilHalfTessFactor
>>FXP_FRACTION_BITS
); // for EVEN, we don't include the point always fixed at the midpoint of the TessFactor
1735 if( fxpCeilHalfTessFactor
== fxpFloorHalfTessFactor
)
1737 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= /*pick value to cause this to be ignored*/ TessFactorCtx
.numHalfTessFactorPoints
+1;
1741 if( fxpFloorHalfTessFactor
== FXP_ONE
)
1743 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= 0;
1747 #ifdef ALLOW_XBOX_360_COMPARISON
1748 if( m_bXBox360Mode
)
1749 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= TessFactorCtx
.numHalfTessFactorPoints
-2;
1752 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= (RemoveMSB((fxpFloorHalfTessFactor
>>FXP_FRACTION_BITS
)-1)<<1) + 1;
1757 #ifdef ALLOW_XBOX_360_COMPARISON
1758 if( m_bXBox360Mode
)
1759 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= TessFactorCtx
.numHalfTessFactorPoints
-1;
1762 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= (RemoveMSB(fxpFloorHalfTessFactor
>>FXP_FRACTION_BITS
)<<1) + 1;
1764 int numFloorSegments
= (fxpFloorHalfTessFactor
* 2)>>FXP_FRACTION_BITS
;
1765 int numCeilSegments
= (fxpCeilHalfTessFactor
* 2)>>FXP_FRACTION_BITS
;
1768 numFloorSegments
-= 1;
1769 numCeilSegments
-= 1;
1771 TessFactorCtx
.fxpInvNumSegmentsOnFloorTessFactor
= s_fixedReciprocal
[numFloorSegments
];
1772 TessFactorCtx
.fxpInvNumSegmentsOnCeilTessFactor
= s_fixedReciprocal
[numCeilSegments
];
1775 //---------------------------------------------------------------------------------------------------------------------------------
1776 // CHWTessellator::PlacePointIn1D()
1777 //---------------------------------------------------------------------------------------------------------------------------------
1778 void CHWTessellator::PlacePointIn1D( const TESS_FACTOR_CONTEXT
& TessFactorCtx
, int point
, FXP
& fxpLocation
)
1781 if( point
>= TessFactorCtx
.numHalfTessFactorPoints
)
1783 point
= (TessFactorCtx
.numHalfTessFactorPoints
<< 1) - point
;
1794 if( point
== TessFactorCtx
.numHalfTessFactorPoints
)
1796 fxpLocation
= FXP_ONE_HALF
; // special casing middle since 16 bit fixed math below can't reproduce 0.5 exactly
1799 unsigned int indexOnCeilHalfTessFactor
= point
;
1800 unsigned int indexOnFloorHalfTessFactor
= indexOnCeilHalfTessFactor
;
1801 if( point
> TessFactorCtx
.splitPointOnFloorHalfTessFactor
)
1803 indexOnFloorHalfTessFactor
-= 1;
1805 // For the fixed point multiplies below, we know the results are <= 16 bits because
1806 // the locations on the halfTessFactor are <= half the number of segments for the total TessFactor.
1807 // So a number divided by a number that is at least twice as big will give
1808 // a result no bigger than 0.5 (which in fixed point is 16 bits in our case)
1809 FXP fxpLocationOnFloorHalfTessFactor
= indexOnFloorHalfTessFactor
* TessFactorCtx
.fxpInvNumSegmentsOnFloorTessFactor
;
1810 FXP fxpLocationOnCeilHalfTessFactor
= indexOnCeilHalfTessFactor
* TessFactorCtx
.fxpInvNumSegmentsOnCeilTessFactor
;
1812 // Since we know the numbers calculated above are <= fixed point 0.5, and the equation
1813 // below is just lerping between two values <= fixed point 0.5 (0x00008000), then we know
1814 // that the final result before shifting by 16 bits is no larger than 0x80000000. Once we
1815 // shift that down by 16, we get the result of lerping 2 numbers <= 0.5, which is obviously
1816 // at most 0.5 (0x00008000)
1817 fxpLocation
= fxpLocationOnFloorHalfTessFactor
* (FXP_ONE
- TessFactorCtx
.fxpHalfTessFactorFraction
) +
1818 fxpLocationOnCeilHalfTessFactor
* (TessFactorCtx
.fxpHalfTessFactorFraction
);
1819 fxpLocation
= (fxpLocation
+ FXP_ONE_HALF
/*round*/) >> FXP_FRACTION_BITS
; // get back to n.16
1820 /* Commenting out floating point version. Note the parameter cleansing it does is not needed in fixed point.
1822 location = 1.0f - location; // complement produces cleansed result.
1824 CleanseParameter(location);
1828 fxpLocation
= FXP_ONE
- fxpLocation
;
1832 //---------------------------------------------------------------------------------------------------------------------------------
1833 // CHWTessellator::StitchRegular
1834 //---------------------------------------------------------------------------------------------------------------------------------
1835 void CHWTessellator::StitchRegular(bool bTrapezoid
,DIAGONALS diagonals
,
1836 int baseIndexOffset
, int numInsideEdgePoints
,
1837 int insideEdgePointBaseOffset
, int outsideEdgePointBaseOffset
)
1839 int insidePoint
= insideEdgePointBaseOffset
;
1840 int outsidePoint
= outsideEdgePointBaseOffset
;
1843 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1844 baseIndexOffset
+= 3; outsidePoint
++;
1849 case DIAGONALS_INSIDE_TO_OUTSIDE
:
1850 // Diagonals pointing from inside edge forward towards outside edge
1851 for( p
= 0; p
< numInsideEdgePoints
-1; p
++ )
1853 DefineClockwiseTriangle(insidePoint
,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
1854 baseIndexOffset
+= 3;
1856 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1857 baseIndexOffset
+= 3;
1858 insidePoint
++; outsidePoint
++;
1861 case DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE
: // Assumes ODD tessellation
1862 // Diagonals pointing from outside edge forward towards inside edge
1865 for( p
= 0; p
< numInsideEdgePoints
/2-1; p
++ )
1867 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1868 baseIndexOffset
+= 3;
1869 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1870 baseIndexOffset
+= 3;
1871 insidePoint
++; outsidePoint
++;
1875 DefineClockwiseTriangle(outsidePoint
,insidePoint
+1,insidePoint
,baseIndexOffset
);
1876 baseIndexOffset
+= 3;
1877 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1878 baseIndexOffset
+= 3;
1879 insidePoint
++; outsidePoint
++; p
+=2;
1882 for( ; p
< numInsideEdgePoints
; p
++ )
1884 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1885 baseIndexOffset
+= 3;
1886 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1887 baseIndexOffset
+= 3;
1888 insidePoint
++; outsidePoint
++;
1891 case DIAGONALS_MIRRORED
:
1892 // First half, diagonals pointing from outside of outside edge to inside of inside edge
1893 for( p
= 0; p
< numInsideEdgePoints
/2; p
++ )
1895 DefineClockwiseTriangle(outsidePoint
,insidePoint
+1,insidePoint
,baseIndexOffset
);
1896 baseIndexOffset
+= 3;
1897 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1898 baseIndexOffset
+= 3;
1899 insidePoint
++; outsidePoint
++;
1901 // Second half, diagonals pointing from inside of inside edge to outside of outside edge
1902 for( ; p
< numInsideEdgePoints
-1; p
++ )
1904 DefineClockwiseTriangle(insidePoint
,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
1905 baseIndexOffset
+= 3;
1906 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1907 baseIndexOffset
+= 3;
1908 insidePoint
++; outsidePoint
++;
1914 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1915 baseIndexOffset
+= 3;
1919 //---------------------------------------------------------------------------------------------------------------------------------
1920 // CHWTessellator::StitchTransition()
1921 //---------------------------------------------------------------------------------------------------------------------------------
1922 void CHWTessellator::StitchTransition(int baseIndexOffset
,
1923 int insideEdgePointBaseOffset
, int insideNumHalfTessFactorPoints
,
1924 TESSELLATOR_PARITY insideEdgeTessFactorParity
,
1925 int outsideEdgePointBaseOffset
, int outsideNumHalfTessFactorPoints
,
1926 TESSELLATOR_PARITY outsideTessFactorParity
1930 #ifdef ALLOW_XBOX_360_COMPARISON
1931 // Tables to assist in the stitching of 2 rows of points having arbitrary TessFactors.
1932 // The stitching order is governed by Ruler Function vertex split ordering (see external documentation).
1934 // The contents of the finalPointPositionTable are where vertex i [0..32] ends up on the half-edge
1935 // at the max tessellation amount given ruler-function split order.
1936 // Recall the other half of an edge is mirrored, so we only need to deal with one half.
1937 // This table is used to decide when to advance a point on the interior or exterior.
1938 // It supports odd TessFactor up to 65 and even TessFactor up to 64.
1939 static const int _finalPointPositionTable
[33] =
1940 { 0, 32, 16, 8, 17, 4, 18, 9, 19, 2, 20, 10, 21, 5, 22, 11, 23,
1941 1, 24, 12, 25, 6, 26, 13, 27, 3, 28, 14, 29, 7, 30, 15, 31 };
1942 // The loopStart and loopEnd tables below just provide optimal loop bounds for the
1943 // stitching algorithm further below, for any given halfTssFactor.
1944 // There is probably a better way to encode this...
1946 // loopStart[halfTessFactor] encodes the FIRST entry other that [0] in finalPointPositionTable[] above which is
1947 // less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
1948 static const int _loopStart
[33] =
1949 {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};
1950 // loopStart[halfTessFactor] encodes the LAST entry in finalPointPositionTable[] above which is
1951 // less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
1952 static const int _loopEnd
[33] =
1953 {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};
1954 const int* finalPointPositionTable
;
1955 const int* loopStart
;
1957 if( m_bXBox360Mode
)
1959 // The XBox360 vertex introduction order is always from the center of the edge.
1960 // So the final positions of points on the half-edge are this trivial table.
1961 static const int XBOXfinalPointPositionTable
[33] =
1962 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
1963 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 };
1964 // loopStart and loopEnd (meaning described above) also become trivial for XBox360 splitting.
1965 static const int XBOXloopStart
[33] =
1966 {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};
1967 static const int XBOXloopEnd
[33] =
1968 {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};
1970 finalPointPositionTable
= XBOXfinalPointPositionTable
;
1971 loopStart
= XBOXloopStart
;
1972 loopEnd
= XBOXloopEnd
;
1976 finalPointPositionTable
= _finalPointPositionTable
;
1977 loopStart
= _loopStart
;
1981 // Tables to assist in the stitching of 2 rows of points having arbitrary TessFactors.
1982 // The stitching order is governed by Ruler Function vertex split ordering (see external documentation).
1984 // The contents of the finalPointPositionTable are where vertex i [0..33] ends up on the half-edge
1985 // at the max tessellation amount given ruler-function split order.
1986 // Recall the other half of an edge is mirrored, so we only need to deal with one half.
1987 // This table is used to decide when to advance a point on the interior or exterior.
1988 // It supports odd TessFactor up to 65 and even TessFactor up to 64.
1989 static const int finalPointPositionTable
[33] =
1990 { 0, 32, 16, 8, 17, 4, 18, 9, 19, 2, 20, 10, 21, 5, 22, 11, 23,
1991 1, 24, 12, 25, 6, 26, 13, 27, 3, 28, 14, 29, 7, 30, 15, 31 };
1993 // The loopStart and loopEnd tables below just provide optimal loop bounds for the
1994 // stitching algorithm further below, for any given halfTssFactor.
1995 // There is probably a better way to encode this...
1997 // loopStart[halfTessFactor] encodes the FIRST entry in finalPointPositionTable[] above which is
1998 // less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
1999 static const int loopStart
[33] =
2000 {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};
2001 // loopStart[halfTessFactor] encodes the LAST entry in finalPointPositionTable[] above which is
2002 // less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
2003 static const int loopEnd
[33] =
2004 {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};
2006 if( TESSELLATOR_PARITY_ODD
== insideEdgeTessFactorParity
)
2008 insideNumHalfTessFactorPoints
-= 1;
2010 if( TESSELLATOR_PARITY_ODD
== outsideTessFactorParity
)
2012 outsideNumHalfTessFactorPoints
-= 1;
2015 int outsidePoint
= outsideEdgePointBaseOffset
;
2016 int insidePoint
= insideEdgePointBaseOffset
;
2018 // iStart,iEnd are a small optimization so the loop below doesn't have to go from 0 up to 31
2019 int iStart
= min(loopStart
[insideNumHalfTessFactorPoints
],loopStart
[outsideNumHalfTessFactorPoints
]);
2020 int iEnd
= max(loopEnd
[insideNumHalfTessFactorPoints
],loopEnd
[outsideNumHalfTessFactorPoints
]);
2022 if( finalPointPositionTable
[0] < outsideNumHalfTessFactorPoints
) // since we dont' start the loop at 0 below, we need a special case.
2025 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2026 baseIndexOffset
+= 3; outsidePoint
++;
2029 for(int i
= iStart
; i
<= iEnd
; i
++)
2031 if( /*(i>0) && <-- not needed since iStart is never 0*/(finalPointPositionTable
[i
] < insideNumHalfTessFactorPoints
))
2034 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2035 baseIndexOffset
+= 3; insidePoint
++;
2037 if((finalPointPositionTable
[i
] < outsideNumHalfTessFactorPoints
))
2040 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2041 baseIndexOffset
+= 3; outsidePoint
++;
2045 if( (insideEdgeTessFactorParity
!= outsideTessFactorParity
) || (insideEdgeTessFactorParity
== TESSELLATOR_PARITY_ODD
))
2047 if( insideEdgeTessFactorParity
== outsideTessFactorParity
)
2049 // Quad in the middle
2050 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2051 baseIndexOffset
+= 3;
2052 DefineClockwiseTriangle(insidePoint
+1,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
2053 baseIndexOffset
+= 3;
2057 else if( TESSELLATOR_PARITY_EVEN
== insideEdgeTessFactorParity
)
2059 // Triangle pointing inside
2060 DefineClockwiseTriangle(insidePoint
,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
2061 baseIndexOffset
+= 3;
2066 // Triangle pointing outside
2067 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2068 baseIndexOffset
+= 3;
2073 // Walk second half.
2074 for(int i
= iEnd
; i
>= iStart
; i
--)
2076 if((finalPointPositionTable
[i
] < outsideNumHalfTessFactorPoints
))
2079 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2080 baseIndexOffset
+= 3; outsidePoint
++;
2082 if( /*(i>0) && <-- not needed since iStart is never 0*/ (finalPointPositionTable
[i
] < insideNumHalfTessFactorPoints
))
2085 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2086 baseIndexOffset
+= 3; insidePoint
++;
2089 // Below case is not needed if we didn't optimize loop above and made it run from 31 down to 0.
2090 if((finalPointPositionTable
[0] < outsideNumHalfTessFactorPoints
))
2092 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2093 baseIndexOffset
+= 3; outsidePoint
++;
2097 //---------------------------------------------------------------------------------------------------------------------------------
2098 // CHWTessellator::PatchIndexValue()
2099 //--------------------------------------------------------------------------------------------------------------------------------
2100 int CHWTessellator::PatchIndexValue(int index
)
2102 if( m_bUsingPatchedIndices
)
2104 if( index
>= m_IndexPatchContext
.outsidePointIndexPatchBase
) // assumed remapped outide indices are > remapped inside vertices
2106 if( index
== m_IndexPatchContext
.outsidePointIndexBadValue
)
2107 index
= m_IndexPatchContext
.outsidePointIndexReplacementValue
;
2109 index
+= m_IndexPatchContext
.outsidePointIndexDeltaToRealValue
;
2113 if( index
== m_IndexPatchContext
.insidePointIndexBadValue
)
2114 index
= m_IndexPatchContext
.insidePointIndexReplacementValue
;
2116 index
+= m_IndexPatchContext
.insidePointIndexDeltaToRealValue
;
2119 else if( m_bUsingPatchedIndices2
)
2121 if( index
>= m_IndexPatchContext2
.baseIndexToInvert
)
2123 if( index
== m_IndexPatchContext2
.cornerCaseBadValue
)
2125 index
= m_IndexPatchContext2
.cornerCaseReplacementValue
;
2129 index
= m_IndexPatchContext2
.indexInversionEndPoint
- index
;
2132 else if( index
== m_IndexPatchContext2
.cornerCaseBadValue
)
2134 index
= m_IndexPatchContext2
.cornerCaseReplacementValue
;
2141 //=================================================================================================================================
2143 //=================================================================================================================================
2145 //---------------------------------------------------------------------------------------------------------------------------------
2146 // CHLSLTessellator::CHLSLTessellator
2147 //---------------------------------------------------------------------------------------------------------------------------------
2148 CHLSLTessellator::CHLSLTessellator()
2150 m_LastComputedTessFactors
[0] = m_LastComputedTessFactors
[1] = m_LastComputedTessFactors
[2] =
2151 m_LastComputedTessFactors
[3] = m_LastComputedTessFactors
[4] = m_LastComputedTessFactors
[5] = 0;
2154 //---------------------------------------------------------------------------------------------------------------------------------
2155 // CHLSLTessellator::Init
2157 //---------------------------------------------------------------------------------------------------------------------------------
2158 void CHLSLTessellator::Init(
2159 D3D11_TESSELLATOR_PARTITIONING partitioning
,
2160 D3D11_TESSELLATOR_REDUCTION insideTessFactorReduction
,
2161 D3D11_TESSELLATOR_QUAD_REDUCTION_AXIS quadInsideTessFactorReductionAxis
,
2162 D3D11_TESSELLATOR_OUTPUT_PRIMITIVE outputPrimitive
)
2164 CHWTessellator::Init(partitioning
,outputPrimitive
);
2165 m_LastComputedTessFactors
[0] = m_LastComputedTessFactors
[1] = m_LastComputedTessFactors
[2] =
2166 m_LastComputedTessFactors
[3] = m_LastComputedTessFactors
[4] = m_LastComputedTessFactors
[5] = 0;
2167 m_partitioning
= partitioning
;
2168 m_originalPartitioning
= partitioning
;
2169 switch( partitioning
)
2171 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
2174 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
2175 m_parity
= TESSELLATOR_PARITY_ODD
;
2177 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
2178 m_parity
= TESSELLATOR_PARITY_EVEN
;
2181 m_originalParity
= m_parity
;
2182 m_outputPrimitive
= outputPrimitive
;
2183 m_insideTessFactorReduction
= insideTessFactorReduction
;
2184 m_quadInsideTessFactorReductionAxis
= quadInsideTessFactorReductionAxis
;
2186 //---------------------------------------------------------------------------------------------------------------------------------
2187 // CHLSLTessellator::TessellateQuadDomain
2189 //---------------------------------------------------------------------------------------------------------------------------------
2190 void CHLSLTessellator::TessellateQuadDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
2191 float insideTessFactorScaleU
, float insideTessFactorScaleV
)
2193 QuadHLSLProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Ueq1
,tessFactor_Veq1
,insideTessFactorScaleU
,insideTessFactorScaleV
);
2195 CHWTessellator::TessellateQuadDomain(m_LastComputedTessFactors
[0],m_LastComputedTessFactors
[1],m_LastComputedTessFactors
[2],m_LastComputedTessFactors
[3],
2196 m_LastComputedTessFactors
[4],m_LastComputedTessFactors
[5]);
2199 //---------------------------------------------------------------------------------------------------------------------------------
2200 // CHLSLTessellator::QuadHLSLProcessTessFactors
2201 //---------------------------------------------------------------------------------------------------------------------------------
2202 void CHLSLTessellator::QuadHLSLProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
2203 float insideTessFactorScaleU
, float insideTessFactorScaleV
)
2205 if( !(tessFactor_Ueq0
> 0) ||// NaN will pass
2206 !(tessFactor_Veq0
> 0) ||
2207 !(tessFactor_Ueq1
> 0) ||
2208 !(tessFactor_Veq1
> 0) )
2210 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2211 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2212 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Ueq1
;
2213 m_LastUnRoundedComputedTessFactors
[3] = tessFactor_Veq1
;
2214 m_LastUnRoundedComputedTessFactors
[4] = 0;
2215 m_LastUnRoundedComputedTessFactors
[5] = 0;
2216 m_LastComputedTessFactors
[0] =
2217 m_LastComputedTessFactors
[1] =
2218 m_LastComputedTessFactors
[2] =
2219 m_LastComputedTessFactors
[3] =
2220 m_LastComputedTessFactors
[4] =
2221 m_LastComputedTessFactors
[5] = 0;
2225 CleanupFloatTessFactor(tessFactor_Ueq0
);// clamp to [1.0f..INF], NaN->1.0f
2226 CleanupFloatTessFactor(tessFactor_Veq0
);
2227 CleanupFloatTessFactor(tessFactor_Ueq1
);
2228 CleanupFloatTessFactor(tessFactor_Veq1
);
2230 // Save off tessFactors so they can be returned to app
2231 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2232 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2233 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Ueq1
;
2234 m_LastUnRoundedComputedTessFactors
[3] = tessFactor_Veq1
;
2236 // Process outside tessFactors
2237 float outsideTessFactor
[QUAD_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Ueq1
, tessFactor_Veq1
};
2239 TESSELLATOR_PARITY insideTessFactorParity
[QUAD_AXES
], outsideTessFactorParity
[QUAD_EDGES
];
2240 if( Pow2Partitioning() || IntegerPartitioning() )
2242 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
2244 RoundUpTessFactor(outsideTessFactor
[edge
]);
2245 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2246 int edgeEven
= isEven(outsideTessFactor
[edge
]);
2247 outsideTessFactorParity
[edge
] = edgeEven
? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2252 SetTessellationParity(m_originalParity
); // ClampTessFactor needs it
2253 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
2255 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2256 outsideTessFactorParity
[edge
] = m_originalParity
;
2260 // Compute inside TessFactors
2261 float insideTessFactor
[QUAD_AXES
];
2262 if( m_quadInsideTessFactorReductionAxis
== D3D11_TESSELLATOR_QUAD_REDUCTION_1_AXIS
)
2264 switch( m_insideTessFactorReduction
)
2266 case D3D11_TESSELLATOR_REDUCTION_MIN
:
2267 insideTessFactor
[U
] = fmin(fmin(tessFactor_Veq0
,tessFactor_Veq1
),fmin(tessFactor_Ueq0
,tessFactor_Ueq1
));
2269 case D3D11_TESSELLATOR_REDUCTION_MAX
:
2270 insideTessFactor
[U
] = fmax(fmax(tessFactor_Veq0
,tessFactor_Veq1
),fmax(tessFactor_Ueq0
,tessFactor_Ueq1
));
2272 case D3D11_TESSELLATOR_REDUCTION_AVERAGE
:
2273 insideTessFactor
[U
] = (tessFactor_Veq0
+ tessFactor_Veq1
+ tessFactor_Ueq0
+ tessFactor_Ueq1
) / 4;
2276 // Scale inside tessFactor based on user scale factor.
2278 ClampFloatTessFactorScale(insideTessFactorScaleU
); // clamp scale value to [0..1], NaN->0
2279 insideTessFactor
[U
] = insideTessFactor
[U
]*insideTessFactorScaleU
;
2281 // Compute inside parity
2282 if( Pow2Partitioning() || IntegerPartitioning() )
2284 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction + scale result that is based on unbounded user input
2285 m_LastUnRoundedComputedTessFactors
[4] = m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2286 RoundUpTessFactor(insideTessFactor
[U
]);
2287 insideTessFactorParity
[U
] =
2288 insideTessFactorParity
[V
] =
2289 (isEven(insideTessFactor
[U
]) || (FLOAT_ONE
== insideTessFactor
[U
]) )
2290 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2294 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction + scale result that is based on unbounded user input
2295 m_LastUnRoundedComputedTessFactors
[4] = m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2296 // no parity changes for fractional tessellation - just use what the user requested
2297 insideTessFactorParity
[U
] = insideTessFactorParity
[V
] = m_originalParity
;
2300 // To prevent snapping on edges, the "picture frame" comes
2301 // in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2302 if( (TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[U
]) &&
2303 (insideTessFactor
[U
] < FLOAT_THREE
) )
2305 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2307 insideTessFactor
[U
] = fmin(FLOAT_THREE
,fmax(fmax(tessFactor_Veq0
,tessFactor_Veq1
),fmax(tessFactor_Ueq0
,tessFactor_Ueq1
)));
2311 insideTessFactor
[U
] = fmin(FLOAT_THREE
,(tessFactor_Veq0
+ tessFactor_Veq1
+ tessFactor_Ueq0
+ tessFactor_Ueq1
) / 4);
2313 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction result that is based on unbounded user input
2314 m_LastUnRoundedComputedTessFactors
[4] = m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2315 if( IntegerPartitioning())
2317 RoundUpTessFactor(insideTessFactor
[U
]);
2318 insideTessFactorParity
[U
] =
2319 insideTessFactorParity
[V
] = isEven(insideTessFactor
[U
]) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2322 insideTessFactor
[V
] = insideTessFactor
[U
];
2326 switch( m_insideTessFactorReduction
)
2328 case D3D11_TESSELLATOR_REDUCTION_MIN
:
2329 insideTessFactor
[U
] = fmin(tessFactor_Veq0
,tessFactor_Veq1
);
2330 insideTessFactor
[V
] = fmin(tessFactor_Ueq0
,tessFactor_Ueq1
);
2332 case D3D11_TESSELLATOR_REDUCTION_MAX
:
2333 insideTessFactor
[U
] = fmax(tessFactor_Veq0
,tessFactor_Veq1
);
2334 insideTessFactor
[V
] = fmax(tessFactor_Ueq0
,tessFactor_Ueq1
);
2336 case D3D11_TESSELLATOR_REDUCTION_AVERAGE
:
2337 insideTessFactor
[U
] = (tessFactor_Veq0
+ tessFactor_Veq1
) / 2;
2338 insideTessFactor
[V
] = (tessFactor_Ueq0
+ tessFactor_Ueq1
) / 2;
2341 // Scale inside tessFactors based on user scale factor.
2343 ClampFloatTessFactorScale(insideTessFactorScaleU
); // clamp scale value to [0..1], NaN->0
2344 ClampFloatTessFactorScale(insideTessFactorScaleV
);
2345 insideTessFactor
[U
] = insideTessFactor
[U
]*insideTessFactorScaleU
;
2346 insideTessFactor
[V
] = insideTessFactor
[V
]*insideTessFactorScaleV
;
2348 // Compute inside parity
2349 if( Pow2Partitioning() || IntegerPartitioning() )
2351 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
2353 ClampTessFactor(insideTessFactor
[axis
]); // clamp reduction + scale result that is based on unbounded user input
2354 m_LastUnRoundedComputedTessFactors
[4+axis
] = insideTessFactor
[axis
]; // Save off TessFactors so they can be returned to app
2355 RoundUpTessFactor(insideTessFactor
[axis
]);
2356 insideTessFactorParity
[axis
] =
2357 (isEven(insideTessFactor
[axis
]) || (FLOAT_ONE
== insideTessFactor
[axis
]) )
2358 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2363 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction + scale result that is based on unbounded user input
2364 ClampTessFactor(insideTessFactor
[V
]); // clamp reduction + scale result that is based on unbounded user input
2365 m_LastUnRoundedComputedTessFactors
[4] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2366 m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[V
]; // Save off TessFactors so they can be returned to app
2367 // no parity changes for fractional tessellation - just use what the user requested
2368 insideTessFactorParity
[U
] = insideTessFactorParity
[V
] = m_originalParity
;
2371 // To prevent snapping on edges, the "picture frame" comes
2372 // in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2373 if( (TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[U
]) &&
2374 (insideTessFactor
[U
] < FLOAT_THREE
) )
2376 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2378 insideTessFactor
[U
] = fmin(FLOAT_THREE
,fmax(tessFactor_Veq0
,tessFactor_Veq1
));
2382 insideTessFactor
[U
] = fmin(FLOAT_THREE
,(tessFactor_Veq0
+ tessFactor_Veq1
) / 2);
2384 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction result that is based on unbounded user input
2385 m_LastUnRoundedComputedTessFactors
[4] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2386 if( IntegerPartitioning())
2388 RoundUpTessFactor(insideTessFactor
[U
]);
2389 insideTessFactorParity
[U
] = isEven(insideTessFactor
[U
]) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2393 if( (TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[V
]) &&
2394 (insideTessFactor
[V
] < FLOAT_THREE
) )
2396 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2398 insideTessFactor
[V
] = fmin(FLOAT_THREE
,fmax(tessFactor_Ueq0
,tessFactor_Ueq1
));
2402 insideTessFactor
[V
] = fmin(FLOAT_THREE
,(tessFactor_Ueq0
+ tessFactor_Ueq1
) / 2);
2404 ClampTessFactor(insideTessFactor
[V
]);// clamp reduction result that is based on unbounded user input
2405 m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[V
]; // Save off TessFactors so they can be returned to app
2406 if( IntegerPartitioning())
2408 RoundUpTessFactor(insideTessFactor
[V
]);
2409 insideTessFactorParity
[V
] = isEven(insideTessFactor
[V
]) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2413 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
2415 if( TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[axis
] )
2417 // Ensure the first ring ("picture frame") interpolates in on all sides
2418 // as much as the side with the minimum TessFactor. Prevents snapping to edge.
2419 if( (insideTessFactor
[axis
] < FLOAT_THREE
) && (insideTessFactor
[axis
] < insideTessFactor
[(axis
+1)&0x1]))
2421 insideTessFactor
[axis
] = fmin(insideTessFactor
[(axis
+1)&0x1],FLOAT_THREE
);
2422 m_LastUnRoundedComputedTessFactors
[4+axis
] = insideTessFactor
[axis
]; // Save off TessFactors so they can be returned to app
2428 // Save off TessFactors so they can be returned to app
2429 m_LastComputedTessFactors
[0] = outsideTessFactor
[Ueq0
];
2430 m_LastComputedTessFactors
[1] = outsideTessFactor
[Veq0
];
2431 m_LastComputedTessFactors
[2] = outsideTessFactor
[Ueq1
];
2432 m_LastComputedTessFactors
[3] = outsideTessFactor
[Veq1
];
2433 m_LastComputedTessFactors
[4] = insideTessFactor
[U
];
2434 m_LastComputedTessFactors
[5] = insideTessFactor
[V
];
2437 //---------------------------------------------------------------------------------------------------------------------------------
2438 // CHLSLTessellator::TessellateTriDomain
2440 //---------------------------------------------------------------------------------------------------------------------------------
2441 void CHLSLTessellator::TessellateTriDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
2442 float insideTessFactorScale
)
2444 TriHLSLProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Weq0
,insideTessFactorScale
);
2446 CHWTessellator::TessellateTriDomain(m_LastComputedTessFactors
[0],m_LastComputedTessFactors
[1],m_LastComputedTessFactors
[2],m_LastComputedTessFactors
[3]);
2449 //---------------------------------------------------------------------------------------------------------------------------------
2450 // CHLSLTessellator::TriHLSLProcessTessFactors
2451 //---------------------------------------------------------------------------------------------------------------------------------
2452 void CHLSLTessellator::TriHLSLProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
2453 float insideTessFactorScale
)
2455 if( !(tessFactor_Ueq0
> 0) || // NaN will pass
2456 !(tessFactor_Veq0
> 0) ||
2457 !(tessFactor_Weq0
> 0) )
2459 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2460 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2461 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Weq0
;
2462 m_LastUnRoundedComputedTessFactors
[3] =
2463 m_LastComputedTessFactors
[0] =
2464 m_LastComputedTessFactors
[1] =
2465 m_LastComputedTessFactors
[2] =
2466 m_LastComputedTessFactors
[3] = 0;
2470 CleanupFloatTessFactor(tessFactor_Ueq0
); // clamp to [1.0f..INF], NaN->1.0f
2471 CleanupFloatTessFactor(tessFactor_Veq0
);
2472 CleanupFloatTessFactor(tessFactor_Weq0
);
2474 // Save off TessFactors so they can be returned to app
2475 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2476 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2477 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Weq0
;
2479 // Process outside TessFactors
2480 float outsideTessFactor
[TRI_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Weq0
};
2482 if( Pow2Partitioning() || IntegerPartitioning() )
2484 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
2486 RoundUpTessFactor(outsideTessFactor
[edge
]); // for pow2 this rounds to pow2
2487 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2492 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
2494 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2498 // Compute inside TessFactor
2499 float insideTessFactor
;
2500 switch( m_insideTessFactorReduction
)
2502 case D3D11_TESSELLATOR_REDUCTION_MIN
:
2503 insideTessFactor
= fmin(fmin(tessFactor_Ueq0
,tessFactor_Veq0
),tessFactor_Weq0
);
2505 case D3D11_TESSELLATOR_REDUCTION_MAX
:
2506 insideTessFactor
= fmax(fmax(tessFactor_Ueq0
,tessFactor_Veq0
),tessFactor_Weq0
);
2508 case D3D11_TESSELLATOR_REDUCTION_AVERAGE
:
2509 insideTessFactor
= (tessFactor_Ueq0
+ tessFactor_Veq0
+ tessFactor_Weq0
) / 3;
2513 // Scale inside TessFactor based on user scale factor.
2514 ClampFloatTessFactorScale(insideTessFactorScale
); // clamp scale value to [0..1], NaN->0
2515 insideTessFactor
= insideTessFactor
*fmin(FLOAT_ONE
,insideTessFactorScale
);
2517 ClampTessFactor(insideTessFactor
); // clamp reduction + scale result that is based on unbounded user input
2518 m_LastUnRoundedComputedTessFactors
[3] = insideTessFactor
;// Save off TessFactors so they can be returned to app
2519 TESSELLATOR_PARITY parity
;
2520 if( Pow2Partitioning() || IntegerPartitioning() )
2522 RoundUpTessFactor(insideTessFactor
);
2523 parity
= (isEven(insideTessFactor
) || (FLOAT_ONE
== insideTessFactor
))
2524 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2528 parity
= m_originalParity
;
2531 if( (TESSELLATOR_PARITY_ODD
== parity
) &&
2532 (insideTessFactor
< FLOAT_THREE
))
2534 // To prevent snapping on edges, the "picture frame" comes
2535 // in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2536 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2538 insideTessFactor
= fmin(FLOAT_THREE
,fmax(tessFactor_Ueq0
,fmax(tessFactor_Veq0
,tessFactor_Weq0
)));
2542 insideTessFactor
= fmin(FLOAT_THREE
,(tessFactor_Ueq0
+ tessFactor_Veq0
+ tessFactor_Weq0
) / 3);
2544 ClampTessFactor(insideTessFactor
); // clamp reduction result that is based on unbounded user input
2545 m_LastUnRoundedComputedTessFactors
[3] = insideTessFactor
;// Save off TessFactors so they can be returned to app
2546 if( IntegerPartitioning())
2548 RoundUpTessFactor(insideTessFactor
);
2552 // Save off TessFactors so they can be returned to app
2553 m_LastComputedTessFactors
[0] = outsideTessFactor
[Ueq0
];
2554 m_LastComputedTessFactors
[1] = outsideTessFactor
[Veq0
];
2555 m_LastComputedTessFactors
[2] = outsideTessFactor
[Weq0
];
2556 m_LastComputedTessFactors
[3] = insideTessFactor
;
2559 //---------------------------------------------------------------------------------------------------------------------------------
2560 // CHLSLTessellator::TessellateIsoLineDomain
2562 //---------------------------------------------------------------------------------------------------------------------------------
2563 void CHLSLTessellator::TessellateIsoLineDomain( float TessFactor_U_LineDetail
, float TessFactor_V_LineDensity
)
2565 IsoLineHLSLProcessTessFactors(TessFactor_V_LineDensity
,TessFactor_U_LineDetail
);
2566 CHWTessellator::TessellateIsoLineDomain(m_LastComputedTessFactors
[0],m_LastComputedTessFactors
[1]);
2569 //---------------------------------------------------------------------------------------------------------------------------------
2570 // CHLSLTessellator::IsoLineHLSLProcessTessFactors
2571 //---------------------------------------------------------------------------------------------------------------------------------
2572 void CHLSLTessellator::IsoLineHLSLProcessTessFactors( float TessFactor_V_LineDensity
, float TessFactor_U_LineDetail
)
2574 if( !(TessFactor_V_LineDensity
> 0) || // NaN will pass
2575 !(TessFactor_U_LineDetail
> 0) )
2577 m_LastUnRoundedComputedTessFactors
[0] = TessFactor_V_LineDensity
;
2578 m_LastUnRoundedComputedTessFactors
[1] = TessFactor_U_LineDetail
;
2579 m_LastComputedTessFactors
[0] =
2580 m_LastComputedTessFactors
[1] = 0;
2584 CleanupFloatTessFactor(TessFactor_V_LineDensity
); // clamp to [1.0f..INF], NaN->1.0f
2585 CleanupFloatTessFactor(TessFactor_U_LineDetail
); // clamp to [1.0f..INF], NaN->1.0f
2587 ClampTessFactor(TessFactor_U_LineDetail
); // clamp unbounded user input based on tessellation mode
2589 m_LastUnRoundedComputedTessFactors
[1] = TessFactor_U_LineDetail
; // Save off TessFactors so they can be returned to app
2591 TESSELLATOR_PARITY parity
;
2592 if(Pow2Partitioning()||IntegerPartitioning())
2594 RoundUpTessFactor(TessFactor_U_LineDetail
);
2595 parity
= isEven(TessFactor_U_LineDetail
) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2599 parity
= m_originalParity
;
2602 FXP fxpTessFactor_U_LineDetail
= floatToFixed(TessFactor_U_LineDetail
);
2604 OverridePartitioning(D3D11_TESSELLATOR_PARTITIONING_INTEGER
);
2606 ClampTessFactor(TessFactor_V_LineDensity
); // Clamp unbounded user input to integer
2607 m_LastUnRoundedComputedTessFactors
[0] = TessFactor_V_LineDensity
; // Save off TessFactors so they can be returned to app
2609 RoundUpTessFactor(TessFactor_V_LineDensity
);
2611 RestorePartitioning();
2613 // Save off TessFactors so they can be returned to app
2614 m_LastComputedTessFactors
[0] = TessFactor_V_LineDensity
;
2615 m_LastComputedTessFactors
[1] = TessFactor_U_LineDetail
;
2618 //---------------------------------------------------------------------------------------------------------------------------------
2619 // CHLSLTessellator::ClampTessFactor()
2620 //---------------------------------------------------------------------------------------------------------------------------------
2621 void CHLSLTessellator::ClampTessFactor(float& TessFactor
)
2623 if( Pow2Partitioning() )
2625 TessFactor
= fmin( D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
, fmax( TessFactor
, D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
) );
2627 else if( IntegerPartitioning() )
2629 TessFactor
= fmin( D3D11_TESSELLATOR_MAX_TESSELLATION_FACTOR
, fmax( TessFactor
, D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
) );
2633 TessFactor
= fmin( D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
, fmax( TessFactor
, D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
) );
2637 TessFactor
= fmin( D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
, fmax( TessFactor
, D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
) );
2641 //---------------------------------------------------------------------------------------------------------------------------------
2642 // CHLSLTessellator::CleanupFloatTessFactor()
2643 //---------------------------------------------------------------------------------------------------------------------------------
2644 static const int exponentMask
= 0x7f800000;
2645 static const int mantissaMask
= 0x007fffff;
2646 void CHLSLTessellator::CleanupFloatTessFactor(float& input
)
2648 // If input is < 1.0f or NaN, clamp to 1.0f.
2649 // In other words, clamp input to [1.0f...+INF]
2650 int bits
= *(int*)&input
;
2651 if( ( ( ( bits
& exponentMask
) == exponentMask
) && ( bits
& mantissaMask
) ) ||// nan?
2658 //---------------------------------------------------------------------------------------------------------------------------------
2659 // CHLSLTessellator::ClampFloatTessFactorScale()
2660 //---------------------------------------------------------------------------------------------------------------------------------
2661 void CHLSLTessellator::ClampFloatTessFactorScale(float& input
)
2663 // If input is < 0.0f or NaN, clamp to 0.0f. > 1 clamps to 1.
2664 // In other words, clamp input to [0.0f...1.0f]
2665 int bits
= *(int*)&input
;
2666 if( ( ( ( bits
& exponentMask
) == exponentMask
) && ( bits
& mantissaMask
) ) ||// nan?
2671 else if( input
> 1 )
2677 //---------------------------------------------------------------------------------------------------------------------------------
2678 // CHLSLTessellator::RoundUpTessFactor()
2679 //---------------------------------------------------------------------------------------------------------------------------------
2680 static const int exponentLSB
= 0x00800000;
2681 void CHLSLTessellator::RoundUpTessFactor(float& TessFactor
)
2683 // Assume TessFactor is in [1.0f..+INF]
2684 if( Pow2Partitioning() )
2686 int bits
= *(int*)&TessFactor
;
2687 if( bits
& mantissaMask
)
2689 *(int*)&TessFactor
= (bits
& exponentMask
) + exponentLSB
;
2692 else if( IntegerPartitioning() )
2694 TessFactor
= ceil(TessFactor
);