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"
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 //---------------------------------------------------------------------------------------------------------------------------------
38 static bool tess_isNaN( float a
)
40 static const int exponentMask
= 0x7f800000;
41 static const int mantissaMask
= 0x007fffff;
43 return ( ( ( u
& exponentMask
) == exponentMask
) && ( u
& mantissaMask
) ); // NaN
46 //---------------------------------------------------------------------------------------------------------------------------------
48 //---------------------------------------------------------------------------------------------------------------------------------
49 static float tess_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 static float tess_fmin( float a
, float b
)
68 float _a
= tess_flush( a
);
69 float _b
= tess_flush( b
);
70 if( tess_isNaN( _b
) )
74 else if( ( _a
== 0 ) && ( _b
== 0 ) )
76 return ( (*(int*)&_a
) & 0x80000000 ) ? a
: b
;
78 return _a
< _b
? a
: b
;
81 //---------------------------------------------------------------------------------------------------------------------------------
83 //---------------------------------------------------------------------------------------------------------------------------------
84 static float tess_fmax( float a
, float b
)
86 float _a
= tess_flush( a
);
87 float _b
= tess_flush( b
);
89 if( tess_isNaN( _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 #if defined(_MSC_VER)
183 #pragma warning( suppress : 4293 )
185 _fxpMaxPosValueFloat
-= INT32( 1 ) << iShift
;
188 // The maximum negative fixed point value is -2^(i-1).
189 // The following constructs the floating point bit pattern for this value,
190 // as long as i >= 2.
191 // We need this number without the sign bit
192 _fxpMaxNegValueFloat
= (_fltExponentBias
+ c_uIBits
- 1) << _fltMantissaBitCount
;
196 // The maximum positive fixed point value is 2^(i) - 2^(-f).
197 // The following constructs the floating point bit pattern for this value,
198 // as long as i >= 2.
199 _fxpMaxPosValueFloat
= (_fltExponentBias
+ c_uIBits
) <<_fltMantissaBitCount
;
200 const INT32 iShift
= _fltMantissaBitCount
+ 1 - c_uIBits
- c_uFBits
;
203 // assert( iShift < 32 );
204 #if defined(_MSC_VER)
205 #pragma warning( suppress : 4293 )
207 _fxpMaxPosValueFloat
-= INT32( 1 ) << iShift
;
210 // The maximum negative fixed point value is 0.
211 _fxpMaxNegValueFloat
= 0;
214 // ------------------------------------------------------------------------
215 // float -> fixed conversion
216 // ------------------------------------------------------------------------
218 // ------------------------------------------------------------------------
219 // examine input float
220 // ------------------------------------------------------------------------
221 INT32 output
= *(INT32
*)&input
;
222 INT32 unbiasedExponent
= ((output
& _fltExponentMask
) >> _fltMantissaBitCount
) - _fltExponentBias
;
223 INT32 isNegative
= output
& _fltSignBit
;
225 // ------------------------------------------------------------------------
227 // ------------------------------------------------------------------------
228 if (unbiasedExponent
== (_fltExponentBias
+ 1) && (output
& _fltMantissaMask
))
233 // ------------------------------------------------------------------------
234 // too large positive
235 // ------------------------------------------------------------------------
236 else if (!isNegative
&& output
>= _fxpMaxPosValueFloat
) // integer compare
238 output
= c_iMaxResult
;
240 // ------------------------------------------------------------------------
241 // too large negative
242 // ------------------------------------------------------------------------
244 else if (isNegative
&& (output
& ~_fltSignBit
) >= _fxpMaxNegValueFloat
)
246 output
= c_iMinResult
;
248 // ------------------------------------------------------------------------
250 // ------------------------------------------------------------------------
251 else if (unbiasedExponent
< -c_uFBits
- 1)
256 // ------------------------------------------------------------------------
258 // ------------------------------------------------------------------------
261 // copy mantissa, add hidden bit
262 output
= (output
& _fltMantissaMask
) | _fltHiddenBit
;
264 INT32 extraBits
= _fltMantissaBitCount
- c_uFBits
- unbiasedExponent
;
267 // 2's complement if negative
270 output
= ~output
+ 1;
273 // From the range checks that led here, it is known that
274 // unbiasedExponent < c_uIBits. So, at most:
275 // (a) unbiasedExponent == c_uIBits - 1.
277 // From compile validation above, it is known that
278 // c_uIBits + c_uFBits <= _fltMantissaBitCount + 1).
280 // (b) _fltMantissaBitCount == _fxtIntBitCount + c_uFBits - 1
282 // Substituting (a) and (b) into extraBits calculation above:
283 // extraBits >= (_fxtIntBitCount + c_uFBits - 1)
284 // - c_uFBits - (c_uIBits - 1)
287 // Thus we only have to worry about shifting right by 0 or more
288 // bits to get the decimal to the right place, and never have
291 INT32 LSB
= 1 << extraBits
; // last bit being kept
292 INT32 extraBitsMask
= LSB
- 1;
293 INT32 half
= LSB
>> 1; // round bias
295 // round to nearest-even at LSB
296 if ((output
& LSB
) || (output
& extraBitsMask
) > half
)
301 // shift off the extra bits (sign extending)
302 output
>>= extraBits
;
306 output
<<= -extraBits
;
308 // 2's complement if negative
311 output
= ~output
+ 1;
317 //-----------------------------------------------------------------------------------------------------------------------------
319 #define FXP_INTEGER_BITS 15
320 #define FXP_FRACTION_BITS 16
321 #define FXP_FRACTION_MASK 0x0000ffff
322 #define FXP_INTEGER_MASK 0x7fff0000
323 #define FXP_THREE (3<<FXP_FRACTION_BITS)
324 #define FXP_ONE (1<<FXP_FRACTION_BITS)
325 #define FXP_ONE_THIRD 0x00005555
326 #define FXP_TWO_THIRDS 0x0000aaaa
327 #define FXP_ONE_HALF 0x00008000
329 #define FXP_MAX_INPUT_TESS_FACTOR_BEFORE_TRIPLE_AVERAGE 0x55540000 // 1/3 of max fixed point number - 1. Numbers less than
330 // or equal to this allows avg. reduction on a tri patch
331 // including rounding.
333 #define FXP_MAX_INPUT_TESS_FACTOR_BEFORE_PAIR_AVERAGE 0x7FFF0000 // 1/2 of max fixed point number - 1. Numbers less than
334 // or equal to this allows avg. reduction on a quad patch
335 // including rounding.
337 static const FXP s_fixedReciprocal
[D3D11_TESSELLATOR_MAX_TESSELLATION_FACTOR
+1] =
339 0xffffffff, // 1/0 is the first entry (unused)
340 0x10000, 0x8000, 0x5555, 0x4000,
341 0x3333, 0x2aab, 0x2492, 0x2000,
342 0x1c72, 0x199a, 0x1746, 0x1555,
343 0x13b1, 0x1249, 0x1111, 0x1000,
344 0xf0f, 0xe39, 0xd79, 0xccd,
345 0xc31, 0xba3, 0xb21, 0xaab,
346 0xa3d, 0x9d9, 0x97b, 0x925,
347 0x8d4, 0x889, 0x842, 0x800,
348 0x7c2, 0x788, 0x750, 0x71c,
349 0x6eb, 0x6bd, 0x690, 0x666,
350 0x63e, 0x618, 0x5f4, 0x5d1,
351 0x5b0, 0x591, 0x572, 0x555,
352 0x539, 0x51f, 0x505, 0x4ec,
353 0x4d5, 0x4be, 0x4a8, 0x492,
354 0x47e, 0x46a, 0x457, 0x444,
355 0x432, 0x421, 0x410, 0x400, // 1/64 is the last entry
358 #define FLOAT_THREE 3.0f
359 #define FLOAT_ONE 1.0f
361 //---------------------------------------------------------------------------------------------------------------------------------
363 //---------------------------------------------------------------------------------------------------------------------------------
364 FXP
floatToFixed(const float& input
)
366 return floatToIDotF
< FXP_INTEGER_BITS
, FXP_FRACTION_BITS
, /*bSigned*/false >( input
);
369 //---------------------------------------------------------------------------------------------------------------------------------
371 //---------------------------------------------------------------------------------------------------------------------------------
372 float fixedToFloat(const FXP
& input
)
374 // not worrying about denorm flushing the float operations (the DX spec behavior for div), since the numbers will not be that small during tessellation.
375 return ((float)(input
>>FXP_FRACTION_BITS
) + (float)(input
&FXP_FRACTION_MASK
)/(1<<FXP_FRACTION_BITS
));
378 //---------------------------------------------------------------------------------------------------------------------------------
380 //---------------------------------------------------------------------------------------------------------------------------------
381 bool isEven(const float& input
)
383 return (((int)input
) & 1) ? false : true;
386 //---------------------------------------------------------------------------------------------------------------------------------
388 //---------------------------------------------------------------------------------------------------------------------------------
389 FXP
fxpCeil(const FXP
& input
)
391 if( input
& FXP_FRACTION_MASK
)
393 return (input
& FXP_INTEGER_MASK
) + FXP_ONE
;
398 //---------------------------------------------------------------------------------------------------------------------------------
400 //---------------------------------------------------------------------------------------------------------------------------------
401 FXP
fxpFloor(const FXP
& input
)
403 return (input
& FXP_INTEGER_MASK
);
406 //=================================================================================================================================
408 //=================================================================================================================================
410 //---------------------------------------------------------------------------------------------------------------------------------
411 // CHWTessellator::CHWTessellator
412 //---------------------------------------------------------------------------------------------------------------------------------
413 CHWTessellator::CHWTessellator()
419 m_bUsingPatchedIndices
= false;
420 m_bUsingPatchedIndices2
= false;
421 #ifdef ALLOW_XBOX_360_COMPARISON
422 m_bXBox360Mode
= false;
425 //---------------------------------------------------------------------------------------------------------------------------------
426 // CHWTessellator::~CHWTessellator
427 //---------------------------------------------------------------------------------------------------------------------------------
428 CHWTessellator::~CHWTessellator()
434 //---------------------------------------------------------------------------------------------------------------------------------
435 // CHWTessellator::Init
437 //---------------------------------------------------------------------------------------------------------------------------------
438 void CHWTessellator::Init(
439 D3D11_TESSELLATOR_PARTITIONING partitioning
,
440 D3D11_TESSELLATOR_OUTPUT_PRIMITIVE outputPrimitive
)
444 m_Point
= new DOMAIN_POINT
[MAX_POINT_COUNT
];
448 m_Index
= new int[MAX_INDEX_COUNT
];
450 m_partitioning
= partitioning
;
451 m_originalPartitioning
= partitioning
;
452 switch( partitioning
)
454 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
457 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
458 m_parity
= TESSELLATOR_PARITY_ODD
;
460 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
461 m_parity
= TESSELLATOR_PARITY_EVEN
;
464 m_originalParity
= m_parity
;
465 m_outputPrimitive
= outputPrimitive
;
469 //---------------------------------------------------------------------------------------------------------------------------------
470 // CHWTessellator::TessellateQuadDomain
472 //---------------------------------------------------------------------------------------------------------------------------------
473 void CHWTessellator::TessellateQuadDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
474 float insideTessFactor_U
, float insideTessFactor_V
)
476 PROCESSED_TESS_FACTORS_QUAD processedTessFactors
;
477 QuadProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Ueq1
,tessFactor_Veq1
,insideTessFactor_U
,insideTessFactor_V
,processedTessFactors
);
479 if( processedTessFactors
.bPatchCulled
)
485 else if( processedTessFactors
.bJustDoMinimumTessFactor
)
487 DefinePoint(/*U*/0,/*V*/0,/*pointStorageOffset*/0);
488 DefinePoint(/*U*/FXP_ONE
,/*V*/0,/*pointStorageOffset*/1);
489 DefinePoint(/*U*/FXP_ONE
,/*V*/FXP_ONE
,/*pointStorageOffset*/2);
490 DefinePoint(/*U*/0,/*V*/FXP_ONE
,/*pointStorageOffset*/3);
493 switch(m_outputPrimitive
)
495 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CW
:
496 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CCW
:
497 // function orients them CCW if needed
498 DefineClockwiseTriangle(0,1,3,/*indexStorageOffset*/0);
499 DefineClockwiseTriangle(1,2,3,/*indexStorageOffset*/3);
502 case D3D11_TESSELLATOR_OUTPUT_POINT
:
505 case D3D11_TESSELLATOR_OUTPUT_LINE
:
506 DumpAllPointsAsInOrderLineList();
512 QuadGeneratePoints(processedTessFactors
);
514 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
519 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_LINE
)
521 DumpAllPointsAsInOrderLineList();
525 QuadGenerateConnectivity(processedTessFactors
); // can be done in parallel to QuadGeneratePoints()
528 //---------------------------------------------------------------------------------------------------------------------------------
529 // CHWTessellator::QuadProcessTessFactors
530 //---------------------------------------------------------------------------------------------------------------------------------
531 void CHWTessellator::QuadProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
532 float insideTessFactor_U
, float insideTessFactor_V
, PROCESSED_TESS_FACTORS_QUAD
& processedTessFactors
)
534 // Is the patch culled?
535 if( !(tessFactor_Ueq0
> 0) || // NaN will pass
536 !(tessFactor_Veq0
> 0) ||
537 !(tessFactor_Ueq1
> 0) ||
538 !(tessFactor_Veq1
> 0) )
540 processedTessFactors
.bPatchCulled
= true;
545 processedTessFactors
.bPatchCulled
= false;
548 // Clamp edge TessFactors
549 float lowerBound
= 0.0, upperBound
= 0.0;
550 switch(m_originalPartitioning
)
552 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
553 case D3D11_TESSELLATOR_PARTITIONING_POW2
: // don�t care about pow2 distinction for validation, just treat as integer
554 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
555 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
558 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
559 lowerBound
= D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
;
560 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
563 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
564 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
565 upperBound
= D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
;
569 tessFactor_Ueq0
= tess_fmin( upperBound
, tess_fmax( lowerBound
, tessFactor_Ueq0
) );
570 tessFactor_Veq0
= tess_fmin( upperBound
, tess_fmax( lowerBound
, tessFactor_Veq0
) );
571 tessFactor_Ueq1
= tess_fmin( upperBound
, tess_fmax( lowerBound
, tessFactor_Ueq1
) );
572 tessFactor_Veq1
= tess_fmin( upperBound
, tess_fmax( lowerBound
, tessFactor_Veq1
) );
574 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
576 tessFactor_Ueq0
= ceil(tessFactor_Ueq0
);
577 tessFactor_Veq0
= ceil(tessFactor_Veq0
);
578 tessFactor_Ueq1
= ceil(tessFactor_Ueq1
);
579 tessFactor_Veq1
= ceil(tessFactor_Veq1
);
582 // Clamp inside TessFactors
583 if(D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
== m_originalPartitioning
)
585 #define EPSILON 0.0000152587890625f // 2^(-16), min positive fixed point fraction
586 #define MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON (D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON/2)
587 // If any TessFactor will end up > 1 after floatToFixed conversion later,
588 // then force the inside TessFactors to be > 1 so there is a picture frame.
589 if( (tessFactor_Ueq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
590 (tessFactor_Veq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
591 (tessFactor_Ueq1
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
592 (tessFactor_Veq1
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
593 (insideTessFactor_U
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
594 (insideTessFactor_V
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) )
596 // Force picture frame
597 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
+ EPSILON
;
601 insideTessFactor_U
= tess_fmin( upperBound
, tess_fmax( lowerBound
, insideTessFactor_U
) );
602 insideTessFactor_V
= tess_fmin( upperBound
, tess_fmax( lowerBound
, insideTessFactor_V
) );
603 // Note the above clamps map NaN to lowerBound
606 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
608 insideTessFactor_U
= ceil(insideTessFactor_U
);
609 insideTessFactor_V
= ceil(insideTessFactor_V
);
612 // Reset our vertex and index buffers. We have enough storage for the max tessFactor.
616 // Process tessFactors
617 float outsideTessFactor
[QUAD_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Ueq1
, tessFactor_Veq1
};
618 float insideTessFactor
[QUAD_AXES
] = {insideTessFactor_U
,insideTessFactor_V
};
620 if( HWIntegerPartitioning() )
622 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
624 int edgeEven
= isEven(outsideTessFactor
[edge
]);
625 processedTessFactors
.outsideTessFactorParity
[edge
] = edgeEven
? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
627 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
629 processedTessFactors
.insideTessFactorParity
[axis
] =
630 (isEven(insideTessFactor
[axis
]) || (FLOAT_ONE
== insideTessFactor
[axis
]) )
631 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
636 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
638 processedTessFactors
.outsideTessFactorParity
[edge
] = m_originalParity
;
640 processedTessFactors
.insideTessFactorParity
[U
] = processedTessFactors
.insideTessFactorParity
[V
] = m_originalParity
;
643 // Save fixed point TessFactors
644 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
646 processedTessFactors
.outsideTessFactor
[edge
] = floatToFixed(outsideTessFactor
[edge
]);
648 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
650 processedTessFactors
.insideTessFactor
[axis
] = floatToFixed(insideTessFactor
[axis
]);
653 if( HWIntegerPartitioning() || Odd() )
655 // Special case if all TessFactors are 1
656 if( (FXP_ONE
== processedTessFactors
.insideTessFactor
[U
]) &&
657 (FXP_ONE
== processedTessFactors
.insideTessFactor
[V
]) &&
658 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Ueq0
]) &&
659 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Veq0
]) &&
660 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Ueq1
]) &&
661 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Veq1
]) )
663 processedTessFactors
.bJustDoMinimumTessFactor
= true;
667 processedTessFactors
.bJustDoMinimumTessFactor
= false;
669 // Compute TessFactor-specific metadata
670 for(int edge
= 0; edge
< QUAD_EDGES
; edge
++ )
672 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
673 ComputeTessFactorContext(processedTessFactors
.outsideTessFactor
[edge
], processedTessFactors
.outsideTessFactorCtx
[edge
]);
676 for(int axis
= 0; axis
< QUAD_AXES
; axis
++)
678 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[axis
]);
679 ComputeTessFactorContext(processedTessFactors
.insideTessFactor
[axis
], processedTessFactors
.insideTessFactorCtx
[axis
]);
682 // Compute some initial data.
684 // outside edge offsets and storage
685 for(int edge
= 0; edge
< QUAD_EDGES
; edge
++ )
687 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
688 processedTessFactors
.numPointsForOutsideEdge
[edge
] = NumPointsForTessFactor(processedTessFactors
.outsideTessFactor
[edge
]);
689 m_NumPoints
+= processedTessFactors
.numPointsForOutsideEdge
[edge
];
693 // inside edge offsets
694 for(int axis
= 0; axis
< QUAD_AXES
; axis
++)
696 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[axis
]);
697 processedTessFactors
.numPointsForInsideTessFactor
[axis
] = NumPointsForTessFactor(processedTessFactors
.insideTessFactor
[axis
]);
698 int pointCountMin
= ( TESSELLATOR_PARITY_ODD
== processedTessFactors
.insideTessFactorParity
[axis
] ) ? 4 : 3;
699 // max() allows degenerate transition regions when inside TessFactor == 1
700 processedTessFactors
.numPointsForInsideTessFactor
[axis
] = max(pointCountMin
,processedTessFactors
.numPointsForInsideTessFactor
[axis
]);
703 processedTessFactors
.insideEdgePointBaseOffset
= m_NumPoints
;
705 // inside storage, including interior edges above
706 int numInteriorPoints
= (processedTessFactors
.numPointsForInsideTessFactor
[U
] - 2)*(processedTessFactors
.numPointsForInsideTessFactor
[V
]-2);
707 m_NumPoints
+= numInteriorPoints
;
710 //---------------------------------------------------------------------------------------------------------------------------------
711 // CHWTessellator::QuadGeneratePoints
712 //---------------------------------------------------------------------------------------------------------------------------------
713 void CHWTessellator::QuadGeneratePoints( const PROCESSED_TESS_FACTORS_QUAD
& processedTessFactors
)
715 // Generate exterior ring edge points, clockwise from top-left
718 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
720 int parity
= edge
&0x1;
722 int endPoint
= processedTessFactors
.numPointsForOutsideEdge
[edge
] - 1;
723 for(int p
= startPoint
; p
< endPoint
; p
++,pointOffset
++) // don't include end, since next edge starts with it.
726 int q
= ((edge
==1)||(edge
==2)) ? p
: endPoint
- p
; // reverse order
727 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
728 PlacePointIn1D(processedTessFactors
.outsideTessFactorCtx
[edge
],q
,fxpParam
);
731 DefinePoint(/*U*/fxpParam
,
732 /*V*/(edge
== 3) ? FXP_ONE
: 0,
733 /*pointStorageOffset*/pointOffset
);
737 DefinePoint(/*U*/(edge
== 2) ? FXP_ONE
: 0,
739 /*pointStorageOffset*/pointOffset
);
744 // Generate interior ring points, clockwise from (U==0,V==1) (bottom-left) spiralling toward center
745 static const int startRing
= 1;
746 int minNumPointsForTessFactor
= min(processedTessFactors
.numPointsForInsideTessFactor
[U
],processedTessFactors
.numPointsForInsideTessFactor
[V
]);
747 int numRings
= (minNumPointsForTessFactor
>> 1); // note for even tess we aren't counting center point here.
748 for(int ring
= startRing
; ring
< numRings
; ring
++)
750 int startPoint
= ring
;
751 int endPoint
[QUAD_AXES
] = {processedTessFactors
.numPointsForInsideTessFactor
[U
] - 1 - startPoint
,
752 processedTessFactors
.numPointsForInsideTessFactor
[V
] - 1 - startPoint
};
754 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
756 int parity
[QUAD_AXES
] = {edge
&0x1,((edge
+1)&0x1)};
757 int perpendicularAxisPoint
= (edge
< 2) ? startPoint
: endPoint
[parity
[0]];
759 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[parity
[0]]);
760 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[parity
[0]],perpendicularAxisPoint
,fxpPerpParam
);
761 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[parity
[1]]);
762 for(int p
= startPoint
; p
< endPoint
[parity
[1]]; p
++, pointOffset
++) // don't include end: next edge starts with it.
765 int q
= ((edge
== 1)||(edge
==2)) ? p
: endPoint
[parity
[1]] - (p
- startPoint
);
766 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[parity
[1]],q
,fxpParam
);
769 DefinePoint(/*U*/fxpPerpParam
,
771 /*pointStorageOffset*/pointOffset
);
775 DefinePoint(/*U*/fxpParam
,
777 /*pointStorageOffset*/pointOffset
);
782 // For even tessellation, the inner "ring" is degenerate - a row of points
783 if( (processedTessFactors
.numPointsForInsideTessFactor
[U
] > processedTessFactors
.numPointsForInsideTessFactor
[V
]) &&
784 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
]) )
786 int startPoint
= numRings
;
787 int endPoint
= processedTessFactors
.numPointsForInsideTessFactor
[U
] - 1 - startPoint
;
788 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[U
]);
789 for( int p
= startPoint
; p
<= endPoint
; p
++, pointOffset
++ )
792 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[U
],p
,fxpParam
);
793 DefinePoint(/*U*/fxpParam
,
794 /*V*/FXP_ONE_HALF
, // middle
795 /*pointStorageOffset*/pointOffset
);
798 else if( (processedTessFactors
.numPointsForInsideTessFactor
[V
] >= processedTessFactors
.numPointsForInsideTessFactor
[U
]) &&
799 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[U
]) )
801 int startPoint
= numRings
;
804 endPoint
= processedTessFactors
.numPointsForInsideTessFactor
[V
] - 1 - startPoint
;
805 SetTessellationParity(processedTessFactors
.insideTessFactorParity
[V
]);
806 for( int p
= endPoint
; p
>= startPoint
; p
--, pointOffset
++ )
808 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
[V
],p
,fxpParam
);
809 DefinePoint(/*U*/FXP_ONE_HALF
, // middle
811 /*pointStorageOffset*/pointOffset
);
815 //---------------------------------------------------------------------------------------------------------------------------------
816 // CHWTessellator::QuadGenerateConnectivity
817 //---------------------------------------------------------------------------------------------------------------------------------
818 void CHWTessellator::QuadGenerateConnectivity( const PROCESSED_TESS_FACTORS_QUAD
& processedTessFactors
)
820 // Generate primitives for all the concentric rings, one side at a time for each ring
821 static const int startRing
= 1;
822 int numPointRowsToCenter
[QUAD_AXES
] = {((processedTessFactors
.numPointsForInsideTessFactor
[U
]+1) >> 1),
823 ((processedTessFactors
.numPointsForInsideTessFactor
[V
]+1) >> 1)}; // +1 is so even tess includes the center point
824 int numRings
= min(numPointRowsToCenter
[U
],numPointRowsToCenter
[V
]);
825 int degeneratePointRing
[QUAD_AXES
] = { // Even partitioning causes degenerate row of points,
826 // which results in exceptions to the point ordering conventions
827 // when travelling around the rings counterclockwise.
828 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
]) ? numPointRowsToCenter
[V
] - 1 : -1,
829 (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[U
]) ? numPointRowsToCenter
[U
] - 1 : -1 };
831 const TESS_FACTOR_CONTEXT
* outsideTessFactorCtx
[QUAD_EDGES
] = {&processedTessFactors
.outsideTessFactorCtx
[Ueq0
],
832 &processedTessFactors
.outsideTessFactorCtx
[Veq0
],
833 &processedTessFactors
.outsideTessFactorCtx
[Ueq1
],
834 &processedTessFactors
.outsideTessFactorCtx
[Veq1
]};
835 TESSELLATOR_PARITY outsideTessFactorParity
[QUAD_EDGES
] = {processedTessFactors
.outsideTessFactorParity
[Ueq0
],
836 processedTessFactors
.outsideTessFactorParity
[Veq0
],
837 processedTessFactors
.outsideTessFactorParity
[Ueq1
],
838 processedTessFactors
.outsideTessFactorParity
[Veq1
]};
839 int numPointsForOutsideEdge
[QUAD_EDGES
] = {processedTessFactors
.numPointsForOutsideEdge
[Ueq0
],
840 processedTessFactors
.numPointsForOutsideEdge
[Veq0
],
841 processedTessFactors
.numPointsForOutsideEdge
[Ueq1
],
842 processedTessFactors
.numPointsForOutsideEdge
[Veq1
]};
844 int insideEdgePointBaseOffset
= processedTessFactors
.insideEdgePointBaseOffset
;
845 int outsideEdgePointBaseOffset
= 0;
847 for(int ring
= startRing
; ring
< numRings
; ring
++)
849 int numPointsForInsideEdge
[QUAD_AXES
] = {processedTessFactors
.numPointsForInsideTessFactor
[U
] - 2*ring
,
850 processedTessFactors
.numPointsForInsideTessFactor
[V
] - 2*ring
};
852 int edge0InsidePointBaseOffset
= insideEdgePointBaseOffset
;
853 int edge0OutsidePointBaseOffset
= outsideEdgePointBaseOffset
;
855 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
857 int parity
= (edge
+1)&0x1;
859 int numTriangles
= numPointsForInsideEdge
[parity
] + numPointsForOutsideEdge
[edge
] - 2;
860 int insideBaseOffset
;
861 int outsideBaseOffset
;
862 if( edge
== 3 ) // We need to patch the indexing so Stitch() can think it sees
863 // 2 sequentially increasing rows of points, even though we have wrapped around
864 // to the end of the inner and outer ring's points, so the last point is really
865 // the first point for the ring.
866 // We make it so that when Stitch() calls AddIndex(), that function
867 // will do any necessary index adjustment.
869 if( ring
== degeneratePointRing
[parity
] )
871 m_IndexPatchContext2
.baseIndexToInvert
= insideEdgePointBaseOffset
+ 1;
872 m_IndexPatchContext2
.cornerCaseBadValue
= outsideEdgePointBaseOffset
+ numPointsForOutsideEdge
[edge
] - 1;
873 m_IndexPatchContext2
.cornerCaseReplacementValue
= edge0OutsidePointBaseOffset
;
874 m_IndexPatchContext2
.indexInversionEndPoint
= (m_IndexPatchContext2
.baseIndexToInvert
<< 1) - 1;
875 insideBaseOffset
= m_IndexPatchContext2
.baseIndexToInvert
;
876 outsideBaseOffset
= outsideEdgePointBaseOffset
;
877 SetUsingPatchedIndices2(true);
881 m_IndexPatchContext
.insidePointIndexDeltaToRealValue
= insideEdgePointBaseOffset
;
882 m_IndexPatchContext
.insidePointIndexBadValue
= numPointsForInsideEdge
[parity
] - 1;
883 m_IndexPatchContext
.insidePointIndexReplacementValue
= edge0InsidePointBaseOffset
;
884 m_IndexPatchContext
.outsidePointIndexPatchBase
= m_IndexPatchContext
.insidePointIndexBadValue
+1; // past inside patched index range
885 m_IndexPatchContext
.outsidePointIndexDeltaToRealValue
= outsideEdgePointBaseOffset
886 - m_IndexPatchContext
.outsidePointIndexPatchBase
;
887 m_IndexPatchContext
.outsidePointIndexBadValue
= m_IndexPatchContext
.outsidePointIndexPatchBase
888 + numPointsForOutsideEdge
[edge
] - 1;
889 m_IndexPatchContext
.outsidePointIndexReplacementValue
= edge0OutsidePointBaseOffset
;
891 insideBaseOffset
= 0;
892 outsideBaseOffset
= m_IndexPatchContext
.outsidePointIndexPatchBase
;
893 SetUsingPatchedIndices(true);
896 else if( (edge
== 2) && (ring
== degeneratePointRing
[parity
]) )
898 m_IndexPatchContext2
.baseIndexToInvert
= insideEdgePointBaseOffset
;
899 m_IndexPatchContext2
.cornerCaseBadValue
= -1; // unused
900 m_IndexPatchContext2
.cornerCaseReplacementValue
= -1; // unused
901 m_IndexPatchContext2
.indexInversionEndPoint
= m_IndexPatchContext2
.baseIndexToInvert
<< 1;
902 insideBaseOffset
= m_IndexPatchContext2
.baseIndexToInvert
;
903 outsideBaseOffset
= outsideEdgePointBaseOffset
;
904 SetUsingPatchedIndices2(true);
908 insideBaseOffset
= insideEdgePointBaseOffset
;
909 outsideBaseOffset
= outsideEdgePointBaseOffset
;
911 if( ring
== startRing
)
913 StitchTransition(/*baseIndexOffset: */m_NumIndices
,
914 insideBaseOffset
,processedTessFactors
.insideTessFactorCtx
[parity
].numHalfTessFactorPoints
,processedTessFactors
.insideTessFactorParity
[parity
],
915 outsideBaseOffset
,outsideTessFactorCtx
[edge
]->numHalfTessFactorPoints
,outsideTessFactorParity
[edge
]);
919 StitchRegular(/*bTrapezoid*/true, DIAGONALS_MIRRORED
,
920 /*baseIndexOffset: */m_NumIndices
,
921 numPointsForInsideEdge
[parity
],
922 insideBaseOffset
,outsideBaseOffset
);
924 SetUsingPatchedIndices(false);
925 SetUsingPatchedIndices2(false);
926 m_NumIndices
+= numTriangles
*3;
927 outsideEdgePointBaseOffset
+= numPointsForOutsideEdge
[edge
] - 1;
928 if( (edge
== 2) && (ring
== degeneratePointRing
[parity
]) )
930 insideEdgePointBaseOffset
-= numPointsForInsideEdge
[parity
] - 1;
934 insideEdgePointBaseOffset
+= numPointsForInsideEdge
[parity
] - 1;
936 numPointsForOutsideEdge
[edge
] = numPointsForInsideEdge
[parity
];
938 if( startRing
== ring
)
940 for(edge
= 0; edge
< QUAD_EDGES
; edge
++ )
942 outsideTessFactorCtx
[edge
] = &processedTessFactors
.insideTessFactorCtx
[edge
&1];
943 outsideTessFactorParity
[edge
] = processedTessFactors
.insideTessFactorParity
[edge
&1];
948 // Triangulate center - a row of quads if odd
949 // This triangulation may be producing diagonals that are asymmetric about
950 // the center of the patch in this region.
951 if( (processedTessFactors
.numPointsForInsideTessFactor
[U
] > processedTessFactors
.numPointsForInsideTessFactor
[V
]) &&
952 (TESSELLATOR_PARITY_ODD
== processedTessFactors
.insideTessFactorParity
[V
] ) )
954 SetUsingPatchedIndices2(true);
955 int stripNumQuads
= (((processedTessFactors
.numPointsForInsideTessFactor
[U
]>>1) - (processedTessFactors
.numPointsForInsideTessFactor
[V
]>>1))<<1)+
956 ((TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[U
] ) ? 2 : 1);
957 m_IndexPatchContext2
.baseIndexToInvert
= outsideEdgePointBaseOffset
+ stripNumQuads
+ 2;
958 m_IndexPatchContext2
.cornerCaseBadValue
= m_IndexPatchContext2
.baseIndexToInvert
;
959 m_IndexPatchContext2
.cornerCaseReplacementValue
= outsideEdgePointBaseOffset
;
960 m_IndexPatchContext2
.indexInversionEndPoint
= m_IndexPatchContext2
.baseIndexToInvert
+
961 m_IndexPatchContext2
.baseIndexToInvert
+ stripNumQuads
;
962 StitchRegular(/*bTrapezoid*/false,DIAGONALS_INSIDE_TO_OUTSIDE
,
963 /*baseIndexOffset: */m_NumIndices
, /*numInsideEdgePoints:*/stripNumQuads
+1,
964 /*insideEdgePointBaseOffset*/m_IndexPatchContext2
.baseIndexToInvert
,
965 outsideEdgePointBaseOffset
+1);
966 SetUsingPatchedIndices2(false);
967 m_NumIndices
+= stripNumQuads
*6;
969 else if((processedTessFactors
.numPointsForInsideTessFactor
[V
] >= processedTessFactors
.numPointsForInsideTessFactor
[U
]) &&
970 (TESSELLATOR_PARITY_ODD
== processedTessFactors
.insideTessFactorParity
[U
]) )
972 SetUsingPatchedIndices2(true);
973 int stripNumQuads
= (((processedTessFactors
.numPointsForInsideTessFactor
[V
]>>1) - (processedTessFactors
.numPointsForInsideTessFactor
[U
]>>1))<<1)+
974 ((TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
] ) ? 2 : 1);
975 m_IndexPatchContext2
.baseIndexToInvert
= outsideEdgePointBaseOffset
+ stripNumQuads
+ 1;
976 m_IndexPatchContext2
.cornerCaseBadValue
= -1; // unused
977 m_IndexPatchContext2
.indexInversionEndPoint
= m_IndexPatchContext2
.baseIndexToInvert
+
978 m_IndexPatchContext2
.baseIndexToInvert
+ stripNumQuads
;
979 DIAGONALS diag
= (TESSELLATOR_PARITY_EVEN
== processedTessFactors
.insideTessFactorParity
[V
]) ?
980 DIAGONALS_INSIDE_TO_OUTSIDE
: DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE
;
981 StitchRegular(/*bTrapezoid*/false,diag
,
982 /*baseIndexOffset: */m_NumIndices
, /*numInsideEdgePoints:*/stripNumQuads
+1,
983 /*insideEdgePointBaseOffset*/m_IndexPatchContext2
.baseIndexToInvert
,
984 outsideEdgePointBaseOffset
);
985 SetUsingPatchedIndices2(false);
986 m_NumIndices
+= stripNumQuads
*6;
990 //---------------------------------------------------------------------------------------------------------------------------------
991 // CHWTessellator::TessellateTriDomain
993 //---------------------------------------------------------------------------------------------------------------------------------
994 void CHWTessellator::TessellateTriDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
995 float insideTessFactor
)
997 PROCESSED_TESS_FACTORS_TRI processedTessFactors
;
998 TriProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Weq0
,insideTessFactor
,processedTessFactors
);
1000 if( processedTessFactors
.bPatchCulled
)
1006 else if( processedTessFactors
.bJustDoMinimumTessFactor
)
1008 DefinePoint(/*U*/0,/*V*/FXP_ONE
,/*pointStorageOffset*/0); //V=1 (beginning of Ueq0 edge VW)
1009 DefinePoint(/*U*/0,/*V*/0,/*pointStorageOffset*/1); //W=1 (beginning of Veq0 edge WU)
1010 DefinePoint(/*U*/FXP_ONE
,/*V*/0,/*pointStorageOffset*/2); //U=1 (beginning of Weq0 edge UV)
1013 switch(m_outputPrimitive
)
1015 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CW
:
1016 case D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CCW
:
1017 // function orients them CCW if needed
1018 DefineClockwiseTriangle(0,1,2,/*indexStorageBaseOffset*/m_NumIndices
);
1021 case D3D11_TESSELLATOR_OUTPUT_POINT
:
1024 case D3D11_TESSELLATOR_OUTPUT_LINE
:
1025 DumpAllPointsAsInOrderLineList();
1031 TriGeneratePoints(processedTessFactors
);
1033 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
1038 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_LINE
)
1040 DumpAllPointsAsInOrderLineList();
1044 TriGenerateConnectivity(processedTessFactors
); // can be done in parallel to TriGeneratePoints()
1047 //---------------------------------------------------------------------------------------------------------------------------------
1048 // CHWTessellator::TriProcessTessFactors
1049 //---------------------------------------------------------------------------------------------------------------------------------
1050 void CHWTessellator::TriProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
1051 float insideTessFactor
, PROCESSED_TESS_FACTORS_TRI
& processedTessFactors
)
1053 // Is the patch culled?
1054 if( !(tessFactor_Ueq0
> 0) || // NaN will pass
1055 !(tessFactor_Veq0
> 0) ||
1056 !(tessFactor_Weq0
> 0) )
1058 processedTessFactors
.bPatchCulled
= true;
1063 processedTessFactors
.bPatchCulled
= false;
1066 // Clamp edge TessFactors
1067 float lowerBound
= 0.0, upperBound
= 0.0;
1068 switch(m_originalPartitioning
)
1070 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
1071 case D3D11_TESSELLATOR_PARTITIONING_POW2
: // don�t care about pow2 distinction for validation, just treat as integer
1072 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1073 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1076 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
1077 lowerBound
= D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
;
1078 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1081 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
1082 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1083 upperBound
= D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
;
1087 tessFactor_Ueq0
= tess_fmin( upperBound
, tess_fmax( lowerBound
, tessFactor_Ueq0
) );
1088 tessFactor_Veq0
= tess_fmin( upperBound
, tess_fmax( lowerBound
, tessFactor_Veq0
) );
1089 tessFactor_Weq0
= tess_fmin( upperBound
, tess_fmax( lowerBound
, tessFactor_Weq0
) );
1091 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
1093 tessFactor_Ueq0
= ceil(tessFactor_Ueq0
);
1094 tessFactor_Veq0
= ceil(tessFactor_Veq0
);
1095 tessFactor_Weq0
= ceil(tessFactor_Weq0
);
1098 // Clamp inside TessFactors
1099 if(D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
== m_originalPartitioning
)
1101 if( (tessFactor_Ueq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
1102 (tessFactor_Veq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
) ||
1103 (tessFactor_Weq0
> MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON
))
1104 // Don't need the same check for insideTessFactor for tri patches,
1105 // since there is only one insideTessFactor, as opposed to quad
1106 // patches which have 2 insideTessFactors.
1108 // Force picture frame
1109 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
+ EPSILON
;
1113 insideTessFactor
= tess_fmin( upperBound
, tess_fmax( lowerBound
, insideTessFactor
) );
1114 // Note the above clamps map NaN to lowerBound
1116 if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
1118 insideTessFactor
= ceil(insideTessFactor
);
1121 // Reset our vertex and index buffers. We have enough storage for the max tessFactor.
1125 // Process tessFactors
1126 float outsideTessFactor
[TRI_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Weq0
};
1128 if( HWIntegerPartitioning() )
1130 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
1132 int edgeEven
= isEven(outsideTessFactor
[edge
]);
1133 processedTessFactors
.outsideTessFactorParity
[edge
] = edgeEven
? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1135 processedTessFactors
.insideTessFactorParity
= (isEven(insideTessFactor
) || (FLOAT_ONE
== insideTessFactor
))
1136 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1140 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
1142 processedTessFactors
.outsideTessFactorParity
[edge
] = m_originalParity
;
1144 processedTessFactors
.insideTessFactorParity
= m_originalParity
;
1147 // Save fixed point TessFactors
1148 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
1150 processedTessFactors
.outsideTessFactor
[edge
] = floatToFixed(outsideTessFactor
[edge
]);
1152 processedTessFactors
.insideTessFactor
= floatToFixed(insideTessFactor
);
1154 if( HWIntegerPartitioning() || Odd() )
1156 // Special case if all TessFactors are 1
1157 if( (FXP_ONE
== processedTessFactors
.insideTessFactor
) &&
1158 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Ueq0
]) &&
1159 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Veq0
]) &&
1160 (FXP_ONE
== processedTessFactors
.outsideTessFactor
[Weq0
]) )
1162 processedTessFactors
.bJustDoMinimumTessFactor
= true;
1166 processedTessFactors
.bJustDoMinimumTessFactor
= false;
1168 // Compute per-TessFactor metadata
1169 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1171 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
1172 ComputeTessFactorContext(processedTessFactors
.outsideTessFactor
[edge
], processedTessFactors
.outsideTessFactorCtx
[edge
]);
1174 SetTessellationParity(processedTessFactors
.insideTessFactorParity
);
1175 ComputeTessFactorContext(processedTessFactors
.insideTessFactor
, processedTessFactors
.insideTessFactorCtx
);
1177 // Compute some initial data.
1179 // outside edge offsets and storage
1180 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1182 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
1183 processedTessFactors
.numPointsForOutsideEdge
[edge
] = NumPointsForTessFactor(processedTessFactors
.outsideTessFactor
[edge
]);
1184 m_NumPoints
+= processedTessFactors
.numPointsForOutsideEdge
[edge
];
1188 // inside edge offsets
1189 SetTessellationParity(processedTessFactors
.insideTessFactorParity
);
1190 processedTessFactors
.numPointsForInsideTessFactor
= NumPointsForTessFactor(processedTessFactors
.insideTessFactor
);
1192 int pointCountMin
= Odd() ? 4 : 3;
1193 // max() allows degenerate transition regions when inside TessFactor == 1
1194 processedTessFactors
.numPointsForInsideTessFactor
= max(pointCountMin
,processedTessFactors
.numPointsForInsideTessFactor
);
1197 processedTessFactors
.insideEdgePointBaseOffset
= m_NumPoints
;
1199 // inside storage, including interior edges above
1201 int numInteriorRings
= (processedTessFactors
.numPointsForInsideTessFactor
>> 1) - 1;
1202 int numInteriorPoints
;
1205 numInteriorPoints
= TRI_EDGES
*(numInteriorRings
*(numInteriorRings
+1) - numInteriorRings
);
1209 numInteriorPoints
= TRI_EDGES
*(numInteriorRings
*(numInteriorRings
+1)) + 1;
1211 m_NumPoints
+= numInteriorPoints
;
1216 //---------------------------------------------------------------------------------------------------------------------------------
1217 // CHWTessellator::TriGeneratePoints
1218 //---------------------------------------------------------------------------------------------------------------------------------
1219 void CHWTessellator::TriGeneratePoints( const PROCESSED_TESS_FACTORS_TRI
& processedTessFactors
)
1221 // Generate exterior ring edge points, clockwise starting from point V (VW, the U==0 edge)
1222 int pointOffset
= 0;
1224 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1226 int parity
= edge
&0x1;
1228 int endPoint
= processedTessFactors
.numPointsForOutsideEdge
[edge
] - 1;
1229 for(int p
= startPoint
; p
< endPoint
; p
++, pointOffset
++) // don't include end, since next edge starts with it.
1232 int q
= (parity
) ? p
: endPoint
- p
; // whether to reverse point order given we are defining V or U (W implicit):
1233 // edge0, VW, has V decreasing, so reverse 1D points below
1234 // edge1, WU, has U increasing, so don't reverse 1D points below
1235 // edge2, UV, has U decreasing, so reverse 1D points below
1236 SetTessellationParity(processedTessFactors
.outsideTessFactorParity
[edge
]);
1237 PlacePointIn1D(processedTessFactors
.outsideTessFactorCtx
[edge
],q
,fxpParam
);
1242 /*pointStorageOffset*/pointOffset
);
1246 DefinePoint(/*U*/fxpParam
,
1247 /*V*/(edge
== 2) ? FXP_ONE
- fxpParam
: 0,
1248 /*pointStorageOffset*/pointOffset
);
1253 // Generate interior ring points, clockwise spiralling in
1254 SetTessellationParity(processedTessFactors
.insideTessFactorParity
);
1255 static const int startRing
= 1;
1256 int numRings
= (processedTessFactors
.numPointsForInsideTessFactor
>> 1);
1257 for(int ring
= startRing
; ring
< numRings
; ring
++)
1259 int startPoint
= ring
;
1260 int endPoint
= processedTessFactors
.numPointsForInsideTessFactor
- 1 - startPoint
;
1262 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1264 int parity
= edge
&0x1;
1265 int perpendicularAxisPoint
= startPoint
;
1267 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
,perpendicularAxisPoint
,fxpPerpParam
);
1268 fxpPerpParam
*= FXP_TWO_THIRDS
; // Map location to the right size in barycentric space.
1269 // I (amarp) can draw a picture to explain.
1270 // We know this fixed point math won't over/underflow
1271 fxpPerpParam
= (fxpPerpParam
+FXP_ONE_HALF
/*round*/)>>FXP_FRACTION_BITS
; // get back to n.16
1272 for(int p
= startPoint
; p
< endPoint
; p
++, pointOffset
++) // don't include end: next edge starts with it.
1275 int q
= (parity
) ? p
: endPoint
- (p
- startPoint
); // whether to reverse point given we are defining V or U (W implicit):
1276 // edge0, VW, has V decreasing, so reverse 1D points below
1277 // edge1, WU, has U increasing, so don't reverse 1D points below
1278 // edge2, UV, has U decreasing, so reverse 1D points below
1279 PlacePointIn1D(processedTessFactors
.insideTessFactorCtx
,q
,fxpParam
);
1280 // edge0 VW, has perpendicular parameter U constant
1281 // edge1 WU, has perpendicular parameter V constant
1282 // edge2 UV, has perpendicular parameter W constant
1283 const unsigned int deriv
= 2; // reciprocal is the rate of change of edge-parallel parameters as they are pushed into the triangle
1287 DefinePoint(/*U*/fxpPerpParam
,
1288 /*V*/fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
, // we know this fixed point math won't over/underflow
1289 /*pointStorageOffset*/pointOffset
);
1292 DefinePoint(/*U*/fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
,// we know this fixed point math won't over/underflow
1294 /*pointStorageOffset*/pointOffset
);
1297 DefinePoint(/*U*/fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
,// we know this fixed point math won't over/underflow
1298 /*V*/FXP_ONE
- (fxpParam
- (fxpPerpParam
+1/*round*/)/deriv
) - fxpPerpParam
,// we know this fixed point math won't over/underflow
1299 /*pointStorageOffset*/pointOffset
);
1307 // Last point is the point at the center.
1308 DefinePoint(/*U*/FXP_ONE_THIRD
,
1310 /*pointStorageOffset*/pointOffset
);
1313 //---------------------------------------------------------------------------------------------------------------------------------
1314 // CHWTessellator::TriGenerateConnectivity
1315 //---------------------------------------------------------------------------------------------------------------------------------
1316 void CHWTessellator::TriGenerateConnectivity( const PROCESSED_TESS_FACTORS_TRI
& processedTessFactors
)
1318 // Generate primitives for all the concentric rings, one side at a time for each ring
1319 static const int startRing
= 1;
1320 int numRings
= ((processedTessFactors
.numPointsForInsideTessFactor
+1) >> 1); // +1 is so even tess includes the center point, which we want to now
1321 const TESS_FACTOR_CONTEXT
* outsideTessFactorCtx
[TRI_EDGES
] = {&processedTessFactors
.outsideTessFactorCtx
[Ueq0
],
1322 &processedTessFactors
.outsideTessFactorCtx
[Veq0
],
1323 &processedTessFactors
.outsideTessFactorCtx
[Weq0
]};
1324 TESSELLATOR_PARITY outsideTessFactorParity
[TRI_EDGES
] = {processedTessFactors
.outsideTessFactorParity
[Ueq0
],
1325 processedTessFactors
.outsideTessFactorParity
[Veq0
],
1326 processedTessFactors
.outsideTessFactorParity
[Weq0
]};
1327 int numPointsForOutsideEdge
[TRI_EDGES
] = {processedTessFactors
.numPointsForOutsideEdge
[Ueq0
],
1328 processedTessFactors
.numPointsForOutsideEdge
[Veq0
],
1329 processedTessFactors
.numPointsForOutsideEdge
[Weq0
]};
1331 int insideEdgePointBaseOffset
= processedTessFactors
.insideEdgePointBaseOffset
;
1332 int outsideEdgePointBaseOffset
= 0;
1334 for(int ring
= startRing
; ring
< numRings
; ring
++)
1336 int numPointsForInsideEdge
= processedTessFactors
.numPointsForInsideTessFactor
- 2*ring
;
1337 int edge0InsidePointBaseOffset
= insideEdgePointBaseOffset
;
1338 int edge0OutsidePointBaseOffset
= outsideEdgePointBaseOffset
;
1339 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1341 int numTriangles
= numPointsForInsideEdge
+ numPointsForOutsideEdge
[edge
] - 2;
1343 int insideBaseOffset
;
1344 int outsideBaseOffset
;
1347 m_IndexPatchContext
.insidePointIndexDeltaToRealValue
= insideEdgePointBaseOffset
;
1348 m_IndexPatchContext
.insidePointIndexBadValue
= numPointsForInsideEdge
- 1;
1349 m_IndexPatchContext
.insidePointIndexReplacementValue
= edge0InsidePointBaseOffset
;
1350 m_IndexPatchContext
.outsidePointIndexPatchBase
= m_IndexPatchContext
.insidePointIndexBadValue
+1; // past inside patched index range
1351 m_IndexPatchContext
.outsidePointIndexDeltaToRealValue
= outsideEdgePointBaseOffset
1352 - m_IndexPatchContext
.outsidePointIndexPatchBase
;
1353 m_IndexPatchContext
.outsidePointIndexBadValue
= m_IndexPatchContext
.outsidePointIndexPatchBase
1354 + numPointsForOutsideEdge
[edge
] - 1;
1355 m_IndexPatchContext
.outsidePointIndexReplacementValue
= edge0OutsidePointBaseOffset
;
1356 SetUsingPatchedIndices(true);
1357 insideBaseOffset
= 0;
1358 outsideBaseOffset
= m_IndexPatchContext
.outsidePointIndexPatchBase
;
1362 insideBaseOffset
= insideEdgePointBaseOffset
;
1363 outsideBaseOffset
= outsideEdgePointBaseOffset
;
1365 if( ring
== startRing
)
1367 StitchTransition(/*baseIndexOffset: */m_NumIndices
,
1368 insideBaseOffset
,processedTessFactors
.insideTessFactorCtx
.numHalfTessFactorPoints
,processedTessFactors
.insideTessFactorParity
,
1369 outsideBaseOffset
,outsideTessFactorCtx
[edge
]->numHalfTessFactorPoints
,outsideTessFactorParity
[edge
]);
1373 StitchRegular(/*bTrapezoid*/true, DIAGONALS_MIRRORED
,
1374 /*baseIndexOffset: */m_NumIndices
,
1375 numPointsForInsideEdge
,
1376 insideBaseOffset
,outsideBaseOffset
);
1380 SetUsingPatchedIndices(false);
1382 m_NumIndices
+= numTriangles
*3;
1383 outsideEdgePointBaseOffset
+= numPointsForOutsideEdge
[edge
] - 1;
1384 insideEdgePointBaseOffset
+= numPointsForInsideEdge
- 1;
1385 numPointsForOutsideEdge
[edge
] = numPointsForInsideEdge
;
1387 if( startRing
== ring
)
1389 for(edge
= 0; edge
< TRI_EDGES
; edge
++ )
1391 outsideTessFactorCtx
[edge
] = &processedTessFactors
.insideTessFactorCtx
;
1392 outsideTessFactorParity
[edge
] = processedTessFactors
.insideTessFactorParity
;
1398 // Triangulate center (a single triangle)
1399 DefineClockwiseTriangle(outsideEdgePointBaseOffset
, outsideEdgePointBaseOffset
+1, outsideEdgePointBaseOffset
+2,
1405 //---------------------------------------------------------------------------------------------------------------------------------
1406 // CHWTessellator::TessellateIsoLineDomain
1408 //---------------------------------------------------------------------------------------------------------------------------------
1409 void CHWTessellator::TessellateIsoLineDomain( float TessFactor_V_LineDensity
, float TessFactor_U_LineDetail
)
1411 PROCESSED_TESS_FACTORS_ISOLINE processedTessFactors
;
1412 IsoLineProcessTessFactors(TessFactor_V_LineDensity
,TessFactor_U_LineDetail
,processedTessFactors
);
1413 if( processedTessFactors
.bPatchCulled
)
1419 IsoLineGeneratePoints(processedTessFactors
);
1420 IsoLineGenerateConnectivity(processedTessFactors
); // can be done in parallel to IsoLineGeneratePoints
1423 //---------------------------------------------------------------------------------------------------------------------------------
1424 // CHWTessellator::IsoLineProcessTessFactors
1425 //---------------------------------------------------------------------------------------------------------------------------------
1426 void CHWTessellator::IsoLineProcessTessFactors( float TessFactor_V_LineDensity
, float TessFactor_U_LineDetail
,
1427 PROCESSED_TESS_FACTORS_ISOLINE
& processedTessFactors
)
1429 // Is the patch culled?
1430 if( !(TessFactor_V_LineDensity
> 0) || // NaN will pass
1431 !(TessFactor_U_LineDetail
> 0) )
1433 processedTessFactors
.bPatchCulled
= true;
1438 processedTessFactors
.bPatchCulled
= false;
1441 // Clamp edge TessFactors
1442 float lowerBound
= 0.0, upperBound
= 0.0;
1443 switch(m_originalPartitioning
)
1445 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
1446 case D3D11_TESSELLATOR_PARTITIONING_POW2
: // don�t care about pow2 distinction for validation, just treat as integer
1447 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1448 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1451 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
1452 lowerBound
= D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
;
1453 upperBound
= D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
;
1456 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
1457 lowerBound
= D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
;
1458 upperBound
= D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
;
1462 TessFactor_V_LineDensity
= tess_fmin( D3D11_TESSELLATOR_MAX_ISOLINE_DENSITY_TESSELLATION_FACTOR
,
1463 tess_fmax( D3D11_TESSELLATOR_MIN_ISOLINE_DENSITY_TESSELLATION_FACTOR
, TessFactor_V_LineDensity
) );
1464 TessFactor_U_LineDetail
= tess_fmin( upperBound
, tess_fmax( lowerBound
, TessFactor_U_LineDetail
) );
1466 // Reset our vertex and index buffers. We have enough storage for the max tessFactor.
1470 // Process tessFactors
1471 if( HWIntegerPartitioning() )
1473 TessFactor_U_LineDetail
= ceil(TessFactor_U_LineDetail
);
1474 processedTessFactors
.lineDetailParity
= isEven(TessFactor_U_LineDetail
) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1478 processedTessFactors
.lineDetailParity
= m_originalParity
;
1481 FXP fxpTessFactor_U_LineDetail
= floatToFixed(TessFactor_U_LineDetail
);
1483 SetTessellationParity(processedTessFactors
.lineDetailParity
);
1485 ComputeTessFactorContext(fxpTessFactor_U_LineDetail
, processedTessFactors
.lineDetailTessFactorCtx
);
1486 processedTessFactors
.numPointsPerLine
= NumPointsForTessFactor(fxpTessFactor_U_LineDetail
);
1488 OverridePartitioning(D3D11_TESSELLATOR_PARTITIONING_INTEGER
);
1490 TessFactor_V_LineDensity
= ceil(TessFactor_V_LineDensity
);
1491 processedTessFactors
.lineDensityParity
= isEven(TessFactor_V_LineDensity
) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
1492 SetTessellationParity(processedTessFactors
.lineDensityParity
);
1493 FXP fxpTessFactor_V_LineDensity
= floatToFixed(TessFactor_V_LineDensity
);
1494 ComputeTessFactorContext(fxpTessFactor_V_LineDensity
, processedTessFactors
.lineDensityTessFactorCtx
);
1496 processedTessFactors
.numLines
= NumPointsForTessFactor(fxpTessFactor_V_LineDensity
) - 1; // don't draw last line at V == 1.
1498 RestorePartitioning();
1500 // Compute some initial data.
1502 // outside edge offsets
1503 m_NumPoints
= processedTessFactors
.numPointsPerLine
* processedTessFactors
.numLines
;
1504 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
1506 m_NumIndices
= m_NumPoints
;
1510 m_NumIndices
= processedTessFactors
.numLines
*(processedTessFactors
.numPointsPerLine
-1)*2;
1514 //---------------------------------------------------------------------------------------------------------------------------------
1515 // CHWTessellator::IsoLineGeneratePoints
1516 //---------------------------------------------------------------------------------------------------------------------------------
1517 void CHWTessellator::IsoLineGeneratePoints( const PROCESSED_TESS_FACTORS_ISOLINE
& processedTessFactors
)
1519 int line
, pointOffset
;
1520 for(line
= 0, pointOffset
= 0; line
< processedTessFactors
.numLines
; line
++)
1522 for(int point
= 0; point
< processedTessFactors
.numPointsPerLine
; point
++)
1525 SetTessellationParity(processedTessFactors
.lineDensityParity
);
1526 PlacePointIn1D(processedTessFactors
.lineDensityTessFactorCtx
,line
,fxpV
);
1528 SetTessellationParity(processedTessFactors
.lineDetailParity
);
1529 PlacePointIn1D(processedTessFactors
.lineDetailTessFactorCtx
,point
,fxpU
);
1531 DefinePoint(fxpU
,fxpV
,pointOffset
++);
1536 //---------------------------------------------------------------------------------------------------------------------------------
1537 // CHWTessellator::IsoLineGenerateConnectivity
1538 //---------------------------------------------------------------------------------------------------------------------------------
1539 void CHWTessellator::IsoLineGenerateConnectivity( const PROCESSED_TESS_FACTORS_ISOLINE
& processedTessFactors
)
1541 int line
, pointOffset
, indexOffset
;
1542 if( m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_POINT
)
1544 for(line
= 0, pointOffset
= 0, indexOffset
= 0; line
< processedTessFactors
.numLines
; line
++)
1546 for(int point
= 0; point
< processedTessFactors
.numPointsPerLine
; point
++)
1548 DefineIndex(pointOffset
++,indexOffset
++);
1554 for(line
= 0, pointOffset
= 0, indexOffset
= 0; line
< processedTessFactors
.numLines
; line
++)
1556 for(int point
= 0; point
< processedTessFactors
.numPointsPerLine
; point
++)
1560 DefineIndex(pointOffset
-1,indexOffset
++);
1561 DefineIndex(pointOffset
,indexOffset
++);
1569 //---------------------------------------------------------------------------------------------------------------------------------
1570 // CHWTessellator::GetPointCount
1572 //---------------------------------------------------------------------------------------------------------------------------------
1573 int CHWTessellator::GetPointCount()
1578 //---------------------------------------------------------------------------------------------------------------------------------
1579 // CHWTessellator::GetIndexCount()
1581 //---------------------------------------------------------------------------------------------------------------------------------
1582 int CHWTessellator::GetIndexCount()
1584 return m_NumIndices
;
1587 //---------------------------------------------------------------------------------------------------------------------------------
1588 // CHWTessellator::GetPoints()
1590 //---------------------------------------------------------------------------------------------------------------------------------
1591 DOMAIN_POINT
* CHWTessellator::GetPoints()
1595 //---------------------------------------------------------------------------------------------------------------------------------
1596 // CHWTessellator::GetIndices()
1598 //---------------------------------------------------------------------------------------------------------------------------------
1599 int* CHWTessellator::GetIndices()
1604 //---------------------------------------------------------------------------------------------------------------------------------
1605 // CHWTessellator::DefinePoint()
1606 //---------------------------------------------------------------------------------------------------------------------------------
1607 int CHWTessellator::DefinePoint(FXP fxpU
, FXP fxpV
, int pointStorageOffset
)
1610 // StringCchPrintf(foo,80,L"off:%d, uv=(%f,%f)\n",pointStorageOffset,fixedToFloat(fxpU),fixedToFloat(fxpV));
1611 // OutputDebugString(foo);
1612 m_Point
[pointStorageOffset
].u
= fixedToFloat(fxpU
);
1613 m_Point
[pointStorageOffset
].v
= fixedToFloat(fxpV
);
1614 return pointStorageOffset
;
1617 //---------------------------------------------------------------------------------------------------------------------------------
1618 // CHWTessellator::DefineIndex()
1619 //--------------------------------------------------------------------------------------------------------------------------------
1620 void CHWTessellator::DefineIndex(int index
, int indexStorageOffset
)
1622 index
= PatchIndexValue(index
);
1624 // StringCchPrintf(foo,80,L"off:%d, idx=%d, uv=(%f,%f)\n",indexStorageOffset,index,m_Point[index].u,m_Point[index].v);
1625 // OutputDebugString(foo);
1626 m_Index
[indexStorageOffset
] = index
;
1629 //---------------------------------------------------------------------------------------------------------------------------------
1630 // CHWTessellator::DefineClockwiseTriangle()
1631 //---------------------------------------------------------------------------------------------------------------------------------
1632 void CHWTessellator::DefineClockwiseTriangle(int index0
, int index1
, int index2
, int indexStorageBaseOffset
)
1634 // inputs a clockwise triangle, stores a CW or CCW triangle depending on the state
1635 DefineIndex(index0
,indexStorageBaseOffset
);
1636 bool bWantClockwise
= (m_outputPrimitive
== D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CW
) ? true : false;
1637 if( bWantClockwise
)
1639 DefineIndex(index1
,indexStorageBaseOffset
+1);
1640 DefineIndex(index2
,indexStorageBaseOffset
+2);
1644 DefineIndex(index2
,indexStorageBaseOffset
+1);
1645 DefineIndex(index1
,indexStorageBaseOffset
+2);
1649 //---------------------------------------------------------------------------------------------------------------------------------
1650 // CHWTessellator::DumpAllPoints()
1651 //---------------------------------------------------------------------------------------------------------------------------------
1652 void CHWTessellator::DumpAllPoints()
1654 for( int p
= 0; p
< m_NumPoints
; p
++ )
1656 DefineIndex(p
,m_NumIndices
++);
1660 //---------------------------------------------------------------------------------------------------------------------------------
1661 // CHWTessellator::DumpAllPointsAsInOrderLineList()
1662 //---------------------------------------------------------------------------------------------------------------------------------
1663 void CHWTessellator::DumpAllPointsAsInOrderLineList()
1665 for( int p
= 1; p
< m_NumPoints
; p
++ )
1667 DefineIndex(p
-1,m_NumIndices
++);
1668 DefineIndex(p
,m_NumIndices
++);
1672 //---------------------------------------------------------------------------------------------------------------------------------
1674 //---------------------------------------------------------------------------------------------------------------------------------
1675 int RemoveMSB(int val
)
1678 if( val
<= 0x0000ffff ) { check
= ( val
<= 0x000000ff ) ? 0x00000080 : 0x00008000; }
1679 else { check
= ( val
<= 0x00ffffff ) ? 0x00800000 : 0x80000000; }
1680 for( int i
= 0; i
< 8; i
++, check
>>= 1 ) { if( val
& check
) return (val
& ~check
); }
1683 //---------------------------------------------------------------------------------------------------------------------------------
1685 //---------------------------------------------------------------------------------------------------------------------------------
1689 if( val
<= 0x0000ffff ) { check
= ( val
<= 0x000000ff ) ? 0x00000080 : 0x00008000; }
1690 else { check
= ( val
<= 0x00ffffff ) ? 0x00800000 : 0x80000000; }
1691 for( int i
= 0; i
< 8; i
++, check
>>= 1 ) { if( val
& check
) return check
; }
1695 //---------------------------------------------------------------------------------------------------------------------------------
1696 // CHWTessellator::CleanseParameter()
1697 //---------------------------------------------------------------------------------------------------------------------------------
1698 /* NOTHING TO DO FOR FIXED POINT ARITHMETIC!
1699 void CHWTessellator::CleanseParameter(float& parameter)
1701 // Clean up [0..1] parameter to guarantee that (1 - (1 - parameter)) == parameter.
1702 parameter = 1.0f - parameter;
1703 parameter = 1.0f - parameter;
1707 //---------------------------------------------------------------------------------------------------------------------------------
1708 // CHWTessellator::NumPointsForTessFactor()
1709 //---------------------------------------------------------------------------------------------------------------------------------
1710 int CHWTessellator::NumPointsForTessFactor( FXP fxpTessFactor
)
1715 numPoints
= (fxpCeil(FXP_ONE_HALF
+ (fxpTessFactor
+1/*round*/)/2)*2)>>FXP_FRACTION_BITS
;
1719 numPoints
= ((fxpCeil((fxpTessFactor
+1/*round*/)/2)*2)>>FXP_FRACTION_BITS
)+1;
1724 //---------------------------------------------------------------------------------------------------------------------------------
1725 // CHWTessellator::ComputeTessFactorContext()
1726 //---------------------------------------------------------------------------------------------------------------------------------
1727 void CHWTessellator::ComputeTessFactorContext( FXP fxpTessFactor
, TESS_FACTOR_CONTEXT
& TessFactorCtx
)
1729 FXP fxpHalfTessFactor
= (fxpTessFactor
+1/*round*/)/2;
1730 if( Odd() || (fxpHalfTessFactor
== FXP_ONE_HALF
)) // fxpHalfTessFactor == 1/2 if TessFactor is 1, but we're pretending we are even.
1732 fxpHalfTessFactor
+= FXP_ONE_HALF
;
1734 FXP fxpFloorHalfTessFactor
= fxpFloor(fxpHalfTessFactor
);
1735 FXP fxpCeilHalfTessFactor
= fxpCeil(fxpHalfTessFactor
);
1736 TessFactorCtx
.fxpHalfTessFactorFraction
= fxpHalfTessFactor
- fxpFloorHalfTessFactor
;
1737 //CleanseParameter(TessFactorCtx.fxpHalfTessFactorFraction);
1738 TessFactorCtx
.numHalfTessFactorPoints
= (fxpCeilHalfTessFactor
>>FXP_FRACTION_BITS
); // for EVEN, we don't include the point always fixed at the midpoint of the TessFactor
1739 if( fxpCeilHalfTessFactor
== fxpFloorHalfTessFactor
)
1741 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= /*pick value to cause this to be ignored*/ TessFactorCtx
.numHalfTessFactorPoints
+1;
1745 if( fxpFloorHalfTessFactor
== FXP_ONE
)
1747 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= 0;
1751 #ifdef ALLOW_XBOX_360_COMPARISON
1752 if( m_bXBox360Mode
)
1753 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= TessFactorCtx
.numHalfTessFactorPoints
-2;
1756 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= (RemoveMSB((fxpFloorHalfTessFactor
>>FXP_FRACTION_BITS
)-1)<<1) + 1;
1761 #ifdef ALLOW_XBOX_360_COMPARISON
1762 if( m_bXBox360Mode
)
1763 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= TessFactorCtx
.numHalfTessFactorPoints
-1;
1766 TessFactorCtx
.splitPointOnFloorHalfTessFactor
= (RemoveMSB(fxpFloorHalfTessFactor
>>FXP_FRACTION_BITS
)<<1) + 1;
1768 int numFloorSegments
= (fxpFloorHalfTessFactor
* 2)>>FXP_FRACTION_BITS
;
1769 int numCeilSegments
= (fxpCeilHalfTessFactor
* 2)>>FXP_FRACTION_BITS
;
1772 numFloorSegments
-= 1;
1773 numCeilSegments
-= 1;
1775 TessFactorCtx
.fxpInvNumSegmentsOnFloorTessFactor
= s_fixedReciprocal
[numFloorSegments
];
1776 TessFactorCtx
.fxpInvNumSegmentsOnCeilTessFactor
= s_fixedReciprocal
[numCeilSegments
];
1779 //---------------------------------------------------------------------------------------------------------------------------------
1780 // CHWTessellator::PlacePointIn1D()
1781 //---------------------------------------------------------------------------------------------------------------------------------
1782 void CHWTessellator::PlacePointIn1D( const TESS_FACTOR_CONTEXT
& TessFactorCtx
, int point
, FXP
& fxpLocation
)
1785 if( point
>= TessFactorCtx
.numHalfTessFactorPoints
)
1787 point
= (TessFactorCtx
.numHalfTessFactorPoints
<< 1) - point
;
1798 if( point
== TessFactorCtx
.numHalfTessFactorPoints
)
1800 fxpLocation
= FXP_ONE_HALF
; // special casing middle since 16 bit fixed math below can't reproduce 0.5 exactly
1803 unsigned int indexOnCeilHalfTessFactor
= point
;
1804 unsigned int indexOnFloorHalfTessFactor
= indexOnCeilHalfTessFactor
;
1805 if( point
> TessFactorCtx
.splitPointOnFloorHalfTessFactor
)
1807 indexOnFloorHalfTessFactor
-= 1;
1809 // For the fixed point multiplies below, we know the results are <= 16 bits because
1810 // the locations on the halfTessFactor are <= half the number of segments for the total TessFactor.
1811 // So a number divided by a number that is at least twice as big will give
1812 // a result no bigger than 0.5 (which in fixed point is 16 bits in our case)
1813 FXP fxpLocationOnFloorHalfTessFactor
= indexOnFloorHalfTessFactor
* TessFactorCtx
.fxpInvNumSegmentsOnFloorTessFactor
;
1814 FXP fxpLocationOnCeilHalfTessFactor
= indexOnCeilHalfTessFactor
* TessFactorCtx
.fxpInvNumSegmentsOnCeilTessFactor
;
1816 // Since we know the numbers calculated above are <= fixed point 0.5, and the equation
1817 // below is just lerping between two values <= fixed point 0.5 (0x00008000), then we know
1818 // that the final result before shifting by 16 bits is no larger than 0x80000000. Once we
1819 // shift that down by 16, we get the result of lerping 2 numbers <= 0.5, which is obviously
1820 // at most 0.5 (0x00008000)
1821 fxpLocation
= fxpLocationOnFloorHalfTessFactor
* (FXP_ONE
- TessFactorCtx
.fxpHalfTessFactorFraction
) +
1822 fxpLocationOnCeilHalfTessFactor
* (TessFactorCtx
.fxpHalfTessFactorFraction
);
1823 fxpLocation
= (fxpLocation
+ FXP_ONE_HALF
/*round*/) >> FXP_FRACTION_BITS
; // get back to n.16
1824 /* Commenting out floating point version. Note the parameter cleansing it does is not needed in fixed point.
1826 location = 1.0f - location; // complement produces cleansed result.
1828 CleanseParameter(location);
1832 fxpLocation
= FXP_ONE
- fxpLocation
;
1836 //---------------------------------------------------------------------------------------------------------------------------------
1837 // CHWTessellator::StitchRegular
1838 //---------------------------------------------------------------------------------------------------------------------------------
1839 void CHWTessellator::StitchRegular(bool bTrapezoid
,DIAGONALS diagonals
,
1840 int baseIndexOffset
, int numInsideEdgePoints
,
1841 int insideEdgePointBaseOffset
, int outsideEdgePointBaseOffset
)
1843 int insidePoint
= insideEdgePointBaseOffset
;
1844 int outsidePoint
= outsideEdgePointBaseOffset
;
1847 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1848 baseIndexOffset
+= 3; outsidePoint
++;
1853 case DIAGONALS_INSIDE_TO_OUTSIDE
:
1854 // Diagonals pointing from inside edge forward towards outside edge
1855 for( p
= 0; p
< numInsideEdgePoints
-1; p
++ )
1857 DefineClockwiseTriangle(insidePoint
,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
1858 baseIndexOffset
+= 3;
1860 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1861 baseIndexOffset
+= 3;
1862 insidePoint
++; outsidePoint
++;
1865 case DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE
: // Assumes ODD tessellation
1866 // Diagonals pointing from outside edge forward towards inside edge
1869 for( p
= 0; p
< numInsideEdgePoints
/2-1; p
++ )
1871 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1872 baseIndexOffset
+= 3;
1873 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1874 baseIndexOffset
+= 3;
1875 insidePoint
++; outsidePoint
++;
1879 DefineClockwiseTriangle(outsidePoint
,insidePoint
+1,insidePoint
,baseIndexOffset
);
1880 baseIndexOffset
+= 3;
1881 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1882 baseIndexOffset
+= 3;
1883 insidePoint
++; outsidePoint
++; p
+=2;
1886 for( ; p
< numInsideEdgePoints
; p
++ )
1888 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1889 baseIndexOffset
+= 3;
1890 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1891 baseIndexOffset
+= 3;
1892 insidePoint
++; outsidePoint
++;
1895 case DIAGONALS_MIRRORED
:
1896 // First half, diagonals pointing from outside of outside edge to inside of inside edge
1897 for( p
= 0; p
< numInsideEdgePoints
/2; p
++ )
1899 DefineClockwiseTriangle(outsidePoint
,insidePoint
+1,insidePoint
,baseIndexOffset
);
1900 baseIndexOffset
+= 3;
1901 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1902 baseIndexOffset
+= 3;
1903 insidePoint
++; outsidePoint
++;
1905 // Second half, diagonals pointing from inside of inside edge to outside of outside edge
1906 for( ; p
< numInsideEdgePoints
-1; p
++ )
1908 DefineClockwiseTriangle(insidePoint
,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
1909 baseIndexOffset
+= 3;
1910 DefineClockwiseTriangle(insidePoint
,outsidePoint
+1,insidePoint
+1,baseIndexOffset
);
1911 baseIndexOffset
+= 3;
1912 insidePoint
++; outsidePoint
++;
1918 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
1919 baseIndexOffset
+= 3;
1923 //---------------------------------------------------------------------------------------------------------------------------------
1924 // CHWTessellator::StitchTransition()
1925 //---------------------------------------------------------------------------------------------------------------------------------
1926 void CHWTessellator::StitchTransition(int baseIndexOffset
,
1927 int insideEdgePointBaseOffset
, int insideNumHalfTessFactorPoints
,
1928 TESSELLATOR_PARITY insideEdgeTessFactorParity
,
1929 int outsideEdgePointBaseOffset
, int outsideNumHalfTessFactorPoints
,
1930 TESSELLATOR_PARITY outsideTessFactorParity
1934 #ifdef ALLOW_XBOX_360_COMPARISON
1935 // Tables to assist in the stitching of 2 rows of points having arbitrary TessFactors.
1936 // The stitching order is governed by Ruler Function vertex split ordering (see external documentation).
1938 // The contents of the finalPointPositionTable are where vertex i [0..32] ends up on the half-edge
1939 // at the max tessellation amount given ruler-function split order.
1940 // Recall the other half of an edge is mirrored, so we only need to deal with one half.
1941 // This table is used to decide when to advance a point on the interior or exterior.
1942 // It supports odd TessFactor up to 65 and even TessFactor up to 64.
1943 static const int _finalPointPositionTable
[33] =
1944 { 0, 32, 16, 8, 17, 4, 18, 9, 19, 2, 20, 10, 21, 5, 22, 11, 23,
1945 1, 24, 12, 25, 6, 26, 13, 27, 3, 28, 14, 29, 7, 30, 15, 31 };
1946 // The loopStart and loopEnd tables below just provide optimal loop bounds for the
1947 // stitching algorithm further below, for any given halfTssFactor.
1948 // There is probably a better way to encode this...
1950 // loopStart[halfTessFactor] encodes the FIRST entry other that [0] 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 _loopStart
[33] =
1953 {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};
1954 // loopStart[halfTessFactor] encodes the LAST entry in finalPointPositionTable[] above which is
1955 // less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
1956 static const int _loopEnd
[33] =
1957 {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};
1958 const int* finalPointPositionTable
;
1959 const int* loopStart
;
1961 if( m_bXBox360Mode
)
1963 // The XBox360 vertex introduction order is always from the center of the edge.
1964 // So the final positions of points on the half-edge are this trivial table.
1965 static const int XBOXfinalPointPositionTable
[33] =
1966 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
1967 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 };
1968 // loopStart and loopEnd (meaning described above) also become trivial for XBox360 splitting.
1969 static const int XBOXloopStart
[33] =
1970 {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};
1971 static const int XBOXloopEnd
[33] =
1972 {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};
1974 finalPointPositionTable
= XBOXfinalPointPositionTable
;
1975 loopStart
= XBOXloopStart
;
1976 loopEnd
= XBOXloopEnd
;
1980 finalPointPositionTable
= _finalPointPositionTable
;
1981 loopStart
= _loopStart
;
1985 // Tables to assist in the stitching of 2 rows of points having arbitrary TessFactors.
1986 // The stitching order is governed by Ruler Function vertex split ordering (see external documentation).
1988 // The contents of the finalPointPositionTable are where vertex i [0..33] ends up on the half-edge
1989 // at the max tessellation amount given ruler-function split order.
1990 // Recall the other half of an edge is mirrored, so we only need to deal with one half.
1991 // This table is used to decide when to advance a point on the interior or exterior.
1992 // It supports odd TessFactor up to 65 and even TessFactor up to 64.
1993 static const int finalPointPositionTable
[33] =
1994 { 0, 32, 16, 8, 17, 4, 18, 9, 19, 2, 20, 10, 21, 5, 22, 11, 23,
1995 1, 24, 12, 25, 6, 26, 13, 27, 3, 28, 14, 29, 7, 30, 15, 31 };
1997 // The loopStart and loopEnd tables below just provide optimal loop bounds for the
1998 // stitching algorithm further below, for any given halfTssFactor.
1999 // There is probably a better way to encode this...
2001 // loopStart[halfTessFactor] encodes the FIRST 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 loopStart
[33] =
2004 {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};
2005 // loopStart[halfTessFactor] encodes the LAST entry in finalPointPositionTable[] above which is
2006 // less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
2007 static const int loopEnd
[33] =
2008 {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};
2010 if( TESSELLATOR_PARITY_ODD
== insideEdgeTessFactorParity
)
2012 insideNumHalfTessFactorPoints
-= 1;
2014 if( TESSELLATOR_PARITY_ODD
== outsideTessFactorParity
)
2016 outsideNumHalfTessFactorPoints
-= 1;
2019 int outsidePoint
= outsideEdgePointBaseOffset
;
2020 int insidePoint
= insideEdgePointBaseOffset
;
2022 // iStart,iEnd are a small optimization so the loop below doesn't have to go from 0 up to 31
2023 int iStart
= min(loopStart
[insideNumHalfTessFactorPoints
],loopStart
[outsideNumHalfTessFactorPoints
]);
2024 int iEnd
= max(loopEnd
[insideNumHalfTessFactorPoints
],loopEnd
[outsideNumHalfTessFactorPoints
]);
2026 if( finalPointPositionTable
[0] < outsideNumHalfTessFactorPoints
) // since we dont' start the loop at 0 below, we need a special case.
2029 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2030 baseIndexOffset
+= 3; outsidePoint
++;
2033 for(int i
= iStart
; i
<= iEnd
; i
++)
2035 if( /*(i>0) && <-- not needed since iStart is never 0*/(finalPointPositionTable
[i
] < insideNumHalfTessFactorPoints
))
2038 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2039 baseIndexOffset
+= 3; insidePoint
++;
2041 if((finalPointPositionTable
[i
] < outsideNumHalfTessFactorPoints
))
2044 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2045 baseIndexOffset
+= 3; outsidePoint
++;
2049 if( (insideEdgeTessFactorParity
!= outsideTessFactorParity
) || (insideEdgeTessFactorParity
== TESSELLATOR_PARITY_ODD
))
2051 if( insideEdgeTessFactorParity
== outsideTessFactorParity
)
2053 // Quad in the middle
2054 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2055 baseIndexOffset
+= 3;
2056 DefineClockwiseTriangle(insidePoint
+1,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
2057 baseIndexOffset
+= 3;
2061 else if( TESSELLATOR_PARITY_EVEN
== insideEdgeTessFactorParity
)
2063 // Triangle pointing inside
2064 DefineClockwiseTriangle(insidePoint
,outsidePoint
,outsidePoint
+1,baseIndexOffset
);
2065 baseIndexOffset
+= 3;
2070 // Triangle pointing outside
2071 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2072 baseIndexOffset
+= 3;
2077 // Walk second half.
2078 for(int i
= iEnd
; i
>= iStart
; i
--)
2080 if((finalPointPositionTable
[i
] < outsideNumHalfTessFactorPoints
))
2083 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2084 baseIndexOffset
+= 3; outsidePoint
++;
2086 if( /*(i>0) && <-- not needed since iStart is never 0*/ (finalPointPositionTable
[i
] < insideNumHalfTessFactorPoints
))
2089 DefineClockwiseTriangle(insidePoint
,outsidePoint
,insidePoint
+1,baseIndexOffset
);
2090 baseIndexOffset
+= 3; insidePoint
++;
2093 // Below case is not needed if we didn't optimize loop above and made it run from 31 down to 0.
2094 if((finalPointPositionTable
[0] < outsideNumHalfTessFactorPoints
))
2096 DefineClockwiseTriangle(outsidePoint
,outsidePoint
+1,insidePoint
,baseIndexOffset
);
2097 baseIndexOffset
+= 3; outsidePoint
++;
2101 //---------------------------------------------------------------------------------------------------------------------------------
2102 // CHWTessellator::PatchIndexValue()
2103 //--------------------------------------------------------------------------------------------------------------------------------
2104 int CHWTessellator::PatchIndexValue(int index
)
2106 if( m_bUsingPatchedIndices
)
2108 if( index
>= m_IndexPatchContext
.outsidePointIndexPatchBase
) // assumed remapped outide indices are > remapped inside vertices
2110 if( index
== m_IndexPatchContext
.outsidePointIndexBadValue
)
2111 index
= m_IndexPatchContext
.outsidePointIndexReplacementValue
;
2113 index
+= m_IndexPatchContext
.outsidePointIndexDeltaToRealValue
;
2117 if( index
== m_IndexPatchContext
.insidePointIndexBadValue
)
2118 index
= m_IndexPatchContext
.insidePointIndexReplacementValue
;
2120 index
+= m_IndexPatchContext
.insidePointIndexDeltaToRealValue
;
2123 else if( m_bUsingPatchedIndices2
)
2125 if( index
>= m_IndexPatchContext2
.baseIndexToInvert
)
2127 if( index
== m_IndexPatchContext2
.cornerCaseBadValue
)
2129 index
= m_IndexPatchContext2
.cornerCaseReplacementValue
;
2133 index
= m_IndexPatchContext2
.indexInversionEndPoint
- index
;
2136 else if( index
== m_IndexPatchContext2
.cornerCaseBadValue
)
2138 index
= m_IndexPatchContext2
.cornerCaseReplacementValue
;
2145 //=================================================================================================================================
2147 //=================================================================================================================================
2149 //---------------------------------------------------------------------------------------------------------------------------------
2150 // CHLSLTessellator::CHLSLTessellator
2151 //---------------------------------------------------------------------------------------------------------------------------------
2152 CHLSLTessellator::CHLSLTessellator()
2154 m_LastComputedTessFactors
[0] = m_LastComputedTessFactors
[1] = m_LastComputedTessFactors
[2] =
2155 m_LastComputedTessFactors
[3] = m_LastComputedTessFactors
[4] = m_LastComputedTessFactors
[5] = 0;
2158 //---------------------------------------------------------------------------------------------------------------------------------
2159 // CHLSLTessellator::Init
2161 //---------------------------------------------------------------------------------------------------------------------------------
2162 void CHLSLTessellator::Init(
2163 D3D11_TESSELLATOR_PARTITIONING partitioning
,
2164 D3D11_TESSELLATOR_REDUCTION insideTessFactorReduction
,
2165 D3D11_TESSELLATOR_QUAD_REDUCTION_AXIS quadInsideTessFactorReductionAxis
,
2166 D3D11_TESSELLATOR_OUTPUT_PRIMITIVE outputPrimitive
)
2168 CHWTessellator::Init(partitioning
,outputPrimitive
);
2169 m_LastComputedTessFactors
[0] = m_LastComputedTessFactors
[1] = m_LastComputedTessFactors
[2] =
2170 m_LastComputedTessFactors
[3] = m_LastComputedTessFactors
[4] = m_LastComputedTessFactors
[5] = 0;
2171 m_partitioning
= partitioning
;
2172 m_originalPartitioning
= partitioning
;
2173 switch( partitioning
)
2175 case D3D11_TESSELLATOR_PARTITIONING_INTEGER
:
2178 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD
:
2179 m_parity
= TESSELLATOR_PARITY_ODD
;
2181 case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN
:
2182 m_parity
= TESSELLATOR_PARITY_EVEN
;
2185 m_originalParity
= m_parity
;
2186 m_outputPrimitive
= outputPrimitive
;
2187 m_insideTessFactorReduction
= insideTessFactorReduction
;
2188 m_quadInsideTessFactorReductionAxis
= quadInsideTessFactorReductionAxis
;
2190 //---------------------------------------------------------------------------------------------------------------------------------
2191 // CHLSLTessellator::TessellateQuadDomain
2193 //---------------------------------------------------------------------------------------------------------------------------------
2194 void CHLSLTessellator::TessellateQuadDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
2195 float insideTessFactorScaleU
, float insideTessFactorScaleV
)
2197 QuadHLSLProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Ueq1
,tessFactor_Veq1
,insideTessFactorScaleU
,insideTessFactorScaleV
);
2199 CHWTessellator::TessellateQuadDomain(m_LastComputedTessFactors
[0],m_LastComputedTessFactors
[1],m_LastComputedTessFactors
[2],m_LastComputedTessFactors
[3],
2200 m_LastComputedTessFactors
[4],m_LastComputedTessFactors
[5]);
2203 //---------------------------------------------------------------------------------------------------------------------------------
2204 // CHLSLTessellator::QuadHLSLProcessTessFactors
2205 //---------------------------------------------------------------------------------------------------------------------------------
2206 void CHLSLTessellator::QuadHLSLProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Ueq1
, float tessFactor_Veq1
,
2207 float insideTessFactorScaleU
, float insideTessFactorScaleV
)
2209 if( !(tessFactor_Ueq0
> 0) ||// NaN will pass
2210 !(tessFactor_Veq0
> 0) ||
2211 !(tessFactor_Ueq1
> 0) ||
2212 !(tessFactor_Veq1
> 0) )
2214 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2215 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2216 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Ueq1
;
2217 m_LastUnRoundedComputedTessFactors
[3] = tessFactor_Veq1
;
2218 m_LastUnRoundedComputedTessFactors
[4] = 0;
2219 m_LastUnRoundedComputedTessFactors
[5] = 0;
2220 m_LastComputedTessFactors
[0] =
2221 m_LastComputedTessFactors
[1] =
2222 m_LastComputedTessFactors
[2] =
2223 m_LastComputedTessFactors
[3] =
2224 m_LastComputedTessFactors
[4] =
2225 m_LastComputedTessFactors
[5] = 0;
2229 CleanupFloatTessFactor(tessFactor_Ueq0
);// clamp to [1.0f..INF], NaN->1.0f
2230 CleanupFloatTessFactor(tessFactor_Veq0
);
2231 CleanupFloatTessFactor(tessFactor_Ueq1
);
2232 CleanupFloatTessFactor(tessFactor_Veq1
);
2234 // Save off tessFactors so they can be returned to app
2235 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2236 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2237 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Ueq1
;
2238 m_LastUnRoundedComputedTessFactors
[3] = tessFactor_Veq1
;
2240 // Process outside tessFactors
2241 float outsideTessFactor
[QUAD_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Ueq1
, tessFactor_Veq1
};
2243 TESSELLATOR_PARITY insideTessFactorParity
[QUAD_AXES
];
2244 if( Pow2Partitioning() || IntegerPartitioning() )
2246 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
2248 RoundUpTessFactor(outsideTessFactor
[edge
]);
2249 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2254 SetTessellationParity(m_originalParity
); // ClampTessFactor needs it
2255 for( edge
= 0; edge
< QUAD_EDGES
; edge
++ )
2257 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2261 // Compute inside TessFactors
2262 float insideTessFactor
[QUAD_AXES
];
2263 if( m_quadInsideTessFactorReductionAxis
== D3D11_TESSELLATOR_QUAD_REDUCTION_1_AXIS
)
2265 switch( m_insideTessFactorReduction
)
2267 case D3D11_TESSELLATOR_REDUCTION_MIN
:
2268 insideTessFactor
[U
] = tess_fmin(tess_fmin(tessFactor_Veq0
,tessFactor_Veq1
),tess_fmin(tessFactor_Ueq0
,tessFactor_Ueq1
));
2270 case D3D11_TESSELLATOR_REDUCTION_MAX
:
2271 insideTessFactor
[U
] = tess_fmax(tess_fmax(tessFactor_Veq0
,tessFactor_Veq1
),tess_fmax(tessFactor_Ueq0
,tessFactor_Ueq1
));
2273 case D3D11_TESSELLATOR_REDUCTION_AVERAGE
:
2274 insideTessFactor
[U
] = (tessFactor_Veq0
+ tessFactor_Veq1
+ tessFactor_Ueq0
+ tessFactor_Ueq1
) / 4;
2277 // Scale inside tessFactor based on user scale factor.
2279 ClampFloatTessFactorScale(insideTessFactorScaleU
); // clamp scale value to [0..1], NaN->0
2280 insideTessFactor
[U
] = insideTessFactor
[U
]*insideTessFactorScaleU
;
2282 // Compute inside parity
2283 if( Pow2Partitioning() || IntegerPartitioning() )
2285 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction + scale result that is based on unbounded user input
2286 m_LastUnRoundedComputedTessFactors
[4] = m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2287 RoundUpTessFactor(insideTessFactor
[U
]);
2288 insideTessFactorParity
[U
] =
2289 insideTessFactorParity
[V
] =
2290 (isEven(insideTessFactor
[U
]) || (FLOAT_ONE
== insideTessFactor
[U
]) )
2291 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2295 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction + scale result that is based on unbounded user input
2296 m_LastUnRoundedComputedTessFactors
[4] = m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2297 // no parity changes for fractional tessellation - just use what the user requested
2298 insideTessFactorParity
[U
] = insideTessFactorParity
[V
] = m_originalParity
;
2301 // To prevent snapping on edges, the "picture frame" comes
2302 // in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2303 if( (TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[U
]) &&
2304 (insideTessFactor
[U
] < FLOAT_THREE
) )
2306 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2308 insideTessFactor
[U
] = tess_fmin(FLOAT_THREE
,tess_fmax(tess_fmax(tessFactor_Veq0
,tessFactor_Veq1
),tess_fmax(tessFactor_Ueq0
,tessFactor_Ueq1
)));
2312 insideTessFactor
[U
] = tess_fmin(FLOAT_THREE
,(tessFactor_Veq0
+ tessFactor_Veq1
+ tessFactor_Ueq0
+ tessFactor_Ueq1
) / 4);
2314 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction result that is based on unbounded user input
2315 m_LastUnRoundedComputedTessFactors
[4] = m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2316 if( IntegerPartitioning())
2318 RoundUpTessFactor(insideTessFactor
[U
]);
2319 insideTessFactorParity
[U
] =
2320 insideTessFactorParity
[V
] = isEven(insideTessFactor
[U
]) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2323 insideTessFactor
[V
] = insideTessFactor
[U
];
2327 switch( m_insideTessFactorReduction
)
2329 case D3D11_TESSELLATOR_REDUCTION_MIN
:
2330 insideTessFactor
[U
] = tess_fmin(tessFactor_Veq0
,tessFactor_Veq1
);
2331 insideTessFactor
[V
] = tess_fmin(tessFactor_Ueq0
,tessFactor_Ueq1
);
2333 case D3D11_TESSELLATOR_REDUCTION_MAX
:
2334 insideTessFactor
[U
] = tess_fmax(tessFactor_Veq0
,tessFactor_Veq1
);
2335 insideTessFactor
[V
] = tess_fmax(tessFactor_Ueq0
,tessFactor_Ueq1
);
2337 case D3D11_TESSELLATOR_REDUCTION_AVERAGE
:
2338 insideTessFactor
[U
] = (tessFactor_Veq0
+ tessFactor_Veq1
) / 2;
2339 insideTessFactor
[V
] = (tessFactor_Ueq0
+ tessFactor_Ueq1
) / 2;
2342 // Scale inside tessFactors based on user scale factor.
2344 ClampFloatTessFactorScale(insideTessFactorScaleU
); // clamp scale value to [0..1], NaN->0
2345 ClampFloatTessFactorScale(insideTessFactorScaleV
);
2346 insideTessFactor
[U
] = insideTessFactor
[U
]*insideTessFactorScaleU
;
2347 insideTessFactor
[V
] = insideTessFactor
[V
]*insideTessFactorScaleV
;
2349 // Compute inside parity
2350 if( Pow2Partitioning() || IntegerPartitioning() )
2352 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
2354 ClampTessFactor(insideTessFactor
[axis
]); // clamp reduction + scale result that is based on unbounded user input
2355 m_LastUnRoundedComputedTessFactors
[4+axis
] = insideTessFactor
[axis
]; // Save off TessFactors so they can be returned to app
2356 RoundUpTessFactor(insideTessFactor
[axis
]);
2357 insideTessFactorParity
[axis
] =
2358 (isEven(insideTessFactor
[axis
]) || (FLOAT_ONE
== insideTessFactor
[axis
]) )
2359 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2364 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction + scale result that is based on unbounded user input
2365 ClampTessFactor(insideTessFactor
[V
]); // clamp reduction + scale result that is based on unbounded user input
2366 m_LastUnRoundedComputedTessFactors
[4] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2367 m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[V
]; // Save off TessFactors so they can be returned to app
2368 // no parity changes for fractional tessellation - just use what the user requested
2369 insideTessFactorParity
[U
] = insideTessFactorParity
[V
] = m_originalParity
;
2372 // To prevent snapping on edges, the "picture frame" comes
2373 // in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2374 if( (TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[U
]) &&
2375 (insideTessFactor
[U
] < FLOAT_THREE
) )
2377 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2379 insideTessFactor
[U
] = tess_fmin(FLOAT_THREE
,tess_fmax(tessFactor_Veq0
,tessFactor_Veq1
));
2383 insideTessFactor
[U
] = tess_fmin(FLOAT_THREE
,(tessFactor_Veq0
+ tessFactor_Veq1
) / 2);
2385 ClampTessFactor(insideTessFactor
[U
]); // clamp reduction result that is based on unbounded user input
2386 m_LastUnRoundedComputedTessFactors
[4] = insideTessFactor
[U
]; // Save off TessFactors so they can be returned to app
2387 if( IntegerPartitioning())
2389 RoundUpTessFactor(insideTessFactor
[U
]);
2390 insideTessFactorParity
[U
] = isEven(insideTessFactor
[U
]) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2394 if( (TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[V
]) &&
2395 (insideTessFactor
[V
] < FLOAT_THREE
) )
2397 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2399 insideTessFactor
[V
] = tess_fmin(FLOAT_THREE
,tess_fmax(tessFactor_Ueq0
,tessFactor_Ueq1
));
2403 insideTessFactor
[V
] = tess_fmin(FLOAT_THREE
,(tessFactor_Ueq0
+ tessFactor_Ueq1
) / 2);
2405 ClampTessFactor(insideTessFactor
[V
]);// clamp reduction result that is based on unbounded user input
2406 m_LastUnRoundedComputedTessFactors
[5] = insideTessFactor
[V
]; // Save off TessFactors so they can be returned to app
2407 if( IntegerPartitioning())
2409 RoundUpTessFactor(insideTessFactor
[V
]);
2410 insideTessFactorParity
[V
] = isEven(insideTessFactor
[V
]) ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2414 for( axis
= 0; axis
< QUAD_AXES
; axis
++ )
2416 if( TESSELLATOR_PARITY_ODD
== insideTessFactorParity
[axis
] )
2418 // Ensure the first ring ("picture frame") interpolates in on all sides
2419 // as much as the side with the minimum TessFactor. Prevents snapping to edge.
2420 if( (insideTessFactor
[axis
] < FLOAT_THREE
) && (insideTessFactor
[axis
] < insideTessFactor
[(axis
+1)&0x1]))
2422 insideTessFactor
[axis
] = tess_fmin(insideTessFactor
[(axis
+1)&0x1],FLOAT_THREE
);
2423 m_LastUnRoundedComputedTessFactors
[4+axis
] = insideTessFactor
[axis
]; // Save off TessFactors so they can be returned to app
2429 // Save off TessFactors so they can be returned to app
2430 m_LastComputedTessFactors
[0] = outsideTessFactor
[Ueq0
];
2431 m_LastComputedTessFactors
[1] = outsideTessFactor
[Veq0
];
2432 m_LastComputedTessFactors
[2] = outsideTessFactor
[Ueq1
];
2433 m_LastComputedTessFactors
[3] = outsideTessFactor
[Veq1
];
2434 m_LastComputedTessFactors
[4] = insideTessFactor
[U
];
2435 m_LastComputedTessFactors
[5] = insideTessFactor
[V
];
2438 //---------------------------------------------------------------------------------------------------------------------------------
2439 // CHLSLTessellator::TessellateTriDomain
2441 //---------------------------------------------------------------------------------------------------------------------------------
2442 void CHLSLTessellator::TessellateTriDomain( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
2443 float insideTessFactorScale
)
2445 TriHLSLProcessTessFactors(tessFactor_Ueq0
,tessFactor_Veq0
,tessFactor_Weq0
,insideTessFactorScale
);
2447 CHWTessellator::TessellateTriDomain(m_LastComputedTessFactors
[0],m_LastComputedTessFactors
[1],m_LastComputedTessFactors
[2],m_LastComputedTessFactors
[3]);
2450 //---------------------------------------------------------------------------------------------------------------------------------
2451 // CHLSLTessellator::TriHLSLProcessTessFactors
2452 //---------------------------------------------------------------------------------------------------------------------------------
2453 void CHLSLTessellator::TriHLSLProcessTessFactors( float tessFactor_Ueq0
, float tessFactor_Veq0
, float tessFactor_Weq0
,
2454 float insideTessFactorScale
)
2456 if( !(tessFactor_Ueq0
> 0) || // NaN will pass
2457 !(tessFactor_Veq0
> 0) ||
2458 !(tessFactor_Weq0
> 0) )
2460 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2461 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2462 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Weq0
;
2463 m_LastUnRoundedComputedTessFactors
[3] =
2464 m_LastComputedTessFactors
[0] =
2465 m_LastComputedTessFactors
[1] =
2466 m_LastComputedTessFactors
[2] =
2467 m_LastComputedTessFactors
[3] = 0;
2471 CleanupFloatTessFactor(tessFactor_Ueq0
); // clamp to [1.0f..INF], NaN->1.0f
2472 CleanupFloatTessFactor(tessFactor_Veq0
);
2473 CleanupFloatTessFactor(tessFactor_Weq0
);
2475 // Save off TessFactors so they can be returned to app
2476 m_LastUnRoundedComputedTessFactors
[0] = tessFactor_Ueq0
;
2477 m_LastUnRoundedComputedTessFactors
[1] = tessFactor_Veq0
;
2478 m_LastUnRoundedComputedTessFactors
[2] = tessFactor_Weq0
;
2480 // Process outside TessFactors
2481 float outsideTessFactor
[TRI_EDGES
] = {tessFactor_Ueq0
, tessFactor_Veq0
, tessFactor_Weq0
};
2483 if( Pow2Partitioning() || IntegerPartitioning() )
2485 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
2487 RoundUpTessFactor(outsideTessFactor
[edge
]); // for pow2 this rounds to pow2
2488 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2493 for( edge
= 0; edge
< TRI_EDGES
; edge
++ )
2495 ClampTessFactor(outsideTessFactor
[edge
]); // clamp unbounded user input based on tessellation mode
2499 // Compute inside TessFactor
2500 float insideTessFactor
;
2501 switch( m_insideTessFactorReduction
)
2503 case D3D11_TESSELLATOR_REDUCTION_MIN
:
2504 insideTessFactor
= tess_fmin(tess_fmin(tessFactor_Ueq0
,tessFactor_Veq0
),tessFactor_Weq0
);
2506 case D3D11_TESSELLATOR_REDUCTION_MAX
:
2507 insideTessFactor
= tess_fmax(tess_fmax(tessFactor_Ueq0
,tessFactor_Veq0
),tessFactor_Weq0
);
2509 case D3D11_TESSELLATOR_REDUCTION_AVERAGE
:
2510 insideTessFactor
= (tessFactor_Ueq0
+ tessFactor_Veq0
+ tessFactor_Weq0
) / 3;
2514 // Scale inside TessFactor based on user scale factor.
2515 ClampFloatTessFactorScale(insideTessFactorScale
); // clamp scale value to [0..1], NaN->0
2516 insideTessFactor
= insideTessFactor
*tess_fmin(FLOAT_ONE
,insideTessFactorScale
);
2518 ClampTessFactor(insideTessFactor
); // clamp reduction + scale result that is based on unbounded user input
2519 m_LastUnRoundedComputedTessFactors
[3] = insideTessFactor
;// Save off TessFactors so they can be returned to app
2520 TESSELLATOR_PARITY parity
;
2521 if( Pow2Partitioning() || IntegerPartitioning() )
2523 RoundUpTessFactor(insideTessFactor
);
2524 parity
= (isEven(insideTessFactor
) || (FLOAT_ONE
== insideTessFactor
))
2525 ? TESSELLATOR_PARITY_EVEN
: TESSELLATOR_PARITY_ODD
;
2529 parity
= m_originalParity
;
2532 if( (TESSELLATOR_PARITY_ODD
== parity
) &&
2533 (insideTessFactor
< FLOAT_THREE
))
2535 // To prevent snapping on edges, the "picture frame" comes
2536 // in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2537 if(D3D11_TESSELLATOR_REDUCTION_MAX
== m_insideTessFactorReduction
)
2539 insideTessFactor
= tess_fmin(FLOAT_THREE
,tess_fmax(tessFactor_Ueq0
,tess_fmax(tessFactor_Veq0
,tessFactor_Weq0
)));
2543 insideTessFactor
= tess_fmin(FLOAT_THREE
,(tessFactor_Ueq0
+ tessFactor_Veq0
+ tessFactor_Weq0
) / 3);
2545 ClampTessFactor(insideTessFactor
); // clamp reduction result that is based on unbounded user input
2546 m_LastUnRoundedComputedTessFactors
[3] = insideTessFactor
;// Save off TessFactors so they can be returned to app
2547 if( IntegerPartitioning())
2549 RoundUpTessFactor(insideTessFactor
);
2553 // Save off TessFactors so they can be returned to app
2554 m_LastComputedTessFactors
[0] = outsideTessFactor
[Ueq0
];
2555 m_LastComputedTessFactors
[1] = outsideTessFactor
[Veq0
];
2556 m_LastComputedTessFactors
[2] = outsideTessFactor
[Weq0
];
2557 m_LastComputedTessFactors
[3] = insideTessFactor
;
2560 //---------------------------------------------------------------------------------------------------------------------------------
2561 // CHLSLTessellator::TessellateIsoLineDomain
2563 //---------------------------------------------------------------------------------------------------------------------------------
2564 void CHLSLTessellator::TessellateIsoLineDomain( float TessFactor_U_LineDetail
, float TessFactor_V_LineDensity
)
2566 IsoLineHLSLProcessTessFactors(TessFactor_V_LineDensity
,TessFactor_U_LineDetail
);
2567 CHWTessellator::TessellateIsoLineDomain(m_LastComputedTessFactors
[0],m_LastComputedTessFactors
[1]);
2570 //---------------------------------------------------------------------------------------------------------------------------------
2571 // CHLSLTessellator::IsoLineHLSLProcessTessFactors
2572 //---------------------------------------------------------------------------------------------------------------------------------
2573 void CHLSLTessellator::IsoLineHLSLProcessTessFactors( float TessFactor_V_LineDensity
, float TessFactor_U_LineDetail
)
2575 if( !(TessFactor_V_LineDensity
> 0) || // NaN will pass
2576 !(TessFactor_U_LineDetail
> 0) )
2578 m_LastUnRoundedComputedTessFactors
[0] = TessFactor_V_LineDensity
;
2579 m_LastUnRoundedComputedTessFactors
[1] = TessFactor_U_LineDetail
;
2580 m_LastComputedTessFactors
[0] =
2581 m_LastComputedTessFactors
[1] = 0;
2585 CleanupFloatTessFactor(TessFactor_V_LineDensity
); // clamp to [1.0f..INF], NaN->1.0f
2586 CleanupFloatTessFactor(TessFactor_U_LineDetail
); // clamp to [1.0f..INF], NaN->1.0f
2588 ClampTessFactor(TessFactor_U_LineDetail
); // clamp unbounded user input based on tessellation mode
2590 m_LastUnRoundedComputedTessFactors
[1] = TessFactor_U_LineDetail
; // Save off TessFactors so they can be returned to app
2592 if(Pow2Partitioning()||IntegerPartitioning())
2594 RoundUpTessFactor(TessFactor_U_LineDetail
);
2597 OverridePartitioning(D3D11_TESSELLATOR_PARTITIONING_INTEGER
);
2599 ClampTessFactor(TessFactor_V_LineDensity
); // Clamp unbounded user input to integer
2600 m_LastUnRoundedComputedTessFactors
[0] = TessFactor_V_LineDensity
; // Save off TessFactors so they can be returned to app
2602 RoundUpTessFactor(TessFactor_V_LineDensity
);
2604 RestorePartitioning();
2606 // Save off TessFactors so they can be returned to app
2607 m_LastComputedTessFactors
[0] = TessFactor_V_LineDensity
;
2608 m_LastComputedTessFactors
[1] = TessFactor_U_LineDetail
;
2611 //---------------------------------------------------------------------------------------------------------------------------------
2612 // CHLSLTessellator::ClampTessFactor()
2613 //---------------------------------------------------------------------------------------------------------------------------------
2614 void CHLSLTessellator::ClampTessFactor(float& TessFactor
)
2616 if( Pow2Partitioning() )
2618 TessFactor
= tess_fmin( D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
, tess_fmax( TessFactor
, D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
) );
2620 else if( IntegerPartitioning() )
2622 TessFactor
= tess_fmin( D3D11_TESSELLATOR_MAX_TESSELLATION_FACTOR
, tess_fmax( TessFactor
, D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
) );
2626 TessFactor
= tess_fmin( D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR
, tess_fmax( TessFactor
, D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR
) );
2630 TessFactor
= tess_fmin( D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR
, tess_fmax( TessFactor
, D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR
) );
2634 //---------------------------------------------------------------------------------------------------------------------------------
2635 // CHLSLTessellator::CleanupFloatTessFactor()
2636 //---------------------------------------------------------------------------------------------------------------------------------
2637 static const int exponentMask
= 0x7f800000;
2638 static const int mantissaMask
= 0x007fffff;
2639 void CHLSLTessellator::CleanupFloatTessFactor(float& input
)
2641 // If input is < 1.0f or NaN, clamp to 1.0f.
2642 // In other words, clamp input to [1.0f...+INF]
2643 int bits
= *(int*)&input
;
2644 if( ( ( ( bits
& exponentMask
) == exponentMask
) && ( bits
& mantissaMask
) ) ||// nan?
2651 //---------------------------------------------------------------------------------------------------------------------------------
2652 // CHLSLTessellator::ClampFloatTessFactorScale()
2653 //---------------------------------------------------------------------------------------------------------------------------------
2654 void CHLSLTessellator::ClampFloatTessFactorScale(float& input
)
2656 // If input is < 0.0f or NaN, clamp to 0.0f. > 1 clamps to 1.
2657 // In other words, clamp input to [0.0f...1.0f]
2658 int bits
= *(int*)&input
;
2659 if( ( ( ( bits
& exponentMask
) == exponentMask
) && ( bits
& mantissaMask
) ) ||// nan?
2664 else if( input
> 1 )
2670 //---------------------------------------------------------------------------------------------------------------------------------
2671 // CHLSLTessellator::RoundUpTessFactor()
2672 //---------------------------------------------------------------------------------------------------------------------------------
2673 static const int exponentLSB
= 0x00800000;
2674 void CHLSLTessellator::RoundUpTessFactor(float& TessFactor
)
2676 // Assume TessFactor is in [1.0f..+INF]
2677 if( Pow2Partitioning() )
2679 int bits
= *(int*)&TessFactor
;
2680 if( bits
& mantissaMask
)
2682 *(int*)&TessFactor
= (bits
& exponentMask
) + exponentLSB
;
2685 else if( IntegerPartitioning() )
2687 TessFactor
= ceil(TessFactor
);