diff --git a/neo/CMakeLists.txt b/neo/CMakeLists.txt index b98055798..ce56939e8 100644 --- a/neo/CMakeLists.txt +++ b/neo/CMakeLists.txt @@ -380,6 +380,7 @@ if(D3_COMPILER_IS_GCC_OR_CLANG) endif() # TODO fix these warnings + add_compile_options(-Wno-unused-variable) add_compile_options(-Wno-sign-compare) add_compile_options(-Wno-switch) @@ -796,6 +797,8 @@ set(src_idlib idlib/math/Rotation.cpp idlib/math/Simd.cpp idlib/math/Simd_Generic.cpp + idlib/math/Simd_AVX.cpp + idlib/math/Simd_AVX2.cpp idlib/math/Simd_AltiVec.cpp idlib/math/Simd_MMX.cpp idlib/math/Simd_3DNow.cpp diff --git a/neo/idlib/math/Simd.cpp b/neo/idlib/math/Simd.cpp index 6cbdae17f..bbcb04bec 100644 --- a/neo/idlib/math/Simd.cpp +++ b/neo/idlib/math/Simd.cpp @@ -43,18 +43,19 @@ If you have questions concerning this license or the applicable additional terms #include "idlib/math/Simd_SSE.h" #include "idlib/math/Simd_SSE2.h" #include "idlib/math/Simd_SSE3.h" +#include "idlib/math/Simd_AVX.h" +#include "idlib/math/Simd_AVX2.h" #include "idlib/math/Simd_AltiVec.h" #include "idlib/math/Plane.h" #include "idlib/bv/Bounds.h" #include "idlib/Lib.h" #include "framework/Common.h" #include "renderer/Model.h" - #include "idlib/math/Simd.h" -idSIMDProcessor * processor = NULL; // pointer to SIMD processor -idSIMDProcessor * generic = NULL; // pointer to generic SIMD implementation -idSIMDProcessor * SIMDProcessor = NULL; +idSIMDProcessor *processor = NULL; // pointer to SIMD processor +idSIMDProcessor *generic = NULL; // pointer to generic SIMD implementation +idSIMDProcessor *SIMDProcessor = NULL; /* ================ @@ -71,39 +72,99 @@ void idSIMD::Init( void ) { /* ============ idSIMD::InitProcessor + +Darkmod has a cvar to force specific cpu optimizations +but it requires a lot more code so i just use this simpler version. ============ */ void idSIMD::InitProcessor( const char *module, bool forceGeneric ) { - int cpuid; - idSIMDProcessor *newProcessor; + int cpuid = idLib::sys->GetProcessorId(); + idSIMDProcessor *newProcessor = NULL; + +// stgatilov: force cpuid bits for SIMD choice if compiler macros are set +// this is used for Elbrus compiler, which can cross-compile SSE intrinsics but has no CPUID instruction +#ifdef __MMX__ + cpuid |= CPUID_MMX; +#endif +#ifdef __3dNOW__ + cpuid |= CPUID_3DNOW; +#endif +#ifdef __SSE__ + cpuid |= CPUID_SSE; +#endif +#ifdef __SSE2__ + cpuid |= CPUID_SSE2; +#endif +#ifdef __SSE3__ + cpuid |= CPUID_SSE3; +#endif +#ifdef __SSE4_1__ + cpuid |= CPUID_SSE41; +#endif +#ifdef __AVX__ + cpuid |= CPUID_AVX; +#endif +#ifdef __AVX2__ + cpuid |= CPUID_AVX2; + cpuid |= CPUID_FMA3; +#endif +#ifdef __ALTIVEC__ + cpuid |= CPUID_ALTIVEC; +#endif - cpuid = idLib::sys->GetProcessorId(); + // Print what we found to console + idLib::common->Printf( "Found %s CPU, With these features: %s %s %s %s %s %s %s %s %s %s\n", + // Vendor + cpuid & CPUID_AMD ? "AMD" : + cpuid & CPUID_INTEL ? "Intel" : + cpuid & CPUID_GENERIC ? "Generic" : + "Unsupported", + // Flags + cpuid & CPUID_MMX ? " MMX" : "", + cpuid & CPUID_3DNOW ? " 3DNow" : "", + cpuid & CPUID_SSE ? " SSE" : "", + cpuid & CPUID_SSE2 ? " SSE2" : "", + cpuid & CPUID_SSE3 ? " SSE3" : "", + cpuid & CPUID_SSE41 ? " SSE41" : "", + cpuid & CPUID_AVX ? " AVX" : "", + cpuid & CPUID_AVX2 ? " AVX2" : "", + cpuid & CPUID_FMA3 ? " FMA3" : "", + cpuid & CPUID_ALTIVEC ? " ALTIVEC" : "" ); if ( forceGeneric ) { - newProcessor = generic; - } else { - if ( !processor ) { - if ( ( cpuid & CPUID_ALTIVEC ) ) { + bool upToMMX = ( cpuid & CPUID_MMX ); + bool upTo3DNow = ( cpuid & CPUID_3DNOW ) && ( cpuid & CPUID_AMD ); // newer AMD processors no longer support this. + bool upToSSE = upToMMX && ( cpuid & CPUID_SSE ); + bool upToSSE2 = upToSSE && ( cpuid & CPUID_SSE2 ); + bool upToSSE3 = upToSSE2 && ( cpuid & CPUID_SSE3 ); + bool upToAVX = upToSSE3 && ( cpuid & CPUID_AVX ); + bool upToAVX2 = upToAVX && ( cpuid & CPUID_AVX2 ) && ( cpuid & CPUID_FMA3 ); // while not strictly nessesary with SDL2 or greater we still set the FMA3 flag + bool isAlTiVec = ( cpuid & CPUID_ALTIVEC ); // unused on anything but apple i think... + + if ( isAlTiVec ) { processor = new idSIMD_AltiVec; - } else if ( ( cpuid & CPUID_MMX ) && ( cpuid & CPUID_SSE ) && ( cpuid & CPUID_SSE2 ) && ( cpuid & CPUID_SSE3 ) ) { + } else if ( upToAVX2 ) { + processor = new idSIMD_AVX2; + } else if ( upToAVX ) { + processor = new idSIMD_AVX; + } else if ( upToSSE3 ) { processor = new idSIMD_SSE3; - } else if ( ( cpuid & CPUID_MMX ) && ( cpuid & CPUID_SSE ) && ( cpuid & CPUID_SSE2 ) ) { + } else if ( upToSSE2 ) { processor = new idSIMD_SSE2; - } else if ( ( cpuid & CPUID_MMX ) && ( cpuid & CPUID_SSE ) ) { + } else if ( upToSSE ) { processor = new idSIMD_SSE; - } else if ( ( cpuid & CPUID_MMX ) && ( cpuid & CPUID_3DNOW ) ) { + } else if ( upTo3DNow ) { processor = new idSIMD_3DNow; - } else if ( ( cpuid & CPUID_MMX ) ) { + } else if ( upToMMX ) { processor = new idSIMD_MMX; } else { processor = generic; } processor->cpuid = cpuid; } - newProcessor = processor; } @@ -111,11 +172,13 @@ void idSIMD::InitProcessor( const char *module, bool forceGeneric ) { SIMDProcessor = newProcessor; idLib::common->Printf( "%s using %s for SIMD processing\n", module, SIMDProcessor->GetName() ); } + bool enable = ( cpuid & CPUID_SSE ); - if ( cpuid & CPUID_SSE ) { - idLib::sys->FPU_SetFTZ( true ); - idLib::sys->FPU_SetDAZ( true ); - } + // enable Denormals-Are-Zero if we have the capability (SSE and up) + idLib::sys->FPU_SetDAZ( enable ); + + // enable Flush-To-Zero if we have the capability (SSE and up, allegedly altivec has the ability to but is dicouraged ?) + idLib::sys->FPU_SetFTZ( enable ); } /* @@ -140,9 +203,8 @@ void idSIMD::Shutdown( void ) { // //=============================================================== -#define COUNT 1024 // data count -#define NUMTESTS 2048 // number of tests - +#define COUNT 1024 // data count +#define NUMTESTS 2048 // number of tests #define RANDOM_SEED 1013904223L //((int)idLib::sys->GetClockTicks()) idSIMDProcessor *p_simd; @@ -204,7 +266,6 @@ double ticksPerNanosecond; best = end - start; \ } - /* ============ PrintClocks @@ -214,13 +275,15 @@ void PrintClocks( const char *string, int dataCount, int clocks, int otherClocks int i; idLib::common->Printf( "%s", string ); - for ( i = idStr::LengthWithoutColors(string); i < 48; i++ ) { - idLib::common->Printf(" "); + + for ( i = idStr::LengthWithoutColors( string ); i < 48; i++ ) { + idLib::common->Printf( " " ); } clocks -= baseClocks; + if ( otherClocks && clocks ) { otherClocks -= baseClocks; - int p = (int) ( (float) ( otherClocks - clocks ) * 100.0f / (float) otherClocks ); + int p = ( int )( ( float )( otherClocks - clocks ) * 100.0f / ( float ) otherClocks ); idLib::common->Printf( "c = %4d, clcks = %5d, %d%%\n", dataCount, clocks, p ); } else { idLib::common->Printf( "c = %4d, clcks = %5d\n", dataCount, clocks ); @@ -236,6 +299,7 @@ void GetBaseClocks( void ) { int i, start, end, bestClocks; bestClocks = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); StopRecordTime( end ); @@ -264,10 +328,11 @@ void TestAdd( void ) { fsrc0[i] = srnd.CRandomFloat() * 10.0f; fsrc1[i] = srnd.CRandomFloat() * 10.0f; } + idLib::common->Printf( "====================================\n" ); - idLib::common->Printf("====================================\n" ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Add( fdst0, 4.0f, fsrc1, COUNT ); @@ -276,7 +341,9 @@ void TestAdd( void ) { } PrintClocks( "generic->Add( float + float[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Add( fdst1, 4.0f, fsrc1, COUNT ); @@ -292,7 +359,9 @@ void TestAdd( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->Add( float + float[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Add( fdst0, fsrc0, fsrc1, COUNT ); @@ -301,7 +370,9 @@ void TestAdd( void ) { } PrintClocks( "generic->Add( float[] + float[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Add( fdst1, fsrc0, fsrc1, COUNT ); @@ -338,10 +409,11 @@ void TestSub( void ) { fsrc0[i] = srnd.CRandomFloat() * 10.0f; fsrc1[i] = srnd.CRandomFloat() * 10.0f; } + idLib::common->Printf( "====================================\n" ); - idLib::common->Printf("====================================\n" ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Sub( fdst0, 4.0f, fsrc1, COUNT ); @@ -350,7 +422,9 @@ void TestSub( void ) { } PrintClocks( "generic->Sub( float + float[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Sub( fdst1, 4.0f, fsrc1, COUNT ); @@ -366,7 +440,9 @@ void TestSub( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->Sub( float + float[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Sub( fdst0, fsrc0, fsrc1, COUNT ); @@ -375,7 +451,9 @@ void TestSub( void ) { } PrintClocks( "generic->Sub( float[] + float[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Sub( fdst1, fsrc0, fsrc1, COUNT ); @@ -412,10 +490,11 @@ void TestMul( void ) { fsrc0[i] = srnd.CRandomFloat() * 10.0f; fsrc1[i] = srnd.CRandomFloat() * 10.0f; } + idLib::common->Printf( "====================================\n" ); - idLib::common->Printf("====================================\n" ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Mul( fdst0, 4.0f, fsrc1, COUNT ); @@ -424,7 +503,9 @@ void TestMul( void ) { } PrintClocks( "generic->Mul( float * float[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Mul( fdst1, 4.0f, fsrc1, COUNT ); @@ -440,8 +521,9 @@ void TestMul( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->Mul( float * float[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Mul( fdst0, fsrc0, fsrc1, COUNT ); @@ -450,7 +532,9 @@ void TestMul( void ) { } PrintClocks( "generic->Mul( float[] * float[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Mul( fdst1, fsrc0, fsrc1, COUNT ); @@ -487,13 +571,13 @@ void TestDiv( void ) { fsrc0[i] = srnd.CRandomFloat() * 10.0f; do { fsrc1[i] = srnd.CRandomFloat() * 10.0f; - } while( idMath::Fabs( fsrc1[i] ) < 0.1f ); + } while ( idMath::Fabs( fsrc1[i] ) < 0.1f ); } + idLib::common->Printf( "====================================\n" ); - idLib::common->Printf("====================================\n" ); - - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Div( fdst0, 4.0f, fsrc1, COUNT ); @@ -502,7 +586,9 @@ void TestDiv( void ) { } PrintClocks( "generic->Div( float * float[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Div( fdst1, 4.0f, fsrc1, COUNT ); @@ -518,8 +604,9 @@ void TestDiv( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->Div( float * float[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Div( fdst0, fsrc0, fsrc1, COUNT ); @@ -528,7 +615,9 @@ void TestDiv( void ) { } PrintClocks( "generic->Div( float[] * float[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Div( fdst1, fsrc0, fsrc1, COUNT ); @@ -563,12 +652,11 @@ void TestMulAdd( void ) { for ( i = 0; i < COUNT; i++ ) { fsrc0[i] = srnd.CRandomFloat() * 10.0f; } - - idLib::common->Printf("====================================\n" ); + idLib::common->Printf( "====================================\n" ); for ( j = 0; j < 50 && j < COUNT; j++ ) { - bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { for ( int k = 0; k < COUNT; k++ ) { fdst0[k] = k; @@ -580,7 +668,9 @@ void TestMulAdd( void ) { } PrintClocks( va( "generic->MulAdd( float * float[%2d] )", j ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { for ( int k = 0; k < COUNT; k++ ) { fdst1[k] = k; @@ -619,12 +709,11 @@ void TestMulSub( void ) { for ( i = 0; i < COUNT; i++ ) { fsrc0[i] = srnd.CRandomFloat() * 10.0f; } - - idLib::common->Printf("====================================\n" ); + idLib::common->Printf( "====================================\n" ); for ( j = 0; j < 50 && j < COUNT; j++ ) { - bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { for ( int k = 0; k < COUNT; k++ ) { fdst0[k] = k; @@ -636,7 +725,9 @@ void TestMulSub( void ) { } PrintClocks( va( "generic->MulSub( float * float[%2d] )", j ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { for ( int k = 0; k < COUNT; k++ ) { fdst1[k] = k; @@ -671,9 +762,9 @@ void TestDot( void ) { ALIGN16( float fsrc1[COUNT] ); ALIGN16( idVec3 v3src0[COUNT] ); ALIGN16( idVec3 v3src1[COUNT] ); - ALIGN16( idVec3 v3constant ) ( 1.0f, 2.0f, 3.0f ); + ALIGN16( idVec3 v3constant )( 1.0f, 2.0f, 3.0f ); ALIGN16( idPlane v4src0[COUNT] ); - ALIGN16( idPlane v4constant ) (1.0f, 2.0f, 3.0f, 4.0f); + ALIGN16( idPlane v4constant )( 1.0f, 2.0f, 3.0f, 4.0f ); ALIGN16( idDrawVert drawVerts[COUNT] ); const char *result; @@ -692,11 +783,11 @@ void TestDot( void ) { v4src0[i][3] = srnd.CRandomFloat() * 10.0f; drawVerts[i].xyz = v3src0[i]; } + idLib::common->Printf( "====================================\n" ); - idLib::common->Printf("====================================\n" ); - - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Dot( fdst0, v3constant, v3src0, COUNT ); @@ -705,7 +796,9 @@ void TestDot( void ) { } PrintClocks( "generic->Dot( idVec3 * idVec3[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Dot( fdst1, v3constant, v3src0, COUNT ); @@ -721,8 +814,9 @@ void TestDot( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->Dot( idVec3 * idVec3[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Dot( fdst0, v3constant, v4src0, COUNT ); @@ -731,7 +825,9 @@ void TestDot( void ) { } PrintClocks( "generic->Dot( idVec3 * idPlane[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Dot( fdst1, v3constant, v4src0, COUNT ); @@ -747,8 +843,9 @@ void TestDot( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->Dot( idVec3 * idPlane[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Dot( fdst0, v3constant, drawVerts, COUNT ); @@ -757,7 +854,9 @@ void TestDot( void ) { } PrintClocks( "generic->Dot( idVec3 * idDrawVert[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Dot( fdst1, v3constant, drawVerts, COUNT ); @@ -773,8 +872,9 @@ void TestDot( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->Dot( idVec3 * idDrawVert[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Dot( fdst0, v4constant, v3src0, COUNT ); @@ -783,7 +883,9 @@ void TestDot( void ) { } PrintClocks( "generic->Dot( idPlane * idVec3[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Dot( fdst1, v4constant, v3src0, COUNT ); @@ -799,8 +901,9 @@ void TestDot( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->Dot( idPlane * idVec3[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Dot( fdst0, v4constant, v4src0, COUNT ); @@ -809,7 +912,9 @@ void TestDot( void ) { } PrintClocks( "generic->Dot( idPlane * idPlane[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Dot( fdst1, v4constant, v4src0, COUNT ); @@ -825,8 +930,9 @@ void TestDot( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->Dot( idPlane * idPlane[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Dot( fdst0, v4constant, drawVerts, COUNT ); @@ -835,7 +941,9 @@ void TestDot( void ) { } PrintClocks( "generic->Dot( idPlane * idDrawVert[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Dot( fdst1, v4constant, drawVerts, COUNT ); @@ -851,8 +959,9 @@ void TestDot( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->Dot( idPlane * idDrawVert[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Dot( fdst0, v3src0, v3src1, COUNT ); @@ -861,7 +970,9 @@ void TestDot( void ) { } PrintClocks( "generic->Dot( idVec3[] * idVec3[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Dot( fdst1, v3src0, v3src1, COUNT ); @@ -877,13 +988,12 @@ void TestDot( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->Dot( idVec3[] * idVec3[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); - - idLib::common->Printf("====================================\n" ); + idLib::common->Printf( "====================================\n" ); float dot1 = 0.0f, dot2 = 0.0f; for ( j = 0; j < 50 && j < COUNT; j++ ) { - bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Dot( dot1, fsrc0, fsrc1, j ); @@ -892,7 +1002,9 @@ void TestDot( void ) { } PrintClocks( va( "generic->Dot( float[%2d] * float[%2d] )", j, j ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Dot( dot2, fsrc0, fsrc1, j ); @@ -922,10 +1034,11 @@ void TestCompare( void ) { for ( i = 0; i < COUNT; i++ ) { fsrc0[i] = srnd.CRandomFloat() * 10.0f; } + idLib::common->Printf( "====================================\n" ); - idLib::common->Printf("====================================\n" ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->CmpGT( bytedst, fsrc0, 0.0f, COUNT ); @@ -934,7 +1047,9 @@ void TestCompare( void ) { } PrintClocks( "generic->CmpGT( float[] >= float )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->CmpGT( bytedst2, fsrc0, 0.0f, COUNT ); @@ -950,7 +1065,9 @@ void TestCompare( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->CmpGT( float[] >= float ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { memset( bytedst, 0, COUNT ); StartRecordTime( start ); @@ -960,7 +1077,9 @@ void TestCompare( void ) { } PrintClocks( "generic->CmpGT( 2, float[] >= float )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { memset( bytedst2, 0, COUNT ); StartRecordTime( start ); @@ -978,8 +1097,8 @@ void TestCompare( void ) { PrintClocks( va( " simd->CmpGT( 2, float[] >= float ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); // ====================== - bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->CmpGE( bytedst, fsrc0, 0.0f, COUNT ); @@ -988,7 +1107,9 @@ void TestCompare( void ) { } PrintClocks( "generic->CmpGE( float[] >= float )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->CmpGE( bytedst2, fsrc0, 0.0f, COUNT ); @@ -1004,7 +1125,9 @@ void TestCompare( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->CmpGE( float[] >= float ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { memset( bytedst, 0, COUNT ); StartRecordTime( start ); @@ -1014,7 +1137,9 @@ void TestCompare( void ) { } PrintClocks( "generic->CmpGE( 2, float[] >= float )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { memset( bytedst2, 0, COUNT ); StartRecordTime( start ); @@ -1032,8 +1157,8 @@ void TestCompare( void ) { PrintClocks( va( " simd->CmpGE( 2, float[] >= float ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); // ====================== - bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->CmpLT( bytedst, fsrc0, 0.0f, COUNT ); @@ -1042,7 +1167,9 @@ void TestCompare( void ) { } PrintClocks( "generic->CmpLT( float[] >= float )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->CmpLT( bytedst2, fsrc0, 0.0f, COUNT ); @@ -1058,7 +1185,9 @@ void TestCompare( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->CmpLT( float[] >= float ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { memset( bytedst, 0, COUNT ); StartRecordTime( start ); @@ -1068,7 +1197,9 @@ void TestCompare( void ) { } PrintClocks( "generic->CmpLT( 2, float[] >= float )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { memset( bytedst2, 0, COUNT ); StartRecordTime( start ); @@ -1086,8 +1217,8 @@ void TestCompare( void ) { PrintClocks( va( " simd->CmpLT( 2, float[] >= float ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); // ====================== - bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->CmpLE( bytedst, fsrc0, 0.0f, COUNT ); @@ -1096,7 +1227,9 @@ void TestCompare( void ) { } PrintClocks( "generic->CmpLE( float[] >= float )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->CmpLE( bytedst2, fsrc0, 0.0f, COUNT ); @@ -1112,7 +1245,9 @@ void TestCompare( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->CmpLE( float[] >= float ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { memset( bytedst, 0, COUNT ); StartRecordTime( start ); @@ -1122,7 +1257,9 @@ void TestCompare( void ) { } PrintClocks( "generic->CmpLE( 2, float[] >= float )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { memset( bytedst2, 0, COUNT ); StartRecordTime( start ); @@ -1170,10 +1307,11 @@ void TestMinMax( void ) { drawVerts[i].xyz = v3src0[i]; indexes[i] = i; } + idLib::common->Printf( "====================================\n" ); - idLib::common->Printf("====================================\n" ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { min = idMath::INFINITY; max = -idMath::INFINITY; @@ -1184,18 +1322,21 @@ void TestMinMax( void ) { } PrintClocks( "generic->MinMax( float[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->MinMax( min2, max2, fsrc0, COUNT ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = ( min == min2 && max == max2 ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MinMax( float[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->MinMax( v2min, v2max, v2src0, COUNT ); @@ -1204,18 +1345,21 @@ void TestMinMax( void ) { } PrintClocks( "generic->MinMax( idVec2[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->MinMax( v2min2, v2max2, v2src0, COUNT ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = ( v2min == v2min2 && v2max == v2max2 ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MinMax( idVec2[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->MinMax( vmin, vmax, v3src0, COUNT ); @@ -1224,18 +1368,21 @@ void TestMinMax( void ) { } PrintClocks( "generic->MinMax( idVec3[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->MinMax( vmin2, vmax2, v3src0, COUNT ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = ( vmin == vmin2 && vmax == vmax2 ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MinMax( idVec3[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->MinMax( vmin, vmax, drawVerts, COUNT ); @@ -1244,18 +1391,21 @@ void TestMinMax( void ) { } PrintClocks( "generic->MinMax( idDrawVert[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->MinMax( vmin2, vmax2, drawVerts, COUNT ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = ( vmin == vmin2 && vmax == vmax2 ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MinMax( idDrawVert[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->MinMax( vmin, vmax, drawVerts, indexes, COUNT ); @@ -1264,14 +1414,15 @@ void TestMinMax( void ) { } PrintClocks( "generic->MinMax( idDrawVert[], indexes[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->MinMax( vmin2, vmax2, drawVerts, indexes, COUNT ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = ( vmin == vmin2 && vmax == vmax2 ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MinMax( idDrawVert[], indexes[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); } @@ -1294,10 +1445,11 @@ void TestClamp( void ) { for ( i = 0; i < COUNT; i++ ) { fsrc0[i] = srnd.CRandomFloat() * 10.0f; } + idLib::common->Printf( "====================================\n" ); - idLib::common->Printf("====================================\n" ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->Clamp( fdst0, fsrc0, -1.0f, 1.0f, COUNT ); @@ -1306,7 +1458,9 @@ void TestClamp( void ) { } PrintClocks( "generic->Clamp( float[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->Clamp( fdst1, fsrc0, -1.0f, 1.0f, COUNT ); @@ -1322,8 +1476,9 @@ void TestClamp( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->Clamp( float[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->ClampMin( fdst0, fsrc0, -1.0f, COUNT ); @@ -1332,7 +1487,9 @@ void TestClamp( void ) { } PrintClocks( "generic->ClampMin( float[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->ClampMin( fdst1, fsrc0, -1.0f, COUNT ); @@ -1348,8 +1505,9 @@ void TestClamp( void ) { result = ( i >= COUNT ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->ClampMin( float[] ) %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->ClampMax( fdst0, fsrc0, 1.0f, COUNT ); @@ -1358,7 +1516,9 @@ void TestClamp( void ) { } PrintClocks( "generic->ClampMax( float[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->ClampMax( fdst1, fsrc0, 1.0f, COUNT ); @@ -1387,13 +1547,14 @@ void TestMemcpy( void ) { idRandom random( RANDOM_SEED ); - idLib::common->Printf("====================================\n" ); + idLib::common->Printf( "====================================\n" ); for ( i = 5; i < 8192; i += 31 ) { for ( j = 0; j < i; j++ ) { test0[j] = random.RandomInt( 255 ); } p_simd->Memcpy( test1, test0, 8192 ); + for ( j = 0; j < i; j++ ) { if ( test1[j] != test0[j] ) { idLib::common->Printf( " simd->Memcpy() " S_COLOR_RED "X\n" ); @@ -1420,8 +1581,9 @@ void TestMemset( void ) { for ( i = 5; i < 8192; i += 31 ) { for ( j = -1; j <= 1; j++ ) { p_simd->Memset( test, j, i ); + for ( k = 0; k < i; k++ ) { - if ( test[k] != (byte)j ) { + if ( test[k] != ( byte )j ) { idLib::common->Printf( " simd->Memset() " S_COLOR_RED "X\n" ); return; } @@ -1443,9 +1605,9 @@ void TestMatXMultiplyVecX( void ) { TIME_TYPE start, end, bestClocksGeneric, bestClocksSIMD; const char *result; idMatX mat; - idVecX src(6); - idVecX dst(6); - idVecX tst(6); + idVecX src( 6 ); + idVecX dst( 6 ); + idVecX tst( 6 ); src[0] = 1.0f; src[1] = 2.0f; @@ -1454,12 +1616,14 @@ void TestMatXMultiplyVecX( void ) { src[4] = 5.0f; src[5] = 6.0f; - idLib::common->Printf("================= NxN * Nx1 ===================\n" ); + idLib::common->Printf( "================= NxN * Nx1 ===================\n" ); for ( i = 1; i <= 6; i++ ) { mat.Random( i, i, RANDOM_SEED, -10.0f, 10.0f ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1468,10 +1632,11 @@ void TestMatXMultiplyVecX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_MultiplyVecX %dx%d*%dx1", i, i, i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1479,17 +1644,17 @@ void TestMatXMultiplyVecX( void ) { StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_MultiplyVecX %dx%d*%dx1 %s", i, i, i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } - - idLib::common->Printf("================= Nx6 * 6x1 ===================\n" ); + idLib::common->Printf( "================= Nx6 * 6x1 ===================\n" ); for ( i = 1; i <= 6; i++ ) { mat.Random( i, 6, RANDOM_SEED, -10.0f, 10.0f ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1498,10 +1663,11 @@ void TestMatXMultiplyVecX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_MultiplyVecX %dx6*6x1", i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1509,17 +1675,17 @@ void TestMatXMultiplyVecX( void ) { StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_MultiplyVecX %dx6*6x1 %s", i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } - - idLib::common->Printf("================= 6xN * Nx1 ===================\n" ); + idLib::common->Printf( "================= 6xN * Nx1 ===================\n" ); for ( i = 1; i <= 6; i++ ) { mat.Random( 6, i, RANDOM_SEED, -10.0f, 10.0f ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1528,17 +1694,17 @@ void TestMatXMultiplyVecX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_MultiplyVecX 6x%d*%dx1", i, i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_simd->MatX_MultiplyVecX( dst, mat, src ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_MultiplyVecX 6x%d*%dx1 %s", i, i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } @@ -1554,9 +1720,9 @@ void TestMatXMultiplyAddVecX( void ) { TIME_TYPE start, end, bestClocksGeneric, bestClocksSIMD; const char *result; idMatX mat; - idVecX src(6); - idVecX dst(6); - idVecX tst(6); + idVecX src( 6 ); + idVecX dst( 6 ); + idVecX tst( 6 ); src[0] = 1.0f; src[1] = 2.0f; @@ -1565,12 +1731,14 @@ void TestMatXMultiplyAddVecX( void ) { src[4] = 5.0f; src[5] = 6.0f; - idLib::common->Printf("================= NxN * Nx1 ===================\n" ); + idLib::common->Printf( "================= NxN * Nx1 ===================\n" ); for ( i = 1; i <= 6; i++ ) { mat.Random( i, i, RANDOM_SEED, -10.0f, 10.0f ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1579,10 +1747,11 @@ void TestMatXMultiplyAddVecX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_MultiplyAddVecX %dx%d*%dx1", i, i, i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1590,17 +1759,17 @@ void TestMatXMultiplyAddVecX( void ) { StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_MultiplyAddVecX %dx%d*%dx1 %s", i, i, i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } - - idLib::common->Printf("================= Nx6 * 6x1 ===================\n" ); + idLib::common->Printf( "================= Nx6 * 6x1 ===================\n" ); for ( i = 1; i <= 6; i++ ) { mat.Random( i, 6, RANDOM_SEED, -10.0f, 10.0f ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1609,10 +1778,11 @@ void TestMatXMultiplyAddVecX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_MultiplyAddVecX %dx6*6x1", i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1620,17 +1790,17 @@ void TestMatXMultiplyAddVecX( void ) { StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_MultiplyAddVecX %dx6*6x1 %s", i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } - - idLib::common->Printf("================= 6xN * Nx1 ===================\n" ); + idLib::common->Printf( "================= 6xN * Nx1 ===================\n" ); for ( i = 1; i <= 6; i++ ) { mat.Random( 6, i, RANDOM_SEED, -10.0f, 10.0f ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1639,10 +1809,11 @@ void TestMatXMultiplyAddVecX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_MultiplyAddVecX 6x%d*%dx1", i, i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1650,7 +1821,6 @@ void TestMatXMultiplyAddVecX( void ) { StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_MultiplyAddVecX 6x%d*%dx1 %s", i, i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } @@ -1666,9 +1836,9 @@ void TestMatXTransposeMultiplyVecX( void ) { TIME_TYPE start, end, bestClocksGeneric, bestClocksSIMD; const char *result; idMatX mat; - idVecX src(6); - idVecX dst(6); - idVecX tst(6); + idVecX src( 6 ); + idVecX dst( 6 ); + idVecX tst( 6 ); src[0] = 1.0f; src[1] = 2.0f; @@ -1677,12 +1847,14 @@ void TestMatXTransposeMultiplyVecX( void ) { src[4] = 5.0f; src[5] = 6.0f; - idLib::common->Printf("================= Nx6 * Nx1 ===================\n" ); + idLib::common->Printf( "================= Nx6 * Nx1 ===================\n" ); for ( i = 1; i <= 6; i++ ) { mat.Random( i, 6, RANDOM_SEED, -10.0f, 10.0f ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1691,10 +1863,11 @@ void TestMatXTransposeMultiplyVecX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_TransposeMulVecX %dx6*%dx1", i, i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1702,17 +1875,17 @@ void TestMatXTransposeMultiplyVecX( void ) { StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_TransposeMulVecX %dx6*%dx1 %s", i, i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } - - idLib::common->Printf("================= 6xN * 6x1 ===================\n" ); + idLib::common->Printf( "================= 6xN * 6x1 ===================\n" ); for ( i = 1; i <= 6; i++ ) { mat.Random( 6, i, RANDOM_SEED, -10.0f, 10.0f ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1721,10 +1894,11 @@ void TestMatXTransposeMultiplyVecX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_TransposeMulVecX 6x%d*6x1", i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1732,7 +1906,6 @@ void TestMatXTransposeMultiplyVecX( void ) { StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_TransposeMulVecX 6x%d*6x1 %s", i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } @@ -1748,9 +1921,9 @@ void TestMatXTransposeMultiplyAddVecX( void ) { TIME_TYPE start, end, bestClocksGeneric, bestClocksSIMD; const char *result; idMatX mat; - idVecX src(6); - idVecX dst(6); - idVecX tst(6); + idVecX src( 6 ); + idVecX dst( 6 ); + idVecX tst( 6 ); src[0] = 1.0f; src[1] = 2.0f; @@ -1759,12 +1932,14 @@ void TestMatXTransposeMultiplyAddVecX( void ) { src[4] = 5.0f; src[5] = 6.0f; - idLib::common->Printf("================= Nx6 * Nx1 ===================\n" ); + idLib::common->Printf( "================= Nx6 * Nx1 ===================\n" ); for ( i = 1; i <= 6; i++ ) { mat.Random( i, 6, RANDOM_SEED, -10.0f, 10.0f ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1773,10 +1948,11 @@ void TestMatXTransposeMultiplyAddVecX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_TransposeMulAddVecX %dx6*%dx1", i, i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1784,17 +1960,17 @@ void TestMatXTransposeMultiplyAddVecX( void ) { StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_TransposeMulAddVecX %dx6*%dx1 %s", i, i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } - - idLib::common->Printf("================= 6xN * 6x1 ===================\n" ); + idLib::common->Printf( "================= 6xN * 6x1 ===================\n" ); for ( i = 1; i <= 6; i++ ) { mat.Random( 6, i, RANDOM_SEED, -10.0f, 10.0f ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1803,10 +1979,11 @@ void TestMatXTransposeMultiplyAddVecX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_TransposeMulAddVecX 6x%d*6x1", i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { dst.Zero(); StartRecordTime( start ); @@ -1814,7 +1991,6 @@ void TestMatXTransposeMultiplyAddVecX( void ) { StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_TransposeMulAddVecX 6x%d*6x1 %s", i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } @@ -1834,7 +2010,7 @@ void TestMatXMultiplyMatX( void ) { const char *result; idMatX m1, m2, dst, tst; - idLib::common->Printf("================= NxN * Nx6 ===================\n" ); + idLib::common->Printf( "================= NxN * Nx6 ===================\n" ); // NxN * Nx6 for ( i = 1; i <= 5; i++ ) { @@ -1842,7 +2018,9 @@ void TestMatXMultiplyMatX( void ) { m2.Random( i, 6, RANDOM_SEED, -TEST_VALUE_RANGE, TEST_VALUE_RANGE ); dst.SetSize( i, 6 ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_generic->MatX_MultiplyMatX( dst, m1, m2 ); @@ -1850,22 +2028,21 @@ void TestMatXMultiplyMatX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_MultiplyMatX %dx%d*%dx6", i, i, i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_simd->MatX_MultiplyMatX( dst, m1, m2 ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_MultiplyMatX %dx%d*%dx6 %s", i, i, i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } - - idLib::common->Printf("================= 6xN * Nx6 ===================\n" ); + idLib::common->Printf( "================= 6xN * Nx6 ===================\n" ); // 6xN * Nx6 for ( i = 1; i <= 5; i++ ) { @@ -1873,7 +2050,9 @@ void TestMatXMultiplyMatX( void ) { m2.Random( i, 6, RANDOM_SEED, -TEST_VALUE_RANGE, TEST_VALUE_RANGE ); dst.SetSize( 6, 6 ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_generic->MatX_MultiplyMatX( dst, m1, m2 ); @@ -1881,22 +2060,21 @@ void TestMatXMultiplyMatX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_MultiplyMatX 6x%d*%dx6", i, i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_simd->MatX_MultiplyMatX( dst, m1, m2 ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_MultiplyMatX 6x%d*%dx6 %s", i, i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } - - idLib::common->Printf("================= Nx6 * 6xN ===================\n" ); + idLib::common->Printf( "================= Nx6 * 6xN ===================\n" ); // Nx6 * 6xN for ( i = 1; i <= 5; i++ ) { @@ -1904,7 +2082,9 @@ void TestMatXMultiplyMatX( void ) { m2.Random( 6, i, RANDOM_SEED, -TEST_VALUE_RANGE, TEST_VALUE_RANGE ); dst.SetSize( i, i ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_generic->MatX_MultiplyMatX( dst, m1, m2 ); @@ -1912,22 +2092,21 @@ void TestMatXMultiplyMatX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_MultiplyMatX %dx6*6x%d", i, i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_simd->MatX_MultiplyMatX( dst, m1, m2 ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_MultiplyMatX %dx6*6x%d %s", i, i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } - - idLib::common->Printf("================= 6x6 * 6xN ===================\n" ); + idLib::common->Printf( "================= 6x6 * 6xN ===================\n" ); // 6x6 * 6xN for ( i = 1; i <= 6; i++ ) { @@ -1935,7 +2114,9 @@ void TestMatXMultiplyMatX( void ) { m2.Random( 6, i, RANDOM_SEED, -TEST_VALUE_RANGE, TEST_VALUE_RANGE ); dst.SetSize( 6, i ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_generic->MatX_MultiplyMatX( dst, m1, m2 ); @@ -1943,17 +2124,17 @@ void TestMatXMultiplyMatX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_MultiplyMatX 6x6*6x%d", i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_simd->MatX_MultiplyMatX( dst, m1, m2 ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_MultiplyMatX 6x6*6x%d %s", i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } @@ -1970,7 +2151,7 @@ void TestMatXTransposeMultiplyMatX( void ) { const char *result; idMatX m1, m2, dst, tst; - idLib::common->Printf("================= Nx6 * NxN ===================\n" ); + idLib::common->Printf( "================= Nx6 * NxN ===================\n" ); // Nx6 * NxN for ( i = 1; i <= 5; i++ ) { @@ -1978,7 +2159,9 @@ void TestMatXTransposeMultiplyMatX( void ) { m2.Random( i, i, RANDOM_SEED, -TEST_VALUE_RANGE, TEST_VALUE_RANGE ); dst.SetSize( 6, i ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_generic->MatX_TransposeMultiplyMatX( dst, m1, m2 ); @@ -1986,22 +2169,21 @@ void TestMatXTransposeMultiplyMatX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_TransMultiplyMatX %dx6*%dx%d", i, i, i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_simd->MatX_TransposeMultiplyMatX( dst, m1, m2 ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_TransMultiplyMatX %dx6*%dx%d %s", i, i, i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } - - idLib::common->Printf("================= 6xN * 6x6 ===================\n" ); + idLib::common->Printf( "================= 6xN * 6x6 ===================\n" ); // 6xN * 6x6 for ( i = 1; i <= 6; i++ ) { @@ -2009,7 +2191,9 @@ void TestMatXTransposeMultiplyMatX( void ) { m2.Random( 6, 6, RANDOM_SEED, -TEST_VALUE_RANGE, TEST_VALUE_RANGE ); dst.SetSize( i, 6 ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_generic->MatX_TransposeMultiplyMatX( dst, m1, m2 ); @@ -2017,17 +2201,17 @@ void TestMatXTransposeMultiplyMatX( void ) { GetBest( start, end, bestClocksGeneric ); } tst = dst; - PrintClocks( va( "generic->MatX_TransMultiplyMatX 6x%d*6x6", i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_simd->MatX_TransposeMultiplyMatX( dst, m1, m2 ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = dst.Compare( tst, MATX_MATX_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_TransMultiplyMatX 6x%d*6x6 %s", i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } @@ -2048,17 +2232,18 @@ void TestMatXLowerTriangularSolve( void ) { idMatX L; idVecX x, b, tst; - idLib::common->Printf("====================================\n" ); + idLib::common->Printf( "====================================\n" ); L.Random( MATX_LTS_SOLVE_SIZE, MATX_LTS_SOLVE_SIZE, 0, -1.0f, 1.0f ); x.SetSize( MATX_LTS_SOLVE_SIZE ); b.Random( MATX_LTS_SOLVE_SIZE, 0, -1.0f, 1.0f ); for ( i = 1; i < MATX_LTS_SOLVE_SIZE; i++ ) { - x.Zero( i ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_generic->MatX_LowerTriangularSolve( L, x.ToFloatPtr(), b.ToFloatPtr(), i ); @@ -2070,14 +2255,15 @@ void TestMatXLowerTriangularSolve( void ) { PrintClocks( va( "generic->MatX_LowerTriangularSolve %dx%d", i, i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_simd->MatX_LowerTriangularSolve( L, x.ToFloatPtr(), b.ToFloatPtr(), i ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = x.Compare( tst, MATX_LTS_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_LowerTriangularSolve %dx%d %s", i, i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } @@ -2095,17 +2281,18 @@ void TestMatXLowerTriangularSolveTranspose( void ) { idMatX L; idVecX x, b, tst; - idLib::common->Printf("====================================\n" ); + idLib::common->Printf( "====================================\n" ); L.Random( MATX_LTS_SOLVE_SIZE, MATX_LTS_SOLVE_SIZE, 0, -1.0f, 1.0f ); x.SetSize( MATX_LTS_SOLVE_SIZE ); b.Random( MATX_LTS_SOLVE_SIZE, 0, -1.0f, 1.0f ); for ( i = 1; i < MATX_LTS_SOLVE_SIZE; i++ ) { - x.Zero( i ); + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_generic->MatX_LowerTriangularSolveTranspose( L, x.ToFloatPtr(), b.ToFloatPtr(), i ); @@ -2117,14 +2304,15 @@ void TestMatXLowerTriangularSolveTranspose( void ) { PrintClocks( va( "generic->MatX_LowerTriangularSolveT %dx%d", i, i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { StartRecordTime( start ); p_simd->MatX_LowerTriangularSolveTranspose( L, x.ToFloatPtr(), b.ToFloatPtr(), i ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = x.Compare( tst, MATX_LTS_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_LowerTriangularSolveT %dx%d %s", i, i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } @@ -2145,15 +2333,16 @@ void TestMatXLDLTFactor( void ) { idMatX src, original, mat1, mat2; idVecX invDiag1, invDiag2; - idLib::common->Printf("====================================\n" ); + idLib::common->Printf( "====================================\n" ); original.SetSize( MATX_LDLT_FACTOR_SOLVE_SIZE, MATX_LDLT_FACTOR_SOLVE_SIZE ); src.Random( MATX_LDLT_FACTOR_SOLVE_SIZE, MATX_LDLT_FACTOR_SOLVE_SIZE, 0, -1.0f, 1.0f ); src.TransposeMultiply( original, src ); for ( i = 1; i < MATX_LDLT_FACTOR_SOLVE_SIZE; i++ ) { - + // ====================== bestClocksGeneric = 0; + for ( j = 0; j < NUMTESTS; j++ ) { mat1 = original; invDiag1.Zero( MATX_LDLT_FACTOR_SOLVE_SIZE ); @@ -2162,10 +2351,11 @@ void TestMatXLDLTFactor( void ) { StopRecordTime( end ); GetBest( start, end, bestClocksGeneric ); } - PrintClocks( va( "generic->MatX_LDLTFactor %dx%d", i, i ), 1, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( j = 0; j < NUMTESTS; j++ ) { mat2 = original; invDiag2.Zero( MATX_LDLT_FACTOR_SOLVE_SIZE ); @@ -2174,7 +2364,6 @@ void TestMatXLDLTFactor( void ) { StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - result = mat1.Compare( mat2, MATX_LDLT_SIMD_EPSILON ) && invDiag1.Compare( invDiag2, MATX_LDLT_SIMD_EPSILON ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MatX_LDLTFactor %dx%d %s", i, i, result ), 1, bestClocksSIMD, bestClocksGeneric ); } @@ -2217,7 +2406,9 @@ void TestBlendJoints( void ) { index[i] = i; } + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { for ( j = 0; j < COUNT; j++ ) { joints1[j] = baseJoints[j]; @@ -2229,7 +2420,9 @@ void TestBlendJoints( void ) { } PrintClocks( "generic->BlendJoints()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { for ( j = 0; j < COUNT; j++ ) { joints2[j] = baseJoints[j]; @@ -2244,6 +2437,7 @@ void TestBlendJoints( void ) { if ( !joints1[i].t.Compare( joints2[i].t, 1e-3f ) ) { break; } + if ( !joints1[i].q.Compare( joints2[i].q, 1e-2f ) ) { break; } @@ -2278,7 +2472,9 @@ void TestConvertJointQuatsToJointMats( void ) { baseJoints[i].t[2] = srnd.CRandomFloat() * 10.0f; } + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->ConvertJointQuatsToJointMats( joints1, baseJoints, COUNT ); @@ -2287,7 +2483,9 @@ void TestConvertJointQuatsToJointMats( void ) { } PrintClocks( "generic->ConvertJointQuatsToJointMats()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->ConvertJointQuatsToJointMats( joints2, baseJoints, COUNT ); @@ -2332,7 +2530,9 @@ void TestConvertJointMatsToJointQuats( void ) { baseJoints[i].SetTranslation( v ); } + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->ConvertJointMatsToJointQuats( joints1, baseJoints, COUNT ); @@ -2341,7 +2541,9 @@ void TestConvertJointMatsToJointQuats( void ) { } PrintClocks( "generic->ConvertJointMatsToJointQuats()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->ConvertJointMatsToJointQuats( joints2, baseJoints, COUNT ); @@ -2351,11 +2553,12 @@ void TestConvertJointMatsToJointQuats( void ) { for ( i = 0; i < COUNT; i++ ) { if ( !joints1[i].q.Compare( joints2[i].q, 1e-4f ) ) { - idLib::common->Printf("ConvertJointMatsToJointQuats: broken q %i\n", i ); + idLib::common->Printf( "ConvertJointMatsToJointQuats: broken q %i\n", i ); break; } + if ( !joints1[i].t.Compare( joints2[i].t, 1e-4f ) ) { - idLib::common->Printf("ConvertJointMatsToJointQuats: broken t %i\n", i ); + idLib::common->Printf( "ConvertJointMatsToJointQuats: broken t %i\n", i ); break; } } @@ -2371,10 +2574,10 @@ TestTransformJoints void TestTransformJoints( void ) { int i, j; TIME_TYPE start, end, bestClocksGeneric, bestClocksSIMD; - ALIGN16( idJointMat joints[COUNT+1] ); - ALIGN16( idJointMat joints1[COUNT+1] ); - ALIGN16( idJointMat joints2[COUNT+1] ); - ALIGN16( int parents[COUNT+1] ); + ALIGN16( idJointMat joints[COUNT + 1] ); + ALIGN16( idJointMat joints1[COUNT + 1] ); + ALIGN16( idJointMat joints2[COUNT + 1] ); + ALIGN16( int parents[COUNT + 1] ); const char *result; idRandom srnd( RANDOM_SEED ); @@ -2393,7 +2596,9 @@ void TestTransformJoints( void ) { parents[i] = i - 1; } + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { for ( j = 0; j <= COUNT; j++ ) { joints1[j] = joints[j]; @@ -2405,7 +2610,9 @@ void TestTransformJoints( void ) { } PrintClocks( "generic->TransformJoints()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { for ( j = 0; j <= COUNT; j++ ) { joints2[j] = joints[j]; @@ -2417,7 +2624,7 @@ void TestTransformJoints( void ) { } for ( i = 0; i < COUNT; i++ ) { - if ( !joints1[i+1].Compare( joints2[i+1], 1e-4f ) ) { + if ( !joints1[i + 1].Compare( joints2[i + 1], 1e-4f ) ) { break; } } @@ -2433,10 +2640,10 @@ TestUntransformJoints void TestUntransformJoints( void ) { int i, j; TIME_TYPE start, end, bestClocksGeneric, bestClocksSIMD; - ALIGN16( idJointMat joints[COUNT+1] ); - ALIGN16( idJointMat joints1[COUNT+1] ); - ALIGN16( idJointMat joints2[COUNT+1] ); - ALIGN16( int parents[COUNT+1] ); + ALIGN16( idJointMat joints[COUNT + 1] ); + ALIGN16( idJointMat joints1[COUNT + 1] ); + ALIGN16( idJointMat joints2[COUNT + 1] ); + ALIGN16( int parents[COUNT + 1] ); const char *result; idRandom srnd( RANDOM_SEED ); @@ -2455,7 +2662,9 @@ void TestUntransformJoints( void ) { parents[i] = i - 1; } + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { for ( j = 0; j <= COUNT; j++ ) { joints1[j] = joints[j]; @@ -2467,7 +2676,9 @@ void TestUntransformJoints( void ) { } PrintClocks( "generic->UntransformJoints()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { for ( j = 0; j <= COUNT; j++ ) { joints2[j] = joints[j]; @@ -2479,7 +2690,7 @@ void TestUntransformJoints( void ) { } for ( i = 0; i < COUNT; i++ ) { - if ( !joints1[i+1].Compare( joints2[i+1], 1e-4f ) ) { + if ( !joints1[i + 1].Compare( joints2[i + 1], 1e-4f ) ) { break; } } @@ -2501,7 +2712,7 @@ void TestTransformVerts( void ) { ALIGN16( idDrawVert drawVerts2[NUMVERTS] ); ALIGN16( idJointMat joints[NUMJOINTS] ); ALIGN16( idVec4 weights[COUNT] ); - ALIGN16( int weightIndex[COUNT*2] ); + ALIGN16( int weightIndex[COUNT * 2] ); const char *result; idRandom srnd( RANDOM_SEED ); @@ -2524,11 +2735,13 @@ void TestTransformVerts( void ) { weights[i][1] = srnd.CRandomFloat() * 2.0f; weights[i][2] = srnd.CRandomFloat() * 2.0f; weights[i][3] = srnd.CRandomFloat(); - weightIndex[i*2+0] = ( i * NUMJOINTS / COUNT ) * sizeof( idJointMat ); - weightIndex[i*2+1] = i & 1; + weightIndex[i * 2 + 0] = ( i * NUMJOINTS / COUNT ) * sizeof( idJointMat ); + weightIndex[i * 2 + 1] = i & 1; } + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->TransformVerts( drawVerts1, NUMVERTS, joints, weights, weightIndex, COUNT ); @@ -2537,7 +2750,9 @@ void TestTransformVerts( void ) { } PrintClocks( "generic->TransformVerts()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->TransformVerts( drawVerts2, NUMVERTS, joints, weights, weightIndex, COUNT ); @@ -2571,10 +2786,10 @@ void TestTracePointCull( void ) { idRandom srnd( RANDOM_SEED ); - planes[0].SetNormal( idVec3( 1, 0, 0 ) ); + planes[0].SetNormal( idVec3( 1, 0, 0 ) ); planes[1].SetNormal( idVec3( -1, 0, 0 ) ); - planes[2].SetNormal( idVec3( 0, 1, 0 ) ); - planes[3].SetNormal( idVec3( 0, -1, 0 ) ); + planes[2].SetNormal( idVec3( 0, 1, 0 ) ); + planes[3].SetNormal( idVec3( 0, -1, 0 ) ); planes[0][3] = -5.3f; planes[1][3] = 5.3f; planes[2][3] = -3.4f; @@ -2586,7 +2801,9 @@ void TestTracePointCull( void ) { } } + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->TracePointCull( cullBits1, totalOr1, 0.0f, planes, drawVerts, COUNT ); @@ -2595,7 +2812,9 @@ void TestTracePointCull( void ) { } PrintClocks( "generic->TracePointCull()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->TracePointCull( cullBits2, totalOr2, 0.0f, planes, drawVerts, COUNT ); @@ -2628,12 +2847,12 @@ void TestDecalPointCull( void ) { idRandom srnd( RANDOM_SEED ); - planes[0].SetNormal( idVec3( 1, 0, 0 ) ); + planes[0].SetNormal( idVec3( 1, 0, 0 ) ); planes[1].SetNormal( idVec3( -1, 0, 0 ) ); - planes[2].SetNormal( idVec3( 0, 1, 0 ) ); - planes[3].SetNormal( idVec3( 0, -1, 0 ) ); - planes[4].SetNormal( idVec3( 0, 0, 1 ) ); - planes[5].SetNormal( idVec3( 0, 0, -1 ) ); + planes[2].SetNormal( idVec3( 0, 1, 0 ) ); + planes[3].SetNormal( idVec3( 0, -1, 0 ) ); + planes[4].SetNormal( idVec3( 0, 0, 1 ) ); + planes[5].SetNormal( idVec3( 0, 0, -1 ) ); planes[0][3] = -5.3f; planes[1][3] = 5.3f; planes[2][3] = -4.4f; @@ -2647,7 +2866,9 @@ void TestDecalPointCull( void ) { } } + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->DecalPointCull( cullBits1, planes, drawVerts, COUNT ); @@ -2656,7 +2877,9 @@ void TestDecalPointCull( void ) { } PrintClocks( "generic->DecalPointCull()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->DecalPointCull( cullBits2, planes, drawVerts, COUNT ); @@ -2702,7 +2925,9 @@ void TestOverlayPointCull( void ) { } } + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->OverlayPointCull( cullBits1, texCoords1, planes, drawVerts, COUNT ); @@ -2711,7 +2936,9 @@ void TestOverlayPointCull( void ) { } PrintClocks( "generic->OverlayPointCull()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->OverlayPointCull( cullBits2, texCoords2, planes, drawVerts, COUNT ); @@ -2723,6 +2950,7 @@ void TestOverlayPointCull( void ) { if ( cullBits1[i] != cullBits2[i] ) { break; } + if ( !texCoords1[i].Compare( texCoords2[i], 1e-4f ) ) { break; } @@ -2743,7 +2971,7 @@ void TestDeriveTriPlanes( void ) { ALIGN16( idDrawVert drawVerts2[COUNT] ); ALIGN16( idPlane planes1[COUNT] ); ALIGN16( idPlane planes2[COUNT] ); - ALIGN16( int indexes[COUNT*3] ); + ALIGN16( int indexes[COUNT * 3] ); const char *result; idRandom srnd( RANDOM_SEED ); @@ -2752,6 +2980,7 @@ void TestDeriveTriPlanes( void ) { for ( j = 0; j < 3; j++ ) { drawVerts1[i].xyz[j] = srnd.CRandomFloat() * 10.0f; } + for ( j = 0; j < 2; j++ ) { drawVerts1[i].st[j] = srnd.CRandomFloat(); } @@ -2759,24 +2988,28 @@ void TestDeriveTriPlanes( void ) { } for ( i = 0; i < COUNT; i++ ) { - indexes[i*3+0] = ( i + 0 ) % COUNT; - indexes[i*3+1] = ( i + 1 ) % COUNT; - indexes[i*3+2] = ( i + 2 ) % COUNT; + indexes[i * 3 + 0] = ( i + 0 ) % COUNT; + indexes[i * 3 + 1] = ( i + 1 ) % COUNT; + indexes[i * 3 + 2] = ( i + 2 ) % COUNT; } + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); - p_generic->DeriveTriPlanes( planes1, drawVerts1, COUNT, indexes, COUNT*3 ); + p_generic->DeriveTriPlanes( planes1, drawVerts1, COUNT, indexes, COUNT * 3 ); StopRecordTime( end ); GetBest( start, end, bestClocksGeneric ); } PrintClocks( "generic->DeriveTriPlanes()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); - p_simd->DeriveTriPlanes( planes2, drawVerts2, COUNT, indexes, COUNT*3 ); + p_simd->DeriveTriPlanes( planes2, drawVerts2, COUNT, indexes, COUNT * 3 ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } @@ -2802,7 +3035,7 @@ void TestDeriveTangents( void ) { ALIGN16( idDrawVert drawVerts2[COUNT] ); ALIGN16( idPlane planes1[COUNT] ); ALIGN16( idPlane planes2[COUNT] ); - ALIGN16( int indexes[COUNT*3] ); + ALIGN16( int indexes[COUNT * 3] ); const char *result; idRandom srnd( RANDOM_SEED ); @@ -2811,6 +3044,7 @@ void TestDeriveTangents( void ) { for ( j = 0; j < 3; j++ ) { drawVerts1[i].xyz[j] = srnd.CRandomFloat() * 10.0f; } + for ( j = 0; j < 2; j++ ) { drawVerts1[i].st[j] = srnd.CRandomFloat(); } @@ -2818,24 +3052,28 @@ void TestDeriveTangents( void ) { } for ( i = 0; i < COUNT; i++ ) { - indexes[i*3+0] = ( i + 0 ) % COUNT; - indexes[i*3+1] = ( i + 1 ) % COUNT; - indexes[i*3+2] = ( i + 2 ) % COUNT; + indexes[i * 3 + 0] = ( i + 0 ) % COUNT; + indexes[i * 3 + 1] = ( i + 1 ) % COUNT; + indexes[i * 3 + 2] = ( i + 2 ) % COUNT; } + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); - p_generic->DeriveTangents( planes1, drawVerts1, COUNT, indexes, COUNT*3 ); + p_generic->DeriveTangents( planes1, drawVerts1, COUNT, indexes, COUNT * 3 ); StopRecordTime( end ); GetBest( start, end, bestClocksGeneric ); } PrintClocks( "generic->DeriveTangents()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); - p_simd->DeriveTangents( planes2, drawVerts2, COUNT, indexes, COUNT*3 ); + p_simd->DeriveTangents( planes2, drawVerts2, COUNT, indexes, COUNT * 3 ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } @@ -2847,26 +3085,30 @@ void TestDeriveTangents( void ) { v1.Normalize(); v2 = drawVerts2[i].normal; v2.Normalize(); + if ( !v1.Compare( v2, 1e-1f ) ) { - idLib::common->Printf("DeriveTangents: broken at normal %i\n -- expecting %s got %s", i, v1.ToString(), v2.ToString()); + idLib::common->Printf( "DeriveTangents: broken at normal %i\n -- expecting %s got %s", i, v1.ToString(), v2.ToString() ); break; } v1 = drawVerts1[i].tangents[0]; v1.Normalize(); v2 = drawVerts2[i].tangents[0]; v2.Normalize(); + if ( !v1.Compare( v2, 1e-1f ) ) { - idLib::common->Printf("DeriveTangents: broken at tangent0 %i -- expecting %s got %s\n", i, v1.ToString(), v2.ToString() ); + idLib::common->Printf( "DeriveTangents: broken at tangent0 %i -- expecting %s got %s\n", i, v1.ToString(), v2.ToString() ); break; } v1 = drawVerts1[i].tangents[1]; v1.Normalize(); v2 = drawVerts2[i].tangents[1]; v2.Normalize(); + if ( !v1.Compare( v2, 1e-1f ) ) { - idLib::common->Printf("DeriveTangents: broken at tangent1 %i -- expecting %s got %s\n", i, v1.ToString(), v2.ToString() ); + idLib::common->Printf( "DeriveTangents: broken at tangent1 %i -- expecting %s got %s\n", i, v1.ToString(), v2.ToString() ); break; } + if ( !planes1[i].Compare( planes2[i], 1e-1f, 1e-1f ) ) { break; } @@ -2894,6 +3136,7 @@ void TestDeriveUnsmoothedTangents( void ) { for ( j = 0; j < 3; j++ ) { drawVerts1[i].xyz[j] = srnd.CRandomFloat() * 10.0f; } + for ( j = 0; j < 2; j++ ) { drawVerts1[i].st[j] = srnd.CRandomFloat(); } @@ -2906,7 +3149,9 @@ void TestDeriveUnsmoothedTangents( void ) { dominantTris[i].normalizationScale[2] = srnd.CRandomFloat(); } + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->DeriveUnsmoothedTangents( drawVerts1, dominantTris, COUNT ); @@ -2915,7 +3160,9 @@ void TestDeriveUnsmoothedTangents( void ) { } PrintClocks( "generic->DeriveUnsmoothedTangents()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->DeriveUnsmoothedTangents( drawVerts2, dominantTris, COUNT ); @@ -2930,6 +3177,7 @@ void TestDeriveUnsmoothedTangents( void ) { v1.Normalize(); v2 = drawVerts2[i].normal; v2.Normalize(); + if ( !v1.Compare( v2, 1e-1f ) ) { break; } @@ -2937,6 +3185,7 @@ void TestDeriveUnsmoothedTangents( void ) { v1.Normalize(); v2 = drawVerts2[i].tangents[0]; v2.Normalize(); + if ( !v1.Compare( v2, 1e-1f ) ) { break; } @@ -2944,6 +3193,7 @@ void TestDeriveUnsmoothedTangents( void ) { v1.Normalize(); v2 = drawVerts2[i].tangents[1]; v2.Normalize(); + if ( !v1.Compare( v2, 1e-1f ) ) { break; } @@ -2975,7 +3225,9 @@ void TestNormalizeTangents( void ) { drawVerts2[i] = drawVerts1[i]; } + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->NormalizeTangents( drawVerts1, COUNT ); @@ -2984,7 +3236,9 @@ void TestNormalizeTangents( void ) { } PrintClocks( "generic->NormalizeTangents()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->NormalizeTangents( drawVerts2, COUNT ); @@ -2996,9 +3250,11 @@ void TestNormalizeTangents( void ) { if ( !drawVerts1[i].normal.Compare( drawVerts2[i].normal, 1e-2f ) ) { break; } + if ( !drawVerts1[i].tangents[0].Compare( drawVerts2[i].tangents[0], 1e-2f ) ) { break; } + if ( !drawVerts1[i].tangents[1].Compare( drawVerts2[i].tangents[1], 1e-2f ) ) { break; } @@ -3022,7 +3278,7 @@ void TestGetTextureSpaceLightVectors( void ) { int i, j; TIME_TYPE start, end, bestClocksGeneric, bestClocksSIMD; ALIGN16( idDrawVert drawVerts[COUNT] ); - ALIGN16( int indexes[COUNT*3] ); + ALIGN16( int indexes[COUNT * 3] ); ALIGN16( idVec3 lightVectors1[COUNT] ); ALIGN16( idVec3 lightVectors2[COUNT] ); idVec3 lightOrigin; @@ -3040,28 +3296,31 @@ void TestGetTextureSpaceLightVectors( void ) { } for ( i = 0; i < COUNT; i++ ) { - indexes[i*3+0] = ( i + 0 ) % COUNT; - indexes[i*3+1] = ( i + 1 ) % COUNT; - indexes[i*3+2] = ( i + 2 ) % COUNT; + indexes[i * 3 + 0] = ( i + 0 ) % COUNT; + indexes[i * 3 + 1] = ( i + 1 ) % COUNT; + indexes[i * 3 + 2] = ( i + 2 ) % COUNT; } - lightOrigin[0] = srnd.CRandomFloat() * 100.0f; lightOrigin[1] = srnd.CRandomFloat() * 100.0f; lightOrigin[2] = srnd.CRandomFloat() * 100.0f; + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); - p_generic->CreateTextureSpaceLightVectors( lightVectors1, lightOrigin, drawVerts, COUNT, indexes, COUNT*3 ); + p_generic->CreateTextureSpaceLightVectors( lightVectors1, lightOrigin, drawVerts, COUNT, indexes, COUNT * 3 ); StopRecordTime( end ); GetBest( start, end, bestClocksGeneric ); } PrintClocks( "generic->CreateTextureSpaceLightVectors()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); - p_simd->CreateTextureSpaceLightVectors( lightVectors2, lightOrigin, drawVerts, COUNT, indexes, COUNT*3 ); + p_simd->CreateTextureSpaceLightVectors( lightVectors2, lightOrigin, drawVerts, COUNT, indexes, COUNT * 3 ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } @@ -3086,7 +3345,7 @@ void TestGetSpecularTextureCoords( void ) { ALIGN16( idDrawVert drawVerts[COUNT] ); ALIGN16( idVec4 texCoords1[COUNT] ); ALIGN16( idVec4 texCoords2[COUNT] ); - ALIGN16( int indexes[COUNT*3] ); + ALIGN16( int indexes[COUNT * 3] ); idVec3 lightOrigin, viewOrigin; const char *result; @@ -3102,11 +3361,10 @@ void TestGetSpecularTextureCoords( void ) { } for ( i = 0; i < COUNT; i++ ) { - indexes[i*3+0] = ( i + 0 ) % COUNT; - indexes[i*3+1] = ( i + 1 ) % COUNT; - indexes[i*3+2] = ( i + 2 ) % COUNT; + indexes[i * 3 + 0] = ( i + 0 ) % COUNT; + indexes[i * 3 + 1] = ( i + 1 ) % COUNT; + indexes[i * 3 + 2] = ( i + 2 ) % COUNT; } - lightOrigin[0] = srnd.CRandomFloat() * 100.0f; lightOrigin[1] = srnd.CRandomFloat() * 100.0f; lightOrigin[2] = srnd.CRandomFloat() * 100.0f; @@ -3114,19 +3372,23 @@ void TestGetSpecularTextureCoords( void ) { viewOrigin[1] = srnd.CRandomFloat() * 100.0f; viewOrigin[2] = srnd.CRandomFloat() * 100.0f; + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); - p_generic->CreateSpecularTextureCoords( texCoords1, lightOrigin, viewOrigin, drawVerts, COUNT, indexes, COUNT*3 ); + p_generic->CreateSpecularTextureCoords( texCoords1, lightOrigin, viewOrigin, drawVerts, COUNT, indexes, COUNT * 3 ); StopRecordTime( end ); GetBest( start, end, bestClocksGeneric ); } PrintClocks( "generic->CreateSpecularTextureCoords()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); - p_simd->CreateSpecularTextureCoords( texCoords2, lightOrigin, viewOrigin, drawVerts, COUNT, indexes, COUNT*3 ); + p_simd->CreateSpecularTextureCoords( texCoords2, lightOrigin, viewOrigin, drawVerts, COUNT, indexes, COUNT * 3 ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } @@ -3149,8 +3411,8 @@ void TestCreateShadowCache( void ) { int i, j; TIME_TYPE start, end, bestClocksGeneric, bestClocksSIMD; ALIGN16( idDrawVert drawVerts[COUNT] ); - ALIGN16( idVec4 vertexCache1[COUNT*2] ); - ALIGN16( idVec4 vertexCache2[COUNT*2] ); + ALIGN16( idVec4 vertexCache1[COUNT * 2] ); + ALIGN16( idVec4 vertexCache2[COUNT * 2] ); ALIGN16( int originalVertRemap[COUNT] ); ALIGN16( int vertRemap1[COUNT] ); ALIGN16( int vertRemap2[COUNT] ); @@ -3170,19 +3432,23 @@ void TestCreateShadowCache( void ) { lightOrigin[1] = srnd.CRandomFloat() * 100.0f; lightOrigin[2] = srnd.CRandomFloat() * 100.0f; + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { for ( j = 0; j < COUNT; j++ ) { vertRemap1[j] = originalVertRemap[j]; } StartRecordTime( start ); - numVerts1 =p_generic->CreateShadowCache( vertexCache1, vertRemap1, lightOrigin, drawVerts, COUNT ); + numVerts1 = p_generic->CreateShadowCache( vertexCache1, vertRemap1, lightOrigin, drawVerts, COUNT ); StopRecordTime( end ); GetBest( start, end, bestClocksGeneric ); } PrintClocks( "generic->CreateShadowCache()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { for ( j = 0; j < COUNT; j++ ) { vertRemap2[j] = originalVertRemap[j]; @@ -3195,22 +3461,25 @@ void TestCreateShadowCache( void ) { for ( i = 0; i < COUNT; i++ ) { if ( i < ( numVerts1 / 2 ) ) { - if ( !vertexCache1[i*2+0].Compare( vertexCache2[i*2+0], 1e-2f ) ) { + if ( !vertexCache1[i * 2 + 0].Compare( vertexCache2[i * 2 + 0], 1e-2f ) ) { break; } - if ( !vertexCache1[i*2+1].Compare( vertexCache2[i*2+1], 1e-2f ) ) { + + if ( !vertexCache1[i * 2 + 1].Compare( vertexCache2[i * 2 + 1], 1e-2f ) ) { break; } } + if ( vertRemap1[i] != vertRemap2[i] ) { break; } } - result = ( i >= COUNT && numVerts1 == numVerts2 ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->CreateShadowCache() %s", result ), COUNT, bestClocksSIMD, bestClocksGeneric ); + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_generic->CreateVertexProgramShadowCache( vertexCache1, drawVerts, COUNT ); @@ -3219,7 +3488,9 @@ void TestCreateShadowCache( void ) { } PrintClocks( "generic->CreateVertexProgramShadowCache()", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); p_simd->CreateVertexProgramShadowCache( vertexCache2, drawVerts, COUNT ); @@ -3228,10 +3499,11 @@ void TestCreateShadowCache( void ) { } for ( i = 0; i < COUNT; i++ ) { - if ( !vertexCache1[i*2+0].Compare( vertexCache2[i*2+0], 1e-2f ) ) { + if ( !vertexCache1[i * 2 + 0].Compare( vertexCache2[i * 2 + 0], 1e-2f ) ) { break; } - if ( !vertexCache1[i*2+1].Compare( vertexCache2[i*2+1], 1e-2f ) ) { + + if ( !vertexCache1[i * 2 + 1].Compare( vertexCache2[i * 2 + 1], 1e-2f ) ) { break; } } @@ -3249,23 +3521,22 @@ TestSoundUpSampling void TestSoundUpSampling( void ) { int i; TIME_TYPE start, end, bestClocksGeneric, bestClocksSIMD; - ALIGN16( short pcm[MIXBUFFER_SAMPLES*2] ); - ALIGN16( float ogg0[MIXBUFFER_SAMPLES*2] ); - ALIGN16( float ogg1[MIXBUFFER_SAMPLES*2] ); - ALIGN16( float samples1[MIXBUFFER_SAMPLES*2] ); - ALIGN16( float samples2[MIXBUFFER_SAMPLES*2] ); + ALIGN16( short pcm[MIXBUFFER_SAMPLES * 2] ); + ALIGN16( float ogg0[MIXBUFFER_SAMPLES * 2] ); + ALIGN16( float ogg1[MIXBUFFER_SAMPLES * 2] ); + ALIGN16( float samples1[MIXBUFFER_SAMPLES * 2] ); + ALIGN16( float samples2[MIXBUFFER_SAMPLES * 2] ); float *ogg[2]; int kHz, numSpeakers; const char *result; idRandom srnd( RANDOM_SEED ); - for ( i = 0; i < MIXBUFFER_SAMPLES*2; i++ ) { - pcm[i] = srnd.RandomInt( (1<<16) ) - (1<<15); + for ( i = 0; i < MIXBUFFER_SAMPLES * 2; i++ ) { + pcm[i] = srnd.RandomInt( ( 1 << 16 ) ) - ( 1 << 15 ); ogg0[i] = srnd.RandomFloat(); ogg1[i] = srnd.RandomFloat(); } - ogg[0] = ogg0; ogg[1] = ogg1; @@ -3273,29 +3544,32 @@ void TestSoundUpSampling( void ) { for ( kHz = 11025; kHz <= 44100; kHz *= 2 ) { bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); - p_generic->UpSamplePCMTo44kHz( samples1, pcm, MIXBUFFER_SAMPLES*numSpeakers*kHz/44100, kHz, numSpeakers ); + p_generic->UpSamplePCMTo44kHz( samples1, pcm, MIXBUFFER_SAMPLES * numSpeakers * kHz / 44100, kHz, numSpeakers ); StopRecordTime( end ); GetBest( start, end, bestClocksGeneric ); } - PrintClocks( va( "generic->UpSamplePCMTo44kHz( %d, %d )", kHz, numSpeakers ), MIXBUFFER_SAMPLES*numSpeakers*kHz/44100, bestClocksGeneric ); + PrintClocks( va( "generic->UpSamplePCMTo44kHz( %d, %d )", kHz, numSpeakers ), MIXBUFFER_SAMPLES * numSpeakers * kHz / 44100, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); - p_simd->UpSamplePCMTo44kHz( samples2, pcm, MIXBUFFER_SAMPLES*numSpeakers*kHz/44100, kHz, numSpeakers ); + p_simd->UpSamplePCMTo44kHz( samples2, pcm, MIXBUFFER_SAMPLES * numSpeakers * kHz / 44100, kHz, numSpeakers ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - for ( i = 0; i < MIXBUFFER_SAMPLES*numSpeakers; i++ ) { + for ( i = 0; i < MIXBUFFER_SAMPLES * numSpeakers; i++ ) { if ( idMath::Fabs( samples1[i] - samples2[i] ) > SOUND_UPSAMPLE_EPSILON ) { break; } } - result = ( i >= MIXBUFFER_SAMPLES*numSpeakers ) ? "ok" : S_COLOR_RED "X"; - PrintClocks( va( " simd->UpSamplePCMTo44kHz( %d, %d ) %s", kHz, numSpeakers, result ), MIXBUFFER_SAMPLES*numSpeakers*kHz/44100, bestClocksSIMD, bestClocksGeneric ); + result = ( i >= MIXBUFFER_SAMPLES * numSpeakers ) ? "ok" : S_COLOR_RED "X"; + PrintClocks( va( " simd->UpSamplePCMTo44kHz( %d, %d ) %s", kHz, numSpeakers, result ), MIXBUFFER_SAMPLES * numSpeakers * kHz / 44100, bestClocksSIMD, bestClocksGeneric ); } } @@ -3303,29 +3577,32 @@ void TestSoundUpSampling( void ) { for ( kHz = 11025; kHz <= 44100; kHz *= 2 ) { bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); - p_generic->UpSampleOGGTo44kHz( samples1, ogg, MIXBUFFER_SAMPLES*numSpeakers*kHz/44100, kHz, numSpeakers ); + p_generic->UpSampleOGGTo44kHz( samples1, ogg, MIXBUFFER_SAMPLES * numSpeakers * kHz / 44100, kHz, numSpeakers ); StopRecordTime( end ); GetBest( start, end, bestClocksGeneric ); } - PrintClocks( va( "generic->UpSampleOGGTo44kHz( %d, %d )", kHz, numSpeakers ), MIXBUFFER_SAMPLES*numSpeakers*kHz/44100, bestClocksGeneric ); + PrintClocks( va( "generic->UpSampleOGGTo44kHz( %d, %d )", kHz, numSpeakers ), MIXBUFFER_SAMPLES * numSpeakers * kHz / 44100, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); - p_simd->UpSampleOGGTo44kHz( samples2, ogg, MIXBUFFER_SAMPLES*numSpeakers*kHz/44100, kHz, numSpeakers ); + p_simd->UpSampleOGGTo44kHz( samples2, ogg, MIXBUFFER_SAMPLES * numSpeakers * kHz / 44100, kHz, numSpeakers ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - for ( i = 0; i < MIXBUFFER_SAMPLES*numSpeakers; i++ ) { + for ( i = 0; i < MIXBUFFER_SAMPLES * numSpeakers; i++ ) { if ( idMath::Fabs( samples1[i] - samples2[i] ) > SOUND_UPSAMPLE_EPSILON ) { break; } } result = ( i >= MIXBUFFER_SAMPLES ) ? "ok" : S_COLOR_RED "X"; - PrintClocks( va( " simd->UpSampleOGGTo44kHz( %d, %d ) %s", kHz, numSpeakers, result ), MIXBUFFER_SAMPLES*numSpeakers*kHz/44100, bestClocksSIMD, bestClocksGeneric ); + PrintClocks( va( " simd->UpSampleOGGTo44kHz( %d, %d ) %s", kHz, numSpeakers, result ), MIXBUFFER_SAMPLES * numSpeakers * kHz / 44100, bestClocksSIMD, bestClocksGeneric ); } } } @@ -3340,12 +3617,12 @@ TestSoundMixing void TestSoundMixing( void ) { int i, j; TIME_TYPE start, end, bestClocksGeneric, bestClocksSIMD; - ALIGN16( float origMixBuffer[MIXBUFFER_SAMPLES*6] ); - ALIGN16( float mixBuffer1[MIXBUFFER_SAMPLES*6] ); - ALIGN16( float mixBuffer2[MIXBUFFER_SAMPLES*6] ); - ALIGN16( float samples[MIXBUFFER_SAMPLES*6] ); - ALIGN16( short outSamples1[MIXBUFFER_SAMPLES*6] ); - ALIGN16( short outSamples2[MIXBUFFER_SAMPLES*6] ); + ALIGN16( float origMixBuffer[MIXBUFFER_SAMPLES * 6] ); + ALIGN16( float mixBuffer1[MIXBUFFER_SAMPLES * 6] ); + ALIGN16( float mixBuffer2[MIXBUFFER_SAMPLES * 6] ); + ALIGN16( float samples[MIXBUFFER_SAMPLES * 6] ); + ALIGN16( short outSamples1[MIXBUFFER_SAMPLES * 6] ); + ALIGN16( short outSamples2[MIXBUFFER_SAMPLES * 6] ); float lastV[6]; float currentV[6]; const char *result; @@ -3357,14 +3634,16 @@ void TestSoundMixing( void ) { currentV[i] = srnd.CRandomFloat(); } - for ( i = 0; i < MIXBUFFER_SAMPLES*6; i++ ) { + for ( i = 0; i < MIXBUFFER_SAMPLES * 6; i++ ) { origMixBuffer[i] = srnd.CRandomFloat(); - samples[i] = srnd.RandomInt( (1<<16) ) - (1<<15); + samples[i] = srnd.RandomInt( ( 1 << 16 ) ) - ( 1 << 15 ); } + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { - for ( j = 0; j < MIXBUFFER_SAMPLES*6; j++ ) { + for ( j = 0; j < MIXBUFFER_SAMPLES * 6; j++ ) { mixBuffer1[j] = origMixBuffer[j]; } StartRecordTime( start ); @@ -3374,10 +3653,11 @@ void TestSoundMixing( void ) { } PrintClocks( "generic->MixSoundTwoSpeakerMono()", MIXBUFFER_SAMPLES, bestClocksGeneric ); - + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { - for ( j = 0; j < MIXBUFFER_SAMPLES*6; j++ ) { + for ( j = 0; j < MIXBUFFER_SAMPLES * 6; j++ ) { mixBuffer2[j] = origMixBuffer[j]; } StartRecordTime( start ); @@ -3386,17 +3666,19 @@ void TestSoundMixing( void ) { GetBest( start, end, bestClocksSIMD ); } - for ( i = 0; i < MIXBUFFER_SAMPLES*6; i++ ) { + for ( i = 0; i < MIXBUFFER_SAMPLES * 6; i++ ) { if ( idMath::Fabs( mixBuffer1[i] - mixBuffer2[i] ) > SOUND_MIX_EPSILON ) { break; } } - result = ( i >= MIXBUFFER_SAMPLES*6 ) ? "ok" : S_COLOR_RED "X"; + result = ( i >= MIXBUFFER_SAMPLES * 6 ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MixSoundTwoSpeakerMono() %s", result ), MIXBUFFER_SAMPLES, bestClocksSIMD, bestClocksGeneric ); + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { - for ( j = 0; j < MIXBUFFER_SAMPLES*6; j++ ) { + for ( j = 0; j < MIXBUFFER_SAMPLES * 6; j++ ) { mixBuffer1[j] = origMixBuffer[j]; } StartRecordTime( start ); @@ -3406,10 +3688,11 @@ void TestSoundMixing( void ) { } PrintClocks( "generic->MixSoundTwoSpeakerStereo()", MIXBUFFER_SAMPLES, bestClocksGeneric ); - + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { - for ( j = 0; j < MIXBUFFER_SAMPLES*6; j++ ) { + for ( j = 0; j < MIXBUFFER_SAMPLES * 6; j++ ) { mixBuffer2[j] = origMixBuffer[j]; } StartRecordTime( start ); @@ -3418,18 +3701,19 @@ void TestSoundMixing( void ) { GetBest( start, end, bestClocksSIMD ); } - for ( i = 0; i < MIXBUFFER_SAMPLES*6; i++ ) { + for ( i = 0; i < MIXBUFFER_SAMPLES * 6; i++ ) { if ( idMath::Fabs( mixBuffer1[i] - mixBuffer2[i] ) > SOUND_MIX_EPSILON ) { break; } } - result = ( i >= MIXBUFFER_SAMPLES*6 ) ? "ok" : S_COLOR_RED "X"; + result = ( i >= MIXBUFFER_SAMPLES * 6 ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MixSoundTwoSpeakerStereo() %s", result ), MIXBUFFER_SAMPLES, bestClocksSIMD, bestClocksGeneric ); - + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { - for ( j = 0; j < MIXBUFFER_SAMPLES*6; j++ ) { + for ( j = 0; j < MIXBUFFER_SAMPLES * 6; j++ ) { mixBuffer1[j] = origMixBuffer[j]; } StartRecordTime( start ); @@ -3439,10 +3723,11 @@ void TestSoundMixing( void ) { } PrintClocks( "generic->MixSoundSixSpeakerMono()", MIXBUFFER_SAMPLES, bestClocksGeneric ); - + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { - for ( j = 0; j < MIXBUFFER_SAMPLES*6; j++ ) { + for ( j = 0; j < MIXBUFFER_SAMPLES * 6; j++ ) { mixBuffer2[j] = origMixBuffer[j]; } StartRecordTime( start ); @@ -3451,17 +3736,19 @@ void TestSoundMixing( void ) { GetBest( start, end, bestClocksSIMD ); } - for ( i = 0; i < MIXBUFFER_SAMPLES*6; i++ ) { + for ( i = 0; i < MIXBUFFER_SAMPLES * 6; i++ ) { if ( idMath::Fabs( mixBuffer1[i] - mixBuffer2[i] ) > SOUND_MIX_EPSILON ) { break; } } - result = ( i >= MIXBUFFER_SAMPLES*6 ) ? "ok" : S_COLOR_RED "X"; + result = ( i >= MIXBUFFER_SAMPLES * 6 ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MixSoundSixSpeakerMono() %s", result ), MIXBUFFER_SAMPLES, bestClocksSIMD, bestClocksGeneric ); + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { - for ( j = 0; j < MIXBUFFER_SAMPLES*6; j++ ) { + for ( j = 0; j < MIXBUFFER_SAMPLES * 6; j++ ) { mixBuffer1[j] = origMixBuffer[j]; } StartRecordTime( start ); @@ -3471,10 +3758,11 @@ void TestSoundMixing( void ) { } PrintClocks( "generic->MixSoundSixSpeakerStereo()", MIXBUFFER_SAMPLES, bestClocksGeneric ); - + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { - for ( j = 0; j < MIXBUFFER_SAMPLES*6; j++ ) { + for ( j = 0; j < MIXBUFFER_SAMPLES * 6; j++ ) { mixBuffer2[j] = origMixBuffer[j]; } StartRecordTime( start ); @@ -3483,48 +3771,51 @@ void TestSoundMixing( void ) { GetBest( start, end, bestClocksSIMD ); } - for ( i = 0; i < MIXBUFFER_SAMPLES*6; i++ ) { + for ( i = 0; i < MIXBUFFER_SAMPLES * 6; i++ ) { if ( idMath::Fabs( mixBuffer1[i] - mixBuffer2[i] ) > SOUND_MIX_EPSILON ) { break; } } - result = ( i >= MIXBUFFER_SAMPLES*6 ) ? "ok" : S_COLOR_RED "X"; + result = ( i >= MIXBUFFER_SAMPLES * 6 ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MixSoundSixSpeakerStereo() %s", result ), MIXBUFFER_SAMPLES, bestClocksSIMD, bestClocksGeneric ); - - for ( i = 0; i < MIXBUFFER_SAMPLES*6; i++ ) { - origMixBuffer[i] = srnd.RandomInt( (1<<17) ) - (1<<16); + for ( i = 0; i < MIXBUFFER_SAMPLES * 6; i++ ) { + origMixBuffer[i] = srnd.RandomInt( ( 1 << 17 ) ) - ( 1 << 16 ); } + // ====================== bestClocksGeneric = 0; + for ( i = 0; i < NUMTESTS; i++ ) { - for ( j = 0; j < MIXBUFFER_SAMPLES*6; j++ ) { + for ( j = 0; j < MIXBUFFER_SAMPLES * 6; j++ ) { mixBuffer1[j] = origMixBuffer[j]; } StartRecordTime( start ); - p_generic->MixedSoundToSamples( outSamples1, mixBuffer1, MIXBUFFER_SAMPLES*6 ); + p_generic->MixedSoundToSamples( outSamples1, mixBuffer1, MIXBUFFER_SAMPLES * 6 ); StopRecordTime( end ); GetBest( start, end, bestClocksGeneric ); } PrintClocks( "generic->MixedSoundToSamples()", MIXBUFFER_SAMPLES, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; + for ( i = 0; i < NUMTESTS; i++ ) { - for ( j = 0; j < MIXBUFFER_SAMPLES*6; j++ ) { + for ( j = 0; j < MIXBUFFER_SAMPLES * 6; j++ ) { mixBuffer2[j] = origMixBuffer[j]; } StartRecordTime( start ); - p_simd->MixedSoundToSamples( outSamples2, mixBuffer2, MIXBUFFER_SAMPLES*6 ); + p_simd->MixedSoundToSamples( outSamples2, mixBuffer2, MIXBUFFER_SAMPLES * 6 ); StopRecordTime( end ); GetBest( start, end, bestClocksSIMD ); } - for ( i = 0; i < MIXBUFFER_SAMPLES*6; i++ ) { + for ( i = 0; i < MIXBUFFER_SAMPLES * 6; i++ ) { if ( outSamples1[i] != outSamples2[i] ) { break; } } - result = ( i >= MIXBUFFER_SAMPLES*6 ) ? "ok" : S_COLOR_RED "X"; + result = ( i >= MIXBUFFER_SAMPLES * 6 ) ? "ok" : S_COLOR_RED "X"; PrintClocks( va( " simd->MixedSoundToSamples() %s", result ), MIXBUFFER_SAMPLES, bestClocksSIMD, bestClocksGeneric ); } @@ -3537,15 +3828,16 @@ void TestMath( void ) { int i; TIME_TYPE start, end, bestClocks; - idLib::common->Printf("====================================\n" ); + idLib::common->Printf( "====================================\n" ); float tst = -1.0f; float tst2 = 1.0f; float testvar = 1.0f; idRandom rnd; - + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = fabs( tst ); @@ -3556,8 +3848,10 @@ void TestMath( void ) { } PrintClocks( " fabs( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); int tmp = * ( int * ) &tst; @@ -3570,8 +3864,10 @@ void TestMath( void ) { } PrintClocks( " idMath::Fabs( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = 10.0f + 100.0f * rnd.RandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = sqrt( tst ); @@ -3582,8 +3878,10 @@ void TestMath( void ) { } PrintClocks( " sqrt( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.RandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::Sqrt( tst ); @@ -3594,8 +3892,10 @@ void TestMath( void ) { } PrintClocks( " idMath::Sqrt( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.RandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::Sqrt16( tst ); @@ -3606,8 +3906,10 @@ void TestMath( void ) { } PrintClocks( " idMath::Sqrt16( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.RandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::Sqrt64( tst ); @@ -3618,8 +3920,10 @@ void TestMath( void ) { } PrintClocks( " idMath::Sqrt64( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.RandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = tst * idMath::RSqrt( tst ); @@ -3630,8 +3934,10 @@ void TestMath( void ) { } PrintClocks( " idMath::RSqrt( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::Sin( tst ); @@ -3642,8 +3948,10 @@ void TestMath( void ) { } PrintClocks( " idMath::Sin( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::Sin16( tst ); @@ -3654,8 +3962,10 @@ void TestMath( void ) { } PrintClocks( " idMath::Sin16( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::Cos( tst ); @@ -3666,8 +3976,10 @@ void TestMath( void ) { } PrintClocks( " idMath::Cos( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::Cos16( tst ); @@ -3678,8 +3990,10 @@ void TestMath( void ) { } PrintClocks( " idMath::Cos16( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); idMath::SinCos( tst, tst, tst2 ); @@ -3690,8 +4004,10 @@ void TestMath( void ) { } PrintClocks( " idMath::SinCos( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); idMath::SinCos16( tst, tst, tst2 ); @@ -3702,8 +4018,10 @@ void TestMath( void ) { } PrintClocks( "idMath::SinCos16( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::Tan( tst ); @@ -3714,8 +4032,10 @@ void TestMath( void ) { } PrintClocks( " idMath::Tan( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::Tan16( tst ); @@ -3726,8 +4046,10 @@ void TestMath( void ) { } PrintClocks( " idMath::Tan16( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::ASin( tst ); @@ -3738,8 +4060,10 @@ void TestMath( void ) { } PrintClocks( " idMath::ASin( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::ASin16( tst ); @@ -3750,8 +4074,10 @@ void TestMath( void ) { } PrintClocks( " idMath::ASin16( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::ACos( tst ); @@ -3762,8 +4088,10 @@ void TestMath( void ) { } PrintClocks( " idMath::ACos( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::ACos16( tst ); @@ -3774,8 +4102,10 @@ void TestMath( void ) { } PrintClocks( " idMath::ACos16( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::ATan( tst ); @@ -3786,8 +4116,10 @@ void TestMath( void ) { } PrintClocks( " idMath::ATan( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::ATan16( tst ); @@ -3798,8 +4130,10 @@ void TestMath( void ) { } PrintClocks( " idMath::ATan16( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::Pow( 2.7f, tst ); @@ -3810,8 +4144,10 @@ void TestMath( void ) { } PrintClocks( " idMath::Pow( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::Pow16( 2.7f, tst ); @@ -3822,8 +4158,10 @@ void TestMath( void ) { } PrintClocks( " idMath::Pow16( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::Exp( tst ); @@ -3834,8 +4172,10 @@ void TestMath( void ) { } PrintClocks( " idMath::Exp( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); tst = idMath::Exp16( tst ); @@ -3846,8 +4186,10 @@ void TestMath( void ) { } PrintClocks( " idMath::Exp16( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { tst = fabs( tst ) + 1.0f; StartRecordTime( start ); @@ -3859,8 +4201,10 @@ void TestMath( void ) { } PrintClocks( " idMath::Log( tst )", 1, bestClocks ); + // ====================== bestClocks = 0; tst = rnd.CRandomFloat(); + for ( i = 0; i < NUMTESTS; i++ ) { tst = fabs( tst ) + 1.0f; StartRecordTime( start ); @@ -3872,19 +4216,24 @@ void TestMath( void ) { } PrintClocks( " idMath::Log16( tst )", 1, bestClocks ); + // ====================== idLib::common->Printf( "testvar = %f\n", testvar ); + // ====================== idMat3 resultMat3; idQuat fromQuat, toQuat, resultQuat; idCQuat cq; idAngles ang; + // ====================== fromQuat = idAngles( 30, 45, 0 ).ToQuat(); toQuat = idAngles( 45, 0, 0 ).ToQuat(); cq = idAngles( 30, 45, 0 ).ToQuat().ToCQuat(); ang = idAngles( 30, 40, 50 ); + // ====================== bestClocks = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); resultMat3 = fromQuat.ToMat3(); @@ -3893,7 +4242,9 @@ void TestMath( void ) { } PrintClocks( " idQuat::ToMat3()", 1, bestClocks ); + // ====================== bestClocks = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); resultQuat.Slerp( fromQuat, toQuat, 0.3f ); @@ -3902,7 +4253,9 @@ void TestMath( void ) { } PrintClocks( " idQuat::Slerp()", 1, bestClocks ); + // ====================== bestClocks = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); resultQuat = cq.ToQuat(); @@ -3911,7 +4264,9 @@ void TestMath( void ) { } PrintClocks( " idCQuat::ToQuat()", 1, bestClocks ); + // ====================== bestClocks = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); resultQuat = ang.ToQuat(); @@ -3920,7 +4275,9 @@ void TestMath( void ) { } PrintClocks( " idAngles::ToQuat()", 1, bestClocks ); + // ====================== bestClocks = 0; + for ( i = 0; i < NUMTESTS; i++ ) { StartRecordTime( start ); resultMat3 = ang.ToMat3(); @@ -3950,15 +4307,14 @@ void TestNegate( void ) { for ( i = 0; i < COUNT; i++ ) { fsrc0[i] = fsrc1[i] = fsrc2[i] = srnd.CRandomFloat() * 10.0f; - //fsrc1[i] = srnd.CRandomFloat() * 10.0f; } + idLib::common->Printf( "====================================\n" ); - idLib::common->Printf("====================================\n" ); - + // ====================== bestClocksGeneric = 0; - for ( i = 0; i < NUMTESTS; i++ ) { - memcpy( &fsrc1[0], &fsrc0[0], COUNT * sizeof(float) ); + for ( i = 0; i < NUMTESTS; i++ ) { + memcpy( &fsrc1[0], &fsrc0[0], COUNT * sizeof( float ) ); StartRecordTime( start ); p_generic->Negate16( fsrc1, COUNT ); @@ -3967,10 +4323,11 @@ void TestNegate( void ) { } PrintClocks( "generic->Negate16( float[] )", COUNT, bestClocksGeneric ); + // ====================== bestClocksSIMD = 0; - for ( i = 0; i < NUMTESTS; i++ ) { - memcpy( &fsrc2[0], &fsrc0[0], COUNT * sizeof(float) ); + for ( i = 0; i < NUMTESTS; i++ ) { + memcpy( &fsrc2[0], &fsrc0[0], COUNT * sizeof( float ) ); StartRecordTime( start ); p_simd->Negate16( fsrc2, COUNT ); @@ -3994,7 +4351,6 @@ idSIMD::Test_f ============ */ void idSIMD::Test_f( const idCmdArgs &args ) { - #ifdef _WIN32 SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ); #endif /* _WIN32 */ @@ -4003,8 +4359,8 @@ void idSIMD::Test_f( const idCmdArgs &args ) { p_generic = generic; if ( idStr::Length( args.Argv( 1 ) ) != 0 ) { - int cpuid = idLib::sys->GetProcessorId(); - idStr argString = args.Args(); + int cpuid = idLib::sys->GetProcessorId(); + idStr argString = args.Args(); argString.Replace( " ", "" ); @@ -4038,6 +4394,18 @@ void idSIMD::Test_f( const idCmdArgs &args ) { return; } p_simd = new idSIMD_SSE3(); + } else if ( idStr::Icmp( argString, "AVX" ) == 0 ) { + if ( !( cpuid & CPUID_SSE ) || !( cpuid & CPUID_SSE2 ) || !( cpuid & CPUID_SSE3 ) || !( cpuid & CPUID_AVX ) ) { + common->Printf( "CPU does not support SSE* & AVX\n" ); + return; + } + p_simd = new idSIMD_AVX(); + } else if ( idStr::Icmp( argString, "AVX2" ) == 0 ) { + if ( !( cpuid & CPUID_SSE ) || !( cpuid & CPUID_SSE2 ) || !( cpuid & CPUID_SSE3 ) || !( cpuid & CPUID_AVX ) || !( cpuid & CPUID_AVX2 ) || !( cpuid & CPUID_FMA3 ) ) { + common->Printf( "CPU does not support SSE* & AVX & AVX2 & FMA3\n" ); + return; + } + p_simd = new idSIMD_AVX2(); } else if ( idStr::Icmp( argString, "AltiVec" ) == 0 ) { if ( !( cpuid & CPUID_ALTIVEC ) ) { common->Printf( "CPU does not support AltiVec\n" ); @@ -4049,13 +4417,13 @@ void idSIMD::Test_f( const idCmdArgs &args ) { return; } } - idLib::common->SetRefreshOnPrint( true ); - idLib::common->Printf( "using %s for SIMD processing\n", p_simd->GetName() ); + // ====================== GetBaseClocks(); + // ====================== TestMath(); TestAdd(); TestSub(); @@ -4071,6 +4439,7 @@ void idSIMD::Test_f( const idCmdArgs &args ) { TestMemset(); TestNegate(); + // ====================== TestMatXMultiplyVecX(); TestMatXMultiplyAddVecX(); TestMatXTransposeMultiplyVecX(); @@ -4081,8 +4450,10 @@ void idSIMD::Test_f( const idCmdArgs &args ) { TestMatXLowerTriangularSolveTranspose(); TestMatXLDLTFactor(); - idLib::common->Printf("====================================\n" ); + // ====================== + idLib::common->Printf( "====================================\n" ); + // ====================== TestBlendJoints(); TestConvertJointQuatsToJointMats(); TestConvertJointMatsToJointQuats(); @@ -4100,13 +4471,17 @@ void idSIMD::Test_f( const idCmdArgs &args ) { TestGetSpecularTextureCoords(); TestCreateShadowCache(); - idLib::common->Printf("====================================\n" ); + // ====================== + idLib::common->Printf( "====================================\n" ); + // ====================== TestSoundUpSampling(); TestSoundMixing(); + // ====================== idLib::common->SetRefreshOnPrint( false ); + // ====================== if ( p_simd != processor ) { delete p_simd; } diff --git a/neo/idlib/math/Simd.h b/neo/idlib/math/Simd.h index 97e4c443f..5d0b710a4 100644 --- a/neo/idlib/math/Simd.h +++ b/neo/idlib/math/Simd.h @@ -45,12 +45,11 @@ If you have questions concerning this license or the applicable additional terms class idSIMD { public: static void Init( void ); - static void InitProcessor( const char *module, bool forceGeneric ); + static void InitProcessor( const char *module, bool forceGeneric = false ); static void Shutdown( void ); static void Test_f( const class idCmdArgs &args ); }; - /* =============================================================================== @@ -94,11 +93,10 @@ typedef enum { SPEAKER_BACKRIGHT } speakerLabel; - class idSIMDProcessor { public: idSIMDProcessor( void ) { cpuid = CPUID_NONE; } - virtual ~idSIMDProcessor() { }; + virtual ~idSIMDProcessor() {}; int cpuid; @@ -199,6 +197,11 @@ class idSIMDProcessor { virtual void VPCALL MixSoundSixSpeakerMono( float *mixBuffer, const float *samples, const int numSamples, const float lastV[6], const float currentV[6] ) = 0; virtual void VPCALL MixSoundSixSpeakerStereo( float *mixBuffer, const float *samples, const int numSamples, const float lastV[6], const float currentV[6] ) = 0; virtual void VPCALL MixedSoundToSamples( short *samples, const float *mixBuffer, const int numSamples ) = 0; + + // plane culling + virtual void VPCALL CullByFrustum( idDrawVert *verts, const int numVerts, const idPlane frustum[6], byte *pointCull, float epsilon ) = 0; + virtual void VPCALL CullByFrustum2( idDrawVert *verts, const int numVerts, const idPlane frustum[6], unsigned short *pointCull, float epsilon ) = 0; + }; // pointer to SIMD processor diff --git a/neo/idlib/math/Simd_3DNow.cpp b/neo/idlib/math/Simd_3DNow.cpp index cbe3e4fe6..2e29f36c0 100644 --- a/neo/idlib/math/Simd_3DNow.cpp +++ b/neo/idlib/math/Simd_3DNow.cpp @@ -27,7 +27,6 @@ If you have questions concerning this license or the applicable additional terms */ #include "sys/platform.h" - #include "idlib/math/Simd_3DNow.h" //=============================================================== diff --git a/neo/idlib/math/Simd_AVX.cpp b/neo/idlib/math/Simd_AVX.cpp new file mode 100644 index 000000000..49ba71ab9 --- /dev/null +++ b/neo/idlib/math/Simd_AVX.cpp @@ -0,0 +1,130 @@ +/* +=========================================================================== + +Doom 3 GPL Source Code +Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. + +This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). + +Doom 3 Source Code is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Doom 3 Source Code is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Doom 3 Source Code. If not, see . + +In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ + +#include "sys/platform.h" +#include "Simd_AVX.h" + +//=============================================================== +// +// AVX implementation of idSIMDProcessor +// +//=============================================================== + +// Revelator: these work whether in gcc clang or msvc in x86 or x64 (no inline assembly used) +#if defined(_MSC_VER) && ( defined(_M_X64) || defined(_M_IX86) ) || \ + defined(__GNUC__) && ( defined(__i386__) || defined (__x86_64__) ) && defined(__AVX__) + +#include + +#include "idlib/geometry/DrawVert.h" +#include "idlib/geometry/JointTransform.h" +#include "idlib/math/Vector.h" +#include "idlib/math/Plane.h" + +/* +============ +idSIMD_AVX::GetName +============ +*/ +const char *idSIMD_AVX::GetName( void ) const { + return "MMX & SSE & SSE2 & SSE3 & AVX"; +} + +/* +============ +idSIMD_AVX::CullByFrustum +============ +*/ +void VPCALL idSIMD_AVX::CullByFrustum( idDrawVert *verts, const int numVerts, const idPlane frustum[6], byte *pointCull, float epsilon ) { + const __m256 fA = _mm256_set_ps( 0, 0, frustum[5][0], frustum[4][0], frustum[3][0], frustum[2][0], frustum[1][0], frustum[0][0] ); + const __m256 fB = _mm256_set_ps( 0, 0, frustum[5][1], frustum[4][1], frustum[3][1], frustum[2][1], frustum[1][1], frustum[0][1] ); + const __m256 fC = _mm256_set_ps( 0, 0, frustum[5][2], frustum[4][2], frustum[3][2], frustum[2][2], frustum[1][2], frustum[0][2] ); + const __m256 fD = _mm256_set_ps( 0, 0, frustum[5][3], frustum[4][3], frustum[3][3], frustum[2][3], frustum[1][3], frustum[0][3] ); + const __m256 eps = _mm256_set1_ps( epsilon ); + const byte mask6 = ( 1 << 6 ) - 1; + + for( int j = 0; j < numVerts; j++ ) { + idVec3 &vec = verts[j].xyz; + __m256 vX = _mm256_set1_ps( vec.x ); + __m256 vY = _mm256_set1_ps( vec.y ); + __m256 vZ = _mm256_set1_ps( vec.z ); + __m256 d = + _mm256_add_ps( + _mm256_add_ps( + _mm256_mul_ps( fA, vX ), + _mm256_mul_ps( fB, vY ) + ), + _mm256_add_ps( + _mm256_mul_ps( fC, vZ ), + fD + ) + ); + int mask_lo = _mm256_movemask_ps( _mm256_cmp_ps( d, eps, _CMP_LT_OQ ) ); + pointCull[j] = ( byte )( mask_lo & mask6 ); // gcc compiler warning + } + _mm256_zeroupper(); +} + +/* +============ +idSIMD_AVX::CullByFrustum2 +============ +*/ +void VPCALL idSIMD_AVX::CullByFrustum2( idDrawVert *verts, const int numVerts, const idPlane frustum[6], unsigned short *pointCull, float epsilon ) { + const __m256 fA = _mm256_set_ps( 0, 0, frustum[5][0], frustum[4][0], frustum[3][0], frustum[2][0], frustum[1][0], frustum[0][0] ); + const __m256 fB = _mm256_set_ps( 0, 0, frustum[5][1], frustum[4][1], frustum[3][1], frustum[2][1], frustum[1][1], frustum[0][1] ); + const __m256 fC = _mm256_set_ps( 0, 0, frustum[5][2], frustum[4][2], frustum[3][2], frustum[2][2], frustum[1][2], frustum[0][2] ); + const __m256 fD = _mm256_set_ps( 0, 0, frustum[5][3], frustum[4][3], frustum[3][3], frustum[2][3], frustum[1][3], frustum[0][3] ); + const __m256 eps = _mm256_set1_ps( epsilon ); + static const __m256 epsM = _mm256_set1_ps( -epsilon ); + const short mask6 = ( 1 << 6 ) - 1; + + for( int j = 0; j < numVerts; j++ ) { + idVec3 &vec = verts[j].xyz; + __m256 vX = _mm256_set1_ps( vec.x ); + __m256 vY = _mm256_set1_ps( vec.y ); + __m256 vZ = _mm256_set1_ps( vec.z ); + __m256 d = + _mm256_add_ps( + _mm256_add_ps( + _mm256_mul_ps( fA, vX ), + _mm256_mul_ps( fB, vY ) + ), + _mm256_add_ps( + _mm256_mul_ps( fC, vZ ), + fD + ) + ); + int mask_lo = _mm256_movemask_ps( _mm256_cmp_ps( d, eps, _CMP_LT_OQ ) ); + int mask_hi = _mm256_movemask_ps( _mm256_cmp_ps( d, eps, _CMP_GT_OQ ) ); + pointCull[j] = ( unsigned short )( ( mask_lo & mask6 ) | ( mask_hi & mask6 ) << 6 ); // gcc compiler warning + } + _mm256_zeroupper(); +} + +#endif /* _MSC_VER */ diff --git a/neo/idlib/math/Simd_AVX.h b/neo/idlib/math/Simd_AVX.h new file mode 100644 index 000000000..6ea997b77 --- /dev/null +++ b/neo/idlib/math/Simd_AVX.h @@ -0,0 +1,42 @@ +/***************************************************************************** + The Dark Mod GPL Source Code + + This file is part of the The Dark Mod Source Code, originally based + on the Doom 3 GPL Source Code as published in 2011. + + The Dark Mod Source Code is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. For details, see LICENSE.TXT. + + Project: The Dark Mod (http://www.thedarkmod.com/) + +******************************************************************************/ + +#ifndef __MATH_SIMD_AVX_H__ +#define __MATH_SIMD_AVX_H__ + +#include "idlib/math/Simd_SSE3.h" + +/* +=============================================================================== + + AVX implementation of idSIMDProcessor + +=============================================================================== +*/ + +class idSIMD_AVX : public idSIMD_SSE3 { +public: +// Revelator: these work whether in gcc clang or msvc x86 or x64 (no inline assembly used) +#if defined(_MSC_VER) && ( defined(_M_X64) || defined(_M_IX86) ) || \ + defined(__GNUC__) && ( defined(__i386__) || defined (__x86_64__) ) && defined(__AVX__) + + virtual const char *VPCALL GetName( void ) const; + virtual void VPCALL CullByFrustum( idDrawVert *verts, const int numVerts, const idPlane frustum[6], byte *pointCull, float epsilon ); + virtual void VPCALL CullByFrustum2( idDrawVert *verts, const int numVerts, const idPlane frustum[6], unsigned short *pointCull, float epsilon ); + +#endif +}; + +#endif /* !__MATH_SIMD_AVX_H__ */ diff --git a/neo/idlib/math/Simd_AVX2.cpp b/neo/idlib/math/Simd_AVX2.cpp new file mode 100644 index 000000000..ebbeb12ef --- /dev/null +++ b/neo/idlib/math/Simd_AVX2.cpp @@ -0,0 +1,114 @@ +/* +=========================================================================== + +Doom 3 GPL Source Code +Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. + +This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). + +Doom 3 Source Code is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Doom 3 Source Code is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Doom 3 Source Code. If not, see . + +In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ + +#include "sys/platform.h" +#include "Simd_AVX2.h" + +//=============================================================== +// +// AVX2 implementation of idSIMDProcessor +// +//=============================================================== + +// Revelator: these work whether in gcc clang or msvc in x86 or x64 (no inline assembly used) +#if defined(_MSC_VER) && ( defined(_M_X64) || defined(_M_IX86) ) || \ + defined(__GNUC__) && ( defined(__i386__) || defined (__x86_64__) ) && defined(__AVX2__) + +#include + +#include "idlib/geometry/DrawVert.h" +#include "idlib/geometry/JointTransform.h" +#include "idlib/math/Vector.h" +#include "idlib/math/Plane.h" + +/* +============ +idSIMD_AVX2::GetName +============ +*/ +const char *idSIMD_AVX2::GetName( void ) const { + return "MMX & SSE & SSE2 & SSE3 & AVX & AVX2"; +} + +/* +============ +idSIMD_AVX2::CullByFrustum +============ +*/ +void VPCALL idSIMD_AVX2::CullByFrustum( idDrawVert *verts, const int numVerts, const idPlane frustum[6], byte *pointCull, float epsilon ) { + const __m256 fA = _mm256_set_ps( 0, 0, frustum[5][0], frustum[4][0], frustum[3][0], frustum[2][0], frustum[1][0], frustum[0][0] ); + const __m256 fB = _mm256_set_ps( 0, 0, frustum[5][1], frustum[4][1], frustum[3][1], frustum[2][1], frustum[1][1], frustum[0][1] ); + const __m256 fC = _mm256_set_ps( 0, 0, frustum[5][2], frustum[4][2], frustum[3][2], frustum[2][2], frustum[1][2], frustum[0][2] ); + const __m256 fD = _mm256_set_ps( 0, 0, frustum[5][3], frustum[4][3], frustum[3][3], frustum[2][3], frustum[1][3], frustum[0][3] ); + const __m256 eps = _mm256_set1_ps( epsilon ); + const byte mask6 = ( 1 << 6 ) - 1; + + for ( int j = 0; j < numVerts; j++ ) { + idVec3 &vec = verts[j].xyz; + __m256 vX = _mm256_set1_ps( vec.x ); + __m256 vY = _mm256_set1_ps( vec.y ); + __m256 vZ = _mm256_set1_ps( vec.z ); + __m256 d = _mm256_fmadd_ps( fA, vX, + _mm256_fmadd_ps( fB, vY, + _mm256_fmadd_ps( fC, vZ, fD ) ) ); + int mask_lo = _mm256_movemask_ps( _mm256_cmp_ps( d, eps, _CMP_LT_OQ ) ); + pointCull[j] = ( byte )( mask_lo & mask6 ); // gcc compiler warning + } + _mm256_zeroupper(); +} + +/* +============ +idSIMD_AVX2::CullByFrustum2 +============ +*/ +void VPCALL idSIMD_AVX2::CullByFrustum2( idDrawVert *verts, const int numVerts, const idPlane frustum[6], unsigned short *pointCull, float epsilon ) { + const __m256 fA = _mm256_set_ps( 0, 0, frustum[5][0], frustum[4][0], frustum[3][0], frustum[2][0], frustum[1][0], frustum[0][0] ); + const __m256 fB = _mm256_set_ps( 0, 0, frustum[5][1], frustum[4][1], frustum[3][1], frustum[2][1], frustum[1][1], frustum[0][1] ); + const __m256 fC = _mm256_set_ps( 0, 0, frustum[5][2], frustum[4][2], frustum[3][2], frustum[2][2], frustum[1][2], frustum[0][2] ); + const __m256 fD = _mm256_set_ps( 0, 0, frustum[5][3], frustum[4][3], frustum[3][3], frustum[2][3], frustum[1][3], frustum[0][3] ); + const __m256 eps = _mm256_set1_ps( epsilon ); + static const __m256 epsM = _mm256_set1_ps( -epsilon ); + const short mask6 = ( 1 << 6 ) - 1; + + for ( int j = 0; j < numVerts; j++ ) { + idVec3 &vec = verts[j].xyz; + __m256 vX = _mm256_set1_ps( vec.x ); + __m256 vY = _mm256_set1_ps( vec.y ); + __m256 vZ = _mm256_set1_ps( vec.z ); + __m256 d = _mm256_fmadd_ps( fA, vX, + _mm256_fmadd_ps( fB, vY, + _mm256_fmadd_ps( fC, vZ, fD ) ) ); + int mask_lo = _mm256_movemask_ps( _mm256_cmp_ps( d, eps, _CMP_LT_OQ ) ); + int mask_hi = _mm256_movemask_ps( _mm256_cmp_ps( d, eps, _CMP_GT_OQ ) ); + pointCull[j] = ( unsigned short )( ( mask_lo & mask6 ) | ( mask_hi & mask6 ) << 6 ); // gcc compiler warning + } + _mm256_zeroupper(); +} + +#endif diff --git a/neo/idlib/math/Simd_AVX2.h b/neo/idlib/math/Simd_AVX2.h new file mode 100644 index 000000000..9fdf2170e --- /dev/null +++ b/neo/idlib/math/Simd_AVX2.h @@ -0,0 +1,42 @@ +/***************************************************************************** + The Dark Mod GPL Source Code + + This file is part of the The Dark Mod Source Code, originally based + on the Doom 3 GPL Source Code as published in 2011. + + The Dark Mod Source Code is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. For details, see LICENSE.TXT. + + Project: The Dark Mod (http://www.thedarkmod.com/) + +******************************************************************************/ + +#ifndef __MATH_SIMD_AVX2_H__ +#define __MATH_SIMD_AVX2_H__ + +#include "idlib/math/Simd_AVX.h" + +/* +=============================================================================== + + AVX2 implementation of idSIMDProcessor + +=============================================================================== +*/ + +class idSIMD_AVX2 : public idSIMD_AVX { +public: +// Revelator: these work whether in gcc clang or msvc in x86 or x64 (no inline assembly used) +#if defined(_MSC_VER) && ( defined(_M_X64) || defined(_M_IX86) ) || \ + defined(__GNUC__) && ( defined(__i386__) || defined (__x86_64__) ) && defined(__AVX2__) + + virtual const char *VPCALL GetName( void ) const; + virtual void VPCALL CullByFrustum( idDrawVert *verts, const int numVerts, const idPlane frustum[6], byte *pointCull, float epsilon ); + virtual void VPCALL CullByFrustum2( idDrawVert *verts, const int numVerts, const idPlane frustum[6], unsigned short *pointCull, float epsilon ); + +#endif +}; + +#endif /* !__MATH_SIMD_AVX2_H__ */ diff --git a/neo/idlib/math/Simd_AltiVec.cpp b/neo/idlib/math/Simd_AltiVec.cpp index 8f8ab4ea6..a3beda5aa 100644 --- a/neo/idlib/math/Simd_AltiVec.cpp +++ b/neo/idlib/math/Simd_AltiVec.cpp @@ -30,7 +30,6 @@ If you have questions concerning this license or the applicable additional terms #include #include "sys/platform.h" - #include "idlib/math/Simd_AltiVec.h" // Doom3 SIMD Library version 0.5 @@ -293,6 +292,7 @@ inline void debugPrintVector( vector unsigned short v, char *msg ) { printf("%s -- %vs\n", msg, v ); } #endif + /* =============== Reciprocal @@ -416,7 +416,6 @@ inline vector float VectorSin16( vector float v ) { #if 0 // load up half PI and use it to calculate the rest of the values. This is // sometimes cheaper than loading them from memory - vector float halfPI = (vector float) ( 0.5f * 3.14159265358979323846f ); vector float PI = vec_add( halfPI, halfPI ); vector float oneandhalfPI = vec_add( PI, halfPI ); @@ -603,7 +602,6 @@ inline void FastScalarInvSqrt_x6( float *arg1, float *arg2, float *arg3, float * #endif } - // End Helper Functions #ifdef ENABLE_SIMPLE_MATH diff --git a/neo/idlib/math/Simd_AltiVec.h b/neo/idlib/math/Simd_AltiVec.h index d50808245..6a66ff8f4 100644 --- a/neo/idlib/math/Simd_AltiVec.h +++ b/neo/idlib/math/Simd_AltiVec.h @@ -113,7 +113,7 @@ class idSIMD_AltiVec : public idSIMD_Generic { #if defined(MACOS_X) && defined(__GNUC__) && defined(__ALTIVEC__) public: - virtual const char * VPCALL GetName( void ) const; + virtual const char *VPCALL GetName( void ) const; #ifdef ENABLE_SIMPLE_MATH // Basic math, works for both aligned and unaligned data diff --git a/neo/idlib/math/Simd_Generic.cpp b/neo/idlib/math/Simd_Generic.cpp index 9ce25f6d7..9c55b3d98 100644 --- a/neo/idlib/math/Simd_Generic.cpp +++ b/neo/idlib/math/Simd_Generic.cpp @@ -33,7 +33,6 @@ If you have questions concerning this license or the applicable additional terms #include "idlib/math/Plane.h" #include "idlib/math/Matrix.h" #include "renderer/Model.h" - #include "idlib/math/Simd_Generic.h" //=============================================================== @@ -61,7 +60,7 @@ If you have questions concerning this license or the applicable additional terms idSIMD_Generic::GetName ============ */ -const char * idSIMD_Generic::GetName( void ) const { +const char *idSIMD_Generic::GetName( void ) const { return "generic code"; } @@ -74,7 +73,7 @@ idSIMD_Generic::Add */ void VPCALL idSIMD_Generic::Add( float *dst, const float constant, const float *src, const int count ) { #define OPER(X) dst[(X)] = src[(X)] + constant; - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -87,7 +86,7 @@ idSIMD_Generic::Add */ void VPCALL idSIMD_Generic::Add( float *dst, const float *src0, const float *src1, const int count ) { #define OPER(X) dst[(X)] = src0[(X)] + src1[(X)]; - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -101,7 +100,7 @@ idSIMD_Generic::Sub void VPCALL idSIMD_Generic::Sub( float *dst, const float constant, const float *src, const int count ) { double c = constant; #define OPER(X) dst[(X)] = c - src[(X)]; - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -114,7 +113,7 @@ idSIMD_Generic::Sub */ void VPCALL idSIMD_Generic::Sub( float *dst, const float *src0, const float *src1, const int count ) { #define OPER(X) dst[(X)] = src0[(X)] - src1[(X)]; - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -125,10 +124,10 @@ idSIMD_Generic::Mul dst[i] = constant * src[i]; ============ */ -void VPCALL idSIMD_Generic::Mul( float *dst, const float constant, const float *src0, const int count) { +void VPCALL idSIMD_Generic::Mul( float *dst, const float constant, const float *src0, const int count ) { double c = constant; #define OPER(X) (dst[(X)] = (c * src0[(X)])) - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -141,7 +140,7 @@ idSIMD_Generic::Mul */ void VPCALL idSIMD_Generic::Mul( float *dst, const float *src0, const float *src1, const int count ) { #define OPER(X) (dst[(X)] = src0[(X)] * src1[(X)]) - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -155,7 +154,7 @@ idSIMD_Generic::Div void VPCALL idSIMD_Generic::Div( float *dst, const float constant, const float *divisor, const int count ) { double c = constant; #define OPER(X) (dst[(X)] = (c / divisor[(X)])) - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -168,7 +167,7 @@ idSIMD_Generic::Div */ void VPCALL idSIMD_Generic::Div( float *dst, const float *src0, const float *src1, const int count ) { #define OPER(X) (dst[(X)] = src0[(X)] / src1[(X)]) - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -182,7 +181,7 @@ idSIMD_Generic::MulAdd void VPCALL idSIMD_Generic::MulAdd( float *dst, const float constant, const float *src, const int count ) { double c = constant; #define OPER(X) (dst[(X)] += c * src[(X)]) - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -195,7 +194,7 @@ idSIMD_Generic::MulAdd */ void VPCALL idSIMD_Generic::MulAdd( float *dst, const float *src0, const float *src1, const int count ) { #define OPER(X) (dst[(X)] += src0[(X)] * src1[(X)]) - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -209,7 +208,7 @@ idSIMD_Generic::MulSub void VPCALL idSIMD_Generic::MulSub( float *dst, const float constant, const float *src, const int count ) { double c = constant; #define OPER(X) (dst[(X)] -= c * src[(X)]) - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -222,7 +221,7 @@ idSIMD_Generic::MulSub */ void VPCALL idSIMD_Generic::MulSub( float *dst, const float *src0, const float *src1, const int count ) { #define OPER(X) (dst[(X)] -= src0[(X)] * src1[(X)]) - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -235,7 +234,7 @@ idSIMD_Generic::Dot */ void VPCALL idSIMD_Generic::Dot( float *dst, const idVec3 &constant, const idVec3 *src, const int count ) { #define OPER(X) dst[(X)] = constant * src[(X)]; - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -248,7 +247,7 @@ idSIMD_Generic::Dot */ void VPCALL idSIMD_Generic::Dot( float *dst, const idVec3 &constant, const idPlane *src, const int count ) { #define OPER(X) dst[(X)] = constant * src[(X)].Normal() + src[(X)][3]; - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -261,7 +260,7 @@ idSIMD_Generic::Dot */ void VPCALL idSIMD_Generic::Dot( float *dst, const idVec3 &constant, const idDrawVert *src, const int count ) { #define OPER(X) dst[(X)] = constant * src[(X)].xyz; - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -274,7 +273,7 @@ idSIMD_Generic::Dot */ void VPCALL idSIMD_Generic::Dot( float *dst, const idPlane &constant, const idVec3 *src, const int count ) { #define OPER(X) dst[(X)] = constant.Normal() * src[(X)] + constant[3]; - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -287,7 +286,7 @@ idSIMD_Generic::Dot */ void VPCALL idSIMD_Generic::Dot( float *dst, const idPlane &constant, const idPlane *src, const int count ) { #define OPER(X) dst[(X)] = constant.Normal() * src[(X)].Normal() + constant[3] * src[(X)][3]; - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -300,7 +299,7 @@ idSIMD_Generic::Dot */ void VPCALL idSIMD_Generic::Dot( float *dst, const idPlane &constant, const idDrawVert *src, const int count ) { #define OPER(X) dst[(X)] = constant.Normal() * src[(X)].xyz + constant[3]; - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -313,7 +312,7 @@ idSIMD_Generic::Dot */ void VPCALL idSIMD_Generic::Dot( float *dst, const idVec3 *src0, const idVec3 *src1, const int count ) { #define OPER(X) dst[(X)] = src0[(X)] * src1[(X)]; - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -326,8 +325,7 @@ idSIMD_Generic::Dot */ void VPCALL idSIMD_Generic::Dot( float &dot, const float *src1, const float *src2, const int count ) { #if 1 - - switch( count ) { + switch ( count ) { case 0: { dot = 0.0f; return; @@ -347,30 +345,41 @@ void VPCALL idSIMD_Generic::Dot( float &dot, const float *src1, const float *src default: { int i; double s0, s1, s2, s3; + s0 = src1[0] * src2[0]; s1 = src1[1] * src2[1]; s2 = src1[2] * src2[2]; s3 = src1[3] * src2[3]; - for ( i = 4; i < count-7; i += 8 ) { - s0 += src1[i+0] * src2[i+0]; - s1 += src1[i+1] * src2[i+1]; - s2 += src1[i+2] * src2[i+2]; - s3 += src1[i+3] * src2[i+3]; - s0 += src1[i+4] * src2[i+4]; - s1 += src1[i+5] * src2[i+5]; - s2 += src1[i+6] * src2[i+6]; - s3 += src1[i+7] * src2[i+7]; + + for ( i = 4; i < count - 7; i += 8 ) { + s0 += src1[i + 0] * src2[i + 0]; + s1 += src1[i + 1] * src2[i + 1]; + s2 += src1[i + 2] * src2[i + 2]; + s3 += src1[i + 3] * src2[i + 3]; + s0 += src1[i + 4] * src2[i + 4]; + s1 += src1[i + 5] * src2[i + 5]; + s2 += src1[i + 6] * src2[i + 6]; + s3 += src1[i + 7] * src2[i + 7]; } - switch( count - i ) { + + switch ( count - i ) { NODEFAULT; - case 7: s0 += src1[i+6] * src2[i+6]; - case 6: s1 += src1[i+5] * src2[i+5]; - case 5: s2 += src1[i+4] * src2[i+4]; - case 4: s3 += src1[i+3] * src2[i+3]; - case 3: s0 += src1[i+2] * src2[i+2]; - case 2: s1 += src1[i+1] * src2[i+1]; - case 1: s2 += src1[i+0] * src2[i+0]; - case 0: break; + case 7: + s0 += src1[i + 6] * src2[i + 6]; + case 6: + s1 += src1[i + 5] * src2[i + 5]; + case 5: + s2 += src1[i + 4] * src2[i + 4]; + case 4: + s3 += src1[i + 3] * src2[i + 3]; + case 3: + s0 += src1[i + 2] * src2[i + 2]; + case 2: + s1 += src1[i + 1] * src2[i + 1]; + case 1: + s2 += src1[i + 0] * src2[i + 0]; + case 0: + break; } double sum; sum = s3; @@ -380,14 +389,12 @@ void VPCALL idSIMD_Generic::Dot( float &dot, const float *src1, const float *src dot = sum; } } - #else - dot = 0.0f; + for ( i = 0; i < count; i++ ) { dot += src1[i] * src2[i]; } - #endif } @@ -400,7 +407,7 @@ idSIMD_Generic::CmpGT */ void VPCALL idSIMD_Generic::CmpGT( byte *dst, const float *src0, const float constant, const int count ) { #define OPER(X) dst[(X)] = src0[(X)] > constant; - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -413,7 +420,7 @@ idSIMD_Generic::CmpGT */ void VPCALL idSIMD_Generic::CmpGT( byte *dst, const byte bitNum, const float *src0, const float constant, const int count ) { #define OPER(X) dst[(X)] |= ( src0[(X)] > constant ) << bitNum; - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -426,7 +433,7 @@ idSIMD_Generic::CmpGE */ void VPCALL idSIMD_Generic::CmpGE( byte *dst, const float *src0, const float constant, const int count ) { #define OPER(X) dst[(X)] = src0[(X)] >= constant; - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -439,7 +446,7 @@ idSIMD_Generic::CmpGE */ void VPCALL idSIMD_Generic::CmpGE( byte *dst, const byte bitNum, const float *src0, const float constant, const int count ) { #define OPER(X) dst[(X)] |= ( src0[(X)] >= constant ) << bitNum; - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -452,7 +459,7 @@ idSIMD_Generic::CmpLT */ void VPCALL idSIMD_Generic::CmpLT( byte *dst, const float *src0, const float constant, const int count ) { #define OPER(X) dst[(X)] = src0[(X)] < constant; - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -465,7 +472,7 @@ idSIMD_Generic::CmpLT */ void VPCALL idSIMD_Generic::CmpLT( byte *dst, const byte bitNum, const float *src0, const float constant, const int count ) { #define OPER(X) dst[(X)] |= ( src0[(X)] < constant ) << bitNum; - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -478,7 +485,7 @@ idSIMD_Generic::CmpLE */ void VPCALL idSIMD_Generic::CmpLE( byte *dst, const float *src0, const float constant, const int count ) { #define OPER(X) dst[(X)] = src0[(X)] <= constant; - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -491,7 +498,7 @@ idSIMD_Generic::CmpLE */ void VPCALL idSIMD_Generic::CmpLE( byte *dst, const byte bitNum, const float *src0, const float constant, const int count ) { #define OPER(X) dst[(X)] |= ( src0[(X)] <= constant ) << bitNum; - UNROLL4(OPER) + UNROLL4( OPER ) #undef OPER } @@ -501,9 +508,10 @@ idSIMD_Generic::MinMax ============ */ void VPCALL idSIMD_Generic::MinMax( float &min, float &max, const float *src, const int count ) { - min = idMath::INFINITY; max = -idMath::INFINITY; + min = idMath::INFINITY; + max = -idMath::INFINITY; #define OPER(X) if ( src[(X)] < min ) {min = src[(X)];} if ( src[(X)] > max ) {max = src[(X)];} - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -513,9 +521,10 @@ idSIMD_Generic::MinMax ============ */ void VPCALL idSIMD_Generic::MinMax( idVec2 &min, idVec2 &max, const idVec2 *src, const int count ) { - min[0] = min[1] = idMath::INFINITY; max[0] = max[1] = -idMath::INFINITY; + min[0] = min[1] = idMath::INFINITY; + max[0] = max[1] = -idMath::INFINITY; #define OPER(X) const idVec2 &v = src[(X)]; if ( v[0] < min[0] ) { min[0] = v[0]; } if ( v[0] > max[0] ) { max[0] = v[0]; } if ( v[1] < min[1] ) { min[1] = v[1]; } if ( v[1] > max[1] ) { max[1] = v[1]; } - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -525,9 +534,10 @@ idSIMD_Generic::MinMax ============ */ void VPCALL idSIMD_Generic::MinMax( idVec3 &min, idVec3 &max, const idVec3 *src, const int count ) { - min[0] = min[1] = min[2] = idMath::INFINITY; max[0] = max[1] = max[2] = -idMath::INFINITY; + min[0] = min[1] = min[2] = idMath::INFINITY; + max[0] = max[1] = max[2] = -idMath::INFINITY; #define OPER(X) const idVec3 &v = src[(X)]; if ( v[0] < min[0] ) { min[0] = v[0]; } if ( v[0] > max[0] ) { max[0] = v[0]; } if ( v[1] < min[1] ) { min[1] = v[1]; } if ( v[1] > max[1] ) { max[1] = v[1]; } if ( v[2] < min[2] ) { min[2] = v[2]; } if ( v[2] > max[2] ) { max[2] = v[2]; } - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -537,9 +547,10 @@ idSIMD_Generic::MinMax ============ */ void VPCALL idSIMD_Generic::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, const int count ) { - min[0] = min[1] = min[2] = idMath::INFINITY; max[0] = max[1] = max[2] = -idMath::INFINITY; + min[0] = min[1] = min[2] = idMath::INFINITY; + max[0] = max[1] = max[2] = -idMath::INFINITY; #define OPER(X) const idVec3 &v = src[(X)].xyz; if ( v[0] < min[0] ) { min[0] = v[0]; } if ( v[0] > max[0] ) { max[0] = v[0]; } if ( v[1] < min[1] ) { min[1] = v[1]; } if ( v[1] > max[1] ) { max[1] = v[1]; } if ( v[2] < min[2] ) { min[2] = v[2]; } if ( v[2] > max[2] ) { max[2] = v[2]; } - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -549,9 +560,10 @@ idSIMD_Generic::MinMax ============ */ void VPCALL idSIMD_Generic::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, const int *indexes, const int count ) { - min[0] = min[1] = min[2] = idMath::INFINITY; max[0] = max[1] = max[2] = -idMath::INFINITY; + min[0] = min[1] = min[2] = idMath::INFINITY; + max[0] = max[1] = max[2] = -idMath::INFINITY; #define OPER(X) const idVec3 &v = src[indexes[(X)]].xyz; if ( v[0] < min[0] ) { min[0] = v[0]; } if ( v[0] > max[0] ) { max[0] = v[0]; } if ( v[1] < min[1] ) { min[1] = v[1]; } if ( v[1] > max[1] ) { max[1] = v[1]; } if ( v[2] < min[2] ) { min[2] = v[2]; } if ( v[2] > max[2] ) { max[2] = v[2]; } - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -562,7 +574,7 @@ idSIMD_Generic::Clamp */ void VPCALL idSIMD_Generic::Clamp( float *dst, const float *src, const float min, const float max, const int count ) { #define OPER(X) dst[(X)] = src[(X)] < min ? min : src[(X)] > max ? max : src[(X)]; - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -573,7 +585,7 @@ idSIMD_Generic::ClampMin */ void VPCALL idSIMD_Generic::ClampMin( float *dst, const float *src, const float min, const int count ) { #define OPER(X) dst[(X)] = src[(X)] < min ? min : src[(X)]; - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -584,7 +596,7 @@ idSIMD_Generic::ClampMax */ void VPCALL idSIMD_Generic::ClampMax( float *dst, const float *src, const float max, const int count ) { #define OPER(X) dst[(X)] = src[(X)] > max ? max : src[(X)]; - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -621,9 +633,9 @@ idSIMD_Generic::Negate16 ============ */ void VPCALL idSIMD_Generic::Negate16( float *dst, const int count ) { - unsigned int *ptr = reinterpret_cast(dst); + unsigned int *ptr = reinterpret_cast( dst ); #define OPER(X) ptr[(X)] ^= ( 1 << 31 ) // IEEE 32 bits float sign bit - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -634,7 +646,7 @@ idSIMD_Generic::Copy16 */ void VPCALL idSIMD_Generic::Copy16( float *dst, const float *src, const int count ) { #define OPER(X) dst[(X)] = src[(X)] - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -645,7 +657,7 @@ idSIMD_Generic::Add16 */ void VPCALL idSIMD_Generic::Add16( float *dst, const float *src1, const float *src2, const int count ) { #define OPER(X) dst[(X)] = src1[(X)] + src2[(X)] - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -656,7 +668,7 @@ idSIMD_Generic::Sub16 */ void VPCALL idSIMD_Generic::Sub16( float *dst, const float *src1, const float *src2, const int count ) { #define OPER(X) dst[(X)] = src1[(X)] - src2[(X)] - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -667,7 +679,7 @@ idSIMD_Generic::Mul16 */ void VPCALL idSIMD_Generic::Mul16( float *dst, const float *src1, const float constant, const int count ) { #define OPER(X) dst[(X)] = src1[(X)] * constant - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -678,7 +690,7 @@ idSIMD_Generic::AddAssign16 */ void VPCALL idSIMD_Generic::AddAssign16( float *dst, const float *src, const int count ) { #define OPER(X) dst[(X)] += src[(X)] - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -689,7 +701,7 @@ idSIMD_Generic::SubAssign16 */ void VPCALL idSIMD_Generic::SubAssign16( float *dst, const float *src, const int count ) { #define OPER(X) dst[(X)] -= src[(X)] - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -700,7 +712,7 @@ idSIMD_Generic::MulAssign16 */ void VPCALL idSIMD_Generic::MulAssign16( float *dst, const float constant, const int count ) { #define OPER(X) dst[(X)] *= constant - UNROLL1(OPER) + UNROLL1( OPER ) #undef OPER } @@ -721,57 +733,60 @@ void VPCALL idSIMD_Generic::MatX_MultiplyVecX( idVecX &dst, const idMatX &mat, c vPtr = vec.ToFloatPtr(); dstPtr = dst.ToFloatPtr(); numRows = mat.GetNumRows(); - switch( mat.GetNumColumns() ) { - case 1: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] = mPtr[0] * vPtr[0]; - mPtr++; - } - break; - case 2: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] = mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1]; - mPtr += 2; - } - break; - case 3: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] = mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2]; - mPtr += 3; - } - break; - case 4: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] = mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + - mPtr[3] * vPtr[3]; - mPtr += 4; - } - break; - case 5: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] = mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + - mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4]; - mPtr += 5; - } - break; - case 6: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] = mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + - mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4] + mPtr[5] * vPtr[5]; - mPtr += 6; - } - break; - default: - int numColumns = mat.GetNumColumns(); - for ( i = 0; i < numRows; i++ ) { - float sum = mPtr[0] * vPtr[0]; - for ( j = 1; j < numColumns; j++ ) { - sum += mPtr[j] * vPtr[j]; - } - dstPtr[i] = sum; - mPtr += numColumns; + + switch ( mat.GetNumColumns() ) { + case 1: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] = mPtr[0] * vPtr[0]; + mPtr++; + } + break; + case 2: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] = mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1]; + mPtr += 2; + } + break; + case 3: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] = mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2]; + mPtr += 3; + } + break; + case 4: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] = mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + + mPtr[3] * vPtr[3]; + mPtr += 4; + } + break; + case 5: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] = mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + + mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4]; + mPtr += 5; + } + break; + case 6: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] = mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + + mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4] + mPtr[5] * vPtr[5]; + mPtr += 6; + } + break; + default: + int numColumns = mat.GetNumColumns(); + + for ( i = 0; i < numRows; i++ ) { + float sum = mPtr[0] * vPtr[0]; + + for ( j = 1; j < numColumns; j++ ) { + sum += mPtr[j] * vPtr[j]; } - break; + dstPtr[i] = sum; + mPtr += numColumns; + } + break; } } @@ -792,57 +807,60 @@ void VPCALL idSIMD_Generic::MatX_MultiplyAddVecX( idVecX &dst, const idMatX &mat vPtr = vec.ToFloatPtr(); dstPtr = dst.ToFloatPtr(); numRows = mat.GetNumRows(); - switch( mat.GetNumColumns() ) { - case 1: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] += mPtr[0] * vPtr[0]; - mPtr++; - } - break; - case 2: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] += mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1]; - mPtr += 2; - } - break; - case 3: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] += mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2]; - mPtr += 3; - } - break; - case 4: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] += mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + - mPtr[3] * vPtr[3]; - mPtr += 4; - } - break; - case 5: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] += mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + - mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4]; - mPtr += 5; - } - break; - case 6: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] += mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + - mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4] + mPtr[5] * vPtr[5]; - mPtr += 6; - } - break; - default: - int numColumns = mat.GetNumColumns(); - for ( i = 0; i < numRows; i++ ) { - float sum = mPtr[0] * vPtr[0]; - for ( j = 1; j < numColumns; j++ ) { - sum += mPtr[j] * vPtr[j]; - } - dstPtr[i] += sum; - mPtr += numColumns; + + switch ( mat.GetNumColumns() ) { + case 1: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] += mPtr[0] * vPtr[0]; + mPtr++; + } + break; + case 2: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] += mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1]; + mPtr += 2; + } + break; + case 3: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] += mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2]; + mPtr += 3; + } + break; + case 4: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] += mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + + mPtr[3] * vPtr[3]; + mPtr += 4; + } + break; + case 5: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] += mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + + mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4]; + mPtr += 5; + } + break; + case 6: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] += mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + + mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4] + mPtr[5] * vPtr[5]; + mPtr += 6; + } + break; + default: + int numColumns = mat.GetNumColumns(); + + for ( i = 0; i < numRows; i++ ) { + float sum = mPtr[0] * vPtr[0]; + + for ( j = 1; j < numColumns; j++ ) { + sum += mPtr[j] * vPtr[j]; } - break; + dstPtr[i] += sum; + mPtr += numColumns; + } + break; } } @@ -863,57 +881,59 @@ void VPCALL idSIMD_Generic::MatX_MultiplySubVecX( idVecX &dst, const idMatX &mat vPtr = vec.ToFloatPtr(); dstPtr = dst.ToFloatPtr(); numRows = mat.GetNumRows(); - switch( mat.GetNumColumns() ) { - case 1: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] -= mPtr[0] * vPtr[0]; - mPtr++; - } - break; - case 2: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] -= mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1]; - mPtr += 2; - } - break; - case 3: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] -= mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2]; - mPtr += 3; - } - break; - case 4: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] -= mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + - mPtr[3] * vPtr[3]; - mPtr += 4; - } - break; - case 5: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] -= mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + - mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4]; - mPtr += 5; - } - break; - case 6: - for ( i = 0; i < numRows; i++ ) { - dstPtr[i] -= mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + - mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4] + mPtr[5] * vPtr[5]; - mPtr += 6; - } - break; - default: - int numColumns = mat.GetNumColumns(); - for ( i = 0; i < numRows; i++ ) { - float sum = mPtr[0] * vPtr[0]; - for ( j = 1; j < numColumns; j++ ) { - sum += mPtr[j] * vPtr[j]; - } - dstPtr[i] -= sum; - mPtr += numColumns; + + switch ( mat.GetNumColumns() ) { + case 1: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] -= mPtr[0] * vPtr[0]; + mPtr++; + } + break; + case 2: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] -= mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1]; + mPtr += 2; + } + break; + case 3: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] -= mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2]; + mPtr += 3; + } + break; + case 4: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] -= mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + + mPtr[3] * vPtr[3]; + mPtr += 4; + } + break; + case 5: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] -= mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + + mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4]; + mPtr += 5; + } + break; + case 6: + for ( i = 0; i < numRows; i++ ) { + dstPtr[i] -= mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + + mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4] + mPtr[5] * vPtr[5]; + mPtr += 6; + } + break; + default: + int numColumns = mat.GetNumColumns(); + + for ( i = 0; i < numRows; i++ ) { + float sum = mPtr[0] * vPtr[0]; + for ( j = 1; j < numColumns; j++ ) { + sum += mPtr[j] * vPtr[j]; } - break; + dstPtr[i] -= sum; + mPtr += numColumns; + } + break; } } @@ -934,58 +954,61 @@ void VPCALL idSIMD_Generic::MatX_TransposeMultiplyVecX( idVecX &dst, const idMat vPtr = vec.ToFloatPtr(); dstPtr = dst.ToFloatPtr(); numColumns = mat.GetNumColumns(); - switch( mat.GetNumRows() ) { - case 1: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] = *(mPtr) * vPtr[0]; - mPtr++; - } - break; - case 2: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] = *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1]; - mPtr++; - } - break; - case 3: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] = *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2]; - mPtr++; - } - break; - case 4: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] = *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3]; - mPtr++; - } - break; - case 5: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] = *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3] + *(mPtr+4*numColumns) * vPtr[4]; - mPtr++; - } - break; - case 6: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] = *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3] + *(mPtr+4*numColumns) * vPtr[4] + *(mPtr+5*numColumns) * vPtr[5]; - mPtr++; - } - break; - default: - int numRows = mat.GetNumRows(); - for ( i = 0; i < numColumns; i++ ) { - mPtr = mat.ToFloatPtr() + i; - float sum = mPtr[0] * vPtr[0]; - for ( j = 1; j < numRows; j++ ) { - mPtr += numColumns; - sum += mPtr[0] * vPtr[j]; - } - dstPtr[i] = sum; + + switch ( mat.GetNumRows() ) { + case 1: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] = *( mPtr ) * vPtr[0]; + mPtr++; + } + break; + case 2: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] = *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1]; + mPtr++; + } + break; + case 3: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] = *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2]; + mPtr++; + } + break; + case 4: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] = *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3]; + mPtr++; + } + break; + case 5: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] = *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3] + *( mPtr + 4 * numColumns ) * vPtr[4]; + mPtr++; + } + break; + case 6: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] = *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3] + *( mPtr + 4 * numColumns ) * vPtr[4] + *( mPtr + 5 * numColumns ) * vPtr[5]; + mPtr++; + } + break; + default: + int numRows = mat.GetNumRows(); + + for ( i = 0; i < numColumns; i++ ) { + mPtr = mat.ToFloatPtr() + i; + float sum = mPtr[0] * vPtr[0]; + + for ( j = 1; j < numRows; j++ ) { + mPtr += numColumns; + sum += mPtr[0] * vPtr[j]; } - break; + dstPtr[i] = sum; + } + break; } } @@ -1006,58 +1029,61 @@ void VPCALL idSIMD_Generic::MatX_TransposeMultiplyAddVecX( idVecX &dst, const id vPtr = vec.ToFloatPtr(); dstPtr = dst.ToFloatPtr(); numColumns = mat.GetNumColumns(); - switch( mat.GetNumRows() ) { - case 1: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] += *(mPtr) * vPtr[0]; - mPtr++; - } - break; - case 2: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] += *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1]; - mPtr++; - } - break; - case 3: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] += *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2]; - mPtr++; - } - break; - case 4: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] += *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3]; - mPtr++; - } - break; - case 5: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] += *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3] + *(mPtr+4*numColumns) * vPtr[4]; - mPtr++; - } - break; - case 6: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] += *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3] + *(mPtr+4*numColumns) * vPtr[4] + *(mPtr+5*numColumns) * vPtr[5]; - mPtr++; - } - break; - default: - int numRows = mat.GetNumRows(); - for ( i = 0; i < numColumns; i++ ) { - mPtr = mat.ToFloatPtr() + i; - float sum = mPtr[0] * vPtr[0]; - for ( j = 1; j < numRows; j++ ) { - mPtr += numColumns; - sum += mPtr[0] * vPtr[j]; - } - dstPtr[i] += sum; + + switch ( mat.GetNumRows() ) { + case 1: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] += *( mPtr ) * vPtr[0]; + mPtr++; + } + break; + case 2: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] += *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1]; + mPtr++; + } + break; + case 3: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] += *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2]; + mPtr++; + } + break; + case 4: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] += *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3]; + mPtr++; + } + break; + case 5: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] += *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3] + *( mPtr + 4 * numColumns ) * vPtr[4]; + mPtr++; + } + break; + case 6: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] += *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3] + *( mPtr + 4 * numColumns ) * vPtr[4] + *( mPtr + 5 * numColumns ) * vPtr[5]; + mPtr++; + } + break; + default: + int numRows = mat.GetNumRows(); + + for ( i = 0; i < numColumns; i++ ) { + mPtr = mat.ToFloatPtr() + i; + + float sum = mPtr[0] * vPtr[0]; + for ( j = 1; j < numRows; j++ ) { + mPtr += numColumns; + sum += mPtr[0] * vPtr[j]; } - break; + dstPtr[i] += sum; + } + break; } } @@ -1078,58 +1104,61 @@ void VPCALL idSIMD_Generic::MatX_TransposeMultiplySubVecX( idVecX &dst, const id vPtr = vec.ToFloatPtr(); dstPtr = dst.ToFloatPtr(); numColumns = mat.GetNumColumns(); - switch( mat.GetNumRows() ) { - case 1: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] -= *(mPtr) * vPtr[0]; - mPtr++; - } - break; - case 2: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] -= *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1]; - mPtr++; - } - break; - case 3: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] -= *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2]; - mPtr++; - } - break; - case 4: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] -= *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3]; - mPtr++; - } - break; - case 5: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] -= *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3] + *(mPtr+4*numColumns) * vPtr[4]; - mPtr++; - } - break; - case 6: - for ( i = 0; i < numColumns; i++ ) { - dstPtr[i] -= *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3] + *(mPtr+4*numColumns) * vPtr[4] + *(mPtr+5*numColumns) * vPtr[5]; - mPtr++; - } - break; - default: - int numRows = mat.GetNumRows(); - for ( i = 0; i < numColumns; i++ ) { - mPtr = mat.ToFloatPtr() + i; - float sum = mPtr[0] * vPtr[0]; - for ( int j = 1; j < numRows; j++ ) { - mPtr += numColumns; - sum += mPtr[0] * vPtr[j]; - } - dstPtr[i] -= sum; + + switch ( mat.GetNumRows() ) { + case 1: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] -= *( mPtr ) * vPtr[0]; + mPtr++; + } + break; + case 2: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] -= *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1]; + mPtr++; + } + break; + case 3: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] -= *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2]; + mPtr++; + } + break; + case 4: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] -= *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3]; + mPtr++; + } + break; + case 5: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] -= *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3] + *( mPtr + 4 * numColumns ) * vPtr[4]; + mPtr++; + } + break; + case 6: + for ( i = 0; i < numColumns; i++ ) { + dstPtr[i] -= *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3] + *( mPtr + 4 * numColumns ) * vPtr[4] + *( mPtr + 5 * numColumns ) * vPtr[5]; + mPtr++; + } + break; + default: + int numRows = mat.GetNumRows(); + + for ( i = 0; i < numColumns; i++ ) { + mPtr = mat.ToFloatPtr() + i; + + float sum = mPtr[0] * vPtr[0]; + for ( int j = 1; j < numRows; j++ ) { + mPtr += numColumns; + sum += mPtr[0] * vPtr[j]; } - break; + dstPtr[i] -= sum; + } + break; } } @@ -1161,7 +1190,7 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co k = m1.GetNumRows(); l = m2.GetNumColumns(); - switch( m1.GetNumColumns() ) { + switch ( m1.GetNumColumns() ) { case 1: { if ( l == 6 ) { for ( i = 0; i < k; i++ ) { // Nx1 * 1x6 @@ -1174,8 +1203,10 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co } return; } + for ( i = 0; i < k; i++ ) { m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { *dstPtr++ = m1Ptr[0] * m2Ptr[0]; m2Ptr++; @@ -1197,8 +1228,10 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co } return; } + for ( i = 0; i < k; i++ ) { m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l]; m2Ptr++; @@ -1220,10 +1253,12 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co } return; } + for ( i = 0; i < k; i++ ) { m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2*l]; + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2 * l]; m2Ptr++; } m1Ptr += 3; @@ -1243,11 +1278,13 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co } return; } + for ( i = 0; i < k; i++ ) { m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2*l] + - m1Ptr[3] * m2Ptr[3*l]; + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2 * l] + + m1Ptr[3] * m2Ptr[3 * l]; m2Ptr++; } m1Ptr += 4; @@ -1267,11 +1304,13 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co } return; } + for ( i = 0; i < k; i++ ) { m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2*l] + - m1Ptr[3] * m2Ptr[3*l] + m1Ptr[4] * m2Ptr[4*l]; + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2 * l] + + m1Ptr[3] * m2Ptr[3 * l] + m1Ptr[4] * m2Ptr[4 * l]; m2Ptr++; } m1Ptr += 5; @@ -1279,11 +1318,11 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co break; } case 6: { - switch( k ) { + switch ( k ) { case 1: { if ( l == 1 ) { // 1x6 * 6x1 dstPtr[0] = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[1] + m1Ptr[2] * m2Ptr[2] + - m1Ptr[3] * m2Ptr[3] + m1Ptr[4] * m2Ptr[4] + m1Ptr[5] * m2Ptr[5]; + m1Ptr[3] * m2Ptr[3] + m1Ptr[4] * m2Ptr[4] + m1Ptr[5] * m2Ptr[5]; return; } break; @@ -1293,11 +1332,11 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co for ( i = 0; i < 2; i++ ) { for ( j = 0; j < 2; j++ ) { *dstPtr = m1Ptr[0] * m2Ptr[ 0 * 2 + j ] - + m1Ptr[1] * m2Ptr[ 1 * 2 + j ] - + m1Ptr[2] * m2Ptr[ 2 * 2 + j ] - + m1Ptr[3] * m2Ptr[ 3 * 2 + j ] - + m1Ptr[4] * m2Ptr[ 4 * 2 + j ] - + m1Ptr[5] * m2Ptr[ 5 * 2 + j ]; + + m1Ptr[1] * m2Ptr[ 1 * 2 + j ] + + m1Ptr[2] * m2Ptr[ 2 * 2 + j ] + + m1Ptr[3] * m2Ptr[ 3 * 2 + j ] + + m1Ptr[4] * m2Ptr[ 4 * 2 + j ] + + m1Ptr[5] * m2Ptr[ 5 * 2 + j ]; dstPtr++; } m1Ptr += 6; @@ -1311,11 +1350,11 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co for ( i = 0; i < 3; i++ ) { for ( j = 0; j < 3; j++ ) { *dstPtr = m1Ptr[0] * m2Ptr[ 0 * 3 + j ] - + m1Ptr[1] * m2Ptr[ 1 * 3 + j ] - + m1Ptr[2] * m2Ptr[ 2 * 3 + j ] - + m1Ptr[3] * m2Ptr[ 3 * 3 + j ] - + m1Ptr[4] * m2Ptr[ 4 * 3 + j ] - + m1Ptr[5] * m2Ptr[ 5 * 3 + j ]; + + m1Ptr[1] * m2Ptr[ 1 * 3 + j ] + + m1Ptr[2] * m2Ptr[ 2 * 3 + j ] + + m1Ptr[3] * m2Ptr[ 3 * 3 + j ] + + m1Ptr[4] * m2Ptr[ 4 * 3 + j ] + + m1Ptr[5] * m2Ptr[ 5 * 3 + j ]; dstPtr++; } m1Ptr += 6; @@ -1329,11 +1368,11 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co for ( i = 0; i < 4; i++ ) { for ( j = 0; j < 4; j++ ) { *dstPtr = m1Ptr[0] * m2Ptr[ 0 * 4 + j ] - + m1Ptr[1] * m2Ptr[ 1 * 4 + j ] - + m1Ptr[2] * m2Ptr[ 2 * 4 + j ] - + m1Ptr[3] * m2Ptr[ 3 * 4 + j ] - + m1Ptr[4] * m2Ptr[ 4 * 4 + j ] - + m1Ptr[5] * m2Ptr[ 5 * 4 + j ]; + + m1Ptr[1] * m2Ptr[ 1 * 4 + j ] + + m1Ptr[2] * m2Ptr[ 2 * 4 + j ] + + m1Ptr[3] * m2Ptr[ 3 * 4 + j ] + + m1Ptr[4] * m2Ptr[ 4 * 4 + j ] + + m1Ptr[5] * m2Ptr[ 5 * 4 + j ]; dstPtr++; } m1Ptr += 6; @@ -1346,11 +1385,11 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co for ( i = 0; i < 5; i++ ) { for ( j = 0; j < 5; j++ ) { *dstPtr = m1Ptr[0] * m2Ptr[ 0 * 5 + j ] - + m1Ptr[1] * m2Ptr[ 1 * 5 + j ] - + m1Ptr[2] * m2Ptr[ 2 * 5 + j ] - + m1Ptr[3] * m2Ptr[ 3 * 5 + j ] - + m1Ptr[4] * m2Ptr[ 4 * 5 + j ] - + m1Ptr[5] * m2Ptr[ 5 * 5 + j ]; + + m1Ptr[1] * m2Ptr[ 1 * 5 + j ] + + m1Ptr[2] * m2Ptr[ 2 * 5 + j ] + + m1Ptr[3] * m2Ptr[ 3 * 5 + j ] + + m1Ptr[4] * m2Ptr[ 4 * 5 + j ] + + m1Ptr[5] * m2Ptr[ 5 * 5 + j ]; dstPtr++; } m1Ptr += 6; @@ -1359,15 +1398,15 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co } } case 6: { - switch( l ) { + switch ( l ) { case 1: { // 6x6 * 6x1 for ( i = 0; i < 6; i++ ) { *dstPtr = m1Ptr[0] * m2Ptr[ 0 * 1 ] - + m1Ptr[1] * m2Ptr[ 1 * 1 ] - + m1Ptr[2] * m2Ptr[ 2 * 1 ] - + m1Ptr[3] * m2Ptr[ 3 * 1 ] - + m1Ptr[4] * m2Ptr[ 4 * 1 ] - + m1Ptr[5] * m2Ptr[ 5 * 1 ]; + + m1Ptr[1] * m2Ptr[ 1 * 1 ] + + m1Ptr[2] * m2Ptr[ 2 * 1 ] + + m1Ptr[3] * m2Ptr[ 3 * 1 ] + + m1Ptr[4] * m2Ptr[ 4 * 1 ] + + m1Ptr[5] * m2Ptr[ 5 * 1 ]; dstPtr++; m1Ptr += 6; } @@ -1377,11 +1416,11 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co for ( i = 0; i < 6; i++ ) { for ( j = 0; j < 2; j++ ) { *dstPtr = m1Ptr[0] * m2Ptr[ 0 * 2 + j ] - + m1Ptr[1] * m2Ptr[ 1 * 2 + j ] - + m1Ptr[2] * m2Ptr[ 2 * 2 + j ] - + m1Ptr[3] * m2Ptr[ 3 * 2 + j ] - + m1Ptr[4] * m2Ptr[ 4 * 2 + j ] - + m1Ptr[5] * m2Ptr[ 5 * 2 + j ]; + + m1Ptr[1] * m2Ptr[ 1 * 2 + j ] + + m1Ptr[2] * m2Ptr[ 2 * 2 + j ] + + m1Ptr[3] * m2Ptr[ 3 * 2 + j ] + + m1Ptr[4] * m2Ptr[ 4 * 2 + j ] + + m1Ptr[5] * m2Ptr[ 5 * 2 + j ]; dstPtr++; } m1Ptr += 6; @@ -1392,11 +1431,11 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co for ( i = 0; i < 6; i++ ) { for ( j = 0; j < 3; j++ ) { *dstPtr = m1Ptr[0] * m2Ptr[ 0 * 3 + j ] - + m1Ptr[1] * m2Ptr[ 1 * 3 + j ] - + m1Ptr[2] * m2Ptr[ 2 * 3 + j ] - + m1Ptr[3] * m2Ptr[ 3 * 3 + j ] - + m1Ptr[4] * m2Ptr[ 4 * 3 + j ] - + m1Ptr[5] * m2Ptr[ 5 * 3 + j ]; + + m1Ptr[1] * m2Ptr[ 1 * 3 + j ] + + m1Ptr[2] * m2Ptr[ 2 * 3 + j ] + + m1Ptr[3] * m2Ptr[ 3 * 3 + j ] + + m1Ptr[4] * m2Ptr[ 4 * 3 + j ] + + m1Ptr[5] * m2Ptr[ 5 * 3 + j ]; dstPtr++; } m1Ptr += 6; @@ -1407,11 +1446,11 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co for ( i = 0; i < 6; i++ ) { for ( j = 0; j < 4; j++ ) { *dstPtr = m1Ptr[0] * m2Ptr[ 0 * 4 + j ] - + m1Ptr[1] * m2Ptr[ 1 * 4 + j ] - + m1Ptr[2] * m2Ptr[ 2 * 4 + j ] - + m1Ptr[3] * m2Ptr[ 3 * 4 + j ] - + m1Ptr[4] * m2Ptr[ 4 * 4 + j ] - + m1Ptr[5] * m2Ptr[ 5 * 4 + j ]; + + m1Ptr[1] * m2Ptr[ 1 * 4 + j ] + + m1Ptr[2] * m2Ptr[ 2 * 4 + j ] + + m1Ptr[3] * m2Ptr[ 3 * 4 + j ] + + m1Ptr[4] * m2Ptr[ 4 * 4 + j ] + + m1Ptr[5] * m2Ptr[ 5 * 4 + j ]; dstPtr++; } m1Ptr += 6; @@ -1422,11 +1461,11 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co for ( i = 0; i < 6; i++ ) { for ( j = 0; j < 5; j++ ) { *dstPtr = m1Ptr[0] * m2Ptr[ 0 * 5 + j ] - + m1Ptr[1] * m2Ptr[ 1 * 5 + j ] - + m1Ptr[2] * m2Ptr[ 2 * 5 + j ] - + m1Ptr[3] * m2Ptr[ 3 * 5 + j ] - + m1Ptr[4] * m2Ptr[ 4 * 5 + j ] - + m1Ptr[5] * m2Ptr[ 5 * 5 + j ]; + + m1Ptr[1] * m2Ptr[ 1 * 5 + j ] + + m1Ptr[2] * m2Ptr[ 2 * 5 + j ] + + m1Ptr[3] * m2Ptr[ 3 * 5 + j ] + + m1Ptr[4] * m2Ptr[ 4 * 5 + j ] + + m1Ptr[5] * m2Ptr[ 5 * 5 + j ]; dstPtr++; } m1Ptr += 6; @@ -1437,11 +1476,11 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co for ( i = 0; i < 6; i++ ) { for ( j = 0; j < 6; j++ ) { *dstPtr = m1Ptr[0] * m2Ptr[ 0 * 6 + j ] - + m1Ptr[1] * m2Ptr[ 1 * 6 + j ] - + m1Ptr[2] * m2Ptr[ 2 * 6 + j ] - + m1Ptr[3] * m2Ptr[ 3 * 6 + j ] - + m1Ptr[4] * m2Ptr[ 4 * 6 + j ] - + m1Ptr[5] * m2Ptr[ 5 * 6 + j ]; + + m1Ptr[1] * m2Ptr[ 1 * 6 + j ] + + m1Ptr[2] * m2Ptr[ 2 * 6 + j ] + + m1Ptr[3] * m2Ptr[ 3 * 6 + j ] + + m1Ptr[4] * m2Ptr[ 4 * 6 + j ] + + m1Ptr[5] * m2Ptr[ 5 * 6 + j ]; dstPtr++; } m1Ptr += 6; @@ -1451,11 +1490,13 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co } } } + for ( i = 0; i < k; i++ ) { m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2*l] + - m1Ptr[3] * m2Ptr[3*l] + m1Ptr[4] * m2Ptr[4*l] + m1Ptr[5] * m2Ptr[5*l]; + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2 * l] + + m1Ptr[3] * m2Ptr[3 * l] + m1Ptr[4] * m2Ptr[4 * l] + m1Ptr[5] * m2Ptr[5 * l]; m2Ptr++; } m1Ptr += 6; @@ -1467,6 +1508,7 @@ void VPCALL idSIMD_Generic::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, co for ( j = 0; j < l; j++ ) { m2Ptr = m2.ToFloatPtr() + j; sum = m1Ptr[0] * m2Ptr[0]; + for ( n = 1; n < m1.GetNumColumns(); n++ ) { m2Ptr += l; sum += m1Ptr[n] * m2Ptr[0]; @@ -1506,220 +1548,240 @@ void VPCALL idSIMD_Generic::MatX_TransposeMultiplyMatX( idMatX &dst, const idMat k = m1.GetNumColumns(); l = m2.GetNumColumns(); - switch( m1.GetNumRows() ) { - case 1: - if ( k == 6 && l == 1 ) { // 1x6 * 1x1 - for ( i = 0; i < 6; i++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0]; - m1Ptr++; - } - return; + switch ( m1.GetNumRows() ) { + case 1: + if ( k == 6 && l == 1 ) { // 1x6 * 1x1 + for ( i = 0; i < 6; i++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0]; + m1Ptr++; + } + return; + } + + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0]; + m2Ptr++; + } + m1Ptr++; + } + break; + case 2: + if ( k == 6 && l == 2 ) { // 2x6 * 2x2 + for ( i = 0; i < 6; i++ ) { + *dstPtr++ = m1Ptr[0 * 6] * m2Ptr[0 * 2 + 0] + m1Ptr[1 * 6] * m2Ptr[1 * 2 + 0]; + *dstPtr++ = m1Ptr[0 * 6] * m2Ptr[0 * 2 + 1] + m1Ptr[1 * 6] * m2Ptr[1 * 2 + 1]; + m1Ptr++; + } + return; + } + + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l]; + m2Ptr++; + } + m1Ptr++; + } + break; + case 3: + if ( k == 6 && l == 3 ) { // 3x6 * 3x3 + for ( i = 0; i < 6; i++ ) { + *dstPtr++ = m1Ptr[0 * 6] * m2Ptr[0 * 3 + 0] + m1Ptr[1 * 6] * m2Ptr[1 * 3 + 0] + m1Ptr[2 * 6] * m2Ptr[2 * 3 + 0]; + *dstPtr++ = m1Ptr[0 * 6] * m2Ptr[0 * 3 + 1] + m1Ptr[1 * 6] * m2Ptr[1 * 3 + 1] + m1Ptr[2 * 6] * m2Ptr[2 * 3 + 1]; + *dstPtr++ = m1Ptr[0 * 6] * m2Ptr[0 * 3 + 2] + m1Ptr[1 * 6] * m2Ptr[1 * 3 + 2] + m1Ptr[2 * 6] * m2Ptr[2 * 3 + 2]; + m1Ptr++; + } + return; + } + + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2 * k] * m2Ptr[2 * l]; + m2Ptr++; + } + m1Ptr++; + } + break; + case 4: + if ( k == 6 && l == 4 ) { // 4x6 * 4x4 + for ( i = 0; i < 6; i++ ) { + *dstPtr++ = m1Ptr[0 * 6] * m2Ptr[0 * 4 + 0] + m1Ptr[1 * 6] * m2Ptr[1 * 4 + 0] + m1Ptr[2 * 6] * m2Ptr[2 * 4 + 0] + m1Ptr[3 * 6] * m2Ptr[3 * 4 + 0]; + *dstPtr++ = m1Ptr[0 * 6] * m2Ptr[0 * 4 + 1] + m1Ptr[1 * 6] * m2Ptr[1 * 4 + 1] + m1Ptr[2 * 6] * m2Ptr[2 * 4 + 1] + m1Ptr[3 * 6] * m2Ptr[3 * 4 + 1]; + *dstPtr++ = m1Ptr[0 * 6] * m2Ptr[0 * 4 + 2] + m1Ptr[1 * 6] * m2Ptr[1 * 4 + 2] + m1Ptr[2 * 6] * m2Ptr[2 * 4 + 2] + m1Ptr[3 * 6] * m2Ptr[3 * 4 + 2]; + *dstPtr++ = m1Ptr[0 * 6] * m2Ptr[0 * 4 + 3] + m1Ptr[1 * 6] * m2Ptr[1 * 4 + 3] + m1Ptr[2 * 6] * m2Ptr[2 * 4 + 3] + m1Ptr[3 * 6] * m2Ptr[3 * 4 + 3]; + m1Ptr++; + } + return; + } + + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2 * k] * m2Ptr[2 * l] + + m1Ptr[3 * k] * m2Ptr[3 * l]; + m2Ptr++; + } + m1Ptr++; + } + break; + case 5: + if ( k == 6 && l == 5 ) { // 5x6 * 5x5 + for ( i = 0; i < 6; i++ ) { + *dstPtr++ = m1Ptr[0 * 6] * m2Ptr[0 * 5 + 0] + m1Ptr[1 * 6] * m2Ptr[1 * 5 + 0] + m1Ptr[2 * 6] * m2Ptr[2 * 5 + 0] + m1Ptr[3 * 6] * m2Ptr[3 * 5 + 0] + m1Ptr[4 * 6] * m2Ptr[4 * 5 + 0]; + *dstPtr++ = m1Ptr[0 * 6] * m2Ptr[0 * 5 + 1] + m1Ptr[1 * 6] * m2Ptr[1 * 5 + 1] + m1Ptr[2 * 6] * m2Ptr[2 * 5 + 1] + m1Ptr[3 * 6] * m2Ptr[3 * 5 + 1] + m1Ptr[4 * 6] * m2Ptr[4 * 5 + 1]; + *dstPtr++ = m1Ptr[0 * 6] * m2Ptr[0 * 5 + 2] + m1Ptr[1 * 6] * m2Ptr[1 * 5 + 2] + m1Ptr[2 * 6] * m2Ptr[2 * 5 + 2] + m1Ptr[3 * 6] * m2Ptr[3 * 5 + 2] + m1Ptr[4 * 6] * m2Ptr[4 * 5 + 2]; + *dstPtr++ = m1Ptr[0 * 6] * m2Ptr[0 * 5 + 3] + m1Ptr[1 * 6] * m2Ptr[1 * 5 + 3] + m1Ptr[2 * 6] * m2Ptr[2 * 5 + 3] + m1Ptr[3 * 6] * m2Ptr[3 * 5 + 3] + m1Ptr[4 * 6] * m2Ptr[4 * 5 + 3]; + *dstPtr++ = m1Ptr[0 * 6] * m2Ptr[0 * 5 + 4] + m1Ptr[1 * 6] * m2Ptr[1 * 5 + 4] + m1Ptr[2 * 6] * m2Ptr[2 * 5 + 4] + m1Ptr[3 * 6] * m2Ptr[3 * 5 + 4] + m1Ptr[4 * 6] * m2Ptr[4 * 5 + 4]; + m1Ptr++; + } + return; + } + + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2 * k] * m2Ptr[2 * l] + + m1Ptr[3 * k] * m2Ptr[3 * l] + m1Ptr[4 * k] * m2Ptr[4 * l]; + m2Ptr++; } - for ( i = 0; i < k; i++ ) { + m1Ptr++; + } + break; + case 6: + if ( l == 6 ) { + switch ( k ) { + case 1: // 6x1 * 6x6 m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0]; + + for ( j = 0; j < 6; j++ ) { + *dstPtr++ = m1Ptr[0 * 1] * m2Ptr[0 * 6] + + m1Ptr[1 * 1] * m2Ptr[1 * 6] + + m1Ptr[2 * 1] * m2Ptr[2 * 6] + + m1Ptr[3 * 1] * m2Ptr[3 * 6] + + m1Ptr[4 * 1] * m2Ptr[4 * 6] + + m1Ptr[5 * 1] * m2Ptr[5 * 6]; m2Ptr++; } - m1Ptr++; - } - break; - case 2: - if ( k == 6 && l == 2 ) { // 2x6 * 2x2 - for ( i = 0; i < 6; i++ ) { - *dstPtr++ = m1Ptr[0*6] * m2Ptr[0*2+0] + m1Ptr[1*6] * m2Ptr[1*2+0]; - *dstPtr++ = m1Ptr[0*6] * m2Ptr[0*2+1] + m1Ptr[1*6] * m2Ptr[1*2+1]; + return; + case 2: // 6x2 * 6x6 + for ( i = 0; i < 2; i++ ) { + m2Ptr = m2.ToFloatPtr(); + + for ( j = 0; j < 6; j++ ) { + *dstPtr++ = m1Ptr[0 * 2] * m2Ptr[0 * 6] + + m1Ptr[1 * 2] * m2Ptr[1 * 6] + + m1Ptr[2 * 2] * m2Ptr[2 * 6] + + m1Ptr[3 * 2] * m2Ptr[3 * 6] + + m1Ptr[4 * 2] * m2Ptr[4 * 6] + + m1Ptr[5 * 2] * m2Ptr[5 * 6]; + m2Ptr++; + } m1Ptr++; } return; - } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l]; - m2Ptr++; - } - m1Ptr++; - } - break; - case 3: - if ( k == 6 && l == 3 ) { // 3x6 * 3x3 - for ( i = 0; i < 6; i++ ) { - *dstPtr++ = m1Ptr[0*6] * m2Ptr[0*3+0] + m1Ptr[1*6] * m2Ptr[1*3+0] + m1Ptr[2*6] * m2Ptr[2*3+0]; - *dstPtr++ = m1Ptr[0*6] * m2Ptr[0*3+1] + m1Ptr[1*6] * m2Ptr[1*3+1] + m1Ptr[2*6] * m2Ptr[2*3+1]; - *dstPtr++ = m1Ptr[0*6] * m2Ptr[0*3+2] + m1Ptr[1*6] * m2Ptr[1*3+2] + m1Ptr[2*6] * m2Ptr[2*3+2]; + case 3: // 6x3 * 6x6 + for ( i = 0; i < 3; i++ ) { + m2Ptr = m2.ToFloatPtr(); + + for ( j = 0; j < 6; j++ ) { + *dstPtr++ = m1Ptr[0 * 3] * m2Ptr[0 * 6] + + m1Ptr[1 * 3] * m2Ptr[1 * 6] + + m1Ptr[2 * 3] * m2Ptr[2 * 6] + + m1Ptr[3 * 3] * m2Ptr[3 * 6] + + m1Ptr[4 * 3] * m2Ptr[4 * 6] + + m1Ptr[5 * 3] * m2Ptr[5 * 6]; + m2Ptr++; + } m1Ptr++; } return; - } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2*k] * m2Ptr[2*l]; - m2Ptr++; - } - m1Ptr++; - } - break; - case 4: - if ( k == 6 && l == 4 ) { // 4x6 * 4x4 - for ( i = 0; i < 6; i++ ) { - *dstPtr++ = m1Ptr[0*6] * m2Ptr[0*4+0] + m1Ptr[1*6] * m2Ptr[1*4+0] + m1Ptr[2*6] * m2Ptr[2*4+0] + m1Ptr[3*6] * m2Ptr[3*4+0]; - *dstPtr++ = m1Ptr[0*6] * m2Ptr[0*4+1] + m1Ptr[1*6] * m2Ptr[1*4+1] + m1Ptr[2*6] * m2Ptr[2*4+1] + m1Ptr[3*6] * m2Ptr[3*4+1]; - *dstPtr++ = m1Ptr[0*6] * m2Ptr[0*4+2] + m1Ptr[1*6] * m2Ptr[1*4+2] + m1Ptr[2*6] * m2Ptr[2*4+2] + m1Ptr[3*6] * m2Ptr[3*4+2]; - *dstPtr++ = m1Ptr[0*6] * m2Ptr[0*4+3] + m1Ptr[1*6] * m2Ptr[1*4+3] + m1Ptr[2*6] * m2Ptr[2*4+3] + m1Ptr[3*6] * m2Ptr[3*4+3]; + case 4: // 6x4 * 6x6 + for ( i = 0; i < 4; i++ ) { + m2Ptr = m2.ToFloatPtr(); + + for ( j = 0; j < 6; j++ ) { + *dstPtr++ = m1Ptr[0 * 4] * m2Ptr[0 * 6] + + m1Ptr[1 * 4] * m2Ptr[1 * 6] + + m1Ptr[2 * 4] * m2Ptr[2 * 6] + + m1Ptr[3 * 4] * m2Ptr[3 * 6] + + m1Ptr[4 * 4] * m2Ptr[4 * 6] + + m1Ptr[5 * 4] * m2Ptr[5 * 6]; + m2Ptr++; + } m1Ptr++; } return; - } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2*k] * m2Ptr[2*l] + - m1Ptr[3*k] * m2Ptr[3*l]; - m2Ptr++; + case 5: // 6x5 * 6x6 + for ( i = 0; i < 5; i++ ) { + m2Ptr = m2.ToFloatPtr(); + + for ( j = 0; j < 6; j++ ) { + *dstPtr++ = m1Ptr[0 * 5] * m2Ptr[0 * 6] + + m1Ptr[1 * 5] * m2Ptr[1 * 6] + + m1Ptr[2 * 5] * m2Ptr[2 * 6] + + m1Ptr[3 * 5] * m2Ptr[3 * 6] + + m1Ptr[4 * 5] * m2Ptr[4 * 6] + + m1Ptr[5 * 5] * m2Ptr[5 * 6]; + m2Ptr++; + } + m1Ptr++; } - m1Ptr++; - } - break; - case 5: - if ( k == 6 && l == 5 ) { // 5x6 * 5x5 + return; + case 6: // 6x6 * 6x6 for ( i = 0; i < 6; i++ ) { - *dstPtr++ = m1Ptr[0*6] * m2Ptr[0*5+0] + m1Ptr[1*6] * m2Ptr[1*5+0] + m1Ptr[2*6] * m2Ptr[2*5+0] + m1Ptr[3*6] * m2Ptr[3*5+0] + m1Ptr[4*6] * m2Ptr[4*5+0]; - *dstPtr++ = m1Ptr[0*6] * m2Ptr[0*5+1] + m1Ptr[1*6] * m2Ptr[1*5+1] + m1Ptr[2*6] * m2Ptr[2*5+1] + m1Ptr[3*6] * m2Ptr[3*5+1] + m1Ptr[4*6] * m2Ptr[4*5+1]; - *dstPtr++ = m1Ptr[0*6] * m2Ptr[0*5+2] + m1Ptr[1*6] * m2Ptr[1*5+2] + m1Ptr[2*6] * m2Ptr[2*5+2] + m1Ptr[3*6] * m2Ptr[3*5+2] + m1Ptr[4*6] * m2Ptr[4*5+2]; - *dstPtr++ = m1Ptr[0*6] * m2Ptr[0*5+3] + m1Ptr[1*6] * m2Ptr[1*5+3] + m1Ptr[2*6] * m2Ptr[2*5+3] + m1Ptr[3*6] * m2Ptr[3*5+3] + m1Ptr[4*6] * m2Ptr[4*5+3]; - *dstPtr++ = m1Ptr[0*6] * m2Ptr[0*5+4] + m1Ptr[1*6] * m2Ptr[1*5+4] + m1Ptr[2*6] * m2Ptr[2*5+4] + m1Ptr[3*6] * m2Ptr[3*5+4] + m1Ptr[4*6] * m2Ptr[4*5+4]; + m2Ptr = m2.ToFloatPtr(); + + for ( j = 0; j < 6; j++ ) { + *dstPtr++ = m1Ptr[0 * 6] * m2Ptr[0 * 6] + + m1Ptr[1 * 6] * m2Ptr[1 * 6] + + m1Ptr[2 * 6] * m2Ptr[2 * 6] + + m1Ptr[3 * 6] * m2Ptr[3 * 6] + + m1Ptr[4 * 6] * m2Ptr[4 * 6] + + m1Ptr[5 * 6] * m2Ptr[5 * 6]; + m2Ptr++; + } m1Ptr++; } return; } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2*k] * m2Ptr[2*l] + - m1Ptr[3*k] * m2Ptr[3*l] + m1Ptr[4*k] * m2Ptr[4*l]; - m2Ptr++; - } - m1Ptr++; - } - break; - case 6: - if ( l == 6 ) { - switch( k ) { - case 1: // 6x1 * 6x6 - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < 6; j++ ) { - *dstPtr++ = m1Ptr[0*1] * m2Ptr[0*6] + - m1Ptr[1*1] * m2Ptr[1*6] + - m1Ptr[2*1] * m2Ptr[2*6] + - m1Ptr[3*1] * m2Ptr[3*6] + - m1Ptr[4*1] * m2Ptr[4*6] + - m1Ptr[5*1] * m2Ptr[5*6]; - m2Ptr++; - } - return; - case 2: // 6x2 * 6x6 - for ( i = 0; i < 2; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < 6; j++ ) { - *dstPtr++ = m1Ptr[0*2] * m2Ptr[0*6] + - m1Ptr[1*2] * m2Ptr[1*6] + - m1Ptr[2*2] * m2Ptr[2*6] + - m1Ptr[3*2] * m2Ptr[3*6] + - m1Ptr[4*2] * m2Ptr[4*6] + - m1Ptr[5*2] * m2Ptr[5*6]; - m2Ptr++; - } - m1Ptr++; - } - return; - case 3: // 6x3 * 6x6 - for ( i = 0; i < 3; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < 6; j++ ) { - *dstPtr++ = m1Ptr[0*3] * m2Ptr[0*6] + - m1Ptr[1*3] * m2Ptr[1*6] + - m1Ptr[2*3] * m2Ptr[2*6] + - m1Ptr[3*3] * m2Ptr[3*6] + - m1Ptr[4*3] * m2Ptr[4*6] + - m1Ptr[5*3] * m2Ptr[5*6]; - m2Ptr++; - } - m1Ptr++; - } - return; - case 4: // 6x4 * 6x6 - for ( i = 0; i < 4; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < 6; j++ ) { - *dstPtr++ = m1Ptr[0*4] * m2Ptr[0*6] + - m1Ptr[1*4] * m2Ptr[1*6] + - m1Ptr[2*4] * m2Ptr[2*6] + - m1Ptr[3*4] * m2Ptr[3*6] + - m1Ptr[4*4] * m2Ptr[4*6] + - m1Ptr[5*4] * m2Ptr[5*6]; - m2Ptr++; - } - m1Ptr++; - } - return; - case 5: // 6x5 * 6x6 - for ( i = 0; i < 5; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < 6; j++ ) { - *dstPtr++ = m1Ptr[0*5] * m2Ptr[0*6] + - m1Ptr[1*5] * m2Ptr[1*6] + - m1Ptr[2*5] * m2Ptr[2*6] + - m1Ptr[3*5] * m2Ptr[3*6] + - m1Ptr[4*5] * m2Ptr[4*6] + - m1Ptr[5*5] * m2Ptr[5*6]; - m2Ptr++; - } - m1Ptr++; - } - return; - case 6: // 6x6 * 6x6 - for ( i = 0; i < 6; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < 6; j++ ) { - *dstPtr++ = m1Ptr[0*6] * m2Ptr[0*6] + - m1Ptr[1*6] * m2Ptr[1*6] + - m1Ptr[2*6] * m2Ptr[2*6] + - m1Ptr[3*6] * m2Ptr[3*6] + - m1Ptr[4*6] * m2Ptr[4*6] + - m1Ptr[5*6] * m2Ptr[5*6]; - m2Ptr++; - } - m1Ptr++; - } - return; - } - } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2*k] * m2Ptr[2*l] + - m1Ptr[3*k] * m2Ptr[3*l] + m1Ptr[4*k] * m2Ptr[4*l] + m1Ptr[5*k] * m2Ptr[5*l]; - m2Ptr++; - } - m1Ptr++; + } + + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2 * k] * m2Ptr[2 * l] + + m1Ptr[3 * k] * m2Ptr[3 * l] + m1Ptr[4 * k] * m2Ptr[4 * l] + m1Ptr[5 * k] * m2Ptr[5 * l]; + m2Ptr++; } - break; - default: - for ( i = 0; i < k; i++ ) { - for ( j = 0; j < l; j++ ) { - m1Ptr = m1.ToFloatPtr() + i; - m2Ptr = m2.ToFloatPtr() + j; - sum = m1Ptr[0] * m2Ptr[0]; - for ( n = 1; n < m1.GetNumRows(); n++ ) { - m1Ptr += k; - m2Ptr += l; - sum += m1Ptr[0] * m2Ptr[0]; - } - *dstPtr++ = sum; + m1Ptr++; + } + break; + default: + for ( i = 0; i < k; i++ ) { + for ( j = 0; j < l; j++ ) { + m1Ptr = m1.ToFloatPtr() + i; + m2Ptr = m2.ToFloatPtr() + j; + + sum = m1Ptr[0] * m2Ptr[0]; + + for ( n = 1; n < m1.GetNumRows(); n++ ) { + m1Ptr += k; + m2Ptr += l; + sum += m1Ptr[0] * m2Ptr[0]; } + *dstPtr++ = sum; } + } break; } } @@ -1736,101 +1798,140 @@ idSIMD_Generic::MatX_LowerTriangularSolve */ void VPCALL idSIMD_Generic::MatX_LowerTriangularSolve( const idMatX &L, float *x, const float *b, const int n, int skip ) { #if 1 - int nc; const float *lptr; if ( skip >= n ) { return; } - lptr = L.ToFloatPtr(); nc = L.GetNumColumns(); // unrolled cases for n < 8 if ( n < 8 ) { - #define NSKIP( n, s ) ((n<<3)|(s&7)) - switch( NSKIP( n, skip ) ) { - case NSKIP( 1, 0 ): x[0] = b[0]; - return; - case NSKIP( 2, 0 ): x[0] = b[0]; - case NSKIP( 2, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - return; - case NSKIP( 3, 0 ): x[0] = b[0]; - case NSKIP( 3, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - case NSKIP( 3, 2 ): x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - return; - case NSKIP( 4, 0 ): x[0] = b[0]; - case NSKIP( 4, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - case NSKIP( 4, 2 ): x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - case NSKIP( 4, 3 ): x[3] = b[3] - lptr[3*nc+0] * x[0] - lptr[3*nc+1] * x[1] - lptr[3*nc+2] * x[2]; - return; - case NSKIP( 5, 0 ): x[0] = b[0]; - case NSKIP( 5, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - case NSKIP( 5, 2 ): x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - case NSKIP( 5, 3 ): x[3] = b[3] - lptr[3*nc+0] * x[0] - lptr[3*nc+1] * x[1] - lptr[3*nc+2] * x[2]; - case NSKIP( 5, 4 ): x[4] = b[4] - lptr[4*nc+0] * x[0] - lptr[4*nc+1] * x[1] - lptr[4*nc+2] * x[2] - lptr[4*nc+3] * x[3]; - return; - case NSKIP( 6, 0 ): x[0] = b[0]; - case NSKIP( 6, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - case NSKIP( 6, 2 ): x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - case NSKIP( 6, 3 ): x[3] = b[3] - lptr[3*nc+0] * x[0] - lptr[3*nc+1] * x[1] - lptr[3*nc+2] * x[2]; - case NSKIP( 6, 4 ): x[4] = b[4] - lptr[4*nc+0] * x[0] - lptr[4*nc+1] * x[1] - lptr[4*nc+2] * x[2] - lptr[4*nc+3] * x[3]; - case NSKIP( 6, 5 ): x[5] = b[5] - lptr[5*nc+0] * x[0] - lptr[5*nc+1] * x[1] - lptr[5*nc+2] * x[2] - lptr[5*nc+3] * x[3] - lptr[5*nc+4] * x[4]; - return; - case NSKIP( 7, 0 ): x[0] = b[0]; - case NSKIP( 7, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - case NSKIP( 7, 2 ): x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - case NSKIP( 7, 3 ): x[3] = b[3] - lptr[3*nc+0] * x[0] - lptr[3*nc+1] * x[1] - lptr[3*nc+2] * x[2]; - case NSKIP( 7, 4 ): x[4] = b[4] - lptr[4*nc+0] * x[0] - lptr[4*nc+1] * x[1] - lptr[4*nc+2] * x[2] - lptr[4*nc+3] * x[3]; - case NSKIP( 7, 5 ): x[5] = b[5] - lptr[5*nc+0] * x[0] - lptr[5*nc+1] * x[1] - lptr[5*nc+2] * x[2] - lptr[5*nc+3] * x[3] - lptr[5*nc+4] * x[4]; - case NSKIP( 7, 6 ): x[6] = b[6] - lptr[6*nc+0] * x[0] - lptr[6*nc+1] * x[1] - lptr[6*nc+2] * x[2] - lptr[6*nc+3] * x[3] - lptr[6*nc+4] * x[4] - lptr[6*nc+5] * x[5]; - return; +#define NSKIP( n, s ) ((n<<3)|(s&7)) + switch ( NSKIP( n, skip ) ) { + case NSKIP( 1, 0 ): + x[0] = b[0]; + return; + case NSKIP( 2, 0 ): + x[0] = b[0]; + case NSKIP( 2, 1 ): + x[1] = b[1] - lptr[1 * nc + 0] * x[0]; + return; + case NSKIP( 3, 0 ): + x[0] = b[0]; + case NSKIP( 3, 1 ): + x[1] = b[1] - lptr[1 * nc + 0] * x[0]; + case NSKIP( 3, 2 ): + x[2] = b[2] - lptr[2 * nc + 0] * x[0] - lptr[2 * nc + 1] * x[1]; + return; + case NSKIP( 4, 0 ): + x[0] = b[0]; + case NSKIP( 4, 1 ): + x[1] = b[1] - lptr[1 * nc + 0] * x[0]; + case NSKIP( 4, 2 ): + x[2] = b[2] - lptr[2 * nc + 0] * x[0] - lptr[2 * nc + 1] * x[1]; + case NSKIP( 4, 3 ): + x[3] = b[3] - lptr[3 * nc + 0] * x[0] - lptr[3 * nc + 1] * x[1] - lptr[3 * nc + 2] * x[2]; + return; + case NSKIP( 5, 0 ): + x[0] = b[0]; + case NSKIP( 5, 1 ): + x[1] = b[1] - lptr[1 * nc + 0] * x[0]; + case NSKIP( 5, 2 ): + x[2] = b[2] - lptr[2 * nc + 0] * x[0] - lptr[2 * nc + 1] * x[1]; + case NSKIP( 5, 3 ): + x[3] = b[3] - lptr[3 * nc + 0] * x[0] - lptr[3 * nc + 1] * x[1] - lptr[3 * nc + 2] * x[2]; + case NSKIP( 5, 4 ): + x[4] = b[4] - lptr[4 * nc + 0] * x[0] - lptr[4 * nc + 1] * x[1] - lptr[4 * nc + 2] * x[2] - lptr[4 * nc + 3] * x[3]; + return; + case NSKIP( 6, 0 ): + x[0] = b[0]; + case NSKIP( 6, 1 ): + x[1] = b[1] - lptr[1 * nc + 0] * x[0]; + case NSKIP( 6, 2 ): + x[2] = b[2] - lptr[2 * nc + 0] * x[0] - lptr[2 * nc + 1] * x[1]; + case NSKIP( 6, 3 ): + x[3] = b[3] - lptr[3 * nc + 0] * x[0] - lptr[3 * nc + 1] * x[1] - lptr[3 * nc + 2] * x[2]; + case NSKIP( 6, 4 ): + x[4] = b[4] - lptr[4 * nc + 0] * x[0] - lptr[4 * nc + 1] * x[1] - lptr[4 * nc + 2] * x[2] - lptr[4 * nc + 3] * x[3]; + case NSKIP( 6, 5 ): + x[5] = b[5] - lptr[5 * nc + 0] * x[0] - lptr[5 * nc + 1] * x[1] - lptr[5 * nc + 2] * x[2] - lptr[5 * nc + 3] * x[3] - lptr[5 * nc + 4] * x[4]; + return; + case NSKIP( 7, 0 ): + x[0] = b[0]; + case NSKIP( 7, 1 ): + x[1] = b[1] - lptr[1 * nc + 0] * x[0]; + case NSKIP( 7, 2 ): + x[2] = b[2] - lptr[2 * nc + 0] * x[0] - lptr[2 * nc + 1] * x[1]; + case NSKIP( 7, 3 ): + x[3] = b[3] - lptr[3 * nc + 0] * x[0] - lptr[3 * nc + 1] * x[1] - lptr[3 * nc + 2] * x[2]; + case NSKIP( 7, 4 ): + x[4] = b[4] - lptr[4 * nc + 0] * x[0] - lptr[4 * nc + 1] * x[1] - lptr[4 * nc + 2] * x[2] - lptr[4 * nc + 3] * x[3]; + case NSKIP( 7, 5 ): + x[5] = b[5] - lptr[5 * nc + 0] * x[0] - lptr[5 * nc + 1] * x[1] - lptr[5 * nc + 2] * x[2] - lptr[5 * nc + 3] * x[3] - lptr[5 * nc + 4] * x[4]; + case NSKIP( 7, 6 ): + x[6] = b[6] - lptr[6 * nc + 0] * x[0] - lptr[6 * nc + 1] * x[1] - lptr[6 * nc + 2] * x[2] - lptr[6 * nc + 3] * x[3] - lptr[6 * nc + 4] * x[4] - lptr[6 * nc + 5] * x[5]; + return; } return; } // process first 4 rows - switch( skip ) { - case 0: x[0] = b[0]; - case 1: x[1] = b[1] - lptr[1*nc+0] * x[0]; - case 2: x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - case 3: x[3] = b[3] - lptr[3*nc+0] * x[0] - lptr[3*nc+1] * x[1] - lptr[3*nc+2] * x[2]; - skip = 4; + switch ( skip ) { + case 0: + x[0] = b[0]; + case 1: + x[1] = b[1] - lptr[1 * nc + 0] * x[0]; + case 2: + x[2] = b[2] - lptr[2 * nc + 0] * x[0] - lptr[2 * nc + 1] * x[1]; + case 3: + x[3] = b[3] - lptr[3 * nc + 0] * x[0] - lptr[3 * nc + 1] * x[1] - lptr[3 * nc + 2] * x[2]; + skip = 4; } - lptr = L[skip]; int i, j; double s0, s1, s2, s3; - for ( i = skip; i < n; i++ ) { s0 = lptr[0] * x[0]; s1 = lptr[1] * x[1]; s2 = lptr[2] * x[2]; s3 = lptr[3] * x[3]; - for ( j = 4; j < i-7; j += 8 ) { - s0 += lptr[j+0] * x[j+0]; - s1 += lptr[j+1] * x[j+1]; - s2 += lptr[j+2] * x[j+2]; - s3 += lptr[j+3] * x[j+3]; - s0 += lptr[j+4] * x[j+4]; - s1 += lptr[j+5] * x[j+5]; - s2 += lptr[j+6] * x[j+6]; - s3 += lptr[j+7] * x[j+7]; - } - switch( i - j ) { + + for ( j = 4; j < i - 7; j += 8 ) { + s0 += lptr[j + 0] * x[j + 0]; + s1 += lptr[j + 1] * x[j + 1]; + s2 += lptr[j + 2] * x[j + 2]; + s3 += lptr[j + 3] * x[j + 3]; + s0 += lptr[j + 4] * x[j + 4]; + s1 += lptr[j + 5] * x[j + 5]; + s2 += lptr[j + 6] * x[j + 6]; + s3 += lptr[j + 7] * x[j + 7]; + } + + switch ( i - j ) { NODEFAULT; - case 7: s0 += lptr[j+6] * x[j+6]; - case 6: s1 += lptr[j+5] * x[j+5]; - case 5: s2 += lptr[j+4] * x[j+4]; - case 4: s3 += lptr[j+3] * x[j+3]; - case 3: s0 += lptr[j+2] * x[j+2]; - case 2: s1 += lptr[j+1] * x[j+1]; - case 1: s2 += lptr[j+0] * x[j+0]; - case 0: break; + case 7: + s0 += lptr[j + 6] * x[j + 6]; + case 6: + s1 += lptr[j + 5] * x[j + 5]; + case 5: + s2 += lptr[j + 4] * x[j + 4]; + case 4: + s3 += lptr[j + 3] * x[j + 3]; + case 3: + s0 += lptr[j + 2] * x[j + 2]; + case 2: + s1 += lptr[j + 1] * x[j + 1]; + case 1: + s2 += lptr[j + 0] * x[j + 0]; + case 0: + break; } double sum; + sum = s3; sum += s2; sum += s1; @@ -1839,9 +1940,7 @@ void VPCALL idSIMD_Generic::MatX_LowerTriangularSolve( const idMatX &L, float *x x[i] = -sum; lptr += nc; } - #else - int i, j; const float *lptr; double sum; @@ -1849,12 +1948,12 @@ void VPCALL idSIMD_Generic::MatX_LowerTriangularSolve( const idMatX &L, float *x for ( i = skip; i < n; i++ ) { sum = b[i]; lptr = L[i]; + for ( j = 0; j < i; j++ ) { sum -= lptr[j] * x[j]; } x[i] = sum; } - #endif } @@ -1869,7 +1968,6 @@ idSIMD_Generic::MatX_LowerTriangularSolveTranspose */ void VPCALL idSIMD_Generic::MatX_LowerTriangularSolveTranspose( const idMatX &L, float *x, const float *b, const int n ) { #if 1 - int nc; const float *lptr; @@ -1878,55 +1976,54 @@ void VPCALL idSIMD_Generic::MatX_LowerTriangularSolveTranspose( const idMatX &L, // unrolled cases for n < 8 if ( n < 8 ) { - switch( n ) { - case 0: - return; - case 1: - x[0] = b[0]; - return; - case 2: - x[1] = b[1]; - x[0] = b[0] - lptr[1*nc+0] * x[1]; - return; - case 3: - x[2] = b[2]; - x[1] = b[1] - lptr[2*nc+1] * x[2]; - x[0] = b[0] - lptr[2*nc+0] * x[2] - lptr[1*nc+0] * x[1]; - return; - case 4: - x[3] = b[3]; - x[2] = b[2] - lptr[3*nc+2] * x[3]; - x[1] = b[1] - lptr[3*nc+1] * x[3] - lptr[2*nc+1] * x[2]; - x[0] = b[0] - lptr[3*nc+0] * x[3] - lptr[2*nc+0] * x[2] - lptr[1*nc+0] * x[1]; - return; - case 5: - x[4] = b[4]; - x[3] = b[3] - lptr[4*nc+3] * x[4]; - x[2] = b[2] - lptr[4*nc+2] * x[4] - lptr[3*nc+2] * x[3]; - x[1] = b[1] - lptr[4*nc+1] * x[4] - lptr[3*nc+1] * x[3] - lptr[2*nc+1] * x[2]; - x[0] = b[0] - lptr[4*nc+0] * x[4] - lptr[3*nc+0] * x[3] - lptr[2*nc+0] * x[2] - lptr[1*nc+0] * x[1]; - return; - case 6: - x[5] = b[5]; - x[4] = b[4] - lptr[5*nc+4] * x[5]; - x[3] = b[3] - lptr[5*nc+3] * x[5] - lptr[4*nc+3] * x[4]; - x[2] = b[2] - lptr[5*nc+2] * x[5] - lptr[4*nc+2] * x[4] - lptr[3*nc+2] * x[3]; - x[1] = b[1] - lptr[5*nc+1] * x[5] - lptr[4*nc+1] * x[4] - lptr[3*nc+1] * x[3] - lptr[2*nc+1] * x[2]; - x[0] = b[0] - lptr[5*nc+0] * x[5] - lptr[4*nc+0] * x[4] - lptr[3*nc+0] * x[3] - lptr[2*nc+0] * x[2] - lptr[1*nc+0] * x[1]; - return; - case 7: - x[6] = b[6]; - x[5] = b[5] - lptr[6*nc+5] * x[6]; - x[4] = b[4] - lptr[6*nc+4] * x[6] - lptr[5*nc+4] * x[5]; - x[3] = b[3] - lptr[6*nc+3] * x[6] - lptr[5*nc+3] * x[5] - lptr[4*nc+3] * x[4]; - x[2] = b[2] - lptr[6*nc+2] * x[6] - lptr[5*nc+2] * x[5] - lptr[4*nc+2] * x[4] - lptr[3*nc+2] * x[3]; - x[1] = b[1] - lptr[6*nc+1] * x[6] - lptr[5*nc+1] * x[5] - lptr[4*nc+1] * x[4] - lptr[3*nc+1] * x[3] - lptr[2*nc+1] * x[2]; - x[0] = b[0] - lptr[6*nc+0] * x[6] - lptr[5*nc+0] * x[5] - lptr[4*nc+0] * x[4] - lptr[3*nc+0] * x[3] - lptr[2*nc+0] * x[2] - lptr[1*nc+0] * x[1]; - return; + switch ( n ) { + case 0: + return; + case 1: + x[0] = b[0]; + return; + case 2: + x[1] = b[1]; + x[0] = b[0] - lptr[1 * nc + 0] * x[1]; + return; + case 3: + x[2] = b[2]; + x[1] = b[1] - lptr[2 * nc + 1] * x[2]; + x[0] = b[0] - lptr[2 * nc + 0] * x[2] - lptr[1 * nc + 0] * x[1]; + return; + case 4: + x[3] = b[3]; + x[2] = b[2] - lptr[3 * nc + 2] * x[3]; + x[1] = b[1] - lptr[3 * nc + 1] * x[3] - lptr[2 * nc + 1] * x[2]; + x[0] = b[0] - lptr[3 * nc + 0] * x[3] - lptr[2 * nc + 0] * x[2] - lptr[1 * nc + 0] * x[1]; + return; + case 5: + x[4] = b[4]; + x[3] = b[3] - lptr[4 * nc + 3] * x[4]; + x[2] = b[2] - lptr[4 * nc + 2] * x[4] - lptr[3 * nc + 2] * x[3]; + x[1] = b[1] - lptr[4 * nc + 1] * x[4] - lptr[3 * nc + 1] * x[3] - lptr[2 * nc + 1] * x[2]; + x[0] = b[0] - lptr[4 * nc + 0] * x[4] - lptr[3 * nc + 0] * x[3] - lptr[2 * nc + 0] * x[2] - lptr[1 * nc + 0] * x[1]; + return; + case 6: + x[5] = b[5]; + x[4] = b[4] - lptr[5 * nc + 4] * x[5]; + x[3] = b[3] - lptr[5 * nc + 3] * x[5] - lptr[4 * nc + 3] * x[4]; + x[2] = b[2] - lptr[5 * nc + 2] * x[5] - lptr[4 * nc + 2] * x[4] - lptr[3 * nc + 2] * x[3]; + x[1] = b[1] - lptr[5 * nc + 1] * x[5] - lptr[4 * nc + 1] * x[4] - lptr[3 * nc + 1] * x[3] - lptr[2 * nc + 1] * x[2]; + x[0] = b[0] - lptr[5 * nc + 0] * x[5] - lptr[4 * nc + 0] * x[4] - lptr[3 * nc + 0] * x[3] - lptr[2 * nc + 0] * x[2] - lptr[1 * nc + 0] * x[1]; + return; + case 7: + x[6] = b[6]; + x[5] = b[5] - lptr[6 * nc + 5] * x[6]; + x[4] = b[4] - lptr[6 * nc + 4] * x[6] - lptr[5 * nc + 4] * x[5]; + x[3] = b[3] - lptr[6 * nc + 3] * x[6] - lptr[5 * nc + 3] * x[5] - lptr[4 * nc + 3] * x[4]; + x[2] = b[2] - lptr[6 * nc + 2] * x[6] - lptr[5 * nc + 2] * x[5] - lptr[4 * nc + 2] * x[4] - lptr[3 * nc + 2] * x[3]; + x[1] = b[1] - lptr[6 * nc + 1] * x[6] - lptr[5 * nc + 1] * x[5] - lptr[4 * nc + 1] * x[4] - lptr[3 * nc + 1] * x[3] - lptr[2 * nc + 1] * x[2]; + x[0] = b[0] - lptr[6 * nc + 0] * x[6] - lptr[5 * nc + 0] * x[5] - lptr[4 * nc + 0] * x[4] - lptr[3 * nc + 0] * x[3] - lptr[2 * nc + 0] * x[2] - lptr[1 * nc + 0] * x[1]; + return; } return; } - int i, j; double s0, s1, s2, s3; float *xptr; @@ -1936,67 +2033,73 @@ void VPCALL idSIMD_Generic::MatX_LowerTriangularSolveTranspose( const idMatX &L, // process 4 rows at a time for ( i = n; i >= 4; i -= 4 ) { - s0 = b[i-4]; - s1 = b[i-3]; - s2 = b[i-2]; - s3 = b[i-1]; + s0 = b[i - 4]; + s1 = b[i - 3]; + s2 = b[i - 2]; + s3 = b[i - 1]; + // process 4x4 blocks - for ( j = 0; j < n-i; j += 4 ) { - s0 -= lptr[(j+0)*nc+0] * xptr[j+0]; - s1 -= lptr[(j+0)*nc+1] * xptr[j+0]; - s2 -= lptr[(j+0)*nc+2] * xptr[j+0]; - s3 -= lptr[(j+0)*nc+3] * xptr[j+0]; - s0 -= lptr[(j+1)*nc+0] * xptr[j+1]; - s1 -= lptr[(j+1)*nc+1] * xptr[j+1]; - s2 -= lptr[(j+1)*nc+2] * xptr[j+1]; - s3 -= lptr[(j+1)*nc+3] * xptr[j+1]; - s0 -= lptr[(j+2)*nc+0] * xptr[j+2]; - s1 -= lptr[(j+2)*nc+1] * xptr[j+2]; - s2 -= lptr[(j+2)*nc+2] * xptr[j+2]; - s3 -= lptr[(j+2)*nc+3] * xptr[j+2]; - s0 -= lptr[(j+3)*nc+0] * xptr[j+3]; - s1 -= lptr[(j+3)*nc+1] * xptr[j+3]; - s2 -= lptr[(j+3)*nc+2] * xptr[j+3]; - s3 -= lptr[(j+3)*nc+3] * xptr[j+3]; + for ( j = 0; j < n - i; j += 4 ) { + s0 -= lptr[( j + 0 ) * nc + 0] * xptr[j + 0]; + s1 -= lptr[( j + 0 ) * nc + 1] * xptr[j + 0]; + s2 -= lptr[( j + 0 ) * nc + 2] * xptr[j + 0]; + s3 -= lptr[( j + 0 ) * nc + 3] * xptr[j + 0]; + s0 -= lptr[( j + 1 ) * nc + 0] * xptr[j + 1]; + s1 -= lptr[( j + 1 ) * nc + 1] * xptr[j + 1]; + s2 -= lptr[( j + 1 ) * nc + 2] * xptr[j + 1]; + s3 -= lptr[( j + 1 ) * nc + 3] * xptr[j + 1]; + s0 -= lptr[( j + 2 ) * nc + 0] * xptr[j + 2]; + s1 -= lptr[( j + 2 ) * nc + 1] * xptr[j + 2]; + s2 -= lptr[( j + 2 ) * nc + 2] * xptr[j + 2]; + s3 -= lptr[( j + 2 ) * nc + 3] * xptr[j + 2]; + s0 -= lptr[( j + 3 ) * nc + 0] * xptr[j + 3]; + s1 -= lptr[( j + 3 ) * nc + 1] * xptr[j + 3]; + s2 -= lptr[( j + 3 ) * nc + 2] * xptr[j + 3]; + s3 -= lptr[( j + 3 ) * nc + 3] * xptr[j + 3]; } + // process left over of the 4 rows - s0 -= lptr[0-1*nc] * s3; - s1 -= lptr[1-1*nc] * s3; - s2 -= lptr[2-1*nc] * s3; - s0 -= lptr[0-2*nc] * s2; - s1 -= lptr[1-2*nc] * s2; - s0 -= lptr[0-3*nc] * s1; + s0 -= lptr[0 - 1 * nc] * s3; + s1 -= lptr[1 - 1 * nc] * s3; + s2 -= lptr[2 - 1 * nc] * s3; + s0 -= lptr[0 - 2 * nc] * s2; + s1 -= lptr[1 - 2 * nc] * s2; + s0 -= lptr[0 - 3 * nc] * s1; + // store result xptr[-4] = s0; xptr[-3] = s1; xptr[-2] = s2; xptr[-1] = s3; + // update pointers for next four rows lptr -= 4 + 4 * nc; xptr -= 4; } + // process left over rows for ( i--; i >= 0; i-- ) { s0 = b[i]; lptr = L[0] + i; + for ( j = i + 1; j < n; j++ ) { - s0 -= lptr[j*nc] * x[j]; + s0 -= lptr[j * nc] * x[j]; } x[i] = s0; } - #else - int i, j, nc; const float *ptr; double sum; nc = L.GetNumColumns(); + for ( i = n - 1; i >= 0; i-- ) { sum = b[i]; ptr = L[0] + i; + for ( j = i + 1; j < n; j++ ) { - sum -= ptr[j*nc] * x[j]; + sum -= ptr[j * nc] * x[j]; } x[i] = sum; } @@ -2012,130 +2115,126 @@ idSIMD_Generic::MatX_LDLTFactor the reciprocal of the diagonal elements are stored in invDiag ============ */ -bool VPCALL idSIMD_Generic::MatX_LDLTFactor( idMatX &mat, idVecX &invDiag, const int n ) { +bool VPCALL idSIMD_Generic::MatX_LDLTFactor(idMatX &mat, idVecX &invDiag, const int n) { #if 1 - int i, j, k, nc; float *v, *diag, *mptr; double s0, s1, s2, s3, sum, d; - v = (float *) _alloca16( n * sizeof( float ) ); - diag = (float *) _alloca16( n * sizeof( float ) ); + v = (float *)_alloca16(n * sizeof(float)); + diag = (float *)_alloca16(n * sizeof(float)); nc = mat.GetNumColumns(); - if ( n <= 0 ) { + if (n <= 0) { return true; } - mptr = mat[0]; sum = mptr[0]; - if ( sum == 0.0f ) { + if (sum == 0.0f) { return false; } - diag[0] = sum; + invDiag[0] = d = 1.0f / sum; - if ( n <= 1 ) { + if (n <= 1) { return true; } - mptr = mat[0]; - for ( j = 1; j < n; j++ ) { - mptr[j*nc+0] = ( mptr[j*nc+0] ) * d; - } + for (j = 1; j < n; j++) { + mptr[j*nc + 0] = (mptr[j*nc + 0]) * d; + } mptr = mat[1]; v[0] = diag[0] * mptr[0]; s0 = v[0] * mptr[0]; + sum = mptr[1] - s0; - if ( sum == 0.0f ) { + if (sum == 0.0f) { return false; } - mat[1][1] = sum; diag[1] = sum; invDiag[1] = d = 1.0f / sum; - if ( n <= 2 ) { + if (n <= 2) { return true; } - mptr = mat[0]; - for ( j = 2; j < n; j++ ) { - mptr[j*nc+1] = ( mptr[j*nc+1] - v[0] * mptr[j*nc+0] ) * d; - } + for (j = 2; j < n; j++) { + mptr[j*nc + 1] = (mptr[j*nc + 1] - v[0] * mptr[j*nc + 0]) * d; + } mptr = mat[2]; v[0] = diag[0] * mptr[0]; s0 = v[0] * mptr[0]; v[1] = diag[1] * mptr[1]; s1 = v[1] * mptr[1]; + sum = mptr[2] - s0 - s1; - if ( sum == 0.0f ) { + if (sum == 0.0f) { return false; } - mat[2][2] = sum; diag[2] = sum; invDiag[2] = d = 1.0f / sum; - if ( n <= 3 ) { + if (n <= 3) { return true; } - mptr = mat[0]; - for ( j = 3; j < n; j++ ) { - mptr[j*nc+2] = ( mptr[j*nc+2] - v[0] * mptr[j*nc+0] - v[1] * mptr[j*nc+1] ) * d; - } + for (j = 3; j < n; j++) { + mptr[j*nc + 2] = (mptr[j*nc + 2] - v[0] * mptr[j*nc + 0] - v[1] * mptr[j*nc + 1]) * d; + } mptr = mat[3]; v[0] = diag[0] * mptr[0]; s0 = v[0] * mptr[0]; v[1] = diag[1] * mptr[1]; s1 = v[1] * mptr[1]; v[2] = diag[2] * mptr[2]; s2 = v[2] * mptr[2]; + sum = mptr[3] - s0 - s1 - s2; - if ( sum == 0.0f ) { + if (sum == 0.0f) { return false; } - mat[3][3] = sum; diag[3] = sum; invDiag[3] = d = 1.0f / sum; - if ( n <= 4 ) { + if (n <= 4) { return true; } - mptr = mat[0]; - for ( j = 4; j < n; j++ ) { - mptr[j*nc+3] = ( mptr[j*nc+3] - v[0] * mptr[j*nc+0] - v[1] * mptr[j*nc+1] - v[2] * mptr[j*nc+2] ) * d; - } - for ( i = 4; i < n; i++ ) { + for (j = 4; j < n; j++) { + mptr[j*nc + 3] = (mptr[j*nc + 3] - v[0] * mptr[j*nc + 0] - v[1] * mptr[j*nc + 1] - v[2] * mptr[j*nc + 2]) * d; + } + for (i = 4; i < n; i++) { mptr = mat[i]; v[0] = diag[0] * mptr[0]; s0 = v[0] * mptr[0]; v[1] = diag[1] * mptr[1]; s1 = v[1] * mptr[1]; v[2] = diag[2] * mptr[2]; s2 = v[2] * mptr[2]; v[3] = diag[3] * mptr[3]; s3 = v[3] * mptr[3]; - for ( k = 4; k < i-3; k += 4 ) { - v[k+0] = diag[k+0] * mptr[k+0]; s0 += v[k+0] * mptr[k+0]; - v[k+1] = diag[k+1] * mptr[k+1]; s1 += v[k+1] * mptr[k+1]; - v[k+2] = diag[k+2] * mptr[k+2]; s2 += v[k+2] * mptr[k+2]; - v[k+3] = diag[k+3] * mptr[k+3]; s3 += v[k+3] * mptr[k+3]; + + for (k = 4; k < i - 3; k += 4) { + v[k + 0] = diag[k + 0] * mptr[k + 0]; s0 += v[k + 0] * mptr[k + 0]; + v[k + 1] = diag[k + 1] * mptr[k + 1]; s1 += v[k + 1] * mptr[k + 1]; + v[k + 2] = diag[k + 2] * mptr[k + 2]; s2 += v[k + 2] * mptr[k + 2]; + v[k + 3] = diag[k + 3] * mptr[k + 3]; s3 += v[k + 3] * mptr[k + 3]; } - switch( i - k ) { + + switch (i - k) { NODEFAULT; - case 3: v[k+2] = diag[k+2] * mptr[k+2]; s0 += v[k+2] * mptr[k+2]; - case 2: v[k+1] = diag[k+1] * mptr[k+1]; s1 += v[k+1] * mptr[k+1]; - case 1: v[k+0] = diag[k+0] * mptr[k+0]; s2 += v[k+0] * mptr[k+0]; + case 3: v[k + 2] = diag[k + 2] * mptr[k + 2]; s0 += v[k + 2] * mptr[k + 2]; + case 2: v[k + 1] = diag[k + 1] * mptr[k + 1]; s1 += v[k + 1] * mptr[k + 1]; + case 1: v[k + 0] = diag[k + 0] * mptr[k + 0]; s2 += v[k + 0] * mptr[k + 0]; case 0: break; } sum = s3; @@ -2144,101 +2243,97 @@ bool VPCALL idSIMD_Generic::MatX_LDLTFactor( idMatX &mat, idVecX &invDiag, const sum += s0; sum = mptr[i] - sum; - if ( sum == 0.0f ) { + if (sum == 0.0f) { return false; } - mat[i][i] = sum; diag[i] = sum; invDiag[i] = d = 1.0f / sum; - if ( i + 1 >= n ) { + if (i + 1 >= n) { return true; } + mptr = mat[i + 1]; - mptr = mat[i+1]; - for ( j = i+1; j < n; j++ ) { + for (j = i + 1; j < n; j++) { s0 = mptr[0] * v[0]; s1 = mptr[1] * v[1]; s2 = mptr[2] * v[2]; s3 = mptr[3] * v[3]; - for ( k = 4; k < i-7; k += 8 ) { - s0 += mptr[k+0] * v[k+0]; - s1 += mptr[k+1] * v[k+1]; - s2 += mptr[k+2] * v[k+2]; - s3 += mptr[k+3] * v[k+3]; - s0 += mptr[k+4] * v[k+4]; - s1 += mptr[k+5] * v[k+5]; - s2 += mptr[k+6] * v[k+6]; - s3 += mptr[k+7] * v[k+7]; + + for (k = 4; k < i - 7; k += 8) { + s0 += mptr[k + 0] * v[k + 0]; + s1 += mptr[k + 1] * v[k + 1]; + s2 += mptr[k + 2] * v[k + 2]; + s3 += mptr[k + 3] * v[k + 3]; + s0 += mptr[k + 4] * v[k + 4]; + s1 += mptr[k + 5] * v[k + 5]; + s2 += mptr[k + 6] * v[k + 6]; + s3 += mptr[k + 7] * v[k + 7]; } - switch( i - k ) { + + switch (i - k) { NODEFAULT; - case 7: s0 += mptr[k+6] * v[k+6]; - case 6: s1 += mptr[k+5] * v[k+5]; - case 5: s2 += mptr[k+4] * v[k+4]; - case 4: s3 += mptr[k+3] * v[k+3]; - case 3: s0 += mptr[k+2] * v[k+2]; - case 2: s1 += mptr[k+1] * v[k+1]; - case 1: s2 += mptr[k+0] * v[k+0]; + case 7: s0 += mptr[k + 6] * v[k + 6]; + case 6: s1 += mptr[k + 5] * v[k + 5]; + case 5: s2 += mptr[k + 4] * v[k + 4]; + case 4: s3 += mptr[k + 3] * v[k + 3]; + case 3: s0 += mptr[k + 2] * v[k + 2]; + case 2: s1 += mptr[k + 1] * v[k + 1]; + case 1: s2 += mptr[k + 0] * v[k + 0]; case 0: break; } sum = s3; sum += s2; sum += s1; sum += s0; - mptr[i] = ( mptr[i] - sum ) * d; + mptr[i] = (mptr[i] - sum) * d; mptr += nc; } } - return true; - #else - int i, j, k, nc; float *v, *ptr, *diagPtr; double d, sum; - v = (float *) _alloca16( n * sizeof( float ) ); + v = (float *)_alloca16(n * sizeof(float)); nc = mat.GetNumColumns(); - for ( i = 0; i < n; i++ ) { - + for (i = 0; i < n; i++) { ptr = mat[i]; diagPtr = mat[0]; sum = ptr[i]; - for ( j = 0; j < i; j++ ) { + + for (j = 0; j < i; j++) { d = ptr[j]; v[j] = diagPtr[0] * d; sum -= v[j] * d; diagPtr += nc + 1; } - if ( sum == 0.0f ) { + if (sum == 0.0f) { return false; } - diagPtr[0] = sum; invDiag[i] = d = 1.0f / sum; - if ( i + 1 >= n ) { + if (i + 1 >= n) { continue; } + ptr = mat[i + 1]; - ptr = mat[i+1]; - for ( j = i + 1; j < n; j++ ) { + for (j = i + 1; j < n; j++) { sum = ptr[i]; - for ( k = 0; k < i; k++ ) { + + for (k = 0; k < i; k++) { sum -= ptr[k] * v[k]; } ptr[i] = sum * d; ptr += nc; } } - return true; - #endif } @@ -2292,7 +2387,7 @@ idSIMD_Generic::TransformJoints void VPCALL idSIMD_Generic::TransformJoints( idJointMat *jointMats, const int *parents, const int firstJoint, const int lastJoint ) { int i; - for( i = firstJoint; i <= lastJoint; i++ ) { + for ( i = firstJoint; i <= lastJoint; i++ ) { assert( parents[i] < i ); jointMats[i] *= jointMats[parents[i]]; } @@ -2306,7 +2401,7 @@ idSIMD_Generic::UntransformJoints void VPCALL idSIMD_Generic::UntransformJoints( idJointMat *jointMats, const int *parents, const int firstJoint, const int lastJoint ) { int i; - for( i = lastJoint; i >= firstJoint; i-- ) { + for ( i = lastJoint; i >= firstJoint; i-- ) { assert( parents[i] < i ); jointMats[i] /= jointMats[parents[i]]; } @@ -2319,15 +2414,16 @@ idSIMD_Generic::TransformVerts */ void VPCALL idSIMD_Generic::TransformVerts( idDrawVert *verts, const int numVerts, const idJointMat *joints, const idVec4 *weights, const int *index, int numWeights ) { int i, j; - const byte *jointsPtr = (byte *)joints; + const byte *jointsPtr = ( byte * )joints; - for( j = i = 0; i < numVerts; i++ ) { + for ( j = i = 0; i < numVerts; i++ ) { idVec3 v; - v = ( *(idJointMat *) ( jointsPtr + index[j*2+0] ) ) * weights[j]; - while( index[j*2+1] == 0 ) { + v = ( *( idJointMat * )( jointsPtr + index[j * 2 + 0] ) ) * weights[j]; + + while ( index[j * 2 + 1] == 0 ) { j++; - v += ( *(idJointMat *) ( jointsPtr + index[j*2+0] ) ) * weights[j]; + v += ( *( idJointMat * )( jointsPtr + index[j * 2 + 0] ) ) * weights[j]; } j++; @@ -2379,7 +2475,6 @@ void VPCALL idSIMD_Generic::TracePointCull( byte *cullBits, byte &totalOr, const tOr |= bits; cullBits[i] = bits; } - totalOr = tOr; } @@ -2495,13 +2590,11 @@ idSIMD_Generic::DeriveTangents ============ */ void VPCALL idSIMD_Generic::DeriveTangents( idPlane *planes, idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes ) { - int i; - - bool *used = (bool *)_alloca16( numVerts * sizeof( used[0] ) ); + bool *used = ( bool * )_alloca16( numVerts * sizeof( used[0] ) ); memset( used, 0, numVerts * sizeof( used[0] ) ); - idPlane *planesPtr = planes; - for ( i = 0; i < numIndexes; i += 3 ) { + + for ( int i = 0; i < numIndexes; i += 3 ) { idDrawVert *a, *b, *c; unsigned int signBit; float d0[5], d1[5], f, area; @@ -2544,7 +2637,7 @@ void VPCALL idSIMD_Generic::DeriveTangents( idPlane *planes, idDrawVert *verts, // area sign bit area = d0[3] * d1[4] - d0[4] * d1[3]; - signBit = ( *(unsigned int *)&area ) & ( 1 << 31 ); + signBit = ( *( unsigned int * )&area ) & ( 1 << 31 ); // first tangent t0[0] = d0[0] * d1[4] - d0[4] * d1[0]; @@ -2552,7 +2645,7 @@ void VPCALL idSIMD_Generic::DeriveTangents( idPlane *planes, idDrawVert *verts, t0[2] = d0[2] * d1[4] - d0[4] * d1[2]; f = idMath::RSqrt( t0.x * t0.x + t0.y * t0.y + t0.z * t0.z ); - *(unsigned int *)&f ^= signBit; + *( unsigned int * )&f ^= signBit; t0.x *= f; t0.y *= f; @@ -2564,7 +2657,7 @@ void VPCALL idSIMD_Generic::DeriveTangents( idPlane *planes, idDrawVert *verts, t1[2] = d0[3] * d1[2] - d0[2] * d1[3]; f = idMath::RSqrt( t1.x * t1.x + t1.y * t1.y + t1.z * t1.z ); - *(unsigned int *)&f ^= signBit; + *( unsigned int * )&f ^= signBit; t1.x *= f; t1.y *= f; @@ -2673,7 +2766,6 @@ void VPCALL idSIMD_Generic::DeriveUnsmoothedTangents( idDrawVert *verts, const d t4 = s1 * ( n0 * t2 - n2 * t0 ); t5 = s1 * ( n1 * t0 - n0 * t1 ); #endif - a->normal[0] = n0; a->normal[1] = n1; a->normal[2] = n2; @@ -2697,20 +2789,22 @@ idSIMD_Generic::NormalizeTangents ============ */ void VPCALL idSIMD_Generic::NormalizeTangents( idDrawVert *verts, const int numVerts ) { - for ( int i = 0; i < numVerts; i++ ) { idVec3 &v = verts[i].normal; - float f; + float f = idMath::RSqrt( v.x * v.x + v.y * v.y + v.z * v.z ); - f = idMath::RSqrt( v.x * v.x + v.y * v.y + v.z * v.z ); - v.x *= f; v.y *= f; v.z *= f; + v.x *= f; + v.y *= f; + v.z *= f; for ( int j = 0; j < 2; j++ ) { idVec3 &t = verts[i].tangents[j]; t -= ( t * v ) * v; f = idMath::RSqrt( t.x * t.x + t.y * t.y + t.z * t.z ); - t.x *= f; t.y *= f; t.z *= f; + t.x *= f; + t.y *= f; + t.z *= f; } } } @@ -2725,8 +2819,8 @@ idSIMD_Generic::CreateTextureSpaceLightVectors ============ */ void VPCALL idSIMD_Generic::CreateTextureSpaceLightVectors( idVec3 *lightVectors, const idVec3 &lightOrigin, const idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes ) { + bool *used = ( bool * )_alloca16( numVerts * sizeof( used[0] ) ); - bool *used = (bool *)_alloca16( numVerts * sizeof( used[0] ) ); memset( used, 0, numVerts * sizeof( used[0] ) ); for ( int i = numIndexes - 1; i >= 0; i-- ) { @@ -2737,9 +2831,7 @@ void VPCALL idSIMD_Generic::CreateTextureSpaceLightVectors( idVec3 *lightVectors if ( !used[i] ) { continue; } - const idDrawVert *v = &verts[i]; - idVec3 lightDir = lightOrigin - v->xyz; lightVectors[i][0] = lightDir * v->tangents[0]; @@ -2759,8 +2851,8 @@ idSIMD_Generic::CreateSpecularTextureCoords ============ */ void VPCALL idSIMD_Generic::CreateSpecularTextureCoords( idVec4 *texCoords, const idVec3 &lightOrigin, const idVec3 &viewOrigin, const idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes ) { + bool *used = ( bool * )_alloca16( numVerts * sizeof( used[0] ) ); - bool *used = (bool *)_alloca16( numVerts * sizeof( used[0] ) ); memset( used, 0, numVerts * sizeof( used[0] ) ); for ( int i = numIndexes - 1; i >= 0; i-- ) { @@ -2771,7 +2863,6 @@ void VPCALL idSIMD_Generic::CreateSpecularTextureCoords( idVec4 *texCoords, cons if ( !used[i] ) { continue; } - const idDrawVert *v = &verts[i]; idVec3 lightDir = lightOrigin - v->xyz; @@ -2811,18 +2902,19 @@ int VPCALL idSIMD_Generic::CreateShadowCache( idVec4 *vertexCache, int *vertRema continue; } const float *v = verts[i].xyz.ToFloatPtr(); - vertexCache[outVerts+0][0] = v[0]; - vertexCache[outVerts+0][1] = v[1]; - vertexCache[outVerts+0][2] = v[2]; - vertexCache[outVerts+0][3] = 1.0f; + + vertexCache[outVerts + 0][0] = v[0]; + vertexCache[outVerts + 0][1] = v[1]; + vertexCache[outVerts + 0][2] = v[2]; + vertexCache[outVerts + 0][3] = 1.0f; // R_SetupProjection() builds the projection matrix with a slight crunch // for depth, which keeps this w=0 division from rasterizing right at the // wrap around point and causing depth fighting with the rear caps - vertexCache[outVerts+1][0] = v[0] - lightOrigin[0]; - vertexCache[outVerts+1][1] = v[1] - lightOrigin[1]; - vertexCache[outVerts+1][2] = v[2] - lightOrigin[2]; - vertexCache[outVerts+1][3] = 0.0f; + vertexCache[outVerts + 1][0] = v[0] - lightOrigin[0]; + vertexCache[outVerts + 1][1] = v[1] - lightOrigin[1]; + vertexCache[outVerts + 1][2] = v[2] - lightOrigin[2]; + vertexCache[outVerts + 1][3] = 0.0f; vertRemap[i] = outVerts; outVerts += 2; } @@ -2837,14 +2929,15 @@ idSIMD_Generic::CreateVertexProgramShadowCache int VPCALL idSIMD_Generic::CreateVertexProgramShadowCache( idVec4 *vertexCache, const idDrawVert *verts, const int numVerts ) { for ( int i = 0; i < numVerts; i++ ) { const float *v = verts[i].xyz.ToFloatPtr(); - vertexCache[i*2+0][0] = v[0]; - vertexCache[i*2+1][0] = v[0]; - vertexCache[i*2+0][1] = v[1]; - vertexCache[i*2+1][1] = v[1]; - vertexCache[i*2+0][2] = v[2]; - vertexCache[i*2+1][2] = v[2]; - vertexCache[i*2+0][3] = 1.0f; - vertexCache[i*2+1][3] = 0.0f; + + vertexCache[i * 2 + 0][0] = v[0]; + vertexCache[i * 2 + 1][0] = v[0]; + vertexCache[i * 2 + 0][1] = v[1]; + vertexCache[i * 2 + 1][1] = v[1]; + vertexCache[i * 2 + 0][2] = v[2]; + vertexCache[i * 2 + 1][2] = v[2]; + vertexCache[i * 2 + 0][3] = 1.0f; + vertexCache[i * 2 + 1][3] = 0.0f; } return numVerts * 2; } @@ -2860,28 +2953,28 @@ void idSIMD_Generic::UpSamplePCMTo44kHz( float *dest, const short *src, const in if ( kHz == 11025 ) { if ( numChannels == 1 ) { for ( int i = 0; i < numSamples; i++ ) { - dest[i*4+0] = dest[i*4+1] = dest[i*4+2] = dest[i*4+3] = (float) src[i+0]; + dest[i * 4 + 0] = dest[i * 4 + 1] = dest[i * 4 + 2] = dest[i * 4 + 3] = ( float ) src[i + 0]; } } else { for ( int i = 0; i < numSamples; i += 2 ) { - dest[i*4+0] = dest[i*4+2] = dest[i*4+4] = dest[i*4+6] = (float) src[i+0]; - dest[i*4+1] = dest[i*4+3] = dest[i*4+5] = dest[i*4+7] = (float) src[i+1]; + dest[i * 4 + 0] = dest[i * 4 + 2] = dest[i * 4 + 4] = dest[i * 4 + 6] = ( float ) src[i + 0]; + dest[i * 4 + 1] = dest[i * 4 + 3] = dest[i * 4 + 5] = dest[i * 4 + 7] = ( float ) src[i + 1]; } } } else if ( kHz == 22050 ) { if ( numChannels == 1 ) { for ( int i = 0; i < numSamples; i++ ) { - dest[i*2+0] = dest[i*2+1] = (float) src[i+0]; + dest[i * 2 + 0] = dest[i * 2 + 1] = ( float ) src[i + 0]; } } else { for ( int i = 0; i < numSamples; i += 2 ) { - dest[i*2+0] = dest[i*2+2] = (float) src[i+0]; - dest[i*2+1] = dest[i*2+3] = (float) src[i+1]; + dest[i * 2 + 0] = dest[i * 2 + 2] = ( float ) src[i + 0]; + dest[i * 2 + 1] = dest[i * 2 + 3] = ( float ) src[i + 1]; } } } else if ( kHz == 44100 ) { for ( int i = 0; i < numSamples; i++ ) { - dest[i] = (float) src[i]; + dest[i] = ( float ) src[i]; } } else { assert( 0 ); @@ -2895,38 +2988,38 @@ idSIMD_Generic::UpSampleOGGTo44kHz Duplicate samples for 44kHz output. ============ */ -void idSIMD_Generic::UpSampleOGGTo44kHz( float *dest, const float * const *ogg, const int numSamples, const int kHz, const int numChannels ) { +void idSIMD_Generic::UpSampleOGGTo44kHz( float *dest, const float *const *ogg, const int numSamples, const int kHz, const int numChannels ) { if ( kHz == 11025 ) { if ( numChannels == 1 ) { for ( int i = 0; i < numSamples; i++ ) { - dest[i*4+0] = dest[i*4+1] = dest[i*4+2] = dest[i*4+3] = ogg[0][i] * 32768.0f; + dest[i * 4 + 0] = dest[i * 4 + 1] = dest[i * 4 + 2] = dest[i * 4 + 3] = ogg[0][i] * 32768.0f; } } else { for ( int i = 0; i < numSamples >> 1; i++ ) { - dest[i*8+0] = dest[i*8+2] = dest[i*8+4] = dest[i*8+6] = ogg[0][i] * 32768.0f; - dest[i*8+1] = dest[i*8+3] = dest[i*8+5] = dest[i*8+7] = ogg[1][i] * 32768.0f; + dest[i * 8 + 0] = dest[i * 8 + 2] = dest[i * 8 + 4] = dest[i * 8 + 6] = ogg[0][i] * 32768.0f; + dest[i * 8 + 1] = dest[i * 8 + 3] = dest[i * 8 + 5] = dest[i * 8 + 7] = ogg[1][i] * 32768.0f; } } } else if ( kHz == 22050 ) { if ( numChannels == 1 ) { for ( int i = 0; i < numSamples; i++ ) { - dest[i*2+0] = dest[i*2+1] = ogg[0][i] * 32768.0f; + dest[i * 2 + 0] = dest[i * 2 + 1] = ogg[0][i] * 32768.0f; } } else { for ( int i = 0; i < numSamples >> 1; i++ ) { - dest[i*4+0] = dest[i*4+2] = ogg[0][i] * 32768.0f; - dest[i*4+1] = dest[i*4+3] = ogg[1][i] * 32768.0f; + dest[i * 4 + 0] = dest[i * 4 + 2] = ogg[0][i] * 32768.0f; + dest[i * 4 + 1] = dest[i * 4 + 3] = ogg[1][i] * 32768.0f; } } } else if ( kHz == 44100 ) { if ( numChannels == 1 ) { for ( int i = 0; i < numSamples; i++ ) { - dest[i*1+0] = ogg[0][i] * 32768.0f; + dest[i * 1 + 0] = ogg[0][i] * 32768.0f; } } else { for ( int i = 0; i < numSamples >> 1; i++ ) { - dest[i*2+0] = ogg[0][i] * 32768.0f; - dest[i*2+1] = ogg[1][i] * 32768.0f; + dest[i * 2 + 0] = ogg[0][i] * 32768.0f; + dest[i * 2 + 1] = ogg[1][i] * 32768.0f; } } } else { @@ -2947,9 +3040,9 @@ void VPCALL idSIMD_Generic::MixSoundTwoSpeakerMono( float *mixBuffer, const floa assert( numSamples == MIXBUFFER_SAMPLES ); - for( int j = 0; j < MIXBUFFER_SAMPLES; j++ ) { - mixBuffer[j*2+0] += samples[j] * sL; - mixBuffer[j*2+1] += samples[j] * sR; + for ( int j = 0; j < MIXBUFFER_SAMPLES; j++ ) { + mixBuffer[j * 2 + 0] += samples[j] * sL; + mixBuffer[j * 2 + 1] += samples[j] * sR; sL += incL; sR += incR; } @@ -2968,9 +3061,9 @@ void VPCALL idSIMD_Generic::MixSoundTwoSpeakerStereo( float *mixBuffer, const fl assert( numSamples == MIXBUFFER_SAMPLES ); - for( int j = 0; j < MIXBUFFER_SAMPLES; j++ ) { - mixBuffer[j*2+0] += samples[j*2+0] * sL; - mixBuffer[j*2+1] += samples[j*2+1] * sR; + for ( int j = 0; j < MIXBUFFER_SAMPLES; j++ ) { + mixBuffer[j * 2 + 0] += samples[j * 2 + 0] * sL; + mixBuffer[j * 2 + 1] += samples[j * 2 + 1] * sR; sL += incL; sR += incR; } @@ -2998,13 +3091,13 @@ void VPCALL idSIMD_Generic::MixSoundSixSpeakerMono( float *mixBuffer, const floa assert( numSamples == MIXBUFFER_SAMPLES ); - for( int i = 0; i < MIXBUFFER_SAMPLES; i++ ) { - mixBuffer[i*6+0] += samples[i] * sL0; - mixBuffer[i*6+1] += samples[i] * sL1; - mixBuffer[i*6+2] += samples[i] * sL2; - mixBuffer[i*6+3] += samples[i] * sL3; - mixBuffer[i*6+4] += samples[i] * sL4; - mixBuffer[i*6+5] += samples[i] * sL5; + for ( int i = 0; i < MIXBUFFER_SAMPLES; i++ ) { + mixBuffer[i * 6 + 0] += samples[i] * sL0; + mixBuffer[i * 6 + 1] += samples[i] * sL1; + mixBuffer[i * 6 + 2] += samples[i] * sL2; + mixBuffer[i * 6 + 3] += samples[i] * sL3; + mixBuffer[i * 6 + 4] += samples[i] * sL4; + mixBuffer[i * 6 + 5] += samples[i] * sL5; sL0 += incL0; sL1 += incL1; sL2 += incL2; @@ -3036,13 +3129,13 @@ void VPCALL idSIMD_Generic::MixSoundSixSpeakerStereo( float *mixBuffer, const fl assert( numSamples == MIXBUFFER_SAMPLES ); - for( int i = 0; i < MIXBUFFER_SAMPLES; i++ ) { - mixBuffer[i*6+0] += samples[i*2+0] * sL0; - mixBuffer[i*6+1] += samples[i*2+1] * sL1; - mixBuffer[i*6+2] += samples[i*2+0] * sL2; - mixBuffer[i*6+3] += samples[i*2+0] * sL3; - mixBuffer[i*6+4] += samples[i*2+0] * sL4; - mixBuffer[i*6+5] += samples[i*2+1] * sL5; + for ( int i = 0; i < MIXBUFFER_SAMPLES; i++ ) { + mixBuffer[i * 6 + 0] += samples[i * 2 + 0] * sL0; + mixBuffer[i * 6 + 1] += samples[i * 2 + 1] * sL1; + mixBuffer[i * 6 + 2] += samples[i * 2 + 0] * sL2; + mixBuffer[i * 6 + 3] += samples[i * 2 + 0] * sL3; + mixBuffer[i * 6 + 4] += samples[i * 2 + 0] * sL4; + mixBuffer[i * 6 + 5] += samples[i * 2 + 1] * sL5; sL0 += incL0; sL1 += incL1; sL2 += incL2; @@ -3065,7 +3158,47 @@ void VPCALL idSIMD_Generic::MixedSoundToSamples( short *samples, const float *mi } else if ( mixBuffer[i] >= 32767.0f ) { samples[i] = 32767; } else { - samples[i] = (short) mixBuffer[i]; + samples[i] = ( short ) mixBuffer[i]; + } + } +} + +/* +============ +idSIMD_Generic::CullByFrustum + +Moved from R_CalcInteractionCullBits +============ +*/ +void VPCALL idSIMD_Generic::CullByFrustum( idDrawVert *verts, const int numVerts, const idPlane frustum[6], byte *pointCull, float epsilon ) { + for ( int j = 0; j < numVerts; j++ ) { + idVec3 &vec = verts[j].xyz; + byte bits = 0; + + for ( int i = 0; i < 6; i++ ) { + float d = frustum[i].Distance( vec ); + bits |= ( d < epsilon ) << i; + } + pointCull[j] = bits; + } +} +/* +============ +idSIMD_Generic::CullByFrustum2 + +Moved from R_CalcPointCull +============ +*/ +void VPCALL idSIMD_Generic::CullByFrustum2( idDrawVert *verts, const int numVerts, const idPlane frustum[6], unsigned short *pointCull, float epsilon ) { + for ( int j = 0; j < numVerts; j++ ) { + idVec3 &vec = verts[j].xyz; + short bits = 0; + + for ( int i = 0; i < 6; i++ ) { + float d = frustum[i].Distance( vec ); + bits |= ( d < epsilon ) << i; + bits |= ( d > -epsilon ) << ( i + 6 ); } + pointCull[j] = bits; } } diff --git a/neo/idlib/math/Simd_Generic.h b/neo/idlib/math/Simd_Generic.h index a9a46322b..c3832ebf9 100644 --- a/neo/idlib/math/Simd_Generic.h +++ b/neo/idlib/math/Simd_Generic.h @@ -41,7 +41,7 @@ If you have questions concerning this license or the applicable additional terms class idSIMD_Generic : public idSIMDProcessor { public: - virtual const char * VPCALL GetName( void ) const; + virtual const char *VPCALL GetName( void ) const; virtual void VPCALL Add( float *dst, const float constant, const float *src, const int count ); virtual void VPCALL Add( float *dst, const float *src0, const float *src1, const int count ); @@ -59,9 +59,9 @@ class idSIMD_Generic : public idSIMDProcessor { virtual void VPCALL Dot( float *dst, const idVec3 &constant, const idVec3 *src, const int count ); virtual void VPCALL Dot( float *dst, const idVec3 &constant, const idPlane *src, const int count ); virtual void VPCALL Dot( float *dst, const idVec3 &constant, const idDrawVert *src, const int count ); - virtual void VPCALL Dot( float *dst, const idPlane &constant,const idVec3 *src, const int count ); - virtual void VPCALL Dot( float *dst, const idPlane &constant,const idPlane *src, const int count ); - virtual void VPCALL Dot( float *dst, const idPlane &constant,const idDrawVert *src, const int count ); + virtual void VPCALL Dot( float *dst, const idPlane &constant, const idVec3 *src, const int count ); + virtual void VPCALL Dot( float *dst, const idPlane &constant, const idPlane *src, const int count ); + virtual void VPCALL Dot( float *dst, const idPlane &constant, const idDrawVert *src, const int count ); virtual void VPCALL Dot( float *dst, const idVec3 *src0, const idVec3 *src1, const int count ); virtual void VPCALL Dot( float &dot, const float *src1, const float *src2, const int count ); @@ -128,12 +128,15 @@ class idSIMD_Generic : public idSIMDProcessor { virtual int VPCALL CreateVertexProgramShadowCache( idVec4 *vertexCache, const idDrawVert *verts, const int numVerts ); virtual void VPCALL UpSamplePCMTo44kHz( float *dest, const short *pcm, const int numSamples, const int kHz, const int numChannels ); - virtual void VPCALL UpSampleOGGTo44kHz( float *dest, const float * const *ogg, const int numSamples, const int kHz, const int numChannels ); + virtual void VPCALL UpSampleOGGTo44kHz( float *dest, const float *const *ogg, const int numSamples, const int kHz, const int numChannels ); virtual void VPCALL MixSoundTwoSpeakerMono( float *mixBuffer, const float *samples, const int numSamples, const float lastV[2], const float currentV[2] ); virtual void VPCALL MixSoundTwoSpeakerStereo( float *mixBuffer, const float *samples, const int numSamples, const float lastV[2], const float currentV[2] ); virtual void VPCALL MixSoundSixSpeakerMono( float *mixBuffer, const float *samples, const int numSamples, const float lastV[6], const float currentV[6] ); virtual void VPCALL MixSoundSixSpeakerStereo( float *mixBuffer, const float *samples, const int numSamples, const float lastV[6], const float currentV[6] ); virtual void VPCALL MixedSoundToSamples( short *samples, const float *mixBuffer, const int numSamples ); + + virtual void VPCALL CullByFrustum( idDrawVert *verts, const int numVerts, const idPlane frustum[6], byte *pointCull, float epsilon ); + virtual void VPCALL CullByFrustum2( idDrawVert *verts, const int numVerts, const idPlane frustum[6], unsigned short *pointCull, float epsilon ); }; #endif /* !__MATH_SIMD_GENERIC_H__ */ diff --git a/neo/idlib/math/Simd_MMX.cpp b/neo/idlib/math/Simd_MMX.cpp index 3251f5f5d..b818bb071 100644 --- a/neo/idlib/math/Simd_MMX.cpp +++ b/neo/idlib/math/Simd_MMX.cpp @@ -27,7 +27,6 @@ If you have questions concerning this license or the applicable additional terms */ #include "sys/platform.h" - #include "idlib/math/Simd_MMX.h" //=============================================================== @@ -55,7 +54,7 @@ const char * idSIMD_MMX::GetName( void ) const { idSIMD_MMX::GetName ============ */ -const char * idSIMD_MMX::GetName( void ) const { +const char *idSIMD_MMX::GetName( void ) const { return "MMX"; } diff --git a/neo/idlib/math/Simd_SSE.cpp b/neo/idlib/math/Simd_SSE.cpp index c8ba7e43f..98282bdc5 100644 --- a/neo/idlib/math/Simd_SSE.cpp +++ b/neo/idlib/math/Simd_SSE.cpp @@ -27,8 +27,6 @@ If you have questions concerning this license or the applicable additional terms */ #include "sys/platform.h" -#include "idlib/geometry/DrawVert.h" - #include "idlib/math/Simd_SSE.h" //=============================================================== @@ -37,6 +35,14 @@ If you have questions concerning this license or the applicable additional terms // E //=============================================================== +#include "idlib/geometry/DrawVert.h" +#include "idlib/geometry/JointTransform.h" +#include "idlib/math/Vector.h" +#include "idlib/math/Matrix.h" +#include "idlib/math/Quat.h" +#include "idlib/math/Plane.h" +#include "renderer/Model.h" + #define DRAWVERT_SIZE 60 #define DRAWVERT_XYZ_OFFSET (0*4) #define DRAWVERT_ST_OFFSET (3*4) @@ -57,7 +63,7 @@ If you have questions concerning this license or the applicable additional terms idSIMD_SSE::GetName ============ */ -const char * idSIMD_SSE::GetName( void ) const { +const char *idSIMD_SSE::GetName( void ) const { return "MMX & SSE"; } @@ -84,12 +90,12 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idDrawVe __m128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; // Declare 8 xmm registers. int count_l4 = count; // count_l4 = eax int count_l1 = count; // count_l1 = edx - char *constant_p = (char *)&constant; // constant_p = edi - char *src_p = (char *) src; // src_p = esi - char *dst_p = (char *) dst; // dst_p = ecx + char *constant_p = ( char * )&constant; // constant_p = edi + char *src_p = ( char * ) src; // src_p = esi + char *dst_p = ( char * ) dst; // dst_p = ecx assert( sizeof( idDrawVert ) == DRAWVERT_SIZE ); - assert( ptrdiff_t(&src->xyz) - ptrdiff_t(src) == DRAWVERT_XYZ_OFFSET ); + assert( ptrdiff_t( &src->xyz ) - ptrdiff_t( src ) == DRAWVERT_XYZ_OFFSET ); /* and eax, ~3 @@ -103,100 +109,100 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idDrawVe shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) */ count_l4 = count_l4 & ~3; - xmm4 = _mm_load_ss((float *) (constant_p)); - xmm4 = _mm_shuffle_ps(xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 )); - xmm5 = _mm_load_ss((float *) (constant_p + 4)); - xmm5 = _mm_shuffle_ps(xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 )); - xmm6 = _mm_load_ss((float *) (constant_p + 8)); - xmm6 = _mm_shuffle_ps(xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 )); - xmm7 = _mm_load_ss((float *) (constant_p + 12)); - xmm7 = _mm_shuffle_ps(xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 )); + xmm4 = _mm_load_ss( ( float * )( constant_p ) ); + xmm4 = _mm_shuffle_ps( xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) ); + xmm5 = _mm_load_ss( ( float * )( constant_p + 4 ) ); + xmm5 = _mm_shuffle_ps( xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) ); + xmm6 = _mm_load_ss( ( float * )( constant_p + 8 ) ); + xmm6 = _mm_shuffle_ps( xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) ); + xmm7 = _mm_load_ss( ( float * )( constant_p + 12 ) ); + xmm7 = _mm_shuffle_ps( xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) ); /* jz startVert1 */ - if(count_l4 != 0) { - /* - imul eax, DRAWVERT_SIZE - add esi, eax - neg eax - */ + if ( count_l4 != 0 ) { + /* + imul eax, DRAWVERT_SIZE + add esi, eax + neg eax + */ count_l4 = count_l4 * DRAWVERT_SIZE; src_p = src_p + count_l4; count_l4 = -count_l4; - /* - loopVert4: - */ + /* + loopVert4: + */ do { - /* - movss xmm0, [esi+eax+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 3, X, X, X - movss xmm2, [esi+eax+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] // 2, X, X, X - movhps xmm0, [esi+eax+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 3, X, 0, 1 - movaps xmm1, xmm0 // 3, X, 0, 1 - */ - xmm0 = _mm_load_ss((float *) (src_p+count_l4+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0)); // 3, X, X, X - xmm2 = _mm_load_ss((float *) (src_p+count_l4+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8)); // 2, X, X, X - xmm0 = _mm_loadh_pi(xmm0, (__m64 *) (src_p+count_l4+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0)); // 3, X, 0, 1 + /* + movss xmm0, [esi+eax+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 3, X, X, X + movss xmm2, [esi+eax+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] // 2, X, X, X + movhps xmm0, [esi+eax+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 3, X, 0, 1 + movaps xmm1, xmm0 // 3, X, 0, 1 + */ + xmm0 = _mm_load_ss( ( float * )( src_p + count_l4 + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0 ) ); // 3, X, X, X + xmm2 = _mm_load_ss( ( float * )( src_p + count_l4 + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8 ) ); // 2, X, X, X + xmm0 = _mm_loadh_pi( xmm0, ( __m64 * )( src_p + count_l4 + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0 ) ); // 3, X, 0, 1 xmm1 = xmm0; // 3, X, 0, 1 - /* - movlps xmm1, [esi+eax+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] // 4, 5, 0, 1 - shufps xmm2, xmm1, R_SHUFFLEPS( 0, 1, 0, 1 ) // 2, X, 4, 5 - */ - xmm1 = _mm_loadl_pi(xmm1, (__m64 *) (src_p+count_l4+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4)); // 4, 5, 0, 1 - xmm2 = _mm_shuffle_ps(xmm2, xmm1, R_SHUFFLEPS( 0, 1, 0, 1 )); // 2, X, 4, 5 - - /* - movss xmm3, [esi+eax+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 9, X, X, X - movhps xmm3, [esi+eax+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 9, X, 6, 7 - shufps xmm0, xmm3, R_SHUFFLEPS( 2, 0, 2, 0 ) // 0, 3, 6, 9 - */ - xmm3 = _mm_load_ss((float *) (src_p+count_l4+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0)); // 9, X, X, X - xmm3 = _mm_loadh_pi(xmm3, (__m64 *) (src_p+count_l4+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0)); // 9, X, 6, 7 - xmm0 = _mm_shuffle_ps(xmm0, xmm3, R_SHUFFLEPS( 2, 0, 2, 0 )); // 0, 3, 6, 9 - /* - movlps xmm3, [esi+eax+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] // 10, 11, 6, 7 - shufps xmm1, xmm3, R_SHUFFLEPS( 3, 0, 3, 0 ) // 1, 4, 7, 10 - */ - xmm3 = _mm_loadl_pi(xmm3, (__m64 *)(src_p+count_l4+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4)); // 10, 11, 6, 7 - xmm1 = _mm_shuffle_ps(xmm1, xmm3, R_SHUFFLEPS( 3, 0, 3, 0 )); // 1, 4, 7, 10 - /* - movhps xmm3, [esi+eax+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] // 10, 11, 8, X - shufps xmm2, xmm3, R_SHUFFLEPS( 0, 3, 2, 1 ) // 2, 5, 8, 11 - */ - xmm3 = _mm_loadh_pi(xmm3, (__m64 *)(src_p+count_l4+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8)); // 10, 11, 8, X - xmm2 = _mm_shuffle_ps(xmm2, xmm3, R_SHUFFLEPS( 0, 3, 2, 1 )); // 2, 5, 8, 11 - - /* - add ecx, 16 - add eax, 4*DRAWVERT_SIZE - */ + /* + movlps xmm1, [esi+eax+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] // 4, 5, 0, 1 + shufps xmm2, xmm1, R_SHUFFLEPS( 0, 1, 0, 1 ) // 2, X, 4, 5 + */ + xmm1 = _mm_loadl_pi( xmm1, ( __m64 * )( src_p + count_l4 + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4 ) ); // 4, 5, 0, 1 + xmm2 = _mm_shuffle_ps( xmm2, xmm1, R_SHUFFLEPS( 0, 1, 0, 1 ) ); // 2, X, 4, 5 + + /* + movss xmm3, [esi+eax+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 9, X, X, X + movhps xmm3, [esi+eax+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 9, X, 6, 7 + shufps xmm0, xmm3, R_SHUFFLEPS( 2, 0, 2, 0 ) // 0, 3, 6, 9 + */ + xmm3 = _mm_load_ss( ( float * )( src_p + count_l4 + 3 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0 ) ); // 9, X, X, X + xmm3 = _mm_loadh_pi( xmm3, ( __m64 * )( src_p + count_l4 + 2 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0 ) ); // 9, X, 6, 7 + xmm0 = _mm_shuffle_ps( xmm0, xmm3, R_SHUFFLEPS( 2, 0, 2, 0 ) ); // 0, 3, 6, 9 + /* + movlps xmm3, [esi+eax+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] // 10, 11, 6, 7 + shufps xmm1, xmm3, R_SHUFFLEPS( 3, 0, 3, 0 ) // 1, 4, 7, 10 + */ + xmm3 = _mm_loadl_pi( xmm3, ( __m64 * )( src_p + count_l4 + 3 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4 ) ); // 10, 11, 6, 7 + xmm1 = _mm_shuffle_ps( xmm1, xmm3, R_SHUFFLEPS( 3, 0, 3, 0 ) ); // 1, 4, 7, 10 + /* + movhps xmm3, [esi+eax+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] // 10, 11, 8, X + shufps xmm2, xmm3, R_SHUFFLEPS( 0, 3, 2, 1 ) // 2, 5, 8, 11 + */ + xmm3 = _mm_loadh_pi( xmm3, ( __m64 * )( src_p + count_l4 + 2 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8 ) ); // 10, 11, 8, X + xmm2 = _mm_shuffle_ps( xmm2, xmm3, R_SHUFFLEPS( 0, 3, 2, 1 ) ); // 2, 5, 8, 11 + + /* + add ecx, 16 + add eax, 4*DRAWVERT_SIZE + */ dst_p = dst_p + 16; - count_l4 = count_l4 + 4*DRAWVERT_SIZE; - - /* - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - addps xmm0, xmm7 - addps xmm0, xmm1 - addps xmm0, xmm2 - */ - xmm0 = _mm_mul_ps(xmm0, xmm4); - xmm1 = _mm_mul_ps(xmm1, xmm5); - xmm2 = _mm_mul_ps(xmm2, xmm6); - xmm0 = _mm_add_ps(xmm0, xmm7); - xmm0 = _mm_add_ps(xmm0, xmm1); - xmm0 = _mm_add_ps(xmm0, xmm2); + count_l4 = count_l4 + 4 * DRAWVERT_SIZE; - /* - movlps [ecx-16+0], xmm0 - movhps [ecx-16+8], xmm0 - jl loopVert4 - */ - _mm_storel_pi((__m64 *) (dst_p-16+0), xmm0); - _mm_storeh_pi((__m64 *) (dst_p-16+8), xmm0); - } while(count_l4 < 0); + /* + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + addps xmm0, xmm7 + addps xmm0, xmm1 + addps xmm0, xmm2 + */ + xmm0 = _mm_mul_ps( xmm0, xmm4 ); + xmm1 = _mm_mul_ps( xmm1, xmm5 ); + xmm2 = _mm_mul_ps( xmm2, xmm6 ); + xmm0 = _mm_add_ps( xmm0, xmm7 ); + xmm0 = _mm_add_ps( xmm0, xmm1 ); + xmm0 = _mm_add_ps( xmm0, xmm2 ); + + /* + movlps [ecx-16+0], xmm0 + movhps [ecx-16+8], xmm0 + jl loopVert4 + */ + _mm_storel_pi( ( __m64 * )( dst_p - 16 + 0 ), xmm0 ); + _mm_storeh_pi( ( __m64 * )( dst_p - 16 + 8 ), xmm0 ); + } while ( count_l4 < 0 ); } /* @@ -205,39 +211,39 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idDrawVe jz done */ count_l1 = count_l1 & 3; - if(count_l1 != 0) { - /* - loopVert1: - movss xmm0, [esi+eax+DRAWVERT_XYZ_OFFSET+0] - movss xmm1, [esi+eax+DRAWVERT_XYZ_OFFSET+4] - movss xmm2, [esi+eax+DRAWVERT_XYZ_OFFSET+8] - mulss xmm0, xmm4 - mulss xmm1, xmm5 - mulss xmm2, xmm6 - addss xmm0, xmm7 - add ecx, 4 - addss xmm0, xmm1 - add eax, DRAWVERT_SIZE - addss xmm0, xmm2 - dec edx - movss [ecx-4], xmm0 - jnz loopVert1 - */ + if ( count_l1 != 0 ) { + /* + loopVert1: + movss xmm0, [esi+eax+DRAWVERT_XYZ_OFFSET+0] + movss xmm1, [esi+eax+DRAWVERT_XYZ_OFFSET+4] + movss xmm2, [esi+eax+DRAWVERT_XYZ_OFFSET+8] + mulss xmm0, xmm4 + mulss xmm1, xmm5 + mulss xmm2, xmm6 + addss xmm0, xmm7 + add ecx, 4 + addss xmm0, xmm1 + add eax, DRAWVERT_SIZE + addss xmm0, xmm2 + dec edx + movss [ecx-4], xmm0 + jnz loopVert1 + */ do { - xmm0 = _mm_load_ss((float *) (src_p+count_l4+DRAWVERT_XYZ_OFFSET+0)); - xmm1 = _mm_load_ss((float *) (src_p+count_l4+DRAWVERT_XYZ_OFFSET+4)); - xmm2 = _mm_load_ss((float *) (src_p+count_l4+DRAWVERT_XYZ_OFFSET+8)); - xmm0 = _mm_mul_ss(xmm0, xmm4); - xmm1 = _mm_mul_ss(xmm1, xmm5); - xmm2 = _mm_mul_ss(xmm2, xmm6); - xmm0 = _mm_add_ss(xmm0, xmm7); + xmm0 = _mm_load_ss( ( float * )( src_p + count_l4 + DRAWVERT_XYZ_OFFSET + 0 ) ); + xmm1 = _mm_load_ss( ( float * )( src_p + count_l4 + DRAWVERT_XYZ_OFFSET + 4 ) ); + xmm2 = _mm_load_ss( ( float * )( src_p + count_l4 + DRAWVERT_XYZ_OFFSET + 8 ) ); + xmm0 = _mm_mul_ss( xmm0, xmm4 ); + xmm1 = _mm_mul_ss( xmm1, xmm5 ); + xmm2 = _mm_mul_ss( xmm2, xmm6 ); + xmm0 = _mm_add_ss( xmm0, xmm7 ); dst_p = dst_p + 4; - xmm0 = _mm_add_ss(xmm0, xmm1); + xmm0 = _mm_add_ss( xmm0, xmm1 ); count_l4 = count_l4 + DRAWVERT_SIZE; - xmm0 = _mm_add_ss(xmm0, xmm2); + xmm0 = _mm_add_ss( xmm0, xmm2 ); count_l1 = count_l1 - 1; - _mm_store_ss((float *) (dst_p-4), xmm0); - } while( count_l1 != 0); + _mm_store_ss( ( float * )( dst_p - 4 ), xmm0 ); + } while ( count_l1 != 0 ); } /* done: @@ -252,7 +258,7 @@ idSIMD_SSE::MinMax void VPCALL idSIMD_SSE::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, const int *indexes, const int count ) { assert( sizeof( idDrawVert ) == DRAWVERT_SIZE ); - assert( ptrdiff_t(&src->xyz) - ptrdiff_t(src) == DRAWVERT_XYZ_OFFSET ); + assert( ptrdiff_t( &src->xyz ) - ptrdiff_t( src ) == DRAWVERT_XYZ_OFFSET ); __m128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; char *indexes_p; @@ -270,13 +276,13 @@ void VPCALL idSIMD_SSE::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, movaps xmm2, xmm0 movaps xmm3, xmm1 */ - xmm0 = _mm_load_ss(&idMath::INFINITY); - // To satisfy the compiler use xmm0 instead. - xmm1 = _mm_xor_ps(xmm0, xmm0); - xmm0 = _mm_shuffle_ps(xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 )); - xmm1 = _mm_sub_ps(xmm1, xmm0); - xmm2 = xmm0; - xmm3 = xmm1; + xmm0 = _mm_load_ss( &idMath::INFINITY ); + // To satisfy the compiler use xmm0 instead. + xmm1 = _mm_xor_ps( xmm0, xmm0 ); + xmm0 = _mm_shuffle_ps( xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) ); + xmm1 = _mm_sub_ps( xmm1, xmm0 ); + xmm2 = xmm0; + xmm3 = xmm1; /* mov edi, indexes @@ -285,91 +291,91 @@ void VPCALL idSIMD_SSE::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, and eax, ~3 jz done4 */ - indexes_p = (char *) indexes; - src_p = (char *) src; - count_l = count; - count_l = count_l & ~3; - if(count_l != 0) { - /* - shl eax, 2 - add edi, eax - neg eax - */ - count_l = count_l << 2; - indexes_p = indexes_p + count_l; - count_l = -count_l; - /* - loop4: -// prefetchnta [edi+128] -// prefetchnta [esi+4*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET] - */ + indexes_p = ( char * ) indexes; + src_p = ( char * ) src; + count_l = count; + count_l = count_l & ~3; + if ( count_l != 0 ) { + /* + shl eax, 2 + add edi, eax + neg eax + */ + count_l = count_l << 2; + indexes_p = indexes_p + count_l; + count_l = -count_l; + /* + loop4: + // prefetchnta [edi+128] + // prefetchnta [esi+4*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET] + */ do { - /* - mov edx, [edi+eax+0] - imul edx, DRAWVERT_SIZE - movss xmm4, [esi+edx+DRAWVERT_XYZ_OFFSET+8] - movhps xmm4, [esi+edx+DRAWVERT_XYZ_OFFSET+0] - minps xmm0, xmm4 - maxps xmm1, xmm4 - */ - edx = *((int*)(indexes_p+count_l+0)); + /* + mov edx, [edi+eax+0] + imul edx, DRAWVERT_SIZE + movss xmm4, [esi+edx+DRAWVERT_XYZ_OFFSET+8] + movhps xmm4, [esi+edx+DRAWVERT_XYZ_OFFSET+0] + minps xmm0, xmm4 + maxps xmm1, xmm4 + */ + edx = *( ( int * )( indexes_p + count_l + 0 ) ); edx = edx * DRAWVERT_SIZE; - xmm4 = _mm_load_ss((float *) (src_p+edx+DRAWVERT_XYZ_OFFSET+8)); - xmm4 = _mm_loadh_pi(xmm4, (__m64 *) (src_p+edx+DRAWVERT_XYZ_OFFSET+0) ); - xmm0 = _mm_min_ps(xmm0, xmm4); - xmm1 = _mm_max_ps(xmm1, xmm4); - - /* - mov edx, [edi+eax+4] - imul edx, DRAWVERT_SIZE - movss xmm5, [esi+edx+DRAWVERT_XYZ_OFFSET+0] - movhps xmm5, [esi+edx+DRAWVERT_XYZ_OFFSET+4] - minps xmm2, xmm5 - maxps xmm3, xmm5 - */ - edx = *((int*)(indexes_p+count_l+4)); + xmm4 = _mm_load_ss( ( float * )( src_p + edx + DRAWVERT_XYZ_OFFSET + 8 ) ); + xmm4 = _mm_loadh_pi( xmm4, ( __m64 * )( src_p + edx + DRAWVERT_XYZ_OFFSET + 0 ) ); + xmm0 = _mm_min_ps( xmm0, xmm4 ); + xmm1 = _mm_max_ps( xmm1, xmm4 ); + + /* + mov edx, [edi+eax+4] + imul edx, DRAWVERT_SIZE + movss xmm5, [esi+edx+DRAWVERT_XYZ_OFFSET+0] + movhps xmm5, [esi+edx+DRAWVERT_XYZ_OFFSET+4] + minps xmm2, xmm5 + maxps xmm3, xmm5 + */ + edx = *( ( int * )( indexes_p + count_l + 4 ) ); edx = edx * DRAWVERT_SIZE; - xmm5 = _mm_load_ss((float *) (src_p+edx+DRAWVERT_XYZ_OFFSET+0)); - xmm5 = _mm_loadh_pi(xmm5, (__m64 *) (src_p+edx+DRAWVERT_XYZ_OFFSET+4) ); - xmm2 = _mm_min_ps(xmm2, xmm5); - xmm3 = _mm_max_ps(xmm3, xmm5); - - /* - mov edx, [edi+eax+8] - imul edx, DRAWVERT_SIZE - movss xmm6, [esi+edx+DRAWVERT_XYZ_OFFSET+8] - movhps xmm6, [esi+edx+DRAWVERT_XYZ_OFFSET+0] - minps xmm0, xmm6 - maxps xmm1, xmm6 - */ - edx = *((int*)(indexes_p+count_l+8)); + xmm5 = _mm_load_ss( ( float * )( src_p + edx + DRAWVERT_XYZ_OFFSET + 0 ) ); + xmm5 = _mm_loadh_pi( xmm5, ( __m64 * )( src_p + edx + DRAWVERT_XYZ_OFFSET + 4 ) ); + xmm2 = _mm_min_ps( xmm2, xmm5 ); + xmm3 = _mm_max_ps( xmm3, xmm5 ); + + /* + mov edx, [edi+eax+8] + imul edx, DRAWVERT_SIZE + movss xmm6, [esi+edx+DRAWVERT_XYZ_OFFSET+8] + movhps xmm6, [esi+edx+DRAWVERT_XYZ_OFFSET+0] + minps xmm0, xmm6 + maxps xmm1, xmm6 + */ + edx = *( ( int * )( indexes_p + count_l + 8 ) ); edx = edx * DRAWVERT_SIZE; - xmm6 = _mm_load_ss((float *) (src_p+edx+DRAWVERT_XYZ_OFFSET+8)); - xmm6 = _mm_loadh_pi(xmm6, (__m64 *) (src_p+edx+DRAWVERT_XYZ_OFFSET+0) ); - xmm0 = _mm_min_ps(xmm0, xmm6); - xmm1 = _mm_max_ps(xmm1, xmm6); - - /* - mov edx, [edi+eax+12] - imul edx, DRAWVERT_SIZE - movss xmm7, [esi+edx+DRAWVERT_XYZ_OFFSET+0] - movhps xmm7, [esi+edx+DRAWVERT_XYZ_OFFSET+4] - minps xmm2, xmm7 - maxps xmm3, xmm7 - */ - edx = *((int*)(indexes_p+count_l+12)); + xmm6 = _mm_load_ss( ( float * )( src_p + edx + DRAWVERT_XYZ_OFFSET + 8 ) ); + xmm6 = _mm_loadh_pi( xmm6, ( __m64 * )( src_p + edx + DRAWVERT_XYZ_OFFSET + 0 ) ); + xmm0 = _mm_min_ps( xmm0, xmm6 ); + xmm1 = _mm_max_ps( xmm1, xmm6 ); + + /* + mov edx, [edi+eax+12] + imul edx, DRAWVERT_SIZE + movss xmm7, [esi+edx+DRAWVERT_XYZ_OFFSET+0] + movhps xmm7, [esi+edx+DRAWVERT_XYZ_OFFSET+4] + minps xmm2, xmm7 + maxps xmm3, xmm7 + */ + edx = *( ( int * )( indexes_p + count_l + 12 ) ); edx = edx * DRAWVERT_SIZE; - xmm7 = _mm_load_ss((float *) (src_p+edx+DRAWVERT_XYZ_OFFSET+0)); - xmm7 = _mm_loadh_pi(xmm7, (__m64 *) (src_p+edx+DRAWVERT_XYZ_OFFSET+4) ); - xmm2 = _mm_min_ps(xmm2, xmm7); - xmm3 = _mm_max_ps(xmm3, xmm7); - - /* - add eax, 4*4 - jl loop4 - */ - count_l = count_l + 4*4; - } while (count_l < 0); + xmm7 = _mm_load_ss( ( float * )( src_p + edx + DRAWVERT_XYZ_OFFSET + 0 ) ); + xmm7 = _mm_loadh_pi( xmm7, ( __m64 * )( src_p + edx + DRAWVERT_XYZ_OFFSET + 4 ) ); + xmm2 = _mm_min_ps( xmm2, xmm7 ); + xmm3 = _mm_max_ps( xmm3, xmm7 ); + + /* + add eax, 4*4 + jl loop4 + */ + count_l = count_l + 4 * 4; + } while ( count_l < 0 ); } /* done4: @@ -379,40 +385,40 @@ void VPCALL idSIMD_SSE::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, */ count_l = count; count_l = count_l & 3; - if(count_l != 0) { - /* - shl eax, 2 - add edi, eax - neg eax - */ + if ( count_l != 0 ) { + /* + shl eax, 2 + add edi, eax + neg eax + */ count_l = count_l << 2; indexes_p = indexes_p + count_l; count_l = -count_l; - /* - loop1: - */ - do{ - /* - mov edx, [edi+eax+0] - imul edx, DRAWVERT_SIZE; - movss xmm4, [esi+edx+DRAWVERT_XYZ_OFFSET+8] - movhps xmm4, [esi+edx+DRAWVERT_XYZ_OFFSET+0] - minps xmm0, xmm4 - maxps xmm1, xmm4 - */ - edx = *((int*)(indexes_p+count_l+0)); + /* + loop1: + */ + do { + /* + mov edx, [edi+eax+0] + imul edx, DRAWVERT_SIZE; + movss xmm4, [esi+edx+DRAWVERT_XYZ_OFFSET+8] + movhps xmm4, [esi+edx+DRAWVERT_XYZ_OFFSET+0] + minps xmm0, xmm4 + maxps xmm1, xmm4 + */ + edx = *( ( int * )( indexes_p + count_l + 0 ) ); edx = edx * DRAWVERT_SIZE; - xmm4 = _mm_load_ss((float *) (src_p+edx+DRAWVERT_XYZ_OFFSET+8)); - xmm4 = _mm_loadh_pi(xmm4, (__m64 *) (src_p+edx+DRAWVERT_XYZ_OFFSET+0) ); - xmm0 = _mm_min_ps(xmm0, xmm4); - xmm1 = _mm_max_ps(xmm1, xmm4); - - /* - add eax, 4 - jl loop1 - */ + xmm4 = _mm_load_ss( ( float * )( src_p + edx + DRAWVERT_XYZ_OFFSET + 8 ) ); + xmm4 = _mm_loadh_pi( xmm4, ( __m64 * )( src_p + edx + DRAWVERT_XYZ_OFFSET + 0 ) ); + xmm0 = _mm_min_ps( xmm0, xmm4 ); + xmm1 = _mm_max_ps( xmm1, xmm4 ); + + /* + add eax, 4 + jl loop1 + */ count_l = count_l + 4; - } while (count_l < 0); + } while ( count_l < 0 ); } @@ -429,16 +435,16 @@ void VPCALL idSIMD_SSE::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, movhps [edi], xmm1 movss [edi+8], xmm1 */ - xmm2 = _mm_shuffle_ps(xmm2, xmm2, R_SHUFFLEPS( 3, 1, 0, 2 )); - xmm3 = _mm_shuffle_ps(xmm3, xmm3, R_SHUFFLEPS( 3, 1, 0, 2 )); - xmm0 = _mm_min_ps(xmm0, xmm2); - xmm1 = _mm_max_ps(xmm1, xmm3); - min_p = (char *) &min; - _mm_storeh_pi((__m64 *)(min_p), xmm0); - _mm_store_ss((float *)(min_p+8), xmm0); - max_p = (char *) &max; - _mm_storeh_pi((__m64 *)(max_p), xmm1); - _mm_store_ss((float *)(max_p+8), xmm1); + xmm2 = _mm_shuffle_ps( xmm2, xmm2, R_SHUFFLEPS( 3, 1, 0, 2 ) ); + xmm3 = _mm_shuffle_ps( xmm3, xmm3, R_SHUFFLEPS( 3, 1, 0, 2 ) ); + xmm0 = _mm_min_ps( xmm0, xmm2 ); + xmm1 = _mm_max_ps( xmm1, xmm3 ); + min_p = ( char * ) &min; + _mm_storeh_pi( ( __m64 * )( min_p ), xmm0 ); + _mm_store_ss( ( float * )( min_p + 8 ), xmm0 ); + max_p = ( char * ) &max; + _mm_storeh_pi( ( __m64 * )( max_p ), xmm1 ); + _mm_store_ss( ( float * )( max_p + 8 ), xmm1 ); } /* @@ -473,10 +479,10 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idPlane * and eax, ~3 */ count_l4 = count; - constant_p = (char *) &constant; + constant_p = ( char * ) &constant; count_l1 = count_l4; - src_p = (char *) src; - dst_p = (char *) dst; + src_p = ( char * ) src; + dst_p = ( char * ) dst; count_l4 = count_l4 & ~3; /* @@ -487,91 +493,91 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idPlane * movss xmm7, [edi+8] shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) */ - xmm5 = _mm_load_ss((float *) (constant_p+0)); - xmm5 = _mm_shuffle_ps(xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 )); - xmm6 = _mm_load_ss((float *) (constant_p+4)); - xmm6 = _mm_shuffle_ps(xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 )); - xmm7 = _mm_load_ss((float *) (constant_p+8)); - xmm7 = _mm_shuffle_ps(xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 )); + xmm5 = _mm_load_ss( ( float * )( constant_p + 0 ) ); + xmm5 = _mm_shuffle_ps( xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) ); + xmm6 = _mm_load_ss( ( float * )( constant_p + 4 ) ); + xmm6 = _mm_shuffle_ps( xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) ); + xmm7 = _mm_load_ss( ( float * )( constant_p + 8 ) ); + xmm7 = _mm_shuffle_ps( xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) ); /* jz startVert1 */ - if (count_l4 != 0) { - /* - imul eax, 16 - add esi, eax - neg eax - */ + if ( count_l4 != 0 ) { + /* + imul eax, 16 + add esi, eax + neg eax + */ count_l4 = count_l4 * 16; src_p = src_p + count_l4; count_l4 = -count_l4; - /* - loopVert4: - */ + /* + loopVert4: + */ do { - /* - movlps xmm1, [esi+eax+ 0] - movlps xmm3, [esi+eax+ 8] - movhps xmm1, [esi+eax+16] - movhps xmm3, [esi+eax+24] - movlps xmm2, [esi+eax+32] - movlps xmm4, [esi+eax+40] - movhps xmm2, [esi+eax+48] - movhps xmm4, [esi+eax+56] - movaps xmm0, xmm1 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm1, xmm2, R_SHUFFLEPS( 1, 3, 1, 3 ) - movaps xmm2, xmm3 - shufps xmm2, xmm4, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm3, xmm4, R_SHUFFLEPS( 1, 3, 1, 3 ) - */ - xmm1 = _mm_loadl_pi(xmm1, (__m64 *)(src_p+count_l4+ 0)); - xmm3 = _mm_loadl_pi(xmm3, (__m64 *)(src_p+count_l4+ 8)); - xmm1 = _mm_loadh_pi(xmm1, (__m64 *)(src_p+count_l4+16)); - xmm3 = _mm_loadh_pi(xmm3, (__m64 *)(src_p+count_l4+24)); - xmm2 = _mm_loadl_pi(xmm2, (__m64 *)(src_p+count_l4+32)); - xmm4 = _mm_loadl_pi(xmm4, (__m64 *)(src_p+count_l4+40)); - xmm2 = _mm_loadh_pi(xmm2, (__m64 *)(src_p+count_l4+48)); - xmm4 = _mm_loadh_pi(xmm4, (__m64 *)(src_p+count_l4+56)); + /* + movlps xmm1, [esi+eax+ 0] + movlps xmm3, [esi+eax+ 8] + movhps xmm1, [esi+eax+16] + movhps xmm3, [esi+eax+24] + movlps xmm2, [esi+eax+32] + movlps xmm4, [esi+eax+40] + movhps xmm2, [esi+eax+48] + movhps xmm4, [esi+eax+56] + movaps xmm0, xmm1 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm1, xmm2, R_SHUFFLEPS( 1, 3, 1, 3 ) + movaps xmm2, xmm3 + shufps xmm2, xmm4, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm3, xmm4, R_SHUFFLEPS( 1, 3, 1, 3 ) + */ + xmm1 = _mm_loadl_pi( xmm1, ( __m64 * )( src_p + count_l4 + 0 ) ); + xmm3 = _mm_loadl_pi( xmm3, ( __m64 * )( src_p + count_l4 + 8 ) ); + xmm1 = _mm_loadh_pi( xmm1, ( __m64 * )( src_p + count_l4 + 16 ) ); + xmm3 = _mm_loadh_pi( xmm3, ( __m64 * )( src_p + count_l4 + 24 ) ); + xmm2 = _mm_loadl_pi( xmm2, ( __m64 * )( src_p + count_l4 + 32 ) ); + xmm4 = _mm_loadl_pi( xmm4, ( __m64 * )( src_p + count_l4 + 40 ) ); + xmm2 = _mm_loadh_pi( xmm2, ( __m64 * )( src_p + count_l4 + 48 ) ); + xmm4 = _mm_loadh_pi( xmm4, ( __m64 * )( src_p + count_l4 + 56 ) ); xmm0 = xmm1; - xmm0 = _mm_shuffle_ps(xmm0, xmm2, R_SHUFFLEPS( 0, 2, 0, 2 )); - xmm1 = _mm_shuffle_ps(xmm1, xmm2, R_SHUFFLEPS( 1, 3, 1, 3 )); + xmm0 = _mm_shuffle_ps( xmm0, xmm2, R_SHUFFLEPS( 0, 2, 0, 2 ) ); + xmm1 = _mm_shuffle_ps( xmm1, xmm2, R_SHUFFLEPS( 1, 3, 1, 3 ) ); xmm2 = xmm3; - xmm2 = _mm_shuffle_ps(xmm2, xmm4, R_SHUFFLEPS( 0, 2, 0, 2 )); - xmm3 = _mm_shuffle_ps(xmm3, xmm4, R_SHUFFLEPS( 1, 3, 1, 3 )); + xmm2 = _mm_shuffle_ps( xmm2, xmm4, R_SHUFFLEPS( 0, 2, 0, 2 ) ); + xmm3 = _mm_shuffle_ps( xmm3, xmm4, R_SHUFFLEPS( 1, 3, 1, 3 ) ); - /* - add ecx, 16 - add eax, 4*16 - */ + /* + add ecx, 16 + add eax, 4*16 + */ dst_p = dst_p + 16; - count_l4 = count_l4 + 4*16; - - /* - mulps xmm0, xmm5 - mulps xmm1, xmm6 - mulps xmm2, xmm7 - addps xmm0, xmm3 - addps xmm0, xmm1 - addps xmm0, xmm2 - */ - xmm0 = _mm_mul_ps(xmm0, xmm5); - xmm1 = _mm_mul_ps(xmm1, xmm6); - xmm2 = _mm_mul_ps(xmm2, xmm7); - xmm0 = _mm_add_ps(xmm0, xmm3); - xmm0 = _mm_add_ps(xmm0, xmm1); - xmm0 = _mm_add_ps(xmm0, xmm2); + count_l4 = count_l4 + 4 * 16; - /* - movlps [ecx-16+0], xmm0 - movhps [ecx-16+8], xmm0 - jl loopVert4 - */ - _mm_storel_pi((__m64 *) (dst_p-16+0), xmm0); - _mm_storeh_pi((__m64 *) (dst_p-16+8), xmm0); - } while (count_l4 < 0); + /* + mulps xmm0, xmm5 + mulps xmm1, xmm6 + mulps xmm2, xmm7 + addps xmm0, xmm3 + addps xmm0, xmm1 + addps xmm0, xmm2 + */ + xmm0 = _mm_mul_ps( xmm0, xmm5 ); + xmm1 = _mm_mul_ps( xmm1, xmm6 ); + xmm2 = _mm_mul_ps( xmm2, xmm7 ); + xmm0 = _mm_add_ps( xmm0, xmm3 ); + xmm0 = _mm_add_ps( xmm0, xmm1 ); + xmm0 = _mm_add_ps( xmm0, xmm2 ); + + /* + movlps [ecx-16+0], xmm0 + movhps [ecx-16+8], xmm0 + jl loopVert4 + */ + _mm_storel_pi( ( __m64 * )( dst_p - 16 + 0 ), xmm0 ); + _mm_storeh_pi( ( __m64 * )( dst_p - 16 + 8 ), xmm0 ); + } while ( count_l4 < 0 ); } /* @@ -581,61 +587,156 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idPlane * */ count_l1 = count_l1 & 3; - if(count_l1 != 0) { - /* - loopVert1: - */ + if ( count_l1 != 0 ) { + /* + loopVert1: + */ do { - /* - movss xmm0, [esi+eax+0] - movss xmm1, [esi+eax+4] - movss xmm2, [esi+eax+8] - mulss xmm0, xmm5 - mulss xmm1, xmm6 - mulss xmm2, xmm7 - addss xmm0, [esi+eax+12] - add ecx, 4 - addss xmm0, xmm1 - add eax, 16 - addss xmm0, xmm2 - dec edx - movss [ecx-4], xmm0 - jnz loopVert1 - */ - xmm0 = _mm_load_ss((float *) (src_p+count_l4+ 0)); - xmm1 = _mm_load_ss((float *) (src_p+count_l4+ 4)); - xmm2 = _mm_load_ss((float *) (src_p+count_l4+ 8)); - xmm3 = _mm_load_ss((float *) (src_p+count_l4+12)); - - xmm0 = _mm_mul_ss(xmm0, xmm5); - xmm1 = _mm_mul_ss(xmm1, xmm6); - xmm2 = _mm_mul_ss(xmm2, xmm7); - - xmm0 = _mm_add_ss(xmm0, xmm3); + /* + movss xmm0, [esi+eax+0] + movss xmm1, [esi+eax+4] + movss xmm2, [esi+eax+8] + mulss xmm0, xmm5 + mulss xmm1, xmm6 + mulss xmm2, xmm7 + addss xmm0, [esi+eax+12] + add ecx, 4 + addss xmm0, xmm1 + add eax, 16 + addss xmm0, xmm2 + dec edx + movss [ecx-4], xmm0 + jnz loopVert1 + */ + xmm0 = _mm_load_ss( ( float * )( src_p + count_l4 + 0 ) ); + xmm1 = _mm_load_ss( ( float * )( src_p + count_l4 + 4 ) ); + xmm2 = _mm_load_ss( ( float * )( src_p + count_l4 + 8 ) ); + xmm3 = _mm_load_ss( ( float * )( src_p + count_l4 + 12 ) ); + + xmm0 = _mm_mul_ss( xmm0, xmm5 ); + xmm1 = _mm_mul_ss( xmm1, xmm6 ); + xmm2 = _mm_mul_ss( xmm2, xmm7 ); + + xmm0 = _mm_add_ss( xmm0, xmm3 ); dst_p = dst_p + 4; - xmm0 = _mm_add_ss(xmm0, xmm1); + xmm0 = _mm_add_ss( xmm0, xmm1 ); count_l4 = count_l4 + 16; - xmm0 = _mm_add_ss(xmm0, xmm2); + xmm0 = _mm_add_ss( xmm0, xmm2 ); count_l1 = count_l1 - 1; - _mm_store_ss((float *) (dst_p-4), xmm0); - } while (count_l1 != 0); + _mm_store_ss( ( float * )( dst_p - 4 ), xmm0 ); + } while ( count_l1 != 0 ); } /* done: */ } +/* +============ +idSIMD_SSE::CullByFrustum +============ +*/ +void VPCALL idSIMD_SSE::CullByFrustum( idDrawVert *verts, const int numVerts, const idPlane frustum[6], byte *pointCull, float epsilon ) { + __m128 fA14 = _mm_set_ps( frustum[3][0], frustum[2][0], frustum[1][0], frustum[0][0] ); + __m128 fA56 = _mm_set_ps( 0, 0, frustum[5][0], frustum[4][0] ); + __m128 fB14 = _mm_set_ps( frustum[3][1], frustum[2][1], frustum[1][1], frustum[0][1] ); + __m128 fB56 = _mm_set_ps( 0, 0, frustum[5][1], frustum[4][1] ); + __m128 fC14 = _mm_set_ps( frustum[3][2], frustum[2][2], frustum[1][2], frustum[0][2] ); + __m128 fC56 = _mm_set_ps( 0, 0, frustum[5][2], frustum[4][2] ); + __m128 fD14 = _mm_set_ps( frustum[3][3], frustum[2][3], frustum[1][3], frustum[0][3] ); + __m128 fD56 = _mm_set_ps( 0, 0, frustum[5][3], frustum[4][3] ); + + for ( int j = 0; j < numVerts; j++ ) { + idVec3 &vec = verts[j].xyz; + __m128 vX = _mm_set1_ps( vec.x ); + __m128 vY = _mm_set1_ps( vec.y ); + __m128 vZ = _mm_set1_ps( vec.z ); + __m128 d14 = _mm_add_ps( + _mm_add_ps( + _mm_mul_ps( fA14, vX ), + _mm_mul_ps( fB14, vY ) + ), + _mm_add_ps( + _mm_mul_ps( fC14, vZ ), + fD14 + ) + ); + __m128 d56 = _mm_add_ps( + _mm_add_ps( + _mm_mul_ps( fA56, vX ), + _mm_mul_ps( fB56, vY ) + ), + _mm_add_ps( + _mm_mul_ps( fC56, vZ ), + fD56 + ) + ); + const short mask6 = ( 1 << 6 ) - 1; + __m128 eps = _mm_set1_ps( epsilon ); + int mask_lo14 = _mm_movemask_ps( _mm_cmplt_ps( d14, eps ) ); + int mask_lo56 = _mm_movemask_ps( _mm_cmplt_ps( d56, eps ) ); + int mask_lo = mask_lo14 | mask_lo56 << 4; + pointCull[j] = ( mask_lo & mask6 ); // gcc compiler warning + } +} + +/* +============ +idSIMD_SSE::CullByFrustum2 +============ +*/ +void VPCALL idSIMD_SSE::CullByFrustum2( idDrawVert *verts, const int numVerts, const idPlane frustum[6], unsigned short *pointCull, float epsilon ) { + __m128 fA14 = _mm_set_ps( frustum[3][0], frustum[2][0], frustum[1][0], frustum[0][0] ); + __m128 fA56 = _mm_set_ps( 0, 0, frustum[5][0], frustum[4][0] ); + __m128 fB14 = _mm_set_ps( frustum[3][1], frustum[2][1], frustum[1][1], frustum[0][1] ); + __m128 fB56 = _mm_set_ps( 0, 0, frustum[5][1], frustum[4][1] ); + __m128 fC14 = _mm_set_ps( frustum[3][2], frustum[2][2], frustum[1][2], frustum[0][2] ); + __m128 fC56 = _mm_set_ps( 0, 0, frustum[5][2], frustum[4][2] ); + __m128 fD14 = _mm_set_ps( frustum[3][3], frustum[2][3], frustum[1][3], frustum[0][3] ); + __m128 fD56 = _mm_set_ps( 0, 0, frustum[5][3], frustum[4][3] ); + + for ( int j = 0; j < numVerts; j++ ) { + idVec3 &vec = verts[j].xyz; + __m128 vX = _mm_set1_ps( vec.x ); + __m128 vY = _mm_set1_ps( vec.y ); + __m128 vZ = _mm_set1_ps( vec.z ); + __m128 d14 = _mm_add_ps( + _mm_add_ps( + _mm_mul_ps( fA14, vX ), + _mm_mul_ps( fB14, vY ) + ), + _mm_add_ps( + _mm_mul_ps( fC14, vZ ), + fD14 + ) + ); + __m128 d56 = _mm_add_ps( + _mm_add_ps( + _mm_mul_ps( fA56, vX ), + _mm_mul_ps( fB56, vY ) + ), + _mm_add_ps( + _mm_mul_ps( fC56, vZ ), + fD56 + ) + ); + const short mask6 = ( 1 << 6 ) - 1; + __m128 eps = _mm_set1_ps( epsilon ); + int mask_lo14 = _mm_movemask_ps( _mm_cmplt_ps( d14, eps ) ); + int mask_lo56 = _mm_movemask_ps( _mm_cmplt_ps( d56, eps ) ); + eps = _mm_set1_ps( -epsilon ); + int mask_hi14 = _mm_movemask_ps( _mm_cmpgt_ps( d14, eps ) ); + int mask_hi56 = _mm_movemask_ps( _mm_cmpgt_ps( d56, eps ) ); + int mask_lo = mask_lo14 | mask_lo56 << 4; + int mask_hi = mask_hi14 | mask_hi56 << 4; + pointCull[j] = ( ( mask_lo & mask6 ) | ( mask_hi & mask6 ) << 6 ); // gcc compiler warning + } +} + #elif defined(_MSC_VER) && defined(_M_IX86) #include -#include "idlib/geometry/JointTransform.h" -#include "idlib/math/Vector.h" -#include "idlib/math/Matrix.h" -#include "idlib/math/Quat.h" -#include "idlib/math/Plane.h" -#include "renderer/Model.h" - #define SHUFFLEPS( x, y, z, w ) (( (x) & 3 ) << 6 | ( (y) & 3 ) << 4 | ( (z) & 3 ) << 2 | ( (w) & 3 )) #define R_SHUFFLEPS( x, y, z, w ) (( (w) & 3 ) << 6 | ( (z) & 3 ) << 4 | ( (y) & 3 ) << 2 | ( (x) & 3 )) @@ -1020,17 +1121,17 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idPlane * #define ALIGN8_INIT1( X, INIT ) ALIGN16( static X[8] ) = { INIT, INIT, INIT, INIT, INIT, INIT, INIT, INIT } ALIGN8_INIT1( unsigned short SIMD_W_zero, 0 ); -ALIGN8_INIT1( unsigned short SIMD_W_maxShort, 1<<15 ); +ALIGN8_INIT1( unsigned short SIMD_W_maxShort, 1 << 15 ); -ALIGN4_INIT1( unsigned int SIMD_DW_mat2quatShuffle0, (3<<0)|(2<<8)|(1<<16)|(0<<24) ); -ALIGN4_INIT1( unsigned int SIMD_DW_mat2quatShuffle1, (0<<0)|(1<<8)|(2<<16)|(3<<24) ); -ALIGN4_INIT1( unsigned int SIMD_DW_mat2quatShuffle2, (1<<0)|(0<<8)|(3<<16)|(2<<24) ); -ALIGN4_INIT1( unsigned int SIMD_DW_mat2quatShuffle3, (2<<0)|(3<<8)|(0<<16)|(1<<24) ); +ALIGN4_INIT1( unsigned int SIMD_DW_mat2quatShuffle0, ( 3 << 0 ) | ( 2 << 8 ) | ( 1 << 16 ) | ( 0 << 24 ) ); +ALIGN4_INIT1( unsigned int SIMD_DW_mat2quatShuffle1, ( 0 << 0 ) | ( 1 << 8 ) | ( 2 << 16 ) | ( 3 << 24 ) ); +ALIGN4_INIT1( unsigned int SIMD_DW_mat2quatShuffle2, ( 1 << 0 ) | ( 0 << 8 ) | ( 3 << 16 ) | ( 2 << 24 ) ); +ALIGN4_INIT1( unsigned int SIMD_DW_mat2quatShuffle3, ( 2 << 0 ) | ( 3 << 8 ) | ( 0 << 16 ) | ( 1 << 24 ) ); -ALIGN4_INIT4( unsigned int SIMD_SP_singleSignBitMask, (unsigned int) ( 1 << 31 ), 0, 0, 0 ); -ALIGN4_INIT1( unsigned int SIMD_SP_signBitMask, (unsigned int) ( 1 << 31 ) ); -ALIGN4_INIT1( unsigned int SIMD_SP_absMask, (unsigned int) ~( 1 << 31 ) ); -ALIGN4_INIT1( unsigned int SIMD_SP_infinityMask, (unsigned int) ~( 1 << 23 ) ); +ALIGN4_INIT4( unsigned int SIMD_SP_singleSignBitMask, ( unsigned int )( 1 << 31 ), 0, 0, 0 ); +ALIGN4_INIT1( unsigned int SIMD_SP_signBitMask, ( unsigned int )( 1 << 31 ) ); +ALIGN4_INIT1( unsigned int SIMD_SP_absMask, ( unsigned int ) ~( 1 << 31 ) ); +ALIGN4_INIT1( unsigned int SIMD_SP_infinityMask, ( unsigned int ) ~( 1 << 23 ) ); ALIGN4_INIT1( unsigned int SIMD_SP_not, 0xFFFFFFFF ); ALIGN4_INIT1( float SIMD_SP_zero, 0.0f ); @@ -1039,7 +1140,7 @@ ALIGN4_INIT1( float SIMD_SP_one, 1.0f ); ALIGN4_INIT1( float SIMD_SP_two, 2.0f ); ALIGN4_INIT1( float SIMD_SP_three, 3.0f ); ALIGN4_INIT1( float SIMD_SP_four, 4.0f ); -ALIGN4_INIT1( float SIMD_SP_maxShort, (1<<15) ); +ALIGN4_INIT1( float SIMD_SP_maxShort, ( 1 << 15 ) ); ALIGN4_INIT1( float SIMD_SP_tiny, 1e-10f ); ALIGN4_INIT1( float SIMD_SP_PI, idMath::PI ); ALIGN4_INIT1( float SIMD_SP_halfPI, idMath::HALF_PI ); @@ -1050,7 +1151,7 @@ ALIGN4_INIT4( float SIMD_SP_lastOne, 0.0f, 0.0f, 0.0f, 1.0f ); ALIGN4_INIT1( float SIMD_SP_rsqrt_c0, 3.0f ); ALIGN4_INIT1( float SIMD_SP_rsqrt_c1, -0.5f ); -ALIGN4_INIT1( float SIMD_SP_mat2quat_rsqrt_c1, -0.5f*0.5f ); +ALIGN4_INIT1( float SIMD_SP_mat2quat_rsqrt_c1, -0.5f * 0.5f ); ALIGN4_INIT1( float SIMD_SP_sin_c0, -2.39e-08f ); ALIGN4_INIT1( float SIMD_SP_sin_c1, 2.7526e-06f ); @@ -1955,7 +2056,7 @@ float SSE_ATan( float y, float x ) { if ( fabs( y ) > fabs( x ) ) { a = -x / y; d = idMath::HALF_PI; - *((unsigned int *)&d) ^= ( *((unsigned int *)&x) ^ *((unsigned int *)&y) ) & (1<<31); + *( ( unsigned int * )&d ) ^= ( *( ( unsigned int * )&x ) ^ * ( ( unsigned int * )&y ) ) & ( 1 << 31 ); } else { a = y / x; d = 0.0f; @@ -2101,7 +2202,7 @@ void SSE_TestTrigonometry( void ) { idSIMD_SSE::GetName ============ */ -const char * idSIMD_SSE::GetName( void ) const { +const char *idSIMD_SSE::GetName( void ) const { return "MMX & SSE"; } @@ -2182,63 +2283,62 @@ void VPCALL idSIMD_SSE::Div( float *dst, const float constant, const float *src, int pre, post; // 1 / x = 2 * rcpps(x) - (x * rcpps(x) * rcpps(x)); - __asm - { - movss xmm1,constant - shufps xmm1,xmm1,0 + __asm { + movss xmm1, constant + shufps xmm1, xmm1, 0 KFLOATINITDS( dst, src, count, pre, post ) - and eax,15 + and eax, 15 jne lpNA jmp lpA align 16 -lpA: - movaps xmm2,[edx+ebx] - movaps xmm3,[edx+ebx+16] - rcpps xmm4,xmm2 - rcpps xmm5,xmm3 - prefetchnta [edx+ebx+64] - mulps xmm2,xmm4 - mulps xmm2,xmm4 - mulps xmm3,xmm5 - mulps xmm3,xmm5 - addps xmm4,xmm4 - addps xmm5,xmm5 - subps xmm4,xmm2 - subps xmm5,xmm3 - mulps xmm4,xmm1 - mulps xmm5,xmm1 - movaps [edi+ebx],xmm4 - movaps [edi+ebx+16],xmm5 - add ebx,16*2 + lpA: + movaps xmm2, [edx + ebx] + movaps xmm3, [edx + ebx + 16] + rcpps xmm4, xmm2 + rcpps xmm5, xmm3 + prefetchnta [edx + ebx + 64] + mulps xmm2, xmm4 + mulps xmm2, xmm4 + mulps xmm3, xmm5 + mulps xmm3, xmm5 + addps xmm4, xmm4 + addps xmm5, xmm5 + subps xmm4, xmm2 + subps xmm5, xmm3 + mulps xmm4, xmm1 + mulps xmm5, xmm1 + movaps [edi + ebx], xmm4 + movaps [edi + ebx + 16], xmm5 + add ebx, 16 * 2 jl lpA jmp done align 16 -lpNA: - movups xmm2,[edx+ebx] - movups xmm3,[edx+ebx+16] - rcpps xmm4,xmm2 - rcpps xmm5,xmm3 - prefetchnta [edx+ebx+64] - mulps xmm2,xmm4 - mulps xmm2,xmm4 - mulps xmm3,xmm5 - mulps xmm3,xmm5 - addps xmm4,xmm4 - addps xmm5,xmm5 - subps xmm4,xmm2 - subps xmm5,xmm3 - mulps xmm4,xmm1 - mulps xmm5,xmm1 - movaps [edi+ebx],xmm4 - movaps [edi+ebx+16],xmm5 - add ebx,16*2 + lpNA: + movups xmm2, [edx + ebx] + movups xmm3, [edx + ebx + 16] + rcpps xmm4, xmm2 + rcpps xmm5, xmm3 + prefetchnta [edx + ebx + 64] + mulps xmm2, xmm4 + mulps xmm2, xmm4 + mulps xmm3, xmm5 + mulps xmm3, xmm5 + addps xmm4, xmm4 + addps xmm5, xmm5 + subps xmm4, xmm2 + subps xmm5, xmm3 + mulps xmm4, xmm1 + mulps xmm5, xmm1 + movaps [edi + ebx], xmm4 + movaps [edi + ebx + 16], xmm5 + add ebx, 16 * 2 jl lpNA -done: - mov edx,src - mov edi,dst - KFLOATOPER( KDIVDSS1( [edi+ebx],xmm1,[edx+ebx] ), - KDIVDSS4( [edi+ebx],xmm1,[edx+ebx] ), count ) + done: + mov edx, src + mov edi, dst + KFLOATOPER( KDIVDSS1( [edi + ebx], xmm1, [edx + ebx] ), + KDIVDSS4( [edi + ebx], xmm1, [edx + ebx] ), count ) } } @@ -2250,66 +2350,65 @@ idSIMD_SSE::Div ============ */ void VPCALL idSIMD_SSE::Div( float *dst, const float *src0, const float *src1, const int count ) { - int pre,post; + int pre, post; // 1 / x = 2 * rcpps(x) - (x * rcpps(x) * rcpps(x)); - __asm - { + __asm { KFLOATINITDSS( dst, src0, src1, count, pre, post ) - and eax,15 + and eax, 15 jne lpNA jmp lpA align 16 -lpA: - movaps xmm2,[esi+ebx] - movaps xmm3,[esi+ebx+16] - rcpps xmm4,xmm2 - rcpps xmm5,xmm3 - prefetchnta [esi+ebx+64] - mulps xmm2,xmm4 - mulps xmm2,xmm4 - mulps xmm3,xmm5 - mulps xmm3,xmm5 - addps xmm4,xmm4 - addps xmm5,xmm5 - subps xmm4,xmm2 - subps xmm5,xmm3 - mulps xmm4,[edx+ebx] - mulps xmm5,[edx+ebx+16] - movaps [edi+ebx],xmm4 - movaps [edi+ebx+16],xmm5 - add ebx,16*2 + lpA: + movaps xmm2, [esi + ebx] + movaps xmm3, [esi + ebx + 16] + rcpps xmm4, xmm2 + rcpps xmm5, xmm3 + prefetchnta [esi + ebx + 64] + mulps xmm2, xmm4 + mulps xmm2, xmm4 + mulps xmm3, xmm5 + mulps xmm3, xmm5 + addps xmm4, xmm4 + addps xmm5, xmm5 + subps xmm4, xmm2 + subps xmm5, xmm3 + mulps xmm4, [edx + ebx] + mulps xmm5, [edx + ebx + 16] + movaps [edi + ebx], xmm4 + movaps [edi + ebx + 16], xmm5 + add ebx, 16 * 2 jl lpA jmp done align 16 -lpNA: - movups xmm2,[esi+ebx] - movups xmm3,[esi+ebx+16] - rcpps xmm4,xmm2 - rcpps xmm5,xmm3 - prefetchnta [esi+ebx+64] - mulps xmm2,xmm4 - mulps xmm2,xmm4 - mulps xmm3,xmm5 - mulps xmm3,xmm5 - addps xmm4,xmm4 - addps xmm5,xmm5 - subps xmm4,xmm2 - subps xmm5,xmm3 - movups xmm2,[edx+ebx] - movups xmm3,[edx+ebx+16] - mulps xmm4,xmm2 - mulps xmm5,xmm3 - movaps [edi+ebx],xmm4 - movaps [edi+ebx+16],xmm5 - add ebx,16*2 + lpNA: + movups xmm2, [esi + ebx] + movups xmm3, [esi + ebx + 16] + rcpps xmm4, xmm2 + rcpps xmm5, xmm3 + prefetchnta [esi + ebx + 64] + mulps xmm2, xmm4 + mulps xmm2, xmm4 + mulps xmm3, xmm5 + mulps xmm3, xmm5 + addps xmm4, xmm4 + addps xmm5, xmm5 + subps xmm4, xmm2 + subps xmm5, xmm3 + movups xmm2, [edx + ebx] + movups xmm3, [edx + ebx + 16] + mulps xmm4, xmm2 + mulps xmm5, xmm3 + movaps [edi + ebx], xmm4 + movaps [edi + ebx + 16], xmm5 + add ebx, 16 * 2 jl lpNA -done: - mov edx,src0 - mov esi,src1 - mov edi,dst - KFLOATOPER( KDIVDSS1( [edi+ebx],[edx+ebx],[esi+ebx] ), - KDIVDSS4( [edi+ebx],[edx+ebx],[esi+ebx] ), count ) + done: + mov edx, src0 + mov esi, src1 + mov edi, dst + KFLOATOPER( KDIVDSS1( [edi + ebx], [edx + ebx], [esi + ebx] ), + KDIVDSS4( [edi + ebx], [edx + ebx], [esi + ebx] ), count ) } } /* @@ -2530,8 +2629,7 @@ idSIMD_SSE::Dot ============ */ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idVec3 *src, const int count ) { - __asm - { + __asm { mov eax, count mov edi, constant mov edx, eax @@ -2541,9 +2639,9 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idVec3 *s movss xmm4, [edi+0] shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm5, [edi+4] + movss xmm5, [edi + 4] shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm6, [edi+8] + movss xmm6, [edi + 8] shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) jz done4 @@ -2551,37 +2649,37 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idVec3 *s add esi, eax neg eax - loop4: - movlps xmm1, [esi+eax+ 0] - movlps xmm2, [esi+eax+ 8] - movlps xmm3, [esi+eax+16] - movhps xmm1, [esi+eax+24] - movhps xmm2, [esi+eax+32] - movhps xmm3, [esi+eax+40] + loop4: + movlps xmm1, [esi + eax + 0] + movlps xmm2, [esi + eax + 8] + movlps xmm3, [esi + eax + 16] + movhps xmm1, [esi + eax + 24] + movhps xmm2, [esi + eax + 32] + movhps xmm3, [esi + eax + 40] movaps xmm0, xmm1 shufps xmm0, xmm2, R_SHUFFLEPS( 0, 2, 1, 3 ) shufps xmm1, xmm3, R_SHUFFLEPS( 1, 3, 0, 2 ) shufps xmm2, xmm3, R_SHUFFLEPS( 0, 2, 1, 3 ) add ecx, 16 - add eax, 4*12 + add eax, 4 * 12 mulps xmm0, xmm4 mulps xmm1, xmm5 mulps xmm2, xmm6 addps xmm0, xmm1 addps xmm0, xmm2 shufps xmm0, xmm0, R_SHUFFLEPS( 0, 2, 1, 3 ) - movlps [ecx-16+0], xmm0 - movhps [ecx-16+8], xmm0 + movlps [ecx - 16 + 0], xmm0 + movhps [ecx - 16 + 8], xmm0 jl loop4 - done4: + done4: and edx, 3 jz done1 - loop1: - movss xmm0, [esi+eax+0] - movss xmm1, [esi+eax+4] - movss xmm2, [esi+eax+8] + loop1: + movss xmm0, [esi + eax + 0] + movss xmm1, [esi + eax + 4] + movss xmm2, [esi + eax + 8] mulss xmm0, xmm4 mulss xmm1, xmm5 mulss xmm2, xmm6 @@ -2590,10 +2688,10 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idVec3 *s add eax, 12 addss xmm0, xmm2 dec edx - movss [ecx-4], xmm0 + movss [ecx - 4], xmm0 jnz loop1 - done1: + done1: } } @@ -2615,9 +2713,9 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idPlane * movss xmm5, [edi+0] shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm6, [edi+4] + movss xmm6, [edi + 4] shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm7, [edi+8] + movss xmm7, [edi + 8] shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) jz startVert1 @@ -2625,16 +2723,16 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idPlane * add esi, eax neg eax - loopVert4: + loopVert4: - movlps xmm1, [esi+eax+ 0] - movlps xmm3, [esi+eax+ 8] - movhps xmm1, [esi+eax+16] - movhps xmm3, [esi+eax+24] - movlps xmm2, [esi+eax+32] - movlps xmm4, [esi+eax+40] - movhps xmm2, [esi+eax+48] - movhps xmm4, [esi+eax+56] + movlps xmm1, [esi + eax + 0] + movlps xmm3, [esi + eax + 8] + movhps xmm1, [esi + eax + 16] + movhps xmm3, [esi + eax + 24] + movlps xmm2, [esi + eax + 32] + movlps xmm4, [esi + eax + 40] + movhps xmm2, [esi + eax + 48] + movhps xmm4, [esi + eax + 56] movaps xmm0, xmm1 shufps xmm0, xmm2, R_SHUFFLEPS( 0, 2, 0, 2 ) shufps xmm1, xmm2, R_SHUFFLEPS( 1, 3, 1, 3 ) @@ -2643,7 +2741,7 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idPlane * shufps xmm3, xmm4, R_SHUFFLEPS( 1, 3, 1, 3 ) add ecx, 16 - add eax, 4*16 + add eax, 4 * 16 mulps xmm0, xmm5 mulps xmm1, xmm6 @@ -2652,31 +2750,31 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idPlane * addps xmm0, xmm1 addps xmm0, xmm2 - movlps [ecx-16+0], xmm0 - movhps [ecx-16+8], xmm0 + movlps [ecx - 16 + 0], xmm0 + movhps [ecx - 16 + 8], xmm0 jl loopVert4 - startVert1: + startVert1: and edx, 3 jz done - loopVert1: - movss xmm0, [esi+eax+0] - movss xmm1, [esi+eax+4] - movss xmm2, [esi+eax+8] + loopVert1: + movss xmm0, [esi + eax + 0] + movss xmm1, [esi + eax + 4] + movss xmm2, [esi + eax + 8] mulss xmm0, xmm5 mulss xmm1, xmm6 mulss xmm2, xmm7 - addss xmm0, [esi+eax+12] + addss xmm0, [esi + eax + 12] add ecx, 4 addss xmm0, xmm1 add eax, 16 addss xmm0, xmm2 dec edx - movss [ecx-4], xmm0 + movss [ecx - 4], xmm0 jnz loopVert1 - done: + done: } } @@ -2690,7 +2788,7 @@ idSIMD_SSE::Dot void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idDrawVert *src, const int count ) { assert( sizeof( idDrawVert ) == DRAWVERT_SIZE ); - assert( (int)&((idDrawVert *)0)->xyz == DRAWVERT_XYZ_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->xyz == DRAWVERT_XYZ_OFFSET ); // 0, 1, 2 // 3, 4, 5 @@ -2707,9 +2805,9 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idDrawVer movss xmm4, [edi+0] shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm5, [edi+4] + movss xmm5, [edi + 4] shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm6, [edi+8] + movss xmm6, [edi + 8] shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) jz startVert1 @@ -2717,27 +2815,27 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idDrawVer add esi, eax neg eax - loopVert4: - movss xmm0, [esi+eax+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 3, X, X, X - movss xmm2, [esi+eax+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] // 2, X, X, X - movhps xmm0, [esi+eax+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 3, X, 0, 1 + loopVert4: + movss xmm0, [esi + eax + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] // 3, X, X, X + movss xmm2, [esi + eax + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] // 2, X, X, X + movhps xmm0, [esi + eax + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] // 3, X, 0, 1 movaps xmm1, xmm0 // 3, X, 0, 1 - movlps xmm1, [esi+eax+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] // 4, 5, 0, 1 + movlps xmm1, [esi + eax + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4] // 4, 5, 0, 1 shufps xmm2, xmm1, R_SHUFFLEPS( 0, 1, 0, 1 ) // 2, X, 4, 5 - movss xmm3, [esi+eax+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 9, X, X, X - movhps xmm3, [esi+eax+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 9, X, 6, 7 + movss xmm3, [esi + eax + 3 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] // 9, X, X, X + movhps xmm3, [esi + eax + 2 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] // 9, X, 6, 7 shufps xmm0, xmm3, R_SHUFFLEPS( 2, 0, 2, 0 ) // 0, 3, 6, 9 - movlps xmm3, [esi+eax+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] // 10, 11, 6, 7 + movlps xmm3, [esi + eax + 3 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4] // 10, 11, 6, 7 shufps xmm1, xmm3, R_SHUFFLEPS( 3, 0, 3, 0 ) // 1, 4, 7, 10 - movhps xmm3, [esi+eax+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] // 10, 11, 8, X + movhps xmm3, [esi + eax + 2 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] // 10, 11, 8, X shufps xmm2, xmm3, R_SHUFFLEPS( 0, 3, 2, 1 ) // 2, 5, 8, 11 add ecx, 16 - add eax, 4*DRAWVERT_SIZE + add eax, 4 * DRAWVERT_SIZE mulps xmm0, xmm4 mulps xmm1, xmm5 @@ -2745,18 +2843,18 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idDrawVer addps xmm0, xmm1 addps xmm0, xmm2 - movlps [ecx-16+0], xmm0 - movhps [ecx-16+8], xmm0 + movlps [ecx - 16 + 0], xmm0 + movhps [ecx - 16 + 8], xmm0 jl loopVert4 - startVert1: + startVert1: and edx, 3 jz done - loopVert1: - movss xmm0, [esi+eax+DRAWVERT_XYZ_OFFSET+0] - movss xmm1, [esi+eax+DRAWVERT_XYZ_OFFSET+4] - movss xmm2, [esi+eax+DRAWVERT_XYZ_OFFSET+8] + loopVert1: + movss xmm0, [esi + eax + DRAWVERT_XYZ_OFFSET + 0] + movss xmm1, [esi + eax + DRAWVERT_XYZ_OFFSET + 4] + movss xmm2, [esi + eax + DRAWVERT_XYZ_OFFSET + 8] mulss xmm0, xmm4 mulss xmm1, xmm5 mulss xmm2, xmm6 @@ -2765,10 +2863,10 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idDrawVer add eax, DRAWVERT_SIZE addss xmm0, xmm2 dec edx - movss [ecx-4], xmm0 + movss [ecx - 4], xmm0 jnz loopVert1 - done: + done: } } @@ -2780,8 +2878,7 @@ idSIMD_SSE::Dot ============ */ void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idVec3 *src, const int count ) { - __asm - { + __asm { mov eax, count mov edi, constant mov edx, eax @@ -2791,11 +2888,11 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idVec3 * movss xmm4, [edi+0] shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm5, [edi+4] + movss xmm5, [edi + 4] shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm6, [edi+8] + movss xmm6, [edi + 8] shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm7, [edi+12] + movss xmm7, [edi + 12] shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) jz done4 @@ -2803,20 +2900,20 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idVec3 * add esi, eax neg eax - loop4: - movlps xmm1, [esi+eax+ 0] - movlps xmm2, [esi+eax+ 8] - movlps xmm3, [esi+eax+16] - movhps xmm1, [esi+eax+24] - movhps xmm2, [esi+eax+32] - movhps xmm3, [esi+eax+40] + loop4: + movlps xmm1, [esi + eax + 0] + movlps xmm2, [esi + eax + 8] + movlps xmm3, [esi + eax + 16] + movhps xmm1, [esi + eax + 24] + movhps xmm2, [esi + eax + 32] + movhps xmm3, [esi + eax + 40] movaps xmm0, xmm1 shufps xmm0, xmm2, R_SHUFFLEPS( 0, 2, 1, 3 ) shufps xmm1, xmm3, R_SHUFFLEPS( 1, 3, 0, 2 ) shufps xmm2, xmm3, R_SHUFFLEPS( 0, 2, 1, 3 ) add ecx, 16 - add eax, 4*12 + add eax, 4 * 12 mulps xmm0, xmm4 mulps xmm1, xmm5 @@ -2826,18 +2923,18 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idVec3 * addps xmm0, xmm2 shufps xmm0, xmm0, R_SHUFFLEPS( 0, 2, 1, 3 ) - movlps [ecx-16+0], xmm0 - movhps [ecx-16+8], xmm0 + movlps [ecx - 16 + 0], xmm0 + movhps [ecx - 16 + 8], xmm0 jl loop4 - done4: + done4: and edx, 3 jz done1 - loop1: - movss xmm0, [esi+eax+0] - movss xmm1, [esi+eax+4] - movss xmm2, [esi+eax+8] + loop1: + movss xmm0, [esi + eax + 0] + movss xmm1, [esi + eax + 4] + movss xmm2, [esi + eax + 8] mulss xmm0, xmm4 mulss xmm1, xmm5 mulss xmm2, xmm6 @@ -2847,10 +2944,10 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idVec3 * add eax, 12 addss xmm0, xmm2 dec edx - movss [ecx-4], xmm0 + movss [ecx - 4], xmm0 jnz loop1 - done1: + done1: } } @@ -2898,22 +2995,22 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idPlane mov ecx, count movlps xmm4, [ebx] - shufps xmm4, xmm4, SHUFFLEPS(1,0,1,0) - movlps xmm5, [ebx+8] - shufps xmm5, xmm5, SHUFFLEPS(1,0,1,0) + shufps xmm4, xmm4, SHUFFLEPS( 1, 0, 1, 0 ) + movlps xmm5, [ebx + 8] + shufps xmm5, xmm5, SHUFFLEPS( 1, 0, 1, 0 ) xorps xmm0, xmm0 xorps xmm1, xmm1 - _lpAlignDest: + _lpAlignDest: test edx, 0x0f jz _destAligned - SINGLE_OP(eax,edx) + SINGLE_OP( eax, edx ) dec ecx jnz _lpAlignDest jmp _vpExit - _destAligned: + _destAligned: push ecx cmp ecx, 4 @@ -2921,30 +3018,30 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idPlane and ecx, ~3 shl ecx, 2 - lea eax, [eax+ecx*4] + lea eax, [eax + ecx * 4] add edx, ecx neg ecx - movlps xmm0, [eax+ecx*4] - movhps xmm0, [eax+ecx*4+16] - movlps xmm2, [eax+ecx*4+32] - movhps xmm2, [eax+ecx*4+48] + movlps xmm0, [eax + ecx * 4] + movhps xmm0, [eax + ecx * 4 + 16] + movlps xmm2, [eax + ecx * 4 + 32] + movhps xmm2, [eax + ecx * 4 + 48] jmp _lpStart align 16 - _lp: - prefetchnta [eax+ecx*4+128] + _lp: + prefetchnta [eax + ecx * 4 + 128] addps xmm1, xmm0 - movlps xmm0, [eax+ecx*4] - movhps xmm0, [eax+ecx*4+16] - movlps xmm2, [eax+ecx*4+32] - movhps xmm2, [eax+ecx*4+48] - movaps [edx+ecx-16],xmm1 - _lpStart: - movlps xmm1, [eax+ecx*4+8] - movhps xmm1, [eax+ecx*4+24] - movlps xmm3, [eax+ecx*4+40] - movhps xmm3, [eax+ecx*4+56] + movlps xmm0, [eax + ecx * 4] + movhps xmm0, [eax + ecx * 4 + 16] + movlps xmm2, [eax + ecx * 4 + 32] + movhps xmm2, [eax + ecx * 4 + 48] + movaps [edx + ecx - 16], xmm1 + _lpStart: + movlps xmm1, [eax + ecx * 4 + 8] + movhps xmm1, [eax + ecx * 4 + 24] + movlps xmm3, [eax + ecx * 4 + 40] + movhps xmm3, [eax + ecx * 4 + 56] add ecx, 16 mulps xmm1, xmm5 mulps xmm2, xmm4 @@ -2953,23 +3050,23 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idPlane mulps xmm0, xmm4 addps xmm0, xmm1 // y1+w1 x1+z1 y0+w0 x0+z0 movaps xmm1, xmm0 - shufps xmm0, xmm2, SHUFFLEPS(2,0,2,0) // x3+z3 x2+z2 x1+z1 x0+z0 - shufps xmm1, xmm2, SHUFFLEPS(3,1,3,1) // y3+w3 y2+w2 y1+w1 y0+w0 + shufps xmm0, xmm2, SHUFFLEPS( 2, 0, 2, 0 ) // x3+z3 x2+z2 x1+z1 x0+z0 + shufps xmm1, xmm2, SHUFFLEPS( 3, 1, 3, 1 ) // y3+w3 y2+w2 y1+w1 y0+w0 js _lp addps xmm1, xmm0 - movaps [edx+ecx-16], xmm1 - _post: + movaps [edx + ecx - 16], xmm1 + _post: pop ecx and ecx, 0x3 cmp ecx, 2 jl _post1 - DUAL_OP(eax,edx) + DUAL_OP( eax, edx ) sub ecx, 2 - _post1: + _post1: cmp ecx, 1 jne _vpExit - SINGLE_OP(eax,edx) - _vpExit: + SINGLE_OP( eax, edx ) + _vpExit: } #undef DUAL_OP @@ -2987,7 +3084,7 @@ idSIMD_SSE::Dot void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idDrawVert *src, const int count ) { assert( sizeof( idDrawVert ) == DRAWVERT_SIZE ); - assert( (int)&((idDrawVert *)0)->xyz == DRAWVERT_XYZ_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->xyz == DRAWVERT_XYZ_OFFSET ); // 0, 1, 2 // 3, 4, 5 @@ -3004,11 +3101,11 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idDrawVe movss xmm4, [edi+0] shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm5, [edi+4] + movss xmm5, [edi + 4] shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm6, [edi+8] + movss xmm6, [edi + 8] shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm7, [edi+12] + movss xmm7, [edi + 12] shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) jz startVert1 @@ -3016,27 +3113,27 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idDrawVe add esi, eax neg eax - loopVert4: - movss xmm0, [esi+eax+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 3, X, X, X - movss xmm2, [esi+eax+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] // 2, X, X, X - movhps xmm0, [esi+eax+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 3, X, 0, 1 + loopVert4: + movss xmm0, [esi + eax + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] // 3, X, X, X + movss xmm2, [esi + eax + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] // 2, X, X, X + movhps xmm0, [esi + eax + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] // 3, X, 0, 1 movaps xmm1, xmm0 // 3, X, 0, 1 - movlps xmm1, [esi+eax+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] // 4, 5, 0, 1 + movlps xmm1, [esi + eax + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4] // 4, 5, 0, 1 shufps xmm2, xmm1, R_SHUFFLEPS( 0, 1, 0, 1 ) // 2, X, 4, 5 - movss xmm3, [esi+eax+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 9, X, X, X - movhps xmm3, [esi+eax+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] // 9, X, 6, 7 + movss xmm3, [esi + eax + 3 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] // 9, X, X, X + movhps xmm3, [esi + eax + 2 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] // 9, X, 6, 7 shufps xmm0, xmm3, R_SHUFFLEPS( 2, 0, 2, 0 ) // 0, 3, 6, 9 - movlps xmm3, [esi+eax+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] // 10, 11, 6, 7 + movlps xmm3, [esi + eax + 3 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4] // 10, 11, 6, 7 shufps xmm1, xmm3, R_SHUFFLEPS( 3, 0, 3, 0 ) // 1, 4, 7, 10 - movhps xmm3, [esi+eax+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] // 10, 11, 8, X + movhps xmm3, [esi + eax + 2 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] // 10, 11, 8, X shufps xmm2, xmm3, R_SHUFFLEPS( 0, 3, 2, 1 ) // 2, 5, 8, 11 add ecx, 16 - add eax, 4*DRAWVERT_SIZE + add eax, 4 * DRAWVERT_SIZE mulps xmm0, xmm4 mulps xmm1, xmm5 @@ -3045,18 +3142,18 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idDrawVe addps xmm0, xmm1 addps xmm0, xmm2 - movlps [ecx-16+0], xmm0 - movhps [ecx-16+8], xmm0 + movlps [ecx - 16 + 0], xmm0 + movhps [ecx - 16 + 8], xmm0 jl loopVert4 - startVert1: + startVert1: and edx, 3 jz done - loopVert1: - movss xmm0, [esi+eax+DRAWVERT_XYZ_OFFSET+0] - movss xmm1, [esi+eax+DRAWVERT_XYZ_OFFSET+4] - movss xmm2, [esi+eax+DRAWVERT_XYZ_OFFSET+8] + loopVert1: + movss xmm0, [esi + eax + DRAWVERT_XYZ_OFFSET + 0] + movss xmm1, [esi + eax + DRAWVERT_XYZ_OFFSET + 4] + movss xmm2, [esi + eax + DRAWVERT_XYZ_OFFSET + 8] mulss xmm0, xmm4 mulss xmm1, xmm5 mulss xmm2, xmm6 @@ -3066,10 +3163,10 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idPlane &constant, const idDrawVe add eax, DRAWVERT_SIZE addss xmm0, xmm2 dec edx - movss [ecx-4], xmm0 + movss [ecx - 4], xmm0 jnz loopVert1 - done: + done: } } @@ -3081,8 +3178,7 @@ idSIMD_SSE::Dot ============ */ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 *src0, const idVec3 *src1, const int count ) { - __asm - { + __asm { mov eax, count mov edi, src0 mov edx, eax @@ -3096,7 +3192,7 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 *src0, const idVec3 *src1, add esi, eax neg eax - loop4: + loop4: movlps xmm0, [esi+eax] // 0, 1, X, X movlps xmm3, [edi+eax] // 0, 1, X, X movlps xmm1, [esi+eax+8] // 2, 3, X, X @@ -3124,21 +3220,21 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 *src0, const idVec3 *src1, addps xmm7, xmm1 shufps xmm7, xmm7, R_SHUFFLEPS( 0, 2, 1, 3 ) - movlps [ecx-16+0], xmm7 - movhps [ecx-16+8], xmm7 + movlps [ecx - 16 + 0], xmm7 + movhps [ecx - 16 + 8], xmm7 jl loop4 - done4: + done4: and edx, 3 jz done1 - loop1: - movss xmm0, [esi+eax+0] - movss xmm3, [edi+eax+0] - movss xmm1, [esi+eax+4] - movss xmm4, [edi+eax+4] - movss xmm2, [esi+eax+8] - movss xmm5, [edi+eax+8] + loop1: + movss xmm0, [esi + eax + 0] + movss xmm3, [edi + eax + 0] + movss xmm1, [esi + eax + 4] + movss xmm4, [edi + eax + 4] + movss xmm2, [esi + eax + 8] + movss xmm5, [edi + eax + 8] mulss xmm0, xmm3 mulss xmm1, xmm4 mulss xmm2, xmm5 @@ -3147,10 +3243,10 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 *src0, const idVec3 *src1, add eax, 12 addss xmm0, xmm2 dec edx - movss [ecx-4], xmm0 + movss [ecx - 4], xmm0 jnz loop1 - done1: + done1: } } @@ -3162,108 +3258,108 @@ idSIMD_SSE::Dot ============ */ void VPCALL idSIMD_SSE::Dot( float &dot, const float *src1, const float *src2, const int count ) { - switch( count ) { - case 0: - dot = 0.0f; - return; - case 1: - dot = src1[0] * src2[0]; - return; - case 2: - dot = src1[0] * src2[0] + src1[1] * src2[1]; - return; - case 3: - dot = src1[0] * src2[0] + src1[1] * src2[1] + src1[2] * src2[2]; - return; - default: - __asm { - mov ecx, src1 - mov edx, src2 - mov eax, ecx - or eax, edx - and eax, 15 - jz alignedDot - // unaligned - mov eax, count - shr eax, 2 - shl eax, 4 - add ecx, eax - add edx, eax - neg eax - movups xmm0, [ecx+eax] - movups xmm1, [edx+eax] - mulps xmm0, xmm1 - add eax, 16 - jz doneDot - loopUnalignedDot: - movups xmm1, [ecx+eax] - movups xmm2, [edx+eax] - mulps xmm1, xmm2 - addps xmm0, xmm1 - add eax, 16 - jl loopUnalignedDot - jmp doneDot - // aligned + switch ( count ) { + case 0: + dot = 0.0f; + return; + case 1: + dot = src1[0] * src2[0]; + return; + case 2: + dot = src1[0] * src2[0] + src1[1] * src2[1]; + return; + case 3: + dot = src1[0] * src2[0] + src1[1] * src2[1] + src1[2] * src2[2]; + return; + default: + __asm { + mov ecx, src1 + mov edx, src2 + mov eax, ecx + or eax, edx + and eax, 15 + jz alignedDot + // unaligned + mov eax, count + shr eax, 2 + shl eax, 4 + add ecx, eax + add edx, eax + neg eax + movups xmm0, [ecx+eax] + movups xmm1, [edx+eax] + mulps xmm0, xmm1 + add eax, 16 + jz doneDot + loopUnalignedDot: + movups xmm1, [ecx+eax] + movups xmm2, [edx+eax] + mulps xmm1, xmm2 + addps xmm0, xmm1 + add eax, 16 + jl loopUnalignedDot + jmp doneDot + // aligned alignedDot: - mov eax, count - shr eax, 2 - shl eax, 4 - add ecx, eax - add edx, eax - neg eax - movaps xmm0, [ecx+eax] - movaps xmm1, [edx+eax] - mulps xmm0, xmm1 - add eax, 16 - jz doneDot + mov eax, count + shr eax, 2 + shl eax, 4 + add ecx, eax + add edx, eax + neg eax + movaps xmm0, [ecx+eax] + movaps xmm1, [edx+eax] + mulps xmm0, xmm1 + add eax, 16 + jz doneDot loopAlignedDot: - movaps xmm1, [ecx+eax] - movaps xmm2, [edx+eax] - mulps xmm1, xmm2 - addps xmm0, xmm1 - add eax, 16 - jl loopAlignedDot + movaps xmm1, [ecx+eax] + movaps xmm2, [edx+eax] + mulps xmm1, xmm2 + addps xmm0, xmm1 + add eax, 16 + jl loopAlignedDot doneDot: + } + switch ( count & 3 ) { + case 1: + __asm { + movss xmm1, [ecx] + movss xmm2, [edx] + mulss xmm1, xmm2 + addss xmm0, xmm1 } - switch( count & 3 ) { - case 1: - __asm { - movss xmm1, [ecx] - movss xmm2, [edx] - mulss xmm1, xmm2 - addss xmm0, xmm1 - } - break; - case 2: - __asm { - xorps xmm2, xmm2 - movlps xmm1, [ecx] - movlps xmm2, [edx] - mulps xmm1, xmm2 - addps xmm0, xmm1 - } - break; - case 3: - __asm { - movss xmm1, [ecx] - movhps xmm1, [ecx+4] - movss xmm2, [edx] - movhps xmm2, [edx+4] - mulps xmm1, xmm2 - addps xmm0, xmm1 - } - break; + break; + case 2: + __asm { + xorps xmm2, xmm2 + movlps xmm1, [ecx] + movlps xmm2, [edx] + mulps xmm1, xmm2 + addps xmm0, xmm1 } + break; + case 3: __asm { - movhlps xmm1, xmm0 - addps xmm0, xmm1 - movaps xmm1, xmm0 - shufps xmm1, xmm1, R_SHUFFLEPS( 1, 0, 0, 0 ) - addss xmm0, xmm1 - mov eax, dot - movss [eax], xmm0 + movss xmm1, [ecx] + movhps xmm1, [ecx+4] + movss xmm2, [edx] + movhps xmm2, [edx+4] + mulps xmm1, xmm2 + addps xmm0, xmm1 } - return; + break; + } + __asm { + movhlps xmm1, xmm0 + addps xmm0, xmm1 + movaps xmm1, xmm0 + shufps xmm1, xmm1, R_SHUFFLEPS( 1, 0, 0, 0 ) + addss xmm0, xmm1 + mov eax, dot + movss [eax], xmm0 + } + return; } } @@ -3561,10 +3657,10 @@ idSIMD_SSE::MinMax void VPCALL idSIMD_SSE::MinMax( float &min, float &max, const float *src, const int count ) { int i, pre, post; - min = idMath::INFINITY; max = -idMath::INFINITY; + min = idMath::INFINITY; + max = -idMath::INFINITY; - __asm - { + __asm { push ebx mov eax, min mov ebx, max @@ -3578,30 +3674,30 @@ void VPCALL idSIMD_SSE::MinMax( float &min, float &max, const float *src, const jz lpA jmp lpNA align 16 -lpNA: - movups xmm2, [edx+ebx] - movups xmm3, [edx+ebx+16] + lpNA: + movups xmm2, [edx + ebx] + movups xmm3, [edx + ebx + 16] minps xmm0, xmm2 maxps xmm1, xmm2 - prefetchnta [edx+ebx+64] + prefetchnta [edx + ebx + 64] minps xmm0, xmm3 maxps xmm1, xmm3 - add ebx, 16*2 + add ebx, 16 * 2 jl lpNA jmp done2 -lpA: - movaps xmm2, [edx+ebx] - movaps xmm3, [edx+ebx+16] + lpA: + movaps xmm2, [edx + ebx] + movaps xmm3, [edx + ebx + 16] minps xmm0, xmm2 maxps xmm1, xmm2 - prefetchnta [edx+ebx+64] + prefetchnta [edx + ebx + 64] minps xmm0, xmm3 maxps xmm1, xmm3 - add ebx, 16*2 + add ebx, 16 * 2 jl lpA jmp done2 align 16 -done2: + done2: movaps xmm2, xmm0 movaps xmm3, xmm1 shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) @@ -3620,7 +3716,7 @@ void VPCALL idSIMD_SSE::MinMax( float &min, float &max, const float *src, const mov ebx, max movss [eax], xmm0 movss [ebx], xmm1 -done: + done: pop ebx } @@ -3665,21 +3761,21 @@ void VPCALL idSIMD_SSE::MinMax( idVec2 &min, idVec2 &max, const idVec2 *src, con movlps xmm2, [esi] shufps xmm2, xmm2, R_SHUFFLEPS( 0, 1, 0, 1 ) dec eax - add esi, 2*4 + add esi, 2 * 4 minps xmm0, xmm2 maxps xmm1, xmm2 - startLoop: - imul eax, 2*4 + startLoop: + imul eax, 2 * 4 add esi, eax neg eax - loopVert: - movlps xmm2, [esi+eax] - movhps xmm2, [esi+eax+8] - add eax, 4*4 + loopVert: + movlps xmm2, [esi + eax] + movhps xmm2, [esi + eax + 8] + add eax, 4 * 4 minps xmm0, xmm2 maxps xmm1, xmm2 jl loopVert - done: + done: movaps xmm2, xmm0 shufps xmm2, xmm2, R_SHUFFLEPS( 2, 3, 0, 1 ) minps xmm0, xmm2 @@ -3716,33 +3812,33 @@ void VPCALL idSIMD_SSE::MinMax( idVec3 &min, idVec3 &max, const idVec3 *src, con add esi, eax neg eax - loop4: -// prefetchnta [esi+4*12] + loop4: + // prefetchnta [esi+4*12] - movss xmm4, [esi+eax+0*12+8] - movhps xmm4, [esi+eax+0*12+0] + movss xmm4, [esi + eax + 0 * 12 + 8] + movhps xmm4, [esi + eax + 0 * 12 + 0] minps xmm0, xmm4 maxps xmm1, xmm4 - movss xmm5, [esi+eax+1*12+0] - movhps xmm5, [esi+eax+1*12+4] + movss xmm5, [esi + eax + 1 * 12 + 0] + movhps xmm5, [esi + eax + 1 * 12 + 4] minps xmm2, xmm5 maxps xmm3, xmm5 - movss xmm6, [esi+eax+2*12+8] - movhps xmm6, [esi+eax+2*12+0] + movss xmm6, [esi + eax + 2 * 12 + 8] + movhps xmm6, [esi + eax + 2 * 12 + 0] minps xmm0, xmm6 maxps xmm1, xmm6 - movss xmm7, [esi+eax+3*12+0] - movhps xmm7, [esi+eax+3*12+4] + movss xmm7, [esi + eax + 3 * 12 + 0] + movhps xmm7, [esi + eax + 3 * 12 + 4] minps xmm2, xmm7 maxps xmm3, xmm7 - add eax, 4*12 + add eax, 4 * 12 jl loop4 - done4: + done4: mov eax, count and eax, 3 jz done1 @@ -3750,26 +3846,26 @@ void VPCALL idSIMD_SSE::MinMax( idVec3 &min, idVec3 &max, const idVec3 *src, con add esi, eax neg eax - loop1: - movss xmm4, [esi+eax+0*12+8] - movhps xmm4, [esi+eax+0*12+0] + loop1: + movss xmm4, [esi + eax + 0 * 12 + 8] + movhps xmm4, [esi + eax + 0 * 12 + 0] minps xmm0, xmm4 maxps xmm1, xmm4 add eax, 12 jl loop1 - done1: + done1: shufps xmm2, xmm2, R_SHUFFLEPS( 3, 1, 0, 2 ) shufps xmm3, xmm3, R_SHUFFLEPS( 3, 1, 0, 2 ) minps xmm0, xmm2 maxps xmm1, xmm3 mov esi, min movhps [esi], xmm0 - movss [esi+8], xmm0 + movss [esi + 8], xmm0 mov edi, max movhps [edi], xmm1 - movss [edi+8], xmm1 + movss [edi + 8], xmm1 } } @@ -3781,7 +3877,7 @@ idSIMD_SSE::MinMax void VPCALL idSIMD_SSE::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, const int count ) { assert( sizeof( idDrawVert ) == DRAWVERT_SIZE ); - assert( (int)&((idDrawVert *)0)->xyz == DRAWVERT_XYZ_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->xyz == DRAWVERT_XYZ_OFFSET ); __asm { @@ -3800,33 +3896,33 @@ void VPCALL idSIMD_SSE::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, add esi, eax neg eax - loop4: -// prefetchnta [esi+4*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET] + loop4: + // prefetchnta [esi+4*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET] - movss xmm4, [esi+eax+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] - movhps xmm4, [esi+eax+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] + movss xmm4, [esi + eax + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] + movhps xmm4, [esi + eax + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] minps xmm0, xmm4 maxps xmm1, xmm4 - movss xmm5, [esi+eax+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] - movhps xmm5, [esi+eax+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] + movss xmm5, [esi + eax + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] + movhps xmm5, [esi + eax + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4] minps xmm2, xmm5 maxps xmm3, xmm5 - movss xmm6, [esi+eax+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] - movhps xmm6, [esi+eax+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] + movss xmm6, [esi + eax + 2 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] + movhps xmm6, [esi + eax + 2 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] minps xmm0, xmm6 maxps xmm1, xmm6 - movss xmm7, [esi+eax+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] - movhps xmm7, [esi+eax+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] + movss xmm7, [esi + eax + 3 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] + movhps xmm7, [esi + eax + 3 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4] minps xmm2, xmm7 maxps xmm3, xmm7 - add eax, 4*DRAWVERT_SIZE + add eax, 4 * DRAWVERT_SIZE jl loop4 - done4: + done4: mov eax, count and eax, 3 jz done1 @@ -3834,26 +3930,26 @@ void VPCALL idSIMD_SSE::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, add esi, eax neg eax - loop1: - movss xmm4, [esi+eax+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] - movhps xmm4, [esi+eax+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] + loop1: + movss xmm4, [esi + eax + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] + movhps xmm4, [esi + eax + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] minps xmm0, xmm4 maxps xmm1, xmm4 add eax, DRAWVERT_SIZE jl loop1 - done1: + done1: shufps xmm2, xmm2, R_SHUFFLEPS( 3, 1, 0, 2 ) shufps xmm3, xmm3, R_SHUFFLEPS( 3, 1, 0, 2 ) minps xmm0, xmm2 maxps xmm1, xmm3 mov esi, min movhps [esi], xmm0 - movss [esi+8], xmm0 + movss [esi + 8], xmm0 mov edi, max movhps [edi], xmm1 - movss [edi+8], xmm1 + movss [edi + 8], xmm1 } } @@ -3865,7 +3961,7 @@ idSIMD_SSE::MinMax void VPCALL idSIMD_SSE::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, const int *indexes, const int count ) { assert( sizeof( idDrawVert ) == DRAWVERT_SIZE ); - assert( (int)&((idDrawVert *)0)->xyz == DRAWVERT_XYZ_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->xyz == DRAWVERT_XYZ_OFFSET ); __asm { @@ -3885,42 +3981,42 @@ void VPCALL idSIMD_SSE::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, add edi, eax neg eax - loop4: -// prefetchnta [edi+128] -// prefetchnta [esi+4*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET] + loop4: + // prefetchnta [edi+128] + // prefetchnta [esi+4*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET] - mov edx, [edi+eax+0] + mov edx, [edi + eax + 0] imul edx, DRAWVERT_SIZE - movss xmm4, [esi+edx+DRAWVERT_XYZ_OFFSET+8] - movhps xmm4, [esi+edx+DRAWVERT_XYZ_OFFSET+0] + movss xmm4, [esi + edx + DRAWVERT_XYZ_OFFSET + 8] + movhps xmm4, [esi + edx + DRAWVERT_XYZ_OFFSET + 0] minps xmm0, xmm4 maxps xmm1, xmm4 - mov edx, [edi+eax+4] + mov edx, [edi + eax + 4] imul edx, DRAWVERT_SIZE - movss xmm5, [esi+edx+DRAWVERT_XYZ_OFFSET+0] - movhps xmm5, [esi+edx+DRAWVERT_XYZ_OFFSET+4] + movss xmm5, [esi + edx + DRAWVERT_XYZ_OFFSET + 0] + movhps xmm5, [esi + edx + DRAWVERT_XYZ_OFFSET + 4] minps xmm2, xmm5 maxps xmm3, xmm5 - mov edx, [edi+eax+8] + mov edx, [edi + eax + 8] imul edx, DRAWVERT_SIZE - movss xmm6, [esi+edx+DRAWVERT_XYZ_OFFSET+8] - movhps xmm6, [esi+edx+DRAWVERT_XYZ_OFFSET+0] + movss xmm6, [esi + edx + DRAWVERT_XYZ_OFFSET + 8] + movhps xmm6, [esi + edx + DRAWVERT_XYZ_OFFSET + 0] minps xmm0, xmm6 maxps xmm1, xmm6 - mov edx, [edi+eax+12] + mov edx, [edi + eax + 12] imul edx, DRAWVERT_SIZE - movss xmm7, [esi+edx+DRAWVERT_XYZ_OFFSET+0] - movhps xmm7, [esi+edx+DRAWVERT_XYZ_OFFSET+4] + movss xmm7, [esi + edx + DRAWVERT_XYZ_OFFSET + 0] + movhps xmm7, [esi + edx + DRAWVERT_XYZ_OFFSET + 4] minps xmm2, xmm7 maxps xmm3, xmm7 - add eax, 4*4 + add eax, 4 * 4 jl loop4 - done4: + done4: mov eax, count and eax, 3 jz done1 @@ -3928,28 +4024,28 @@ void VPCALL idSIMD_SSE::MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, add edi, eax neg eax - loop1: - mov edx, [edi+eax+0] + loop1: + mov edx, [edi + eax + 0] imul edx, DRAWVERT_SIZE; - movss xmm4, [esi+edx+DRAWVERT_XYZ_OFFSET+8] - movhps xmm4, [esi+edx+DRAWVERT_XYZ_OFFSET+0] + movss xmm4, [esi + edx + DRAWVERT_XYZ_OFFSET + 8] + movhps xmm4, [esi + edx + DRAWVERT_XYZ_OFFSET + 0] minps xmm0, xmm4 maxps xmm1, xmm4 add eax, 4 jl loop1 - done1: + done1: shufps xmm2, xmm2, R_SHUFFLEPS( 3, 1, 0, 2 ) shufps xmm3, xmm3, R_SHUFFLEPS( 3, 1, 0, 2 ) minps xmm0, xmm2 maxps xmm1, xmm3 mov esi, min movhps [esi], xmm0 - movss [esi+8], xmm0 + movss [esi + 8], xmm0 mov edi, max movhps [edi], xmm1 - movss [edi+8], xmm1 + movss [edi + 8], xmm1 } } @@ -3961,64 +4057,63 @@ idSIMD_SSE::Clamp void VPCALL idSIMD_SSE::Clamp( float *dst, const float *src, const float min, const float max, const int count ) { int i, pre, post; - __asm - { - movss xmm0,min - movss xmm1,max - shufps xmm0,xmm0,0 - shufps xmm1,xmm1,0 + __asm { + movss xmm0, min + movss xmm1, max + shufps xmm0, xmm0, 0 + shufps xmm1, xmm1, 0 KFLOATINITDS( dst, src, count, pre, post ) - and eax,15 + and eax, 15 jne lpNA jmp lpA align 16 -lpA: - movaps xmm2,[edx+ebx] - movaps xmm3,[edx+ebx+16] - maxps xmm2,xmm0 - maxps xmm3,xmm0 - prefetchnta [edx+ebx+64] - minps xmm2,xmm1 - minps xmm3,xmm1 - movaps [edi+ebx],xmm2 - movaps [edi+ebx+16],xmm3 - add ebx,16*2 + lpA: + movaps xmm2, [edx + ebx] + movaps xmm3, [edx + ebx + 16] + maxps xmm2, xmm0 + maxps xmm3, xmm0 + prefetchnta [edx + ebx + 64] + minps xmm2, xmm1 + minps xmm3, xmm1 + movaps [edi + ebx], xmm2 + movaps [edi + ebx + 16], xmm3 + add ebx, 16 * 2 jl lpA jmp done align 16 -lpNA: - movups xmm2,[edx+ebx] - movups xmm3,[edx+ebx+16] - maxps xmm2,xmm0 - maxps xmm3,xmm0 - prefetchnta [edx+ebx+64] - minps xmm2,xmm1 - minps xmm3,xmm1 - movaps [edi+ebx],xmm2 - movaps [edi+ebx+16],xmm3 - add ebx,16*2 + lpNA: + movups xmm2, [edx + ebx] + movups xmm3, [edx + ebx + 16] + maxps xmm2, xmm0 + maxps xmm3, xmm0 + prefetchnta [edx + ebx + 64] + minps xmm2, xmm1 + minps xmm3, xmm1 + movaps [edi + ebx], xmm2 + movaps [edi + ebx + 16], xmm3 + add ebx, 16 * 2 jl lpNA -done: + done: } for ( i = 0; i < pre; i++ ) { if ( src[i] < min ) - dst[i] = min; + { dst[i] = min; } else if ( src[i] > max ) - dst[i] = max; + { dst[i] = max; } else - dst[i] = src[i]; + { dst[i] = src[i]; } } - for( i = count - post; i < count; i++ ) { + for ( i = count - post; i < count; i++ ) { if ( src[i] < min ) - dst[i] = min; + { dst[i] = min; } else if ( src[i] > max ) - dst[i] = max; + { dst[i] = max; } else - dst[i] = src[i]; + { dst[i] = src[i]; } } } @@ -4030,53 +4125,52 @@ idSIMD_SSE::ClampMin void VPCALL idSIMD_SSE::ClampMin( float *dst, const float *src, const float min, const int count ) { int i, pre, post; - __asm - { - movss xmm0,min - shufps xmm0,xmm0,0 + __asm { + movss xmm0, min + shufps xmm0, xmm0, 0 KFLOATINITDS( dst, src, count, pre, post ) - and eax,15 + and eax, 15 jne lpNA jmp lpA align 16 -lpA: - movaps xmm2,[edx+ebx] - movaps xmm3,[edx+ebx+16] - maxps xmm2,xmm0 - prefetchnta [edx+ebx+64] - maxps xmm3,xmm0 - movaps [edi+ebx],xmm2 - movaps [edi+ebx+16],xmm3 - add ebx,16*2 + lpA: + movaps xmm2, [edx + ebx] + movaps xmm3, [edx + ebx + 16] + maxps xmm2, xmm0 + prefetchnta [edx + ebx + 64] + maxps xmm3, xmm0 + movaps [edi + ebx], xmm2 + movaps [edi + ebx + 16], xmm3 + add ebx, 16 * 2 jl lpA jmp done align 16 -lpNA: - movups xmm2,[edx+ebx] - movups xmm3,[edx+ebx+16] - maxps xmm2,xmm0 - prefetchnta [edx+ebx+64] - maxps xmm3,xmm0 - movaps [edi+ebx],xmm2 - movaps [edi+ebx+16],xmm3 - add ebx,16*2 + lpNA: + movups xmm2, [edx + ebx] + movups xmm3, [edx + ebx + 16] + maxps xmm2, xmm0 + prefetchnta [edx + ebx + 64] + maxps xmm3, xmm0 + movaps [edi + ebx], xmm2 + movaps [edi + ebx + 16], xmm3 + add ebx, 16 * 2 jl lpNA -done: + done: } - for( i = 0; i < pre; i++ ) { + for ( i = 0; i < pre; i++ ) { if ( src[i] < min ) - dst[i] = min; + { dst[i] = min; } else - dst[i] = src[i]; + { dst[i] = src[i]; } } - for( i = count - post; i < count; i++ ) { + for ( i = count - post; i < count; i++ ) { if ( src[i] < min ) - dst[i] = min; + { dst[i] = min; } else - dst[i] = src[i]; + { dst[i] = src[i]; } } } @@ -4088,54 +4182,53 @@ idSIMD_SSE::ClampMax void VPCALL idSIMD_SSE::ClampMax( float *dst, const float *src, const float max, const int count ) { int i, pre, post; - __asm - { - movss xmm1,max - shufps xmm1,xmm1,0 + __asm { + movss xmm1, max + shufps xmm1, xmm1, 0 KFLOATINITDS( dst, src, count, pre, post ) - and eax,15 + and eax, 15 jne lpNA jmp lpA align 16 -lpA: - movaps xmm2,[edx+ebx] - movaps xmm3,[edx+ebx+16] - minps xmm2,xmm1 - prefetchnta [edx+ebx+64] - minps xmm3,xmm1 - movaps [edi+ebx],xmm2 - movaps [edi+ebx+16],xmm3 - add ebx,16*2 + lpA: + movaps xmm2, [edx + ebx] + movaps xmm3, [edx + ebx + 16] + minps xmm2, xmm1 + prefetchnta [edx + ebx + 64] + minps xmm3, xmm1 + movaps [edi + ebx], xmm2 + movaps [edi + ebx + 16], xmm3 + add ebx, 16 * 2 jl lpA jmp done align 16 -lpNA: - movups xmm2,[edx+ebx] - movups xmm3,[edx+ebx+16] - minps xmm2,xmm1 - prefetchnta [edx+ebx+64] - minps xmm3,xmm1 - movaps [edi+ebx],xmm2 - movaps [edi+ebx+16],xmm3 - add ebx,16*2 + lpNA: + movups xmm2, [edx + ebx] + movups xmm3, [edx + ebx + 16] + minps xmm2, xmm1 + prefetchnta [edx + ebx + 64] + minps xmm3, xmm1 + movaps [edi + ebx], xmm2 + movaps [edi + ebx + 16], xmm3 + add ebx, 16 * 2 jl lpNA -done: + done: } - for( i = 0; i < pre; i++ ) { + for ( i = 0; i < pre; i++ ) { if ( src[i] > max ) - dst[i] = max; + { dst[i] = max; } else - dst[i] = src[i]; + { dst[i] = src[i]; } } - for( i = count - post; i < count; i++ ) { + for ( i = count - post; i < count; i++ ) { if ( src[i] > max ) - dst[i] = max; + { dst[i] = max; } else - dst[i] = src[i]; + { dst[i] = src[i]; } } } @@ -4155,11 +4248,11 @@ void VPCALL idSIMD_SSE::Zero16( float *dst, const int count ) { add edx, eax neg eax xorps xmm0, xmm0 - loopZero16: + loopZero16: movaps [edx+eax], xmm0 add eax, 16 jl loopZero16 - doneZero16: + doneZero16: } } @@ -4180,13 +4273,13 @@ void VPCALL idSIMD_SSE::Negate16( float *dst, const int count ) { neg eax movss xmm0, SIMD_SP_signBitMask shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - loopNegate16: - movaps xmm1, [edx+eax] + loopNegate16: + movaps xmm1, [edx + eax] xorps xmm1, xmm0 - movaps [edx+eax], xmm1 + movaps [edx + eax], xmm1 add eax, 16 jl loopNegate16 - doneNegate16: + doneNegate16: } } @@ -4207,12 +4300,12 @@ void VPCALL idSIMD_SSE::Copy16( float *dst, const float *src, const int count ) add ecx, eax add edx, eax neg eax - loopCopy16: + loopCopy16: movaps xmm0, [ecx+eax] movaps [edx+eax], xmm0 add eax, 16 jl loopCopy16 - doneCopy16: + doneCopy16: } } @@ -4235,13 +4328,13 @@ void VPCALL idSIMD_SSE::Add16( float *dst, const float *src1, const float *src2, add ecx, eax add edx, eax neg eax - loopAdd16: + loopAdd16: movaps xmm0, [ecx+eax] addps xmm0, [edx+eax] movaps [esi+eax], xmm0 add eax, 16 jl loopAdd16 - doneAdd16: + doneAdd16: } } @@ -4264,13 +4357,13 @@ void VPCALL idSIMD_SSE::Sub16( float *dst, const float *src1, const float *src2, add ecx, eax add edx, eax neg eax - loopSub16: + loopSub16: movaps xmm0, [ecx+eax] subps xmm0, [edx+eax] movaps [esi+eax], xmm0 add eax, 16 jl loopSub16 - doneSub16: + doneSub16: } } @@ -4293,13 +4386,13 @@ void VPCALL idSIMD_SSE::Mul16( float *dst, const float *src1, const float consta add edx, eax neg eax shufps xmm1, xmm1, 0x00 - loopMulScalar16: + loopMulScalar16: movaps xmm0, [edx+eax] mulps xmm0, xmm1 movaps [ecx+eax], xmm0 add eax, 16 jl loopMulScalar16 - doneMulScalar16: + doneMulScalar16: } } @@ -4320,13 +4413,13 @@ void VPCALL idSIMD_SSE::AddAssign16( float *dst, const float *src, const int cou add ecx, eax add edx, eax neg eax - loopAddAssign16: + loopAddAssign16: movaps xmm0, [ecx+eax] addps xmm0, [edx+eax] movaps [ecx+eax], xmm0 add eax, 16 jl loopAddAssign16 - doneAddAssign16: + doneAddAssign16: } } @@ -4347,13 +4440,13 @@ void VPCALL idSIMD_SSE::SubAssign16( float *dst, const float *src, const int cou add ecx, eax add edx, eax neg eax - loopSubAssign16: + loopSubAssign16: movaps xmm0, [ecx+eax] subps xmm0, [edx+eax] movaps [ecx+eax], xmm0 add eax, 16 jl loopSubAssign16 - doneSubAssign16: + doneSubAssign16: } } @@ -4374,13 +4467,13 @@ void VPCALL idSIMD_SSE::MulAssign16( float *dst, const float constant, const int add ecx, eax neg eax shufps xmm1, xmm1, 0x00 - loopMulAssign16: + loopMulAssign16: movaps xmm0, [ecx+eax] mulps xmm0, xmm1 movaps [ecx+eax], xmm0 add eax, 16 jl loopMulAssign16 - doneMulAssign16: + doneMulAssign16: } } @@ -4420,698 +4513,698 @@ void VPCALL idSIMD_SSE::MatX_MultiplyVecX( idVecX &dst, const idMatX &mat, const vPtr = vec.ToFloatPtr(); dstPtr = dst.ToFloatPtr(); numRows = mat.GetNumRows(); - switch( mat.GetNumColumns() ) { - case 1: { - switch( numRows ) { - case 1: { // 1x1 * 1x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - mulss xmm0, [edi] - STORE1( 0, xmm0, xmm1 ) - } - return; - } - case 6: { // 6x1 * 1x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm1, xmm0 - mulps xmm0, [edi] - mulps xmm1, [edi+16] - STORE4( 0, xmm0, xmm2 ) - STORE2LO( 16, xmm1, xmm2 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0]; - mPtr++; - } - return; - } + switch ( mat.GetNumColumns() ) { + case 1: { + switch ( numRows ) { + case 1: { // 1x1 * 1x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + mulss xmm0, [edi] + STORE1( 0, xmm0, xmm1 ) } - break; + return; } - case 2: { - switch( numRows ) { - case 2: { // 2x2 * 2x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - movss xmm1, [esi+4] - movss xmm2, [edi] - mulss xmm2, xmm0 - movss xmm3, [edi+4] - mulss xmm3, xmm1 - addss xmm2, xmm3 - STORE1( 0, xmm2, xmm4 ) - mulss xmm0, [edi+8] - mulss xmm1, [edi+8+4] - addss xmm0, xmm1 - STORE1( 4, xmm0, xmm4 ) - } - return; - } - case 6: { // 6x2 * 2x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm7, [esi] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) - movaps xmm0, [edi] - mulps xmm0, xmm7 - movaps xmm1, [edi+16] - mulps xmm1, xmm7 - movaps xmm2, xmm0 - shufps xmm0, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm2, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) - movaps xmm3, [edi+32] - addps xmm0, xmm2 - mulps xmm3, xmm7 - STORE4( 0, xmm0, xmm4 ) - shufps xmm3, xmm3, R_SHUFFLEPS( 0, 2, 1, 3 ) - movhlps xmm1, xmm3 - addps xmm3, xmm1 - STORE2LO( 16, xmm3, xmm4 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1]; - mPtr += 2; - } - return; - } + case 6: { // 6x1 * 1x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm1, xmm0 + mulps xmm0, [edi] + mulps xmm1, [edi + 16] + STORE4( 0, xmm0, xmm2 ) + STORE2LO( 16, xmm1, xmm2 ) } - break; + return; } - case 3: { - switch( numRows ) { - case 3: { // 3x3 * 3x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - movss xmm4, [edi] - mulss xmm4, xmm0 - movss xmm1, [esi+4] - movss xmm5, [edi+4] - mulss xmm5, xmm1 - addss xmm4, xmm5 - movss xmm2, [esi+8] - movss xmm6, [edi+8] - mulss xmm6, xmm2 - addss xmm4, xmm6 - movss xmm3, [edi+12] - mulss xmm3, xmm0 - STORE1( 0, xmm4, xmm7 ); - movss xmm5, [edi+12+4] - mulss xmm5, xmm1 - addss xmm3, xmm5 - movss xmm6, [edi+12+8] - mulss xmm6, xmm2 - addss xmm3, xmm6 - mulss xmm0, [edi+24] - mulss xmm1, [edi+24+4] - STORE1( 4, xmm3, xmm7 ); - addss xmm0, xmm1 - mulss xmm2, [edi+24+8] - addss xmm0, xmm2 - STORE1( 8, xmm0, xmm7 ); - } - return; - } - case 6: { // 6x3 * 3x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm5, [esi] - shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm6, [esi+4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm7, [esi+8] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm0, [edi] // xmm0 = 0, 1, 2, 3 - movlps xmm1, [edi+4*4] - shufps xmm1, xmm0, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm1 = 4, 5, 1, 2 - movlps xmm2, [edi+6*4] - movhps xmm2, [edi+8*4] // xmm2 = 6, 7, 8, 9 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 3, 0, 3 ) // xmm0 = 0, 3, 6, 9 - mulps xmm0, xmm5 - movlps xmm3, [edi+10*4] - shufps xmm2, xmm3, R_SHUFFLEPS( 1, 2, 0, 1 ) // xmm2 = 7, 8, 10, 11 - movaps xmm3, xmm1 - shufps xmm1, xmm2, R_SHUFFLEPS( 2, 0, 0, 2 ) // xmm1 = 1, 4, 7, 10 - mulps xmm1, xmm6 - shufps xmm3, xmm2, R_SHUFFLEPS( 3, 1, 1, 3 ) // xmm3 = 2, 5, 8, 11 - mulps xmm3, xmm7 - addps xmm0, xmm1 - addps xmm0, xmm3 - STORE4( 0, xmm0, xmm4 ) - movss xmm1, [edi+12*4] - mulss xmm1, xmm5 - movss xmm2, [edi+13*4] - mulss xmm2, xmm6 - movss xmm3, [edi+14*4] - mulss xmm3, xmm7 - addss xmm1, xmm2 - addss xmm1, xmm3 - STORE1( 16, xmm1, xmm4 ) - mulss xmm5, [edi+15*4] - mulss xmm6, [edi+16*4] - mulss xmm7, [edi+17*4] - addss xmm5, xmm6 - addss xmm5, xmm7 - STORE1( 20, xmm5, xmm4 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2]; - mPtr += 3; - } - return; - } + default: { + for ( int i = 0; i < numRows; i++ ) { + dstPtr[i] STOREC mPtr[0] * vPtr[0]; + mPtr++; } - break; + return; } - case 4: { - switch( numRows ) { - case 4: { // 4x4 * 4x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm6, qword ptr [esi ] - movlps xmm0, qword ptr [edi ] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) - movhps xmm0, qword ptr [edi+16] - mulps xmm0, xmm6 - movlps xmm7, qword ptr [esi+ 8] - movlps xmm2, qword ptr [edi+ 8] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) - movhps xmm2, qword ptr [edi+24] - mulps xmm2, xmm7 - movlps xmm1, qword ptr [edi+32] - movhps xmm1, qword ptr [edi+48] - mulps xmm1, xmm6 - movlps xmm3, qword ptr [edi+40] - addps xmm0, xmm2 - movhps xmm3, qword ptr [edi+56] - mulps xmm3, xmm7 - movaps xmm4, xmm0 - addps xmm1, xmm3 - shufps xmm4, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) - addps xmm0, xmm4 - STORE4( 0, xmm0, xmm2 ) - } - return; - } - case 6: { // 6x4 * 4x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm6, qword ptr [esi+ 0] - movlps xmm0, qword ptr [edi+ 0] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) - movhps xmm0, qword ptr [edi+16] - mulps xmm0, xmm6 - movlps xmm7, qword ptr [esi+ 8] - movlps xmm2, qword ptr [edi+ 8] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) - movhps xmm2, qword ptr [edi+24] - mulps xmm2, xmm7 - movlps xmm1, qword ptr [edi+32] - movhps xmm1, qword ptr [edi+48] - mulps xmm1, xmm6 - movlps xmm3, qword ptr [edi+40] - addps xmm0, xmm2 - movhps xmm3, qword ptr [edi+56] - mulps xmm3, xmm7 - movaps xmm4, xmm0 - addps xmm1, xmm3 - shufps xmm4, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) - addps xmm0, xmm4 - movlps xmm1, qword ptr [edi+64] - movhps xmm1, qword ptr [edi+80] - STORE4( 0, xmm0, xmm4 ) - mulps xmm1, xmm6 - movlps xmm2, qword ptr [edi+72] - movhps xmm2, qword ptr [edi+88] - mulps xmm2, xmm7 - addps xmm1, xmm2 - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) - movhlps xmm3, xmm1 - addps xmm1, xmm3 - STORE2LO( 16, xmm1, xmm4 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + mPtr[3] * vPtr[3]; - mPtr += 4; - } - return; - } + } + break; + } + case 2: { + switch ( numRows ) { + case 2: { // 2x2 * 2x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + movss xmm1, [esi+4] + movss xmm2, [edi] + mulss xmm2, xmm0 + movss xmm3, [edi+4] + mulss xmm3, xmm1 + addss xmm2, xmm3 + STORE1( 0, xmm2, xmm4 ) + mulss xmm0, [edi + 8] + mulss xmm1, [edi + 8 + 4] + addss xmm0, xmm1 + STORE1( 4, xmm0, xmm4 ) } - break; + return; } - case 5: { - switch( numRows ) { - case 5: { // 5x5 * 5x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [edi+5*4] // xmm0 = 5, X, X, X - movhps xmm0, [edi+0*4] // xmm0 = 5, X, 0, 1 - movss xmm5, [edi+15*4] // xmm4 = 15, X, X, X - movhps xmm5, [edi+10*4] // xmm5 = 15, X, 10, 11 - movaps xmm1, xmm0 // xmm1 = 5, X, 0, 1 - shufps xmm0, xmm5, R_SHUFFLEPS( 2, 0, 2, 0 ) // xmm0 = 0, 5, 10, 15 - movlps xmm1, [edi+6*4] // xmm1 = 6, 7, 0, 1 - movlps xmm5, [edi+16*4] // xmm5 = 16, 17, 10, 11 - movaps xmm2, xmm1 // xmm2 = 6, 7, 0, 1 - shufps xmm1, xmm5, R_SHUFFLEPS( 3, 0, 3, 0 ) // xmm1 = 1, 6, 11, 16 - movhps xmm2, [edi+2*4] // xmm2 = 6, 7, 2, 3 - movhps xmm5, [edi+12*4] // xmm5 = 16, 17, 12, 13 - movaps xmm3, xmm2 // xmm3 = 6, 7, 2, 3 - shufps xmm2, xmm5, R_SHUFFLEPS( 2, 1, 2, 1 ) // xmm2 = 2, 7, 12, 17 - movlps xmm3, [edi+8*4] // xmm3 = 8, 9, 2, 3 - movlps xmm5, [edi+18*4] // xmm5 = 18, 19, 12, 13 - movss xmm4, [edi+4*4] // xmm4 = 4, X, X, X - movlhps xmm4, xmm3 // xmm4 = 4, X, 8, 9 - shufps xmm3, xmm5, R_SHUFFLEPS( 3, 0, 3, 0 ) // xmm3 = 3, 8, 13, 18 - movhps xmm5, [edi+14*4] // xmm6 = 18, 19, 14, 15 - shufps xmm4, xmm5, R_SHUFFLEPS( 0, 3, 2, 1 ) // xmm4 = 4, 9, 14, 19 - movss xmm7, [esi+0*4] - shufps xmm7, xmm7, 0 - mulps xmm0, xmm7 - movss xmm5, [esi+1*4] - shufps xmm5, xmm5, 0 - mulps xmm1, xmm5 - addps xmm0, xmm1 - movss xmm6, [esi+2*4] - shufps xmm6, xmm6, 0 - mulps xmm2, xmm6 - addps xmm0, xmm2 - movss xmm1, [esi+3*4] - shufps xmm1, xmm1, 0 - mulps xmm3, xmm1 - addps xmm0, xmm3 - movss xmm2, [esi+4*4] - shufps xmm2, xmm2, 0 - mulps xmm4, xmm2 - addps xmm0, xmm4 - mulss xmm7, [edi+20*4] - mulss xmm5, [edi+21*4] - addps xmm7, xmm5 - mulss xmm6, [edi+22*4] - addps xmm7, xmm6 - mulss xmm1, [edi+23*4] - addps xmm7, xmm1 - mulss xmm2, [edi+24*4] - addps xmm7, xmm2 - STORE4( 0, xmm0, xmm3 ) - STORE1( 16, xmm7, xmm4 ) - } - return; - } - case 6: { // 6x5 * 5x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm6, [esi] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) - movlps xmm7, [esi+8] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) - movlps xmm0, [edi] - movhps xmm3, [edi+8] - movaps xmm1, [edi+16] - movlps xmm2, [edi+32] - shufps xmm0, xmm1, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm0 = 0, 1, 5, 6 - shufps xmm1, xmm2, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm1 = 4, 7, 8, 9 - shufps xmm3, xmm1, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm3 = 2, 3, 7, 8 - mulps xmm0, xmm6 - mulps xmm3, xmm7 - movlps xmm2, [edi+40] - addps xmm0, xmm3 // xmm0 + xmm1 - movhps xmm5, [edi+40+8] - movlps xmm3, [edi+40+16] - movhps xmm3, [edi+40+24] - movlps xmm4, [edi+40+32] - shufps xmm2, xmm3, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm2 = 10, 11, 15, 16 - shufps xmm3, xmm4, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm3 = 14, 17, 18, 19 - shufps xmm5, xmm3, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm5 = 12, 13, 17, 18 - mulps xmm2, xmm6 - mulps xmm5, xmm7 - addps xmm2, xmm5 // xmm2 + xmm3 - movss xmm5, [esi+16] - shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm4, xmm0 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm4, xmm2, R_SHUFFLEPS( 1, 3, 1, 3 ) - shufps xmm1, xmm3, R_SHUFFLEPS( 0, 3, 0, 3 ) - addps xmm0, xmm4 - mulps xmm1, xmm5 - addps xmm0, xmm1 - STORE4( 0, xmm0, xmm2 ) - movlps xmm4, [edi+80] - movhps xmm3, [edi+80+8] - movaps xmm1, [edi+80+16] - movlps xmm2, [edi+80+32] - shufps xmm4, xmm1, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm4 = 20, 21, 25, 26 - shufps xmm1, xmm2, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm1 = 24, 27, 28, 29 - shufps xmm3, xmm1, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm3 = 22, 23, 27, 28 - mulps xmm4, xmm6 - mulps xmm3, xmm7 - mulps xmm1, xmm5 - addps xmm4, xmm3 // xmm4 + xmm1 - shufps xmm1, xmm4, R_SHUFFLEPS( 0, 3, 0, 2 ) - shufps xmm4, xmm4, R_SHUFFLEPS( 1, 3, 0, 0 ) - addps xmm4, xmm1 - shufps xmm1, xmm1, R_SHUFFLEPS( 2, 3, 0, 1 ) - addps xmm4, xmm1 - STORE2LO( 16, xmm4, xmm2 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4]; - mPtr += 5; - } - return; - } + case 6: { // 6x2 * 2x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm7, [esi] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) + movaps xmm0, [edi] + mulps xmm0, xmm7 + movaps xmm1, [edi + 16] + mulps xmm1, xmm7 + movaps xmm2, xmm0 + shufps xmm0, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm2, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) + movaps xmm3, [edi + 32] + addps xmm0, xmm2 + mulps xmm3, xmm7 + STORE4( 0, xmm0, xmm4 ) + shufps xmm3, xmm3, R_SHUFFLEPS( 0, 2, 1, 3 ) + movhlps xmm1, xmm3 + addps xmm3, xmm1 + STORE2LO( 16, xmm3, xmm4 ) } - break; + return; } - case 6: { - switch( numRows ) { - case 1: { // 1x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - mulss xmm0, [edi] - movss xmm1, [esi+4] - mulss xmm1, [edi+4] - movss xmm2, [esi+8] - addss xmm0, xmm1 - mulss xmm2, [edi+8] - movss xmm3, [esi+12] - addss xmm0, xmm2 - mulss xmm3, [edi+12] - movss xmm4, [esi+16] - addss xmm0, xmm3 - mulss xmm4, [edi+16] - movss xmm5, [esi+20] - addss xmm0, xmm4 - mulss xmm5, [edi+20] - movss xmm6, [esi+24] - addss xmm0, xmm5 - mulss xmm6, [edi+24] - addss xmm0, xmm6 - STORE1( 0, xmm0, xmm7 ) - } - return; - } - case 2: { // 2x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - // load idVecX - movlps xmm4, [esi] - movhps xmm4, [esi+8] - movlps xmm5, [esi+16] - movlhps xmm5, xmm4 - movhlps xmm6, xmm4 - movlhps xmm6, xmm5 - // row 0 and 1 - movaps xmm0, [edi] - movaps xmm1, [edi+16] - movaps xmm2, [edi+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm3, xmm0 - movlhps xmm3, xmm2 - addps xmm1, xmm3 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm1, xmm0 - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) - movhlps xmm0, xmm1 - addps xmm0, xmm1 - STORE2LO( 0, xmm0, xmm3 ) - } - return; - } - case 3: { // 3x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - // load idVecX - movlps xmm4, [esi] - movhps xmm4, [esi+8] - movlps xmm5, [esi+16] - movlhps xmm5, xmm4 - movhlps xmm6, xmm4 - movlhps xmm6, xmm5 - // row 0 and 1 - movaps xmm0, [edi] - movaps xmm1, [edi+16] - movaps xmm2, [edi+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm3, xmm0 - movlhps xmm3, xmm2 - addps xmm1, xmm3 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm1, xmm0 - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) - movhlps xmm0, xmm1 - addps xmm0, xmm1 - STORE2LO( 0, xmm0, xmm3 ) - // row 2 - movaps xmm0, [edi+48] - movaps xmm1, [edi+48+16] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - addps xmm0, xmm1 - movhlps xmm1, xmm0 - addps xmm0, xmm1 - movaps xmm1, xmm0 - shufps xmm1, xmm1, R_SHUFFLEPS( 1, 0, 0, 0 ) - addss xmm0, xmm1 - STORE1( 8, xmm0, xmm3 ) - } - return; - } - case 4: { // 4x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - // load idVecX - movlps xmm4, [esi] - movhps xmm4, [esi+8] - movlps xmm5, [esi+16] - movlhps xmm5, xmm4 - movhlps xmm6, xmm4 - movlhps xmm6, xmm5 - // row 0 and 1 - movaps xmm0, [edi] - movaps xmm1, [edi+16] - movaps xmm2, [edi+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm7, xmm0 - movlhps xmm7, xmm2 - addps xmm7, xmm1 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm7, xmm0 - // row 2 and 3 - movaps xmm0, [edi+48] - movaps xmm1, [edi+48+16] - movaps xmm2, [edi+48+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm3, xmm0 - movlhps xmm3, xmm2 - addps xmm1, xmm3 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm1, xmm0 - // last 4 additions for the first 4 rows and store result - movaps xmm0, xmm7 - shufps xmm7, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) - addps xmm0, xmm7 - STORE4( 0, xmm0, xmm4 ) - } - return; - } - case 5: { // 5x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - // load idVecX - movlps xmm4, [esi] - movhps xmm4, [esi+8] - movlps xmm5, [esi+16] - movlhps xmm5, xmm4 - movhlps xmm6, xmm4 - movlhps xmm6, xmm5 - // row 0 and 1 - movaps xmm0, [edi] - movaps xmm1, [edi+16] - movaps xmm2, [edi+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm7, xmm0 - movlhps xmm7, xmm2 - addps xmm7, xmm1 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm7, xmm0 - // row 2 and 3 - movaps xmm0, [edi+48] - movaps xmm1, [edi+48+16] - movaps xmm2, [edi+48+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm3, xmm0 - movlhps xmm3, xmm2 - addps xmm1, xmm3 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm1, xmm0 - // last 4 additions for the first 4 rows and store result - movaps xmm0, xmm7 - shufps xmm7, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) - addps xmm0, xmm7 - STORE4( 0, xmm0, xmm3 ) - // row 5 - movaps xmm0, [edi+96] - movaps xmm1, [edi+96+16] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - addps xmm0, xmm1 - movhlps xmm1, xmm0 - addps xmm0, xmm1 - movaps xmm1, xmm0 - shufps xmm1, xmm1, 0x01 - addss xmm0, xmm1 - STORE1( 16, xmm0, xmm3 ) - } - return; - } - case 6: { // 6x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm7, qword ptr [esi] - movlps xmm6, qword ptr [esi+8] - shufps xmm7, xmm7, 0x44 - shufps xmm6, xmm6, 0x44 - movlps xmm0, qword ptr [edi ] - movhps xmm0, qword ptr [edi+ 24] - mulps xmm0, xmm7 - movlps xmm3, qword ptr [edi+ 8] - movhps xmm3, qword ptr [edi+ 32] - mulps xmm3, xmm6 - movlps xmm1, qword ptr [edi+ 48] - movhps xmm1, qword ptr [edi+ 72] - mulps xmm1, xmm7 - movlps xmm2, qword ptr [edi+ 96] - movhps xmm2, qword ptr [edi+120] - mulps xmm2, xmm7 - movlps xmm4, qword ptr [edi+ 56] - movhps xmm4, qword ptr [edi+ 80] - movlps xmm5, qword ptr [edi+104] - movhps xmm5, qword ptr [edi+128] - mulps xmm4, xmm6 - movlps xmm7, qword ptr [esi+16] - addps xmm0, xmm3 - shufps xmm7, xmm7, 0x44 - mulps xmm5, xmm6 - addps xmm1, xmm4 - movlps xmm3, qword ptr [edi+ 16] - movhps xmm3, qword ptr [edi+ 40] - addps xmm2, xmm5 - movlps xmm4, qword ptr [edi+ 64] - movhps xmm4, qword ptr [edi+ 88] - mulps xmm3, xmm7 - movlps xmm5, qword ptr [edi+112] - movhps xmm5, qword ptr [edi+136] - addps xmm0, xmm3 - mulps xmm4, xmm7 - mulps xmm5, xmm7 - addps xmm1, xmm4 - addps xmm2, xmm5 - movaps xmm6, xmm0 - shufps xmm0, xmm1, 0x88 - shufps xmm6, xmm1, 0xDD - movaps xmm7, xmm2 - shufps xmm7, xmm2, 0x88 - shufps xmm2, xmm2, 0xDD - addps xmm0, xmm6 - addps xmm2, xmm7 - STORE4( 0, xmm0, xmm3 ) - STORE2LO( 16, xmm2, xmm4 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + - mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4] + mPtr[5] * vPtr[5]; - mPtr += 6; - } - return; - } + default: { + for ( int i = 0; i < numRows; i++ ) { + dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1]; + mPtr += 2; } - break; + return; + } + } + break; + } + case 3: { + switch ( numRows ) { + case 3: { // 3x3 * 3x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + movss xmm4, [edi] + mulss xmm4, xmm0 + movss xmm1, [esi+4] + movss xmm5, [edi+4] + mulss xmm5, xmm1 + addss xmm4, xmm5 + movss xmm2, [esi+8] + movss xmm6, [edi+8] + mulss xmm6, xmm2 + addss xmm4, xmm6 + movss xmm3, [edi+12] + mulss xmm3, xmm0 + STORE1( 0, xmm4, xmm7 ); + movss xmm5, [edi + 12 + 4] + mulss xmm5, xmm1 + addss xmm3, xmm5 + movss xmm6, [edi + 12 + 8] + mulss xmm6, xmm2 + addss xmm3, xmm6 + mulss xmm0, [edi + 24] + mulss xmm1, [edi + 24 + 4] + STORE1( 4, xmm3, xmm7 ); + addss xmm0, xmm1 + mulss xmm2, [edi + 24 + 8] + addss xmm0, xmm2 + STORE1( 8, xmm0, xmm7 ); + } + return; + } + case 6: { // 6x3 * 3x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm5, [esi] + shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) + movss xmm6, [esi + 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + movss xmm7, [esi + 8] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm0, [edi] // xmm0 = 0, 1, 2, 3 + movlps xmm1, [edi + 4 * 4] + shufps xmm1, xmm0, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm1 = 4, 5, 1, 2 + movlps xmm2, [edi + 6 * 4] + movhps xmm2, [edi + 8 * 4] // xmm2 = 6, 7, 8, 9 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 3, 0, 3 ) // xmm0 = 0, 3, 6, 9 + mulps xmm0, xmm5 + movlps xmm3, [edi + 10 * 4] + shufps xmm2, xmm3, R_SHUFFLEPS( 1, 2, 0, 1 ) // xmm2 = 7, 8, 10, 11 + movaps xmm3, xmm1 + shufps xmm1, xmm2, R_SHUFFLEPS( 2, 0, 0, 2 ) // xmm1 = 1, 4, 7, 10 + mulps xmm1, xmm6 + shufps xmm3, xmm2, R_SHUFFLEPS( 3, 1, 1, 3 ) // xmm3 = 2, 5, 8, 11 + mulps xmm3, xmm7 + addps xmm0, xmm1 + addps xmm0, xmm3 + STORE4( 0, xmm0, xmm4 ) + movss xmm1, [edi + 12 * 4] + mulss xmm1, xmm5 + movss xmm2, [edi + 13 * 4] + mulss xmm2, xmm6 + movss xmm3, [edi + 14 * 4] + mulss xmm3, xmm7 + addss xmm1, xmm2 + addss xmm1, xmm3 + STORE1( 16, xmm1, xmm4 ) + mulss xmm5, [edi + 15 * 4] + mulss xmm6, [edi + 16 * 4] + mulss xmm7, [edi + 17 * 4] + addss xmm5, xmm6 + addss xmm5, xmm7 + STORE1( 20, xmm5, xmm4 ) + } + return; } default: { - int numColumns = mat.GetNumColumns(); for ( int i = 0; i < numRows; i++ ) { - float sum = mPtr[0] * vPtr[0]; - for ( int j = 1; j < numColumns; j++ ) { - sum += mPtr[j] * vPtr[j]; - } - dstPtr[i] STOREC sum; - mPtr += numColumns; + dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2]; + mPtr += 3; } - break; + return; + } + } + break; + } + case 4: { + switch ( numRows ) { + case 4: { // 4x4 * 4x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm6, qword ptr [esi ] + movlps xmm0, qword ptr [edi ] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) + movhps xmm0, qword ptr [edi + 16] + mulps xmm0, xmm6 + movlps xmm7, qword ptr [esi + 8] + movlps xmm2, qword ptr [edi + 8] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) + movhps xmm2, qword ptr [edi + 24] + mulps xmm2, xmm7 + movlps xmm1, qword ptr [edi + 32] + movhps xmm1, qword ptr [edi + 48] + mulps xmm1, xmm6 + movlps xmm3, qword ptr [edi + 40] + addps xmm0, xmm2 + movhps xmm3, qword ptr [edi + 56] + mulps xmm3, xmm7 + movaps xmm4, xmm0 + addps xmm1, xmm3 + shufps xmm4, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) + addps xmm0, xmm4 + STORE4( 0, xmm0, xmm2 ) + } + return; + } + case 6: { // 6x4 * 4x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm6, qword ptr [esi+ 0] + movlps xmm0, qword ptr [edi+ 0] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) + movhps xmm0, qword ptr [edi + 16] + mulps xmm0, xmm6 + movlps xmm7, qword ptr [esi + 8] + movlps xmm2, qword ptr [edi + 8] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) + movhps xmm2, qword ptr [edi + 24] + mulps xmm2, xmm7 + movlps xmm1, qword ptr [edi + 32] + movhps xmm1, qword ptr [edi + 48] + mulps xmm1, xmm6 + movlps xmm3, qword ptr [edi + 40] + addps xmm0, xmm2 + movhps xmm3, qword ptr [edi + 56] + mulps xmm3, xmm7 + movaps xmm4, xmm0 + addps xmm1, xmm3 + shufps xmm4, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) + addps xmm0, xmm4 + movlps xmm1, qword ptr [edi + 64] + movhps xmm1, qword ptr [edi + 80] + STORE4( 0, xmm0, xmm4 ) + mulps xmm1, xmm6 + movlps xmm2, qword ptr [edi + 72] + movhps xmm2, qword ptr [edi + 88] + mulps xmm2, xmm7 + addps xmm1, xmm2 + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) + movhlps xmm3, xmm1 + addps xmm1, xmm3 + STORE2LO( 16, xmm1, xmm4 ) + } + return; + } + default: { + for ( int i = 0; i < numRows; i++ ) { + dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + mPtr[3] * vPtr[3]; + mPtr += 4; + } + return; + } + } + break; + } + case 5: { + switch ( numRows ) { + case 5: { // 5x5 * 5x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [edi+5*4] // xmm0 = 5, X, X, X + movhps xmm0, [edi+0*4] // xmm0 = 5, X, 0, 1 + movss xmm5, [edi+15*4] // xmm4 = 15, X, X, X + movhps xmm5, [edi+10*4] // xmm5 = 15, X, 10, 11 + movaps xmm1, xmm0 // xmm1 = 5, X, 0, 1 + shufps xmm0, xmm5, R_SHUFFLEPS( 2, 0, 2, 0 ) // xmm0 = 0, 5, 10, 15 + movlps xmm1, [edi + 6 * 4] // xmm1 = 6, 7, 0, 1 + movlps xmm5, [edi + 16 * 4] // xmm5 = 16, 17, 10, 11 + movaps xmm2, xmm1 // xmm2 = 6, 7, 0, 1 + shufps xmm1, xmm5, R_SHUFFLEPS( 3, 0, 3, 0 ) // xmm1 = 1, 6, 11, 16 + movhps xmm2, [edi + 2 * 4] // xmm2 = 6, 7, 2, 3 + movhps xmm5, [edi + 12 * 4] // xmm5 = 16, 17, 12, 13 + movaps xmm3, xmm2 // xmm3 = 6, 7, 2, 3 + shufps xmm2, xmm5, R_SHUFFLEPS( 2, 1, 2, 1 ) // xmm2 = 2, 7, 12, 17 + movlps xmm3, [edi + 8 * 4] // xmm3 = 8, 9, 2, 3 + movlps xmm5, [edi + 18 * 4] // xmm5 = 18, 19, 12, 13 + movss xmm4, [edi + 4 * 4] // xmm4 = 4, X, X, X + movlhps xmm4, xmm3 // xmm4 = 4, X, 8, 9 + shufps xmm3, xmm5, R_SHUFFLEPS( 3, 0, 3, 0 ) // xmm3 = 3, 8, 13, 18 + movhps xmm5, [edi + 14 * 4] // xmm6 = 18, 19, 14, 15 + shufps xmm4, xmm5, R_SHUFFLEPS( 0, 3, 2, 1 ) // xmm4 = 4, 9, 14, 19 + movss xmm7, [esi + 0 * 4] + shufps xmm7, xmm7, 0 + mulps xmm0, xmm7 + movss xmm5, [esi + 1 * 4] + shufps xmm5, xmm5, 0 + mulps xmm1, xmm5 + addps xmm0, xmm1 + movss xmm6, [esi + 2 * 4] + shufps xmm6, xmm6, 0 + mulps xmm2, xmm6 + addps xmm0, xmm2 + movss xmm1, [esi + 3 * 4] + shufps xmm1, xmm1, 0 + mulps xmm3, xmm1 + addps xmm0, xmm3 + movss xmm2, [esi + 4 * 4] + shufps xmm2, xmm2, 0 + mulps xmm4, xmm2 + addps xmm0, xmm4 + mulss xmm7, [edi + 20 * 4] + mulss xmm5, [edi + 21 * 4] + addps xmm7, xmm5 + mulss xmm6, [edi + 22 * 4] + addps xmm7, xmm6 + mulss xmm1, [edi + 23 * 4] + addps xmm7, xmm1 + mulss xmm2, [edi + 24 * 4] + addps xmm7, xmm2 + STORE4( 0, xmm0, xmm3 ) + STORE1( 16, xmm7, xmm4 ) + } + return; + } + case 6: { // 6x5 * 5x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm6, [esi] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) + movlps xmm7, [esi + 8] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) + movlps xmm0, [edi] + movhps xmm3, [edi + 8] + movaps xmm1, [edi + 16] + movlps xmm2, [edi + 32] + shufps xmm0, xmm1, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm0 = 0, 1, 5, 6 + shufps xmm1, xmm2, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm1 = 4, 7, 8, 9 + shufps xmm3, xmm1, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm3 = 2, 3, 7, 8 + mulps xmm0, xmm6 + mulps xmm3, xmm7 + movlps xmm2, [edi + 40] + addps xmm0, xmm3 // xmm0 + xmm1 + movhps xmm5, [edi + 40 + 8] + movlps xmm3, [edi + 40 + 16] + movhps xmm3, [edi + 40 + 24] + movlps xmm4, [edi + 40 + 32] + shufps xmm2, xmm3, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm2 = 10, 11, 15, 16 + shufps xmm3, xmm4, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm3 = 14, 17, 18, 19 + shufps xmm5, xmm3, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm5 = 12, 13, 17, 18 + mulps xmm2, xmm6 + mulps xmm5, xmm7 + addps xmm2, xmm5 // xmm2 + xmm3 + movss xmm5, [esi + 16] + shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm4, xmm0 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm4, xmm2, R_SHUFFLEPS( 1, 3, 1, 3 ) + shufps xmm1, xmm3, R_SHUFFLEPS( 0, 3, 0, 3 ) + addps xmm0, xmm4 + mulps xmm1, xmm5 + addps xmm0, xmm1 + STORE4( 0, xmm0, xmm2 ) + movlps xmm4, [edi + 80] + movhps xmm3, [edi + 80 + 8] + movaps xmm1, [edi + 80 + 16] + movlps xmm2, [edi + 80 + 32] + shufps xmm4, xmm1, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm4 = 20, 21, 25, 26 + shufps xmm1, xmm2, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm1 = 24, 27, 28, 29 + shufps xmm3, xmm1, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm3 = 22, 23, 27, 28 + mulps xmm4, xmm6 + mulps xmm3, xmm7 + mulps xmm1, xmm5 + addps xmm4, xmm3 // xmm4 + xmm1 + shufps xmm1, xmm4, R_SHUFFLEPS( 0, 3, 0, 2 ) + shufps xmm4, xmm4, R_SHUFFLEPS( 1, 3, 0, 0 ) + addps xmm4, xmm1 + shufps xmm1, xmm1, R_SHUFFLEPS( 2, 3, 0, 1 ) + addps xmm4, xmm1 + STORE2LO( 16, xmm4, xmm2 ) + } + return; + } + default: { + for ( int i = 0; i < numRows; i++ ) { + dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4]; + mPtr += 5; + } + return; + } + } + break; + } + case 6: { + switch ( numRows ) { + case 1: { // 1x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + mulss xmm0, [edi] + movss xmm1, [esi+4] + mulss xmm1, [edi+4] + movss xmm2, [esi+8] + addss xmm0, xmm1 + mulss xmm2, [edi+8] + movss xmm3, [esi+12] + addss xmm0, xmm2 + mulss xmm3, [edi+12] + movss xmm4, [esi+16] + addss xmm0, xmm3 + mulss xmm4, [edi+16] + movss xmm5, [esi+20] + addss xmm0, xmm4 + mulss xmm5, [edi+20] + movss xmm6, [esi+24] + addss xmm0, xmm5 + mulss xmm6, [edi+24] + addss xmm0, xmm6 + STORE1( 0, xmm0, xmm7 ) + } + return; + } + case 2: { // 2x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + // load idVecX + movlps xmm4, [esi] + movhps xmm4, [esi+8] + movlps xmm5, [esi+16] + movlhps xmm5, xmm4 + movhlps xmm6, xmm4 + movlhps xmm6, xmm5 + // row 0 and 1 + movaps xmm0, [edi] + movaps xmm1, [edi+16] + movaps xmm2, [edi+32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm3, xmm0 + movlhps xmm3, xmm2 + addps xmm1, xmm3 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm1, xmm0 + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) + movhlps xmm0, xmm1 + addps xmm0, xmm1 + STORE2LO( 0, xmm0, xmm3 ) + } + return; + } + case 3: { // 3x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + // load idVecX + movlps xmm4, [esi] + movhps xmm4, [esi+8] + movlps xmm5, [esi+16] + movlhps xmm5, xmm4 + movhlps xmm6, xmm4 + movlhps xmm6, xmm5 + // row 0 and 1 + movaps xmm0, [edi] + movaps xmm1, [edi+16] + movaps xmm2, [edi+32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm3, xmm0 + movlhps xmm3, xmm2 + addps xmm1, xmm3 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm1, xmm0 + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) + movhlps xmm0, xmm1 + addps xmm0, xmm1 + STORE2LO( 0, xmm0, xmm3 ) + // row 2 + movaps xmm0, [edi + 48] + movaps xmm1, [edi + 48 + 16] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + addps xmm0, xmm1 + movhlps xmm1, xmm0 + addps xmm0, xmm1 + movaps xmm1, xmm0 + shufps xmm1, xmm1, R_SHUFFLEPS( 1, 0, 0, 0 ) + addss xmm0, xmm1 + STORE1( 8, xmm0, xmm3 ) + } + return; + } + case 4: { // 4x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + // load idVecX + movlps xmm4, [esi] + movhps xmm4, [esi+8] + movlps xmm5, [esi+16] + movlhps xmm5, xmm4 + movhlps xmm6, xmm4 + movlhps xmm6, xmm5 + // row 0 and 1 + movaps xmm0, [edi] + movaps xmm1, [edi+16] + movaps xmm2, [edi+32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm7, xmm0 + movlhps xmm7, xmm2 + addps xmm7, xmm1 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm7, xmm0 + // row 2 and 3 + movaps xmm0, [edi + 48] + movaps xmm1, [edi + 48 + 16] + movaps xmm2, [edi + 48 + 32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm3, xmm0 + movlhps xmm3, xmm2 + addps xmm1, xmm3 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm1, xmm0 + // last 4 additions for the first 4 rows and store result + movaps xmm0, xmm7 + shufps xmm7, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) + addps xmm0, xmm7 + STORE4( 0, xmm0, xmm4 ) + } + return; + } + case 5: { // 5x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + // load idVecX + movlps xmm4, [esi] + movhps xmm4, [esi+8] + movlps xmm5, [esi+16] + movlhps xmm5, xmm4 + movhlps xmm6, xmm4 + movlhps xmm6, xmm5 + // row 0 and 1 + movaps xmm0, [edi] + movaps xmm1, [edi+16] + movaps xmm2, [edi+32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm7, xmm0 + movlhps xmm7, xmm2 + addps xmm7, xmm1 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm7, xmm0 + // row 2 and 3 + movaps xmm0, [edi + 48] + movaps xmm1, [edi + 48 + 16] + movaps xmm2, [edi + 48 + 32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm3, xmm0 + movlhps xmm3, xmm2 + addps xmm1, xmm3 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm1, xmm0 + // last 4 additions for the first 4 rows and store result + movaps xmm0, xmm7 + shufps xmm7, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) + addps xmm0, xmm7 + STORE4( 0, xmm0, xmm3 ) + // row 5 + movaps xmm0, [edi + 96] + movaps xmm1, [edi + 96 + 16] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + addps xmm0, xmm1 + movhlps xmm1, xmm0 + addps xmm0, xmm1 + movaps xmm1, xmm0 + shufps xmm1, xmm1, 0x01 + addss xmm0, xmm1 + STORE1( 16, xmm0, xmm3 ) + } + return; + } + case 6: { // 6x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm7, qword ptr [esi] + movlps xmm6, qword ptr [esi+8] + shufps xmm7, xmm7, 0x44 + shufps xmm6, xmm6, 0x44 + movlps xmm0, qword ptr [edi ] + movhps xmm0, qword ptr [edi+ 24] + mulps xmm0, xmm7 + movlps xmm3, qword ptr [edi+ 8] + movhps xmm3, qword ptr [edi+ 32] + mulps xmm3, xmm6 + movlps xmm1, qword ptr [edi+ 48] + movhps xmm1, qword ptr [edi+ 72] + mulps xmm1, xmm7 + movlps xmm2, qword ptr [edi+ 96] + movhps xmm2, qword ptr [edi+120] + mulps xmm2, xmm7 + movlps xmm4, qword ptr [edi+ 56] + movhps xmm4, qword ptr [edi+ 80] + movlps xmm5, qword ptr [edi+104] + movhps xmm5, qword ptr [edi+128] + mulps xmm4, xmm6 + movlps xmm7, qword ptr [esi+16] + addps xmm0, xmm3 + shufps xmm7, xmm7, 0x44 + mulps xmm5, xmm6 + addps xmm1, xmm4 + movlps xmm3, qword ptr [edi+ 16] + movhps xmm3, qword ptr [edi+ 40] + addps xmm2, xmm5 + movlps xmm4, qword ptr [edi+ 64] + movhps xmm4, qword ptr [edi+ 88] + mulps xmm3, xmm7 + movlps xmm5, qword ptr [edi+112] + movhps xmm5, qword ptr [edi+136] + addps xmm0, xmm3 + mulps xmm4, xmm7 + mulps xmm5, xmm7 + addps xmm1, xmm4 + addps xmm2, xmm5 + movaps xmm6, xmm0 + shufps xmm0, xmm1, 0x88 + shufps xmm6, xmm1, 0xDD + movaps xmm7, xmm2 + shufps xmm7, xmm2, 0x88 + shufps xmm2, xmm2, 0xDD + addps xmm0, xmm6 + addps xmm2, xmm7 + STORE4( 0, xmm0, xmm3 ) + STORE2LO( 16, xmm2, xmm4 ) + } + return; + } + default: { + for ( int i = 0; i < numRows; i++ ) { + dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + + mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4] + mPtr[5] * vPtr[5]; + mPtr += 6; + } + return; + } + } + break; + } + default: { + int numColumns = mat.GetNumColumns(); + for ( int i = 0; i < numRows; i++ ) { + float sum = mPtr[0] * vPtr[0]; + for ( int j = 1; j < numColumns; j++ ) { + sum += mPtr[j] * vPtr[j]; + } + dstPtr[i] STOREC sum; + mPtr += numColumns; } + break; + } } #undef STOREC @@ -5166,698 +5259,698 @@ void VPCALL idSIMD_SSE::MatX_MultiplyAddVecX( idVecX &dst, const idMatX &mat, co vPtr = vec.ToFloatPtr(); dstPtr = dst.ToFloatPtr(); numRows = mat.GetNumRows(); - switch( mat.GetNumColumns() ) { - case 1: { - switch( numRows ) { - case 1: { // 1x1 * 1x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - mulss xmm0, [edi] - STORE1( 0, xmm0, xmm1 ) - } - return; - } - case 6: { // 6x1 * 1x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm1, xmm0 - mulps xmm0, [edi] - mulps xmm1, [edi+16] - STORE4( 0, xmm0, xmm2 ) - STORE2LO( 16, xmm1, xmm2 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0]; - mPtr++; - } - return; - } + switch ( mat.GetNumColumns() ) { + case 1: { + switch ( numRows ) { + case 1: { // 1x1 * 1x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + mulss xmm0, [edi] + STORE1( 0, xmm0, xmm1 ) } - break; + return; } - case 2: { - switch( numRows ) { - case 2: { // 2x2 * 2x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - movss xmm1, [esi+4] - movss xmm2, [edi] - mulss xmm2, xmm0 - movss xmm3, [edi+4] - mulss xmm3, xmm1 - addss xmm2, xmm3 - STORE1( 0, xmm2, xmm4 ) - mulss xmm0, [edi+8] - mulss xmm1, [edi+8+4] - addss xmm0, xmm1 - STORE1( 4, xmm0, xmm4 ) - } - return; - } - case 6: { // 6x2 * 2x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm7, [esi] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) - movaps xmm0, [edi] - mulps xmm0, xmm7 - movaps xmm1, [edi+16] - mulps xmm1, xmm7 - movaps xmm2, xmm0 - shufps xmm0, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm2, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) - movaps xmm3, [edi+32] - addps xmm0, xmm2 - mulps xmm3, xmm7 - STORE4( 0, xmm0, xmm4 ) - shufps xmm3, xmm3, R_SHUFFLEPS( 0, 2, 1, 3 ) - movhlps xmm1, xmm3 - addps xmm3, xmm1 - STORE2LO( 16, xmm3, xmm4 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1]; - mPtr += 2; - } - return; - } + case 6: { // 6x1 * 1x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm1, xmm0 + mulps xmm0, [edi] + mulps xmm1, [edi + 16] + STORE4( 0, xmm0, xmm2 ) + STORE2LO( 16, xmm1, xmm2 ) } - break; + return; } - case 3: { - switch( numRows ) { - case 3: { // 3x3 * 3x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - movss xmm4, [edi] - mulss xmm4, xmm0 - movss xmm1, [esi+4] - movss xmm5, [edi+4] - mulss xmm5, xmm1 - addss xmm4, xmm5 - movss xmm2, [esi+8] - movss xmm6, [edi+8] - mulss xmm6, xmm2 - addss xmm4, xmm6 - movss xmm3, [edi+12] - mulss xmm3, xmm0 - STORE1( 0, xmm4, xmm7 ); - movss xmm5, [edi+12+4] - mulss xmm5, xmm1 - addss xmm3, xmm5 - movss xmm6, [edi+12+8] - mulss xmm6, xmm2 - addss xmm3, xmm6 - mulss xmm0, [edi+24] - mulss xmm1, [edi+24+4] - STORE1( 4, xmm3, xmm7 ); - addss xmm0, xmm1 - mulss xmm2, [edi+24+8] - addss xmm0, xmm2 - STORE1( 8, xmm0, xmm7 ); - } - return; - } - case 6: { // 6x3 * 3x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm5, [esi] - shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm6, [esi+4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm7, [esi+8] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm0, [edi] // xmm0 = 0, 1, 2, 3 - movlps xmm1, [edi+4*4] - shufps xmm1, xmm0, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm1 = 4, 5, 1, 2 - movlps xmm2, [edi+6*4] - movhps xmm2, [edi+8*4] // xmm2 = 6, 7, 8, 9 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 3, 0, 3 ) // xmm0 = 0, 3, 6, 9 - mulps xmm0, xmm5 - movlps xmm3, [edi+10*4] - shufps xmm2, xmm3, R_SHUFFLEPS( 1, 2, 0, 1 ) // xmm2 = 7, 8, 10, 11 - movaps xmm3, xmm1 - shufps xmm1, xmm2, R_SHUFFLEPS( 2, 0, 0, 2 ) // xmm1 = 1, 4, 7, 10 - mulps xmm1, xmm6 - shufps xmm3, xmm2, R_SHUFFLEPS( 3, 1, 1, 3 ) // xmm3 = 2, 5, 8, 11 - mulps xmm3, xmm7 - addps xmm0, xmm1 - addps xmm0, xmm3 - STORE4( 0, xmm0, xmm4 ) - movss xmm1, [edi+12*4] - mulss xmm1, xmm5 - movss xmm2, [edi+13*4] - mulss xmm2, xmm6 - movss xmm3, [edi+14*4] - mulss xmm3, xmm7 - addss xmm1, xmm2 - addss xmm1, xmm3 - STORE1( 16, xmm1, xmm4 ) - mulss xmm5, [edi+15*4] - mulss xmm6, [edi+16*4] - mulss xmm7, [edi+17*4] - addss xmm5, xmm6 - addss xmm5, xmm7 - STORE1( 20, xmm5, xmm4 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2]; - mPtr += 3; - } - return; - } + default: { + for ( int i = 0; i < numRows; i++ ) { + dstPtr[i] STOREC mPtr[0] * vPtr[0]; + mPtr++; } - break; + return; } - case 4: { - switch( numRows ) { - case 4: { // 4x4 * 4x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm6, qword ptr [esi ] - movlps xmm0, qword ptr [edi ] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) - movhps xmm0, qword ptr [edi+16] - mulps xmm0, xmm6 - movlps xmm7, qword ptr [esi+ 8] - movlps xmm2, qword ptr [edi+ 8] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) - movhps xmm2, qword ptr [edi+24] - mulps xmm2, xmm7 - movlps xmm1, qword ptr [edi+32] - movhps xmm1, qword ptr [edi+48] - mulps xmm1, xmm6 - movlps xmm3, qword ptr [edi+40] - addps xmm0, xmm2 - movhps xmm3, qword ptr [edi+56] - mulps xmm3, xmm7 - movaps xmm4, xmm0 - addps xmm1, xmm3 - shufps xmm4, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) - addps xmm0, xmm4 - STORE4( 0, xmm0, xmm2 ) - } - return; - } - case 6: { // 6x4 * 4x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm6, qword ptr [esi+ 0] - movlps xmm0, qword ptr [edi+ 0] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) - movhps xmm0, qword ptr [edi+16] - mulps xmm0, xmm6 - movlps xmm7, qword ptr [esi+ 8] - movlps xmm2, qword ptr [edi+ 8] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) - movhps xmm2, qword ptr [edi+24] - mulps xmm2, xmm7 - movlps xmm1, qword ptr [edi+32] - movhps xmm1, qword ptr [edi+48] - mulps xmm1, xmm6 - movlps xmm3, qword ptr [edi+40] - addps xmm0, xmm2 - movhps xmm3, qword ptr [edi+56] - mulps xmm3, xmm7 - movaps xmm4, xmm0 - addps xmm1, xmm3 - shufps xmm4, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) - addps xmm0, xmm4 - movlps xmm1, qword ptr [edi+64] - movhps xmm1, qword ptr [edi+80] - STORE4( 0, xmm0, xmm4 ) - mulps xmm1, xmm6 - movlps xmm2, qword ptr [edi+72] - movhps xmm2, qword ptr [edi+88] - mulps xmm2, xmm7 - addps xmm1, xmm2 - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) - movhlps xmm3, xmm1 - addps xmm1, xmm3 - STORE2LO( 16, xmm1, xmm4 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + mPtr[3] * vPtr[3]; - mPtr += 4; - } - return; - } + } + break; + } + case 2: { + switch ( numRows ) { + case 2: { // 2x2 * 2x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + movss xmm1, [esi+4] + movss xmm2, [edi] + mulss xmm2, xmm0 + movss xmm3, [edi+4] + mulss xmm3, xmm1 + addss xmm2, xmm3 + STORE1( 0, xmm2, xmm4 ) + mulss xmm0, [edi + 8] + mulss xmm1, [edi + 8 + 4] + addss xmm0, xmm1 + STORE1( 4, xmm0, xmm4 ) } - break; + return; } - case 5: { - switch( numRows ) { - case 5: { // 5x5 * 5x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [edi+5*4] // xmm0 = 5, X, X, X - movhps xmm0, [edi+0*4] // xmm0 = 5, X, 0, 1 - movss xmm5, [edi+15*4] // xmm4 = 15, X, X, X - movhps xmm5, [edi+10*4] // xmm5 = 15, X, 10, 11 - movaps xmm1, xmm0 // xmm1 = 5, X, 0, 1 - shufps xmm0, xmm5, R_SHUFFLEPS( 2, 0, 2, 0 ) // xmm0 = 0, 5, 10, 15 - movlps xmm1, [edi+6*4] // xmm1 = 6, 7, 0, 1 - movlps xmm5, [edi+16*4] // xmm5 = 16, 17, 10, 11 - movaps xmm2, xmm1 // xmm2 = 6, 7, 0, 1 - shufps xmm1, xmm5, R_SHUFFLEPS( 3, 0, 3, 0 ) // xmm1 = 1, 6, 11, 16 - movhps xmm2, [edi+2*4] // xmm2 = 6, 7, 2, 3 - movhps xmm5, [edi+12*4] // xmm5 = 16, 17, 12, 13 - movaps xmm3, xmm2 // xmm3 = 6, 7, 2, 3 - shufps xmm2, xmm5, R_SHUFFLEPS( 2, 1, 2, 1 ) // xmm2 = 2, 7, 12, 17 - movlps xmm3, [edi+8*4] // xmm3 = 8, 9, 2, 3 - movlps xmm5, [edi+18*4] // xmm5 = 18, 19, 12, 13 - movss xmm4, [edi+4*4] // xmm4 = 4, X, X, X - movlhps xmm4, xmm3 // xmm4 = 4, X, 8, 9 - shufps xmm3, xmm5, R_SHUFFLEPS( 3, 0, 3, 0 ) // xmm3 = 3, 8, 13, 18 - movhps xmm5, [edi+14*4] // xmm6 = 18, 19, 14, 15 - shufps xmm4, xmm5, R_SHUFFLEPS( 0, 3, 2, 1 ) // xmm4 = 4, 9, 14, 19 - movss xmm7, [esi+0*4] - shufps xmm7, xmm7, 0 - mulps xmm0, xmm7 - movss xmm5, [esi+1*4] - shufps xmm5, xmm5, 0 - mulps xmm1, xmm5 - addps xmm0, xmm1 - movss xmm6, [esi+2*4] - shufps xmm6, xmm6, 0 - mulps xmm2, xmm6 - addps xmm0, xmm2 - movss xmm1, [esi+3*4] - shufps xmm1, xmm1, 0 - mulps xmm3, xmm1 - addps xmm0, xmm3 - movss xmm2, [esi+4*4] - shufps xmm2, xmm2, 0 - mulps xmm4, xmm2 - addps xmm0, xmm4 - mulss xmm7, [edi+20*4] - mulss xmm5, [edi+21*4] - addps xmm7, xmm5 - mulss xmm6, [edi+22*4] - addps xmm7, xmm6 - mulss xmm1, [edi+23*4] - addps xmm7, xmm1 - mulss xmm2, [edi+24*4] - addps xmm7, xmm2 - STORE4( 0, xmm0, xmm3 ) - STORE1( 16, xmm7, xmm4 ) - } - return; - } - case 6: { // 6x5 * 5x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm6, [esi] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) - movlps xmm7, [esi+8] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) - movlps xmm0, [edi] - movhps xmm3, [edi+8] - movaps xmm1, [edi+16] - movlps xmm2, [edi+32] - shufps xmm0, xmm1, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm0 = 0, 1, 5, 6 - shufps xmm1, xmm2, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm1 = 4, 7, 8, 9 - shufps xmm3, xmm1, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm3 = 2, 3, 7, 8 - mulps xmm0, xmm6 - mulps xmm3, xmm7 - movlps xmm2, [edi+40] - addps xmm0, xmm3 // xmm0 + xmm1 - movhps xmm5, [edi+40+8] - movlps xmm3, [edi+40+16] - movhps xmm3, [edi+40+24] - movlps xmm4, [edi+40+32] - shufps xmm2, xmm3, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm2 = 10, 11, 15, 16 - shufps xmm3, xmm4, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm3 = 14, 17, 18, 19 - shufps xmm5, xmm3, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm5 = 12, 13, 17, 18 - mulps xmm2, xmm6 - mulps xmm5, xmm7 - addps xmm2, xmm5 // xmm2 + xmm3 - movss xmm5, [esi+16] - shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm4, xmm0 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm4, xmm2, R_SHUFFLEPS( 1, 3, 1, 3 ) - shufps xmm1, xmm3, R_SHUFFLEPS( 0, 3, 0, 3 ) - addps xmm0, xmm4 - mulps xmm1, xmm5 - addps xmm0, xmm1 - STORE4( 0, xmm0, xmm2 ) - movlps xmm4, [edi+80] - movhps xmm3, [edi+80+8] - movaps xmm1, [edi+80+16] - movlps xmm2, [edi+80+32] - shufps xmm4, xmm1, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm4 = 20, 21, 25, 26 - shufps xmm1, xmm2, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm1 = 24, 27, 28, 29 - shufps xmm3, xmm1, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm3 = 22, 23, 27, 28 - mulps xmm4, xmm6 - mulps xmm3, xmm7 - mulps xmm1, xmm5 - addps xmm4, xmm3 // xmm4 + xmm1 - shufps xmm1, xmm4, R_SHUFFLEPS( 0, 3, 0, 2 ) - shufps xmm4, xmm4, R_SHUFFLEPS( 1, 3, 0, 0 ) - addps xmm4, xmm1 - shufps xmm1, xmm1, R_SHUFFLEPS( 2, 3, 0, 1 ) - addps xmm4, xmm1 - STORE2LO( 16, xmm4, xmm2 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4]; - mPtr += 5; - } - return; - } + case 6: { // 6x2 * 2x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm7, [esi] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) + movaps xmm0, [edi] + mulps xmm0, xmm7 + movaps xmm1, [edi + 16] + mulps xmm1, xmm7 + movaps xmm2, xmm0 + shufps xmm0, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm2, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) + movaps xmm3, [edi + 32] + addps xmm0, xmm2 + mulps xmm3, xmm7 + STORE4( 0, xmm0, xmm4 ) + shufps xmm3, xmm3, R_SHUFFLEPS( 0, 2, 1, 3 ) + movhlps xmm1, xmm3 + addps xmm3, xmm1 + STORE2LO( 16, xmm3, xmm4 ) } - break; + return; } - case 6: { - switch( numRows ) { - case 1: { // 1x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - mulss xmm0, [edi] - movss xmm1, [esi+4] - mulss xmm1, [edi+4] - movss xmm2, [esi+8] - addss xmm0, xmm1 - mulss xmm2, [edi+8] - movss xmm3, [esi+12] - addss xmm0, xmm2 - mulss xmm3, [edi+12] - movss xmm4, [esi+16] - addss xmm0, xmm3 - mulss xmm4, [edi+16] - movss xmm5, [esi+20] - addss xmm0, xmm4 - mulss xmm5, [edi+20] - movss xmm6, [esi+24] - addss xmm0, xmm5 - mulss xmm6, [edi+24] - addss xmm0, xmm6 - STORE1( 0, xmm0, xmm7 ) - } - return; - } - case 2: { // 2x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - // load idVecX - movlps xmm4, [esi] - movhps xmm4, [esi+8] - movlps xmm5, [esi+16] - movlhps xmm5, xmm4 - movhlps xmm6, xmm4 - movlhps xmm6, xmm5 - // row 0 and 1 - movaps xmm0, [edi] - movaps xmm1, [edi+16] - movaps xmm2, [edi+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm3, xmm0 - movlhps xmm3, xmm2 - addps xmm1, xmm3 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm1, xmm0 - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) - movhlps xmm0, xmm1 - addps xmm0, xmm1 - STORE2LO( 0, xmm0, xmm3 ) - } - return; - } - case 3: { // 3x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - // load idVecX - movlps xmm4, [esi] - movhps xmm4, [esi+8] - movlps xmm5, [esi+16] - movlhps xmm5, xmm4 - movhlps xmm6, xmm4 - movlhps xmm6, xmm5 - // row 0 and 1 - movaps xmm0, [edi] - movaps xmm1, [edi+16] - movaps xmm2, [edi+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm3, xmm0 - movlhps xmm3, xmm2 - addps xmm1, xmm3 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm1, xmm0 - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) - movhlps xmm0, xmm1 - addps xmm0, xmm1 - STORE2LO( 0, xmm0, xmm3 ) - // row 2 - movaps xmm0, [edi+48] - movaps xmm1, [edi+48+16] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - addps xmm0, xmm1 - movhlps xmm1, xmm0 - addps xmm0, xmm1 - movaps xmm1, xmm0 - shufps xmm1, xmm1, R_SHUFFLEPS( 1, 0, 0, 0 ) - addss xmm0, xmm1 - STORE1( 8, xmm0, xmm3 ) - } - return; - } - case 4: { // 4x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - // load idVecX - movlps xmm4, [esi] - movhps xmm4, [esi+8] - movlps xmm5, [esi+16] - movlhps xmm5, xmm4 - movhlps xmm6, xmm4 - movlhps xmm6, xmm5 - // row 0 and 1 - movaps xmm0, [edi] - movaps xmm1, [edi+16] - movaps xmm2, [edi+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm7, xmm0 - movlhps xmm7, xmm2 - addps xmm7, xmm1 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm7, xmm0 - // row 2 and 3 - movaps xmm0, [edi+48] - movaps xmm1, [edi+48+16] - movaps xmm2, [edi+48+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm3, xmm0 - movlhps xmm3, xmm2 - addps xmm1, xmm3 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm1, xmm0 - // last 4 additions for the first 4 rows and store result - movaps xmm0, xmm7 - shufps xmm7, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) - addps xmm0, xmm7 - STORE4( 0, xmm0, xmm4 ) - } - return; - } - case 5: { // 5x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - // load idVecX - movlps xmm4, [esi] - movhps xmm4, [esi+8] - movlps xmm5, [esi+16] - movlhps xmm5, xmm4 - movhlps xmm6, xmm4 - movlhps xmm6, xmm5 - // row 0 and 1 - movaps xmm0, [edi] - movaps xmm1, [edi+16] - movaps xmm2, [edi+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm7, xmm0 - movlhps xmm7, xmm2 - addps xmm7, xmm1 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm7, xmm0 - // row 2 and 3 - movaps xmm0, [edi+48] - movaps xmm1, [edi+48+16] - movaps xmm2, [edi+48+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm3, xmm0 - movlhps xmm3, xmm2 - addps xmm1, xmm3 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm1, xmm0 - // last 4 additions for the first 4 rows and store result - movaps xmm0, xmm7 - shufps xmm7, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) - addps xmm0, xmm7 - STORE4( 0, xmm0, xmm3 ) - // row 5 - movaps xmm0, [edi+96] - movaps xmm1, [edi+96+16] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - addps xmm0, xmm1 - movhlps xmm1, xmm0 - addps xmm0, xmm1 - movaps xmm1, xmm0 - shufps xmm1, xmm1, 0x01 - addss xmm0, xmm1 - STORE1( 16, xmm0, xmm3 ) - } - return; - } - case 6: { // 6x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm7, qword ptr [esi] - movlps xmm6, qword ptr [esi+8] - shufps xmm7, xmm7, 0x44 - shufps xmm6, xmm6, 0x44 - movlps xmm0, qword ptr [edi ] - movhps xmm0, qword ptr [edi+ 24] - mulps xmm0, xmm7 - movlps xmm3, qword ptr [edi+ 8] - movhps xmm3, qword ptr [edi+ 32] - mulps xmm3, xmm6 - movlps xmm1, qword ptr [edi+ 48] - movhps xmm1, qword ptr [edi+ 72] - mulps xmm1, xmm7 - movlps xmm2, qword ptr [edi+ 96] - movhps xmm2, qword ptr [edi+120] - mulps xmm2, xmm7 - movlps xmm4, qword ptr [edi+ 56] - movhps xmm4, qword ptr [edi+ 80] - movlps xmm5, qword ptr [edi+104] - movhps xmm5, qword ptr [edi+128] - mulps xmm4, xmm6 - movlps xmm7, qword ptr [esi+16] - addps xmm0, xmm3 - shufps xmm7, xmm7, 0x44 - mulps xmm5, xmm6 - addps xmm1, xmm4 - movlps xmm3, qword ptr [edi+ 16] - movhps xmm3, qword ptr [edi+ 40] - addps xmm2, xmm5 - movlps xmm4, qword ptr [edi+ 64] - movhps xmm4, qword ptr [edi+ 88] - mulps xmm3, xmm7 - movlps xmm5, qword ptr [edi+112] - movhps xmm5, qword ptr [edi+136] - addps xmm0, xmm3 - mulps xmm4, xmm7 - mulps xmm5, xmm7 - addps xmm1, xmm4 - addps xmm2, xmm5 - movaps xmm6, xmm0 - shufps xmm0, xmm1, 0x88 - shufps xmm6, xmm1, 0xDD - movaps xmm7, xmm2 - shufps xmm7, xmm2, 0x88 - shufps xmm2, xmm2, 0xDD - addps xmm0, xmm6 - addps xmm2, xmm7 - STORE4( 0, xmm0, xmm3 ) - STORE2LO( 16, xmm2, xmm4 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + - mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4] + mPtr[5] * vPtr[5]; - mPtr += 6; - } - return; - } + default: { + for ( int i = 0; i < numRows; i++ ) { + dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1]; + mPtr += 2; } - break; + return; + } + } + break; + } + case 3: { + switch ( numRows ) { + case 3: { // 3x3 * 3x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + movss xmm4, [edi] + mulss xmm4, xmm0 + movss xmm1, [esi+4] + movss xmm5, [edi+4] + mulss xmm5, xmm1 + addss xmm4, xmm5 + movss xmm2, [esi+8] + movss xmm6, [edi+8] + mulss xmm6, xmm2 + addss xmm4, xmm6 + movss xmm3, [edi+12] + mulss xmm3, xmm0 + STORE1( 0, xmm4, xmm7 ); + movss xmm5, [edi + 12 + 4] + mulss xmm5, xmm1 + addss xmm3, xmm5 + movss xmm6, [edi + 12 + 8] + mulss xmm6, xmm2 + addss xmm3, xmm6 + mulss xmm0, [edi + 24] + mulss xmm1, [edi + 24 + 4] + STORE1( 4, xmm3, xmm7 ); + addss xmm0, xmm1 + mulss xmm2, [edi + 24 + 8] + addss xmm0, xmm2 + STORE1( 8, xmm0, xmm7 ); + } + return; + } + case 6: { // 6x3 * 3x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm5, [esi] + shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) + movss xmm6, [esi + 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + movss xmm7, [esi + 8] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm0, [edi] // xmm0 = 0, 1, 2, 3 + movlps xmm1, [edi + 4 * 4] + shufps xmm1, xmm0, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm1 = 4, 5, 1, 2 + movlps xmm2, [edi + 6 * 4] + movhps xmm2, [edi + 8 * 4] // xmm2 = 6, 7, 8, 9 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 3, 0, 3 ) // xmm0 = 0, 3, 6, 9 + mulps xmm0, xmm5 + movlps xmm3, [edi + 10 * 4] + shufps xmm2, xmm3, R_SHUFFLEPS( 1, 2, 0, 1 ) // xmm2 = 7, 8, 10, 11 + movaps xmm3, xmm1 + shufps xmm1, xmm2, R_SHUFFLEPS( 2, 0, 0, 2 ) // xmm1 = 1, 4, 7, 10 + mulps xmm1, xmm6 + shufps xmm3, xmm2, R_SHUFFLEPS( 3, 1, 1, 3 ) // xmm3 = 2, 5, 8, 11 + mulps xmm3, xmm7 + addps xmm0, xmm1 + addps xmm0, xmm3 + STORE4( 0, xmm0, xmm4 ) + movss xmm1, [edi + 12 * 4] + mulss xmm1, xmm5 + movss xmm2, [edi + 13 * 4] + mulss xmm2, xmm6 + movss xmm3, [edi + 14 * 4] + mulss xmm3, xmm7 + addss xmm1, xmm2 + addss xmm1, xmm3 + STORE1( 16, xmm1, xmm4 ) + mulss xmm5, [edi + 15 * 4] + mulss xmm6, [edi + 16 * 4] + mulss xmm7, [edi + 17 * 4] + addss xmm5, xmm6 + addss xmm5, xmm7 + STORE1( 20, xmm5, xmm4 ) + } + return; } default: { - int numColumns = mat.GetNumColumns(); for ( int i = 0; i < numRows; i++ ) { - float sum = mPtr[0] * vPtr[0]; - for ( int j = 1; j < numColumns; j++ ) { - sum += mPtr[j] * vPtr[j]; - } - dstPtr[i] STOREC sum; - mPtr += numColumns; + dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2]; + mPtr += 3; } - break; + return; + } + } + break; + } + case 4: { + switch ( numRows ) { + case 4: { // 4x4 * 4x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm6, qword ptr [esi ] + movlps xmm0, qword ptr [edi ] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) + movhps xmm0, qword ptr [edi + 16] + mulps xmm0, xmm6 + movlps xmm7, qword ptr [esi + 8] + movlps xmm2, qword ptr [edi + 8] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) + movhps xmm2, qword ptr [edi + 24] + mulps xmm2, xmm7 + movlps xmm1, qword ptr [edi + 32] + movhps xmm1, qword ptr [edi + 48] + mulps xmm1, xmm6 + movlps xmm3, qword ptr [edi + 40] + addps xmm0, xmm2 + movhps xmm3, qword ptr [edi + 56] + mulps xmm3, xmm7 + movaps xmm4, xmm0 + addps xmm1, xmm3 + shufps xmm4, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) + addps xmm0, xmm4 + STORE4( 0, xmm0, xmm2 ) + } + return; + } + case 6: { // 6x4 * 4x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm6, qword ptr [esi+ 0] + movlps xmm0, qword ptr [edi+ 0] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) + movhps xmm0, qword ptr [edi + 16] + mulps xmm0, xmm6 + movlps xmm7, qword ptr [esi + 8] + movlps xmm2, qword ptr [edi + 8] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) + movhps xmm2, qword ptr [edi + 24] + mulps xmm2, xmm7 + movlps xmm1, qword ptr [edi + 32] + movhps xmm1, qword ptr [edi + 48] + mulps xmm1, xmm6 + movlps xmm3, qword ptr [edi + 40] + addps xmm0, xmm2 + movhps xmm3, qword ptr [edi + 56] + mulps xmm3, xmm7 + movaps xmm4, xmm0 + addps xmm1, xmm3 + shufps xmm4, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) + addps xmm0, xmm4 + movlps xmm1, qword ptr [edi + 64] + movhps xmm1, qword ptr [edi + 80] + STORE4( 0, xmm0, xmm4 ) + mulps xmm1, xmm6 + movlps xmm2, qword ptr [edi + 72] + movhps xmm2, qword ptr [edi + 88] + mulps xmm2, xmm7 + addps xmm1, xmm2 + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) + movhlps xmm3, xmm1 + addps xmm1, xmm3 + STORE2LO( 16, xmm1, xmm4 ) + } + return; + } + default: { + for ( int i = 0; i < numRows; i++ ) { + dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + mPtr[3] * vPtr[3]; + mPtr += 4; + } + return; + } + } + break; + } + case 5: { + switch ( numRows ) { + case 5: { // 5x5 * 5x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [edi+5*4] // xmm0 = 5, X, X, X + movhps xmm0, [edi+0*4] // xmm0 = 5, X, 0, 1 + movss xmm5, [edi+15*4] // xmm4 = 15, X, X, X + movhps xmm5, [edi+10*4] // xmm5 = 15, X, 10, 11 + movaps xmm1, xmm0 // xmm1 = 5, X, 0, 1 + shufps xmm0, xmm5, R_SHUFFLEPS( 2, 0, 2, 0 ) // xmm0 = 0, 5, 10, 15 + movlps xmm1, [edi + 6 * 4] // xmm1 = 6, 7, 0, 1 + movlps xmm5, [edi + 16 * 4] // xmm5 = 16, 17, 10, 11 + movaps xmm2, xmm1 // xmm2 = 6, 7, 0, 1 + shufps xmm1, xmm5, R_SHUFFLEPS( 3, 0, 3, 0 ) // xmm1 = 1, 6, 11, 16 + movhps xmm2, [edi + 2 * 4] // xmm2 = 6, 7, 2, 3 + movhps xmm5, [edi + 12 * 4] // xmm5 = 16, 17, 12, 13 + movaps xmm3, xmm2 // xmm3 = 6, 7, 2, 3 + shufps xmm2, xmm5, R_SHUFFLEPS( 2, 1, 2, 1 ) // xmm2 = 2, 7, 12, 17 + movlps xmm3, [edi + 8 * 4] // xmm3 = 8, 9, 2, 3 + movlps xmm5, [edi + 18 * 4] // xmm5 = 18, 19, 12, 13 + movss xmm4, [edi + 4 * 4] // xmm4 = 4, X, X, X + movlhps xmm4, xmm3 // xmm4 = 4, X, 8, 9 + shufps xmm3, xmm5, R_SHUFFLEPS( 3, 0, 3, 0 ) // xmm3 = 3, 8, 13, 18 + movhps xmm5, [edi + 14 * 4] // xmm6 = 18, 19, 14, 15 + shufps xmm4, xmm5, R_SHUFFLEPS( 0, 3, 2, 1 ) // xmm4 = 4, 9, 14, 19 + movss xmm7, [esi + 0 * 4] + shufps xmm7, xmm7, 0 + mulps xmm0, xmm7 + movss xmm5, [esi + 1 * 4] + shufps xmm5, xmm5, 0 + mulps xmm1, xmm5 + addps xmm0, xmm1 + movss xmm6, [esi + 2 * 4] + shufps xmm6, xmm6, 0 + mulps xmm2, xmm6 + addps xmm0, xmm2 + movss xmm1, [esi + 3 * 4] + shufps xmm1, xmm1, 0 + mulps xmm3, xmm1 + addps xmm0, xmm3 + movss xmm2, [esi + 4 * 4] + shufps xmm2, xmm2, 0 + mulps xmm4, xmm2 + addps xmm0, xmm4 + mulss xmm7, [edi + 20 * 4] + mulss xmm5, [edi + 21 * 4] + addps xmm7, xmm5 + mulss xmm6, [edi + 22 * 4] + addps xmm7, xmm6 + mulss xmm1, [edi + 23 * 4] + addps xmm7, xmm1 + mulss xmm2, [edi + 24 * 4] + addps xmm7, xmm2 + STORE4( 0, xmm0, xmm3 ) + STORE1( 16, xmm7, xmm4 ) + } + return; + } + case 6: { // 6x5 * 5x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm6, [esi] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) + movlps xmm7, [esi + 8] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) + movlps xmm0, [edi] + movhps xmm3, [edi + 8] + movaps xmm1, [edi + 16] + movlps xmm2, [edi + 32] + shufps xmm0, xmm1, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm0 = 0, 1, 5, 6 + shufps xmm1, xmm2, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm1 = 4, 7, 8, 9 + shufps xmm3, xmm1, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm3 = 2, 3, 7, 8 + mulps xmm0, xmm6 + mulps xmm3, xmm7 + movlps xmm2, [edi + 40] + addps xmm0, xmm3 // xmm0 + xmm1 + movhps xmm5, [edi + 40 + 8] + movlps xmm3, [edi + 40 + 16] + movhps xmm3, [edi + 40 + 24] + movlps xmm4, [edi + 40 + 32] + shufps xmm2, xmm3, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm2 = 10, 11, 15, 16 + shufps xmm3, xmm4, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm3 = 14, 17, 18, 19 + shufps xmm5, xmm3, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm5 = 12, 13, 17, 18 + mulps xmm2, xmm6 + mulps xmm5, xmm7 + addps xmm2, xmm5 // xmm2 + xmm3 + movss xmm5, [esi + 16] + shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm4, xmm0 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm4, xmm2, R_SHUFFLEPS( 1, 3, 1, 3 ) + shufps xmm1, xmm3, R_SHUFFLEPS( 0, 3, 0, 3 ) + addps xmm0, xmm4 + mulps xmm1, xmm5 + addps xmm0, xmm1 + STORE4( 0, xmm0, xmm2 ) + movlps xmm4, [edi + 80] + movhps xmm3, [edi + 80 + 8] + movaps xmm1, [edi + 80 + 16] + movlps xmm2, [edi + 80 + 32] + shufps xmm4, xmm1, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm4 = 20, 21, 25, 26 + shufps xmm1, xmm2, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm1 = 24, 27, 28, 29 + shufps xmm3, xmm1, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm3 = 22, 23, 27, 28 + mulps xmm4, xmm6 + mulps xmm3, xmm7 + mulps xmm1, xmm5 + addps xmm4, xmm3 // xmm4 + xmm1 + shufps xmm1, xmm4, R_SHUFFLEPS( 0, 3, 0, 2 ) + shufps xmm4, xmm4, R_SHUFFLEPS( 1, 3, 0, 0 ) + addps xmm4, xmm1 + shufps xmm1, xmm1, R_SHUFFLEPS( 2, 3, 0, 1 ) + addps xmm4, xmm1 + STORE2LO( 16, xmm4, xmm2 ) + } + return; + } + default: { + for ( int i = 0; i < numRows; i++ ) { + dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4]; + mPtr += 5; + } + return; + } + } + break; + } + case 6: { + switch ( numRows ) { + case 1: { // 1x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + mulss xmm0, [edi] + movss xmm1, [esi+4] + mulss xmm1, [edi+4] + movss xmm2, [esi+8] + addss xmm0, xmm1 + mulss xmm2, [edi+8] + movss xmm3, [esi+12] + addss xmm0, xmm2 + mulss xmm3, [edi+12] + movss xmm4, [esi+16] + addss xmm0, xmm3 + mulss xmm4, [edi+16] + movss xmm5, [esi+20] + addss xmm0, xmm4 + mulss xmm5, [edi+20] + movss xmm6, [esi+24] + addss xmm0, xmm5 + mulss xmm6, [edi+24] + addss xmm0, xmm6 + STORE1( 0, xmm0, xmm7 ) + } + return; + } + case 2: { // 2x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + // load idVecX + movlps xmm4, [esi] + movhps xmm4, [esi+8] + movlps xmm5, [esi+16] + movlhps xmm5, xmm4 + movhlps xmm6, xmm4 + movlhps xmm6, xmm5 + // row 0 and 1 + movaps xmm0, [edi] + movaps xmm1, [edi+16] + movaps xmm2, [edi+32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm3, xmm0 + movlhps xmm3, xmm2 + addps xmm1, xmm3 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm1, xmm0 + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) + movhlps xmm0, xmm1 + addps xmm0, xmm1 + STORE2LO( 0, xmm0, xmm3 ) + } + return; + } + case 3: { // 3x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + // load idVecX + movlps xmm4, [esi] + movhps xmm4, [esi+8] + movlps xmm5, [esi+16] + movlhps xmm5, xmm4 + movhlps xmm6, xmm4 + movlhps xmm6, xmm5 + // row 0 and 1 + movaps xmm0, [edi] + movaps xmm1, [edi+16] + movaps xmm2, [edi+32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm3, xmm0 + movlhps xmm3, xmm2 + addps xmm1, xmm3 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm1, xmm0 + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) + movhlps xmm0, xmm1 + addps xmm0, xmm1 + STORE2LO( 0, xmm0, xmm3 ) + // row 2 + movaps xmm0, [edi + 48] + movaps xmm1, [edi + 48 + 16] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + addps xmm0, xmm1 + movhlps xmm1, xmm0 + addps xmm0, xmm1 + movaps xmm1, xmm0 + shufps xmm1, xmm1, R_SHUFFLEPS( 1, 0, 0, 0 ) + addss xmm0, xmm1 + STORE1( 8, xmm0, xmm3 ) + } + return; + } + case 4: { // 4x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + // load idVecX + movlps xmm4, [esi] + movhps xmm4, [esi+8] + movlps xmm5, [esi+16] + movlhps xmm5, xmm4 + movhlps xmm6, xmm4 + movlhps xmm6, xmm5 + // row 0 and 1 + movaps xmm0, [edi] + movaps xmm1, [edi+16] + movaps xmm2, [edi+32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm7, xmm0 + movlhps xmm7, xmm2 + addps xmm7, xmm1 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm7, xmm0 + // row 2 and 3 + movaps xmm0, [edi + 48] + movaps xmm1, [edi + 48 + 16] + movaps xmm2, [edi + 48 + 32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm3, xmm0 + movlhps xmm3, xmm2 + addps xmm1, xmm3 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm1, xmm0 + // last 4 additions for the first 4 rows and store result + movaps xmm0, xmm7 + shufps xmm7, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) + addps xmm0, xmm7 + STORE4( 0, xmm0, xmm4 ) + } + return; + } + case 5: { // 5x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + // load idVecX + movlps xmm4, [esi] + movhps xmm4, [esi+8] + movlps xmm5, [esi+16] + movlhps xmm5, xmm4 + movhlps xmm6, xmm4 + movlhps xmm6, xmm5 + // row 0 and 1 + movaps xmm0, [edi] + movaps xmm1, [edi+16] + movaps xmm2, [edi+32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm7, xmm0 + movlhps xmm7, xmm2 + addps xmm7, xmm1 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm7, xmm0 + // row 2 and 3 + movaps xmm0, [edi + 48] + movaps xmm1, [edi + 48 + 16] + movaps xmm2, [edi + 48 + 32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm3, xmm0 + movlhps xmm3, xmm2 + addps xmm1, xmm3 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm1, xmm0 + // last 4 additions for the first 4 rows and store result + movaps xmm0, xmm7 + shufps xmm7, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) + addps xmm0, xmm7 + STORE4( 0, xmm0, xmm3 ) + // row 5 + movaps xmm0, [edi + 96] + movaps xmm1, [edi + 96 + 16] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + addps xmm0, xmm1 + movhlps xmm1, xmm0 + addps xmm0, xmm1 + movaps xmm1, xmm0 + shufps xmm1, xmm1, 0x01 + addss xmm0, xmm1 + STORE1( 16, xmm0, xmm3 ) + } + return; + } + case 6: { // 6x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm7, qword ptr [esi] + movlps xmm6, qword ptr [esi+8] + shufps xmm7, xmm7, 0x44 + shufps xmm6, xmm6, 0x44 + movlps xmm0, qword ptr [edi ] + movhps xmm0, qword ptr [edi+ 24] + mulps xmm0, xmm7 + movlps xmm3, qword ptr [edi+ 8] + movhps xmm3, qword ptr [edi+ 32] + mulps xmm3, xmm6 + movlps xmm1, qword ptr [edi+ 48] + movhps xmm1, qword ptr [edi+ 72] + mulps xmm1, xmm7 + movlps xmm2, qword ptr [edi+ 96] + movhps xmm2, qword ptr [edi+120] + mulps xmm2, xmm7 + movlps xmm4, qword ptr [edi+ 56] + movhps xmm4, qword ptr [edi+ 80] + movlps xmm5, qword ptr [edi+104] + movhps xmm5, qword ptr [edi+128] + mulps xmm4, xmm6 + movlps xmm7, qword ptr [esi+16] + addps xmm0, xmm3 + shufps xmm7, xmm7, 0x44 + mulps xmm5, xmm6 + addps xmm1, xmm4 + movlps xmm3, qword ptr [edi+ 16] + movhps xmm3, qword ptr [edi+ 40] + addps xmm2, xmm5 + movlps xmm4, qword ptr [edi+ 64] + movhps xmm4, qword ptr [edi+ 88] + mulps xmm3, xmm7 + movlps xmm5, qword ptr [edi+112] + movhps xmm5, qword ptr [edi+136] + addps xmm0, xmm3 + mulps xmm4, xmm7 + mulps xmm5, xmm7 + addps xmm1, xmm4 + addps xmm2, xmm5 + movaps xmm6, xmm0 + shufps xmm0, xmm1, 0x88 + shufps xmm6, xmm1, 0xDD + movaps xmm7, xmm2 + shufps xmm7, xmm2, 0x88 + shufps xmm2, xmm2, 0xDD + addps xmm0, xmm6 + addps xmm2, xmm7 + STORE4( 0, xmm0, xmm3 ) + STORE2LO( 16, xmm2, xmm4 ) + } + return; } + default: { + for ( int i = 0; i < numRows; i++ ) { + dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + + mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4] + mPtr[5] * vPtr[5]; + mPtr += 6; + } + return; + } + } + break; + } + default: { + int numColumns = mat.GetNumColumns(); + for ( int i = 0; i < numRows; i++ ) { + float sum = mPtr[0] * vPtr[0]; + for ( int j = 1; j < numColumns; j++ ) { + sum += mPtr[j] * vPtr[j]; + } + dstPtr[i] STOREC sum; + mPtr += numColumns; + } + break; + } } #undef STOREC @@ -5912,698 +6005,698 @@ void VPCALL idSIMD_SSE::MatX_MultiplySubVecX( idVecX &dst, const idMatX &mat, co vPtr = vec.ToFloatPtr(); dstPtr = dst.ToFloatPtr(); numRows = mat.GetNumRows(); - switch( mat.GetNumColumns() ) { - case 1: { - switch( numRows ) { - case 1: { // 1x1 * 1x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - mulss xmm0, [edi] - STORE1( 0, xmm0, xmm1 ) - } - return; - } - case 6: { // 6x1 * 1x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm1, xmm0 - mulps xmm0, [edi] - mulps xmm1, [edi+16] - STORE4( 0, xmm0, xmm2 ) - STORE2LO( 16, xmm1, xmm2 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0]; - mPtr++; - } - return; - } + switch ( mat.GetNumColumns() ) { + case 1: { + switch ( numRows ) { + case 1: { // 1x1 * 1x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + mulss xmm0, [edi] + STORE1( 0, xmm0, xmm1 ) } - break; + return; } - case 2: { - switch( numRows ) { - case 2: { // 2x2 * 2x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - movss xmm1, [esi+4] - movss xmm2, [edi] - mulss xmm2, xmm0 - movss xmm3, [edi+4] - mulss xmm3, xmm1 - addss xmm2, xmm3 - STORE1( 0, xmm2, xmm4 ) - mulss xmm0, [edi+8] - mulss xmm1, [edi+8+4] - addss xmm0, xmm1 - STORE1( 4, xmm0, xmm4 ) - } - return; - } - case 6: { // 6x2 * 2x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm7, [esi] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) - movaps xmm0, [edi] - mulps xmm0, xmm7 - movaps xmm1, [edi+16] - mulps xmm1, xmm7 - movaps xmm2, xmm0 - shufps xmm0, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm2, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) - movaps xmm3, [edi+32] - addps xmm0, xmm2 - mulps xmm3, xmm7 - STORE4( 0, xmm0, xmm4 ) - shufps xmm3, xmm3, R_SHUFFLEPS( 0, 2, 1, 3 ) - movhlps xmm1, xmm3 - addps xmm3, xmm1 - STORE2LO( 16, xmm3, xmm4 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1]; - mPtr += 2; - } - return; - } + case 6: { // 6x1 * 1x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm1, xmm0 + mulps xmm0, [edi] + mulps xmm1, [edi + 16] + STORE4( 0, xmm0, xmm2 ) + STORE2LO( 16, xmm1, xmm2 ) } - break; + return; } - case 3: { - switch( numRows ) { - case 3: { // 3x3 * 3x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - movss xmm4, [edi] - mulss xmm4, xmm0 - movss xmm1, [esi+4] - movss xmm5, [edi+4] - mulss xmm5, xmm1 - addss xmm4, xmm5 - movss xmm2, [esi+8] - movss xmm6, [edi+8] - mulss xmm6, xmm2 - addss xmm4, xmm6 - movss xmm3, [edi+12] - mulss xmm3, xmm0 - STORE1( 0, xmm4, xmm7 ); - movss xmm5, [edi+12+4] - mulss xmm5, xmm1 - addss xmm3, xmm5 - movss xmm6, [edi+12+8] - mulss xmm6, xmm2 - addss xmm3, xmm6 - mulss xmm0, [edi+24] - mulss xmm1, [edi+24+4] - STORE1( 4, xmm3, xmm7 ); - addss xmm0, xmm1 - mulss xmm2, [edi+24+8] - addss xmm0, xmm2 - STORE1( 8, xmm0, xmm7 ); - } - return; - } - case 6: { // 6x3 * 3x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm5, [esi] - shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm6, [esi+4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm7, [esi+8] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm0, [edi] // xmm0 = 0, 1, 2, 3 - movlps xmm1, [edi+4*4] - shufps xmm1, xmm0, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm1 = 4, 5, 1, 2 - movlps xmm2, [edi+6*4] - movhps xmm2, [edi+8*4] // xmm2 = 6, 7, 8, 9 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 3, 0, 3 ) // xmm0 = 0, 3, 6, 9 - mulps xmm0, xmm5 - movlps xmm3, [edi+10*4] - shufps xmm2, xmm3, R_SHUFFLEPS( 1, 2, 0, 1 ) // xmm2 = 7, 8, 10, 11 - movaps xmm3, xmm1 - shufps xmm1, xmm2, R_SHUFFLEPS( 2, 0, 0, 2 ) // xmm1 = 1, 4, 7, 10 - mulps xmm1, xmm6 - shufps xmm3, xmm2, R_SHUFFLEPS( 3, 1, 1, 3 ) // xmm3 = 2, 5, 8, 11 - mulps xmm3, xmm7 - addps xmm0, xmm1 - addps xmm0, xmm3 - STORE4( 0, xmm0, xmm4 ) - movss xmm1, [edi+12*4] - mulss xmm1, xmm5 - movss xmm2, [edi+13*4] - mulss xmm2, xmm6 - movss xmm3, [edi+14*4] - mulss xmm3, xmm7 - addss xmm1, xmm2 - addss xmm1, xmm3 - STORE1( 16, xmm1, xmm4 ) - mulss xmm5, [edi+15*4] - mulss xmm6, [edi+16*4] - mulss xmm7, [edi+17*4] - addss xmm5, xmm6 - addss xmm5, xmm7 - STORE1( 20, xmm5, xmm4 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2]; - mPtr += 3; - } - return; - } + default: { + for ( int i = 0; i < numRows; i++ ) { + dstPtr[i] STOREC mPtr[0] * vPtr[0]; + mPtr++; } - break; + return; } - case 4: { - switch( numRows ) { - case 4: { // 4x4 * 4x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm6, qword ptr [esi ] - movlps xmm0, qword ptr [edi ] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) - movhps xmm0, qword ptr [edi+16] - mulps xmm0, xmm6 - movlps xmm7, qword ptr [esi+ 8] - movlps xmm2, qword ptr [edi+ 8] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) - movhps xmm2, qword ptr [edi+24] - mulps xmm2, xmm7 - movlps xmm1, qword ptr [edi+32] - movhps xmm1, qword ptr [edi+48] - mulps xmm1, xmm6 - movlps xmm3, qword ptr [edi+40] - addps xmm0, xmm2 - movhps xmm3, qword ptr [edi+56] - mulps xmm3, xmm7 - movaps xmm4, xmm0 - addps xmm1, xmm3 - shufps xmm4, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) - addps xmm0, xmm4 - STORE4( 0, xmm0, xmm2 ) - } - return; - } - case 6: { // 6x4 * 4x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm6, qword ptr [esi+ 0] - movlps xmm0, qword ptr [edi+ 0] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) - movhps xmm0, qword ptr [edi+16] - mulps xmm0, xmm6 - movlps xmm7, qword ptr [esi+ 8] - movlps xmm2, qword ptr [edi+ 8] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) - movhps xmm2, qword ptr [edi+24] - mulps xmm2, xmm7 - movlps xmm1, qword ptr [edi+32] - movhps xmm1, qword ptr [edi+48] - mulps xmm1, xmm6 - movlps xmm3, qword ptr [edi+40] - addps xmm0, xmm2 - movhps xmm3, qword ptr [edi+56] - mulps xmm3, xmm7 - movaps xmm4, xmm0 - addps xmm1, xmm3 - shufps xmm4, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) - addps xmm0, xmm4 - movlps xmm1, qword ptr [edi+64] - movhps xmm1, qword ptr [edi+80] - STORE4( 0, xmm0, xmm4 ) - mulps xmm1, xmm6 - movlps xmm2, qword ptr [edi+72] - movhps xmm2, qword ptr [edi+88] - mulps xmm2, xmm7 - addps xmm1, xmm2 - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) - movhlps xmm3, xmm1 - addps xmm1, xmm3 - STORE2LO( 16, xmm1, xmm4 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + mPtr[3] * vPtr[3]; - mPtr += 4; - } - return; - } + } + break; + } + case 2: { + switch ( numRows ) { + case 2: { // 2x2 * 2x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + movss xmm1, [esi+4] + movss xmm2, [edi] + mulss xmm2, xmm0 + movss xmm3, [edi+4] + mulss xmm3, xmm1 + addss xmm2, xmm3 + STORE1( 0, xmm2, xmm4 ) + mulss xmm0, [edi + 8] + mulss xmm1, [edi + 8 + 4] + addss xmm0, xmm1 + STORE1( 4, xmm0, xmm4 ) } - break; + return; } - case 5: { - switch( numRows ) { - case 5: { // 5x5 * 5x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [edi+5*4] // xmm0 = 5, X, X, X - movhps xmm0, [edi+0*4] // xmm0 = 5, X, 0, 1 - movss xmm5, [edi+15*4] // xmm4 = 15, X, X, X - movhps xmm5, [edi+10*4] // xmm5 = 15, X, 10, 11 - movaps xmm1, xmm0 // xmm1 = 5, X, 0, 1 - shufps xmm0, xmm5, R_SHUFFLEPS( 2, 0, 2, 0 ) // xmm0 = 0, 5, 10, 15 - movlps xmm1, [edi+6*4] // xmm1 = 6, 7, 0, 1 - movlps xmm5, [edi+16*4] // xmm5 = 16, 17, 10, 11 - movaps xmm2, xmm1 // xmm2 = 6, 7, 0, 1 - shufps xmm1, xmm5, R_SHUFFLEPS( 3, 0, 3, 0 ) // xmm1 = 1, 6, 11, 16 - movhps xmm2, [edi+2*4] // xmm2 = 6, 7, 2, 3 - movhps xmm5, [edi+12*4] // xmm5 = 16, 17, 12, 13 - movaps xmm3, xmm2 // xmm3 = 6, 7, 2, 3 - shufps xmm2, xmm5, R_SHUFFLEPS( 2, 1, 2, 1 ) // xmm2 = 2, 7, 12, 17 - movlps xmm3, [edi+8*4] // xmm3 = 8, 9, 2, 3 - movlps xmm5, [edi+18*4] // xmm5 = 18, 19, 12, 13 - movss xmm4, [edi+4*4] // xmm4 = 4, X, X, X - movlhps xmm4, xmm3 // xmm4 = 4, X, 8, 9 - shufps xmm3, xmm5, R_SHUFFLEPS( 3, 0, 3, 0 ) // xmm3 = 3, 8, 13, 18 - movhps xmm5, [edi+14*4] // xmm6 = 18, 19, 14, 15 - shufps xmm4, xmm5, R_SHUFFLEPS( 0, 3, 2, 1 ) // xmm4 = 4, 9, 14, 19 - movss xmm7, [esi+0*4] - shufps xmm7, xmm7, 0 - mulps xmm0, xmm7 - movss xmm5, [esi+1*4] - shufps xmm5, xmm5, 0 - mulps xmm1, xmm5 - addps xmm0, xmm1 - movss xmm6, [esi+2*4] - shufps xmm6, xmm6, 0 - mulps xmm2, xmm6 - addps xmm0, xmm2 - movss xmm1, [esi+3*4] - shufps xmm1, xmm1, 0 - mulps xmm3, xmm1 - addps xmm0, xmm3 - movss xmm2, [esi+4*4] - shufps xmm2, xmm2, 0 - mulps xmm4, xmm2 - addps xmm0, xmm4 - mulss xmm7, [edi+20*4] - mulss xmm5, [edi+21*4] - addps xmm7, xmm5 - mulss xmm6, [edi+22*4] - addps xmm7, xmm6 - mulss xmm1, [edi+23*4] - addps xmm7, xmm1 - mulss xmm2, [edi+24*4] - addps xmm7, xmm2 - STORE4( 0, xmm0, xmm3 ) - STORE1( 16, xmm7, xmm4 ) - } - return; - } - case 6: { // 6x5 * 5x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm6, [esi] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) - movlps xmm7, [esi+8] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) - movlps xmm0, [edi] - movhps xmm3, [edi+8] - movaps xmm1, [edi+16] - movlps xmm2, [edi+32] - shufps xmm0, xmm1, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm0 = 0, 1, 5, 6 - shufps xmm1, xmm2, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm1 = 4, 7, 8, 9 - shufps xmm3, xmm1, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm3 = 2, 3, 7, 8 - mulps xmm0, xmm6 - mulps xmm3, xmm7 - movlps xmm2, [edi+40] - addps xmm0, xmm3 // xmm0 + xmm1 - movhps xmm5, [edi+40+8] - movlps xmm3, [edi+40+16] - movhps xmm3, [edi+40+24] - movlps xmm4, [edi+40+32] - shufps xmm2, xmm3, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm2 = 10, 11, 15, 16 - shufps xmm3, xmm4, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm3 = 14, 17, 18, 19 - shufps xmm5, xmm3, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm5 = 12, 13, 17, 18 - mulps xmm2, xmm6 - mulps xmm5, xmm7 - addps xmm2, xmm5 // xmm2 + xmm3 - movss xmm5, [esi+16] - shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm4, xmm0 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm4, xmm2, R_SHUFFLEPS( 1, 3, 1, 3 ) - shufps xmm1, xmm3, R_SHUFFLEPS( 0, 3, 0, 3 ) - addps xmm0, xmm4 - mulps xmm1, xmm5 - addps xmm0, xmm1 - STORE4( 0, xmm0, xmm2 ) - movlps xmm4, [edi+80] - movhps xmm3, [edi+80+8] - movaps xmm1, [edi+80+16] - movlps xmm2, [edi+80+32] - shufps xmm4, xmm1, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm4 = 20, 21, 25, 26 - shufps xmm1, xmm2, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm1 = 24, 27, 28, 29 - shufps xmm3, xmm1, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm3 = 22, 23, 27, 28 - mulps xmm4, xmm6 - mulps xmm3, xmm7 - mulps xmm1, xmm5 - addps xmm4, xmm3 // xmm4 + xmm1 - shufps xmm1, xmm4, R_SHUFFLEPS( 0, 3, 0, 2 ) - shufps xmm4, xmm4, R_SHUFFLEPS( 1, 3, 0, 0 ) - addps xmm4, xmm1 - shufps xmm1, xmm1, R_SHUFFLEPS( 2, 3, 0, 1 ) - addps xmm4, xmm1 - STORE2LO( 16, xmm4, xmm2 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4]; - mPtr += 5; - } - return; - } + case 6: { // 6x2 * 2x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm7, [esi] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) + movaps xmm0, [edi] + mulps xmm0, xmm7 + movaps xmm1, [edi + 16] + mulps xmm1, xmm7 + movaps xmm2, xmm0 + shufps xmm0, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm2, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) + movaps xmm3, [edi + 32] + addps xmm0, xmm2 + mulps xmm3, xmm7 + STORE4( 0, xmm0, xmm4 ) + shufps xmm3, xmm3, R_SHUFFLEPS( 0, 2, 1, 3 ) + movhlps xmm1, xmm3 + addps xmm3, xmm1 + STORE2LO( 16, xmm3, xmm4 ) } - break; + return; } - case 6: { - switch( numRows ) { - case 1: { // 1x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - mulss xmm0, [edi] - movss xmm1, [esi+4] - mulss xmm1, [edi+4] - movss xmm2, [esi+8] - addss xmm0, xmm1 - mulss xmm2, [edi+8] - movss xmm3, [esi+12] - addss xmm0, xmm2 - mulss xmm3, [edi+12] - movss xmm4, [esi+16] - addss xmm0, xmm3 - mulss xmm4, [edi+16] - movss xmm5, [esi+20] - addss xmm0, xmm4 - mulss xmm5, [edi+20] - movss xmm6, [esi+24] - addss xmm0, xmm5 - mulss xmm6, [edi+24] - addss xmm0, xmm6 - STORE1( 0, xmm0, xmm7 ) - } - return; - } - case 2: { // 2x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - // load idVecX - movlps xmm4, [esi] - movhps xmm4, [esi+8] - movlps xmm5, [esi+16] - movlhps xmm5, xmm4 - movhlps xmm6, xmm4 - movlhps xmm6, xmm5 - // row 0 and 1 - movaps xmm0, [edi] - movaps xmm1, [edi+16] - movaps xmm2, [edi+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm3, xmm0 - movlhps xmm3, xmm2 - addps xmm1, xmm3 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm1, xmm0 - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) - movhlps xmm0, xmm1 - addps xmm0, xmm1 - STORE2LO( 0, xmm0, xmm3 ) - } - return; - } - case 3: { // 3x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - // load idVecX - movlps xmm4, [esi] - movhps xmm4, [esi+8] - movlps xmm5, [esi+16] - movlhps xmm5, xmm4 - movhlps xmm6, xmm4 - movlhps xmm6, xmm5 - // row 0 and 1 - movaps xmm0, [edi] - movaps xmm1, [edi+16] - movaps xmm2, [edi+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm3, xmm0 - movlhps xmm3, xmm2 - addps xmm1, xmm3 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm1, xmm0 - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) - movhlps xmm0, xmm1 - addps xmm0, xmm1 - STORE2LO( 0, xmm0, xmm3 ) - // row 2 - movaps xmm0, [edi+48] - movaps xmm1, [edi+48+16] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - addps xmm0, xmm1 - movhlps xmm1, xmm0 - addps xmm0, xmm1 - movaps xmm1, xmm0 - shufps xmm1, xmm1, R_SHUFFLEPS( 1, 0, 0, 0 ) - addss xmm0, xmm1 - STORE1( 8, xmm0, xmm3 ) - } - return; - } - case 4: { // 4x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - // load idVecX - movlps xmm4, [esi] - movhps xmm4, [esi+8] - movlps xmm5, [esi+16] - movlhps xmm5, xmm4 - movhlps xmm6, xmm4 - movlhps xmm6, xmm5 - // row 0 and 1 - movaps xmm0, [edi] - movaps xmm1, [edi+16] - movaps xmm2, [edi+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm7, xmm0 - movlhps xmm7, xmm2 - addps xmm7, xmm1 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm7, xmm0 - // row 2 and 3 - movaps xmm0, [edi+48] - movaps xmm1, [edi+48+16] - movaps xmm2, [edi+48+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm3, xmm0 - movlhps xmm3, xmm2 - addps xmm1, xmm3 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm1, xmm0 - // last 4 additions for the first 4 rows and store result - movaps xmm0, xmm7 - shufps xmm7, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) - addps xmm0, xmm7 - STORE4( 0, xmm0, xmm4 ) - } - return; - } - case 5: { // 5x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - // load idVecX - movlps xmm4, [esi] - movhps xmm4, [esi+8] - movlps xmm5, [esi+16] - movlhps xmm5, xmm4 - movhlps xmm6, xmm4 - movlhps xmm6, xmm5 - // row 0 and 1 - movaps xmm0, [edi] - movaps xmm1, [edi+16] - movaps xmm2, [edi+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm7, xmm0 - movlhps xmm7, xmm2 - addps xmm7, xmm1 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm7, xmm0 - // row 2 and 3 - movaps xmm0, [edi+48] - movaps xmm1, [edi+48+16] - movaps xmm2, [edi+48+32] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - mulps xmm2, xmm6 - movhlps xmm3, xmm0 - movlhps xmm3, xmm2 - addps xmm1, xmm3 - shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) - addps xmm1, xmm0 - // last 4 additions for the first 4 rows and store result - movaps xmm0, xmm7 - shufps xmm7, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) - shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) - addps xmm0, xmm7 - STORE4( 0, xmm0, xmm3 ) - // row 5 - movaps xmm0, [edi+96] - movaps xmm1, [edi+96+16] - mulps xmm0, xmm4 - mulps xmm1, xmm5 - addps xmm0, xmm1 - movhlps xmm1, xmm0 - addps xmm0, xmm1 - movaps xmm1, xmm0 - shufps xmm1, xmm1, 0x01 - addss xmm0, xmm1 - STORE1( 16, xmm0, xmm3 ) - } - return; - } - case 6: { // 6x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm7, qword ptr [esi] - movlps xmm6, qword ptr [esi+8] - shufps xmm7, xmm7, 0x44 - shufps xmm6, xmm6, 0x44 - movlps xmm0, qword ptr [edi ] - movhps xmm0, qword ptr [edi+ 24] - mulps xmm0, xmm7 - movlps xmm3, qword ptr [edi+ 8] - movhps xmm3, qword ptr [edi+ 32] - mulps xmm3, xmm6 - movlps xmm1, qword ptr [edi+ 48] - movhps xmm1, qword ptr [edi+ 72] - mulps xmm1, xmm7 - movlps xmm2, qword ptr [edi+ 96] - movhps xmm2, qword ptr [edi+120] - mulps xmm2, xmm7 - movlps xmm4, qword ptr [edi+ 56] - movhps xmm4, qword ptr [edi+ 80] - movlps xmm5, qword ptr [edi+104] - movhps xmm5, qword ptr [edi+128] - mulps xmm4, xmm6 - movlps xmm7, qword ptr [esi+16] - addps xmm0, xmm3 - shufps xmm7, xmm7, 0x44 - mulps xmm5, xmm6 - addps xmm1, xmm4 - movlps xmm3, qword ptr [edi+ 16] - movhps xmm3, qword ptr [edi+ 40] - addps xmm2, xmm5 - movlps xmm4, qword ptr [edi+ 64] - movhps xmm4, qword ptr [edi+ 88] - mulps xmm3, xmm7 - movlps xmm5, qword ptr [edi+112] - movhps xmm5, qword ptr [edi+136] - addps xmm0, xmm3 - mulps xmm4, xmm7 - mulps xmm5, xmm7 - addps xmm1, xmm4 - addps xmm2, xmm5 - movaps xmm6, xmm0 - shufps xmm0, xmm1, 0x88 - shufps xmm6, xmm1, 0xDD - movaps xmm7, xmm2 - shufps xmm7, xmm2, 0x88 - shufps xmm2, xmm2, 0xDD - addps xmm0, xmm6 - addps xmm2, xmm7 - STORE4( 0, xmm0, xmm3 ) - STORE2LO( 16, xmm2, xmm4 ) - } - return; - } - default: { - for ( int i = 0; i < numRows; i++ ) { - dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + - mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4] + mPtr[5] * vPtr[5]; - mPtr += 6; - } - return; - } + default: { + for ( int i = 0; i < numRows; i++ ) { + dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1]; + mPtr += 2; } - break; + return; + } + } + break; + } + case 3: { + switch ( numRows ) { + case 3: { // 3x3 * 3x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + movss xmm4, [edi] + mulss xmm4, xmm0 + movss xmm1, [esi+4] + movss xmm5, [edi+4] + mulss xmm5, xmm1 + addss xmm4, xmm5 + movss xmm2, [esi+8] + movss xmm6, [edi+8] + mulss xmm6, xmm2 + addss xmm4, xmm6 + movss xmm3, [edi+12] + mulss xmm3, xmm0 + STORE1( 0, xmm4, xmm7 ); + movss xmm5, [edi + 12 + 4] + mulss xmm5, xmm1 + addss xmm3, xmm5 + movss xmm6, [edi + 12 + 8] + mulss xmm6, xmm2 + addss xmm3, xmm6 + mulss xmm0, [edi + 24] + mulss xmm1, [edi + 24 + 4] + STORE1( 4, xmm3, xmm7 ); + addss xmm0, xmm1 + mulss xmm2, [edi + 24 + 8] + addss xmm0, xmm2 + STORE1( 8, xmm0, xmm7 ); + } + return; + } + case 6: { // 6x3 * 3x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm5, [esi] + shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) + movss xmm6, [esi + 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + movss xmm7, [esi + 8] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm0, [edi] // xmm0 = 0, 1, 2, 3 + movlps xmm1, [edi + 4 * 4] + shufps xmm1, xmm0, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm1 = 4, 5, 1, 2 + movlps xmm2, [edi + 6 * 4] + movhps xmm2, [edi + 8 * 4] // xmm2 = 6, 7, 8, 9 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 3, 0, 3 ) // xmm0 = 0, 3, 6, 9 + mulps xmm0, xmm5 + movlps xmm3, [edi + 10 * 4] + shufps xmm2, xmm3, R_SHUFFLEPS( 1, 2, 0, 1 ) // xmm2 = 7, 8, 10, 11 + movaps xmm3, xmm1 + shufps xmm1, xmm2, R_SHUFFLEPS( 2, 0, 0, 2 ) // xmm1 = 1, 4, 7, 10 + mulps xmm1, xmm6 + shufps xmm3, xmm2, R_SHUFFLEPS( 3, 1, 1, 3 ) // xmm3 = 2, 5, 8, 11 + mulps xmm3, xmm7 + addps xmm0, xmm1 + addps xmm0, xmm3 + STORE4( 0, xmm0, xmm4 ) + movss xmm1, [edi + 12 * 4] + mulss xmm1, xmm5 + movss xmm2, [edi + 13 * 4] + mulss xmm2, xmm6 + movss xmm3, [edi + 14 * 4] + mulss xmm3, xmm7 + addss xmm1, xmm2 + addss xmm1, xmm3 + STORE1( 16, xmm1, xmm4 ) + mulss xmm5, [edi + 15 * 4] + mulss xmm6, [edi + 16 * 4] + mulss xmm7, [edi + 17 * 4] + addss xmm5, xmm6 + addss xmm5, xmm7 + STORE1( 20, xmm5, xmm4 ) + } + return; } default: { - int numColumns = mat.GetNumColumns(); for ( int i = 0; i < numRows; i++ ) { - float sum = mPtr[0] * vPtr[0]; - for ( int j = 1; j < numColumns; j++ ) { - sum += mPtr[j] * vPtr[j]; - } - dstPtr[i] STOREC sum; - mPtr += numColumns; + dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2]; + mPtr += 3; } - break; + return; + } + } + break; + } + case 4: { + switch ( numRows ) { + case 4: { // 4x4 * 4x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm6, qword ptr [esi ] + movlps xmm0, qword ptr [edi ] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) + movhps xmm0, qword ptr [edi + 16] + mulps xmm0, xmm6 + movlps xmm7, qword ptr [esi + 8] + movlps xmm2, qword ptr [edi + 8] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) + movhps xmm2, qword ptr [edi + 24] + mulps xmm2, xmm7 + movlps xmm1, qword ptr [edi + 32] + movhps xmm1, qword ptr [edi + 48] + mulps xmm1, xmm6 + movlps xmm3, qword ptr [edi + 40] + addps xmm0, xmm2 + movhps xmm3, qword ptr [edi + 56] + mulps xmm3, xmm7 + movaps xmm4, xmm0 + addps xmm1, xmm3 + shufps xmm4, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) + addps xmm0, xmm4 + STORE4( 0, xmm0, xmm2 ) + } + return; + } + case 6: { // 6x4 * 4x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm6, qword ptr [esi+ 0] + movlps xmm0, qword ptr [edi+ 0] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) + movhps xmm0, qword ptr [edi + 16] + mulps xmm0, xmm6 + movlps xmm7, qword ptr [esi + 8] + movlps xmm2, qword ptr [edi + 8] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) + movhps xmm2, qword ptr [edi + 24] + mulps xmm2, xmm7 + movlps xmm1, qword ptr [edi + 32] + movhps xmm1, qword ptr [edi + 48] + mulps xmm1, xmm6 + movlps xmm3, qword ptr [edi + 40] + addps xmm0, xmm2 + movhps xmm3, qword ptr [edi + 56] + mulps xmm3, xmm7 + movaps xmm4, xmm0 + addps xmm1, xmm3 + shufps xmm4, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) + addps xmm0, xmm4 + movlps xmm1, qword ptr [edi + 64] + movhps xmm1, qword ptr [edi + 80] + STORE4( 0, xmm0, xmm4 ) + mulps xmm1, xmm6 + movlps xmm2, qword ptr [edi + 72] + movhps xmm2, qword ptr [edi + 88] + mulps xmm2, xmm7 + addps xmm1, xmm2 + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) + movhlps xmm3, xmm1 + addps xmm1, xmm3 + STORE2LO( 16, xmm1, xmm4 ) + } + return; } + default: { + for ( int i = 0; i < numRows; i++ ) { + dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + mPtr[3] * vPtr[3]; + mPtr += 4; + } + return; + } + } + break; + } + case 5: { + switch ( numRows ) { + case 5: { // 5x5 * 5x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [edi+5*4] // xmm0 = 5, X, X, X + movhps xmm0, [edi+0*4] // xmm0 = 5, X, 0, 1 + movss xmm5, [edi+15*4] // xmm4 = 15, X, X, X + movhps xmm5, [edi+10*4] // xmm5 = 15, X, 10, 11 + movaps xmm1, xmm0 // xmm1 = 5, X, 0, 1 + shufps xmm0, xmm5, R_SHUFFLEPS( 2, 0, 2, 0 ) // xmm0 = 0, 5, 10, 15 + movlps xmm1, [edi + 6 * 4] // xmm1 = 6, 7, 0, 1 + movlps xmm5, [edi + 16 * 4] // xmm5 = 16, 17, 10, 11 + movaps xmm2, xmm1 // xmm2 = 6, 7, 0, 1 + shufps xmm1, xmm5, R_SHUFFLEPS( 3, 0, 3, 0 ) // xmm1 = 1, 6, 11, 16 + movhps xmm2, [edi + 2 * 4] // xmm2 = 6, 7, 2, 3 + movhps xmm5, [edi + 12 * 4] // xmm5 = 16, 17, 12, 13 + movaps xmm3, xmm2 // xmm3 = 6, 7, 2, 3 + shufps xmm2, xmm5, R_SHUFFLEPS( 2, 1, 2, 1 ) // xmm2 = 2, 7, 12, 17 + movlps xmm3, [edi + 8 * 4] // xmm3 = 8, 9, 2, 3 + movlps xmm5, [edi + 18 * 4] // xmm5 = 18, 19, 12, 13 + movss xmm4, [edi + 4 * 4] // xmm4 = 4, X, X, X + movlhps xmm4, xmm3 // xmm4 = 4, X, 8, 9 + shufps xmm3, xmm5, R_SHUFFLEPS( 3, 0, 3, 0 ) // xmm3 = 3, 8, 13, 18 + movhps xmm5, [edi + 14 * 4] // xmm6 = 18, 19, 14, 15 + shufps xmm4, xmm5, R_SHUFFLEPS( 0, 3, 2, 1 ) // xmm4 = 4, 9, 14, 19 + movss xmm7, [esi + 0 * 4] + shufps xmm7, xmm7, 0 + mulps xmm0, xmm7 + movss xmm5, [esi + 1 * 4] + shufps xmm5, xmm5, 0 + mulps xmm1, xmm5 + addps xmm0, xmm1 + movss xmm6, [esi + 2 * 4] + shufps xmm6, xmm6, 0 + mulps xmm2, xmm6 + addps xmm0, xmm2 + movss xmm1, [esi + 3 * 4] + shufps xmm1, xmm1, 0 + mulps xmm3, xmm1 + addps xmm0, xmm3 + movss xmm2, [esi + 4 * 4] + shufps xmm2, xmm2, 0 + mulps xmm4, xmm2 + addps xmm0, xmm4 + mulss xmm7, [edi + 20 * 4] + mulss xmm5, [edi + 21 * 4] + addps xmm7, xmm5 + mulss xmm6, [edi + 22 * 4] + addps xmm7, xmm6 + mulss xmm1, [edi + 23 * 4] + addps xmm7, xmm1 + mulss xmm2, [edi + 24 * 4] + addps xmm7, xmm2 + STORE4( 0, xmm0, xmm3 ) + STORE1( 16, xmm7, xmm4 ) + } + return; + } + case 6: { // 6x5 * 5x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm6, [esi] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 1, 0, 1 ) + movlps xmm7, [esi + 8] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 1, 0, 1 ) + movlps xmm0, [edi] + movhps xmm3, [edi + 8] + movaps xmm1, [edi + 16] + movlps xmm2, [edi + 32] + shufps xmm0, xmm1, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm0 = 0, 1, 5, 6 + shufps xmm1, xmm2, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm1 = 4, 7, 8, 9 + shufps xmm3, xmm1, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm3 = 2, 3, 7, 8 + mulps xmm0, xmm6 + mulps xmm3, xmm7 + movlps xmm2, [edi + 40] + addps xmm0, xmm3 // xmm0 + xmm1 + movhps xmm5, [edi + 40 + 8] + movlps xmm3, [edi + 40 + 16] + movhps xmm3, [edi + 40 + 24] + movlps xmm4, [edi + 40 + 32] + shufps xmm2, xmm3, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm2 = 10, 11, 15, 16 + shufps xmm3, xmm4, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm3 = 14, 17, 18, 19 + shufps xmm5, xmm3, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm5 = 12, 13, 17, 18 + mulps xmm2, xmm6 + mulps xmm5, xmm7 + addps xmm2, xmm5 // xmm2 + xmm3 + movss xmm5, [esi + 16] + shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm4, xmm0 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm4, xmm2, R_SHUFFLEPS( 1, 3, 1, 3 ) + shufps xmm1, xmm3, R_SHUFFLEPS( 0, 3, 0, 3 ) + addps xmm0, xmm4 + mulps xmm1, xmm5 + addps xmm0, xmm1 + STORE4( 0, xmm0, xmm2 ) + movlps xmm4, [edi + 80] + movhps xmm3, [edi + 80 + 8] + movaps xmm1, [edi + 80 + 16] + movlps xmm2, [edi + 80 + 32] + shufps xmm4, xmm1, R_SHUFFLEPS( 0, 1, 1, 2 ) // xmm4 = 20, 21, 25, 26 + shufps xmm1, xmm2, R_SHUFFLEPS( 0, 3, 0, 1 ) // xmm1 = 24, 27, 28, 29 + shufps xmm3, xmm1, R_SHUFFLEPS( 2, 3, 1, 2 ) // xmm3 = 22, 23, 27, 28 + mulps xmm4, xmm6 + mulps xmm3, xmm7 + mulps xmm1, xmm5 + addps xmm4, xmm3 // xmm4 + xmm1 + shufps xmm1, xmm4, R_SHUFFLEPS( 0, 3, 0, 2 ) + shufps xmm4, xmm4, R_SHUFFLEPS( 1, 3, 0, 0 ) + addps xmm4, xmm1 + shufps xmm1, xmm1, R_SHUFFLEPS( 2, 3, 0, 1 ) + addps xmm4, xmm1 + STORE2LO( 16, xmm4, xmm2 ) + } + return; + } + default: { + for ( int i = 0; i < numRows; i++ ) { + dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4]; + mPtr += 5; + } + return; + } + } + break; + } + case 6: { + switch ( numRows ) { + case 1: { // 1x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + mulss xmm0, [edi] + movss xmm1, [esi+4] + mulss xmm1, [edi+4] + movss xmm2, [esi+8] + addss xmm0, xmm1 + mulss xmm2, [edi+8] + movss xmm3, [esi+12] + addss xmm0, xmm2 + mulss xmm3, [edi+12] + movss xmm4, [esi+16] + addss xmm0, xmm3 + mulss xmm4, [edi+16] + movss xmm5, [esi+20] + addss xmm0, xmm4 + mulss xmm5, [edi+20] + movss xmm6, [esi+24] + addss xmm0, xmm5 + mulss xmm6, [edi+24] + addss xmm0, xmm6 + STORE1( 0, xmm0, xmm7 ) + } + return; + } + case 2: { // 2x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + // load idVecX + movlps xmm4, [esi] + movhps xmm4, [esi+8] + movlps xmm5, [esi+16] + movlhps xmm5, xmm4 + movhlps xmm6, xmm4 + movlhps xmm6, xmm5 + // row 0 and 1 + movaps xmm0, [edi] + movaps xmm1, [edi+16] + movaps xmm2, [edi+32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm3, xmm0 + movlhps xmm3, xmm2 + addps xmm1, xmm3 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm1, xmm0 + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) + movhlps xmm0, xmm1 + addps xmm0, xmm1 + STORE2LO( 0, xmm0, xmm3 ) + } + return; + } + case 3: { // 3x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + // load idVecX + movlps xmm4, [esi] + movhps xmm4, [esi+8] + movlps xmm5, [esi+16] + movlhps xmm5, xmm4 + movhlps xmm6, xmm4 + movlhps xmm6, xmm5 + // row 0 and 1 + movaps xmm0, [edi] + movaps xmm1, [edi+16] + movaps xmm2, [edi+32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm3, xmm0 + movlhps xmm3, xmm2 + addps xmm1, xmm3 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm1, xmm0 + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 1, 3 ) + movhlps xmm0, xmm1 + addps xmm0, xmm1 + STORE2LO( 0, xmm0, xmm3 ) + // row 2 + movaps xmm0, [edi + 48] + movaps xmm1, [edi + 48 + 16] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + addps xmm0, xmm1 + movhlps xmm1, xmm0 + addps xmm0, xmm1 + movaps xmm1, xmm0 + shufps xmm1, xmm1, R_SHUFFLEPS( 1, 0, 0, 0 ) + addss xmm0, xmm1 + STORE1( 8, xmm0, xmm3 ) + } + return; + } + case 4: { // 4x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + // load idVecX + movlps xmm4, [esi] + movhps xmm4, [esi+8] + movlps xmm5, [esi+16] + movlhps xmm5, xmm4 + movhlps xmm6, xmm4 + movlhps xmm6, xmm5 + // row 0 and 1 + movaps xmm0, [edi] + movaps xmm1, [edi+16] + movaps xmm2, [edi+32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm7, xmm0 + movlhps xmm7, xmm2 + addps xmm7, xmm1 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm7, xmm0 + // row 2 and 3 + movaps xmm0, [edi + 48] + movaps xmm1, [edi + 48 + 16] + movaps xmm2, [edi + 48 + 32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm3, xmm0 + movlhps xmm3, xmm2 + addps xmm1, xmm3 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm1, xmm0 + // last 4 additions for the first 4 rows and store result + movaps xmm0, xmm7 + shufps xmm7, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) + addps xmm0, xmm7 + STORE4( 0, xmm0, xmm4 ) + } + return; + } + case 5: { // 5x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + // load idVecX + movlps xmm4, [esi] + movhps xmm4, [esi+8] + movlps xmm5, [esi+16] + movlhps xmm5, xmm4 + movhlps xmm6, xmm4 + movlhps xmm6, xmm5 + // row 0 and 1 + movaps xmm0, [edi] + movaps xmm1, [edi+16] + movaps xmm2, [edi+32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm7, xmm0 + movlhps xmm7, xmm2 + addps xmm7, xmm1 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm7, xmm0 + // row 2 and 3 + movaps xmm0, [edi + 48] + movaps xmm1, [edi + 48 + 16] + movaps xmm2, [edi + 48 + 32] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + mulps xmm2, xmm6 + movhlps xmm3, xmm0 + movlhps xmm3, xmm2 + addps xmm1, xmm3 + shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 2, 3 ) + addps xmm1, xmm0 + // last 4 additions for the first 4 rows and store result + movaps xmm0, xmm7 + shufps xmm7, xmm1, R_SHUFFLEPS( 0, 2, 0, 2 ) + shufps xmm0, xmm1, R_SHUFFLEPS( 1, 3, 1, 3 ) + addps xmm0, xmm7 + STORE4( 0, xmm0, xmm3 ) + // row 5 + movaps xmm0, [edi + 96] + movaps xmm1, [edi + 96 + 16] + mulps xmm0, xmm4 + mulps xmm1, xmm5 + addps xmm0, xmm1 + movhlps xmm1, xmm0 + addps xmm0, xmm1 + movaps xmm1, xmm0 + shufps xmm1, xmm1, 0x01 + addss xmm0, xmm1 + STORE1( 16, xmm0, xmm3 ) + } + return; + } + case 6: { // 6x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm7, qword ptr [esi] + movlps xmm6, qword ptr [esi+8] + shufps xmm7, xmm7, 0x44 + shufps xmm6, xmm6, 0x44 + movlps xmm0, qword ptr [edi ] + movhps xmm0, qword ptr [edi+ 24] + mulps xmm0, xmm7 + movlps xmm3, qword ptr [edi+ 8] + movhps xmm3, qword ptr [edi+ 32] + mulps xmm3, xmm6 + movlps xmm1, qword ptr [edi+ 48] + movhps xmm1, qword ptr [edi+ 72] + mulps xmm1, xmm7 + movlps xmm2, qword ptr [edi+ 96] + movhps xmm2, qword ptr [edi+120] + mulps xmm2, xmm7 + movlps xmm4, qword ptr [edi+ 56] + movhps xmm4, qword ptr [edi+ 80] + movlps xmm5, qword ptr [edi+104] + movhps xmm5, qword ptr [edi+128] + mulps xmm4, xmm6 + movlps xmm7, qword ptr [esi+16] + addps xmm0, xmm3 + shufps xmm7, xmm7, 0x44 + mulps xmm5, xmm6 + addps xmm1, xmm4 + movlps xmm3, qword ptr [edi+ 16] + movhps xmm3, qword ptr [edi+ 40] + addps xmm2, xmm5 + movlps xmm4, qword ptr [edi+ 64] + movhps xmm4, qword ptr [edi+ 88] + mulps xmm3, xmm7 + movlps xmm5, qword ptr [edi+112] + movhps xmm5, qword ptr [edi+136] + addps xmm0, xmm3 + mulps xmm4, xmm7 + mulps xmm5, xmm7 + addps xmm1, xmm4 + addps xmm2, xmm5 + movaps xmm6, xmm0 + shufps xmm0, xmm1, 0x88 + shufps xmm6, xmm1, 0xDD + movaps xmm7, xmm2 + shufps xmm7, xmm2, 0x88 + shufps xmm2, xmm2, 0xDD + addps xmm0, xmm6 + addps xmm2, xmm7 + STORE4( 0, xmm0, xmm3 ) + STORE2LO( 16, xmm2, xmm4 ) + } + return; + } + default: { + for ( int i = 0; i < numRows; i++ ) { + dstPtr[i] STOREC mPtr[0] * vPtr[0] + mPtr[1] * vPtr[1] + mPtr[2] * vPtr[2] + + mPtr[3] * vPtr[3] + mPtr[4] * vPtr[4] + mPtr[5] * vPtr[5]; + mPtr += 6; + } + return; + } + } + break; + } + default: { + int numColumns = mat.GetNumColumns(); + for ( int i = 0; i < numRows; i++ ) { + float sum = mPtr[0] * vPtr[0]; + for ( int j = 1; j < numColumns; j++ ) { + sum += mPtr[j] * vPtr[j]; + } + dstPtr[i] STOREC sum; + mPtr += numColumns; + } + break; + } } #undef STOREC @@ -6648,517 +6741,517 @@ void VPCALL idSIMD_SSE::MatX_TransposeMultiplyVecX( idVecX &dst, const idMatX &m vPtr = vec.ToFloatPtr(); dstPtr = dst.ToFloatPtr(); numColumns = mat.GetNumColumns(); - switch( mat.GetNumRows() ) { - case 1: - switch( numColumns ) { - case 6: { // 1x6 * 1x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm1, xmm0 - mulps xmm0, [edi] - mulps xmm1, [edi+16] - STORE4( 0, xmm0, xmm2 ) - STORE2LO( 16, xmm1, xmm3 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0]; - mPtr++; - } - return; - } + switch ( mat.GetNumRows() ) { + case 1: + switch ( numColumns ) { + case 6: { // 1x6 * 1x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm1, xmm0 + mulps xmm0, [edi] + mulps xmm1, [edi + 16] + STORE4( 0, xmm0, xmm2 ) + STORE2LO( 16, xmm1, xmm3 ) } - break; - case 2: - switch( numColumns ) { - case 6: { // 2x6 * 2x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi] - movaps xmm1, xmm0 - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - shufps xmm1, xmm1, R_SHUFFLEPS( 1, 1, 1, 1 ) - movaps xmm2, [edi] - mulps xmm2, xmm0 - movlps xmm3, [edi+24] - movhps xmm3, [edi+32] - mulps xmm3, xmm1 - addps xmm2, xmm3 - shufps xmm0, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps xmm4, [edi+16] - movhps xmm4, [edi+40] - mulps xmm4, xmm0 - movhlps xmm3, xmm4 - addps xmm3, xmm4 - STORE4( 0, xmm2, xmm5 ) - STORE2LO( 16, xmm3, xmm6 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1]; - mPtr++; - } - return; - } + return; + } + default: { + for ( int i = 0; i < numColumns; i++ ) { + dstPtr[i] STOREC *( mPtr ) * vPtr[0]; + mPtr++; } - break; - case 3: - switch( numColumns ) { - case 6: { // 3x6 * 3x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi+0*4] - movss xmm1, [esi+2*4] - movlps xmm3, [edi+(0*6+0)*4] - movhps xmm3, [edi+(0*6+2)*4] - movaps xmm4, xmm0 - shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm3, xmm4 - movlps xmm5, [edi+(1*6+0)*4] - movhps xmm5, [edi+(1*6+2)*4] - movaps xmm6, xmm0 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movlps xmm4, [edi+(2*6+0)*4] - movhps xmm4, [edi+(2*6+2)*4] - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm4, xmm1 - addps xmm3, xmm4 - STORE4( 0, xmm3, xmm7 ) - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) - movlps xmm3, [edi+(0*6+4)*4] - movhps xmm3, [edi+(1*6+4)*4] - mulps xmm3, xmm0 - movhlps xmm4, xmm3 - addps xmm3, xmm4 - movlps xmm5, [edi+(2*6+4)*4] - mulps xmm5, xmm1 - addps xmm3, xmm5 - STORE2LO( 16, xmm3, xmm7 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2]; - mPtr++; - } - return; - } + return; + } + } + break; + case 2: + switch ( numColumns ) { + case 6: { // 2x6 * 2x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi] + movaps xmm1, xmm0 + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) + shufps xmm1, xmm1, R_SHUFFLEPS( 1, 1, 1, 1 ) + movaps xmm2, [edi] + mulps xmm2, xmm0 + movlps xmm3, [edi + 24] + movhps xmm3, [edi + 32] + mulps xmm3, xmm1 + addps xmm2, xmm3 + shufps xmm0, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) + movlps xmm4, [edi + 16] + movhps xmm4, [edi + 40] + mulps xmm4, xmm0 + movhlps xmm3, xmm4 + addps xmm3, xmm4 + STORE4( 0, xmm2, xmm5 ) + STORE2LO( 16, xmm3, xmm6 ) } - break; - case 4: - switch( numColumns ) { - case 6: { // 4x6 * 4x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi+0*4] - movlps xmm1, [esi+2*4] - movaps xmm3, xmm0 - shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm3, [edi+(0*6+0)*4] - movlps xmm5, [edi+(1*6+0)*4] - movhps xmm5, [edi+(1*6+2)*4] - movaps xmm6, xmm0 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movlps xmm4, [edi+(2*6+0)*4] - movhps xmm4, [edi+(2*6+2)*4] - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm4, xmm6 - addps xmm3, xmm4 - movlps xmm5, [edi+(3*6+0)*4] - movhps xmm5, [edi+(3*6+2)*4] - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - STORE4( 0, xmm3, xmm7 ) - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) - movlps xmm3, [edi+(0*6+4)*4] - movhps xmm3, [edi+(1*6+4)*4] - mulps xmm3, xmm0 - movlps xmm4, [edi+(2*6+4)*4] - movhps xmm4, [edi+(3*6+4)*4] - mulps xmm4, xmm1 - addps xmm3, xmm4 - movhlps xmm4, xmm3 - addps xmm3, xmm4 - STORE2LO( 16, xmm3, xmm7 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3]; - mPtr++; - } - return; - } + return; + } + default: { + for ( int i = 0; i < numColumns; i++ ) { + dstPtr[i] STOREC *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1]; + mPtr++; } - break; - case 5: - switch( numColumns ) { - case 6: { // 5x6 * 5x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi+0*4] - movlps xmm1, [esi+2*4] - movss xmm2, [esi+4*4] - movaps xmm3, xmm0 - shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm3, [edi+(0*6+0)*4] - movlps xmm5, [edi+(1*6+0)*4] - movhps xmm5, [edi+(1*6+2)*4] - movaps xmm6, xmm0 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm6, [edi+(2*6+0)*4] - addps xmm3, xmm6 - movlps xmm5, [edi+(3*6+0)*4] - movhps xmm5, [edi+(3*6+2)*4] - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm4, xmm2 - mulps xmm4, [edi+(4*6+0)*4] - addps xmm3, xmm4 - STORE4( 0, xmm3, xmm7 ) - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) - movlps xmm3, [edi+(0*6+4)*4] - movhps xmm3, [edi+(1*6+4)*4] - mulps xmm3, xmm0 - movlps xmm4, [edi+(2*6+4)*4] - movhps xmm4, [edi+(3*6+4)*4] - mulps xmm4, xmm1 - addps xmm3, xmm4 - movhlps xmm4, xmm3 - addps xmm3, xmm4 - movlps xmm5, [edi+(4*6+4)*4] - mulps xmm5, xmm2 - addps xmm3, xmm5 - STORE2LO( 16, xmm3, xmm7 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3] + *(mPtr+4*numColumns) * vPtr[4]; - mPtr++; - } - return; - } + return; + } + } + break; + case 3: + switch ( numColumns ) { + case 6: { // 3x6 * 3x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi+0*4] + movss xmm1, [esi+2*4] + movlps xmm3, [edi+( 0*6+0 )*4] + movhps xmm3, [edi+( 0*6+2 )*4] + movaps xmm4, xmm0 + shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm3, xmm4 + movlps xmm5, [edi + ( 1 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 1 * 6 + 2 ) * 4] + movaps xmm6, xmm0 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movlps xmm4, [edi + ( 2 * 6 + 0 ) * 4] + movhps xmm4, [edi + ( 2 * 6 + 2 ) * 4] + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm4, xmm1 + addps xmm3, xmm4 + STORE4( 0, xmm3, xmm7 ) + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) + movlps xmm3, [edi + ( 0 * 6 + 4 ) * 4] + movhps xmm3, [edi + ( 1 * 6 + 4 ) * 4] + mulps xmm3, xmm0 + movhlps xmm4, xmm3 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 2 * 6 + 4 ) * 4] + mulps xmm5, xmm1 + addps xmm3, xmm5 + STORE2LO( 16, xmm3, xmm7 ) } - break; - case 6: - switch( numColumns ) { - case 1: { // 6x1 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi] - movhps xmm0, [esi+8] - movlps xmm1, [esi+16] - mulps xmm0, [edi] - mulps xmm1, [edi+16] - shufps xmm1, xmm0, R_SHUFFLEPS( 0, 1, 3, 2 ) - addps xmm0, xmm1 - movhlps xmm2, xmm0 - addss xmm2, xmm0 - shufps xmm0, xmm0, R_SHUFFLEPS( 1, 0, 0, 0 ) - addss xmm2, xmm0 - STORE1( 0, xmm2, xmm3 ) - } - return; - } - case 2: { // 6x2 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi+0*4] - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) - movaps xmm6, [edi+0*4] - mulps xmm6, xmm0 - movlps xmm1, [esi+2*4] - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) - movaps xmm7, [edi+4*4] - mulps xmm7, xmm1 - addps xmm6, xmm7 - movlps xmm2, [esi+4*4] - shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 1, 1 ) - movaps xmm7, [edi+8*4] - mulps xmm7, xmm2 - addps xmm6, xmm7 - movhlps xmm3, xmm6 - addps xmm3, xmm6 - STORE2LO( 0, xmm3, xmm7 ) - } - return; - } - case 3: { // 6x3 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [edi+(0*3+2)*4] - movhps xmm0, [edi+(0*3+0)*4] - shufps xmm0, xmm0, R_SHUFFLEPS( 2, 1, 3, 0 ) - movss xmm6, [esi+0*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm6, xmm0 - movss xmm1, [edi+(1*3+0)*4] - movhps xmm1, [edi+(1*3+1)*4] - movss xmm7, [esi+1*4] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm1 - addps xmm6, xmm7 - movss xmm2, [edi+(2*3+2)*4] - movhps xmm2, [edi+(2*3+0)*4] - shufps xmm2, xmm2, R_SHUFFLEPS( 2, 1, 3, 0 ) - movss xmm7, [esi+2*4] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm2 - addps xmm6, xmm7 - movss xmm3, [edi+(3*3+0)*4] - movhps xmm3, [edi+(3*3+1)*4] - movss xmm7, [esi+3*4] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm3 - addps xmm6, xmm7 - movss xmm4, [edi+(4*3+2)*4] - movhps xmm4, [edi+(4*3+0)*4] - shufps xmm4, xmm4, R_SHUFFLEPS( 2, 1, 3, 0 ) - movss xmm7, [esi+4*4] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm4 - addps xmm6, xmm7 - movss xmm5, [edi+(5*3+0)*4] - movhps xmm5, [edi+(5*3+1)*4] - movss xmm7, [esi+5*4] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm5 - addps xmm6, xmm7 - STORE1( 0, xmm6, xmm7 ) - STORE2HI( 4, xmm6, xmm7 ) - } - return; - } - case 4: { // 6x4 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm3, [edi+(0*4+0)*4] - movhps xmm3, [edi+(0*4+2)*4] - movss xmm4, [esi+0*4] - shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm3, xmm4 - movlps xmm5, [edi+(1*4+0)*4] - movhps xmm5, [edi+(1*4+2)*4] - movss xmm6, [esi+1*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movlps xmm4, [edi+(2*4+0)*4] - movhps xmm4, [edi+(2*4+2)*4] - movss xmm6, [esi+2*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm4, xmm6 - addps xmm3, xmm4 - movlps xmm5, [edi+(3*4+0)*4] - movhps xmm5, [edi+(3*4+2)*4] - movss xmm6, [esi+3*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movlps xmm4, [edi+(4*4+0)*4] - movhps xmm4, [edi+(4*4+2)*4] - movss xmm6, [esi+4*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm4, xmm6 - addps xmm3, xmm4 - movlps xmm5, [edi+(5*4+0)*4] - movhps xmm5, [edi+(5*4+2)*4] - movss xmm6, [esi+5*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - STORE4( 0, xmm3, xmm7 ) - } - return; - } - case 5: { // 6x5 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm6, [edi+(0*5+0)*4] - movhps xmm6, [edi+(0*5+2)*4] - movss xmm0, [esi+0*4] - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm6, xmm0 - movlps xmm7, [edi+(1*5+0)*4] - movhps xmm7, [edi+(1*5+2)*4] - movss xmm1, [esi+1*4] - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm1 - addps xmm6, xmm7 - movlps xmm7, [edi+(2*5+0)*4] - movhps xmm7, [edi+(2*5+2)*4] - movss xmm2, [esi+2*4] - shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm2 - addps xmm6, xmm7 - movlps xmm7, [edi+(3*5+0)*4] - movhps xmm7, [edi+(3*5+2)*4] - movss xmm3, [esi+3*4] - shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm3 - addps xmm6, xmm7 - movlps xmm7, [edi+(4*5+0)*4] - movhps xmm7, [edi+(4*5+2)*4] - movss xmm4, [esi+4*4] - shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm4 - addps xmm6, xmm7 - movlps xmm7, [edi+(5*5+0)*4] - movhps xmm7, [edi+(5*5+2)*4] - movss xmm5, [esi+5*4] - shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm5 - addps xmm6, xmm7 - STORE4( 0, xmm6, xmm7 ) - movss xmm6, [edi+(0*5+4)*4] - mulss xmm6, xmm0 - movss xmm7, [edi+(1*5+4)*4] - mulss xmm7, xmm1 - addss xmm6, xmm7 - movss xmm7, [edi+(2*5+4)*4] - mulss xmm7, xmm2 - addss xmm6, xmm7 - movss xmm7, [edi+(3*5+4)*4] - mulss xmm7, xmm3 - addss xmm6, xmm7 - movss xmm7, [edi+(4*5+4)*4] - mulss xmm7, xmm4 - addss xmm6, xmm7 - movss xmm7, [edi+(5*5+4)*4] - mulss xmm7, xmm5 - addss xmm6, xmm7 - STORE1( 16, xmm6, xmm7 ) - } - return; - } - case 6: { // 6x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi+0*4] - movlps xmm1, [esi+2*4] - movlps xmm2, [esi+4*4] - movaps xmm3, xmm0 - shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm3, [edi+(0*6+0)*4] - movlps xmm5, [edi+(1*6+0)*4] - movhps xmm5, [edi+(1*6+2)*4] - movaps xmm6, xmm0 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm6, [edi+(2*6+0)*4] - addps xmm3, xmm6 - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - movlps xmm5, [edi+(3*6+0)*4] - movhps xmm5, [edi+(3*6+2)*4] - mulps xmm5, xmm6 - addps xmm3, xmm5 - movaps xmm6, xmm2 - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm6, [edi+(4*6+0)*4] - addps xmm3, xmm6 - movaps xmm6, xmm2 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - movlps xmm5, [edi+(5*6+0)*4] - movhps xmm5, [edi+(5*6+2)*4] - mulps xmm5, xmm6 - addps xmm3, xmm5 - STORE4( 0, xmm3, xmm7 ) - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) - shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 1, 1 ) - movlps xmm3, [edi+(0*6+4)*4] - movhps xmm3, [edi+(1*6+4)*4] - mulps xmm3, xmm0 - movlps xmm4, [edi+(2*6+4)*4] - movhps xmm4, [edi+(3*6+4)*4] - mulps xmm4, xmm1 - addps xmm3, xmm4 - movlps xmm5, [edi+(4*6+4)*4] - movhps xmm5, [edi+(5*6+4)*4] - mulps xmm5, xmm2 - addps xmm3, xmm5 - movhlps xmm4, xmm3 - addps xmm3, xmm4 - STORE2LO( 16, xmm3, xmm7 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3] + *(mPtr+4*numColumns) * vPtr[4] + *(mPtr+5*numColumns) * vPtr[5]; - mPtr++; - } - return; - } + return; + } + default: { + for ( int i = 0; i < numColumns; i++ ) { + dstPtr[i] STOREC *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2]; + mPtr++; } - break; - default: - int numRows = mat.GetNumRows(); + return; + } + } + break; + case 4: + switch ( numColumns ) { + case 6: { // 4x6 * 4x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi+0*4] + movlps xmm1, [esi+2*4] + movaps xmm3, xmm0 + shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm3, [edi + ( 0 * 6 + 0 ) * 4] + movlps xmm5, [edi + ( 1 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 1 * 6 + 2 ) * 4] + movaps xmm6, xmm0 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movlps xmm4, [edi + ( 2 * 6 + 0 ) * 4] + movhps xmm4, [edi + ( 2 * 6 + 2 ) * 4] + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm4, xmm6 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 3 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 3 * 6 + 2 ) * 4] + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + STORE4( 0, xmm3, xmm7 ) + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) + movlps xmm3, [edi + ( 0 * 6 + 4 ) * 4] + movhps xmm3, [edi + ( 1 * 6 + 4 ) * 4] + mulps xmm3, xmm0 + movlps xmm4, [edi + ( 2 * 6 + 4 ) * 4] + movhps xmm4, [edi + ( 3 * 6 + 4 ) * 4] + mulps xmm4, xmm1 + addps xmm3, xmm4 + movhlps xmm4, xmm3 + addps xmm3, xmm4 + STORE2LO( 16, xmm3, xmm7 ) + } + return; + } + default: { for ( int i = 0; i < numColumns; i++ ) { - mPtr = mat.ToFloatPtr() + i; - float sum = mPtr[0] * vPtr[0]; - for ( int j = 1; j < numRows; j++ ) { - mPtr += numColumns; - sum += mPtr[0] * vPtr[j]; - } - dstPtr[i] STOREC sum; + dstPtr[i] STOREC *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3]; + mPtr++; } - break; + return; + } + } + break; + case 5: + switch ( numColumns ) { + case 6: { // 5x6 * 5x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi+0*4] + movlps xmm1, [esi+2*4] + movss xmm2, [esi+4*4] + movaps xmm3, xmm0 + shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm3, [edi + ( 0 * 6 + 0 ) * 4] + movlps xmm5, [edi + ( 1 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 1 * 6 + 2 ) * 4] + movaps xmm6, xmm0 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm6, [edi + ( 2 * 6 + 0 ) * 4] + addps xmm3, xmm6 + movlps xmm5, [edi + ( 3 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 3 * 6 + 2 ) * 4] + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm4, xmm2 + mulps xmm4, [edi + ( 4 * 6 + 0 ) * 4] + addps xmm3, xmm4 + STORE4( 0, xmm3, xmm7 ) + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) + movlps xmm3, [edi + ( 0 * 6 + 4 ) * 4] + movhps xmm3, [edi + ( 1 * 6 + 4 ) * 4] + mulps xmm3, xmm0 + movlps xmm4, [edi + ( 2 * 6 + 4 ) * 4] + movhps xmm4, [edi + ( 3 * 6 + 4 ) * 4] + mulps xmm4, xmm1 + addps xmm3, xmm4 + movhlps xmm4, xmm3 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 4 * 6 + 4 ) * 4] + mulps xmm5, xmm2 + addps xmm3, xmm5 + STORE2LO( 16, xmm3, xmm7 ) + } + return; + } + default: { + for ( int i = 0; i < numColumns; i++ ) { + dstPtr[i] STOREC *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3] + *( mPtr + 4 * numColumns ) * vPtr[4]; + mPtr++; + } + return; + } + } + break; + case 6: + switch ( numColumns ) { + case 1: { // 6x1 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi] + movhps xmm0, [esi+8] + movlps xmm1, [esi+16] + mulps xmm0, [edi] + mulps xmm1, [edi+16] + shufps xmm1, xmm0, R_SHUFFLEPS( 0, 1, 3, 2 ) + addps xmm0, xmm1 + movhlps xmm2, xmm0 + addss xmm2, xmm0 + shufps xmm0, xmm0, R_SHUFFLEPS( 1, 0, 0, 0 ) + addss xmm2, xmm0 + STORE1( 0, xmm2, xmm3 ) + } + return; + } + case 2: { // 6x2 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi+0*4] + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) + movaps xmm6, [edi + 0 * 4] + mulps xmm6, xmm0 + movlps xmm1, [esi + 2 * 4] + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) + movaps xmm7, [edi + 4 * 4] + mulps xmm7, xmm1 + addps xmm6, xmm7 + movlps xmm2, [esi + 4 * 4] + shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 1, 1 ) + movaps xmm7, [edi + 8 * 4] + mulps xmm7, xmm2 + addps xmm6, xmm7 + movhlps xmm3, xmm6 + addps xmm3, xmm6 + STORE2LO( 0, xmm3, xmm7 ) + } + return; + } + case 3: { // 6x3 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [edi+( 0*3+2 )*4] + movhps xmm0, [edi+( 0*3+0 )*4] + shufps xmm0, xmm0, R_SHUFFLEPS( 2, 1, 3, 0 ) + movss xmm6, [esi + 0 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm6, xmm0 + movss xmm1, [edi + ( 1 * 3 + 0 ) * 4] + movhps xmm1, [edi + ( 1 * 3 + 1 ) * 4] + movss xmm7, [esi + 1 * 4] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm1 + addps xmm6, xmm7 + movss xmm2, [edi + ( 2 * 3 + 2 ) * 4] + movhps xmm2, [edi + ( 2 * 3 + 0 ) * 4] + shufps xmm2, xmm2, R_SHUFFLEPS( 2, 1, 3, 0 ) + movss xmm7, [esi + 2 * 4] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm2 + addps xmm6, xmm7 + movss xmm3, [edi + ( 3 * 3 + 0 ) * 4] + movhps xmm3, [edi + ( 3 * 3 + 1 ) * 4] + movss xmm7, [esi + 3 * 4] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm3 + addps xmm6, xmm7 + movss xmm4, [edi + ( 4 * 3 + 2 ) * 4] + movhps xmm4, [edi + ( 4 * 3 + 0 ) * 4] + shufps xmm4, xmm4, R_SHUFFLEPS( 2, 1, 3, 0 ) + movss xmm7, [esi + 4 * 4] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm4 + addps xmm6, xmm7 + movss xmm5, [edi + ( 5 * 3 + 0 ) * 4] + movhps xmm5, [edi + ( 5 * 3 + 1 ) * 4] + movss xmm7, [esi + 5 * 4] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm5 + addps xmm6, xmm7 + STORE1( 0, xmm6, xmm7 ) + STORE2HI( 4, xmm6, xmm7 ) + } + return; + } + case 4: { // 6x4 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm3, [edi+( 0*4+0 )*4] + movhps xmm3, [edi+( 0*4+2 )*4] + movss xmm4, [esi+0*4] + shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm3, xmm4 + movlps xmm5, [edi + ( 1 * 4 + 0 ) * 4] + movhps xmm5, [edi + ( 1 * 4 + 2 ) * 4] + movss xmm6, [esi + 1 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movlps xmm4, [edi + ( 2 * 4 + 0 ) * 4] + movhps xmm4, [edi + ( 2 * 4 + 2 ) * 4] + movss xmm6, [esi + 2 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm4, xmm6 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 3 * 4 + 0 ) * 4] + movhps xmm5, [edi + ( 3 * 4 + 2 ) * 4] + movss xmm6, [esi + 3 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movlps xmm4, [edi + ( 4 * 4 + 0 ) * 4] + movhps xmm4, [edi + ( 4 * 4 + 2 ) * 4] + movss xmm6, [esi + 4 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm4, xmm6 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 5 * 4 + 0 ) * 4] + movhps xmm5, [edi + ( 5 * 4 + 2 ) * 4] + movss xmm6, [esi + 5 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + STORE4( 0, xmm3, xmm7 ) + } + return; + } + case 5: { // 6x5 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm6, [edi+( 0*5+0 )*4] + movhps xmm6, [edi+( 0*5+2 )*4] + movss xmm0, [esi+0*4] + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm6, xmm0 + movlps xmm7, [edi + ( 1 * 5 + 0 ) * 4] + movhps xmm7, [edi + ( 1 * 5 + 2 ) * 4] + movss xmm1, [esi + 1 * 4] + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm1 + addps xmm6, xmm7 + movlps xmm7, [edi + ( 2 * 5 + 0 ) * 4] + movhps xmm7, [edi + ( 2 * 5 + 2 ) * 4] + movss xmm2, [esi + 2 * 4] + shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm2 + addps xmm6, xmm7 + movlps xmm7, [edi + ( 3 * 5 + 0 ) * 4] + movhps xmm7, [edi + ( 3 * 5 + 2 ) * 4] + movss xmm3, [esi + 3 * 4] + shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm3 + addps xmm6, xmm7 + movlps xmm7, [edi + ( 4 * 5 + 0 ) * 4] + movhps xmm7, [edi + ( 4 * 5 + 2 ) * 4] + movss xmm4, [esi + 4 * 4] + shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm4 + addps xmm6, xmm7 + movlps xmm7, [edi + ( 5 * 5 + 0 ) * 4] + movhps xmm7, [edi + ( 5 * 5 + 2 ) * 4] + movss xmm5, [esi + 5 * 4] + shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm5 + addps xmm6, xmm7 + STORE4( 0, xmm6, xmm7 ) + movss xmm6, [edi + ( 0 * 5 + 4 ) * 4] + mulss xmm6, xmm0 + movss xmm7, [edi + ( 1 * 5 + 4 ) * 4] + mulss xmm7, xmm1 + addss xmm6, xmm7 + movss xmm7, [edi + ( 2 * 5 + 4 ) * 4] + mulss xmm7, xmm2 + addss xmm6, xmm7 + movss xmm7, [edi + ( 3 * 5 + 4 ) * 4] + mulss xmm7, xmm3 + addss xmm6, xmm7 + movss xmm7, [edi + ( 4 * 5 + 4 ) * 4] + mulss xmm7, xmm4 + addss xmm6, xmm7 + movss xmm7, [edi + ( 5 * 5 + 4 ) * 4] + mulss xmm7, xmm5 + addss xmm6, xmm7 + STORE1( 16, xmm6, xmm7 ) + } + return; + } + case 6: { // 6x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi+0*4] + movlps xmm1, [esi+2*4] + movlps xmm2, [esi+4*4] + movaps xmm3, xmm0 + shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm3, [edi + ( 0 * 6 + 0 ) * 4] + movlps xmm5, [edi + ( 1 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 1 * 6 + 2 ) * 4] + movaps xmm6, xmm0 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm6, [edi + ( 2 * 6 + 0 ) * 4] + addps xmm3, xmm6 + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + movlps xmm5, [edi + ( 3 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 3 * 6 + 2 ) * 4] + mulps xmm5, xmm6 + addps xmm3, xmm5 + movaps xmm6, xmm2 + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm6, [edi + ( 4 * 6 + 0 ) * 4] + addps xmm3, xmm6 + movaps xmm6, xmm2 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + movlps xmm5, [edi + ( 5 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 5 * 6 + 2 ) * 4] + mulps xmm5, xmm6 + addps xmm3, xmm5 + STORE4( 0, xmm3, xmm7 ) + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) + shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 1, 1 ) + movlps xmm3, [edi + ( 0 * 6 + 4 ) * 4] + movhps xmm3, [edi + ( 1 * 6 + 4 ) * 4] + mulps xmm3, xmm0 + movlps xmm4, [edi + ( 2 * 6 + 4 ) * 4] + movhps xmm4, [edi + ( 3 * 6 + 4 ) * 4] + mulps xmm4, xmm1 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 4 * 6 + 4 ) * 4] + movhps xmm5, [edi + ( 5 * 6 + 4 ) * 4] + mulps xmm5, xmm2 + addps xmm3, xmm5 + movhlps xmm4, xmm3 + addps xmm3, xmm4 + STORE2LO( 16, xmm3, xmm7 ) + } + return; + } + default: { + for ( int i = 0; i < numColumns; i++ ) { + dstPtr[i] STOREC *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3] + *( mPtr + 4 * numColumns ) * vPtr[4] + *( mPtr + 5 * numColumns ) * vPtr[5]; + mPtr++; + } + return; + } + } + break; + default: + int numRows = mat.GetNumRows(); + for ( int i = 0; i < numColumns; i++ ) { + mPtr = mat.ToFloatPtr() + i; + float sum = mPtr[0] * vPtr[0]; + for ( int j = 1; j < numRows; j++ ) { + mPtr += numColumns; + sum += mPtr[0] * vPtr[j]; + } + dstPtr[i] STOREC sum; + } + break; } #undef STOREC @@ -7212,517 +7305,517 @@ void VPCALL idSIMD_SSE::MatX_TransposeMultiplyAddVecX( idVecX &dst, const idMatX vPtr = vec.ToFloatPtr(); dstPtr = dst.ToFloatPtr(); numColumns = mat.GetNumColumns(); - switch( mat.GetNumRows() ) { - case 1: - switch( numColumns ) { - case 6: { // 1x6 * 1x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm1, xmm0 - mulps xmm0, [edi] - mulps xmm1, [edi+16] - STORE4( 0, xmm0, xmm2 ) - STORE2LO( 16, xmm1, xmm3 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0]; - mPtr++; - } - return; - } + switch ( mat.GetNumRows() ) { + case 1: + switch ( numColumns ) { + case 6: { // 1x6 * 1x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm1, xmm0 + mulps xmm0, [edi] + mulps xmm1, [edi + 16] + STORE4( 0, xmm0, xmm2 ) + STORE2LO( 16, xmm1, xmm3 ) + } + return; + } + default: { + for ( int i = 0; i < numColumns; i++ ) { + dstPtr[i] STOREC *( mPtr ) * vPtr[0]; + mPtr++; + } + return; + } + } + break; + case 2: + switch ( numColumns ) { + case 6: { // 2x6 * 2x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi] + movaps xmm1, xmm0 + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) + shufps xmm1, xmm1, R_SHUFFLEPS( 1, 1, 1, 1 ) + movaps xmm2, [edi] + mulps xmm2, xmm0 + movlps xmm3, [edi + 24] + movhps xmm3, [edi + 32] + mulps xmm3, xmm1 + addps xmm2, xmm3 + shufps xmm0, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) + movlps xmm4, [edi + 16] + movhps xmm4, [edi + 40] + mulps xmm4, xmm0 + movhlps xmm3, xmm4 + addps xmm3, xmm4 + STORE4( 0, xmm2, xmm5 ) + STORE2LO( 16, xmm3, xmm6 ) + } + return; + } + default: { + for ( int i = 0; i < numColumns; i++ ) { + dstPtr[i] STOREC *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1]; + mPtr++; + } + return; + } + } + break; + case 3: + switch ( numColumns ) { + case 6: { // 3x6 * 3x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi+0*4] + movss xmm1, [esi+2*4] + movlps xmm3, [edi+( 0*6+0 )*4] + movhps xmm3, [edi+( 0*6+2 )*4] + movaps xmm4, xmm0 + shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm3, xmm4 + movlps xmm5, [edi + ( 1 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 1 * 6 + 2 ) * 4] + movaps xmm6, xmm0 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movlps xmm4, [edi + ( 2 * 6 + 0 ) * 4] + movhps xmm4, [edi + ( 2 * 6 + 2 ) * 4] + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm4, xmm1 + addps xmm3, xmm4 + STORE4( 0, xmm3, xmm7 ) + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) + movlps xmm3, [edi + ( 0 * 6 + 4 ) * 4] + movhps xmm3, [edi + ( 1 * 6 + 4 ) * 4] + mulps xmm3, xmm0 + movhlps xmm4, xmm3 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 2 * 6 + 4 ) * 4] + mulps xmm5, xmm1 + addps xmm3, xmm5 + STORE2LO( 16, xmm3, xmm7 ) + } + return; + } + default: { + for ( int i = 0; i < numColumns; i++ ) { + dstPtr[i] STOREC *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2]; + mPtr++; + } + return; + } + } + break; + case 4: + switch ( numColumns ) { + case 6: { // 4x6 * 4x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi+0*4] + movlps xmm1, [esi+2*4] + movaps xmm3, xmm0 + shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm3, [edi + ( 0 * 6 + 0 ) * 4] + movlps xmm5, [edi + ( 1 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 1 * 6 + 2 ) * 4] + movaps xmm6, xmm0 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movlps xmm4, [edi + ( 2 * 6 + 0 ) * 4] + movhps xmm4, [edi + ( 2 * 6 + 2 ) * 4] + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm4, xmm6 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 3 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 3 * 6 + 2 ) * 4] + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + STORE4( 0, xmm3, xmm7 ) + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) + movlps xmm3, [edi + ( 0 * 6 + 4 ) * 4] + movhps xmm3, [edi + ( 1 * 6 + 4 ) * 4] + mulps xmm3, xmm0 + movlps xmm4, [edi + ( 2 * 6 + 4 ) * 4] + movhps xmm4, [edi + ( 3 * 6 + 4 ) * 4] + mulps xmm4, xmm1 + addps xmm3, xmm4 + movhlps xmm4, xmm3 + addps xmm3, xmm4 + STORE2LO( 16, xmm3, xmm7 ) + } + return; + } + default: { + for ( int i = 0; i < numColumns; i++ ) { + dstPtr[i] STOREC *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3]; + mPtr++; + } + return; + } + } + break; + case 5: + switch ( numColumns ) { + case 6: { // 5x6 * 5x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi+0*4] + movlps xmm1, [esi+2*4] + movss xmm2, [esi+4*4] + movaps xmm3, xmm0 + shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm3, [edi + ( 0 * 6 + 0 ) * 4] + movlps xmm5, [edi + ( 1 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 1 * 6 + 2 ) * 4] + movaps xmm6, xmm0 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm6, [edi + ( 2 * 6 + 0 ) * 4] + addps xmm3, xmm6 + movlps xmm5, [edi + ( 3 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 3 * 6 + 2 ) * 4] + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm4, xmm2 + mulps xmm4, [edi + ( 4 * 6 + 0 ) * 4] + addps xmm3, xmm4 + STORE4( 0, xmm3, xmm7 ) + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) + movlps xmm3, [edi + ( 0 * 6 + 4 ) * 4] + movhps xmm3, [edi + ( 1 * 6 + 4 ) * 4] + mulps xmm3, xmm0 + movlps xmm4, [edi + ( 2 * 6 + 4 ) * 4] + movhps xmm4, [edi + ( 3 * 6 + 4 ) * 4] + mulps xmm4, xmm1 + addps xmm3, xmm4 + movhlps xmm4, xmm3 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 4 * 6 + 4 ) * 4] + mulps xmm5, xmm2 + addps xmm3, xmm5 + STORE2LO( 16, xmm3, xmm7 ) + } + return; + } + default: { + for ( int i = 0; i < numColumns; i++ ) { + dstPtr[i] STOREC *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3] + *( mPtr + 4 * numColumns ) * vPtr[4]; + mPtr++; } - break; - case 2: - switch( numColumns ) { - case 6: { // 2x6 * 2x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi] - movaps xmm1, xmm0 - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - shufps xmm1, xmm1, R_SHUFFLEPS( 1, 1, 1, 1 ) - movaps xmm2, [edi] - mulps xmm2, xmm0 - movlps xmm3, [edi+24] - movhps xmm3, [edi+32] - mulps xmm3, xmm1 - addps xmm2, xmm3 - shufps xmm0, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps xmm4, [edi+16] - movhps xmm4, [edi+40] - mulps xmm4, xmm0 - movhlps xmm3, xmm4 - addps xmm3, xmm4 - STORE4( 0, xmm2, xmm5 ) - STORE2LO( 16, xmm3, xmm6 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1]; - mPtr++; - } - return; - } + return; + } + } + break; + case 6: + switch ( numColumns ) { + case 1: { // 6x1 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi] + movhps xmm0, [esi+8] + movlps xmm1, [esi+16] + mulps xmm0, [edi] + mulps xmm1, [edi+16] + shufps xmm1, xmm0, R_SHUFFLEPS( 0, 1, 3, 2 ) + addps xmm0, xmm1 + movhlps xmm2, xmm0 + addss xmm2, xmm0 + shufps xmm0, xmm0, R_SHUFFLEPS( 1, 0, 0, 0 ) + addss xmm2, xmm0 + STORE1( 0, xmm2, xmm3 ) } - break; - case 3: - switch( numColumns ) { - case 6: { // 3x6 * 3x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi+0*4] - movss xmm1, [esi+2*4] - movlps xmm3, [edi+(0*6+0)*4] - movhps xmm3, [edi+(0*6+2)*4] - movaps xmm4, xmm0 - shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm3, xmm4 - movlps xmm5, [edi+(1*6+0)*4] - movhps xmm5, [edi+(1*6+2)*4] - movaps xmm6, xmm0 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movlps xmm4, [edi+(2*6+0)*4] - movhps xmm4, [edi+(2*6+2)*4] - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm4, xmm1 - addps xmm3, xmm4 - STORE4( 0, xmm3, xmm7 ) - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) - movlps xmm3, [edi+(0*6+4)*4] - movhps xmm3, [edi+(1*6+4)*4] - mulps xmm3, xmm0 - movhlps xmm4, xmm3 - addps xmm3, xmm4 - movlps xmm5, [edi+(2*6+4)*4] - mulps xmm5, xmm1 - addps xmm3, xmm5 - STORE2LO( 16, xmm3, xmm7 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2]; - mPtr++; - } - return; - } + return; + } + case 2: { // 6x2 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi+0*4] + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) + movaps xmm6, [edi + 0 * 4] + mulps xmm6, xmm0 + movlps xmm1, [esi + 2 * 4] + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) + movaps xmm7, [edi + 4 * 4] + mulps xmm7, xmm1 + addps xmm6, xmm7 + movlps xmm2, [esi + 4 * 4] + shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 1, 1 ) + movaps xmm7, [edi + 8 * 4] + mulps xmm7, xmm2 + addps xmm6, xmm7 + movhlps xmm3, xmm6 + addps xmm3, xmm6 + STORE2LO( 0, xmm3, xmm7 ) } - break; - case 4: - switch( numColumns ) { - case 6: { // 4x6 * 4x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi+0*4] - movlps xmm1, [esi+2*4] - movaps xmm3, xmm0 - shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm3, [edi+(0*6+0)*4] - movlps xmm5, [edi+(1*6+0)*4] - movhps xmm5, [edi+(1*6+2)*4] - movaps xmm6, xmm0 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movlps xmm4, [edi+(2*6+0)*4] - movhps xmm4, [edi+(2*6+2)*4] - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm4, xmm6 - addps xmm3, xmm4 - movlps xmm5, [edi+(3*6+0)*4] - movhps xmm5, [edi+(3*6+2)*4] - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - STORE4( 0, xmm3, xmm7 ) - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) - movlps xmm3, [edi+(0*6+4)*4] - movhps xmm3, [edi+(1*6+4)*4] - mulps xmm3, xmm0 - movlps xmm4, [edi+(2*6+4)*4] - movhps xmm4, [edi+(3*6+4)*4] - mulps xmm4, xmm1 - addps xmm3, xmm4 - movhlps xmm4, xmm3 - addps xmm3, xmm4 - STORE2LO( 16, xmm3, xmm7 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3]; - mPtr++; - } - return; - } + return; + } + case 3: { // 6x3 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [edi+( 0*3+2 )*4] + movhps xmm0, [edi+( 0*3+0 )*4] + shufps xmm0, xmm0, R_SHUFFLEPS( 2, 1, 3, 0 ) + movss xmm6, [esi + 0 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm6, xmm0 + movss xmm1, [edi + ( 1 * 3 + 0 ) * 4] + movhps xmm1, [edi + ( 1 * 3 + 1 ) * 4] + movss xmm7, [esi + 1 * 4] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm1 + addps xmm6, xmm7 + movss xmm2, [edi + ( 2 * 3 + 2 ) * 4] + movhps xmm2, [edi + ( 2 * 3 + 0 ) * 4] + shufps xmm2, xmm2, R_SHUFFLEPS( 2, 1, 3, 0 ) + movss xmm7, [esi + 2 * 4] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm2 + addps xmm6, xmm7 + movss xmm3, [edi + ( 3 * 3 + 0 ) * 4] + movhps xmm3, [edi + ( 3 * 3 + 1 ) * 4] + movss xmm7, [esi + 3 * 4] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm3 + addps xmm6, xmm7 + movss xmm4, [edi + ( 4 * 3 + 2 ) * 4] + movhps xmm4, [edi + ( 4 * 3 + 0 ) * 4] + shufps xmm4, xmm4, R_SHUFFLEPS( 2, 1, 3, 0 ) + movss xmm7, [esi + 4 * 4] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm4 + addps xmm6, xmm7 + movss xmm5, [edi + ( 5 * 3 + 0 ) * 4] + movhps xmm5, [edi + ( 5 * 3 + 1 ) * 4] + movss xmm7, [esi + 5 * 4] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm5 + addps xmm6, xmm7 + STORE1( 0, xmm6, xmm7 ) + STORE2HI( 4, xmm6, xmm7 ) } - break; - case 5: - switch( numColumns ) { - case 6: { // 5x6 * 5x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi+0*4] - movlps xmm1, [esi+2*4] - movss xmm2, [esi+4*4] - movaps xmm3, xmm0 - shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm3, [edi+(0*6+0)*4] - movlps xmm5, [edi+(1*6+0)*4] - movhps xmm5, [edi+(1*6+2)*4] - movaps xmm6, xmm0 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm6, [edi+(2*6+0)*4] - addps xmm3, xmm6 - movlps xmm5, [edi+(3*6+0)*4] - movhps xmm5, [edi+(3*6+2)*4] - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm4, xmm2 - mulps xmm4, [edi+(4*6+0)*4] - addps xmm3, xmm4 - STORE4( 0, xmm3, xmm7 ) - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) - movlps xmm3, [edi+(0*6+4)*4] - movhps xmm3, [edi+(1*6+4)*4] - mulps xmm3, xmm0 - movlps xmm4, [edi+(2*6+4)*4] - movhps xmm4, [edi+(3*6+4)*4] - mulps xmm4, xmm1 - addps xmm3, xmm4 - movhlps xmm4, xmm3 - addps xmm3, xmm4 - movlps xmm5, [edi+(4*6+4)*4] - mulps xmm5, xmm2 - addps xmm3, xmm5 - STORE2LO( 16, xmm3, xmm7 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3] + *(mPtr+4*numColumns) * vPtr[4]; - mPtr++; - } - return; - } + return; + } + case 4: { // 6x4 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm3, [edi+( 0*4+0 )*4] + movhps xmm3, [edi+( 0*4+2 )*4] + movss xmm4, [esi+0*4] + shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm3, xmm4 + movlps xmm5, [edi + ( 1 * 4 + 0 ) * 4] + movhps xmm5, [edi + ( 1 * 4 + 2 ) * 4] + movss xmm6, [esi + 1 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movlps xmm4, [edi + ( 2 * 4 + 0 ) * 4] + movhps xmm4, [edi + ( 2 * 4 + 2 ) * 4] + movss xmm6, [esi + 2 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm4, xmm6 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 3 * 4 + 0 ) * 4] + movhps xmm5, [edi + ( 3 * 4 + 2 ) * 4] + movss xmm6, [esi + 3 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movlps xmm4, [edi + ( 4 * 4 + 0 ) * 4] + movhps xmm4, [edi + ( 4 * 4 + 2 ) * 4] + movss xmm6, [esi + 4 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm4, xmm6 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 5 * 4 + 0 ) * 4] + movhps xmm5, [edi + ( 5 * 4 + 2 ) * 4] + movss xmm6, [esi + 5 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + STORE4( 0, xmm3, xmm7 ) } - break; - case 6: - switch( numColumns ) { - case 1: { // 6x1 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi] - movhps xmm0, [esi+8] - movlps xmm1, [esi+16] - mulps xmm0, [edi] - mulps xmm1, [edi+16] - shufps xmm1, xmm0, R_SHUFFLEPS( 0, 1, 3, 2 ) - addps xmm0, xmm1 - movhlps xmm2, xmm0 - addss xmm2, xmm0 - shufps xmm0, xmm0, R_SHUFFLEPS( 1, 0, 0, 0 ) - addss xmm2, xmm0 - STORE1( 0, xmm2, xmm3 ) - } - return; - } - case 2: { // 6x2 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi+0*4] - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) - movaps xmm6, [edi+0*4] - mulps xmm6, xmm0 - movlps xmm1, [esi+2*4] - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) - movaps xmm7, [edi+4*4] - mulps xmm7, xmm1 - addps xmm6, xmm7 - movlps xmm2, [esi+4*4] - shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 1, 1 ) - movaps xmm7, [edi+8*4] - mulps xmm7, xmm2 - addps xmm6, xmm7 - movhlps xmm3, xmm6 - addps xmm3, xmm6 - STORE2LO( 0, xmm3, xmm7 ) - } - return; - } - case 3: { // 6x3 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [edi+(0*3+2)*4] - movhps xmm0, [edi+(0*3+0)*4] - shufps xmm0, xmm0, R_SHUFFLEPS( 2, 1, 3, 0 ) - movss xmm6, [esi+0*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm6, xmm0 - movss xmm1, [edi+(1*3+0)*4] - movhps xmm1, [edi+(1*3+1)*4] - movss xmm7, [esi+1*4] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm1 - addps xmm6, xmm7 - movss xmm2, [edi+(2*3+2)*4] - movhps xmm2, [edi+(2*3+0)*4] - shufps xmm2, xmm2, R_SHUFFLEPS( 2, 1, 3, 0 ) - movss xmm7, [esi+2*4] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm2 - addps xmm6, xmm7 - movss xmm3, [edi+(3*3+0)*4] - movhps xmm3, [edi+(3*3+1)*4] - movss xmm7, [esi+3*4] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm3 - addps xmm6, xmm7 - movss xmm4, [edi+(4*3+2)*4] - movhps xmm4, [edi+(4*3+0)*4] - shufps xmm4, xmm4, R_SHUFFLEPS( 2, 1, 3, 0 ) - movss xmm7, [esi+4*4] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm4 - addps xmm6, xmm7 - movss xmm5, [edi+(5*3+0)*4] - movhps xmm5, [edi+(5*3+1)*4] - movss xmm7, [esi+5*4] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm5 - addps xmm6, xmm7 - STORE1( 0, xmm6, xmm7 ) - STORE2HI( 4, xmm6, xmm7 ) - } - return; - } - case 4: { // 6x4 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm3, [edi+(0*4+0)*4] - movhps xmm3, [edi+(0*4+2)*4] - movss xmm4, [esi+0*4] - shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm3, xmm4 - movlps xmm5, [edi+(1*4+0)*4] - movhps xmm5, [edi+(1*4+2)*4] - movss xmm6, [esi+1*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movlps xmm4, [edi+(2*4+0)*4] - movhps xmm4, [edi+(2*4+2)*4] - movss xmm6, [esi+2*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm4, xmm6 - addps xmm3, xmm4 - movlps xmm5, [edi+(3*4+0)*4] - movhps xmm5, [edi+(3*4+2)*4] - movss xmm6, [esi+3*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movlps xmm4, [edi+(4*4+0)*4] - movhps xmm4, [edi+(4*4+2)*4] - movss xmm6, [esi+4*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm4, xmm6 - addps xmm3, xmm4 - movlps xmm5, [edi+(5*4+0)*4] - movhps xmm5, [edi+(5*4+2)*4] - movss xmm6, [esi+5*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - STORE4( 0, xmm3, xmm7 ) - } - return; - } - case 5: { // 6x5 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm6, [edi+(0*5+0)*4] - movhps xmm6, [edi+(0*5+2)*4] - movss xmm0, [esi+0*4] - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm6, xmm0 - movlps xmm7, [edi+(1*5+0)*4] - movhps xmm7, [edi+(1*5+2)*4] - movss xmm1, [esi+1*4] - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm1 - addps xmm6, xmm7 - movlps xmm7, [edi+(2*5+0)*4] - movhps xmm7, [edi+(2*5+2)*4] - movss xmm2, [esi+2*4] - shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm2 - addps xmm6, xmm7 - movlps xmm7, [edi+(3*5+0)*4] - movhps xmm7, [edi+(3*5+2)*4] - movss xmm3, [esi+3*4] - shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm3 - addps xmm6, xmm7 - movlps xmm7, [edi+(4*5+0)*4] - movhps xmm7, [edi+(4*5+2)*4] - movss xmm4, [esi+4*4] - shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm4 - addps xmm6, xmm7 - movlps xmm7, [edi+(5*5+0)*4] - movhps xmm7, [edi+(5*5+2)*4] - movss xmm5, [esi+5*4] - shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm5 - addps xmm6, xmm7 - STORE4( 0, xmm6, xmm7 ) - movss xmm6, [edi+(0*5+4)*4] - mulss xmm6, xmm0 - movss xmm7, [edi+(1*5+4)*4] - mulss xmm7, xmm1 - addss xmm6, xmm7 - movss xmm7, [edi+(2*5+4)*4] - mulss xmm7, xmm2 - addss xmm6, xmm7 - movss xmm7, [edi+(3*5+4)*4] - mulss xmm7, xmm3 - addss xmm6, xmm7 - movss xmm7, [edi+(4*5+4)*4] - mulss xmm7, xmm4 - addss xmm6, xmm7 - movss xmm7, [edi+(5*5+4)*4] - mulss xmm7, xmm5 - addss xmm6, xmm7 - STORE1( 16, xmm6, xmm7 ) - } - return; - } - case 6: { // 6x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi+0*4] - movlps xmm1, [esi+2*4] - movlps xmm2, [esi+4*4] - movaps xmm3, xmm0 - shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm3, [edi+(0*6+0)*4] - movlps xmm5, [edi+(1*6+0)*4] - movhps xmm5, [edi+(1*6+2)*4] - movaps xmm6, xmm0 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm6, [edi+(2*6+0)*4] - addps xmm3, xmm6 - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - movlps xmm5, [edi+(3*6+0)*4] - movhps xmm5, [edi+(3*6+2)*4] - mulps xmm5, xmm6 - addps xmm3, xmm5 - movaps xmm6, xmm2 - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm6, [edi+(4*6+0)*4] - addps xmm3, xmm6 - movaps xmm6, xmm2 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - movlps xmm5, [edi+(5*6+0)*4] - movhps xmm5, [edi+(5*6+2)*4] - mulps xmm5, xmm6 - addps xmm3, xmm5 - STORE4( 0, xmm3, xmm7 ) - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) - shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 1, 1 ) - movlps xmm3, [edi+(0*6+4)*4] - movhps xmm3, [edi+(1*6+4)*4] - mulps xmm3, xmm0 - movlps xmm4, [edi+(2*6+4)*4] - movhps xmm4, [edi+(3*6+4)*4] - mulps xmm4, xmm1 - addps xmm3, xmm4 - movlps xmm5, [edi+(4*6+4)*4] - movhps xmm5, [edi+(5*6+4)*4] - mulps xmm5, xmm2 - addps xmm3, xmm5 - movhlps xmm4, xmm3 - addps xmm3, xmm4 - STORE2LO( 16, xmm3, xmm7 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3] + *(mPtr+4*numColumns) * vPtr[4] + *(mPtr+5*numColumns) * vPtr[5]; - mPtr++; - } - return; - } + return; + } + case 5: { // 6x5 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm6, [edi+( 0*5+0 )*4] + movhps xmm6, [edi+( 0*5+2 )*4] + movss xmm0, [esi+0*4] + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm6, xmm0 + movlps xmm7, [edi + ( 1 * 5 + 0 ) * 4] + movhps xmm7, [edi + ( 1 * 5 + 2 ) * 4] + movss xmm1, [esi + 1 * 4] + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm1 + addps xmm6, xmm7 + movlps xmm7, [edi + ( 2 * 5 + 0 ) * 4] + movhps xmm7, [edi + ( 2 * 5 + 2 ) * 4] + movss xmm2, [esi + 2 * 4] + shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm2 + addps xmm6, xmm7 + movlps xmm7, [edi + ( 3 * 5 + 0 ) * 4] + movhps xmm7, [edi + ( 3 * 5 + 2 ) * 4] + movss xmm3, [esi + 3 * 4] + shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm3 + addps xmm6, xmm7 + movlps xmm7, [edi + ( 4 * 5 + 0 ) * 4] + movhps xmm7, [edi + ( 4 * 5 + 2 ) * 4] + movss xmm4, [esi + 4 * 4] + shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm4 + addps xmm6, xmm7 + movlps xmm7, [edi + ( 5 * 5 + 0 ) * 4] + movhps xmm7, [edi + ( 5 * 5 + 2 ) * 4] + movss xmm5, [esi + 5 * 4] + shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm5 + addps xmm6, xmm7 + STORE4( 0, xmm6, xmm7 ) + movss xmm6, [edi + ( 0 * 5 + 4 ) * 4] + mulss xmm6, xmm0 + movss xmm7, [edi + ( 1 * 5 + 4 ) * 4] + mulss xmm7, xmm1 + addss xmm6, xmm7 + movss xmm7, [edi + ( 2 * 5 + 4 ) * 4] + mulss xmm7, xmm2 + addss xmm6, xmm7 + movss xmm7, [edi + ( 3 * 5 + 4 ) * 4] + mulss xmm7, xmm3 + addss xmm6, xmm7 + movss xmm7, [edi + ( 4 * 5 + 4 ) * 4] + mulss xmm7, xmm4 + addss xmm6, xmm7 + movss xmm7, [edi + ( 5 * 5 + 4 ) * 4] + mulss xmm7, xmm5 + addss xmm6, xmm7 + STORE1( 16, xmm6, xmm7 ) } - break; - default: - int numRows = mat.GetNumRows(); + return; + } + case 6: { // 6x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi+0*4] + movlps xmm1, [esi+2*4] + movlps xmm2, [esi+4*4] + movaps xmm3, xmm0 + shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm3, [edi + ( 0 * 6 + 0 ) * 4] + movlps xmm5, [edi + ( 1 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 1 * 6 + 2 ) * 4] + movaps xmm6, xmm0 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm6, [edi + ( 2 * 6 + 0 ) * 4] + addps xmm3, xmm6 + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + movlps xmm5, [edi + ( 3 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 3 * 6 + 2 ) * 4] + mulps xmm5, xmm6 + addps xmm3, xmm5 + movaps xmm6, xmm2 + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm6, [edi + ( 4 * 6 + 0 ) * 4] + addps xmm3, xmm6 + movaps xmm6, xmm2 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + movlps xmm5, [edi + ( 5 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 5 * 6 + 2 ) * 4] + mulps xmm5, xmm6 + addps xmm3, xmm5 + STORE4( 0, xmm3, xmm7 ) + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) + shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 1, 1 ) + movlps xmm3, [edi + ( 0 * 6 + 4 ) * 4] + movhps xmm3, [edi + ( 1 * 6 + 4 ) * 4] + mulps xmm3, xmm0 + movlps xmm4, [edi + ( 2 * 6 + 4 ) * 4] + movhps xmm4, [edi + ( 3 * 6 + 4 ) * 4] + mulps xmm4, xmm1 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 4 * 6 + 4 ) * 4] + movhps xmm5, [edi + ( 5 * 6 + 4 ) * 4] + mulps xmm5, xmm2 + addps xmm3, xmm5 + movhlps xmm4, xmm3 + addps xmm3, xmm4 + STORE2LO( 16, xmm3, xmm7 ) + } + return; + } + default: { for ( int i = 0; i < numColumns; i++ ) { - mPtr = mat.ToFloatPtr() + i; - float sum = mPtr[0] * vPtr[0]; - for ( int j = 1; j < numRows; j++ ) { - mPtr += numColumns; - sum += mPtr[0] * vPtr[j]; - } - dstPtr[i] STOREC sum; + dstPtr[i] STOREC *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3] + *( mPtr + 4 * numColumns ) * vPtr[4] + *( mPtr + 5 * numColumns ) * vPtr[5]; + mPtr++; } - break; + return; + } + } + break; + default: + int numRows = mat.GetNumRows(); + for ( int i = 0; i < numColumns; i++ ) { + mPtr = mat.ToFloatPtr() + i; + float sum = mPtr[0] * vPtr[0]; + for ( int j = 1; j < numRows; j++ ) { + mPtr += numColumns; + sum += mPtr[0] * vPtr[j]; + } + dstPtr[i] STOREC sum; + } + break; } #undef STOREC @@ -7776,517 +7869,517 @@ void VPCALL idSIMD_SSE::MatX_TransposeMultiplySubVecX( idVecX &dst, const idMatX vPtr = vec.ToFloatPtr(); dstPtr = dst.ToFloatPtr(); numColumns = mat.GetNumColumns(); - switch( mat.GetNumRows() ) { - case 1: - switch( numColumns ) { - case 6: { // 1x6 * 1x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [esi] - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm1, xmm0 - mulps xmm0, [edi] - mulps xmm1, [edi+16] - STORE4( 0, xmm0, xmm2 ) - STORE2LO( 16, xmm1, xmm3 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0]; - mPtr++; - } - return; - } + switch ( mat.GetNumRows() ) { + case 1: + switch ( numColumns ) { + case 6: { // 1x6 * 1x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [esi] + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm1, xmm0 + mulps xmm0, [edi] + mulps xmm1, [edi + 16] + STORE4( 0, xmm0, xmm2 ) + STORE2LO( 16, xmm1, xmm3 ) } - break; - case 2: - switch( numColumns ) { - case 6: { // 2x6 * 2x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi] - movaps xmm1, xmm0 - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - shufps xmm1, xmm1, R_SHUFFLEPS( 1, 1, 1, 1 ) - movaps xmm2, [edi] - mulps xmm2, xmm0 - movlps xmm3, [edi+24] - movhps xmm3, [edi+32] - mulps xmm3, xmm1 - addps xmm2, xmm3 - shufps xmm0, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps xmm4, [edi+16] - movhps xmm4, [edi+40] - mulps xmm4, xmm0 - movhlps xmm3, xmm4 - addps xmm3, xmm4 - STORE4( 0, xmm2, xmm5 ) - STORE2LO( 16, xmm3, xmm6 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1]; - mPtr++; - } - return; - } + return; + } + default: { + for ( int i = 0; i < numColumns; i++ ) { + dstPtr[i] STOREC *( mPtr ) * vPtr[0]; + mPtr++; } - break; - case 3: - switch( numColumns ) { - case 6: { // 3x6 * 3x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi+0*4] - movss xmm1, [esi+2*4] - movlps xmm3, [edi+(0*6+0)*4] - movhps xmm3, [edi+(0*6+2)*4] - movaps xmm4, xmm0 - shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm3, xmm4 - movlps xmm5, [edi+(1*6+0)*4] - movhps xmm5, [edi+(1*6+2)*4] - movaps xmm6, xmm0 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movlps xmm4, [edi+(2*6+0)*4] - movhps xmm4, [edi+(2*6+2)*4] - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm4, xmm1 - addps xmm3, xmm4 - STORE4( 0, xmm3, xmm7 ) - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) - movlps xmm3, [edi+(0*6+4)*4] - movhps xmm3, [edi+(1*6+4)*4] - mulps xmm3, xmm0 - movhlps xmm4, xmm3 - addps xmm3, xmm4 - movlps xmm5, [edi+(2*6+4)*4] - mulps xmm5, xmm1 - addps xmm3, xmm5 - STORE2LO( 16, xmm3, xmm7 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2]; - mPtr++; - } - return; - } + return; + } + } + break; + case 2: + switch ( numColumns ) { + case 6: { // 2x6 * 2x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi] + movaps xmm1, xmm0 + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) + shufps xmm1, xmm1, R_SHUFFLEPS( 1, 1, 1, 1 ) + movaps xmm2, [edi] + mulps xmm2, xmm0 + movlps xmm3, [edi + 24] + movhps xmm3, [edi + 32] + mulps xmm3, xmm1 + addps xmm2, xmm3 + shufps xmm0, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) + movlps xmm4, [edi + 16] + movhps xmm4, [edi + 40] + mulps xmm4, xmm0 + movhlps xmm3, xmm4 + addps xmm3, xmm4 + STORE4( 0, xmm2, xmm5 ) + STORE2LO( 16, xmm3, xmm6 ) } - break; - case 4: - switch( numColumns ) { - case 6: { // 4x6 * 4x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi+0*4] - movlps xmm1, [esi+2*4] - movaps xmm3, xmm0 - shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm3, [edi+(0*6+0)*4] - movlps xmm5, [edi+(1*6+0)*4] - movhps xmm5, [edi+(1*6+2)*4] - movaps xmm6, xmm0 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movlps xmm4, [edi+(2*6+0)*4] - movhps xmm4, [edi+(2*6+2)*4] - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm4, xmm6 - addps xmm3, xmm4 - movlps xmm5, [edi+(3*6+0)*4] - movhps xmm5, [edi+(3*6+2)*4] - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - STORE4( 0, xmm3, xmm7 ) - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) - movlps xmm3, [edi+(0*6+4)*4] - movhps xmm3, [edi+(1*6+4)*4] - mulps xmm3, xmm0 - movlps xmm4, [edi+(2*6+4)*4] - movhps xmm4, [edi+(3*6+4)*4] - mulps xmm4, xmm1 - addps xmm3, xmm4 - movhlps xmm4, xmm3 - addps xmm3, xmm4 - STORE2LO( 16, xmm3, xmm7 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3]; - mPtr++; - } - return; - } + return; + } + default: { + for ( int i = 0; i < numColumns; i++ ) { + dstPtr[i] STOREC *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1]; + mPtr++; } - break; - case 5: - switch( numColumns ) { - case 6: { // 5x6 * 5x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi+0*4] - movlps xmm1, [esi+2*4] - movss xmm2, [esi+4*4] - movaps xmm3, xmm0 - shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm3, [edi+(0*6+0)*4] - movlps xmm5, [edi+(1*6+0)*4] - movhps xmm5, [edi+(1*6+2)*4] - movaps xmm6, xmm0 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm6, [edi+(2*6+0)*4] - addps xmm3, xmm6 - movlps xmm5, [edi+(3*6+0)*4] - movhps xmm5, [edi+(3*6+2)*4] - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm4, xmm2 - mulps xmm4, [edi+(4*6+0)*4] - addps xmm3, xmm4 - STORE4( 0, xmm3, xmm7 ) - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) - movlps xmm3, [edi+(0*6+4)*4] - movhps xmm3, [edi+(1*6+4)*4] - mulps xmm3, xmm0 - movlps xmm4, [edi+(2*6+4)*4] - movhps xmm4, [edi+(3*6+4)*4] - mulps xmm4, xmm1 - addps xmm3, xmm4 - movhlps xmm4, xmm3 - addps xmm3, xmm4 - movlps xmm5, [edi+(4*6+4)*4] - mulps xmm5, xmm2 - addps xmm3, xmm5 - STORE2LO( 16, xmm3, xmm7 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3] + *(mPtr+4*numColumns) * vPtr[4]; - mPtr++; - } - return; - } + return; + } + } + break; + case 3: + switch ( numColumns ) { + case 6: { // 3x6 * 3x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi+0*4] + movss xmm1, [esi+2*4] + movlps xmm3, [edi+( 0*6+0 )*4] + movhps xmm3, [edi+( 0*6+2 )*4] + movaps xmm4, xmm0 + shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm3, xmm4 + movlps xmm5, [edi + ( 1 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 1 * 6 + 2 ) * 4] + movaps xmm6, xmm0 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movlps xmm4, [edi + ( 2 * 6 + 0 ) * 4] + movhps xmm4, [edi + ( 2 * 6 + 2 ) * 4] + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm4, xmm1 + addps xmm3, xmm4 + STORE4( 0, xmm3, xmm7 ) + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) + movlps xmm3, [edi + ( 0 * 6 + 4 ) * 4] + movhps xmm3, [edi + ( 1 * 6 + 4 ) * 4] + mulps xmm3, xmm0 + movhlps xmm4, xmm3 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 2 * 6 + 4 ) * 4] + mulps xmm5, xmm1 + addps xmm3, xmm5 + STORE2LO( 16, xmm3, xmm7 ) } - break; - case 6: - switch( numColumns ) { - case 1: { // 6x1 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi] - movhps xmm0, [esi+8] - movlps xmm1, [esi+16] - mulps xmm0, [edi] - mulps xmm1, [edi+16] - shufps xmm1, xmm0, R_SHUFFLEPS( 0, 1, 3, 2 ) - addps xmm0, xmm1 - movhlps xmm2, xmm0 - addss xmm2, xmm0 - shufps xmm0, xmm0, R_SHUFFLEPS( 1, 0, 0, 0 ) - addss xmm2, xmm0 - STORE1( 0, xmm2, xmm3 ) - } - return; - } - case 2: { // 6x2 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi+0*4] - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) - movaps xmm6, [edi+0*4] - mulps xmm6, xmm0 - movlps xmm1, [esi+2*4] - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) - movaps xmm7, [edi+4*4] - mulps xmm7, xmm1 - addps xmm6, xmm7 - movlps xmm2, [esi+4*4] - shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 1, 1 ) - movaps xmm7, [edi+8*4] - mulps xmm7, xmm2 - addps xmm6, xmm7 - movhlps xmm3, xmm6 - addps xmm3, xmm6 - STORE2LO( 0, xmm3, xmm7 ) - } - return; - } - case 3: { // 6x3 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movss xmm0, [edi+(0*3+2)*4] - movhps xmm0, [edi+(0*3+0)*4] - shufps xmm0, xmm0, R_SHUFFLEPS( 2, 1, 3, 0 ) - movss xmm6, [esi+0*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm6, xmm0 - movss xmm1, [edi+(1*3+0)*4] - movhps xmm1, [edi+(1*3+1)*4] - movss xmm7, [esi+1*4] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm1 - addps xmm6, xmm7 - movss xmm2, [edi+(2*3+2)*4] - movhps xmm2, [edi+(2*3+0)*4] - shufps xmm2, xmm2, R_SHUFFLEPS( 2, 1, 3, 0 ) - movss xmm7, [esi+2*4] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm2 - addps xmm6, xmm7 - movss xmm3, [edi+(3*3+0)*4] - movhps xmm3, [edi+(3*3+1)*4] - movss xmm7, [esi+3*4] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm3 - addps xmm6, xmm7 - movss xmm4, [edi+(4*3+2)*4] - movhps xmm4, [edi+(4*3+0)*4] - shufps xmm4, xmm4, R_SHUFFLEPS( 2, 1, 3, 0 ) - movss xmm7, [esi+4*4] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm4 - addps xmm6, xmm7 - movss xmm5, [edi+(5*3+0)*4] - movhps xmm5, [edi+(5*3+1)*4] - movss xmm7, [esi+5*4] - shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm5 - addps xmm6, xmm7 - STORE1( 0, xmm6, xmm7 ) - STORE2HI( 4, xmm6, xmm7 ) - } - return; - } - case 4: { // 6x4 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm3, [edi+(0*4+0)*4] - movhps xmm3, [edi+(0*4+2)*4] - movss xmm4, [esi+0*4] - shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm3, xmm4 - movlps xmm5, [edi+(1*4+0)*4] - movhps xmm5, [edi+(1*4+2)*4] - movss xmm6, [esi+1*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movlps xmm4, [edi+(2*4+0)*4] - movhps xmm4, [edi+(2*4+2)*4] - movss xmm6, [esi+2*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm4, xmm6 - addps xmm3, xmm4 - movlps xmm5, [edi+(3*4+0)*4] - movhps xmm5, [edi+(3*4+2)*4] - movss xmm6, [esi+3*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movlps xmm4, [edi+(4*4+0)*4] - movhps xmm4, [edi+(4*4+2)*4] - movss xmm6, [esi+4*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm4, xmm6 - addps xmm3, xmm4 - movlps xmm5, [edi+(5*4+0)*4] - movhps xmm5, [edi+(5*4+2)*4] - movss xmm6, [esi+5*4] - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - STORE4( 0, xmm3, xmm7 ) - } - return; - } - case 5: { // 6x5 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm6, [edi+(0*5+0)*4] - movhps xmm6, [edi+(0*5+2)*4] - movss xmm0, [esi+0*4] - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm6, xmm0 - movlps xmm7, [edi+(1*5+0)*4] - movhps xmm7, [edi+(1*5+2)*4] - movss xmm1, [esi+1*4] - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm1 - addps xmm6, xmm7 - movlps xmm7, [edi+(2*5+0)*4] - movhps xmm7, [edi+(2*5+2)*4] - movss xmm2, [esi+2*4] - shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm2 - addps xmm6, xmm7 - movlps xmm7, [edi+(3*5+0)*4] - movhps xmm7, [edi+(3*5+2)*4] - movss xmm3, [esi+3*4] - shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm3 - addps xmm6, xmm7 - movlps xmm7, [edi+(4*5+0)*4] - movhps xmm7, [edi+(4*5+2)*4] - movss xmm4, [esi+4*4] - shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm4 - addps xmm6, xmm7 - movlps xmm7, [edi+(5*5+0)*4] - movhps xmm7, [edi+(5*5+2)*4] - movss xmm5, [esi+5*4] - shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm7, xmm5 - addps xmm6, xmm7 - STORE4( 0, xmm6, xmm7 ) - movss xmm6, [edi+(0*5+4)*4] - mulss xmm6, xmm0 - movss xmm7, [edi+(1*5+4)*4] - mulss xmm7, xmm1 - addss xmm6, xmm7 - movss xmm7, [edi+(2*5+4)*4] - mulss xmm7, xmm2 - addss xmm6, xmm7 - movss xmm7, [edi+(3*5+4)*4] - mulss xmm7, xmm3 - addss xmm6, xmm7 - movss xmm7, [edi+(4*5+4)*4] - mulss xmm7, xmm4 - addss xmm6, xmm7 - movss xmm7, [edi+(5*5+4)*4] - mulss xmm7, xmm5 - addss xmm6, xmm7 - STORE1( 16, xmm6, xmm7 ) - } - return; - } - case 6: { // 6x6 * 6x1 - __asm { - mov esi, vPtr - mov edi, mPtr - mov eax, dstPtr - movlps xmm0, [esi+0*4] - movlps xmm1, [esi+2*4] - movlps xmm2, [esi+4*4] - movaps xmm3, xmm0 - shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm3, [edi+(0*6+0)*4] - movlps xmm5, [edi+(1*6+0)*4] - movhps xmm5, [edi+(1*6+2)*4] - movaps xmm6, xmm0 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm5, xmm6 - addps xmm3, xmm5 - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm6, [edi+(2*6+0)*4] - addps xmm3, xmm6 - movaps xmm6, xmm1 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - movlps xmm5, [edi+(3*6+0)*4] - movhps xmm5, [edi+(3*6+2)*4] - mulps xmm5, xmm6 - addps xmm3, xmm5 - movaps xmm6, xmm2 - shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) - mulps xmm6, [edi+(4*6+0)*4] - addps xmm3, xmm6 - movaps xmm6, xmm2 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - movlps xmm5, [edi+(5*6+0)*4] - movhps xmm5, [edi+(5*6+2)*4] - mulps xmm5, xmm6 - addps xmm3, xmm5 - STORE4( 0, xmm3, xmm7 ) - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) - shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) - shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 1, 1 ) - movlps xmm3, [edi+(0*6+4)*4] - movhps xmm3, [edi+(1*6+4)*4] - mulps xmm3, xmm0 - movlps xmm4, [edi+(2*6+4)*4] - movhps xmm4, [edi+(3*6+4)*4] - mulps xmm4, xmm1 - addps xmm3, xmm4 - movlps xmm5, [edi+(4*6+4)*4] - movhps xmm5, [edi+(5*6+4)*4] - mulps xmm5, xmm2 - addps xmm3, xmm5 - movhlps xmm4, xmm3 - addps xmm3, xmm4 - STORE2LO( 16, xmm3, xmm7 ) - } - return; - } - default: { - for ( int i = 0; i < numColumns; i++ ) { - dstPtr[i] STOREC *(mPtr) * vPtr[0] + *(mPtr+numColumns) * vPtr[1] + *(mPtr+2*numColumns) * vPtr[2] + - *(mPtr+3*numColumns) * vPtr[3] + *(mPtr+4*numColumns) * vPtr[4] + *(mPtr+5*numColumns) * vPtr[5]; - mPtr++; - } - return; - } + return; + } + default: { + for ( int i = 0; i < numColumns; i++ ) { + dstPtr[i] STOREC *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2]; + mPtr++; } - break; - default: - int numRows = mat.GetNumRows(); + return; + } + } + break; + case 4: + switch ( numColumns ) { + case 6: { // 4x6 * 4x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi+0*4] + movlps xmm1, [esi+2*4] + movaps xmm3, xmm0 + shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm3, [edi + ( 0 * 6 + 0 ) * 4] + movlps xmm5, [edi + ( 1 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 1 * 6 + 2 ) * 4] + movaps xmm6, xmm0 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movlps xmm4, [edi + ( 2 * 6 + 0 ) * 4] + movhps xmm4, [edi + ( 2 * 6 + 2 ) * 4] + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm4, xmm6 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 3 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 3 * 6 + 2 ) * 4] + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + STORE4( 0, xmm3, xmm7 ) + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) + movlps xmm3, [edi + ( 0 * 6 + 4 ) * 4] + movhps xmm3, [edi + ( 1 * 6 + 4 ) * 4] + mulps xmm3, xmm0 + movlps xmm4, [edi + ( 2 * 6 + 4 ) * 4] + movhps xmm4, [edi + ( 3 * 6 + 4 ) * 4] + mulps xmm4, xmm1 + addps xmm3, xmm4 + movhlps xmm4, xmm3 + addps xmm3, xmm4 + STORE2LO( 16, xmm3, xmm7 ) + } + return; + } + default: { for ( int i = 0; i < numColumns; i++ ) { - mPtr = mat.ToFloatPtr() + i; - float sum = mPtr[0] * vPtr[0]; - for ( int j = 1; j < numRows; j++ ) { - mPtr += numColumns; - sum += mPtr[0] * vPtr[j]; - } - dstPtr[i] STOREC sum; + dstPtr[i] STOREC *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3]; + mPtr++; } - break; + return; + } + } + break; + case 5: + switch ( numColumns ) { + case 6: { // 5x6 * 5x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi+0*4] + movlps xmm1, [esi+2*4] + movss xmm2, [esi+4*4] + movaps xmm3, xmm0 + shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm3, [edi + ( 0 * 6 + 0 ) * 4] + movlps xmm5, [edi + ( 1 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 1 * 6 + 2 ) * 4] + movaps xmm6, xmm0 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm6, [edi + ( 2 * 6 + 0 ) * 4] + addps xmm3, xmm6 + movlps xmm5, [edi + ( 3 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 3 * 6 + 2 ) * 4] + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm4, xmm2 + mulps xmm4, [edi + ( 4 * 6 + 0 ) * 4] + addps xmm3, xmm4 + STORE4( 0, xmm3, xmm7 ) + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) + movlps xmm3, [edi + ( 0 * 6 + 4 ) * 4] + movhps xmm3, [edi + ( 1 * 6 + 4 ) * 4] + mulps xmm3, xmm0 + movlps xmm4, [edi + ( 2 * 6 + 4 ) * 4] + movhps xmm4, [edi + ( 3 * 6 + 4 ) * 4] + mulps xmm4, xmm1 + addps xmm3, xmm4 + movhlps xmm4, xmm3 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 4 * 6 + 4 ) * 4] + mulps xmm5, xmm2 + addps xmm3, xmm5 + STORE2LO( 16, xmm3, xmm7 ) + } + return; + } + default: { + for ( int i = 0; i < numColumns; i++ ) { + dstPtr[i] STOREC *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3] + *( mPtr + 4 * numColumns ) * vPtr[4]; + mPtr++; + } + return; + } + } + break; + case 6: + switch ( numColumns ) { + case 1: { // 6x1 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi] + movhps xmm0, [esi+8] + movlps xmm1, [esi+16] + mulps xmm0, [edi] + mulps xmm1, [edi+16] + shufps xmm1, xmm0, R_SHUFFLEPS( 0, 1, 3, 2 ) + addps xmm0, xmm1 + movhlps xmm2, xmm0 + addss xmm2, xmm0 + shufps xmm0, xmm0, R_SHUFFLEPS( 1, 0, 0, 0 ) + addss xmm2, xmm0 + STORE1( 0, xmm2, xmm3 ) + } + return; + } + case 2: { // 6x2 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi+0*4] + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) + movaps xmm6, [edi + 0 * 4] + mulps xmm6, xmm0 + movlps xmm1, [esi + 2 * 4] + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) + movaps xmm7, [edi + 4 * 4] + mulps xmm7, xmm1 + addps xmm6, xmm7 + movlps xmm2, [esi + 4 * 4] + shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 1, 1 ) + movaps xmm7, [edi + 8 * 4] + mulps xmm7, xmm2 + addps xmm6, xmm7 + movhlps xmm3, xmm6 + addps xmm3, xmm6 + STORE2LO( 0, xmm3, xmm7 ) + } + return; + } + case 3: { // 6x3 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movss xmm0, [edi+( 0*3+2 )*4] + movhps xmm0, [edi+( 0*3+0 )*4] + shufps xmm0, xmm0, R_SHUFFLEPS( 2, 1, 3, 0 ) + movss xmm6, [esi + 0 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm6, xmm0 + movss xmm1, [edi + ( 1 * 3 + 0 ) * 4] + movhps xmm1, [edi + ( 1 * 3 + 1 ) * 4] + movss xmm7, [esi + 1 * 4] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm1 + addps xmm6, xmm7 + movss xmm2, [edi + ( 2 * 3 + 2 ) * 4] + movhps xmm2, [edi + ( 2 * 3 + 0 ) * 4] + shufps xmm2, xmm2, R_SHUFFLEPS( 2, 1, 3, 0 ) + movss xmm7, [esi + 2 * 4] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm2 + addps xmm6, xmm7 + movss xmm3, [edi + ( 3 * 3 + 0 ) * 4] + movhps xmm3, [edi + ( 3 * 3 + 1 ) * 4] + movss xmm7, [esi + 3 * 4] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm3 + addps xmm6, xmm7 + movss xmm4, [edi + ( 4 * 3 + 2 ) * 4] + movhps xmm4, [edi + ( 4 * 3 + 0 ) * 4] + shufps xmm4, xmm4, R_SHUFFLEPS( 2, 1, 3, 0 ) + movss xmm7, [esi + 4 * 4] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm4 + addps xmm6, xmm7 + movss xmm5, [edi + ( 5 * 3 + 0 ) * 4] + movhps xmm5, [edi + ( 5 * 3 + 1 ) * 4] + movss xmm7, [esi + 5 * 4] + shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm5 + addps xmm6, xmm7 + STORE1( 0, xmm6, xmm7 ) + STORE2HI( 4, xmm6, xmm7 ) + } + return; + } + case 4: { // 6x4 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm3, [edi+( 0*4+0 )*4] + movhps xmm3, [edi+( 0*4+2 )*4] + movss xmm4, [esi+0*4] + shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm3, xmm4 + movlps xmm5, [edi + ( 1 * 4 + 0 ) * 4] + movhps xmm5, [edi + ( 1 * 4 + 2 ) * 4] + movss xmm6, [esi + 1 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movlps xmm4, [edi + ( 2 * 4 + 0 ) * 4] + movhps xmm4, [edi + ( 2 * 4 + 2 ) * 4] + movss xmm6, [esi + 2 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm4, xmm6 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 3 * 4 + 0 ) * 4] + movhps xmm5, [edi + ( 3 * 4 + 2 ) * 4] + movss xmm6, [esi + 3 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movlps xmm4, [edi + ( 4 * 4 + 0 ) * 4] + movhps xmm4, [edi + ( 4 * 4 + 2 ) * 4] + movss xmm6, [esi + 4 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm4, xmm6 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 5 * 4 + 0 ) * 4] + movhps xmm5, [edi + ( 5 * 4 + 2 ) * 4] + movss xmm6, [esi + 5 * 4] + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + STORE4( 0, xmm3, xmm7 ) + } + return; + } + case 5: { // 6x5 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm6, [edi+( 0*5+0 )*4] + movhps xmm6, [edi+( 0*5+2 )*4] + movss xmm0, [esi+0*4] + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm6, xmm0 + movlps xmm7, [edi + ( 1 * 5 + 0 ) * 4] + movhps xmm7, [edi + ( 1 * 5 + 2 ) * 4] + movss xmm1, [esi + 1 * 4] + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm1 + addps xmm6, xmm7 + movlps xmm7, [edi + ( 2 * 5 + 0 ) * 4] + movhps xmm7, [edi + ( 2 * 5 + 2 ) * 4] + movss xmm2, [esi + 2 * 4] + shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm2 + addps xmm6, xmm7 + movlps xmm7, [edi + ( 3 * 5 + 0 ) * 4] + movhps xmm7, [edi + ( 3 * 5 + 2 ) * 4] + movss xmm3, [esi + 3 * 4] + shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm3 + addps xmm6, xmm7 + movlps xmm7, [edi + ( 4 * 5 + 0 ) * 4] + movhps xmm7, [edi + ( 4 * 5 + 2 ) * 4] + movss xmm4, [esi + 4 * 4] + shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm4 + addps xmm6, xmm7 + movlps xmm7, [edi + ( 5 * 5 + 0 ) * 4] + movhps xmm7, [edi + ( 5 * 5 + 2 ) * 4] + movss xmm5, [esi + 5 * 4] + shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm7, xmm5 + addps xmm6, xmm7 + STORE4( 0, xmm6, xmm7 ) + movss xmm6, [edi + ( 0 * 5 + 4 ) * 4] + mulss xmm6, xmm0 + movss xmm7, [edi + ( 1 * 5 + 4 ) * 4] + mulss xmm7, xmm1 + addss xmm6, xmm7 + movss xmm7, [edi + ( 2 * 5 + 4 ) * 4] + mulss xmm7, xmm2 + addss xmm6, xmm7 + movss xmm7, [edi + ( 3 * 5 + 4 ) * 4] + mulss xmm7, xmm3 + addss xmm6, xmm7 + movss xmm7, [edi + ( 4 * 5 + 4 ) * 4] + mulss xmm7, xmm4 + addss xmm6, xmm7 + movss xmm7, [edi + ( 5 * 5 + 4 ) * 4] + mulss xmm7, xmm5 + addss xmm6, xmm7 + STORE1( 16, xmm6, xmm7 ) + } + return; + } + case 6: { // 6x6 * 6x1 + __asm { + mov esi, vPtr + mov edi, mPtr + mov eax, dstPtr + movlps xmm0, [esi+0*4] + movlps xmm1, [esi+2*4] + movlps xmm2, [esi+4*4] + movaps xmm3, xmm0 + shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm3, [edi + ( 0 * 6 + 0 ) * 4] + movlps xmm5, [edi + ( 1 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 1 * 6 + 2 ) * 4] + movaps xmm6, xmm0 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm5, xmm6 + addps xmm3, xmm5 + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm6, [edi + ( 2 * 6 + 0 ) * 4] + addps xmm3, xmm6 + movaps xmm6, xmm1 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + movlps xmm5, [edi + ( 3 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 3 * 6 + 2 ) * 4] + mulps xmm5, xmm6 + addps xmm3, xmm5 + movaps xmm6, xmm2 + shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) + mulps xmm6, [edi + ( 4 * 6 + 0 ) * 4] + addps xmm3, xmm6 + movaps xmm6, xmm2 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + movlps xmm5, [edi + ( 5 * 6 + 0 ) * 4] + movhps xmm5, [edi + ( 5 * 6 + 2 ) * 4] + mulps xmm5, xmm6 + addps xmm3, xmm5 + STORE4( 0, xmm3, xmm7 ) + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) + shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) + shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 1, 1 ) + movlps xmm3, [edi + ( 0 * 6 + 4 ) * 4] + movhps xmm3, [edi + ( 1 * 6 + 4 ) * 4] + mulps xmm3, xmm0 + movlps xmm4, [edi + ( 2 * 6 + 4 ) * 4] + movhps xmm4, [edi + ( 3 * 6 + 4 ) * 4] + mulps xmm4, xmm1 + addps xmm3, xmm4 + movlps xmm5, [edi + ( 4 * 6 + 4 ) * 4] + movhps xmm5, [edi + ( 5 * 6 + 4 ) * 4] + mulps xmm5, xmm2 + addps xmm3, xmm5 + movhlps xmm4, xmm3 + addps xmm3, xmm4 + STORE2LO( 16, xmm3, xmm7 ) + } + return; + } + default: { + for ( int i = 0; i < numColumns; i++ ) { + dstPtr[i] STOREC *( mPtr ) * vPtr[0] + *( mPtr + numColumns ) * vPtr[1] + *( mPtr + 2 * numColumns ) * vPtr[2] + + *( mPtr + 3 * numColumns ) * vPtr[3] + *( mPtr + 4 * numColumns ) * vPtr[4] + *( mPtr + 5 * numColumns ) * vPtr[5]; + mPtr++; + } + return; + } + } + break; + default: + int numRows = mat.GetNumRows(); + for ( int i = 0; i < numColumns; i++ ) { + mPtr = mat.ToFloatPtr() + i; + float sum = mPtr[0] * vPtr[0]; + for ( int j = 1; j < numRows; j++ ) { + mPtr += numColumns; + sum += mPtr[0] * vPtr[j]; + } + dstPtr[i] STOREC sum; + } + break; } #undef STOREC @@ -8329,1271 +8422,1271 @@ void VPCALL idSIMD_SSE::MatX_MultiplyMatX( idMatX &dst, const idMatX &m1, const l = m2.GetNumColumns(); n = m1.GetNumColumns(); - switch( n ) { - case 1: { - if ( !(l^6) ) { - switch( k ) { - case 1: { // 1x1 * 1x6, no precision loss compared to FPU version - __asm { - mov esi, m2Ptr - mov edi, m1Ptr - mov eax, dstPtr - movss xmm0, [edi] - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm1, [esi] - mulps xmm1, xmm0 - movaps [eax], xmm1 - movlps xmm2, [esi+16] - mulps xmm2, xmm0 - movlps [eax+16], xmm2 - } - return; - } - case 6: { // 6x1 * 1x6, no precision loss compared to FPU version - __asm { - mov esi, m2Ptr - mov edi, m1Ptr - mov eax, dstPtr - xorps xmm1, xmm1 - movaps xmm0, [edi] - movlps xmm1, [edi+16] - movlhps xmm1, xmm0 - movhlps xmm2, xmm0 - movlhps xmm2, xmm1 - // row 0 and 1 - movaps xmm3, [esi] - movaps xmm4, xmm3 - shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm5, xmm3 - shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 1, 1 ) - movaps xmm6, xmm3 - shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm4, xmm0 - mulps xmm5, xmm1 - mulps xmm6, xmm2 - movaps [eax], xmm4 - movaps [eax+16], xmm5 - movaps [eax+32], xmm6 - // row 2 and 3 - movaps xmm4, xmm3 - shufps xmm4, xmm4, R_SHUFFLEPS( 2, 2, 2, 2 ) - movaps xmm5, xmm3 - shufps xmm5, xmm5, R_SHUFFLEPS( 2, 2, 3, 3 ) - shufps xmm3, xmm3, R_SHUFFLEPS( 3, 3, 3, 3 ) - mulps xmm4, xmm0 - mulps xmm5, xmm1 - mulps xmm3, xmm2 - movaps [eax+48], xmm4 - movaps [eax+64], xmm5 - movaps [eax+80], xmm3 - // row 4 and 5 - movlps xmm3, [esi+16] - movaps xmm4, xmm3 - shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm5, xmm3 - shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 1, 1 ) - shufps xmm3, xmm3, R_SHUFFLEPS( 1, 1, 1, 1 ) - mulps xmm4, xmm0 - mulps xmm5, xmm1 - mulps xmm3, xmm2 - movaps [eax+96], xmm4 - movaps [eax+112], xmm5 - movaps [eax+128], xmm3 - } - return; - } - } + switch ( n ) { + case 1: { + if ( !( l ^ 6 ) ) { + switch ( k ) { + case 1: { // 1x1 * 1x6, no precision loss compared to FPU version + __asm { + mov esi, m2Ptr + mov edi, m1Ptr + mov eax, dstPtr + movss xmm0, [edi] + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm1, [esi] + mulps xmm1, xmm0 + movaps [eax], xmm1 + movlps xmm2, [esi + 16] + mulps xmm2, xmm0 + movlps [eax + 16], xmm2 + } + return; + } + case 6: { // 6x1 * 1x6, no precision loss compared to FPU version + __asm { + mov esi, m2Ptr + mov edi, m1Ptr + mov eax, dstPtr + xorps xmm1, xmm1 + movaps xmm0, [edi] + movlps xmm1, [edi+16] + movlhps xmm1, xmm0 + movhlps xmm2, xmm0 + movlhps xmm2, xmm1 + // row 0 and 1 + movaps xmm3, [esi] + movaps xmm4, xmm3 + shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm5, xmm3 + shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 1, 1 ) + movaps xmm6, xmm3 + shufps xmm6, xmm6, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm4, xmm0 + mulps xmm5, xmm1 + mulps xmm6, xmm2 + movaps [eax], xmm4 + movaps [eax + 16], xmm5 + movaps [eax + 32], xmm6 + // row 2 and 3 + movaps xmm4, xmm3 + shufps xmm4, xmm4, R_SHUFFLEPS( 2, 2, 2, 2 ) + movaps xmm5, xmm3 + shufps xmm5, xmm5, R_SHUFFLEPS( 2, 2, 3, 3 ) + shufps xmm3, xmm3, R_SHUFFLEPS( 3, 3, 3, 3 ) + mulps xmm4, xmm0 + mulps xmm5, xmm1 + mulps xmm3, xmm2 + movaps [eax + 48], xmm4 + movaps [eax + 64], xmm5 + movaps [eax + 80], xmm3 + // row 4 and 5 + movlps xmm3, [esi + 16] + movaps xmm4, xmm3 + shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm5, xmm3 + shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 1, 1 ) + shufps xmm3, xmm3, R_SHUFFLEPS( 1, 1, 1, 1 ) + mulps xmm4, xmm0 + mulps xmm5, xmm1 + mulps xmm3, xmm2 + movaps [eax + 96], xmm4 + movaps [eax + 112], xmm5 + movaps [eax + 128], xmm3 + } + return; + } + } + } + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0]; + m2Ptr++; + } + m1Ptr++; + } + break; + } + case 2: { + if ( !( l ^ 6 ) ) { + switch ( k ) { + case 2: { // 2x2 * 2x6 + +#define MUL_Nx2_2x6_INIT \ + __asm mov esi, m2Ptr \ + __asm mov edi, m1Ptr \ + __asm mov eax, dstPtr \ + __asm movaps xmm0, [esi] \ + __asm movlps xmm1, [esi+16] \ + __asm movhps xmm1, [esi+40] \ + __asm movlps xmm2, [esi+24] \ + __asm movhps xmm2, [esi+32] + +#define MUL_Nx2_2x6_ROW2( row ) \ + __asm movaps xmm3, [edi+row*16] \ + __asm movaps xmm5, xmm0 \ + __asm movaps xmm4, xmm3 \ + __asm shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm5, xmm4 \ + __asm movaps xmm4, xmm3 \ + __asm movaps xmm6, xmm2 \ + __asm shufps xmm4, xmm4, R_SHUFFLEPS( 1, 1, 1, 1 ) \ + __asm mulps xmm6, xmm4 \ + __asm addps xmm5, xmm6 \ + __asm movaps [eax+row*48], xmm5 \ + __asm movaps xmm4, xmm3 \ + __asm shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 1, 1 ) \ + __asm movaps xmm7, xmm1 \ + __asm mulps xmm7, xmm4 \ + __asm movaps xmm4, xmm3 \ + __asm movaps xmm5, xmm0 \ + __asm shufps xmm4, xmm4, R_SHUFFLEPS( 2, 2, 2, 2 ) \ + __asm mulps xmm5, xmm4 \ + __asm movaps xmm4, xmm3 \ + __asm movaps xmm6, xmm2 \ + __asm shufps xmm4, xmm4, R_SHUFFLEPS( 3, 3, 3, 3 ) \ + __asm mulps xmm6, xmm4 \ + __asm addps xmm5, xmm6 \ + __asm shufps xmm3, xmm3, R_SHUFFLEPS( 2, 2, 3, 3 ) \ + __asm movaps xmm6, xmm1 \ + __asm mulps xmm6, xmm3 \ + __asm movaps xmm4, xmm7 \ + __asm movlhps xmm7, xmm6 \ + __asm movhlps xmm6, xmm4 \ + __asm addps xmm6, xmm7 \ + __asm movlps [eax+row*48+16], xmm6 \ + __asm movlps [eax+row*48+24], xmm5 \ + __asm movhps [eax+row*48+32], xmm5 \ + __asm movhps [eax+row*48+40], xmm6 + + MUL_Nx2_2x6_INIT + MUL_Nx2_2x6_ROW2( 0 ) + + return; + } + case 6: { // 6x2 * 2x6 + + MUL_Nx2_2x6_INIT + MUL_Nx2_2x6_ROW2( 0 ) + MUL_Nx2_2x6_ROW2( 1 ) + MUL_Nx2_2x6_ROW2( 2 ) + + return; + } + } + } + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l]; + m2Ptr++; + } + m1Ptr += 2; + } + break; + } + case 3: { + if ( !( l ^ 6 ) ) { + switch ( k ) { + case 3: { // 3x3 * 3x6 + __asm { + mov esi, m2Ptr + mov edi, m1Ptr + mov eax, dstPtr + movaps xmm5, xmmword ptr [esi] + movlps xmm6, qword ptr [esi+24] + movhps xmm6, qword ptr [esi+32] + movaps xmm7, xmmword ptr [esi+48] + movss xmm0, dword ptr [edi] + shufps xmm0, xmm0, 0 + mulps xmm0, xmm5 + movss xmm1, dword ptr [edi+4] + shufps xmm1, xmm1, 0 + mulps xmm1, xmm6 + movss xmm2, dword ptr [edi+8] + shufps xmm2, xmm2, 0 + mulps xmm2, xmm7 + addps xmm0, xmm1 + addps xmm0, xmm2 + movaps xmmword ptr [eax], xmm0 + movss xmm3, dword ptr [edi+12] + shufps xmm3, xmm3, 0 + mulps xmm3, xmm5 + movss xmm4, dword ptr [edi+16] + shufps xmm4, xmm4, 0 + mulps xmm4, xmm6 + movss xmm0, dword ptr [edi+20] + shufps xmm0, xmm0, 0 + mulps xmm0, xmm7 + addps xmm3, xmm4 + addps xmm0, xmm3 + movlps qword ptr [eax+24], xmm0 + movhps qword ptr [eax+32], xmm0 + movss xmm1, dword ptr [edi+24] + shufps xmm1, xmm1, 0 + mulps xmm1, xmm5 + movss xmm2, dword ptr [edi+28] + shufps xmm2, xmm2, 0 + mulps xmm2, xmm6 + movss xmm3, dword ptr [edi+32] + shufps xmm3, xmm3, 0 + mulps xmm3, xmm7 + addps xmm1, xmm2 + addps xmm1, xmm3 + movaps xmmword ptr [eax+48], xmm1 + movlps xmm5, qword ptr [esi+16] + movlps xmm6, qword ptr [esi+40] + movlps xmm7, qword ptr [esi+64] + shufps xmm5, xmm5, 0x44 + shufps xmm6, xmm6, 0x44 + shufps xmm7, xmm7, 0x44 + movaps xmm3, xmmword ptr [edi] + movlps xmm4, qword ptr [edi+16] + movaps xmm0, xmm3 + shufps xmm0, xmm0, 0xF0 + mulps xmm0, xmm5 + movaps xmm1, xmm3 + shufps xmm1, xmm4, 0x05 + mulps xmm1, xmm6 + shufps xmm3, xmm4, 0x5A + mulps xmm3, xmm7 + addps xmm1, xmm0 + addps xmm1, xmm3 + movlps qword ptr [eax+16], xmm1 + movhps qword ptr [eax+40], xmm1 + movss xmm0, dword ptr [edi+24] + shufps xmm0, xmm0, 0 + mulps xmm0, xmm5 + movss xmm2, dword ptr [edi+28] + shufps xmm2, xmm2, 0 + mulps xmm2, xmm6 + movss xmm4, dword ptr [edi+32] + shufps xmm4, xmm4, 0 + mulps xmm4, xmm7 + addps xmm0, xmm2 + addps xmm0, xmm4 + movlps qword ptr [eax+64], xmm0 + } + return; + } + case 6: { // 6x3 * 3x6 +#define MUL_Nx3_3x6_FIRST4COLUMNS_INIT \ + __asm mov esi, m2Ptr \ + __asm mov edi, m1Ptr \ + __asm mov eax, dstPtr \ + __asm movlps xmm0, [esi+ 0*4] \ + __asm movhps xmm0, [esi+ 2*4] \ + __asm movlps xmm1, [esi+ 6*4] \ + __asm movhps xmm1, [esi+ 8*4] \ + __asm movlps xmm2, [esi+12*4] \ + __asm movhps xmm2, [esi+14*4] + +#define MUL_Nx3_3x6_FIRST4COLUMNS_ROW( row ) \ + __asm movss xmm3, [edi+(row*3+0)*4] \ + __asm shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm3, xmm0 \ + __asm movss xmm4, [edi+(row*3+1)*4] \ + __asm shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm4, xmm1 \ + __asm addps xmm3, xmm4 \ + __asm movss xmm5, [edi+(row*3+2)*4] \ + __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm5, xmm2 \ + __asm addps xmm3, xmm5 \ + __asm movlps [eax+(row*6+0)*4], xmm3 \ + __asm movhps [eax+(row*6+2)*4], xmm3 + +#define MUL_Nx3_3x6_LAST2COLUMNS_ROW6 \ + __asm movlps xmm0, [esi+ 4*4] \ + __asm movlps xmm1, [esi+10*4] \ + __asm movlps xmm2, [esi+16*4] \ + __asm shufps xmm0, xmm0, 0x44 \ + __asm shufps xmm1, xmm1, 0x44 \ + __asm shufps xmm2, xmm2, 0x44 \ + __asm movlps xmm3, [edi+0*4] \ + __asm movhps xmm3, [edi+2*4] \ + __asm movaps xmm4, xmm3 \ + __asm movaps xmm5, xmm3 \ + __asm shufps xmm3, xmm3, 0xF0 \ + __asm mulps xmm3, xmm0 \ + __asm movlps xmm6, [edi+4*4] \ + __asm movhps xmm6, [edi+6*4] \ + __asm shufps xmm4, xmm6, 0x05 \ + __asm mulps xmm4, xmm1 \ + __asm addps xmm3, xmm4 \ + __asm shufps xmm5, xmm6, 0x5A \ + __asm mulps xmm5, xmm2 \ + __asm addps xmm3, xmm5 \ + __asm movlps [eax+4*4], xmm3 \ + __asm movhps [eax+10*4], xmm3 \ + __asm movaps xmm5, xmm6 \ + __asm movlps xmm3, [edi+8*4] \ + __asm movhps xmm3, [edi+10*4] \ + __asm movaps xmm4, xmm3 \ + __asm shufps xmm5, xmm3, 0x5A \ + __asm mulps xmm5, xmm0 \ + __asm shufps xmm6, xmm3, 0xAF \ + __asm mulps xmm6, xmm1 \ + __asm addps xmm5, xmm6 \ + __asm shufps xmm4, xmm4, 0xF0 \ + __asm mulps xmm4, xmm2 \ + __asm addps xmm4, xmm5 \ + __asm movlps [eax+16*4], xmm4 \ + __asm movhps [eax+22*4], xmm4 \ + __asm movlps xmm6, [edi+12*4] \ + __asm movhps xmm6, [edi+14*4] \ + __asm movaps xmm5, xmm6 \ + __asm movaps xmm4, xmm6 \ + __asm shufps xmm6, xmm6, 0xF0 \ + __asm mulps xmm6, xmm0 \ + __asm movlps xmm3, [edi+16*4] \ + __asm shufps xmm5, xmm3, 0x05 \ + __asm mulps xmm5, xmm1 \ + __asm addps xmm5, xmm6 \ + __asm shufps xmm4, xmm3, 0x5A \ + __asm mulps xmm4, xmm2 \ + __asm addps xmm4, xmm5 \ + __asm movlps [eax+28*4], xmm4 \ + __asm movhps [eax+34*4], xmm4 + + MUL_Nx3_3x6_FIRST4COLUMNS_INIT + MUL_Nx3_3x6_FIRST4COLUMNS_ROW( 0 ) + MUL_Nx3_3x6_FIRST4COLUMNS_ROW( 1 ) + MUL_Nx3_3x6_FIRST4COLUMNS_ROW( 2 ) + MUL_Nx3_3x6_FIRST4COLUMNS_ROW( 3 ) + MUL_Nx3_3x6_FIRST4COLUMNS_ROW( 4 ) + MUL_Nx3_3x6_FIRST4COLUMNS_ROW( 5 ) + MUL_Nx3_3x6_LAST2COLUMNS_ROW6 + + return; + } + } + } + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2 * l]; + m2Ptr++; + } + m1Ptr += 3; + } + break; + } + case 4: { + if ( !( l ^ 6 ) ) { + switch ( k ) { + case 4: { // 4x4 * 4x6 + +#define MUL_Nx4_4x6_FIRST4COLUMNS_INIT \ + __asm mov esi, m2Ptr \ + __asm mov edi, m1Ptr \ + __asm mov eax, dstPtr \ + __asm movlps xmm0, [esi+ 0*4] \ + __asm movhps xmm0, [esi+ 2*4] \ + __asm movlps xmm1, [esi+ 6*4] \ + __asm movhps xmm1, [esi+ 8*4] \ + __asm movlps xmm2, [esi+12*4] \ + __asm movhps xmm2, [esi+14*4] \ + __asm movlps xmm3, [esi+18*4] \ + __asm movhps xmm3, [esi+20*4] + +#define MUL_Nx4_4x6_FIRST4COLUMNS_ROW( row ) \ + __asm movss xmm4, [edi+row*16+0*4] \ + __asm shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm4, xmm0 \ + __asm movss xmm5, [edi+row*16+1*4] \ + __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm5, xmm1 \ + __asm addps xmm4, xmm5 \ + __asm movss xmm6, [edi+row*16+2*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm2 \ + __asm addps xmm4, xmm6 \ + __asm movss xmm7, [edi+row*16+3*4] \ + __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm7, xmm3 \ + __asm addps xmm4, xmm7 \ + __asm movlps [eax+row*24+0], xmm4 \ + __asm movhps [eax+row*24+8], xmm4 + +#define MUL_Nx4_4x6_LAST2COLUMNS_INIT \ + __asm movlps xmm0, [esi+ 4*4] \ + __asm movlps xmm1, [esi+10*4] \ + __asm movlps xmm2, [esi+16*4] \ + __asm movlps xmm3, [esi+22*4] \ + __asm shufps xmm0, xmm1, R_SHUFFLEPS( 0, 1, 0, 1 ) \ + __asm shufps xmm1, xmm0, R_SHUFFLEPS( 0, 1, 0, 1 ) \ + __asm shufps xmm2, xmm3, R_SHUFFLEPS( 0, 1, 0, 1 ) \ + __asm shufps xmm3, xmm2, R_SHUFFLEPS( 0, 1, 0, 1 ) + +#define MUL_Nx4_4x6_LAST2COLUMNS_ROW2( row ) \ + __asm movlps xmm7, [edi+row*32+ 0*4] \ + __asm movhps xmm7, [edi+row*32+ 4*4] \ + __asm movaps xmm6, xmm7 \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 3, 3 ) \ + __asm mulps xmm6, xmm0 \ + __asm shufps xmm7, xmm7, R_SHUFFLEPS( 1, 1, 2, 2 ) \ + __asm mulps xmm7, xmm1 \ + __asm addps xmm6, xmm7 \ + __asm movlps xmm4, [edi+row*32+ 2*4] \ + __asm movhps xmm4, [edi+row*32+ 6*4] \ + __asm movaps xmm5, xmm4 \ + __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 3, 3 ) \ + __asm mulps xmm5, xmm2 \ + __asm addps xmm6, xmm5 \ + __asm shufps xmm4, xmm4, R_SHUFFLEPS( 1, 1, 2, 2 ) \ + __asm mulps xmm4, xmm3 \ + __asm addps xmm6, xmm4 \ + __asm movlps [eax+row*48+ 4*4], xmm6 \ + __asm movhps [eax+row*48+10*4], xmm6 + + MUL_Nx4_4x6_FIRST4COLUMNS_INIT + MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 0 ) + MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 1 ) + MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 2 ) + MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 3 ) + MUL_Nx4_4x6_LAST2COLUMNS_INIT + MUL_Nx4_4x6_LAST2COLUMNS_ROW2( 0 ) + MUL_Nx4_4x6_LAST2COLUMNS_ROW2( 1 ) + + return; + } + case 6: { // 6x4 * 4x6 + + MUL_Nx4_4x6_FIRST4COLUMNS_INIT + MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 0 ) + MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 1 ) + MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 2 ) + MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 3 ) + MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 4 ) + MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 5 ) + MUL_Nx4_4x6_LAST2COLUMNS_INIT + MUL_Nx4_4x6_LAST2COLUMNS_ROW2( 0 ) + MUL_Nx4_4x6_LAST2COLUMNS_ROW2( 1 ) + MUL_Nx4_4x6_LAST2COLUMNS_ROW2( 2 ) + + return; + } + } + } + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2 * l] + + m1Ptr[3] * m2Ptr[3 * l]; + m2Ptr++; + } + m1Ptr += 4; + } + break; + } + case 5: { + if ( !( l ^ 6 ) ) { + switch ( k ) { + case 5: { // 5x5 * 5x6 + +#define MUL_Nx5_5x6_FIRST4COLUMNS_INIT \ + __asm mov esi, m2Ptr \ + __asm mov edi, m1Ptr \ + __asm mov eax, dstPtr \ + __asm movlps xmm0, [esi+ 0*4] \ + __asm movhps xmm0, [esi+ 2*4] \ + __asm movlps xmm1, [esi+ 6*4] \ + __asm movhps xmm1, [esi+ 8*4] \ + __asm movlps xmm2, [esi+12*4] \ + __asm movhps xmm2, [esi+14*4] \ + __asm movlps xmm3, [esi+18*4] \ + __asm movhps xmm3, [esi+20*4] \ + __asm movlps xmm4, [esi+24*4] \ + __asm movhps xmm4, [esi+26*4] + +#define MUL_Nx5_5x6_FIRST4COLUMNS_ROW( row ) \ + __asm movss xmm6, [edi+row*20+0*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm0 \ + __asm movss xmm5, [edi+row*20+1*4] \ + __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm5, xmm1 \ + __asm addps xmm6, xmm5 \ + __asm movss xmm5, [edi+row*20+2*4] \ + __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm5, xmm2 \ + __asm addps xmm6, xmm5 \ + __asm movss xmm5, [edi+row*20+3*4] \ + __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm5, xmm3 \ + __asm addps xmm6, xmm5 \ + __asm movss xmm5, [edi+row*20+4*4] \ + __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm5, xmm4 \ + __asm addps xmm6, xmm5 \ + __asm movlps [eax+row*24+0], xmm6 \ + __asm movhps [eax+row*24+8], xmm6 + +#define MUL_Nx5_5x6_LAST2COLUMNS_INIT \ + __asm movlps xmm0, [esi+ 4*4] \ + __asm movlps xmm1, [esi+10*4] \ + __asm movlps xmm2, [esi+16*4] \ + __asm movlps xmm3, [esi+22*4] \ + __asm movlps xmm4, [esi+28*4] \ + __asm shufps xmm0, xmm1, R_SHUFFLEPS( 0, 1, 0, 1 ) \ + __asm shufps xmm1, xmm2, R_SHUFFLEPS( 0, 1, 0, 1 ) \ + __asm shufps xmm2, xmm3, R_SHUFFLEPS( 0, 1, 0, 1 ) \ + __asm shufps xmm3, xmm4, R_SHUFFLEPS( 0, 1, 0, 1 ) \ + __asm shufps xmm4, xmm0, R_SHUFFLEPS( 0, 1, 0, 1 ) + +#define MUL_Nx5_5x6_LAST2COLUMNS_ROW2( row ) \ + __asm movlps xmm7, [edi+row*40+ 0*4] \ + __asm movhps xmm7, [edi+row*40+ 6*4] \ + __asm movaps xmm6, xmm7 \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 2, 2 ) \ + __asm mulps xmm6, xmm0 \ + __asm movaps xmm5, xmm7 \ + __asm shufps xmm5, xmm5, R_SHUFFLEPS( 1, 1, 3, 3 ) \ + __asm mulps xmm5, xmm1 \ + __asm addps xmm6, xmm5 \ + __asm movlps xmm7, [edi+row*40+ 2*4] \ + __asm movhps xmm7, [edi+row*40+ 8*4] \ + __asm movaps xmm5, xmm7 \ + __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 2, 2 ) \ + __asm mulps xmm5, xmm2 \ + __asm addps xmm6, xmm5 \ + __asm movaps xmm5, xmm7 \ + __asm shufps xmm5, xmm5, R_SHUFFLEPS( 1, 1, 3, 3 ) \ + __asm mulps xmm5, xmm3 \ + __asm addps xmm6, xmm5 \ + __asm movlps xmm5, [edi+row*40+ 4*4] \ + __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 1, 1 ) \ + __asm mulps xmm5, xmm4 \ + __asm addps xmm6, xmm5 \ + __asm movlps [eax+row*48+ 4*4], xmm6 \ + __asm movhps [eax+row*48+10*4], xmm6 + +#define MUL_Nx5_5x6_LAST2COLUMNS_ROW( row ) \ + __asm movlps xmm6, [edi+20*4+0*4] \ + __asm unpcklps xmm6, xmm6 \ + __asm mulps xmm6, xmm0 \ + __asm movlps xmm5, [edi+20*4+2*4] \ + __asm unpcklps xmm5, xmm5 \ + __asm mulps xmm5, xmm2 \ + __asm addps xmm6, xmm5 \ + __asm movss xmm5, [edi+20*4+4*4] \ + __asm unpcklps xmm5, xmm5 \ + __asm mulps xmm5, xmm4 \ + __asm addps xmm6, xmm5 \ + __asm movhlps xmm7, xmm6 \ + __asm addps xmm6, xmm7 \ + __asm movlps [eax+row*24+4*4], xmm6 + + MUL_Nx5_5x6_FIRST4COLUMNS_INIT + MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 0 ) + MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 1 ) + MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 2 ) + MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 3 ) + MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 4 ) + MUL_Nx5_5x6_LAST2COLUMNS_INIT + MUL_Nx5_5x6_LAST2COLUMNS_ROW2( 0 ) + MUL_Nx5_5x6_LAST2COLUMNS_ROW2( 1 ) + MUL_Nx5_5x6_LAST2COLUMNS_ROW( 4 ) + + return; + } + case 6: { // 6x5 * 5x6 + + MUL_Nx5_5x6_FIRST4COLUMNS_INIT + MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 0 ) + MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 1 ) + MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 2 ) + MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 3 ) + MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 4 ) + MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 5 ) + MUL_Nx5_5x6_LAST2COLUMNS_INIT + MUL_Nx5_5x6_LAST2COLUMNS_ROW2( 0 ) + MUL_Nx5_5x6_LAST2COLUMNS_ROW2( 1 ) + MUL_Nx5_5x6_LAST2COLUMNS_ROW2( 2 ) + + return; } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0]; - m2Ptr++; - } - m1Ptr++; + } + } + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2 * l] + + m1Ptr[3] * m2Ptr[3 * l] + m1Ptr[4] * m2Ptr[4 * l]; + m2Ptr++; + } + m1Ptr += 5; + } + break; + } + case 6: { + switch ( k ) { + case 1: { + if ( !( l ^ 1 ) ) { // 1x6 * 6x1 + dstPtr[0] = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[1] + m1Ptr[2] * m2Ptr[2] + + m1Ptr[3] * m2Ptr[3] + m1Ptr[4] * m2Ptr[4] + m1Ptr[5] * m2Ptr[5]; + return; } break; } case 2: { - if ( !(l^6) ) { - switch( k ) { - case 2: { // 2x2 * 2x6 - - #define MUL_Nx2_2x6_INIT \ - __asm mov esi, m2Ptr \ - __asm mov edi, m1Ptr \ - __asm mov eax, dstPtr \ - __asm movaps xmm0, [esi] \ - __asm movlps xmm1, [esi+16] \ - __asm movhps xmm1, [esi+40] \ - __asm movlps xmm2, [esi+24] \ - __asm movhps xmm2, [esi+32] - - #define MUL_Nx2_2x6_ROW2( row ) \ - __asm movaps xmm3, [edi+row*16] \ - __asm movaps xmm5, xmm0 \ - __asm movaps xmm4, xmm3 \ - __asm shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm5, xmm4 \ - __asm movaps xmm4, xmm3 \ - __asm movaps xmm6, xmm2 \ - __asm shufps xmm4, xmm4, R_SHUFFLEPS( 1, 1, 1, 1 ) \ - __asm mulps xmm6, xmm4 \ - __asm addps xmm5, xmm6 \ - __asm movaps [eax+row*48], xmm5 \ - __asm movaps xmm4, xmm3 \ - __asm shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 1, 1 ) \ - __asm movaps xmm7, xmm1 \ - __asm mulps xmm7, xmm4 \ - __asm movaps xmm4, xmm3 \ - __asm movaps xmm5, xmm0 \ - __asm shufps xmm4, xmm4, R_SHUFFLEPS( 2, 2, 2, 2 ) \ - __asm mulps xmm5, xmm4 \ - __asm movaps xmm4, xmm3 \ - __asm movaps xmm6, xmm2 \ - __asm shufps xmm4, xmm4, R_SHUFFLEPS( 3, 3, 3, 3 ) \ - __asm mulps xmm6, xmm4 \ - __asm addps xmm5, xmm6 \ - __asm shufps xmm3, xmm3, R_SHUFFLEPS( 2, 2, 3, 3 ) \ - __asm movaps xmm6, xmm1 \ - __asm mulps xmm6, xmm3 \ - __asm movaps xmm4, xmm7 \ - __asm movlhps xmm7, xmm6 \ - __asm movhlps xmm6, xmm4 \ - __asm addps xmm6, xmm7 \ - __asm movlps [eax+row*48+16], xmm6 \ - __asm movlps [eax+row*48+24], xmm5 \ - __asm movhps [eax+row*48+32], xmm5 \ - __asm movhps [eax+row*48+40], xmm6 - - MUL_Nx2_2x6_INIT - MUL_Nx2_2x6_ROW2( 0 ) - - return; - } - case 6: { // 6x2 * 2x6 - - MUL_Nx2_2x6_INIT - MUL_Nx2_2x6_ROW2( 0 ) - MUL_Nx2_2x6_ROW2( 1 ) - MUL_Nx2_2x6_ROW2( 2 ) - - return; - } - } - } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l]; - m2Ptr++; - } - m1Ptr += 2; + if ( !( l ^ 2 ) ) { // 2x6 * 6x2 + +#define MUL_Nx6_6x2_INIT \ + __asm mov esi, m2Ptr \ + __asm mov edi, m1Ptr \ + __asm mov eax, dstPtr \ + __asm movaps xmm0, [esi] \ + __asm movaps xmm1, [esi+16] \ + __asm movaps xmm2, [esi+32] + +#define MUL_Nx6_6x2_ROW2( row ) \ + __asm movaps xmm7, [edi+row*48+0*4] \ + __asm movaps xmm6, xmm7 \ + __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 1, 1 ) \ + __asm mulps xmm7, xmm0 \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 2, 2, 3, 3 ) \ + __asm mulps xmm6, xmm1 \ + __asm addps xmm7, xmm6 \ + __asm movaps xmm6, [edi+row*48+4*4] \ + __asm movaps xmm5, xmm6 \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 1, 1 ) \ + __asm mulps xmm6, xmm2 \ + __asm addps xmm7, xmm6 \ + __asm shufps xmm5, xmm5, R_SHUFFLEPS( 2, 2, 3, 3 ) \ + __asm mulps xmm5, xmm0 \ + __asm movaps xmm6, [edi+row*48+24+2*4] \ + __asm movaps xmm4, xmm6 \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 1, 1 ) \ + __asm mulps xmm6, xmm1 \ + __asm addps xmm5, xmm6 \ + __asm shufps xmm4, xmm4, R_SHUFFLEPS( 2, 2, 3, 3 ) \ + __asm mulps xmm4, xmm2 \ + __asm addps xmm5, xmm4 \ + __asm movaps xmm4, xmm5 \ + __asm movhlps xmm5, xmm7 \ + __asm movlhps xmm7, xmm4 \ + __asm addps xmm7, xmm5 \ + __asm movaps [eax+row*16], xmm7 + + MUL_Nx6_6x2_INIT + MUL_Nx6_6x2_ROW2( 0 ) + + return; } break; } case 3: { - if ( !(l^6) ) { - switch( k ) { - case 3: { // 3x3 * 3x6 - __asm { - mov esi, m2Ptr - mov edi, m1Ptr - mov eax, dstPtr - movaps xmm5, xmmword ptr [esi] - movlps xmm6, qword ptr [esi+24] - movhps xmm6, qword ptr [esi+32] - movaps xmm7, xmmword ptr [esi+48] - movss xmm0, dword ptr [edi] - shufps xmm0, xmm0, 0 - mulps xmm0, xmm5 - movss xmm1, dword ptr [edi+4] - shufps xmm1, xmm1, 0 - mulps xmm1, xmm6 - movss xmm2, dword ptr [edi+8] - shufps xmm2, xmm2, 0 - mulps xmm2, xmm7 - addps xmm0, xmm1 - addps xmm0, xmm2 - movaps xmmword ptr [eax], xmm0 - movss xmm3, dword ptr [edi+12] - shufps xmm3, xmm3, 0 - mulps xmm3, xmm5 - movss xmm4, dword ptr [edi+16] - shufps xmm4, xmm4, 0 - mulps xmm4, xmm6 - movss xmm0, dword ptr [edi+20] - shufps xmm0, xmm0, 0 - mulps xmm0, xmm7 - addps xmm3, xmm4 - addps xmm0, xmm3 - movlps qword ptr [eax+24], xmm0 - movhps qword ptr [eax+32], xmm0 - movss xmm1, dword ptr [edi+24] - shufps xmm1, xmm1, 0 - mulps xmm1, xmm5 - movss xmm2, dword ptr [edi+28] - shufps xmm2, xmm2, 0 - mulps xmm2, xmm6 - movss xmm3, dword ptr [edi+32] - shufps xmm3, xmm3, 0 - mulps xmm3, xmm7 - addps xmm1, xmm2 - addps xmm1, xmm3 - movaps xmmword ptr [eax+48], xmm1 - movlps xmm5, qword ptr [esi+16] - movlps xmm6, qword ptr [esi+40] - movlps xmm7, qword ptr [esi+64] - shufps xmm5, xmm5, 0x44 - shufps xmm6, xmm6, 0x44 - shufps xmm7, xmm7, 0x44 - movaps xmm3, xmmword ptr [edi] - movlps xmm4, qword ptr [edi+16] - movaps xmm0, xmm3 - shufps xmm0, xmm0, 0xF0 - mulps xmm0, xmm5 - movaps xmm1, xmm3 - shufps xmm1, xmm4, 0x05 - mulps xmm1, xmm6 - shufps xmm3, xmm4, 0x5A - mulps xmm3, xmm7 - addps xmm1, xmm0 - addps xmm1, xmm3 - movlps qword ptr [eax+16], xmm1 - movhps qword ptr [eax+40], xmm1 - movss xmm0, dword ptr [edi+24] - shufps xmm0, xmm0, 0 - mulps xmm0, xmm5 - movss xmm2, dword ptr [edi+28] - shufps xmm2, xmm2, 0 - mulps xmm2, xmm6 - movss xmm4, dword ptr [edi+32] - shufps xmm4, xmm4, 0 - mulps xmm4, xmm7 - addps xmm0, xmm2 - addps xmm0, xmm4 - movlps qword ptr [eax+64], xmm0 - } - return; - } - case 6: { // 6x3 * 3x6 - #define MUL_Nx3_3x6_FIRST4COLUMNS_INIT \ - __asm mov esi, m2Ptr \ - __asm mov edi, m1Ptr \ - __asm mov eax, dstPtr \ - __asm movlps xmm0, [esi+ 0*4] \ - __asm movhps xmm0, [esi+ 2*4] \ - __asm movlps xmm1, [esi+ 6*4] \ - __asm movhps xmm1, [esi+ 8*4] \ - __asm movlps xmm2, [esi+12*4] \ - __asm movhps xmm2, [esi+14*4] - - #define MUL_Nx3_3x6_FIRST4COLUMNS_ROW( row ) \ - __asm movss xmm3, [edi+(row*3+0)*4] \ - __asm shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm3, xmm0 \ - __asm movss xmm4, [edi+(row*3+1)*4] \ - __asm shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm4, xmm1 \ - __asm addps xmm3, xmm4 \ - __asm movss xmm5, [edi+(row*3+2)*4] \ - __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm5, xmm2 \ - __asm addps xmm3, xmm5 \ - __asm movlps [eax+(row*6+0)*4], xmm3 \ - __asm movhps [eax+(row*6+2)*4], xmm3 - - #define MUL_Nx3_3x6_LAST2COLUMNS_ROW6 \ - __asm movlps xmm0, [esi+ 4*4] \ - __asm movlps xmm1, [esi+10*4] \ - __asm movlps xmm2, [esi+16*4] \ - __asm shufps xmm0, xmm0, 0x44 \ - __asm shufps xmm1, xmm1, 0x44 \ - __asm shufps xmm2, xmm2, 0x44 \ - __asm movlps xmm3, [edi+0*4] \ - __asm movhps xmm3, [edi+2*4] \ - __asm movaps xmm4, xmm3 \ - __asm movaps xmm5, xmm3 \ - __asm shufps xmm3, xmm3, 0xF0 \ - __asm mulps xmm3, xmm0 \ - __asm movlps xmm6, [edi+4*4] \ - __asm movhps xmm6, [edi+6*4] \ - __asm shufps xmm4, xmm6, 0x05 \ - __asm mulps xmm4, xmm1 \ - __asm addps xmm3, xmm4 \ - __asm shufps xmm5, xmm6, 0x5A \ - __asm mulps xmm5, xmm2 \ - __asm addps xmm3, xmm5 \ - __asm movlps [eax+4*4], xmm3 \ - __asm movhps [eax+10*4], xmm3 \ - __asm movaps xmm5, xmm6 \ - __asm movlps xmm3, [edi+8*4] \ - __asm movhps xmm3, [edi+10*4] \ - __asm movaps xmm4, xmm3 \ - __asm shufps xmm5, xmm3, 0x5A \ - __asm mulps xmm5, xmm0 \ - __asm shufps xmm6, xmm3, 0xAF \ - __asm mulps xmm6, xmm1 \ - __asm addps xmm5, xmm6 \ - __asm shufps xmm4, xmm4, 0xF0 \ - __asm mulps xmm4, xmm2 \ - __asm addps xmm4, xmm5 \ - __asm movlps [eax+16*4], xmm4 \ - __asm movhps [eax+22*4], xmm4 \ - __asm movlps xmm6, [edi+12*4] \ - __asm movhps xmm6, [edi+14*4] \ - __asm movaps xmm5, xmm6 \ - __asm movaps xmm4, xmm6 \ - __asm shufps xmm6, xmm6, 0xF0 \ - __asm mulps xmm6, xmm0 \ - __asm movlps xmm3, [edi+16*4] \ - __asm shufps xmm5, xmm3, 0x05 \ - __asm mulps xmm5, xmm1 \ - __asm addps xmm5, xmm6 \ - __asm shufps xmm4, xmm3, 0x5A \ - __asm mulps xmm4, xmm2 \ - __asm addps xmm4, xmm5 \ - __asm movlps [eax+28*4], xmm4 \ - __asm movhps [eax+34*4], xmm4 - - MUL_Nx3_3x6_FIRST4COLUMNS_INIT - MUL_Nx3_3x6_FIRST4COLUMNS_ROW( 0 ) - MUL_Nx3_3x6_FIRST4COLUMNS_ROW( 1 ) - MUL_Nx3_3x6_FIRST4COLUMNS_ROW( 2 ) - MUL_Nx3_3x6_FIRST4COLUMNS_ROW( 3 ) - MUL_Nx3_3x6_FIRST4COLUMNS_ROW( 4 ) - MUL_Nx3_3x6_FIRST4COLUMNS_ROW( 5 ) - MUL_Nx3_3x6_LAST2COLUMNS_ROW6 - - return; - } - } - } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2*l]; - m2Ptr++; - } - m1Ptr += 3; + if ( !( l ^ 3 ) ) { // 3x6 * 6x3 + +#define MUL_Nx6_6x3_INIT \ + __asm mov esi, m2Ptr \ + __asm mov edi, m1Ptr \ + __asm mov eax, dstPtr \ + __asm movss xmm0, [esi+ 0*4] \ + __asm movhps xmm0, [esi+ 1*4] \ + __asm movss xmm1, [esi+ 3*4] \ + __asm movhps xmm1, [esi+ 4*4] \ + __asm movss xmm2, [esi+ 6*4] \ + __asm movhps xmm2, [esi+ 7*4] \ + __asm movss xmm3, [esi+ 9*4] \ + __asm movhps xmm3, [esi+10*4] \ + __asm movss xmm4, [esi+12*4] \ + __asm movhps xmm4, [esi+13*4] \ + __asm movss xmm5, [esi+15*4] \ + __asm movhps xmm5, [esi+16*4] + +#define MUL_Nx6_6x3_ROW( row ) \ + __asm movss xmm7, [edi+row*24+0] \ + __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm7, xmm0 \ + __asm movss xmm6, [edi+row*24+4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm1 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+row*24+8] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm2 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+row*24+12] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm3 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+row*24+16] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm4 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+row*24+20] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm5 \ + __asm addps xmm7, xmm6 \ + __asm movss [eax+row*12+0], xmm7 \ + __asm movhps [eax+row*12+4], xmm7 + + MUL_Nx6_6x3_INIT + MUL_Nx6_6x3_ROW( 0 ) + MUL_Nx6_6x3_ROW( 1 ) + MUL_Nx6_6x3_ROW( 2 ) + + return; } break; } case 4: { - if ( !(l^6) ) { - switch( k ) { - case 4: { // 4x4 * 4x6 - - #define MUL_Nx4_4x6_FIRST4COLUMNS_INIT \ - __asm mov esi, m2Ptr \ - __asm mov edi, m1Ptr \ - __asm mov eax, dstPtr \ - __asm movlps xmm0, [esi+ 0*4] \ - __asm movhps xmm0, [esi+ 2*4] \ - __asm movlps xmm1, [esi+ 6*4] \ - __asm movhps xmm1, [esi+ 8*4] \ - __asm movlps xmm2, [esi+12*4] \ - __asm movhps xmm2, [esi+14*4] \ - __asm movlps xmm3, [esi+18*4] \ - __asm movhps xmm3, [esi+20*4] - - #define MUL_Nx4_4x6_FIRST4COLUMNS_ROW( row ) \ - __asm movss xmm4, [edi+row*16+0*4] \ - __asm shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm4, xmm0 \ - __asm movss xmm5, [edi+row*16+1*4] \ - __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm5, xmm1 \ - __asm addps xmm4, xmm5 \ - __asm movss xmm6, [edi+row*16+2*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm2 \ - __asm addps xmm4, xmm6 \ - __asm movss xmm7, [edi+row*16+3*4] \ - __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm7, xmm3 \ - __asm addps xmm4, xmm7 \ - __asm movlps [eax+row*24+0], xmm4 \ - __asm movhps [eax+row*24+8], xmm4 - - #define MUL_Nx4_4x6_LAST2COLUMNS_INIT \ - __asm movlps xmm0, [esi+ 4*4] \ - __asm movlps xmm1, [esi+10*4] \ - __asm movlps xmm2, [esi+16*4] \ - __asm movlps xmm3, [esi+22*4] \ - __asm shufps xmm0, xmm1, R_SHUFFLEPS( 0, 1, 0, 1 ) \ - __asm shufps xmm1, xmm0, R_SHUFFLEPS( 0, 1, 0, 1 ) \ - __asm shufps xmm2, xmm3, R_SHUFFLEPS( 0, 1, 0, 1 ) \ - __asm shufps xmm3, xmm2, R_SHUFFLEPS( 0, 1, 0, 1 ) - - #define MUL_Nx4_4x6_LAST2COLUMNS_ROW2( row ) \ - __asm movlps xmm7, [edi+row*32+ 0*4] \ - __asm movhps xmm7, [edi+row*32+ 4*4] \ - __asm movaps xmm6, xmm7 \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 3, 3 ) \ - __asm mulps xmm6, xmm0 \ - __asm shufps xmm7, xmm7, R_SHUFFLEPS( 1, 1, 2, 2 ) \ - __asm mulps xmm7, xmm1 \ - __asm addps xmm6, xmm7 \ - __asm movlps xmm4, [edi+row*32+ 2*4] \ - __asm movhps xmm4, [edi+row*32+ 6*4] \ - __asm movaps xmm5, xmm4 \ - __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 3, 3 ) \ - __asm mulps xmm5, xmm2 \ - __asm addps xmm6, xmm5 \ - __asm shufps xmm4, xmm4, R_SHUFFLEPS( 1, 1, 2, 2 ) \ - __asm mulps xmm4, xmm3 \ - __asm addps xmm6, xmm4 \ - __asm movlps [eax+row*48+ 4*4], xmm6 \ - __asm movhps [eax+row*48+10*4], xmm6 - - MUL_Nx4_4x6_FIRST4COLUMNS_INIT - MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 0 ) - MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 1 ) - MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 2 ) - MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 3 ) - MUL_Nx4_4x6_LAST2COLUMNS_INIT - MUL_Nx4_4x6_LAST2COLUMNS_ROW2( 0 ) - MUL_Nx4_4x6_LAST2COLUMNS_ROW2( 1 ) - - return; - } - case 6: { // 6x4 * 4x6 - - MUL_Nx4_4x6_FIRST4COLUMNS_INIT - MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 0 ) - MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 1 ) - MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 2 ) - MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 3 ) - MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 4 ) - MUL_Nx4_4x6_FIRST4COLUMNS_ROW( 5 ) - MUL_Nx4_4x6_LAST2COLUMNS_INIT - MUL_Nx4_4x6_LAST2COLUMNS_ROW2( 0 ) - MUL_Nx4_4x6_LAST2COLUMNS_ROW2( 1 ) - MUL_Nx4_4x6_LAST2COLUMNS_ROW2( 2 ) - - return; - } - } - } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2*l] + - m1Ptr[3] * m2Ptr[3*l]; - m2Ptr++; - } - m1Ptr += 4; + if ( !( l ^ 4 ) ) { // 4x6 * 6x4 + +#define MUL_Nx6_6x4_INIT \ + __asm mov esi, m2Ptr \ + __asm mov edi, m1Ptr \ + __asm mov eax, dstPtr \ + __asm movaps xmm0, [esi] \ + __asm movaps xmm1, [esi+16] \ + __asm movaps xmm2, [esi+32] \ + __asm movaps xmm3, [esi+48] \ + __asm movaps xmm4, [esi+64] \ + __asm movaps xmm5, [esi+80] + +#define MUL_Nx6_6x4_ROW( row ) \ + __asm movss xmm7, [edi+row*24+0] \ + __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm7, xmm0 \ + __asm movss xmm6, [edi+row*24+4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm1 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+row*24+8] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm2 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+row*24+12] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm3 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+row*24+16] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm4 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+row*24+20] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm5 \ + __asm addps xmm7, xmm6 \ + __asm movaps [eax+row*16], xmm7 + + MUL_Nx6_6x4_INIT + MUL_Nx6_6x4_ROW( 0 ) + MUL_Nx6_6x4_ROW( 1 ) + MUL_Nx6_6x4_ROW( 2 ) + MUL_Nx6_6x4_ROW( 3 ) + + return; } break; } case 5: { - if ( !(l^6) ) { - switch( k ) { - case 5: { // 5x5 * 5x6 - - #define MUL_Nx5_5x6_FIRST4COLUMNS_INIT \ - __asm mov esi, m2Ptr \ - __asm mov edi, m1Ptr \ - __asm mov eax, dstPtr \ - __asm movlps xmm0, [esi+ 0*4] \ - __asm movhps xmm0, [esi+ 2*4] \ - __asm movlps xmm1, [esi+ 6*4] \ - __asm movhps xmm1, [esi+ 8*4] \ - __asm movlps xmm2, [esi+12*4] \ - __asm movhps xmm2, [esi+14*4] \ - __asm movlps xmm3, [esi+18*4] \ - __asm movhps xmm3, [esi+20*4] \ - __asm movlps xmm4, [esi+24*4] \ - __asm movhps xmm4, [esi+26*4] - - #define MUL_Nx5_5x6_FIRST4COLUMNS_ROW( row ) \ - __asm movss xmm6, [edi+row*20+0*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm0 \ - __asm movss xmm5, [edi+row*20+1*4] \ - __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm5, xmm1 \ - __asm addps xmm6, xmm5 \ - __asm movss xmm5, [edi+row*20+2*4] \ - __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm5, xmm2 \ - __asm addps xmm6, xmm5 \ - __asm movss xmm5, [edi+row*20+3*4] \ - __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm5, xmm3 \ - __asm addps xmm6, xmm5 \ - __asm movss xmm5, [edi+row*20+4*4] \ - __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm5, xmm4 \ - __asm addps xmm6, xmm5 \ - __asm movlps [eax+row*24+0], xmm6 \ - __asm movhps [eax+row*24+8], xmm6 - - #define MUL_Nx5_5x6_LAST2COLUMNS_INIT \ - __asm movlps xmm0, [esi+ 4*4] \ - __asm movlps xmm1, [esi+10*4] \ - __asm movlps xmm2, [esi+16*4] \ - __asm movlps xmm3, [esi+22*4] \ - __asm movlps xmm4, [esi+28*4] \ - __asm shufps xmm0, xmm1, R_SHUFFLEPS( 0, 1, 0, 1 ) \ - __asm shufps xmm1, xmm2, R_SHUFFLEPS( 0, 1, 0, 1 ) \ - __asm shufps xmm2, xmm3, R_SHUFFLEPS( 0, 1, 0, 1 ) \ - __asm shufps xmm3, xmm4, R_SHUFFLEPS( 0, 1, 0, 1 ) \ - __asm shufps xmm4, xmm0, R_SHUFFLEPS( 0, 1, 0, 1 ) - - #define MUL_Nx5_5x6_LAST2COLUMNS_ROW2( row ) \ - __asm movlps xmm7, [edi+row*40+ 0*4] \ - __asm movhps xmm7, [edi+row*40+ 6*4] \ - __asm movaps xmm6, xmm7 \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 2, 2 ) \ - __asm mulps xmm6, xmm0 \ - __asm movaps xmm5, xmm7 \ - __asm shufps xmm5, xmm5, R_SHUFFLEPS( 1, 1, 3, 3 ) \ - __asm mulps xmm5, xmm1 \ - __asm addps xmm6, xmm5 \ - __asm movlps xmm7, [edi+row*40+ 2*4] \ - __asm movhps xmm7, [edi+row*40+ 8*4] \ - __asm movaps xmm5, xmm7 \ - __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 2, 2 ) \ - __asm mulps xmm5, xmm2 \ - __asm addps xmm6, xmm5 \ - __asm movaps xmm5, xmm7 \ - __asm shufps xmm5, xmm5, R_SHUFFLEPS( 1, 1, 3, 3 ) \ - __asm mulps xmm5, xmm3 \ - __asm addps xmm6, xmm5 \ - __asm movlps xmm5, [edi+row*40+ 4*4] \ - __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 1, 1 ) \ - __asm mulps xmm5, xmm4 \ - __asm addps xmm6, xmm5 \ - __asm movlps [eax+row*48+ 4*4], xmm6 \ - __asm movhps [eax+row*48+10*4], xmm6 - - #define MUL_Nx5_5x6_LAST2COLUMNS_ROW( row ) \ - __asm movlps xmm6, [edi+20*4+0*4] \ - __asm unpcklps xmm6, xmm6 \ - __asm mulps xmm6, xmm0 \ - __asm movlps xmm5, [edi+20*4+2*4] \ - __asm unpcklps xmm5, xmm5 \ - __asm mulps xmm5, xmm2 \ - __asm addps xmm6, xmm5 \ - __asm movss xmm5, [edi+20*4+4*4] \ - __asm unpcklps xmm5, xmm5 \ - __asm mulps xmm5, xmm4 \ - __asm addps xmm6, xmm5 \ - __asm movhlps xmm7, xmm6 \ - __asm addps xmm6, xmm7 \ - __asm movlps [eax+row*24+4*4], xmm6 - - MUL_Nx5_5x6_FIRST4COLUMNS_INIT - MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 0 ) - MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 1 ) - MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 2 ) - MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 3 ) - MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 4 ) - MUL_Nx5_5x6_LAST2COLUMNS_INIT - MUL_Nx5_5x6_LAST2COLUMNS_ROW2( 0 ) - MUL_Nx5_5x6_LAST2COLUMNS_ROW2( 1 ) - MUL_Nx5_5x6_LAST2COLUMNS_ROW( 4 ) - - return; - } - case 6: { // 6x5 * 5x6 - - MUL_Nx5_5x6_FIRST4COLUMNS_INIT - MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 0 ) - MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 1 ) - MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 2 ) - MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 3 ) - MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 4 ) - MUL_Nx5_5x6_FIRST4COLUMNS_ROW( 5 ) - MUL_Nx5_5x6_LAST2COLUMNS_INIT - MUL_Nx5_5x6_LAST2COLUMNS_ROW2( 0 ) - MUL_Nx5_5x6_LAST2COLUMNS_ROW2( 1 ) - MUL_Nx5_5x6_LAST2COLUMNS_ROW2( 2 ) - - return; - } - } - } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2*l] + - m1Ptr[3] * m2Ptr[3*l] + m1Ptr[4] * m2Ptr[4*l]; - m2Ptr++; - } - m1Ptr += 5; + if ( !( l ^ 5 ) ) { // 5x6 * 6x5 + +#define MUL_Nx6_6x5_INIT \ + __asm mov esi, m2Ptr \ + __asm mov edi, m1Ptr \ + __asm mov eax, dstPtr \ + __asm movaps xmm0, [esi] \ + __asm movlps xmm1, [esi+20] \ + __asm movhps xmm1, [esi+28] \ + __asm movlps xmm2, [esi+40] \ + __asm movhps xmm2, [esi+48] \ + __asm movlps xmm3, [esi+60] \ + __asm movhps xmm3, [esi+68] \ + __asm movaps xmm4, [esi+80] \ + __asm movlps xmm5, [esi+100] \ + __asm movhps xmm5, [esi+108] + +#define MUL_Nx6_6x5_ROW( row ) \ + __asm movss xmm7, [edi+row*24+0] \ + __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm7, xmm0 \ + __asm fld dword ptr [edi+(row*6+0)*4] \ + __asm fmul dword ptr [esi+(4+0*5)*4] \ + __asm movss xmm6, [edi+row*24+4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm1 \ + __asm addps xmm7, xmm6 \ + __asm fld dword ptr [edi+(row*6+1)*4] \ + __asm fmul dword ptr [esi+(4+1*5)*4] \ + __asm faddp st(1),st \ + __asm movss xmm6, [edi+row*24+8] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm2 \ + __asm addps xmm7, xmm6 \ + __asm fld dword ptr [edi+(row*6+2)*4] \ + __asm fmul dword ptr [esi+(4+2*5)*4] \ + __asm faddp st(1),st \ + __asm movss xmm6, [edi+row*24+12] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm3 \ + __asm addps xmm7, xmm6 \ + __asm fld dword ptr [edi+(row*6+3)*4] \ + __asm fmul dword ptr [esi+(4+3*5)*4] \ + __asm faddp st(1),st \ + __asm movss xmm6, [edi+row*24+16] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm4 \ + __asm addps xmm7, xmm6 \ + __asm fld dword ptr [edi+(row*6+4)*4] \ + __asm fmul dword ptr [esi+(4+4*5)*4] \ + __asm faddp st(1),st \ + __asm movss xmm6, [edi+row*24+20] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm5 \ + __asm addps xmm7, xmm6 \ + __asm fld dword ptr [edi+(row*6+5)*4] \ + __asm fmul dword ptr [esi+(4+5*5)*4] \ + __asm faddp st(1),st \ + __asm fstp dword ptr [eax+(row*5+4)*4] \ + __asm movlps [eax+row*20], xmm7 \ + __asm movhps [eax+row*20+8], xmm7 + + MUL_Nx6_6x5_INIT + MUL_Nx6_6x5_ROW( 0 ) + MUL_Nx6_6x5_ROW( 1 ) + MUL_Nx6_6x5_ROW( 2 ) + MUL_Nx6_6x5_ROW( 3 ) + MUL_Nx6_6x5_ROW( 4 ) + + return; } break; } case 6: { - switch( k ) { - case 1: { - if ( !(l^1) ) { // 1x6 * 6x1 - dstPtr[0] = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[1] + m1Ptr[2] * m2Ptr[2] + - m1Ptr[3] * m2Ptr[3] + m1Ptr[4] * m2Ptr[4] + m1Ptr[5] * m2Ptr[5]; - return; - } - break; - } - case 2: { - if ( !(l^2) ) { // 2x6 * 6x2 - - #define MUL_Nx6_6x2_INIT \ - __asm mov esi, m2Ptr \ - __asm mov edi, m1Ptr \ - __asm mov eax, dstPtr \ - __asm movaps xmm0, [esi] \ - __asm movaps xmm1, [esi+16] \ - __asm movaps xmm2, [esi+32] - - #define MUL_Nx6_6x2_ROW2( row ) \ - __asm movaps xmm7, [edi+row*48+0*4] \ - __asm movaps xmm6, xmm7 \ - __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 1, 1 ) \ - __asm mulps xmm7, xmm0 \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 2, 2, 3, 3 ) \ - __asm mulps xmm6, xmm1 \ - __asm addps xmm7, xmm6 \ - __asm movaps xmm6, [edi+row*48+4*4] \ - __asm movaps xmm5, xmm6 \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 1, 1 ) \ - __asm mulps xmm6, xmm2 \ - __asm addps xmm7, xmm6 \ - __asm shufps xmm5, xmm5, R_SHUFFLEPS( 2, 2, 3, 3 ) \ - __asm mulps xmm5, xmm0 \ - __asm movaps xmm6, [edi+row*48+24+2*4] \ - __asm movaps xmm4, xmm6 \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 1, 1 ) \ - __asm mulps xmm6, xmm1 \ - __asm addps xmm5, xmm6 \ - __asm shufps xmm4, xmm4, R_SHUFFLEPS( 2, 2, 3, 3 ) \ - __asm mulps xmm4, xmm2 \ - __asm addps xmm5, xmm4 \ - __asm movaps xmm4, xmm5 \ - __asm movhlps xmm5, xmm7 \ - __asm movlhps xmm7, xmm4 \ - __asm addps xmm7, xmm5 \ - __asm movaps [eax+row*16], xmm7 - - MUL_Nx6_6x2_INIT - MUL_Nx6_6x2_ROW2( 0 ) - - return; - } - break; - } - case 3: { - if ( !(l^3) ) { // 3x6 * 6x3 - - #define MUL_Nx6_6x3_INIT \ - __asm mov esi, m2Ptr \ - __asm mov edi, m1Ptr \ - __asm mov eax, dstPtr \ - __asm movss xmm0, [esi+ 0*4] \ - __asm movhps xmm0, [esi+ 1*4] \ - __asm movss xmm1, [esi+ 3*4] \ - __asm movhps xmm1, [esi+ 4*4] \ - __asm movss xmm2, [esi+ 6*4] \ - __asm movhps xmm2, [esi+ 7*4] \ - __asm movss xmm3, [esi+ 9*4] \ - __asm movhps xmm3, [esi+10*4] \ - __asm movss xmm4, [esi+12*4] \ - __asm movhps xmm4, [esi+13*4] \ - __asm movss xmm5, [esi+15*4] \ - __asm movhps xmm5, [esi+16*4] - - #define MUL_Nx6_6x3_ROW( row ) \ - __asm movss xmm7, [edi+row*24+0] \ - __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm7, xmm0 \ - __asm movss xmm6, [edi+row*24+4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm1 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+row*24+8] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm2 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+row*24+12] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm3 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+row*24+16] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm4 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+row*24+20] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm5 \ - __asm addps xmm7, xmm6 \ - __asm movss [eax+row*12+0], xmm7 \ - __asm movhps [eax+row*12+4], xmm7 - - MUL_Nx6_6x3_INIT - MUL_Nx6_6x3_ROW( 0 ) - MUL_Nx6_6x3_ROW( 1 ) - MUL_Nx6_6x3_ROW( 2 ) - - return; - } - break; - } - case 4: { - if ( !(l^4) ) { // 4x6 * 6x4 - - #define MUL_Nx6_6x4_INIT \ - __asm mov esi, m2Ptr \ - __asm mov edi, m1Ptr \ - __asm mov eax, dstPtr \ - __asm movaps xmm0, [esi] \ - __asm movaps xmm1, [esi+16] \ - __asm movaps xmm2, [esi+32] \ - __asm movaps xmm3, [esi+48] \ - __asm movaps xmm4, [esi+64] \ - __asm movaps xmm5, [esi+80] - - #define MUL_Nx6_6x4_ROW( row ) \ - __asm movss xmm7, [edi+row*24+0] \ - __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm7, xmm0 \ - __asm movss xmm6, [edi+row*24+4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm1 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+row*24+8] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm2 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+row*24+12] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm3 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+row*24+16] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm4 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+row*24+20] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm5 \ - __asm addps xmm7, xmm6 \ - __asm movaps [eax+row*16], xmm7 - - MUL_Nx6_6x4_INIT - MUL_Nx6_6x4_ROW( 0 ) - MUL_Nx6_6x4_ROW( 1 ) - MUL_Nx6_6x4_ROW( 2 ) - MUL_Nx6_6x4_ROW( 3 ) - - return; - } - break; - } - case 5: { - if ( !(l^5) ) { // 5x6 * 6x5 - - #define MUL_Nx6_6x5_INIT \ - __asm mov esi, m2Ptr \ - __asm mov edi, m1Ptr \ - __asm mov eax, dstPtr \ - __asm movaps xmm0, [esi] \ - __asm movlps xmm1, [esi+20] \ - __asm movhps xmm1, [esi+28] \ - __asm movlps xmm2, [esi+40] \ - __asm movhps xmm2, [esi+48] \ - __asm movlps xmm3, [esi+60] \ - __asm movhps xmm3, [esi+68] \ - __asm movaps xmm4, [esi+80] \ - __asm movlps xmm5, [esi+100] \ - __asm movhps xmm5, [esi+108] - - #define MUL_Nx6_6x5_ROW( row ) \ - __asm movss xmm7, [edi+row*24+0] \ - __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm7, xmm0 \ - __asm fld dword ptr [edi+(row*6+0)*4] \ - __asm fmul dword ptr [esi+(4+0*5)*4] \ - __asm movss xmm6, [edi+row*24+4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm1 \ - __asm addps xmm7, xmm6 \ - __asm fld dword ptr [edi+(row*6+1)*4] \ - __asm fmul dword ptr [esi+(4+1*5)*4] \ - __asm faddp st(1),st \ - __asm movss xmm6, [edi+row*24+8] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm2 \ - __asm addps xmm7, xmm6 \ - __asm fld dword ptr [edi+(row*6+2)*4] \ - __asm fmul dword ptr [esi+(4+2*5)*4] \ - __asm faddp st(1),st \ - __asm movss xmm6, [edi+row*24+12] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm3 \ - __asm addps xmm7, xmm6 \ - __asm fld dword ptr [edi+(row*6+3)*4] \ - __asm fmul dword ptr [esi+(4+3*5)*4] \ - __asm faddp st(1),st \ - __asm movss xmm6, [edi+row*24+16] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm4 \ - __asm addps xmm7, xmm6 \ - __asm fld dword ptr [edi+(row*6+4)*4] \ - __asm fmul dword ptr [esi+(4+4*5)*4] \ - __asm faddp st(1),st \ - __asm movss xmm6, [edi+row*24+20] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm5 \ - __asm addps xmm7, xmm6 \ - __asm fld dword ptr [edi+(row*6+5)*4] \ - __asm fmul dword ptr [esi+(4+5*5)*4] \ - __asm faddp st(1),st \ - __asm fstp dword ptr [eax+(row*5+4)*4] \ - __asm movlps [eax+row*20], xmm7 \ - __asm movhps [eax+row*20+8], xmm7 - - MUL_Nx6_6x5_INIT - MUL_Nx6_6x5_ROW( 0 ) - MUL_Nx6_6x5_ROW( 1 ) - MUL_Nx6_6x5_ROW( 2 ) - MUL_Nx6_6x5_ROW( 3 ) - MUL_Nx6_6x5_ROW( 4 ) - - return; - } - break; - } - case 6: { - switch( l ) { - case 1: { // 6x6 * 6x1 - __asm { - mov esi, m2Ptr - mov edi, m1Ptr - mov eax, dstPtr - movlps xmm7, qword ptr [esi] - movlps xmm6, qword ptr [esi+8] - shufps xmm7, xmm7, 0x44 - shufps xmm6, xmm6, 0x44 - movlps xmm0, qword ptr [edi ] - movhps xmm0, qword ptr [edi+ 24] - mulps xmm0, xmm7 - movlps xmm3, qword ptr [edi+ 8] - movhps xmm3, qword ptr [edi+ 32] - mulps xmm3, xmm6 - movlps xmm1, qword ptr [edi+ 48] - movhps xmm1, qword ptr [edi+ 72] - mulps xmm1, xmm7 - movlps xmm2, qword ptr [edi+ 96] - movhps xmm2, qword ptr [edi+120] - mulps xmm2, xmm7 - movlps xmm4, qword ptr [edi+ 56] - movhps xmm4, qword ptr [edi+ 80] - movlps xmm5, qword ptr [edi+104] - movhps xmm5, qword ptr [edi+128] - mulps xmm4, xmm6 - movlps xmm7, qword ptr [esi+16] - addps xmm0, xmm3 - shufps xmm7, xmm7, 0x44 - mulps xmm5, xmm6 - addps xmm1, xmm4 - movlps xmm3, qword ptr [edi+ 16] - movhps xmm3, qword ptr [edi+ 40] - addps xmm2, xmm5 - movlps xmm4, qword ptr [edi+ 64] - movhps xmm4, qword ptr [edi+ 88] - mulps xmm3, xmm7 - movlps xmm5, qword ptr [edi+112] - movhps xmm5, qword ptr [edi+136] - addps xmm0, xmm3 - mulps xmm4, xmm7 - mulps xmm5, xmm7 - addps xmm1, xmm4 - addps xmm2, xmm5 - movaps xmm6, xmm0 - shufps xmm0, xmm1, 0x88 - shufps xmm6, xmm1, 0xDD - movaps xmm7, xmm2 - shufps xmm7, xmm2, 0x88 - shufps xmm2, xmm2, 0xDD - addps xmm0, xmm6 - addps xmm2, xmm7 - movlps [eax], xmm0 - movhps [eax+8], xmm0 - movlps [eax+16], xmm2 - } - return; - } - case 2: { // 6x6 * 6x2 - - MUL_Nx6_6x2_INIT - MUL_Nx6_6x2_ROW2( 0 ) - MUL_Nx6_6x2_ROW2( 1 ) - MUL_Nx6_6x2_ROW2( 2 ) - - return; - } - case 3: { // 6x6 * 6x3 - - MUL_Nx6_6x3_INIT - MUL_Nx6_6x3_ROW( 0 ) - MUL_Nx6_6x3_ROW( 1 ) - MUL_Nx6_6x3_ROW( 2 ) - MUL_Nx6_6x3_ROW( 3 ) - MUL_Nx6_6x3_ROW( 4 ) - MUL_Nx6_6x3_ROW( 5 ) - - return; - } - case 4: { // 6x6 * 6x4 - - MUL_Nx6_6x4_INIT - MUL_Nx6_6x4_ROW( 0 ) - MUL_Nx6_6x4_ROW( 1 ) - MUL_Nx6_6x4_ROW( 2 ) - MUL_Nx6_6x4_ROW( 3 ) - MUL_Nx6_6x4_ROW( 4 ) - MUL_Nx6_6x4_ROW( 5 ) - - return; - } - case 5: { // 6x6 * 6x5 - - MUL_Nx6_6x5_INIT - MUL_Nx6_6x5_ROW( 0 ) - MUL_Nx6_6x5_ROW( 1 ) - MUL_Nx6_6x5_ROW( 2 ) - MUL_Nx6_6x5_ROW( 3 ) - MUL_Nx6_6x5_ROW( 4 ) - MUL_Nx6_6x5_ROW( 5 ) - - return; - } - case 6: { // 6x6 * 6x6 - __asm { - mov ecx, dword ptr m2Ptr - movlps xmm3, qword ptr [ecx+72] - mov edx, dword ptr m1Ptr - // Loading first 4 columns (upper 4 rows) of m2Ptr. - movaps xmm0, xmmword ptr [ecx] - movlps xmm1, qword ptr [ecx+24] - movhps xmm1, qword ptr [ecx+32] - movaps xmm2, xmmword ptr [ecx+48] - movhps xmm3, qword ptr [ecx+80] - // Calculating first 4 elements in the first row of the destination matrix. - movss xmm4, dword ptr [edx] - movss xmm5, dword ptr [edx+4] - mov eax, dword ptr dstPtr - shufps xmm4, xmm4, 0 - movss xmm6, dword ptr [edx+8] - shufps xmm5, xmm5, 0 - movss xmm7, dword ptr [edx+12] - mulps xmm4, xmm0 - shufps xmm6, xmm6, 0 - shufps xmm7, xmm7, 0 - mulps xmm5, xmm1 - mulps xmm6, xmm2 - addps xmm5, xmm4 - mulps xmm7, xmm3 - addps xmm6, xmm5 - addps xmm7, xmm6 - movaps xmmword ptr [eax], xmm7 - // Calculating first 4 elements in the second row of the destination matrix. - movss xmm4, dword ptr [edx+24] - shufps xmm4, xmm4, 0 - mulps xmm4, xmm0 - movss xmm5, dword ptr [edx+28] - shufps xmm5, xmm5, 0 - mulps xmm5, xmm1 - movss xmm6, dword ptr [edx+32] - shufps xmm6, xmm6, 0 - movss xmm7, dword ptr [edx+36] - shufps xmm7, xmm7, 0 - mulps xmm6, xmm2 - mulps xmm7, xmm3 - addps xmm7, xmm6 - addps xmm5, xmm4 - addps xmm7, xmm5 - // Calculating first 4 elements in the third row of the destination matrix. - movss xmm4, dword ptr [edx+48] - movss xmm5, dword ptr [edx+52] - movlps qword ptr [eax+24], xmm7 ; save 2nd - movhps qword ptr [eax+32], xmm7 ; row - movss xmm6, dword ptr [edx+56] - movss xmm7, dword ptr [edx+60] - shufps xmm4, xmm4, 0 - shufps xmm5, xmm5, 0 - shufps xmm6, xmm6, 0 - shufps xmm7, xmm7, 0 - mulps xmm4, xmm0 - mulps xmm5, xmm1 - mulps xmm6, xmm2 - mulps xmm7, xmm3 - addps xmm5, xmm4 - addps xmm7, xmm6 - addps xmm7, xmm5 - movaps xmmword ptr [eax+48], xmm7 - // Calculating first 4 elements in the fourth row of the destination matrix. - movss xmm4, dword ptr [edx+72] - movss xmm5, dword ptr [edx+76] - movss xmm6, dword ptr [edx+80] - movss xmm7, dword ptr [edx+84] - shufps xmm4, xmm4, 0 - shufps xmm5, xmm5, 0 - shufps xmm6, xmm6, 0 - shufps xmm7, xmm7, 0 - mulps xmm4, xmm0 - mulps xmm5, xmm1 - mulps xmm6, xmm2 - mulps xmm7, xmm3 - addps xmm4, xmm5 - addps xmm6, xmm4 - addps xmm7, xmm6 - movlps qword ptr [eax+72], xmm7 - movhps qword ptr [eax+80], xmm7 - // Calculating first 4 elements in the fifth row of the destination matrix. - movss xmm4, dword ptr [edx+96] - movss xmm5, dword ptr [edx+100] - movss xmm6, dword ptr [edx+104] - movss xmm7, dword ptr [edx+108] - shufps xmm4, xmm4, 0 - shufps xmm5, xmm5, 0 - shufps xmm6, xmm6, 0 - shufps xmm7, xmm7, 0 - mulps xmm4, xmm0 - mulps xmm5, xmm1 - mulps xmm6, xmm2 - mulps xmm7, xmm3 - addps xmm5, xmm4 - addps xmm7, xmm6 - addps xmm7, xmm5 - movaps xmmword ptr [eax+96], xmm7 - // Calculating first 4 elements in the sixth row of the destination matrix. - movss xmm4, dword ptr [edx+120] - movss xmm5, dword ptr [edx+124] - movss xmm6, dword ptr [edx+128] - movss xmm7, dword ptr [edx+132] - shufps xmm4, xmm4, 0 - shufps xmm5, xmm5, 0 - shufps xmm6, xmm6, 0 - shufps xmm7, xmm7, 0 - mulps xmm4, xmm0 - mulps xmm5, xmm1 - mulps xmm6, xmm2 - mulps xmm7, xmm3 - addps xmm4, xmm5 - addps xmm6, xmm4 - addps xmm7, xmm6 - movhps qword ptr [eax+128], xmm7 - movlps qword ptr [eax+120], xmm7 - // Loading first 4 columns (lower 2 rows) of m2Ptr. - movlps xmm0, qword ptr [ecx+96] - movhps xmm0, qword ptr [ecx+104] - movlps xmm1, qword ptr [ecx+120] - movhps xmm1, qword ptr [ecx+128] - // Calculating first 4 elements in the first row of the destination matrix. - movss xmm2, dword ptr [edx+16] - shufps xmm2, xmm2, 0 - movss xmm4, dword ptr [edx+40] - movss xmm3, dword ptr [edx+20] - movss xmm5, dword ptr [edx+44] - movaps xmm6, xmmword ptr [eax] - movlps xmm7, qword ptr [eax+24] - shufps xmm3, xmm3, 0 - shufps xmm5, xmm5, 0 - movhps xmm7, qword ptr [eax+32] - shufps xmm4, xmm4, 0 - mulps xmm5, xmm1 - mulps xmm2, xmm0 - mulps xmm3, xmm1 - mulps xmm4, xmm0 - addps xmm6, xmm2 - addps xmm7, xmm4 - addps xmm7, xmm5 - addps xmm6, xmm3 - movlps qword ptr [eax+24], xmm7 - movaps xmmword ptr [eax], xmm6 - movhps qword ptr [eax+32], xmm7 - // Calculating first 4 elements in the third row of the destination matrix. - movss xmm2, dword ptr [edx+64] - movss xmm4, dword ptr [edx+88] - movss xmm5, dword ptr [edx+92] - movss xmm3, dword ptr [edx+68] - movaps xmm6, xmmword ptr [eax+48] - movlps xmm7, qword ptr [eax+72] - movhps xmm7, qword ptr [eax+80] - shufps xmm2, xmm2, 0 - shufps xmm4, xmm4, 0 - shufps xmm5, xmm5, 0 - shufps xmm3, xmm3, 0 - mulps xmm2, xmm0 - mulps xmm4, xmm0 - mulps xmm5, xmm1 - mulps xmm3, xmm1 - addps xmm6, xmm2 - addps xmm6, xmm3 - addps xmm7, xmm4 - addps xmm7, xmm5 - movlps qword ptr [eax+72], xmm7 - movaps xmmword ptr [eax+48], xmm6 - movhps qword ptr [eax+80], xmm7 - // Calculating first 4 elements in the fifth row of the destination matrix. - movss xmm2, dword ptr [edx+112] - movss xmm3, dword ptr [edx+116] - movaps xmm6, xmmword ptr [eax+96] - shufps xmm2, xmm2, 0 - shufps xmm3, xmm3, 0 - mulps xmm2, xmm0 - mulps xmm3, xmm1 - addps xmm6, xmm2 - addps xmm6, xmm3 - movaps xmmword ptr [eax+96], xmm6 - // Calculating first 4 elements in the sixth row of the destination matrix. - movss xmm4, dword ptr [edx+136] - movss xmm5, dword ptr [edx+140] - movhps xmm7, qword ptr [eax+128] - movlps xmm7, qword ptr [eax+120] - shufps xmm4, xmm4, 0 - shufps xmm5, xmm5, 0 - mulps xmm4, xmm0 - mulps xmm5, xmm1 - addps xmm7, xmm4 - addps xmm7, xmm5 - // Calculating last 2 columns of the destination matrix. - movlps xmm0, qword ptr [ecx+16] - movhps xmm0, qword ptr [ecx+40] - movhps qword ptr [eax+128], xmm7 - movlps qword ptr [eax+120], xmm7 - movlps xmm2, qword ptr [ecx+64] - movhps xmm2, qword ptr [ecx+88] - movaps xmm3, xmm2 - shufps xmm3, xmm3, 4Eh - movlps xmm4, qword ptr [ecx+112] - movhps xmm4, qword ptr [ecx+136] - movaps xmm5, xmm4 - shufps xmm5, xmm5, 4Eh - movlps xmm6, qword ptr [edx] - movhps xmm6, qword ptr [edx+24] - movaps xmm7, xmm6 - shufps xmm7, xmm7, 0F0h - mulps xmm7, xmm0 - shufps xmm6, xmm6, 0A5h - movaps xmm1, xmm0 - shufps xmm1, xmm1, 4Eh - mulps xmm1, xmm6 - addps xmm7, xmm1 - movlps xmm6, qword ptr [edx+8] - movhps xmm6, qword ptr [edx+32] - movaps xmm1, xmm6 - shufps xmm1, xmm1, 0F0h - shufps xmm6, xmm6, 0A5h - mulps xmm1, xmm2 - mulps xmm6, xmm3 - addps xmm7, xmm1 - addps xmm7, xmm6 - movhps xmm6, qword ptr [edx+40] - movlps xmm6, qword ptr [edx+16] - movaps xmm1, xmm6 - shufps xmm1, xmm1, 0F0h - shufps xmm6, xmm6, 0A5h - mulps xmm1, xmm4 - mulps xmm6, xmm5 - addps xmm7, xmm1 - addps xmm7, xmm6 - movlps qword ptr [eax+16], xmm7 - movhps qword ptr [eax+40], xmm7 - movlps xmm6, qword ptr [edx+48] - movhps xmm6, qword ptr [edx+72] - movaps xmm7, xmm6 - shufps xmm7, xmm7, 0F0h - mulps xmm7, xmm0 - shufps xmm6, xmm6, 0A5h - movaps xmm1, xmm0 - shufps xmm1, xmm1, 4Eh - mulps xmm1, xmm6 - addps xmm7, xmm1 - movhps xmm6, qword ptr [edx+80] - movlps xmm6, qword ptr [edx+56] - movaps xmm1, xmm6 - shufps xmm1, xmm1, 0F0h - shufps xmm6, xmm6, 0A5h - mulps xmm1, xmm2 - mulps xmm6, xmm3 - addps xmm7, xmm1 - addps xmm7, xmm6 - movlps xmm6, qword ptr [edx+64] - movhps xmm6, qword ptr [edx+88] - movaps xmm1, xmm6 - shufps xmm1, xmm1, 0F0h - shufps xmm6, xmm6, 0A5h - mulps xmm1, xmm4 - mulps xmm6, xmm5 - addps xmm7, xmm1 - addps xmm7, xmm6 - movlps qword ptr [eax+64], xmm7 - movhps qword ptr [eax+88], xmm7 - movlps xmm6, qword ptr [edx+96] - movhps xmm6, qword ptr [edx+120] - movaps xmm7, xmm6 - shufps xmm7, xmm7, 0F0h - mulps xmm7, xmm0 - shufps xmm6, xmm6, 0A5h - movaps xmm1, xmm0 - shufps xmm1, xmm1, 4Eh - mulps xmm1, xmm6 - addps xmm7, xmm1 - movlps xmm6, qword ptr [edx+104] - movhps xmm6, qword ptr [edx+128] - movaps xmm1, xmm6 - shufps xmm1, xmm1, 0F0h - shufps xmm6, xmm6, 0A5h - mulps xmm1, xmm2 - mulps xmm6, xmm3 - addps xmm7, xmm1 - addps xmm7, xmm6 - movlps xmm6, qword ptr [edx+112] - movhps xmm6, qword ptr [edx+136] - movaps xmm1, xmm6 - shufps xmm1, xmm1, 0F0h - shufps xmm6, xmm6, 0A5h - mulps xmm1, xmm4 - mulps xmm6, xmm5 - addps xmm7, xmm1 - addps xmm7, xmm6 - movlps qword ptr [eax+112], xmm7 - movhps qword ptr [eax+136], xmm7 - } - return; - } - } + switch ( l ) { + case 1: { // 6x6 * 6x1 + __asm { + mov esi, m2Ptr + mov edi, m1Ptr + mov eax, dstPtr + movlps xmm7, qword ptr [esi] + movlps xmm6, qword ptr [esi+8] + shufps xmm7, xmm7, 0x44 + shufps xmm6, xmm6, 0x44 + movlps xmm0, qword ptr [edi ] + movhps xmm0, qword ptr [edi+ 24] + mulps xmm0, xmm7 + movlps xmm3, qword ptr [edi+ 8] + movhps xmm3, qword ptr [edi+ 32] + mulps xmm3, xmm6 + movlps xmm1, qword ptr [edi+ 48] + movhps xmm1, qword ptr [edi+ 72] + mulps xmm1, xmm7 + movlps xmm2, qword ptr [edi+ 96] + movhps xmm2, qword ptr [edi+120] + mulps xmm2, xmm7 + movlps xmm4, qword ptr [edi+ 56] + movhps xmm4, qword ptr [edi+ 80] + movlps xmm5, qword ptr [edi+104] + movhps xmm5, qword ptr [edi+128] + mulps xmm4, xmm6 + movlps xmm7, qword ptr [esi+16] + addps xmm0, xmm3 + shufps xmm7, xmm7, 0x44 + mulps xmm5, xmm6 + addps xmm1, xmm4 + movlps xmm3, qword ptr [edi+ 16] + movhps xmm3, qword ptr [edi+ 40] + addps xmm2, xmm5 + movlps xmm4, qword ptr [edi+ 64] + movhps xmm4, qword ptr [edi+ 88] + mulps xmm3, xmm7 + movlps xmm5, qword ptr [edi+112] + movhps xmm5, qword ptr [edi+136] + addps xmm0, xmm3 + mulps xmm4, xmm7 + mulps xmm5, xmm7 + addps xmm1, xmm4 + addps xmm2, xmm5 + movaps xmm6, xmm0 + shufps xmm0, xmm1, 0x88 + shufps xmm6, xmm1, 0xDD + movaps xmm7, xmm2 + shufps xmm7, xmm2, 0x88 + shufps xmm2, xmm2, 0xDD + addps xmm0, xmm6 + addps xmm2, xmm7 + movlps [eax], xmm0 + movhps [eax+8], xmm0 + movlps [eax+16], xmm2 } + return; + } + case 2: { // 6x6 * 6x2 + + MUL_Nx6_6x2_INIT + MUL_Nx6_6x2_ROW2( 0 ) + MUL_Nx6_6x2_ROW2( 1 ) + MUL_Nx6_6x2_ROW2( 2 ) + + return; + } + case 3: { // 6x6 * 6x3 + + MUL_Nx6_6x3_INIT + MUL_Nx6_6x3_ROW( 0 ) + MUL_Nx6_6x3_ROW( 1 ) + MUL_Nx6_6x3_ROW( 2 ) + MUL_Nx6_6x3_ROW( 3 ) + MUL_Nx6_6x3_ROW( 4 ) + MUL_Nx6_6x3_ROW( 5 ) + + return; + } + case 4: { // 6x6 * 6x4 + + MUL_Nx6_6x4_INIT + MUL_Nx6_6x4_ROW( 0 ) + MUL_Nx6_6x4_ROW( 1 ) + MUL_Nx6_6x4_ROW( 2 ) + MUL_Nx6_6x4_ROW( 3 ) + MUL_Nx6_6x4_ROW( 4 ) + MUL_Nx6_6x4_ROW( 5 ) + + return; + } + case 5: { // 6x6 * 6x5 + + MUL_Nx6_6x5_INIT + MUL_Nx6_6x5_ROW( 0 ) + MUL_Nx6_6x5_ROW( 1 ) + MUL_Nx6_6x5_ROW( 2 ) + MUL_Nx6_6x5_ROW( 3 ) + MUL_Nx6_6x5_ROW( 4 ) + MUL_Nx6_6x5_ROW( 5 ) + + return; } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2*l] + - m1Ptr[3] * m2Ptr[3*l] + m1Ptr[4] * m2Ptr[4*l] + m1Ptr[5] * m2Ptr[5*l]; - m2Ptr++; + case 6: { // 6x6 * 6x6 + __asm { + mov ecx, dword ptr m2Ptr + movlps xmm3, qword ptr [ecx+72] + mov edx, dword ptr m1Ptr + // Loading first 4 columns (upper 4 rows) of m2Ptr. + movaps xmm0, xmmword ptr [ecx] + movlps xmm1, qword ptr [ecx+24] + movhps xmm1, qword ptr [ecx+32] + movaps xmm2, xmmword ptr [ecx+48] + movhps xmm3, qword ptr [ecx+80] + // Calculating first 4 elements in the first row of the destination matrix. + movss xmm4, dword ptr [edx] + movss xmm5, dword ptr [edx+4] + mov eax, dword ptr dstPtr + shufps xmm4, xmm4, 0 + movss xmm6, dword ptr [edx+8] + shufps xmm5, xmm5, 0 + movss xmm7, dword ptr [edx+12] + mulps xmm4, xmm0 + shufps xmm6, xmm6, 0 + shufps xmm7, xmm7, 0 + mulps xmm5, xmm1 + mulps xmm6, xmm2 + addps xmm5, xmm4 + mulps xmm7, xmm3 + addps xmm6, xmm5 + addps xmm7, xmm6 + movaps xmmword ptr [eax], xmm7 + // Calculating first 4 elements in the second row of the destination matrix. + movss xmm4, dword ptr [edx+24] + shufps xmm4, xmm4, 0 + mulps xmm4, xmm0 + movss xmm5, dword ptr [edx+28] + shufps xmm5, xmm5, 0 + mulps xmm5, xmm1 + movss xmm6, dword ptr [edx+32] + shufps xmm6, xmm6, 0 + movss xmm7, dword ptr [edx+36] + shufps xmm7, xmm7, 0 + mulps xmm6, xmm2 + mulps xmm7, xmm3 + addps xmm7, xmm6 + addps xmm5, xmm4 + addps xmm7, xmm5 + // Calculating first 4 elements in the third row of the destination matrix. + movss xmm4, dword ptr [edx+48] + movss xmm5, dword ptr [edx+52] + movlps qword ptr [eax+24], xmm7 ; save 2nd + movhps qword ptr [eax+32], xmm7 ; row + movss xmm6, dword ptr [edx+56] + movss xmm7, dword ptr [edx+60] + shufps xmm4, xmm4, 0 + shufps xmm5, xmm5, 0 + shufps xmm6, xmm6, 0 + shufps xmm7, xmm7, 0 + mulps xmm4, xmm0 + mulps xmm5, xmm1 + mulps xmm6, xmm2 + mulps xmm7, xmm3 + addps xmm5, xmm4 + addps xmm7, xmm6 + addps xmm7, xmm5 + movaps xmmword ptr [eax+48], xmm7 + // Calculating first 4 elements in the fourth row of the destination matrix. + movss xmm4, dword ptr [edx+72] + movss xmm5, dword ptr [edx+76] + movss xmm6, dword ptr [edx+80] + movss xmm7, dword ptr [edx+84] + shufps xmm4, xmm4, 0 + shufps xmm5, xmm5, 0 + shufps xmm6, xmm6, 0 + shufps xmm7, xmm7, 0 + mulps xmm4, xmm0 + mulps xmm5, xmm1 + mulps xmm6, xmm2 + mulps xmm7, xmm3 + addps xmm4, xmm5 + addps xmm6, xmm4 + addps xmm7, xmm6 + movlps qword ptr [eax+72], xmm7 + movhps qword ptr [eax+80], xmm7 + // Calculating first 4 elements in the fifth row of the destination matrix. + movss xmm4, dword ptr [edx+96] + movss xmm5, dword ptr [edx+100] + movss xmm6, dword ptr [edx+104] + movss xmm7, dword ptr [edx+108] + shufps xmm4, xmm4, 0 + shufps xmm5, xmm5, 0 + shufps xmm6, xmm6, 0 + shufps xmm7, xmm7, 0 + mulps xmm4, xmm0 + mulps xmm5, xmm1 + mulps xmm6, xmm2 + mulps xmm7, xmm3 + addps xmm5, xmm4 + addps xmm7, xmm6 + addps xmm7, xmm5 + movaps xmmword ptr [eax+96], xmm7 + // Calculating first 4 elements in the sixth row of the destination matrix. + movss xmm4, dword ptr [edx+120] + movss xmm5, dword ptr [edx+124] + movss xmm6, dword ptr [edx+128] + movss xmm7, dword ptr [edx+132] + shufps xmm4, xmm4, 0 + shufps xmm5, xmm5, 0 + shufps xmm6, xmm6, 0 + shufps xmm7, xmm7, 0 + mulps xmm4, xmm0 + mulps xmm5, xmm1 + mulps xmm6, xmm2 + mulps xmm7, xmm3 + addps xmm4, xmm5 + addps xmm6, xmm4 + addps xmm7, xmm6 + movhps qword ptr [eax+128], xmm7 + movlps qword ptr [eax+120], xmm7 + // Loading first 4 columns (lower 2 rows) of m2Ptr. + movlps xmm0, qword ptr [ecx+96] + movhps xmm0, qword ptr [ecx+104] + movlps xmm1, qword ptr [ecx+120] + movhps xmm1, qword ptr [ecx+128] + // Calculating first 4 elements in the first row of the destination matrix. + movss xmm2, dword ptr [edx+16] + shufps xmm2, xmm2, 0 + movss xmm4, dword ptr [edx+40] + movss xmm3, dword ptr [edx+20] + movss xmm5, dword ptr [edx+44] + movaps xmm6, xmmword ptr [eax] + movlps xmm7, qword ptr [eax+24] + shufps xmm3, xmm3, 0 + shufps xmm5, xmm5, 0 + movhps xmm7, qword ptr [eax+32] + shufps xmm4, xmm4, 0 + mulps xmm5, xmm1 + mulps xmm2, xmm0 + mulps xmm3, xmm1 + mulps xmm4, xmm0 + addps xmm6, xmm2 + addps xmm7, xmm4 + addps xmm7, xmm5 + addps xmm6, xmm3 + movlps qword ptr [eax+24], xmm7 + movaps xmmword ptr [eax], xmm6 + movhps qword ptr [eax+32], xmm7 + // Calculating first 4 elements in the third row of the destination matrix. + movss xmm2, dword ptr [edx+64] + movss xmm4, dword ptr [edx+88] + movss xmm5, dword ptr [edx+92] + movss xmm3, dword ptr [edx+68] + movaps xmm6, xmmword ptr [eax+48] + movlps xmm7, qword ptr [eax+72] + movhps xmm7, qword ptr [eax+80] + shufps xmm2, xmm2, 0 + shufps xmm4, xmm4, 0 + shufps xmm5, xmm5, 0 + shufps xmm3, xmm3, 0 + mulps xmm2, xmm0 + mulps xmm4, xmm0 + mulps xmm5, xmm1 + mulps xmm3, xmm1 + addps xmm6, xmm2 + addps xmm6, xmm3 + addps xmm7, xmm4 + addps xmm7, xmm5 + movlps qword ptr [eax+72], xmm7 + movaps xmmword ptr [eax+48], xmm6 + movhps qword ptr [eax+80], xmm7 + // Calculating first 4 elements in the fifth row of the destination matrix. + movss xmm2, dword ptr [edx+112] + movss xmm3, dword ptr [edx+116] + movaps xmm6, xmmword ptr [eax+96] + shufps xmm2, xmm2, 0 + shufps xmm3, xmm3, 0 + mulps xmm2, xmm0 + mulps xmm3, xmm1 + addps xmm6, xmm2 + addps xmm6, xmm3 + movaps xmmword ptr [eax+96], xmm6 + // Calculating first 4 elements in the sixth row of the destination matrix. + movss xmm4, dword ptr [edx+136] + movss xmm5, dword ptr [edx+140] + movhps xmm7, qword ptr [eax+128] + movlps xmm7, qword ptr [eax+120] + shufps xmm4, xmm4, 0 + shufps xmm5, xmm5, 0 + mulps xmm4, xmm0 + mulps xmm5, xmm1 + addps xmm7, xmm4 + addps xmm7, xmm5 + // Calculating last 2 columns of the destination matrix. + movlps xmm0, qword ptr [ecx+16] + movhps xmm0, qword ptr [ecx+40] + movhps qword ptr [eax+128], xmm7 + movlps qword ptr [eax+120], xmm7 + movlps xmm2, qword ptr [ecx+64] + movhps xmm2, qword ptr [ecx+88] + movaps xmm3, xmm2 + shufps xmm3, xmm3, 4Eh + movlps xmm4, qword ptr [ecx+112] + movhps xmm4, qword ptr [ecx+136] + movaps xmm5, xmm4 + shufps xmm5, xmm5, 4Eh + movlps xmm6, qword ptr [edx] + movhps xmm6, qword ptr [edx+24] + movaps xmm7, xmm6 + shufps xmm7, xmm7, 0F0h + mulps xmm7, xmm0 + shufps xmm6, xmm6, 0A5h + movaps xmm1, xmm0 + shufps xmm1, xmm1, 4Eh + mulps xmm1, xmm6 + addps xmm7, xmm1 + movlps xmm6, qword ptr [edx+8] + movhps xmm6, qword ptr [edx+32] + movaps xmm1, xmm6 + shufps xmm1, xmm1, 0F0h + shufps xmm6, xmm6, 0A5h + mulps xmm1, xmm2 + mulps xmm6, xmm3 + addps xmm7, xmm1 + addps xmm7, xmm6 + movhps xmm6, qword ptr [edx+40] + movlps xmm6, qword ptr [edx+16] + movaps xmm1, xmm6 + shufps xmm1, xmm1, 0F0h + shufps xmm6, xmm6, 0A5h + mulps xmm1, xmm4 + mulps xmm6, xmm5 + addps xmm7, xmm1 + addps xmm7, xmm6 + movlps qword ptr [eax+16], xmm7 + movhps qword ptr [eax+40], xmm7 + movlps xmm6, qword ptr [edx+48] + movhps xmm6, qword ptr [edx+72] + movaps xmm7, xmm6 + shufps xmm7, xmm7, 0F0h + mulps xmm7, xmm0 + shufps xmm6, xmm6, 0A5h + movaps xmm1, xmm0 + shufps xmm1, xmm1, 4Eh + mulps xmm1, xmm6 + addps xmm7, xmm1 + movhps xmm6, qword ptr [edx+80] + movlps xmm6, qword ptr [edx+56] + movaps xmm1, xmm6 + shufps xmm1, xmm1, 0F0h + shufps xmm6, xmm6, 0A5h + mulps xmm1, xmm2 + mulps xmm6, xmm3 + addps xmm7, xmm1 + addps xmm7, xmm6 + movlps xmm6, qword ptr [edx+64] + movhps xmm6, qword ptr [edx+88] + movaps xmm1, xmm6 + shufps xmm1, xmm1, 0F0h + shufps xmm6, xmm6, 0A5h + mulps xmm1, xmm4 + mulps xmm6, xmm5 + addps xmm7, xmm1 + addps xmm7, xmm6 + movlps qword ptr [eax+64], xmm7 + movhps qword ptr [eax+88], xmm7 + movlps xmm6, qword ptr [edx+96] + movhps xmm6, qword ptr [edx+120] + movaps xmm7, xmm6 + shufps xmm7, xmm7, 0F0h + mulps xmm7, xmm0 + shufps xmm6, xmm6, 0A5h + movaps xmm1, xmm0 + shufps xmm1, xmm1, 4Eh + mulps xmm1, xmm6 + addps xmm7, xmm1 + movlps xmm6, qword ptr [edx+104] + movhps xmm6, qword ptr [edx+128] + movaps xmm1, xmm6 + shufps xmm1, xmm1, 0F0h + shufps xmm6, xmm6, 0A5h + mulps xmm1, xmm2 + mulps xmm6, xmm3 + addps xmm7, xmm1 + addps xmm7, xmm6 + movlps xmm6, qword ptr [edx+112] + movhps xmm6, qword ptr [edx+136] + movaps xmm1, xmm6 + shufps xmm1, xmm1, 0F0h + shufps xmm6, xmm6, 0A5h + mulps xmm1, xmm4 + mulps xmm6, xmm5 + addps xmm7, xmm1 + addps xmm7, xmm6 + movlps qword ptr [eax+112], xmm7 + movhps qword ptr [eax+136], xmm7 } - m1Ptr += 6; + return; + } } - break; } - default: { - for ( i = 0; i < k; i++ ) { - for ( j = 0; j < l; j++ ) { - m2Ptr = m2.ToFloatPtr() + j; - sum = m1Ptr[0] * m2Ptr[0]; - for ( n = 1; n < m1.GetNumColumns(); n++ ) { - m2Ptr += l; - sum += m1Ptr[n] * m2Ptr[0]; - } - *dstPtr++ = sum; + } + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[1] * m2Ptr[l] + m1Ptr[2] * m2Ptr[2 * l] + + m1Ptr[3] * m2Ptr[3 * l] + m1Ptr[4] * m2Ptr[4 * l] + m1Ptr[5] * m2Ptr[5 * l]; + m2Ptr++; + } + m1Ptr += 6; + } + break; + } + default: { + for ( i = 0; i < k; i++ ) { + for ( j = 0; j < l; j++ ) { + m2Ptr = m2.ToFloatPtr() + j; + sum = m1Ptr[0] * m2Ptr[0]; + for ( n = 1; n < m1.GetNumColumns(); n++ ) { + m2Ptr += l; + sum += m1Ptr[n] * m2Ptr[0]; } - m1Ptr += m1.GetNumColumns(); + *dstPtr++ = sum; } - break; + m1Ptr += m1.GetNumColumns(); } + break; + } } } @@ -9623,35 +9716,35 @@ void VPCALL idSIMD_SSE::MatX_TransposeMultiplyMatX( idMatX &dst, const idMatX &m k = m1.GetNumColumns(); l = m2.GetNumColumns(); - switch( m1.GetNumRows() ) { - case 1: - if ( !((k^6)|(l^1)) ) { // 1x6 * 1x1 - __asm { - mov esi, m2Ptr - mov edi, m1Ptr - mov eax, dstPtr - movss xmm0, [esi] - shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - movaps xmm1, xmm0 - mulps xmm0, [edi] - mulps xmm1, [edi+16] - movaps [eax], xmm0 - movlps [eax+16], xmm1 - } - return; + switch ( m1.GetNumRows() ) { + case 1: + if ( !( ( k ^ 6 ) | ( l ^ 1 ) ) ) { // 1x6 * 1x1 + __asm { + mov esi, m2Ptr + mov edi, m1Ptr + mov eax, dstPtr + movss xmm0, [esi] + shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) + movaps xmm1, xmm0 + mulps xmm0, [edi] + mulps xmm1, [edi + 16] + movaps [eax], xmm0 + movlps [eax + 16], xmm1 } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0]; - m2Ptr++; - } - m1Ptr++; + return; + } + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0]; + m2Ptr++; } - break; - case 2: - if ( !((k^6)|(l^2)) ) { // 2x6 * 2x2 - #define MUL_2xN_2x2_INIT \ + m1Ptr++; + } + break; + case 2: + if ( !( ( k ^ 6 ) | ( l ^ 2 ) ) ) { // 2x6 * 2x2 +#define MUL_2xN_2x2_INIT \ __asm mov esi, m2Ptr \ __asm mov edi, m1Ptr \ __asm mov eax, dstPtr \ @@ -9660,7 +9753,7 @@ void VPCALL idSIMD_SSE::MatX_TransposeMultiplyMatX( idMatX &dst, const idMatX &m __asm movlps xmm1, [esi+8] \ __asm shufps xmm1, xmm1, R_SHUFFLEPS( 0, 1, 0, 1 ) - #define MUL_2xN_2x2_ROW2( N, row ) \ +#define MUL_2xN_2x2_ROW2( N, row ) \ __asm movlps xmm6, [edi+(row+0*N)*4] \ __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 1, 1 ) \ __asm movlps xmm7, [edi+(row+1*N)*4] \ @@ -9670,26 +9763,26 @@ void VPCALL idSIMD_SSE::MatX_TransposeMultiplyMatX( idMatX &dst, const idMatX &m __asm addps xmm6, xmm7 \ __asm movaps [eax+(row*2)*4], xmm6 - MUL_2xN_2x2_INIT - MUL_2xN_2x2_ROW2( 6, 0 ) - MUL_2xN_2x2_ROW2( 6, 2 ) - MUL_2xN_2x2_ROW2( 6, 4 ) + MUL_2xN_2x2_INIT + MUL_2xN_2x2_ROW2( 6, 0 ) + MUL_2xN_2x2_ROW2( 6, 2 ) + MUL_2xN_2x2_ROW2( 6, 4 ) - return; - } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l]; - m2Ptr++; - } - m1Ptr++; + return; + } + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l]; + m2Ptr++; } - break; - case 3: - if ( !((k^6)|(l^3)) ) { // 3x6 * 3x3 + m1Ptr++; + } + break; + case 3: + if ( !( ( k ^ 6 ) | ( l ^ 3 ) ) ) { // 3x6 * 3x3 - #define MUL_3xN_3x3_INIT \ +#define MUL_3xN_3x3_INIT \ __asm mov esi, m2Ptr \ __asm mov edi, m1Ptr \ __asm mov eax, dstPtr \ @@ -9700,12 +9793,12 @@ void VPCALL idSIMD_SSE::MatX_TransposeMultiplyMatX( idMatX &dst, const idMatX &m __asm movss xmm2, [esi+(2*3+0)*4] \ __asm movhps xmm2, [esi+(2*3+1)*4] - #define MUL_3xN_3x3_INIT_ROW4 \ +#define MUL_3xN_3x3_INIT_ROW4 \ __asm shufps xmm0, xmm0, R_SHUFFLEPS( 0, 2, 3, 0 ) \ __asm shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 3, 0 ) \ __asm shufps xmm2, xmm2, R_SHUFFLEPS( 0, 2, 3, 0 ) - #define MUL_3xN_3x3_ROW4( N, row ) \ +#define MUL_3xN_3x3_ROW4( N, row ) \ __asm movlps xmm3, [edi+(row+0*N+0)*4] \ __asm shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 1 ) \ __asm movlps xmm4, [edi+(row+1*N+0)*4] \ @@ -9749,17 +9842,17 @@ void VPCALL idSIMD_SSE::MatX_TransposeMultiplyMatX( idMatX &dst, const idMatX &m __asm addps xmm3, xmm5 \ __asm movaps [eax+(row*3+8)*4], xmm3 - #define MUL_3xN_3x3_INIT_ROW4_ROW4 \ +#define MUL_3xN_3x3_INIT_ROW4_ROW4 \ __asm shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) \ __asm shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) \ __asm shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - #define MUL_3xN_3x3_INIT_ROW4_ROW \ +#define MUL_3xN_3x3_INIT_ROW4_ROW \ __asm shufps xmm0, xmm0, R_SHUFFLEPS( 1, 1, 2, 3 ) \ __asm shufps xmm1, xmm1, R_SHUFFLEPS( 1, 1, 2, 3 ) \ __asm shufps xmm2, xmm2, R_SHUFFLEPS( 1, 1, 2, 3 ) - #define MUL_3xN_3x3_ROW( N, row ) \ +#define MUL_3xN_3x3_ROW( N, row ) \ __asm movss xmm3, [edi+(row+0*N)*4] \ __asm shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) \ __asm movss xmm4, [edi+(row+1*N)*4] \ @@ -9774,28 +9867,28 @@ void VPCALL idSIMD_SSE::MatX_TransposeMultiplyMatX( idMatX &dst, const idMatX &m __asm movss [eax+(row*3+0)*4], xmm3 \ __asm movhps [eax+(row*3+1)*4], xmm3 - MUL_3xN_3x3_INIT - MUL_3xN_3x3_INIT_ROW4 - MUL_3xN_3x3_ROW4( 6, 0 ) - MUL_3xN_3x3_INIT_ROW4_ROW - MUL_3xN_3x3_ROW( 6, 4 ) - MUL_3xN_3x3_ROW( 6, 5 ) + MUL_3xN_3x3_INIT + MUL_3xN_3x3_INIT_ROW4 + MUL_3xN_3x3_ROW4( 6, 0 ) + MUL_3xN_3x3_INIT_ROW4_ROW + MUL_3xN_3x3_ROW( 6, 4 ) + MUL_3xN_3x3_ROW( 6, 5 ) - return; - } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2*k] * m2Ptr[2*l]; - m2Ptr++; - } - m1Ptr++; + return; + } + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2 * k] * m2Ptr[2 * l]; + m2Ptr++; } - break; - case 4: - if ( !((k^6)|(l^4)) ) { // 4x6 * 4x4 + m1Ptr++; + } + break; + case 4: + if ( !( ( k ^ 6 ) | ( l ^ 4 ) ) ) { // 4x6 * 4x4 - #define MUL_4xN_4x4_INIT \ +#define MUL_4xN_4x4_INIT \ __asm mov esi, m2Ptr \ __asm mov edi, m1Ptr \ __asm mov eax, dstPtr \ @@ -9804,7 +9897,7 @@ void VPCALL idSIMD_SSE::MatX_TransposeMultiplyMatX( idMatX &dst, const idMatX &m __asm movaps xmm2, [esi+32] \ __asm movaps xmm3, [esi+48] - #define MUL_4xN_4x4_ROW( N, row ) \ +#define MUL_4xN_4x4_ROW( N, row ) \ __asm movss xmm7, [edi+(row+0*N)*4] \ __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) \ __asm mulps xmm7, xmm0 \ @@ -9822,30 +9915,30 @@ void VPCALL idSIMD_SSE::MatX_TransposeMultiplyMatX( idMatX &dst, const idMatX &m __asm addps xmm7, xmm6 \ __asm movaps [eax+row*16], xmm7 - MUL_4xN_4x4_INIT - MUL_4xN_4x4_ROW( 6, 0 ) - MUL_4xN_4x4_ROW( 6, 1 ) - MUL_4xN_4x4_ROW( 6, 2 ) - MUL_4xN_4x4_ROW( 6, 3 ) - MUL_4xN_4x4_ROW( 6, 4 ) - MUL_4xN_4x4_ROW( 6, 5 ) + MUL_4xN_4x4_INIT + MUL_4xN_4x4_ROW( 6, 0 ) + MUL_4xN_4x4_ROW( 6, 1 ) + MUL_4xN_4x4_ROW( 6, 2 ) + MUL_4xN_4x4_ROW( 6, 3 ) + MUL_4xN_4x4_ROW( 6, 4 ) + MUL_4xN_4x4_ROW( 6, 5 ) - return; - } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2*k] * m2Ptr[2*l] + - m1Ptr[3*k] * m2Ptr[3*l]; - m2Ptr++; - } - m1Ptr++; + return; + } + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2 * k] * m2Ptr[2 * l] + + m1Ptr[3 * k] * m2Ptr[3 * l]; + m2Ptr++; } - break; - case 5: - if ( !((k^6)|(l^5)) ) { // 5x6 * 5x5 + m1Ptr++; + } + break; + case 5: + if ( !( ( k ^ 6 ) | ( l ^ 5 ) ) ) { // 5x6 * 5x5 - #define MUL_5xN_5x5_INIT \ +#define MUL_5xN_5x5_INIT \ __asm mov esi, m2Ptr \ __asm mov edi, m1Ptr \ __asm mov eax, dstPtr \ @@ -9860,7 +9953,7 @@ void VPCALL idSIMD_SSE::MatX_TransposeMultiplyMatX( idMatX &dst, const idMatX &m __asm movlps xmm4, [esi+20*4] \ __asm movhps xmm4, [esi+22*4] - #define MUL_5xN_5x5_ROW( N, row ) \ +#define MUL_5xN_5x5_ROW( N, row ) \ __asm movss xmm6, [edi+(row+0*N)*4] \ __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ __asm mulps xmm6, xmm0 \ @@ -9898,240 +9991,240 @@ void VPCALL idSIMD_SSE::MatX_TransposeMultiplyMatX( idMatX &dst, const idMatX &m __asm movlps [eax+(row*5+0)*4], xmm6 \ __asm movhps [eax+(row*5+2)*4], xmm6 - MUL_5xN_5x5_INIT - MUL_5xN_5x5_ROW( 6, 0 ) - MUL_5xN_5x5_ROW( 6, 1 ) - MUL_5xN_5x5_ROW( 6, 2 ) - MUL_5xN_5x5_ROW( 6, 3 ) - MUL_5xN_5x5_ROW( 6, 4 ) - MUL_5xN_5x5_ROW( 6, 5 ) + MUL_5xN_5x5_INIT + MUL_5xN_5x5_ROW( 6, 0 ) + MUL_5xN_5x5_ROW( 6, 1 ) + MUL_5xN_5x5_ROW( 6, 2 ) + MUL_5xN_5x5_ROW( 6, 3 ) + MUL_5xN_5x5_ROW( 6, 4 ) + MUL_5xN_5x5_ROW( 6, 5 ) + + return; + } + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2 * k] * m2Ptr[2 * l] + + m1Ptr[3 * k] * m2Ptr[3 * l] + m1Ptr[4 * k] * m2Ptr[4 * l]; + m2Ptr++; + } + m1Ptr++; + } + break; + case 6: + if ( !( l ^ 6 ) ) { + switch ( k ) { + case 1: { // 6x1 * 6x6 +#define MUL_6xN_6x6_FIRST4COLUMNS_INIT \ + __asm mov esi, m2Ptr \ + __asm mov edi, m1Ptr \ + __asm mov eax, dstPtr \ + __asm movlps xmm0, [esi+ 0*4] \ + __asm movhps xmm0, [esi+ 2*4] \ + __asm movlps xmm1, [esi+ 6*4] \ + __asm movhps xmm1, [esi+ 8*4] \ + __asm movlps xmm2, [esi+12*4] \ + __asm movhps xmm2, [esi+14*4] \ + __asm movlps xmm3, [esi+18*4] \ + __asm movhps xmm3, [esi+20*4] \ + __asm movlps xmm4, [esi+24*4] \ + __asm movhps xmm4, [esi+26*4] \ + __asm movlps xmm5, [esi+30*4] \ + __asm movhps xmm5, [esi+32*4] + +#define MUL_6xN_6x6_FIRST4COLUMNS_ROW( N, row ) \ + __asm movss xmm7, [edi+(row+0*N)*4] \ + __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm7, xmm0 \ + __asm movss xmm6, [edi+(row+1*N)*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm1 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+(row+2*N)*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm2 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+(row+3*N)*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm3 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+(row+4*N)*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm4 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+(row+5*N)*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm5 \ + __asm addps xmm7, xmm6 \ + __asm movlps [eax+(row*6+0)*4], xmm7 \ + __asm movhps [eax+(row*6+2)*4], xmm7 + +#define MUL_6xN_6x6_LAST2COLUMNS_INIT \ + __asm movlps xmm0, [esi+ 4*4] \ + __asm movlps xmm1, [esi+10*4] \ + __asm shufps xmm0, xmm0, R_SHUFFLEPS( 0, 1, 0, 1 ) \ + __asm shufps xmm1, xmm1, R_SHUFFLEPS( 0, 1, 0, 1 ) \ + __asm movlps xmm2, [esi+16*4] \ + __asm movlps xmm3, [esi+22*4] \ + __asm shufps xmm2, xmm2, R_SHUFFLEPS( 0, 1, 0, 1 ) \ + __asm shufps xmm3, xmm3, R_SHUFFLEPS( 0, 1, 0, 1 ) \ + __asm movlps xmm4, [esi+28*4] \ + __asm movlps xmm5, [esi+34*4] \ + __asm shufps xmm4, xmm4, R_SHUFFLEPS( 0, 1, 0, 1 ) \ + __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 1, 0, 1 ) + +#define MUL_6xN_6x6_LAST2COLUMNS_ROW2( N, row ) \ + __asm movlps xmm7, [edi+(row*2+0*N)*4] \ + __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 1, 1 ) \ + __asm mulps xmm7, xmm0 \ + __asm movlps xmm6, [edi+(row*2+1*N)*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 1, 1 ) \ + __asm mulps xmm6, xmm1 \ + __asm addps xmm7, xmm6 \ + __asm movlps xmm6, [edi+(row*2+2*N)*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 1, 1 ) \ + __asm mulps xmm6, xmm2 \ + __asm addps xmm7, xmm6 \ + __asm movlps xmm6, [edi+(row*2+3*N)*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 1, 1 ) \ + __asm mulps xmm6, xmm3 \ + __asm addps xmm7, xmm6 \ + __asm movlps xmm6, [edi+(row*2+4*N)*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 1, 1 ) \ + __asm mulps xmm6, xmm4 \ + __asm addps xmm7, xmm6 \ + __asm movlps xmm6, [edi+(row*2+5*N)*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 1, 1 ) \ + __asm mulps xmm6, xmm5 \ + __asm addps xmm7, xmm6 \ + __asm movlps [eax+(row*12+ 4)*4], xmm7 \ + __asm movhps [eax+(row*12+10)*4], xmm7 + +#define MUL_6xN_6x6_LAST2COLUMNS_ROW( N, row ) \ + __asm movss xmm7, [edi+(1*N-1)*4] \ + __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm7, xmm0 \ + __asm movss xmm6, [edi+(2*N-1)*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm1 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+(3*N-1)*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm2 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+(4*N-1)*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm3 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+(5*N-1)*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm4 \ + __asm addps xmm7, xmm6 \ + __asm movss xmm6, [edi+(6*N-1)*4] \ + __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ + __asm mulps xmm6, xmm5 \ + __asm addps xmm7, xmm6 \ + __asm movlps [eax+(row*6+4)*4], xmm7 + + MUL_6xN_6x6_FIRST4COLUMNS_INIT + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 1, 0 ) + MUL_6xN_6x6_LAST2COLUMNS_INIT + MUL_6xN_6x6_LAST2COLUMNS_ROW( 1, 0 ) return; } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2*k] * m2Ptr[2*l] + - m1Ptr[3*k] * m2Ptr[3*l] + m1Ptr[4*k] * m2Ptr[4*l]; - m2Ptr++; - } - m1Ptr++; + case 2: { // 6x2 * 6x6 + + MUL_6xN_6x6_FIRST4COLUMNS_INIT + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 2, 0 ) + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 2, 1 ) + MUL_6xN_6x6_LAST2COLUMNS_INIT + MUL_6xN_6x6_LAST2COLUMNS_ROW2( 2, 0 ) + + return; } - break; - case 6: - if ( !(l^6) ) { - switch( k ) { - case 1: { // 6x1 * 6x6 - #define MUL_6xN_6x6_FIRST4COLUMNS_INIT \ - __asm mov esi, m2Ptr \ - __asm mov edi, m1Ptr \ - __asm mov eax, dstPtr \ - __asm movlps xmm0, [esi+ 0*4] \ - __asm movhps xmm0, [esi+ 2*4] \ - __asm movlps xmm1, [esi+ 6*4] \ - __asm movhps xmm1, [esi+ 8*4] \ - __asm movlps xmm2, [esi+12*4] \ - __asm movhps xmm2, [esi+14*4] \ - __asm movlps xmm3, [esi+18*4] \ - __asm movhps xmm3, [esi+20*4] \ - __asm movlps xmm4, [esi+24*4] \ - __asm movhps xmm4, [esi+26*4] \ - __asm movlps xmm5, [esi+30*4] \ - __asm movhps xmm5, [esi+32*4] - - #define MUL_6xN_6x6_FIRST4COLUMNS_ROW( N, row ) \ - __asm movss xmm7, [edi+(row+0*N)*4] \ - __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm7, xmm0 \ - __asm movss xmm6, [edi+(row+1*N)*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm1 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+(row+2*N)*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm2 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+(row+3*N)*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm3 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+(row+4*N)*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm4 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+(row+5*N)*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm5 \ - __asm addps xmm7, xmm6 \ - __asm movlps [eax+(row*6+0)*4], xmm7 \ - __asm movhps [eax+(row*6+2)*4], xmm7 - - #define MUL_6xN_6x6_LAST2COLUMNS_INIT \ - __asm movlps xmm0, [esi+ 4*4] \ - __asm movlps xmm1, [esi+10*4] \ - __asm shufps xmm0, xmm0, R_SHUFFLEPS( 0, 1, 0, 1 ) \ - __asm shufps xmm1, xmm1, R_SHUFFLEPS( 0, 1, 0, 1 ) \ - __asm movlps xmm2, [esi+16*4] \ - __asm movlps xmm3, [esi+22*4] \ - __asm shufps xmm2, xmm2, R_SHUFFLEPS( 0, 1, 0, 1 ) \ - __asm shufps xmm3, xmm3, R_SHUFFLEPS( 0, 1, 0, 1 ) \ - __asm movlps xmm4, [esi+28*4] \ - __asm movlps xmm5, [esi+34*4] \ - __asm shufps xmm4, xmm4, R_SHUFFLEPS( 0, 1, 0, 1 ) \ - __asm shufps xmm5, xmm5, R_SHUFFLEPS( 0, 1, 0, 1 ) - - #define MUL_6xN_6x6_LAST2COLUMNS_ROW2( N, row ) \ - __asm movlps xmm7, [edi+(row*2+0*N)*4] \ - __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 1, 1 ) \ - __asm mulps xmm7, xmm0 \ - __asm movlps xmm6, [edi+(row*2+1*N)*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 1, 1 ) \ - __asm mulps xmm6, xmm1 \ - __asm addps xmm7, xmm6 \ - __asm movlps xmm6, [edi+(row*2+2*N)*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 1, 1 ) \ - __asm mulps xmm6, xmm2 \ - __asm addps xmm7, xmm6 \ - __asm movlps xmm6, [edi+(row*2+3*N)*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 1, 1 ) \ - __asm mulps xmm6, xmm3 \ - __asm addps xmm7, xmm6 \ - __asm movlps xmm6, [edi+(row*2+4*N)*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 1, 1 ) \ - __asm mulps xmm6, xmm4 \ - __asm addps xmm7, xmm6 \ - __asm movlps xmm6, [edi+(row*2+5*N)*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 1, 1 ) \ - __asm mulps xmm6, xmm5 \ - __asm addps xmm7, xmm6 \ - __asm movlps [eax+(row*12+ 4)*4], xmm7 \ - __asm movhps [eax+(row*12+10)*4], xmm7 - - #define MUL_6xN_6x6_LAST2COLUMNS_ROW( N, row ) \ - __asm movss xmm7, [edi+(1*N-1)*4] \ - __asm shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm7, xmm0 \ - __asm movss xmm6, [edi+(2*N-1)*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm1 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+(3*N-1)*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm2 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+(4*N-1)*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm3 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+(5*N-1)*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm4 \ - __asm addps xmm7, xmm6 \ - __asm movss xmm6, [edi+(6*N-1)*4] \ - __asm shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) \ - __asm mulps xmm6, xmm5 \ - __asm addps xmm7, xmm6 \ - __asm movlps [eax+(row*6+4)*4], xmm7 - - MUL_6xN_6x6_FIRST4COLUMNS_INIT - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 1, 0 ) - MUL_6xN_6x6_LAST2COLUMNS_INIT - MUL_6xN_6x6_LAST2COLUMNS_ROW( 1, 0 ) - - return; - } - case 2: { // 6x2 * 6x6 - - MUL_6xN_6x6_FIRST4COLUMNS_INIT - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 2, 0 ) - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 2, 1 ) - MUL_6xN_6x6_LAST2COLUMNS_INIT - MUL_6xN_6x6_LAST2COLUMNS_ROW2( 2, 0 ) - - return; - } - case 3: { // 6x3 * 6x6 - - MUL_6xN_6x6_FIRST4COLUMNS_INIT - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 3, 0 ) - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 3, 1 ) - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 3, 2 ) - MUL_6xN_6x6_LAST2COLUMNS_INIT - MUL_6xN_6x6_LAST2COLUMNS_ROW2( 3, 0 ) - MUL_6xN_6x6_LAST2COLUMNS_ROW( 3, 2 ) - - return; - } - case 4: { // 6x4 * 6x6 - - MUL_6xN_6x6_FIRST4COLUMNS_INIT - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 4, 0 ) - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 4, 1 ) - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 4, 2 ) - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 4, 3 ) - MUL_6xN_6x6_LAST2COLUMNS_INIT - MUL_6xN_6x6_LAST2COLUMNS_ROW2( 4, 0 ) - MUL_6xN_6x6_LAST2COLUMNS_ROW2( 4, 1 ) - - return; - } - case 5: { // 6x5 * 6x6 - - MUL_6xN_6x6_FIRST4COLUMNS_INIT - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 5, 0 ) - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 5, 1 ) - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 5, 2 ) - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 5, 3 ) - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 5, 4 ) - MUL_6xN_6x6_LAST2COLUMNS_INIT - MUL_6xN_6x6_LAST2COLUMNS_ROW2( 5, 0 ) - MUL_6xN_6x6_LAST2COLUMNS_ROW2( 5, 1 ) - MUL_6xN_6x6_LAST2COLUMNS_ROW( 5, 4 ) - - return; - } - case 6: { // 6x6 * 6x6 - - MUL_6xN_6x6_FIRST4COLUMNS_INIT - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 6, 0 ) - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 6, 1 ) - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 6, 2 ) - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 6, 3 ) - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 6, 4 ) - MUL_6xN_6x6_FIRST4COLUMNS_ROW( 6, 5 ) - MUL_6xN_6x6_LAST2COLUMNS_INIT - MUL_6xN_6x6_LAST2COLUMNS_ROW2( 6, 0 ) - MUL_6xN_6x6_LAST2COLUMNS_ROW2( 6, 1 ) - MUL_6xN_6x6_LAST2COLUMNS_ROW2( 6, 2 ) - - return; - } - } + case 3: { // 6x3 * 6x6 + + MUL_6xN_6x6_FIRST4COLUMNS_INIT + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 3, 0 ) + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 3, 1 ) + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 3, 2 ) + MUL_6xN_6x6_LAST2COLUMNS_INIT + MUL_6xN_6x6_LAST2COLUMNS_ROW2( 3, 0 ) + MUL_6xN_6x6_LAST2COLUMNS_ROW( 3, 2 ) + + return; } - for ( i = 0; i < k; i++ ) { - m2Ptr = m2.ToFloatPtr(); - for ( j = 0; j < l; j++ ) { - *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2*k] * m2Ptr[2*l] + - m1Ptr[3*k] * m2Ptr[3*l] + m1Ptr[4*k] * m2Ptr[4*l] + m1Ptr[5*k] * m2Ptr[5*l]; - m2Ptr++; - } - m1Ptr++; + case 4: { // 6x4 * 6x6 + + MUL_6xN_6x6_FIRST4COLUMNS_INIT + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 4, 0 ) + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 4, 1 ) + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 4, 2 ) + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 4, 3 ) + MUL_6xN_6x6_LAST2COLUMNS_INIT + MUL_6xN_6x6_LAST2COLUMNS_ROW2( 4, 0 ) + MUL_6xN_6x6_LAST2COLUMNS_ROW2( 4, 1 ) + + return; } - break; - default: - for ( i = 0; i < k; i++ ) { - for ( j = 0; j < l; j++ ) { - m1Ptr = m1.ToFloatPtr() + i; - m2Ptr = m2.ToFloatPtr() + j; - sum = m1Ptr[0] * m2Ptr[0]; - for ( n = 1; n < m1.GetNumRows(); n++ ) { - m1Ptr += k; - m2Ptr += l; - sum += m1Ptr[0] * m2Ptr[0]; - } - *dstPtr++ = sum; + case 5: { // 6x5 * 6x6 + + MUL_6xN_6x6_FIRST4COLUMNS_INIT + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 5, 0 ) + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 5, 1 ) + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 5, 2 ) + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 5, 3 ) + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 5, 4 ) + MUL_6xN_6x6_LAST2COLUMNS_INIT + MUL_6xN_6x6_LAST2COLUMNS_ROW2( 5, 0 ) + MUL_6xN_6x6_LAST2COLUMNS_ROW2( 5, 1 ) + MUL_6xN_6x6_LAST2COLUMNS_ROW( 5, 4 ) + + return; + } + case 6: { // 6x6 * 6x6 + + MUL_6xN_6x6_FIRST4COLUMNS_INIT + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 6, 0 ) + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 6, 1 ) + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 6, 2 ) + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 6, 3 ) + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 6, 4 ) + MUL_6xN_6x6_FIRST4COLUMNS_ROW( 6, 5 ) + MUL_6xN_6x6_LAST2COLUMNS_INIT + MUL_6xN_6x6_LAST2COLUMNS_ROW2( 6, 0 ) + MUL_6xN_6x6_LAST2COLUMNS_ROW2( 6, 1 ) + MUL_6xN_6x6_LAST2COLUMNS_ROW2( 6, 2 ) + + return; + } + } + } + for ( i = 0; i < k; i++ ) { + m2Ptr = m2.ToFloatPtr(); + for ( j = 0; j < l; j++ ) { + *dstPtr++ = m1Ptr[0] * m2Ptr[0] + m1Ptr[k] * m2Ptr[l] + m1Ptr[2 * k] * m2Ptr[2 * l] + + m1Ptr[3 * k] * m2Ptr[3 * l] + m1Ptr[4 * k] * m2Ptr[4 * l] + m1Ptr[5 * k] * m2Ptr[5 * l]; + m2Ptr++; + } + m1Ptr++; + } + break; + default: + for ( i = 0; i < k; i++ ) { + for ( j = 0; j < l; j++ ) { + m1Ptr = m1.ToFloatPtr() + i; + m2Ptr = m2.ToFloatPtr() + j; + sum = m1Ptr[0] * m2Ptr[0]; + for ( n = 1; n < m1.GetNumRows(); n++ ) { + m1Ptr += k; + m2Ptr += l; + sum += m1Ptr[0] * m2Ptr[0]; } + *dstPtr++ = sum; } + } break; } } @@ -10159,54 +10252,86 @@ void VPCALL idSIMD_SSE::MatX_LowerTriangularSolve( const idMatX &L, float *x, co // unrolled cases for n < 8 if ( n < 8 ) { - #define NSKIP( n, s ) ((n<<3)|(s&7)) - switch( NSKIP( n, skip ) ) { - case NSKIP( 1, 0 ): x[0] = b[0]; - return; - case NSKIP( 2, 0 ): x[0] = b[0]; - case NSKIP( 2, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - return; - case NSKIP( 3, 0 ): x[0] = b[0]; - case NSKIP( 3, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - case NSKIP( 3, 2 ): x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - return; - case NSKIP( 4, 0 ): x[0] = b[0]; - case NSKIP( 4, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - case NSKIP( 4, 2 ): x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - case NSKIP( 4, 3 ): x[3] = b[3] - lptr[3*nc+0] * x[0] - lptr[3*nc+1] * x[1] - lptr[3*nc+2] * x[2]; - return; - case NSKIP( 5, 0 ): x[0] = b[0]; - case NSKIP( 5, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - case NSKIP( 5, 2 ): x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - case NSKIP( 5, 3 ): x[3] = b[3] - lptr[3*nc+0] * x[0] - lptr[3*nc+1] * x[1] - lptr[3*nc+2] * x[2]; - case NSKIP( 5, 4 ): x[4] = b[4] - lptr[4*nc+0] * x[0] - lptr[4*nc+1] * x[1] - lptr[4*nc+2] * x[2] - lptr[4*nc+3] * x[3]; - return; - case NSKIP( 6, 0 ): x[0] = b[0]; - case NSKIP( 6, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - case NSKIP( 6, 2 ): x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - case NSKIP( 6, 3 ): x[3] = b[3] - lptr[3*nc+0] * x[0] - lptr[3*nc+1] * x[1] - lptr[3*nc+2] * x[2]; - case NSKIP( 6, 4 ): x[4] = b[4] - lptr[4*nc+0] * x[0] - lptr[4*nc+1] * x[1] - lptr[4*nc+2] * x[2] - lptr[4*nc+3] * x[3]; - case NSKIP( 6, 5 ): x[5] = b[5] - lptr[5*nc+0] * x[0] - lptr[5*nc+1] * x[1] - lptr[5*nc+2] * x[2] - lptr[5*nc+3] * x[3] - lptr[5*nc+4] * x[4]; - return; - case NSKIP( 7, 0 ): x[0] = b[0]; - case NSKIP( 7, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - case NSKIP( 7, 2 ): x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - case NSKIP( 7, 3 ): x[3] = b[3] - lptr[3*nc+0] * x[0] - lptr[3*nc+1] * x[1] - lptr[3*nc+2] * x[2]; - case NSKIP( 7, 4 ): x[4] = b[4] - lptr[4*nc+0] * x[0] - lptr[4*nc+1] * x[1] - lptr[4*nc+2] * x[2] - lptr[4*nc+3] * x[3]; - case NSKIP( 7, 5 ): x[5] = b[5] - lptr[5*nc+0] * x[0] - lptr[5*nc+1] * x[1] - lptr[5*nc+2] * x[2] - lptr[5*nc+3] * x[3] - lptr[5*nc+4] * x[4]; - case NSKIP( 7, 6 ): x[6] = b[6] - lptr[6*nc+0] * x[0] - lptr[6*nc+1] * x[1] - lptr[6*nc+2] * x[2] - lptr[6*nc+3] * x[3] - lptr[6*nc+4] * x[4] - lptr[6*nc+5] * x[5]; - return; +#define NSKIP( n, s ) ((n<<3)|(s&7)) + switch ( NSKIP( n, skip ) ) { + case NSKIP( 1, 0 ): + x[0] = b[0]; + return; + case NSKIP( 2, 0 ): + x[0] = b[0]; + case NSKIP( 2, 1 ): + x[1] = b[1] - lptr[1 * nc + 0] * x[0]; + return; + case NSKIP( 3, 0 ): + x[0] = b[0]; + case NSKIP( 3, 1 ): + x[1] = b[1] - lptr[1 * nc + 0] * x[0]; + case NSKIP( 3, 2 ): + x[2] = b[2] - lptr[2 * nc + 0] * x[0] - lptr[2 * nc + 1] * x[1]; + return; + case NSKIP( 4, 0 ): + x[0] = b[0]; + case NSKIP( 4, 1 ): + x[1] = b[1] - lptr[1 * nc + 0] * x[0]; + case NSKIP( 4, 2 ): + x[2] = b[2] - lptr[2 * nc + 0] * x[0] - lptr[2 * nc + 1] * x[1]; + case NSKIP( 4, 3 ): + x[3] = b[3] - lptr[3 * nc + 0] * x[0] - lptr[3 * nc + 1] * x[1] - lptr[3 * nc + 2] * x[2]; + return; + case NSKIP( 5, 0 ): + x[0] = b[0]; + case NSKIP( 5, 1 ): + x[1] = b[1] - lptr[1 * nc + 0] * x[0]; + case NSKIP( 5, 2 ): + x[2] = b[2] - lptr[2 * nc + 0] * x[0] - lptr[2 * nc + 1] * x[1]; + case NSKIP( 5, 3 ): + x[3] = b[3] - lptr[3 * nc + 0] * x[0] - lptr[3 * nc + 1] * x[1] - lptr[3 * nc + 2] * x[2]; + case NSKIP( 5, 4 ): + x[4] = b[4] - lptr[4 * nc + 0] * x[0] - lptr[4 * nc + 1] * x[1] - lptr[4 * nc + 2] * x[2] - lptr[4 * nc + 3] * x[3]; + return; + case NSKIP( 6, 0 ): + x[0] = b[0]; + case NSKIP( 6, 1 ): + x[1] = b[1] - lptr[1 * nc + 0] * x[0]; + case NSKIP( 6, 2 ): + x[2] = b[2] - lptr[2 * nc + 0] * x[0] - lptr[2 * nc + 1] * x[1]; + case NSKIP( 6, 3 ): + x[3] = b[3] - lptr[3 * nc + 0] * x[0] - lptr[3 * nc + 1] * x[1] - lptr[3 * nc + 2] * x[2]; + case NSKIP( 6, 4 ): + x[4] = b[4] - lptr[4 * nc + 0] * x[0] - lptr[4 * nc + 1] * x[1] - lptr[4 * nc + 2] * x[2] - lptr[4 * nc + 3] * x[3]; + case NSKIP( 6, 5 ): + x[5] = b[5] - lptr[5 * nc + 0] * x[0] - lptr[5 * nc + 1] * x[1] - lptr[5 * nc + 2] * x[2] - lptr[5 * nc + 3] * x[3] - lptr[5 * nc + 4] * x[4]; + return; + case NSKIP( 7, 0 ): + x[0] = b[0]; + case NSKIP( 7, 1 ): + x[1] = b[1] - lptr[1 * nc + 0] * x[0]; + case NSKIP( 7, 2 ): + x[2] = b[2] - lptr[2 * nc + 0] * x[0] - lptr[2 * nc + 1] * x[1]; + case NSKIP( 7, 3 ): + x[3] = b[3] - lptr[3 * nc + 0] * x[0] - lptr[3 * nc + 1] * x[1] - lptr[3 * nc + 2] * x[2]; + case NSKIP( 7, 4 ): + x[4] = b[4] - lptr[4 * nc + 0] * x[0] - lptr[4 * nc + 1] * x[1] - lptr[4 * nc + 2] * x[2] - lptr[4 * nc + 3] * x[3]; + case NSKIP( 7, 5 ): + x[5] = b[5] - lptr[5 * nc + 0] * x[0] - lptr[5 * nc + 1] * x[1] - lptr[5 * nc + 2] * x[2] - lptr[5 * nc + 3] * x[3] - lptr[5 * nc + 4] * x[4]; + case NSKIP( 7, 6 ): + x[6] = b[6] - lptr[6 * nc + 0] * x[0] - lptr[6 * nc + 1] * x[1] - lptr[6 * nc + 2] * x[2] - lptr[6 * nc + 3] * x[3] - lptr[6 * nc + 4] * x[4] - lptr[6 * nc + 5] * x[5]; + return; } return; } // process first 4 rows - switch( skip ) { - case 0: x[0] = b[0]; - case 1: x[1] = b[1] - lptr[1*nc+0] * x[0]; - case 2: x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - case 3: x[3] = b[3] - lptr[3*nc+0] * x[0] - lptr[3*nc+1] * x[1] - lptr[3*nc+2] * x[2]; - skip = 4; + switch ( skip ) { + case 0: + x[0] = b[0]; + case 1: + x[1] = b[1] - lptr[1 * nc + 0] * x[0]; + case 2: + x[2] = b[2] - lptr[2 * nc + 0] * x[0] - lptr[2 * nc + 1] * x[1]; + case 3: + x[3] = b[3] - lptr[3 * nc + 0] * x[0] - lptr[3 * nc + 1] * x[1] - lptr[3 * nc + 2] * x[2]; + skip = 4; } lptr = L[skip]; @@ -10233,56 +10358,56 @@ void VPCALL idSIMD_SSE::MatX_LowerTriangularSolve( const idMatX &L, float *x, co jnz loopurow // aligned - looprow: + looprow: mov ecx, eax neg ecx movaps xmm0, [esi+ecx] mulps xmm0, [edi+ecx] add ecx, 12*4 jg donedot8 - dot8: - movaps xmm1, [esi+ecx-(8*4)] - mulps xmm1, [edi+ecx-(8*4)] + dot8: + movaps xmm1, [esi+ecx-( 8*4 )] + mulps xmm1, [edi+ecx-( 8*4 )] addps xmm0, xmm1 - movaps xmm3, [esi+ecx-(4*4)] - mulps xmm3, [edi+ecx-(4*4)] + movaps xmm3, [esi+ecx-( 4*4 )] + mulps xmm3, [edi+ecx-( 4*4 )] addps xmm0, xmm3 add ecx, 8*4 jle dot8 - donedot8: + donedot8: sub ecx, 4*4 jg donedot4 - //dot4: - movaps xmm1, [esi+ecx-(4*4)] - mulps xmm1, [edi+ecx-(4*4)] + //dot4: + movaps xmm1, [esi+ecx-( 4*4 )] + mulps xmm1, [edi+ecx-( 4*4 )] addps xmm0, xmm1 add ecx, 4*4 - donedot4: + donedot4: movhlps xmm1, xmm0 addps xmm0, xmm1 movaps xmm1, xmm0 shufps xmm1, xmm1, R_SHUFFLEPS( 1, 0, 0, 0 ) addss xmm0, xmm1 - sub ecx, 4*4 + sub ecx, 4 * 4 jz dot0 add ecx, 4 jz dot1 add ecx, 4 jz dot2 - //dot3: - movss xmm1, [esi-(3*4)] - mulss xmm1, [edi-(3*4)] + //dot3: + movss xmm1, [esi - ( 3 * 4 )] + mulss xmm1, [edi - ( 3 * 4 )] addss xmm0, xmm1 - dot2: - movss xmm3, [esi-(2*4)] - mulss xmm3, [edi-(2*4)] + dot2: + movss xmm3, [esi - ( 2 * 4 )] + mulss xmm3, [edi - ( 2 * 4 )] addss xmm0, xmm3 - dot1: - movss xmm5, [esi-(1*4)] - mulss xmm5, [edi-(1*4)] + dot1: + movss xmm5, [esi - ( 1 * 4 )] + mulss xmm5, [edi - ( 1 * 4 )] addss xmm0, xmm5 - dot0: - movss xmm1, [ebx+eax] + dot0: + movss xmm1, [ebx + eax] subss xmm1, xmm0 movss [esi], xmm1 add eax, 4 @@ -10296,63 +10421,63 @@ void VPCALL idSIMD_SSE::MatX_LowerTriangularSolve( const idMatX &L, float *x, co jmp looprow // unaligned - loopurow: + loopurow: mov ecx, eax neg ecx - movups xmm0, [esi+ecx] - movups xmm1, [edi+ecx] + movups xmm0, [esi + ecx] + movups xmm1, [edi + ecx] mulps xmm0, xmm1 - add ecx, 12*4 + add ecx, 12 * 4 jg doneudot8 - udot8: - movups xmm1, [esi+ecx-(8*4)] - movups xmm2, [edi+ecx-(8*4)] + udot8: + movups xmm1, [esi + ecx - ( 8 * 4 )] + movups xmm2, [edi + ecx - ( 8 * 4 )] mulps xmm1, xmm2 addps xmm0, xmm1 - movups xmm3, [esi+ecx-(4*4)] - movups xmm4, [edi+ecx-(4*4)] + movups xmm3, [esi + ecx - ( 4 * 4 )] + movups xmm4, [edi + ecx - ( 4 * 4 )] mulps xmm3, xmm4 addps xmm0, xmm3 - add ecx, 8*4 + add ecx, 8 * 4 jle udot8 - doneudot8: - sub ecx, 4*4 + doneudot8: + sub ecx, 4 * 4 jg doneudot4 - //udot4: - movups xmm1, [esi+ecx-(4*4)] - movups xmm2, [edi+ecx-(4*4)] + //udot4: + movups xmm1, [esi + ecx - ( 4 * 4 )] + movups xmm2, [edi + ecx - ( 4 * 4 )] mulps xmm1, xmm2 addps xmm0, xmm1 - add ecx, 4*4 - doneudot4: + add ecx, 4 * 4 + doneudot4: movhlps xmm1, xmm0 addps xmm0, xmm1 movaps xmm1, xmm0 shufps xmm1, xmm1, R_SHUFFLEPS( 1, 0, 0, 0 ) addss xmm0, xmm1 - sub ecx, 4*4 + sub ecx, 4 * 4 jz udot0 add ecx, 4 jz udot1 add ecx, 4 jz udot2 - //udot3: - movss xmm1, [esi-(3*4)] - movss xmm2, [edi-(3*4)] + //udot3: + movss xmm1, [esi - ( 3 * 4 )] + movss xmm2, [edi - ( 3 * 4 )] mulss xmm1, xmm2 addss xmm0, xmm1 - udot2: - movss xmm3, [esi-(2*4)] - movss xmm4, [edi-(2*4)] + udot2: + movss xmm3, [esi - ( 2 * 4 )] + movss xmm4, [edi - ( 2 * 4 )] mulss xmm3, xmm4 addss xmm0, xmm3 - udot1: - movss xmm5, [esi-(1*4)] - movss xmm6, [edi-(1*4)] + udot1: + movss xmm5, [esi - ( 1 * 4 )] + movss xmm6, [edi - ( 1 * 4 )] mulss xmm5, xmm6 addss xmm0, xmm5 - udot0: - movss xmm1, [ebx+eax] + udot0: + movss xmm1, [ebx + eax] subss xmm1, xmm0 movss [esi], xmm1 add eax, 4 @@ -10364,7 +10489,7 @@ void VPCALL idSIMD_SSE::MatX_LowerTriangularSolve( const idMatX &L, float *x, co add edi, ecx add edi, 4 jmp loopurow - done: + done: pop ebx } } @@ -10387,51 +10512,51 @@ void VPCALL idSIMD_SSE::MatX_LowerTriangularSolveTranspose( const idMatX &L, flo // unrolled cases for n < 8 if ( n < 8 ) { - switch( n ) { - case 0: - return; - case 1: - x[0] = b[0]; - return; - case 2: - x[1] = b[1]; - x[0] = b[0] - lptr[1*nc+0] * x[1]; - return; - case 3: - x[2] = b[2]; - x[1] = b[1] - lptr[2*nc+1] * x[2]; - x[0] = b[0] - lptr[2*nc+0] * x[2] - lptr[1*nc+0] * x[1]; - return; - case 4: - x[3] = b[3]; - x[2] = b[2] - lptr[3*nc+2] * x[3]; - x[1] = b[1] - lptr[3*nc+1] * x[3] - lptr[2*nc+1] * x[2]; - x[0] = b[0] - lptr[3*nc+0] * x[3] - lptr[2*nc+0] * x[2] - lptr[1*nc+0] * x[1]; - return; - case 5: - x[4] = b[4]; - x[3] = b[3] - lptr[4*nc+3] * x[4]; - x[2] = b[2] - lptr[4*nc+2] * x[4] - lptr[3*nc+2] * x[3]; - x[1] = b[1] - lptr[4*nc+1] * x[4] - lptr[3*nc+1] * x[3] - lptr[2*nc+1] * x[2]; - x[0] = b[0] - lptr[4*nc+0] * x[4] - lptr[3*nc+0] * x[3] - lptr[2*nc+0] * x[2] - lptr[1*nc+0] * x[1]; - return; - case 6: - x[5] = b[5]; - x[4] = b[4] - lptr[5*nc+4] * x[5]; - x[3] = b[3] - lptr[5*nc+3] * x[5] - lptr[4*nc+3] * x[4]; - x[2] = b[2] - lptr[5*nc+2] * x[5] - lptr[4*nc+2] * x[4] - lptr[3*nc+2] * x[3]; - x[1] = b[1] - lptr[5*nc+1] * x[5] - lptr[4*nc+1] * x[4] - lptr[3*nc+1] * x[3] - lptr[2*nc+1] * x[2]; - x[0] = b[0] - lptr[5*nc+0] * x[5] - lptr[4*nc+0] * x[4] - lptr[3*nc+0] * x[3] - lptr[2*nc+0] * x[2] - lptr[1*nc+0] * x[1]; - return; - case 7: - x[6] = b[6]; - x[5] = b[5] - lptr[6*nc+5] * x[6]; - x[4] = b[4] - lptr[6*nc+4] * x[6] - lptr[5*nc+4] * x[5]; - x[3] = b[3] - lptr[6*nc+3] * x[6] - lptr[5*nc+3] * x[5] - lptr[4*nc+3] * x[4]; - x[2] = b[2] - lptr[6*nc+2] * x[6] - lptr[5*nc+2] * x[5] - lptr[4*nc+2] * x[4] - lptr[3*nc+2] * x[3]; - x[1] = b[1] - lptr[6*nc+1] * x[6] - lptr[5*nc+1] * x[5] - lptr[4*nc+1] * x[4] - lptr[3*nc+1] * x[3] - lptr[2*nc+1] * x[2]; - x[0] = b[0] - lptr[6*nc+0] * x[6] - lptr[5*nc+0] * x[5] - lptr[4*nc+0] * x[4] - lptr[3*nc+0] * x[3] - lptr[2*nc+0] * x[2] - lptr[1*nc+0] * x[1]; - return; + switch ( n ) { + case 0: + return; + case 1: + x[0] = b[0]; + return; + case 2: + x[1] = b[1]; + x[0] = b[0] - lptr[1 * nc + 0] * x[1]; + return; + case 3: + x[2] = b[2]; + x[1] = b[1] - lptr[2 * nc + 1] * x[2]; + x[0] = b[0] - lptr[2 * nc + 0] * x[2] - lptr[1 * nc + 0] * x[1]; + return; + case 4: + x[3] = b[3]; + x[2] = b[2] - lptr[3 * nc + 2] * x[3]; + x[1] = b[1] - lptr[3 * nc + 1] * x[3] - lptr[2 * nc + 1] * x[2]; + x[0] = b[0] - lptr[3 * nc + 0] * x[3] - lptr[2 * nc + 0] * x[2] - lptr[1 * nc + 0] * x[1]; + return; + case 5: + x[4] = b[4]; + x[3] = b[3] - lptr[4 * nc + 3] * x[4]; + x[2] = b[2] - lptr[4 * nc + 2] * x[4] - lptr[3 * nc + 2] * x[3]; + x[1] = b[1] - lptr[4 * nc + 1] * x[4] - lptr[3 * nc + 1] * x[3] - lptr[2 * nc + 1] * x[2]; + x[0] = b[0] - lptr[4 * nc + 0] * x[4] - lptr[3 * nc + 0] * x[3] - lptr[2 * nc + 0] * x[2] - lptr[1 * nc + 0] * x[1]; + return; + case 6: + x[5] = b[5]; + x[4] = b[4] - lptr[5 * nc + 4] * x[5]; + x[3] = b[3] - lptr[5 * nc + 3] * x[5] - lptr[4 * nc + 3] * x[4]; + x[2] = b[2] - lptr[5 * nc + 2] * x[5] - lptr[4 * nc + 2] * x[4] - lptr[3 * nc + 2] * x[3]; + x[1] = b[1] - lptr[5 * nc + 1] * x[5] - lptr[4 * nc + 1] * x[4] - lptr[3 * nc + 1] * x[3] - lptr[2 * nc + 1] * x[2]; + x[0] = b[0] - lptr[5 * nc + 0] * x[5] - lptr[4 * nc + 0] * x[4] - lptr[3 * nc + 0] * x[3] - lptr[2 * nc + 0] * x[2] - lptr[1 * nc + 0] * x[1]; + return; + case 7: + x[6] = b[6]; + x[5] = b[5] - lptr[6 * nc + 5] * x[6]; + x[4] = b[4] - lptr[6 * nc + 4] * x[6] - lptr[5 * nc + 4] * x[5]; + x[3] = b[3] - lptr[6 * nc + 3] * x[6] - lptr[5 * nc + 3] * x[5] - lptr[4 * nc + 3] * x[4]; + x[2] = b[2] - lptr[6 * nc + 2] * x[6] - lptr[5 * nc + 2] * x[5] - lptr[4 * nc + 2] * x[4] - lptr[3 * nc + 2] * x[3]; + x[1] = b[1] - lptr[6 * nc + 1] * x[6] - lptr[5 * nc + 1] * x[5] - lptr[4 * nc + 1] * x[4] - lptr[3 * nc + 1] * x[3] - lptr[2 * nc + 1] * x[2]; + x[0] = b[0] - lptr[6 * nc + 0] * x[6] - lptr[5 * nc + 0] * x[5] - lptr[4 * nc + 0] * x[4] - lptr[3 * nc + 0] * x[3] - lptr[2 * nc + 0] * x[2] - lptr[1 * nc + 0] * x[1]; + return; } return; } @@ -10461,49 +10586,49 @@ void VPCALL idSIMD_SSE::MatX_LowerTriangularSolveTranspose( const idMatX &L, flo mov ebx, b // ebx = b mov edx, nc // edx = nc*sizeof(float) shl edx, 2 - process4rows_1: + process4rows_1: movlps xmm0, [ebx+eax*4-16] // load b[i-2], b[i-1] movhps xmm0, [ebx+eax*4-8] // load b[i-4], b[i-3] xor ecx, ecx sub eax, m neg eax jz done4x4_1 - process4x4_1: // process 4x4 blocks + process4x4_1: // process 4x4 blocks movlps xmm2, [edi+0] movhps xmm2, [edi+8] add edi, edx movss xmm1, [esi+4*ecx+0] shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps xmm3, [edi+0] - movhps xmm3, [edi+8] + movlps xmm3, [edi + 0] + movhps xmm3, [edi + 8] add edi, edx mulps xmm1, xmm2 subps xmm0, xmm1 - movss xmm1, [esi+4*ecx+4] + movss xmm1, [esi + 4 * ecx + 4] shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps xmm4, [edi+0] - movhps xmm4, [edi+8] + movlps xmm4, [edi + 0] + movhps xmm4, [edi + 8] add edi, edx mulps xmm1, xmm3 subps xmm0, xmm1 - movss xmm1, [esi+4*ecx+8] + movss xmm1, [esi + 4 * ecx + 8] shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps xmm5, [edi+0] - movhps xmm5, [edi+8] + movlps xmm5, [edi + 0] + movhps xmm5, [edi + 8] add edi, edx mulps xmm1, xmm4 subps xmm0, xmm1 - movss xmm1, [esi+4*ecx+12] + movss xmm1, [esi + 4 * ecx + 12] shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) add ecx, 4 cmp ecx, eax mulps xmm1, xmm5 subps xmm0, xmm1 jl process4x4_1 - done4x4_1: // process left over of the 4 rows - movlps xmm2, [edi+0] - movhps xmm2, [edi+8] - movss xmm1, [esi+4*ecx] + done4x4_1: // process left over of the 4 rows + movlps xmm2, [edi + 0] + movhps xmm2, [edi + 8] + movss xmm1, [esi + 4 * ecx] shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm1, xmm2 subps xmm0, xmm1 @@ -10520,34 +10645,34 @@ void VPCALL idSIMD_SSE::MatX_LowerTriangularSolveTranspose( const idMatX &L, flo movaps xmm3, xmm0 shufps xmm3, xmm3, R_SHUFFLEPS( 3, 3, 3, 3 ) sub edi, edx - movss [esi-4], xmm3 // xptr[-1] = s3 + movss [esi - 4], xmm3 // xptr[-1] = s3 movss xmm4, xmm3 movss xmm5, xmm3 - mulss xmm3, [edi+8] // lptr[-1*nc+2] * s3 - mulss xmm4, [edi+4] // lptr[-1*nc+1] * s3 - mulss xmm5, [edi+0] // lptr[-1*nc+0] * s3 + mulss xmm3, [edi + 8] // lptr[-1*nc+2] * s3 + mulss xmm4, [edi + 4] // lptr[-1*nc+1] * s3 + mulss xmm5, [edi + 0] // lptr[-1*nc+0] * s3 subss xmm2, xmm3 - movss [esi-8], xmm2 // xptr[-2] = s2 + movss [esi - 8], xmm2 // xptr[-2] = s2 movss xmm6, xmm2 sub edi, edx subss xmm0, xmm5 subss xmm1, xmm4 - mulss xmm2, [edi+4] // lptr[-2*nc+1] * s2 - mulss xmm6, [edi+0] // lptr[-2*nc+0] * s2 + mulss xmm2, [edi + 4] // lptr[-2*nc+1] * s2 + mulss xmm6, [edi + 0] // lptr[-2*nc+0] * s2 subss xmm1, xmm2 - movss [esi-12], xmm1 // xptr[-3] = s1 + movss [esi - 12], xmm1 // xptr[-3] = s1 subss xmm0, xmm6 sub edi, edx cmp eax, 4 - mulss xmm1, [edi+0] // lptr[-3*nc+0] * s1 + mulss xmm1, [edi + 0] // lptr[-3*nc+0] * s1 subss xmm0, xmm1 - movss [esi-16], xmm0 // xptr[-4] = s0 + movss [esi - 16], xmm0 // xptr[-4] = s0 jl done4rows_1 sub edi, edx sub edi, 16 sub esi, 16 jmp process4rows_1 - done4rows_1: + done4rows_1: pop ebx } @@ -10563,39 +10688,39 @@ void VPCALL idSIMD_SSE::MatX_LowerTriangularSolveTranspose( const idMatX &L, flo mov ebx, b // ebx = b mov edx, nc // edx = nc*sizeof(float) shl edx, 2 - process4rows: + process4rows: movlps xmm0, [ebx+eax*4-16] // load b[i-2], b[i-1] movhps xmm0, [ebx+eax*4-8] // load b[i-4], b[i-3] sub eax, m jz done4x4 neg eax xor ecx, ecx - process4x4: // process 4x4 blocks + process4x4: // process 4x4 blocks movlps xmm2, [edi+0] movhps xmm2, [edi+8] add edi, edx movss xmm1, [esi+4*ecx+0] shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps xmm3, [edi+0] - movhps xmm3, [edi+8] + movlps xmm3, [edi + 0] + movhps xmm3, [edi + 8] add edi, edx mulps xmm1, xmm2 subps xmm0, xmm1 - movss xmm1, [esi+4*ecx+4] + movss xmm1, [esi + 4 * ecx + 4] shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps xmm4, [edi+0] - movhps xmm4, [edi+8] + movlps xmm4, [edi + 0] + movhps xmm4, [edi + 8] add edi, edx mulps xmm1, xmm3 subps xmm0, xmm1 - movss xmm1, [esi+4*ecx+8] + movss xmm1, [esi + 4 * ecx + 8] shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps xmm5, [edi+0] - movhps xmm5, [edi+8] + movlps xmm5, [edi + 0] + movhps xmm5, [edi + 8] add edi, edx mulps xmm1, xmm4 subps xmm0, xmm1 - movss xmm1, [esi+4*ecx+12] + movss xmm1, [esi + 4 * ecx + 12] shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) add ecx, 4 cmp ecx, eax @@ -10605,7 +10730,7 @@ void VPCALL idSIMD_SSE::MatX_LowerTriangularSolveTranspose( const idMatX &L, flo imul ecx, edx sub edi, ecx neg eax - done4x4: // process left over of the 4 rows + done4x4: // process left over of the 4 rows add eax, m sub eax, 4 movaps xmm1, xmm0 @@ -10615,44 +10740,44 @@ void VPCALL idSIMD_SSE::MatX_LowerTriangularSolveTranspose( const idMatX &L, flo movaps xmm3, xmm0 shufps xmm3, xmm3, R_SHUFFLEPS( 3, 3, 3, 3 ) sub edi, edx - movss [esi-4], xmm3 // xptr[-1] = s3 + movss [esi - 4], xmm3 // xptr[-1] = s3 movss xmm4, xmm3 movss xmm5, xmm3 - mulss xmm3, [edi+8] // lptr[-1*nc+2] * s3 - mulss xmm4, [edi+4] // lptr[-1*nc+1] * s3 - mulss xmm5, [edi+0] // lptr[-1*nc+0] * s3 + mulss xmm3, [edi + 8] // lptr[-1*nc+2] * s3 + mulss xmm4, [edi + 4] // lptr[-1*nc+1] * s3 + mulss xmm5, [edi + 0] // lptr[-1*nc+0] * s3 subss xmm2, xmm3 - movss [esi-8], xmm2 // xptr[-2] = s2 + movss [esi - 8], xmm2 // xptr[-2] = s2 movss xmm6, xmm2 sub edi, edx subss xmm0, xmm5 subss xmm1, xmm4 - mulss xmm2, [edi+4] // lptr[-2*nc+1] * s2 - mulss xmm6, [edi+0] // lptr[-2*nc+0] * s2 + mulss xmm2, [edi + 4] // lptr[-2*nc+1] * s2 + mulss xmm6, [edi + 0] // lptr[-2*nc+0] * s2 subss xmm1, xmm2 - movss [esi-12], xmm1 // xptr[-3] = s1 + movss [esi - 12], xmm1 // xptr[-3] = s1 subss xmm0, xmm6 sub edi, edx cmp eax, 4 - mulss xmm1, [edi+0] // lptr[-3*nc+0] * s1 + mulss xmm1, [edi + 0] // lptr[-3*nc+0] * s1 subss xmm0, xmm1 - movss [esi-16], xmm0 // xptr[-4] = s0 + movss [esi - 16], xmm0 // xptr[-4] = s0 jl done4rows sub edi, edx sub edi, 16 sub esi, 16 jmp process4rows - done4rows: + done4rows: pop ebx } } // process left over rows - for ( i = (m&3)-1; i >= 0; i-- ) { + for ( i = ( m & 3 ) - 1; i >= 0; i-- ) { s0 = b[i]; lptr = L[0] + i; for ( j = i + 1; j < n; j++ ) { - s0 -= lptr[j*nc] * x[j]; + s0 -= lptr[j * nc] * x[j]; } x[i] = s0; } @@ -10674,14 +10799,14 @@ void VPCALL idSIMD_SSE::MatX_LowerTriangularSolveTranspose( const idMatX &L, flo xptr = x + m; // process 4 rows at a time for ( i = m; i >= 4; i -= 4 ) { - s0 = b[i-4]; - s1 = b[i-3]; - s2 = b[i-2]; - s3 = b[i-1]; + s0 = b[i - 4]; + s1 = b[i - 3]; + s2 = b[i - 2]; + s3 = b[i - 1]; // process 4x4 blocks xptr2 = xptr; // x + i; lptr2 = lptr; // ptr = L[i] + i - 4; - for ( j = 0; j < m-i; j += 4 ) { + for ( j = 0; j < m - i; j += 4 ) { t = xptr2[0]; s0 -= lptr2[0] * t; s1 -= lptr2[1] * t; @@ -10743,14 +10868,14 @@ void VPCALL idSIMD_SSE::MatX_LowerTriangularSolveTranspose( const idMatX &L, flo xptr = x + m; // process 4 rows at a time for ( i = m; i >= 4; i -= 4 ) { - s0 = b[i-4]; - s1 = b[i-3]; - s2 = b[i-2]; - s3 = b[i-1]; + s0 = b[i - 4]; + s1 = b[i - 3]; + s2 = b[i - 2]; + s3 = b[i - 1]; // process 4x4 blocks xptr2 = xptr; // x + i; lptr2 = lptr; // ptr = L[i] + i - 4; - for ( j = 0; j < m-i; j += 4 ) { + for ( j = 0; j < m - i; j += 4 ) { t = xptr2[0]; s0 -= lptr2[0] * t; s1 -= lptr2[1] * t; @@ -10806,7 +10931,7 @@ void VPCALL idSIMD_SSE::MatX_LowerTriangularSolveTranspose( const idMatX &L, flo s0 = b[i]; lptr = L[0] + i; for ( j = i + 1; j < m; j++ ) { - s0 -= lptr[j*nc] * x[j]; + s0 -= lptr[j * nc] * x[j]; } x[i] = s0; } @@ -10830,8 +10955,8 @@ bool VPCALL idSIMD_SSE::MatX_LDLTFactor( idMatX &mat, idVecX &invDiag, const int float *v, *diag, *invDiagPtr, *mptr; double s0, s1, s2, sum, d; - v = (float *) _alloca16( n * sizeof( float ) ); - diag = (float *) _alloca16( n * sizeof( float ) ); + v = ( float * ) _alloca16( n * sizeof( float ) ); + diag = ( float * ) _alloca16( n * sizeof( float ) ); invDiagPtr = invDiag.ToFloatPtr(); nc = mat.GetNumColumns(); @@ -10859,12 +10984,13 @@ bool VPCALL idSIMD_SSE::MatX_LDLTFactor( idMatX &mat, idVecX &invDiag, const int mptr = mat[0]; for ( j = 1; j < n; j++ ) { - mptr[j*nc+0] = ( mptr[j*nc+0] ) * d; + mptr[j * nc + 0] = ( mptr[j * nc + 0] ) * d; } mptr = mat[1]; - v[0] = diag[0] * mptr[0]; s0 = v[0] * mptr[0]; + v[0] = diag[0] * mptr[0]; + s0 = v[0] * mptr[0]; sum = mptr[1] - s0; if ( sum == 0.0f ) { @@ -10881,13 +11007,15 @@ bool VPCALL idSIMD_SSE::MatX_LDLTFactor( idMatX &mat, idVecX &invDiag, const int mptr = mat[0]; for ( j = 2; j < n; j++ ) { - mptr[j*nc+1] = ( mptr[j*nc+1] - v[0] * mptr[j*nc+0] ) * d; + mptr[j * nc + 1] = ( mptr[j * nc + 1] - v[0] * mptr[j * nc + 0] ) * d; } mptr = mat[2]; - v[0] = diag[0] * mptr[0]; s0 = v[0] * mptr[0]; - v[1] = diag[1] * mptr[1]; s1 = v[1] * mptr[1]; + v[0] = diag[0] * mptr[0]; + s0 = v[0] * mptr[0]; + v[1] = diag[1] * mptr[1]; + s1 = v[1] * mptr[1]; sum = mptr[2] - s0 - s1; if ( sum == 0.0f ) { @@ -10904,14 +11032,17 @@ bool VPCALL idSIMD_SSE::MatX_LDLTFactor( idMatX &mat, idVecX &invDiag, const int mptr = mat[0]; for ( j = 3; j < n; j++ ) { - mptr[j*nc+2] = ( mptr[j*nc+2] - v[0] * mptr[j*nc+0] - v[1] * mptr[j*nc+1] ) * d; + mptr[j * nc + 2] = ( mptr[j * nc + 2] - v[0] * mptr[j * nc + 0] - v[1] * mptr[j * nc + 1] ) * d; } mptr = mat[3]; - v[0] = diag[0] * mptr[0]; s0 = v[0] * mptr[0]; - v[1] = diag[1] * mptr[1]; s1 = v[1] * mptr[1]; - v[2] = diag[2] * mptr[2]; s2 = v[2] * mptr[2]; + v[0] = diag[0] * mptr[0]; + s0 = v[0] * mptr[0]; + v[1] = diag[1] * mptr[1]; + s1 = v[1] * mptr[1]; + v[2] = diag[2] * mptr[2]; + s2 = v[2] * mptr[2]; sum = mptr[3] - s0 - s1 - s2; if ( sum == 0.0f ) { @@ -10928,7 +11059,7 @@ bool VPCALL idSIMD_SSE::MatX_LDLTFactor( idMatX &mat, idVecX &invDiag, const int mptr = mat[0]; for ( j = 4; j < n; j++ ) { - mptr[j*nc+3] = ( mptr[j*nc+3] - v[0] * mptr[j*nc+0] - v[1] * mptr[j*nc+1] - v[2] * mptr[j*nc+2] ) * d; + mptr[j * nc + 3] = ( mptr[j * nc + 3] - v[0] * mptr[j * nc + 0] - v[1] * mptr[j * nc + 1] - v[2] * mptr[j * nc + 2] ) * d; } int ncf = nc * sizeof( float ); @@ -10942,158 +11073,158 @@ bool VPCALL idSIMD_SSE::MatX_LDLTFactor( idMatX &mat, idVecX &invDiag, const int push ebx mov ebx, 4 - loopRow: - cmp ebx, n - jge done - - mov ecx, ebx // esi = i - shl ecx, 2 // esi = i * 4 - mov edx, diag // edx = diag - add edx, ecx // edx = &diag[i] - mov edi, ebx // edi = i - imul edi, ncf // edi = i * nc * sizeof( float ) - add edi, mptr // edi = mat[i] - add edi, ecx // edi = &mat[i][i] - mov esi, v // ecx = v - add esi, ecx // ecx = &v[i] - mov eax, invDiagPtr // eax = invDiagPtr - add eax, ecx // eax = &invDiagPtr[i] - neg ecx - - movaps xmm0, [edx+ecx] - mulps xmm0, [edi+ecx] - movaps [esi+ecx], xmm0 - mulps xmm0, [edi+ecx] - add ecx, 12*4 - jg doneDot8 + loopRow: + cmp ebx, n + jge done + + mov ecx, ebx // esi = i + shl ecx, 2 // esi = i * 4 + mov edx, diag // edx = diag + add edx, ecx // edx = &diag[i] + mov edi, ebx // edi = i + imul edi, ncf // edi = i * nc * sizeof( float ) + add edi, mptr // edi = mat[i] + add edi, ecx // edi = &mat[i][i] + mov esi, v // ecx = v + add esi, ecx // ecx = &v[i] + mov eax, invDiagPtr // eax = invDiagPtr + add eax, ecx // eax = &invDiagPtr[i] + neg ecx + + movaps xmm0, [edx+ecx] + mulps xmm0, [edi+ecx] + movaps [esi+ecx], xmm0 + mulps xmm0, [edi+ecx] + add ecx, 12*4 + jg doneDot8 dot8: - movaps xmm1, [edx+ecx-(8*4)] - mulps xmm1, [edi+ecx-(8*4)] - movaps [esi+ecx-(8*4)], xmm1 - mulps xmm1, [edi+ecx-(8*4)] - addps xmm0, xmm1 - movaps xmm2, [edx+ecx-(4*4)] - mulps xmm2, [edi+ecx-(4*4)] - movaps [esi+ecx-(4*4)], xmm2 - mulps xmm2, [edi+ecx-(4*4)] - addps xmm0, xmm2 - add ecx, 8*4 - jle dot8 + movaps xmm1, [edx+ecx-( 8*4 )] + mulps xmm1, [edi+ecx-( 8*4 )] + movaps [esi+ecx-( 8*4 )], xmm1 + mulps xmm1, [edi+ecx-( 8*4 )] + addps xmm0, xmm1 + movaps xmm2, [edx+ecx-( 4*4 )] + mulps xmm2, [edi+ecx-( 4*4 )] + movaps [esi+ecx-( 4*4 )], xmm2 + mulps xmm2, [edi+ecx-( 4*4 )] + addps xmm0, xmm2 + add ecx, 8*4 + jle dot8 doneDot8: - sub ecx, 4*4 - jg doneDot4 - movaps xmm1, [edx+ecx-(4*4)] - mulps xmm1, [edi+ecx-(4*4)] - movaps [esi+ecx-(4*4)], xmm1 - mulps xmm1, [edi+ecx-(4*4)] - addps xmm0, xmm1 - add ecx, 4*4 + sub ecx, 4*4 + jg doneDot4 + movaps xmm1, [edx+ecx-( 4*4 )] + mulps xmm1, [edi+ecx-( 4*4 )] + movaps [esi+ecx-( 4*4 )], xmm1 + mulps xmm1, [edi+ecx-( 4*4 )] + addps xmm0, xmm1 + add ecx, 4*4 doneDot4: - sub ecx, 2*4 - jg doneDot2 - movlps xmm3, [edx+ecx-(2*4)] - movlps xmm4, [edi+ecx-(2*4)] - mulps xmm3, xmm4 - movlps [esi+ecx-(2*4)], xmm3 - mulps xmm3, xmm4 - addps xmm0, xmm3 - add ecx, 2*4 + sub ecx, 2*4 + jg doneDot2 + movlps xmm3, [edx+ecx-( 2*4 )] + movlps xmm4, [edi+ecx-( 2*4 )] + mulps xmm3, xmm4 + movlps [esi+ecx-( 2*4 )], xmm3 + mulps xmm3, xmm4 + addps xmm0, xmm3 + add ecx, 2*4 doneDot2: - sub ecx, 1*4 - jg doneDot1 - movss xmm3, [edx+ecx-(1*4)] - movss xmm4, [edi+ecx-(1*4)] - mulss xmm3, xmm4 - movss [esi+ecx-(1*4)], xmm3 - mulss xmm3, xmm4 - addss xmm0, xmm3 + sub ecx, 1*4 + jg doneDot1 + movss xmm3, [edx+ecx-( 1*4 )] + movss xmm4, [edi+ecx-( 1*4 )] + mulss xmm3, xmm4 + movss [esi+ecx-( 1*4 )], xmm3 + mulss xmm3, xmm4 + addss xmm0, xmm3 doneDot1: - movhlps xmm2, xmm0 - addps xmm0, xmm2 - movaps xmm2, xmm0 - shufps xmm2, xmm2, R_SHUFFLEPS( 1, 0, 0, 0 ) - addss xmm0, xmm2 - movss xmm1, [edi] - subss xmm1, xmm0 - movss [edi], xmm1 // mptr[i] = sum; - movss [edx], xmm1 // diag[i] = sum; - - // if ( sum == 0.0f ) return false; - movaps xmm2, xmm1 - cmpeqss xmm2, SIMD_SP_zero - andps xmm2, SIMD_SP_tiny - orps xmm1, xmm2 - - rcpss xmm7, xmm1 - mulss xmm1, xmm7 - mulss xmm1, xmm7 - addss xmm7, xmm7 - subss xmm7, xmm1 - movss [eax], xmm7 // invDiagPtr[i] = 1.0f / sum; - - mov edx, n // edx = n - sub edx, ebx // edx = n - i - dec edx // edx = n - i - 1 - jle doneSubRow // if ( i + 1 >= n ) return true; - - mov eax, ebx // eax = i - shl eax, 2 // eax = i * 4 - neg eax + movhlps xmm2, xmm0 + addps xmm0, xmm2 + movaps xmm2, xmm0 + shufps xmm2, xmm2, R_SHUFFLEPS( 1, 0, 0, 0 ) + addss xmm0, xmm2 + movss xmm1, [edi] + subss xmm1, xmm0 + movss [edi], xmm1 // mptr[i] = sum; + movss [edx], xmm1 // diag[i] = sum; + + // if ( sum == 0.0f ) return false; + movaps xmm2, xmm1 + cmpeqss xmm2, SIMD_SP_zero + andps xmm2, SIMD_SP_tiny + orps xmm1, xmm2 + + rcpss xmm7, xmm1 + mulss xmm1, xmm7 + mulss xmm1, xmm7 + addss xmm7, xmm7 + subss xmm7, xmm1 + movss [eax], xmm7 // invDiagPtr[i] = 1.0f / sum; + + mov edx, n // edx = n + sub edx, ebx // edx = n - i + dec edx // edx = n - i - 1 + jle doneSubRow // if ( i + 1 >= n ) return true; + + mov eax, ebx // eax = i + shl eax, 2 // eax = i * 4 + neg eax loopSubRow: - add edi, ncf - mov ecx, eax - movaps xmm0, [esi+ecx] - mulps xmm0, [edi+ecx] - add ecx, 12*4 - jg doneSubDot8 - subDot8: - movaps xmm1, [esi+ecx-(8*4)] - mulps xmm1, [edi+ecx-(8*4)] - addps xmm0, xmm1 - movaps xmm2, [esi+ecx-(4*4)] - mulps xmm2, [edi+ecx-(4*4)] - addps xmm0, xmm2 - add ecx, 8*4 - jle subDot8 - doneSubDot8: - sub ecx, 4*4 - jg doneSubDot4 - movaps xmm1, [esi+ecx-(4*4)] - mulps xmm1, [edi+ecx-(4*4)] - addps xmm0, xmm1 - add ecx, 4*4 - doneSubDot4: - sub ecx, 2*4 - jg doneSubDot2 - movlps xmm3, [esi+ecx-(2*4)] - movlps xmm4, [edi+ecx-(2*4)] - mulps xmm3, xmm4 - addps xmm0, xmm3 - add ecx, 2*4 - doneSubDot2: - sub ecx, 1*4 - jg doneSubDot1 - movss xmm3, [esi+ecx-(1*4)] - movss xmm4, [edi+ecx-(1*4)] - mulss xmm3, xmm4 - addss xmm0, xmm3 - doneSubDot1: - movhlps xmm2, xmm0 - addps xmm0, xmm2 - movaps xmm2, xmm0 - shufps xmm2, xmm2, R_SHUFFLEPS( 1, 0, 0, 0 ) - addss xmm0, xmm2 - movss xmm1, [edi] - subss xmm1, xmm0 - mulss xmm1, xmm7 - movss [edi], xmm1 - dec edx - jg loopSubRow + add edi, ncf + mov ecx, eax + movaps xmm0, [esi + ecx] + mulps xmm0, [edi + ecx] + add ecx, 12 * 4 + jg doneSubDot8 + subDot8: + movaps xmm1, [esi + ecx - ( 8 * 4 )] + mulps xmm1, [edi + ecx - ( 8 * 4 )] + addps xmm0, xmm1 + movaps xmm2, [esi + ecx - ( 4 * 4 )] + mulps xmm2, [edi + ecx - ( 4 * 4 )] + addps xmm0, xmm2 + add ecx, 8 * 4 + jle subDot8 + doneSubDot8: + sub ecx, 4 * 4 + jg doneSubDot4 + movaps xmm1, [esi + ecx - ( 4 * 4 )] + mulps xmm1, [edi + ecx - ( 4 * 4 )] + addps xmm0, xmm1 + add ecx, 4 * 4 + doneSubDot4: + sub ecx, 2 * 4 + jg doneSubDot2 + movlps xmm3, [esi + ecx - ( 2 * 4 )] + movlps xmm4, [edi + ecx - ( 2 * 4 )] + mulps xmm3, xmm4 + addps xmm0, xmm3 + add ecx, 2 * 4 + doneSubDot2: + sub ecx, 1 * 4 + jg doneSubDot1 + movss xmm3, [esi + ecx - ( 1 * 4 )] + movss xmm4, [edi + ecx - ( 1 * 4 )] + mulss xmm3, xmm4 + addss xmm0, xmm3 + doneSubDot1: + movhlps xmm2, xmm0 + addps xmm0, xmm2 + movaps xmm2, xmm0 + shufps xmm2, xmm2, R_SHUFFLEPS( 1, 0, 0, 0 ) + addss xmm0, xmm2 + movss xmm1, [edi] + subss xmm1, xmm0 + mulss xmm1, xmm7 + movss [edi], xmm1 + dec edx + jg loopSubRow doneSubRow: - inc ebx - jmp loopRow - done: + inc ebx + jmp loopRow + done: pop ebx } @@ -11105,8 +11236,8 @@ bool VPCALL idSIMD_SSE::MatX_LDLTFactor( idMatX &mat, idVecX &invDiag, const int float *v, *diag, *mptr; double s0, s1, s2, s3, sum, d; - v = (float *) _alloca16( n * sizeof( float ) ); - diag = (float *) _alloca16( n * sizeof( float ) ); + v = ( float * ) _alloca16( n * sizeof( float ) ); + diag = ( float * ) _alloca16( n * sizeof( float ) ); nc = mat.GetNumColumns(); @@ -11131,12 +11262,13 @@ bool VPCALL idSIMD_SSE::MatX_LDLTFactor( idMatX &mat, idVecX &invDiag, const int mptr = mat[0]; for ( j = 1; j < n; j++ ) { - mptr[j*nc+0] = ( mptr[j*nc+0] ) * d; + mptr[j * nc + 0] = ( mptr[j * nc + 0] ) * d; } mptr = mat[1]; - v[0] = diag[0] * mptr[0]; s0 = v[0] * mptr[0]; + v[0] = diag[0] * mptr[0]; + s0 = v[0] * mptr[0]; sum = mptr[1] - s0; if ( sum == 0.0f ) { @@ -11153,13 +11285,15 @@ bool VPCALL idSIMD_SSE::MatX_LDLTFactor( idMatX &mat, idVecX &invDiag, const int mptr = mat[0]; for ( j = 2; j < n; j++ ) { - mptr[j*nc+1] = ( mptr[j*nc+1] - v[0] * mptr[j*nc+0] ) * d; + mptr[j * nc + 1] = ( mptr[j * nc + 1] - v[0] * mptr[j * nc + 0] ) * d; } mptr = mat[2]; - v[0] = diag[0] * mptr[0]; s0 = v[0] * mptr[0]; - v[1] = diag[1] * mptr[1]; s1 = v[1] * mptr[1]; + v[0] = diag[0] * mptr[0]; + s0 = v[0] * mptr[0]; + v[1] = diag[1] * mptr[1]; + s1 = v[1] * mptr[1]; sum = mptr[2] - s0 - s1; if ( sum == 0.0f ) { @@ -11176,14 +11310,17 @@ bool VPCALL idSIMD_SSE::MatX_LDLTFactor( idMatX &mat, idVecX &invDiag, const int mptr = mat[0]; for ( j = 3; j < n; j++ ) { - mptr[j*nc+2] = ( mptr[j*nc+2] - v[0] * mptr[j*nc+0] - v[1] * mptr[j*nc+1] ) * d; + mptr[j * nc + 2] = ( mptr[j * nc + 2] - v[0] * mptr[j * nc + 0] - v[1] * mptr[j * nc + 1] ) * d; } mptr = mat[3]; - v[0] = diag[0] * mptr[0]; s0 = v[0] * mptr[0]; - v[1] = diag[1] * mptr[1]; s1 = v[1] * mptr[1]; - v[2] = diag[2] * mptr[2]; s2 = v[2] * mptr[2]; + v[0] = diag[0] * mptr[0]; + s0 = v[0] * mptr[0]; + v[1] = diag[1] * mptr[1]; + s1 = v[1] * mptr[1]; + v[2] = diag[2] * mptr[2]; + s2 = v[2] * mptr[2]; sum = mptr[3] - s0 - s1 - s2; if ( sum == 0.0f ) { @@ -11200,27 +11337,41 @@ bool VPCALL idSIMD_SSE::MatX_LDLTFactor( idMatX &mat, idVecX &invDiag, const int mptr = mat[0]; for ( j = 4; j < n; j++ ) { - mptr[j*nc+3] = ( mptr[j*nc+3] - v[0] * mptr[j*nc+0] - v[1] * mptr[j*nc+1] - v[2] * mptr[j*nc+2] ) * d; + mptr[j * nc + 3] = ( mptr[j * nc + 3] - v[0] * mptr[j * nc + 0] - v[1] * mptr[j * nc + 1] - v[2] * mptr[j * nc + 2] ) * d; } for ( i = 4; i < n; i++ ) { mptr = mat[i]; - v[0] = diag[0] * mptr[0]; s0 = v[0] * mptr[0]; - v[1] = diag[1] * mptr[1]; s1 = v[1] * mptr[1]; - v[2] = diag[2] * mptr[2]; s2 = v[2] * mptr[2]; - v[3] = diag[3] * mptr[3]; s3 = v[3] * mptr[3]; - for ( k = 4; k < i-3; k += 4 ) { - v[k+0] = diag[k+0] * mptr[k+0]; s0 += v[k+0] * mptr[k+0]; - v[k+1] = diag[k+1] * mptr[k+1]; s1 += v[k+1] * mptr[k+1]; - v[k+2] = diag[k+2] * mptr[k+2]; s2 += v[k+2] * mptr[k+2]; - v[k+3] = diag[k+3] * mptr[k+3]; s3 += v[k+3] * mptr[k+3]; + v[0] = diag[0] * mptr[0]; + s0 = v[0] * mptr[0]; + v[1] = diag[1] * mptr[1]; + s1 = v[1] * mptr[1]; + v[2] = diag[2] * mptr[2]; + s2 = v[2] * mptr[2]; + v[3] = diag[3] * mptr[3]; + s3 = v[3] * mptr[3]; + for ( k = 4; k < i - 3; k += 4 ) { + v[k + 0] = diag[k + 0] * mptr[k + 0]; + s0 += v[k + 0] * mptr[k + 0]; + v[k + 1] = diag[k + 1] * mptr[k + 1]; + s1 += v[k + 1] * mptr[k + 1]; + v[k + 2] = diag[k + 2] * mptr[k + 2]; + s2 += v[k + 2] * mptr[k + 2]; + v[k + 3] = diag[k + 3] * mptr[k + 3]; + s3 += v[k + 3] * mptr[k + 3]; } - switch( i - k ) { - case 3: v[k+2] = diag[k+2] * mptr[k+2]; s0 += v[k+2] * mptr[k+2]; - case 2: v[k+1] = diag[k+1] * mptr[k+1]; s1 += v[k+1] * mptr[k+1]; - case 1: v[k+0] = diag[k+0] * mptr[k+0]; s2 += v[k+0] * mptr[k+0]; + switch ( i - k ) { + case 3: + v[k + 2] = diag[k + 2] * mptr[k + 2]; + s0 += v[k + 2] * mptr[k + 2]; + case 2: + v[k + 1] = diag[k + 1] * mptr[k + 1]; + s1 += v[k + 1] * mptr[k + 1]; + case 1: + v[k + 0] = diag[k + 0] * mptr[k + 0]; + s2 += v[k + 0] * mptr[k + 0]; } sum = s3; sum += s2; @@ -11240,30 +11391,37 @@ bool VPCALL idSIMD_SSE::MatX_LDLTFactor( idMatX &mat, idVecX &invDiag, const int return true; } - mptr = mat[i+1]; - for ( j = i+1; j < n; j++ ) { + mptr = mat[i + 1]; + for ( j = i + 1; j < n; j++ ) { s0 = mptr[0] * v[0]; s1 = mptr[1] * v[1]; s2 = mptr[2] * v[2]; s3 = mptr[3] * v[3]; - for ( k = 4; k < i-7; k += 8 ) { - s0 += mptr[k+0] * v[k+0]; - s1 += mptr[k+1] * v[k+1]; - s2 += mptr[k+2] * v[k+2]; - s3 += mptr[k+3] * v[k+3]; - s0 += mptr[k+4] * v[k+4]; - s1 += mptr[k+5] * v[k+5]; - s2 += mptr[k+6] * v[k+6]; - s3 += mptr[k+7] * v[k+7]; + for ( k = 4; k < i - 7; k += 8 ) { + s0 += mptr[k + 0] * v[k + 0]; + s1 += mptr[k + 1] * v[k + 1]; + s2 += mptr[k + 2] * v[k + 2]; + s3 += mptr[k + 3] * v[k + 3]; + s0 += mptr[k + 4] * v[k + 4]; + s1 += mptr[k + 5] * v[k + 5]; + s2 += mptr[k + 6] * v[k + 6]; + s3 += mptr[k + 7] * v[k + 7]; } - switch( i - k ) { - case 7: s0 += mptr[k+6] * v[k+6]; - case 6: s1 += mptr[k+5] * v[k+5]; - case 5: s2 += mptr[k+4] * v[k+4]; - case 4: s3 += mptr[k+3] * v[k+3]; - case 3: s0 += mptr[k+2] * v[k+2]; - case 2: s1 += mptr[k+1] * v[k+1]; - case 1: s2 += mptr[k+0] * v[k+0]; + switch ( i - k ) { + case 7: + s0 += mptr[k + 6] * v[k + 6]; + case 6: + s1 += mptr[k + 5] * v[k + 5]; + case 5: + s2 += mptr[k + 4] * v[k + 4]; + case 4: + s3 += mptr[k + 3] * v[k + 3]; + case 3: + s0 += mptr[k + 2] * v[k + 2]; + case 2: + s1 += mptr[k + 1] * v[k + 1]; + case 1: + s2 += mptr[k + 0] * v[k + 0]; } sum = s3; sum += s2; @@ -11316,7 +11474,7 @@ void VPCALL idSIMD_SSE::BlendJoints( idJointQuat *joints, const idJointQuat *ble ALIGN16( float blendQuat3[4] ); for ( int j = 0; j < 4; j++ ) { - int n = index[i+j]; + int n = index[i + j]; jointVert0[j] = joints[n].t[0]; jointVert1[j] = joints[n].t[1]; @@ -11554,15 +11712,15 @@ void VPCALL idSIMD_SSE::BlendJoints( idJointQuat *joints, const idJointQuat *ble cosom[2] += jointQuat3[2] * blendQuat3[2]; cosom[3] += jointQuat3[3] * blendQuat3[3]; - signBit[0] = (*(unsigned int *)&cosom[0]) & ( 1 << 31 ); - signBit[1] = (*(unsigned int *)&cosom[1]) & ( 1 << 31 ); - signBit[2] = (*(unsigned int *)&cosom[2]) & ( 1 << 31 ); - signBit[3] = (*(unsigned int *)&cosom[3]) & ( 1 << 31 ); + signBit[0] = ( *( unsigned int * )&cosom[0] ) & ( 1 << 31 ); + signBit[1] = ( *( unsigned int * )&cosom[1] ) & ( 1 << 31 ); + signBit[2] = ( *( unsigned int * )&cosom[2] ) & ( 1 << 31 ); + signBit[3] = ( *( unsigned int * )&cosom[3] ) & ( 1 << 31 ); - (*(unsigned int *)&cosom[0]) ^= signBit[0]; - (*(unsigned int *)&cosom[1]) ^= signBit[1]; - (*(unsigned int *)&cosom[2]) ^= signBit[2]; - (*(unsigned int *)&cosom[3]) ^= signBit[3]; + ( *( unsigned int * )&cosom[0] ) ^= signBit[0]; + ( *( unsigned int * )&cosom[1] ) ^= signBit[1]; + ( *( unsigned int * )&cosom[2] ) ^= signBit[2]; + ( *( unsigned int * )&cosom[3] ) ^= signBit[3]; scale0[0] = 1.0f - cosom[0] * cosom[0]; scale0[1] = 1.0f - cosom[1] * cosom[1]; @@ -11609,10 +11767,10 @@ void VPCALL idSIMD_SSE::BlendJoints( idJointQuat *joints, const idJointQuat *ble scale1[2] = SSE_SinZeroHalfPI( omega1[2] ) * sinom[2]; scale1[3] = SSE_SinZeroHalfPI( omega1[3] ) * sinom[3]; - (*(unsigned int *)&scale1[0]) ^= signBit[0]; - (*(unsigned int *)&scale1[1]) ^= signBit[1]; - (*(unsigned int *)&scale1[2]) ^= signBit[2]; - (*(unsigned int *)&scale1[3]) ^= signBit[3]; + ( *( unsigned int * )&scale1[0] ) ^= signBit[0]; + ( *( unsigned int * )&scale1[1] ) ^= signBit[1]; + ( *( unsigned int * )&scale1[2] ) ^= signBit[2]; + ( *( unsigned int * )&scale1[3] ) ^= signBit[3]; jointQuat0[0] = scale0[0] * jointQuat0[0] + scale1[0] * blendQuat0[0]; jointQuat0[1] = scale0[1] * jointQuat0[1] + scale1[1] * blendQuat0[1]; @@ -11637,7 +11795,7 @@ void VPCALL idSIMD_SSE::BlendJoints( idJointQuat *joints, const idJointQuat *ble #endif for ( int j = 0; j < 4; j++ ) { - int n = index[i+j]; + int n = index[i + j]; joints[n].t[0] = jointVert0[j]; joints[n].t[1] = jointVert1[j]; @@ -11672,9 +11830,9 @@ void VPCALL idSIMD_SSE::BlendJoints( idJointQuat *joints, const idJointQuat *ble cosom = jointQuat.x * blendQuat.x + jointQuat.y * blendQuat.y + jointQuat.z * blendQuat.z + jointQuat.w * blendQuat.w; - signBit = (*(unsigned int *)&cosom) & ( 1 << 31 ); + signBit = ( *( unsigned int * )&cosom ) & ( 1 << 31 ); - (*(unsigned int *)&cosom) ^= signBit; + ( *( unsigned int * )&cosom ) ^= signBit; scale0 = 1.0f - cosom * cosom; scale0 = ( scale0 <= 0.0f ) ? SIMD_SP_tiny[0] : scale0; @@ -11683,7 +11841,7 @@ void VPCALL idSIMD_SSE::BlendJoints( idJointQuat *joints, const idJointQuat *ble scale0 = idMath::Sin16( ( 1.0f - lerp ) * omega ) * sinom; scale1 = idMath::Sin16( lerp * omega ) * sinom; - (*(unsigned int *)&scale1) ^= signBit; + ( *( unsigned int * )&scale1 ) ^= signBit; jointQuat.x = scale0 * jointQuat.x + scale1 * blendQuat.x; jointQuat.y = scale0 * jointQuat.y + scale1 * blendQuat.y; @@ -11701,16 +11859,16 @@ void VPCALL idSIMD_SSE::ConvertJointQuatsToJointMats( idJointMat *jointMats, con assert( sizeof( idJointQuat ) == JOINTQUAT_SIZE ); assert( sizeof( idJointMat ) == JOINTMAT_SIZE ); - assert( (int)(&((idJointQuat *)0)->t) == (int)(&((idJointQuat *)0)->q) + (int)sizeof( ((idJointQuat *)0)->q ) ); + assert( ( int )( &( ( idJointQuat * )0 )->t ) == ( int )( &( ( idJointQuat * )0 )->q ) + ( int )sizeof( ( ( idJointQuat * )0 )->q ) ); for ( int i = 0; i < numJoints; i++ ) { const float *q = jointQuats[i].q.ToFloatPtr(); float *m = jointMats[i].ToFloatPtr(); - m[0*4+3] = q[4]; - m[1*4+3] = q[5]; - m[2*4+3] = q[6]; + m[0 * 4 + 3] = q[4]; + m[1 * 4 + 3] = q[5]; + m[2 * 4 + 3] = q[6]; float x2 = q[0] + q[0]; float y2 = q[1] + q[1]; @@ -11721,33 +11879,33 @@ void VPCALL idSIMD_SSE::ConvertJointQuatsToJointMats( idJointMat *jointMats, con float yy = q[1] * y2; float zz = q[2] * z2; - m[0*4+0] = 1.0f - yy - zz; - m[1*4+1] = 1.0f - xx - zz; - m[2*4+2] = 1.0f - xx - yy; + m[0 * 4 + 0] = 1.0f - yy - zz; + m[1 * 4 + 1] = 1.0f - xx - zz; + m[2 * 4 + 2] = 1.0f - xx - yy; } { float yz = q[1] * z2; float wx = q[3] * x2; - m[2*4+1] = yz - wx; - m[1*4+2] = yz + wx; + m[2 * 4 + 1] = yz - wx; + m[1 * 4 + 2] = yz + wx; } { float xy = q[0] * y2; float wz = q[3] * z2; - m[1*4+0] = xy - wz; - m[0*4+1] = xy + wz; + m[1 * 4 + 0] = xy - wz; + m[0 * 4 + 1] = xy + wz; } { float xz = q[0] * z2; float wy = q[3] * y2; - m[0*4+2] = xz - wy; - m[2*4+0] = xz + wy; + m[0 * 4 + 2] = xz - wy; + m[2 * 4 + 0] = xz + wy; } } } @@ -11761,7 +11919,7 @@ void VPCALL idSIMD_SSE::ConvertJointMatsToJointQuats( idJointQuat *jointQuats, c assert( sizeof( idJointQuat ) == JOINTQUAT_SIZE ); assert( sizeof( idJointMat ) == JOINTMAT_SIZE ); - assert( (int)(&((idJointQuat *)0)->t) == (int)(&((idJointQuat *)0)->q) + (int)sizeof( ((idJointQuat *)0)->q ) ); + assert( ( int )( &( ( idJointQuat * )0 )->t ) == ( int )( &( ( idJointQuat * )0 )->q ) + ( int )sizeof( ( ( idJointQuat * )0 )->q ) ); #if 1 @@ -11777,7 +11935,7 @@ void VPCALL idSIMD_SSE::ConvertJointMatsToJointQuats( idJointQuat *jointQuats, c add esi, eax neg eax - loopMat4: + loopMat4: movss xmm5, [esi+eax+3*JOINTMAT_SIZE+0*16+0*4] movss xmm6, [esi+eax+3*JOINTMAT_SIZE+1*16+1*4] movss xmm7, [esi+eax+3*JOINTMAT_SIZE+2*16+2*4] @@ -11786,9 +11944,9 @@ void VPCALL idSIMD_SSE::ConvertJointMatsToJointQuats( idJointQuat *jointQuats, c shufps xmm6, xmm6, R_SHUFFLEPS( 3, 0, 1, 2 ) shufps xmm7, xmm7, R_SHUFFLEPS( 3, 0, 1, 2 ) - movss xmm0, [esi+eax+2*JOINTMAT_SIZE+0*16+0*4] - movss xmm1, [esi+eax+2*JOINTMAT_SIZE+1*16+1*4] - movss xmm2, [esi+eax+2*JOINTMAT_SIZE+2*16+2*4] + movss xmm0, [esi + eax + 2 * JOINTMAT_SIZE + 0 * 16 + 0 * 4] + movss xmm1, [esi + eax + 2 * JOINTMAT_SIZE + 1 * 16 + 1 * 4] + movss xmm2, [esi + eax + 2 * JOINTMAT_SIZE + 2 * 16 + 2 * 4] movss xmm5, xmm0 movss xmm6, xmm1 @@ -11798,9 +11956,9 @@ void VPCALL idSIMD_SSE::ConvertJointMatsToJointQuats( idJointQuat *jointQuats, c shufps xmm6, xmm6, R_SHUFFLEPS( 3, 0, 1, 2 ) shufps xmm7, xmm7, R_SHUFFLEPS( 3, 0, 1, 2 ) - movss xmm0, [esi+eax+1*JOINTMAT_SIZE+0*16+0*4] - movss xmm1, [esi+eax+1*JOINTMAT_SIZE+1*16+1*4] - movss xmm2, [esi+eax+1*JOINTMAT_SIZE+2*16+2*4] + movss xmm0, [esi + eax + 1 * JOINTMAT_SIZE + 0 * 16 + 0 * 4] + movss xmm1, [esi + eax + 1 * JOINTMAT_SIZE + 1 * 16 + 1 * 4] + movss xmm2, [esi + eax + 1 * JOINTMAT_SIZE + 2 * 16 + 2 * 4] movss xmm5, xmm0 movss xmm6, xmm1 @@ -11810,9 +11968,9 @@ void VPCALL idSIMD_SSE::ConvertJointMatsToJointQuats( idJointQuat *jointQuats, c shufps xmm6, xmm6, R_SHUFFLEPS( 3, 0, 1, 2 ) shufps xmm7, xmm7, R_SHUFFLEPS( 3, 0, 1, 2 ) - movss xmm0, [esi+eax+0*JOINTMAT_SIZE+0*16+0*4] - movss xmm1, [esi+eax+0*JOINTMAT_SIZE+1*16+1*4] - movss xmm2, [esi+eax+0*JOINTMAT_SIZE+2*16+2*4] + movss xmm0, [esi + eax + 0 * JOINTMAT_SIZE + 0 * 16 + 0 * 4] + movss xmm1, [esi + eax + 0 * JOINTMAT_SIZE + 1 * 16 + 1 * 4] + movss xmm2, [esi + eax + 0 * JOINTMAT_SIZE + 2 * 16 + 2 * 4] movss xmm5, xmm0 movss xmm6, xmm1 @@ -11884,38 +12042,38 @@ void VPCALL idSIMD_SSE::ConvertJointMatsToJointQuats( idJointQuat *jointQuats, c // ------------------- - add edi, 4*JOINTQUAT_SIZE + add edi, 4 * JOINTQUAT_SIZE - movzx ecx, byte ptr shuffle[0*4+0] // ecx = k0 - movss [edi+ecx*4-4*JOINTQUAT_SIZE], xmm7 // q[k0] = s * t; + movzx ecx, byte ptr shuffle[0 * 4 + 0] // ecx = k0 + movss [edi + ecx * 4 - 4 * JOINTQUAT_SIZE], xmm7 // q[k0] = s * t; - movzx edx, byte ptr shuffle[0*4+1] // edx = k1 - movss xmm4, [esi+eax+0*JOINTMAT_SIZE+1*16+0*4] + movzx edx, byte ptr shuffle[0 * 4 + 1] // edx = k1 + movss xmm4, [esi + eax + 0 * JOINTMAT_SIZE + 1 * 16 + 0 * 4] xorps xmm4, xmm2 - subss xmm4, [esi+eax+0*JOINTMAT_SIZE+0*16+1*4] + subss xmm4, [esi + eax + 0 * JOINTMAT_SIZE + 0 * 16 + 1 * 4] mulss xmm4, xmm6 - movss [edi+edx*4-4*JOINTQUAT_SIZE], xmm4 // q[k1] = ( m[0 * 4 + 1] - s2 * m[1 * 4 + 0] ) * s; + movss [edi + edx * 4 - 4 * JOINTQUAT_SIZE], xmm4 // q[k1] = ( m[0 * 4 + 1] - s2 * m[1 * 4 + 0] ) * s; - movzx ecx, byte ptr shuffle[0*4+2] // ecx = k2 - movss xmm3, [esi+eax+0*JOINTMAT_SIZE+0*16+2*4] + movzx ecx, byte ptr shuffle[0 * 4 + 2] // ecx = k2 + movss xmm3, [esi + eax + 0 * JOINTMAT_SIZE + 0 * 16 + 2 * 4] xorps xmm3, xmm1 - subss xmm3, [esi+eax+0*JOINTMAT_SIZE+2*16+0*4] + subss xmm3, [esi + eax + 0 * JOINTMAT_SIZE + 2 * 16 + 0 * 4] mulss xmm3, xmm6 - movss [edi+ecx*4-4*JOINTQUAT_SIZE], xmm3 // q[k2] = ( m[2 * 4 + 0] - s1 * m[0 * 4 + 2] ) * s; + movss [edi + ecx * 4 - 4 * JOINTQUAT_SIZE], xmm3 // q[k2] = ( m[2 * 4 + 0] - s1 * m[0 * 4 + 2] ) * s; - movzx edx, byte ptr shuffle[0*4+3] // edx = k3 - movss xmm4, [esi+eax+0*JOINTMAT_SIZE+2*16+1*4] + movzx edx, byte ptr shuffle[0 * 4 + 3] // edx = k3 + movss xmm4, [esi + eax + 0 * JOINTMAT_SIZE + 2 * 16 + 1 * 4] xorps xmm4, xmm0 - subss xmm4, [esi+eax+0*JOINTMAT_SIZE+1*16+2*4] + subss xmm4, [esi + eax + 0 * JOINTMAT_SIZE + 1 * 16 + 2 * 4] mulss xmm4, xmm6 - movss [edi+edx*4-4*JOINTQUAT_SIZE], xmm4 // q[k3] = ( m[1 * 4 + 2] - s0 * m[2 * 4 + 1] ) * s; + movss [edi + edx * 4 - 4 * JOINTQUAT_SIZE], xmm4 // q[k3] = ( m[1 * 4 + 2] - s0 * m[2 * 4 + 1] ) * s; - mov ecx, [esi+eax+0*JOINTMAT_SIZE+0*16+3*4] - mov [edi-4*JOINTQUAT_SIZE+16], ecx // q[4] = m[0 * 4 + 3]; - mov edx, [esi+eax+0*JOINTMAT_SIZE+1*16+3*4] - mov [edi-4*JOINTQUAT_SIZE+20], edx // q[5] = m[1 * 4 + 3]; - mov ecx, [esi+eax+0*JOINTMAT_SIZE+2*16+3*4] - mov [edi-4*JOINTQUAT_SIZE+24], ecx // q[6] = m[2 * 4 + 3]; + mov ecx, [esi + eax + 0 * JOINTMAT_SIZE + 0 * 16 + 3 * 4] + mov [edi - 4 * JOINTQUAT_SIZE + 16], ecx // q[4] = m[0 * 4 + 3]; + mov edx, [esi + eax + 0 * JOINTMAT_SIZE + 1 * 16 + 3 * 4] + mov [edi - 4 * JOINTQUAT_SIZE + 20], edx // q[5] = m[1 * 4 + 3]; + mov ecx, [esi + eax + 0 * JOINTMAT_SIZE + 2 * 16 + 3 * 4] + mov [edi - 4 * JOINTQUAT_SIZE + 24], ecx // q[6] = m[2 * 4 + 3]; shufps xmm6, xmm6, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm7, xmm7, R_SHUFFLEPS( 1, 2, 3, 0 ) @@ -11923,36 +12081,36 @@ void VPCALL idSIMD_SSE::ConvertJointMatsToJointQuats( idJointQuat *jointQuats, c shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - movzx ecx, byte ptr shuffle[1*4+0] // ecx = k0 - movss [edi+ecx*4-3*JOINTQUAT_SIZE], xmm7 // q[k0] = s * t; + movzx ecx, byte ptr shuffle[1 * 4 + 0] // ecx = k0 + movss [edi + ecx * 4 - 3 * JOINTQUAT_SIZE], xmm7 // q[k0] = s * t; - movzx edx, byte ptr shuffle[1*4+1] // edx = k1 - movss xmm4, [esi+eax+1*JOINTMAT_SIZE+1*16+0*4] + movzx edx, byte ptr shuffle[1 * 4 + 1] // edx = k1 + movss xmm4, [esi + eax + 1 * JOINTMAT_SIZE + 1 * 16 + 0 * 4] xorps xmm4, xmm2 - subss xmm4, [esi+eax+1*JOINTMAT_SIZE+0*16+1*4] + subss xmm4, [esi + eax + 1 * JOINTMAT_SIZE + 0 * 16 + 1 * 4] mulss xmm4, xmm6 - movss [edi+edx*4-3*JOINTQUAT_SIZE], xmm4 // q[k1] = ( m[0 * 4 + 1] - s2 * m[1 * 4 + 0] ) * s; + movss [edi + edx * 4 - 3 * JOINTQUAT_SIZE], xmm4 // q[k1] = ( m[0 * 4 + 1] - s2 * m[1 * 4 + 0] ) * s; - movzx ecx, byte ptr shuffle[1*4+2] // ecx = k2 - movss xmm3, [esi+eax+1*JOINTMAT_SIZE+0*16+2*4] + movzx ecx, byte ptr shuffle[1 * 4 + 2] // ecx = k2 + movss xmm3, [esi + eax + 1 * JOINTMAT_SIZE + 0 * 16 + 2 * 4] xorps xmm3, xmm1 - subss xmm3, [esi+eax+1*JOINTMAT_SIZE+2*16+0*4] + subss xmm3, [esi + eax + 1 * JOINTMAT_SIZE + 2 * 16 + 0 * 4] mulss xmm3, xmm6 - movss [edi+ecx*4-3*JOINTQUAT_SIZE], xmm3 // q[k2] = ( m[2 * 4 + 0] - s1 * m[0 * 4 + 2] ) * s; + movss [edi + ecx * 4 - 3 * JOINTQUAT_SIZE], xmm3 // q[k2] = ( m[2 * 4 + 0] - s1 * m[0 * 4 + 2] ) * s; - movzx edx, byte ptr shuffle[1*4+3] // edx = k3 - movss xmm4, [esi+eax+1*JOINTMAT_SIZE+2*16+1*4] + movzx edx, byte ptr shuffle[1 * 4 + 3] // edx = k3 + movss xmm4, [esi + eax + 1 * JOINTMAT_SIZE + 2 * 16 + 1 * 4] xorps xmm4, xmm0 - subss xmm4, [esi+eax+1*JOINTMAT_SIZE+1*16+2*4] + subss xmm4, [esi + eax + 1 * JOINTMAT_SIZE + 1 * 16 + 2 * 4] mulss xmm4, xmm6 - movss [edi+edx*4-3*JOINTQUAT_SIZE], xmm4 // q[k3] = ( m[1 * 4 + 2] - s0 * m[2 * 4 + 1] ) * s; + movss [edi + edx * 4 - 3 * JOINTQUAT_SIZE], xmm4 // q[k3] = ( m[1 * 4 + 2] - s0 * m[2 * 4 + 1] ) * s; - mov ecx, [esi+eax+1*JOINTMAT_SIZE+0*16+3*4] - mov [edi-3*JOINTQUAT_SIZE+16], ecx // q[4] = m[0 * 4 + 3]; - mov edx, [esi+eax+1*JOINTMAT_SIZE+1*16+3*4] - mov [edi-3*JOINTQUAT_SIZE+20], edx // q[5] = m[1 * 4 + 3]; - mov ecx, [esi+eax+1*JOINTMAT_SIZE+2*16+3*4] - mov [edi-3*JOINTQUAT_SIZE+24], ecx // q[6] = m[2 * 4 + 3]; + mov ecx, [esi + eax + 1 * JOINTMAT_SIZE + 0 * 16 + 3 * 4] + mov [edi - 3 * JOINTQUAT_SIZE + 16], ecx // q[4] = m[0 * 4 + 3]; + mov edx, [esi + eax + 1 * JOINTMAT_SIZE + 1 * 16 + 3 * 4] + mov [edi - 3 * JOINTQUAT_SIZE + 20], edx // q[5] = m[1 * 4 + 3]; + mov ecx, [esi + eax + 1 * JOINTMAT_SIZE + 2 * 16 + 3 * 4] + mov [edi - 3 * JOINTQUAT_SIZE + 24], ecx // q[6] = m[2 * 4 + 3]; shufps xmm6, xmm6, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm7, xmm7, R_SHUFFLEPS( 1, 2, 3, 0 ) @@ -11960,36 +12118,36 @@ void VPCALL idSIMD_SSE::ConvertJointMatsToJointQuats( idJointQuat *jointQuats, c shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - movzx ecx, byte ptr shuffle[2*4+0] // ecx = k0 - movss [edi+ecx*4-2*JOINTQUAT_SIZE], xmm7 // q[k0] = s * t; + movzx ecx, byte ptr shuffle[2 * 4 + 0] // ecx = k0 + movss [edi + ecx * 4 - 2 * JOINTQUAT_SIZE], xmm7 // q[k0] = s * t; - movzx edx, byte ptr shuffle[2*4+1] // edx = k1 - movss xmm4, [esi+eax+2*JOINTMAT_SIZE+1*16+0*4] + movzx edx, byte ptr shuffle[2 * 4 + 1] // edx = k1 + movss xmm4, [esi + eax + 2 * JOINTMAT_SIZE + 1 * 16 + 0 * 4] xorps xmm4, xmm2 - subss xmm4, [esi+eax+2*JOINTMAT_SIZE+0*16+1*4] + subss xmm4, [esi + eax + 2 * JOINTMAT_SIZE + 0 * 16 + 1 * 4] mulss xmm4, xmm6 - movss [edi+edx*4-2*JOINTQUAT_SIZE], xmm4 // q[k1] = ( m[0 * 4 + 1] - s2 * m[1 * 4 + 0] ) * s; + movss [edi + edx * 4 - 2 * JOINTQUAT_SIZE], xmm4 // q[k1] = ( m[0 * 4 + 1] - s2 * m[1 * 4 + 0] ) * s; - movzx ecx, byte ptr shuffle[2*4+2] // ecx = k2 - movss xmm3, [esi+eax+2*JOINTMAT_SIZE+0*16+2*4] + movzx ecx, byte ptr shuffle[2 * 4 + 2] // ecx = k2 + movss xmm3, [esi + eax + 2 * JOINTMAT_SIZE + 0 * 16 + 2 * 4] xorps xmm3, xmm1 - subss xmm3, [esi+eax+2*JOINTMAT_SIZE+2*16+0*4] + subss xmm3, [esi + eax + 2 * JOINTMAT_SIZE + 2 * 16 + 0 * 4] mulss xmm3, xmm6 - movss [edi+ecx*4-2*JOINTQUAT_SIZE], xmm3 // q[k2] = ( m[2 * 4 + 0] - s1 * m[0 * 4 + 2] ) * s; + movss [edi + ecx * 4 - 2 * JOINTQUAT_SIZE], xmm3 // q[k2] = ( m[2 * 4 + 0] - s1 * m[0 * 4 + 2] ) * s; - movzx edx, byte ptr shuffle[2*4+3] // edx = k3 - movss xmm4, [esi+eax+2*JOINTMAT_SIZE+2*16+1*4] + movzx edx, byte ptr shuffle[2 * 4 + 3] // edx = k3 + movss xmm4, [esi + eax + 2 * JOINTMAT_SIZE + 2 * 16 + 1 * 4] xorps xmm4, xmm0 - subss xmm4, [esi+eax+2*JOINTMAT_SIZE+1*16+2*4] + subss xmm4, [esi + eax + 2 * JOINTMAT_SIZE + 1 * 16 + 2 * 4] mulss xmm4, xmm6 - movss [edi+edx*4-2*JOINTQUAT_SIZE], xmm4 // q[k3] = ( m[1 * 4 + 2] - s0 * m[2 * 4 + 1] ) * s; + movss [edi + edx * 4 - 2 * JOINTQUAT_SIZE], xmm4 // q[k3] = ( m[1 * 4 + 2] - s0 * m[2 * 4 + 1] ) * s; - mov ecx, [esi+eax+2*JOINTMAT_SIZE+0*16+3*4] - mov [edi-2*JOINTQUAT_SIZE+16], ecx // q[4] = m[0 * 4 + 3]; - mov edx, [esi+eax+2*JOINTMAT_SIZE+1*16+3*4] - mov [edi-2*JOINTQUAT_SIZE+20], edx // q[5] = m[1 * 4 + 3]; - mov ecx, [esi+eax+2*JOINTMAT_SIZE+2*16+3*4] - mov [edi-2*JOINTQUAT_SIZE+24], ecx // q[6] = m[2 * 4 + 3]; + mov ecx, [esi + eax + 2 * JOINTMAT_SIZE + 0 * 16 + 3 * 4] + mov [edi - 2 * JOINTQUAT_SIZE + 16], ecx // q[4] = m[0 * 4 + 3]; + mov edx, [esi + eax + 2 * JOINTMAT_SIZE + 1 * 16 + 3 * 4] + mov [edi - 2 * JOINTQUAT_SIZE + 20], edx // q[5] = m[1 * 4 + 3]; + mov ecx, [esi + eax + 2 * JOINTMAT_SIZE + 2 * 16 + 3 * 4] + mov [edi - 2 * JOINTQUAT_SIZE + 24], ecx // q[6] = m[2 * 4 + 3]; shufps xmm6, xmm6, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm7, xmm7, R_SHUFFLEPS( 1, 2, 3, 0 ) @@ -11997,41 +12155,41 @@ void VPCALL idSIMD_SSE::ConvertJointMatsToJointQuats( idJointQuat *jointQuats, c shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - movzx ecx, byte ptr shuffle[3*4+0] // ecx = k0 - movss [edi+ecx*4-1*JOINTQUAT_SIZE], xmm7 // q[k0] = s * t; + movzx ecx, byte ptr shuffle[3 * 4 + 0] // ecx = k0 + movss [edi + ecx * 4 - 1 * JOINTQUAT_SIZE], xmm7 // q[k0] = s * t; - movzx edx, byte ptr shuffle[3*4+1] // edx = k1 - movss xmm4, [esi+eax+3*JOINTMAT_SIZE+1*16+0*4] + movzx edx, byte ptr shuffle[3 * 4 + 1] // edx = k1 + movss xmm4, [esi + eax + 3 * JOINTMAT_SIZE + 1 * 16 + 0 * 4] xorps xmm4, xmm2 - subss xmm4, [esi+eax+3*JOINTMAT_SIZE+0*16+1*4] + subss xmm4, [esi + eax + 3 * JOINTMAT_SIZE + 0 * 16 + 1 * 4] mulss xmm4, xmm6 - movss [edi+edx*4-1*JOINTQUAT_SIZE], xmm4 // q[k1] = ( m[0 * 4 + 1] - s2 * m[1 * 4 + 0] ) * s; + movss [edi + edx * 4 - 1 * JOINTQUAT_SIZE], xmm4 // q[k1] = ( m[0 * 4 + 1] - s2 * m[1 * 4 + 0] ) * s; - movzx ecx, byte ptr shuffle[3*4+2] // ecx = k2 - movss xmm3, [esi+eax+3*JOINTMAT_SIZE+0*16+2*4] + movzx ecx, byte ptr shuffle[3 * 4 + 2] // ecx = k2 + movss xmm3, [esi + eax + 3 * JOINTMAT_SIZE + 0 * 16 + 2 * 4] xorps xmm3, xmm1 - subss xmm3, [esi+eax+3*JOINTMAT_SIZE+2*16+0*4] + subss xmm3, [esi + eax + 3 * JOINTMAT_SIZE + 2 * 16 + 0 * 4] mulss xmm3, xmm6 - movss [edi+ecx*4-1*JOINTQUAT_SIZE], xmm3 // q[k2] = ( m[2 * 4 + 0] - s1 * m[0 * 4 + 2] ) * s; + movss [edi + ecx * 4 - 1 * JOINTQUAT_SIZE], xmm3 // q[k2] = ( m[2 * 4 + 0] - s1 * m[0 * 4 + 2] ) * s; - movzx edx, byte ptr shuffle[3*4+3] // edx = k3 - movss xmm4, [esi+eax+3*JOINTMAT_SIZE+2*16+1*4] + movzx edx, byte ptr shuffle[3 * 4 + 3] // edx = k3 + movss xmm4, [esi + eax + 3 * JOINTMAT_SIZE + 2 * 16 + 1 * 4] xorps xmm4, xmm0 - subss xmm4, [esi+eax+3*JOINTMAT_SIZE+1*16+2*4] + subss xmm4, [esi + eax + 3 * JOINTMAT_SIZE + 1 * 16 + 2 * 4] mulss xmm4, xmm6 - movss [edi+edx*4-1*JOINTQUAT_SIZE], xmm4 // q[k3] = ( m[1 * 4 + 2] - s0 * m[2 * 4 + 1] ) * s; + movss [edi + edx * 4 - 1 * JOINTQUAT_SIZE], xmm4 // q[k3] = ( m[1 * 4 + 2] - s0 * m[2 * 4 + 1] ) * s; - mov ecx, [esi+eax+3*JOINTMAT_SIZE+0*16+3*4] - mov [edi-1*JOINTQUAT_SIZE+16], ecx // q[4] = m[0 * 4 + 3]; - mov edx, [esi+eax+3*JOINTMAT_SIZE+1*16+3*4] - mov [edi-1*JOINTQUAT_SIZE+20], edx // q[5] = m[1 * 4 + 3]; - mov ecx, [esi+eax+3*JOINTMAT_SIZE+2*16+3*4] - mov [edi-1*JOINTQUAT_SIZE+24], ecx // q[6] = m[2 * 4 + 3]; + mov ecx, [esi + eax + 3 * JOINTMAT_SIZE + 0 * 16 + 3 * 4] + mov [edi - 1 * JOINTQUAT_SIZE + 16], ecx // q[4] = m[0 * 4 + 3]; + mov edx, [esi + eax + 3 * JOINTMAT_SIZE + 1 * 16 + 3 * 4] + mov [edi - 1 * JOINTQUAT_SIZE + 20], edx // q[5] = m[1 * 4 + 3]; + mov ecx, [esi + eax + 3 * JOINTMAT_SIZE + 2 * 16 + 3 * 4] + mov [edi - 1 * JOINTQUAT_SIZE + 24], ecx // q[6] = m[2 * 4 + 3]; - add eax, 4*JOINTMAT_SIZE + add eax, 4 * JOINTMAT_SIZE jl loopMat4 - done4: + done4: mov eax, numJoints and eax, 3 jz done1 @@ -12039,10 +12197,10 @@ void VPCALL idSIMD_SSE::ConvertJointMatsToJointQuats( idJointQuat *jointQuats, c add esi, eax neg eax - loopMat1: - movss xmm5, [esi+eax+0*JOINTMAT_SIZE+0*16+0*4] - movss xmm6, [esi+eax+0*JOINTMAT_SIZE+1*16+1*4] - movss xmm7, [esi+eax+0*JOINTMAT_SIZE+2*16+2*4] + loopMat1: + movss xmm5, [esi + eax + 0 * JOINTMAT_SIZE + 0 * 16 + 0 * 4] + movss xmm6, [esi + eax + 0 * JOINTMAT_SIZE + 1 * 16 + 1 * 4] + movss xmm7, [esi + eax + 0 * JOINTMAT_SIZE + 2 * 16 + 2 * 4] // ------------------- @@ -12112,40 +12270,40 @@ void VPCALL idSIMD_SSE::ConvertJointMatsToJointQuats( idJointQuat *jointQuats, c movzx ecx, byte ptr shuffle[0] // ecx = k0 add edi, JOINTQUAT_SIZE - movss [edi+ecx*4-1*JOINTQUAT_SIZE], xmm7 // q[k0] = s * t; + movss [edi + ecx * 4 - 1 * JOINTQUAT_SIZE], xmm7 // q[k0] = s * t; movzx edx, byte ptr shuffle[1] // edx = k1 - movss xmm4, [esi+eax+0*JOINTMAT_SIZE+1*16+0*4] + movss xmm4, [esi + eax + 0 * JOINTMAT_SIZE + 1 * 16 + 0 * 4] xorps xmm4, xmm2 - subss xmm4, [esi+eax+0*JOINTMAT_SIZE+0*16+1*4] + subss xmm4, [esi + eax + 0 * JOINTMAT_SIZE + 0 * 16 + 1 * 4] mulss xmm4, xmm6 - movss [edi+edx*4-1*JOINTQUAT_SIZE], xmm4 // q[k1] = ( m[0 * 4 + 1] - s2 * m[1 * 4 + 0] ) * s; + movss [edi + edx * 4 - 1 * JOINTQUAT_SIZE], xmm4 // q[k1] = ( m[0 * 4 + 1] - s2 * m[1 * 4 + 0] ) * s; movzx ecx, byte ptr shuffle[2] // ecx = k2 - movss xmm3, [esi+eax+0*JOINTMAT_SIZE+0*16+2*4] + movss xmm3, [esi + eax + 0 * JOINTMAT_SIZE + 0 * 16 + 2 * 4] xorps xmm3, xmm1 - subss xmm3, [esi+eax+0*JOINTMAT_SIZE+2*16+0*4] + subss xmm3, [esi + eax + 0 * JOINTMAT_SIZE + 2 * 16 + 0 * 4] mulss xmm3, xmm6 - movss [edi+ecx*4-1*JOINTQUAT_SIZE], xmm3 // q[k2] = ( m[2 * 4 + 0] - s1 * m[0 * 4 + 2] ) * s; + movss [edi + ecx * 4 - 1 * JOINTQUAT_SIZE], xmm3 // q[k2] = ( m[2 * 4 + 0] - s1 * m[0 * 4 + 2] ) * s; movzx edx, byte ptr shuffle[3] // edx = k3 - movss xmm4, [esi+eax+0*JOINTMAT_SIZE+2*16+1*4] + movss xmm4, [esi + eax + 0 * JOINTMAT_SIZE + 2 * 16 + 1 * 4] xorps xmm4, xmm0 - subss xmm4, [esi+eax+0*JOINTMAT_SIZE+1*16+2*4] + subss xmm4, [esi + eax + 0 * JOINTMAT_SIZE + 1 * 16 + 2 * 4] mulss xmm4, xmm6 - movss [edi+edx*4-1*JOINTQUAT_SIZE], xmm4 // q[k3] = ( m[1 * 4 + 2] - s0 * m[2 * 4 + 1] ) * s; + movss [edi + edx * 4 - 1 * JOINTQUAT_SIZE], xmm4 // q[k3] = ( m[1 * 4 + 2] - s0 * m[2 * 4 + 1] ) * s; - mov ecx, [esi+eax+0*JOINTMAT_SIZE+0*16+3*4] - mov [edi-1*JOINTQUAT_SIZE+16], ecx // q[4] = m[0 * 4 + 3]; - mov edx, [esi+eax+0*JOINTMAT_SIZE+1*16+3*4] - mov [edi-1*JOINTQUAT_SIZE+20], edx // q[5] = m[1 * 4 + 3]; - mov ecx, [esi+eax+0*JOINTMAT_SIZE+2*16+3*4] - mov [edi-1*JOINTQUAT_SIZE+24], ecx // q[6] = m[2 * 4 + 3]; + mov ecx, [esi + eax + 0 * JOINTMAT_SIZE + 0 * 16 + 3 * 4] + mov [edi - 1 * JOINTQUAT_SIZE + 16], ecx // q[4] = m[0 * 4 + 3]; + mov edx, [esi + eax + 0 * JOINTMAT_SIZE + 1 * 16 + 3 * 4] + mov [edi - 1 * JOINTQUAT_SIZE + 20], edx // q[5] = m[1 * 4 + 3]; + mov ecx, [esi + eax + 0 * JOINTMAT_SIZE + 2 * 16 + 3 * 4] + mov [edi - 1 * JOINTQUAT_SIZE + 24], ecx // q[6] = m[2 * 4 + 3]; add eax, JOINTMAT_SIZE jl loopMat1 - done1: + done1: } #elif 0 @@ -12294,7 +12452,7 @@ void VPCALL idSIMD_SSE::TransformJoints( idJointMat *jointMats, const int *paren add edi, eax neg eax - loopJoint: + loopJoint: movaps xmm0, [esi+ecx+ 0] // xmm0 = m0, m1, m2, t0 mov edx, [edi+eax] @@ -12306,70 +12464,70 @@ void VPCALL idSIMD_SSE::TransformJoints( idJointMat *jointMats, const int *paren shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm4, xmm0 - movss xmm5, [esi+edx+ 4] + movss xmm5, [esi + edx + 4] shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm5, xmm1 addps xmm4, xmm5 - movss xmm6, [esi+edx+ 8] + movss xmm6, [esi + edx + 8] shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm6, xmm2 addps xmm4, xmm6 - movss xmm5, [esi+edx+16] + movss xmm5, [esi + edx + 16] shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm5, xmm0 - movss xmm7, [esi+edx+12] + movss xmm7, [esi + edx + 12] shufps xmm7, xmm7, R_SHUFFLEPS( 1, 2, 3, 0 ) addps xmm4, xmm7 - movaps [esi+ecx+ 0], xmm4 + movaps [esi + ecx + 0], xmm4 - movss xmm6, [esi+edx+20] + movss xmm6, [esi + edx + 20] shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm6, xmm1 addps xmm5, xmm6 - movss xmm7, [esi+edx+24] + movss xmm7, [esi + edx + 24] shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm7, xmm2 addps xmm5, xmm7 - movss xmm6, [esi+edx+32] + movss xmm6, [esi + edx + 32] shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm6, xmm0 - movss xmm3, [esi+edx+28] + movss xmm3, [esi + edx + 28] shufps xmm3, xmm3, R_SHUFFLEPS( 1, 2, 3, 0 ) addps xmm5, xmm3 - movaps [esi+ecx+16], xmm5 + movaps [esi + ecx + 16], xmm5 - movss xmm7, [esi+edx+36] + movss xmm7, [esi + edx + 36] shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm7, xmm1 addps xmm6, xmm7 - movss xmm3, [esi+edx+40] + movss xmm3, [esi + edx + 40] shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm3, xmm2 addps xmm6, xmm3 - movss xmm7, [esi+edx+44] + movss xmm7, [esi + edx + 44] shufps xmm7, xmm7, R_SHUFFLEPS( 1, 2, 3, 0 ) addps xmm6, xmm7 - movaps [esi+ecx+32], xmm6 + movaps [esi + ecx + 32], xmm6 add ecx, JOINTMAT_SIZE add eax, 4 jle loopJoint - done: + done: } #else int i; - for( i = firstJoint; i <= lastJoint; i++ ) { + for ( i = firstJoint; i <= lastJoint; i++ ) { assert( parents[i] < i ); jointMats[i] *= jointMats[parents[i]]; } @@ -12401,7 +12559,7 @@ void VPCALL idSIMD_SSE::UntransformJoints( idJointMat *jointMats, const int *par add edi, edx imul eax, 4 - loopJoint: + loopJoint: movaps xmm0, [esi+ecx+ 0] // xmm0 = m0, m1, m2, t0 mov edx, [edi+eax] @@ -12412,66 +12570,66 @@ void VPCALL idSIMD_SSE::UntransformJoints( idJointMat *jointMats, const int *par movss xmm6, [esi+edx+12] shufps xmm6, xmm6, R_SHUFFLEPS( 1, 2, 3, 0 ) subps xmm0, xmm6 - movss xmm7, [esi+edx+28] + movss xmm7, [esi + edx + 28] shufps xmm7, xmm7, R_SHUFFLEPS( 1, 2, 3, 0 ) subps xmm1, xmm7 - movss xmm3, [esi+edx+44] + movss xmm3, [esi + edx + 44] shufps xmm3, xmm3, R_SHUFFLEPS( 1, 2, 3, 0 ) subps xmm2, xmm3 - movss xmm4, [esi+edx+ 0] + movss xmm4, [esi + edx + 0] shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm4, xmm0 - movss xmm5, [esi+edx+16] + movss xmm5, [esi + edx + 16] shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm5, xmm1 addps xmm4, xmm5 - movss xmm6, [esi+edx+32] + movss xmm6, [esi + edx + 32] shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm6, xmm2 addps xmm4, xmm6 - movaps [esi+ecx+ 0], xmm4 + movaps [esi + ecx + 0], xmm4 - movss xmm5, [esi+edx+ 4] + movss xmm5, [esi + edx + 4] shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm5, xmm0 - movss xmm6, [esi+edx+20] + movss xmm6, [esi + edx + 20] shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm6, xmm1 addps xmm5, xmm6 - movss xmm7, [esi+edx+36] + movss xmm7, [esi + edx + 36] shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm7, xmm2 addps xmm5, xmm7 - movaps [esi+ecx+16], xmm5 + movaps [esi + ecx + 16], xmm5 - movss xmm6, [esi+edx+ 8] + movss xmm6, [esi + edx + 8] shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm6, xmm0 - movss xmm7, [esi+edx+24] + movss xmm7, [esi + edx + 24] shufps xmm7, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm7, xmm1 addps xmm6, xmm7 - movss xmm3, [esi+edx+40] + movss xmm3, [esi + edx + 40] shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm3, xmm2 addps xmm6, xmm3 - movaps [esi+ecx+32], xmm6 + movaps [esi + ecx + 32], xmm6 sub ecx, JOINTMAT_SIZE sub eax, 4 jge loopJoint - done: + done: } #else int i; - for( i = lastJoint; i >= firstJoint; i-- ) { + for ( i = lastJoint; i >= firstJoint; i-- ) { assert( parents[i] < i ); jointMats[i] /= jointMats[parents[i]]; } @@ -12488,12 +12646,11 @@ void VPCALL idSIMD_SSE::TransformVerts( idDrawVert *verts, const int numVerts, c #if 1 assert( sizeof( idDrawVert ) == DRAWVERT_SIZE ); - assert( (int)&((idDrawVert *)0)->xyz == DRAWVERT_XYZ_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->xyz == DRAWVERT_XYZ_OFFSET ); assert( sizeof( idVec4 ) == JOINTWEIGHT_SIZE ); assert( sizeof( idJointMat ) == JOINTMAT_SIZE ); - __asm - { + __asm { mov eax, numVerts test eax, eax jz done @@ -12507,7 +12664,7 @@ void VPCALL idSIMD_SSE::TransformVerts( idDrawVert *verts, const int numVerts, c add ecx, eax neg eax - loopVert: + loopVert: mov ebx, [edx] movaps xmm2, [esi] add edx, 8 @@ -12523,7 +12680,7 @@ void VPCALL idSIMD_SSE::TransformVerts( idDrawVert *verts, const int numVerts, c jne doneWeight - loopWeight: + loopWeight: mov ebx, [edx] movaps xmm5, [esi] add edx, 8 @@ -12543,7 +12700,7 @@ void VPCALL idSIMD_SSE::TransformVerts( idDrawVert *verts, const int numVerts, c je loopWeight - doneWeight: + doneWeight: add eax, DRAWVERT_SIZE movaps xmm6, xmm0 // xmm6 = m0, m1, m2, t0 @@ -12562,24 +12719,24 @@ void VPCALL idSIMD_SSE::TransformVerts( idDrawVert *verts, const int numVerts, c shufps xmm5, xmm5, R_SHUFFLEPS( 1, 0, 2, 3 ) // xmm5 = m7+t2, m6+m8 addss xmm5, xmm6 // xmm5 = m6+m8+m7+t2 - movss [ecx+eax-DRAWVERT_SIZE+8], xmm5 + movss [ecx + eax - DRAWVERT_SIZE + 8], xmm5 jl loopVert - done: + done: } #else int i, j; - const byte *jointsPtr = (byte *)joints; + const byte *jointsPtr = ( byte * )joints; - for( j = i = 0; i < numVerts; i++ ) { + for ( j = i = 0; i < numVerts; i++ ) { idVec3 v; - v = ( *(idJointMat *) ( jointsPtr + index[j*2+0] ) ) * weights[j]; - while( index[j*2+1] == 0 ) { + v = ( *( idJointMat * )( jointsPtr + index[j * 2 + 0] ) ) * weights[j]; + while ( index[j * 2 + 1] == 0 ) { j++; - v += ( *(idJointMat *) ( jointsPtr + index[j*2+0] ) ) * weights[j]; + v += ( *( idJointMat * )( jointsPtr + index[j * 2 + 0] ) ) * weights[j]; } j++; @@ -12598,7 +12755,7 @@ void VPCALL idSIMD_SSE::TracePointCull( byte *cullBits, byte &totalOr, const flo #if 1 assert( sizeof( idDrawVert ) == DRAWVERT_SIZE ); - assert( (int)&((idDrawVert *)0)->xyz == DRAWVERT_XYZ_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->xyz == DRAWVERT_XYZ_OFFSET ); __asm { push ebx @@ -12631,13 +12788,13 @@ void VPCALL idSIMD_SSE::TracePointCull( byte *cullBits, byte &totalOr, const flo add esi, eax neg eax - loopVert: - movss xmm4, [esi+eax+DRAWVERT_XYZ_OFFSET+0] + loopVert: + movss xmm4, [esi + eax + DRAWVERT_XYZ_OFFSET + 0] shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm5, [esi+eax+DRAWVERT_XYZ_OFFSET+4] + movss xmm5, [esi + eax + DRAWVERT_XYZ_OFFSET + 4] mulps xmm4, xmm0 shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) - movss xmm6, [esi+eax+DRAWVERT_XYZ_OFFSET+8] + movss xmm6, [esi + eax + DRAWVERT_XYZ_OFFSET + 8] mulps xmm5, xmm1 shufps xmm6, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) addps xmm4, xmm5 @@ -12655,10 +12812,10 @@ void VPCALL idSIMD_SSE::TracePointCull( byte *cullBits, byte &totalOr, const flo inc edi or dl, cl add eax, DRAWVERT_SIZE - mov byte ptr [edi-1], cl + mov byte ptr [edi - 1], cl jl loopVert - done: + done: mov esi, totalOr mov byte ptr [esi], dl pop ebx @@ -12728,7 +12885,7 @@ void VPCALL idSIMD_SSE::DecalPointCull( byte *cullBits, const idPlane *planes, c ALIGN16( float p7[4] ); assert( sizeof( idDrawVert ) == DRAWVERT_SIZE ); - assert( (int)&((idDrawVert *)0)->xyz == DRAWVERT_XYZ_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->xyz == DRAWVERT_XYZ_OFFSET ); __asm { mov ecx, planes @@ -12752,13 +12909,13 @@ void VPCALL idSIMD_SSE::DecalPointCull( byte *cullBits, const idPlane *planes, c movaps p2, xmm2 movaps p3, xmm3 - movlps xmm4, [ecx+64] // xmm4 = p40, p41, X, X - movhps xmm4, [ecx+80] // xmm4 = p40, p41, p50, p51 + movlps xmm4, [ecx + 64] // xmm4 = p40, p41, X, X + movhps xmm4, [ecx + 80] // xmm4 = p40, p41, p50, p51 movaps xmm5, xmm4 // xmm5 = p40, p41, p50, p51 shufps xmm4, xmm4, R_SHUFFLEPS( 0, 2, 0, 2 ) // xmm4 = p40, p50, p40, p50 shufps xmm5, xmm5, R_SHUFFLEPS( 1, 3, 1, 3 ) // xmm5 = p41, p51, p41, p51 - movlps xmm6, [ecx+72] // xmm6 = p42, p43, X, X - movhps xmm6, [ecx+88] // xmm6 = p42, p43, p52, p53 + movlps xmm6, [ecx + 72] // xmm6 = p42, p43, X, X + movhps xmm6, [ecx + 88] // xmm6 = p42, p43, p52, p53 movaps xmm7, xmm6 // xmm7 = p42, p43, p52, p53 shufps xmm6, xmm6, R_SHUFFLEPS( 0, 2, 0, 2 ) // xmm6 = p42, p52, p42, p52 shufps xmm7, xmm7, R_SHUFFLEPS( 1, 3, 1, 3 ) // xmm7 = p43, p53, p43, p53 @@ -12777,18 +12934,18 @@ void VPCALL idSIMD_SSE::DecalPointCull( byte *cullBits, const idPlane *planes, c add esi, eax neg eax - loopVert2: + loopVert2: movaps xmm6, p0 - movss xmm0, [esi+eax+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] + movss xmm0, [esi + eax + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm6, xmm0 movaps xmm7, p1 - movss xmm1, [esi+eax+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] + movss xmm1, [esi + eax + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4] shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm7, xmm1 addps xmm6, xmm7 movaps xmm7, p2 - movss xmm2, [esi+eax+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] + movss xmm2, [esi + eax + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm7, xmm2 addps xmm6, xmm7 @@ -12798,16 +12955,16 @@ void VPCALL idSIMD_SSE::DecalPointCull( byte *cullBits, const idPlane *planes, c movmskps ecx, xmm6 movaps xmm6, p0 - movss xmm3, [esi+eax+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] + movss xmm3, [esi + eax + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] shufps xmm3, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm6, xmm3 movaps xmm7, p1 - movss xmm4, [esi+eax+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] + movss xmm4, [esi + eax + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4] shufps xmm4, xmm4, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm7, xmm4 addps xmm6, xmm7 movaps xmm7, p2 - movss xmm5, [esi+eax+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] + movss xmm5, [esi + eax + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] shufps xmm5, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm7, xmm5 addps xmm6, xmm7 @@ -12835,30 +12992,30 @@ void VPCALL idSIMD_SSE::DecalPointCull( byte *cullBits, const idPlane *planes, c mov dh, dl shl dl, 4 shl dh, 2 - and edx, (3<<4)|(3<<12) + and edx, ( 3 << 4 ) | ( 3 << 12 ) or ecx, edx - add eax, 2*DRAWVERT_SIZE - mov word ptr [edi-2], cx + add eax, 2 * DRAWVERT_SIZE + mov word ptr [edi - 2], cx jl loopVert2 - done2: + done2: mov eax, numVerts and eax, 1 jz done movaps xmm6, p0 - movss xmm0, [esi+DRAWVERT_XYZ_OFFSET+0] + movss xmm0, [esi + DRAWVERT_XYZ_OFFSET + 0] shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm6, xmm0 movaps xmm7, p1 - movss xmm1, [esi+DRAWVERT_XYZ_OFFSET+4] + movss xmm1, [esi + DRAWVERT_XYZ_OFFSET + 4] shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm7, xmm1 addps xmm6, xmm7 movaps xmm7, p2 - movss xmm2, [esi+DRAWVERT_XYZ_OFFSET+8] + movss xmm2, [esi + DRAWVERT_XYZ_OFFSET + 8] shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm7, xmm2 addps xmm6, xmm7 @@ -12883,7 +13040,7 @@ void VPCALL idSIMD_SSE::DecalPointCull( byte *cullBits, const idPlane *planes, c mov byte ptr [edi], cl - done: + done: } @@ -12894,8 +13051,8 @@ void VPCALL idSIMD_SSE::DecalPointCull( byte *cullBits, const idPlane *planes, c for ( i = 0; i < numVerts; i += 2 ) { unsigned short bits0, bits1; float d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11; - const idVec3 &v0 = verts[i+0].xyz; - const idVec3 &v1 = verts[i+1].xyz; + const idVec3 &v0 = verts[i + 0].xyz; + const idVec3 &v1 = verts[i + 1].xyz; d0 = planes[0][0] * v0[0] + planes[0][1] * v0[1] + planes[0][2] * v0[2] + planes[0][3]; d1 = planes[1][0] * v0[0] + planes[1][1] * v0[1] + planes[1][2] * v0[2] + planes[1][3]; @@ -12912,21 +13069,21 @@ void VPCALL idSIMD_SSE::DecalPointCull( byte *cullBits, const idPlane *planes, c d8 = planes[2][0] * v1[0] + planes[2][1] * v1[1] + planes[2][2] * v1[2] + planes[2][3]; d9 = planes[3][0] * v1[0] + planes[3][1] * v1[1] + planes[3][2] * v1[2] + planes[3][3]; - bits0 = FLOATSIGNBITSET( d0 ) << (0+0); - bits0 |= FLOATSIGNBITSET( d1 ) << (0+1); - bits0 |= FLOATSIGNBITSET( d2 ) << (0+2); - bits0 |= FLOATSIGNBITSET( d3 ) << (0+3); - bits0 |= FLOATSIGNBITSET( d4 ) << (0+4); - bits0 |= FLOATSIGNBITSET( d5 ) << (0+5); - - bits1 = FLOATSIGNBITSET( d6 ) << (8+0); - bits1 |= FLOATSIGNBITSET( d7 ) << (8+1); - bits1 |= FLOATSIGNBITSET( d8 ) << (8+2); - bits1 |= FLOATSIGNBITSET( d9 ) << (8+3); - bits1 |= FLOATSIGNBITSET( d10 ) << (8+4); - bits1 |= FLOATSIGNBITSET( d11 ) << (8+5); - - *(unsigned short *)(cullBits + i) = ( bits0 | bits1 ) ^ 0x3F3F; + bits0 = FLOATSIGNBITSET( d0 ) << ( 0 + 0 ); + bits0 |= FLOATSIGNBITSET( d1 ) << ( 0 + 1 ); + bits0 |= FLOATSIGNBITSET( d2 ) << ( 0 + 2 ); + bits0 |= FLOATSIGNBITSET( d3 ) << ( 0 + 3 ); + bits0 |= FLOATSIGNBITSET( d4 ) << ( 0 + 4 ); + bits0 |= FLOATSIGNBITSET( d5 ) << ( 0 + 5 ); + + bits1 = FLOATSIGNBITSET( d6 ) << ( 8 + 0 ); + bits1 |= FLOATSIGNBITSET( d7 ) << ( 8 + 1 ); + bits1 |= FLOATSIGNBITSET( d8 ) << ( 8 + 2 ); + bits1 |= FLOATSIGNBITSET( d9 ) << ( 8 + 3 ); + bits1 |= FLOATSIGNBITSET( d10 ) << ( 8 + 4 ); + bits1 |= FLOATSIGNBITSET( d11 ) << ( 8 + 5 ); + + *( unsigned short * )( cullBits + i ) = ( bits0 | bits1 ) ^ 0x3F3F; } if ( numVerts & 1 ) { @@ -12965,7 +13122,7 @@ void VPCALL idSIMD_SSE::OverlayPointCull( byte *cullBits, idVec2 *texCoords, con #if 1 assert( sizeof( idDrawVert ) == DRAWVERT_SIZE ); - assert( (int)&((idDrawVert *)0)->xyz == DRAWVERT_XYZ_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->xyz == DRAWVERT_XYZ_OFFSET ); __asm { mov eax, numVerts @@ -12978,16 +13135,16 @@ void VPCALL idSIMD_SSE::OverlayPointCull( byte *cullBits, idVec2 *texCoords, con movss xmm5, [ecx+16] shufps xmm4, xmm5, R_SHUFFLEPS( 0, 0, 0, 0 ) shufps xmm4, xmm4, R_SHUFFLEPS( 0, 2, 0, 2 ) - movss xmm5, [ecx+ 4] - movss xmm6, [ecx+20] + movss xmm5, [ecx + 4] + movss xmm6, [ecx + 20] shufps xmm5, xmm6, R_SHUFFLEPS( 0, 0, 0, 0 ) shufps xmm5, xmm5, R_SHUFFLEPS( 0, 2, 0, 2 ) - movss xmm6, [ecx+ 8] - movss xmm7, [ecx+24] + movss xmm6, [ecx + 8] + movss xmm7, [ecx + 24] shufps xmm6, xmm7, R_SHUFFLEPS( 0, 0, 0, 0 ) shufps xmm6, xmm6, R_SHUFFLEPS( 0, 2, 0, 2 ) - movss xmm7, [ecx+12] - movss xmm0, [ecx+28] + movss xmm7, [ecx + 12] + movss xmm0, [ecx + 28] shufps xmm7, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) shufps xmm7, xmm7, R_SHUFFLEPS( 0, 2, 0, 2 ) @@ -12996,17 +13153,17 @@ void VPCALL idSIMD_SSE::OverlayPointCull( byte *cullBits, idVec2 *texCoords, con add edi, eax neg eax - loopVert2: - movss xmm0, [edx+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] - movss xmm1, [edx+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] + loopVert2: + movss xmm0, [edx + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] + movss xmm1, [edx + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] shufps xmm0, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm0, xmm4 - movss xmm1, [edx+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] - movss xmm2, [edx+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] + movss xmm1, [edx + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4] + movss xmm2, [edx + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4] shufps xmm1, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm1, xmm5 - movss xmm2, [edx+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] - movss xmm3, [edx+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] + movss xmm2, [edx + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] + movss xmm3, [edx + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] shufps xmm2, xmm3, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm2, xmm6 addps xmm0, xmm1 @@ -13018,27 +13175,27 @@ void VPCALL idSIMD_SSE::OverlayPointCull( byte *cullBits, idVec2 *texCoords, con subps xmm2, xmm0 shufps xmm0, xmm2, R_SHUFFLEPS( 0, 1, 0, 1 ) shufps xmm1, xmm2, R_SHUFFLEPS( 2, 3, 2, 3 ) - add edx, 2*DRAWVERT_SIZE + add edx, 2 * DRAWVERT_SIZE movmskps ecx, xmm0 - mov byte ptr [edi+eax+0], cl - add esi, 4*4 + mov byte ptr [edi + eax + 0], cl + add esi, 4 * 4 movmskps ecx, xmm1 - mov byte ptr [edi+eax+1], cl + mov byte ptr [edi + eax + 1], cl add eax, 2 jl loopVert2 - done2: + done2: mov eax, numVerts and eax, 1 jz done - movss xmm0, [edx+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] + movss xmm0, [edx + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm0, xmm4 - movss xmm1, [edx+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] + movss xmm1, [edx + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4] shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm1, xmm5 - movss xmm2, [edx+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] + movss xmm2, [edx + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm2, xmm6 addps xmm0, xmm1 @@ -13052,7 +13209,7 @@ void VPCALL idSIMD_SSE::OverlayPointCull( byte *cullBits, idVec2 *texCoords, con movmskps ecx, xmm0 mov byte ptr [edi], cl - done: + done: } #else @@ -13064,18 +13221,18 @@ void VPCALL idSIMD_SSE::OverlayPointCull( byte *cullBits, idVec2 *texCoords, con unsigned short bits; float d0, d1, d2, d3; - const idVec3 &v0 = verts[i+0].xyz; - const idVec3 &v1 = verts[i+1].xyz; + const idVec3 &v0 = verts[i + 0].xyz; + const idVec3 &v1 = verts[i + 1].xyz; d0 = p0[0] * v0[0] + p0[1] * v0[1] + p0[2] * v0[2] + p0[3]; d1 = p1[0] * v0[0] + p1[1] * v0[1] + p1[2] * v0[2] + p1[3]; d2 = p0[0] * v1[0] + p0[1] * v1[1] + p0[2] * v1[2] + p0[3]; d3 = p1[0] * v1[0] + p1[1] * v1[1] + p1[2] * v1[2] + p1[3]; - texCoords[i+0][0] = d0; - texCoords[i+0][1] = d1; - texCoords[i+1][0] = d2; - texCoords[i+1][1] = d3; + texCoords[i + 0][0] = d0; + texCoords[i + 0][1] = d1; + texCoords[i + 1][0] = d2; + texCoords[i + 1][1] = d3; bits = FLOATSIGNBITSET( d0 ) << 0; bits |= FLOATSIGNBITSET( d1 ) << 1; @@ -13092,7 +13249,7 @@ void VPCALL idSIMD_SSE::OverlayPointCull( byte *cullBits, idVec2 *texCoords, con bits |= FLOATSIGNBITSET( d2 ) << 10; bits |= FLOATSIGNBITSET( d3 ) << 11; - *(unsigned short *)(cullBits + i) = bits; + *( unsigned short * )( cullBits + i ) = bits; } if ( numVerts & 1 ) { @@ -13133,7 +13290,7 @@ void VPCALL idSIMD_SSE::DeriveTriPlanes( idPlane *planes, const idDrawVert *vert #if 1 assert( sizeof( idDrawVert ) == DRAWVERT_SIZE ); - assert( (int)&((idDrawVert *)0)->xyz == DRAWVERT_XYZ_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->xyz == DRAWVERT_XYZ_OFFSET ); __asm { mov eax, numIndexes @@ -13148,7 +13305,7 @@ void VPCALL idSIMD_SSE::DeriveTriPlanes( idPlane *planes, const idDrawVert *vert add eax, 4*12 jge done4 - loopPlane4: + loopPlane4: mov ebx, [edi+eax-4*12+4] imul ebx, DRAWVERT_SIZE mov ecx, [edi+eax-4*12+0] @@ -13170,129 +13327,129 @@ void VPCALL idSIMD_SSE::DeriveTriPlanes( idPlane *planes, const idDrawVert *vert shufps xmm1, xmm1, R_SHUFFLEPS( 3, 0, 1, 2 ) shufps xmm2, xmm2, R_SHUFFLEPS( 3, 0, 1, 2 ) - movss xmm3, [esi+ebx+DRAWVERT_XYZ_OFFSET+0] - subss xmm3, [esi+ecx+DRAWVERT_XYZ_OFFSET+0] + movss xmm3, [esi + ebx + DRAWVERT_XYZ_OFFSET + 0] + subss xmm3, [esi + ecx + DRAWVERT_XYZ_OFFSET + 0] - movss xmm4, [esi+ebx+DRAWVERT_XYZ_OFFSET+4] - subss xmm4, [esi+ecx+DRAWVERT_XYZ_OFFSET+4] + movss xmm4, [esi + ebx + DRAWVERT_XYZ_OFFSET + 4] + subss xmm4, [esi + ecx + DRAWVERT_XYZ_OFFSET + 4] - movss xmm5, [esi+ebx+DRAWVERT_XYZ_OFFSET+8] - subss xmm5, [esi+ecx+DRAWVERT_XYZ_OFFSET+8] + movss xmm5, [esi + ebx + DRAWVERT_XYZ_OFFSET + 8] + subss xmm5, [esi + ecx + DRAWVERT_XYZ_OFFSET + 8] - mov ebx, [edi+eax-3*12+4] + mov ebx, [edi + eax - 3 * 12 + 4] imul ebx, DRAWVERT_SIZE - mov ecx, [edi+eax-3*12+0] + mov ecx, [edi + eax - 3 * 12 + 0] imul ecx, DRAWVERT_SIZE shufps xmm3, xmm3, R_SHUFFLEPS( 3, 0, 1, 2 ) shufps xmm4, xmm4, R_SHUFFLEPS( 3, 0, 1, 2 ) shufps xmm5, xmm5, R_SHUFFLEPS( 3, 0, 1, 2 ) - movss xmm6, [esi+ebx+DRAWVERT_XYZ_OFFSET+0] - subss xmm6, [esi+ecx+DRAWVERT_XYZ_OFFSET+0] + movss xmm6, [esi + ebx + DRAWVERT_XYZ_OFFSET + 0] + subss xmm6, [esi + ecx + DRAWVERT_XYZ_OFFSET + 0] movss xmm0, xmm6 - movss xmm7, [esi+ebx+DRAWVERT_XYZ_OFFSET+4] - subss xmm7, [esi+ecx+DRAWVERT_XYZ_OFFSET+4] + movss xmm7, [esi + ebx + DRAWVERT_XYZ_OFFSET + 4] + subss xmm7, [esi + ecx + DRAWVERT_XYZ_OFFSET + 4] movss xmm1, xmm7 - movss xmm6, [esi+ebx+DRAWVERT_XYZ_OFFSET+8] - subss xmm6, [esi+ecx+DRAWVERT_XYZ_OFFSET+8] + movss xmm6, [esi + ebx + DRAWVERT_XYZ_OFFSET + 8] + subss xmm6, [esi + ecx + DRAWVERT_XYZ_OFFSET + 8] movss xmm2, xmm6 - mov ebx, [edi+eax-3*12+8] + mov ebx, [edi + eax - 3 * 12 + 8] imul ebx, DRAWVERT_SIZE shufps xmm0, xmm0, R_SHUFFLEPS( 3, 0, 1, 2 ) shufps xmm1, xmm1, R_SHUFFLEPS( 3, 0, 1, 2 ) shufps xmm2, xmm2, R_SHUFFLEPS( 3, 0, 1, 2 ) - movss xmm7, [esi+ebx+DRAWVERT_XYZ_OFFSET+0] - subss xmm7, [esi+ecx+DRAWVERT_XYZ_OFFSET+0] + movss xmm7, [esi + ebx + DRAWVERT_XYZ_OFFSET + 0] + subss xmm7, [esi + ecx + DRAWVERT_XYZ_OFFSET + 0] movss xmm3, xmm7 - movss xmm6, [esi+ebx+DRAWVERT_XYZ_OFFSET+4] - subss xmm6, [esi+ecx+DRAWVERT_XYZ_OFFSET+4] + movss xmm6, [esi + ebx + DRAWVERT_XYZ_OFFSET + 4] + subss xmm6, [esi + ecx + DRAWVERT_XYZ_OFFSET + 4] movss xmm4, xmm6 - movss xmm7, [esi+ebx+DRAWVERT_XYZ_OFFSET+8] - subss xmm7, [esi+ecx+DRAWVERT_XYZ_OFFSET+8] + movss xmm7, [esi + ebx + DRAWVERT_XYZ_OFFSET + 8] + subss xmm7, [esi + ecx + DRAWVERT_XYZ_OFFSET + 8] movss xmm5, xmm7 - mov ebx, [edi+eax-2*12+4] + mov ebx, [edi + eax - 2 * 12 + 4] imul ebx, DRAWVERT_SIZE - mov ecx, [edi+eax-2*12+0] + mov ecx, [edi + eax - 2 * 12 + 0] imul ecx, DRAWVERT_SIZE shufps xmm3, xmm3, R_SHUFFLEPS( 3, 0, 1, 2 ) shufps xmm4, xmm4, R_SHUFFLEPS( 3, 0, 1, 2 ) shufps xmm5, xmm5, R_SHUFFLEPS( 3, 0, 1, 2 ) - movss xmm6, [esi+ebx+DRAWVERT_XYZ_OFFSET+0] - subss xmm6, [esi+ecx+DRAWVERT_XYZ_OFFSET+0] + movss xmm6, [esi + ebx + DRAWVERT_XYZ_OFFSET + 0] + subss xmm6, [esi + ecx + DRAWVERT_XYZ_OFFSET + 0] movss xmm0, xmm6 - movss xmm7, [esi+ebx+DRAWVERT_XYZ_OFFSET+4] - subss xmm7, [esi+ecx+DRAWVERT_XYZ_OFFSET+4] + movss xmm7, [esi + ebx + DRAWVERT_XYZ_OFFSET + 4] + subss xmm7, [esi + ecx + DRAWVERT_XYZ_OFFSET + 4] movss xmm1, xmm7 - movss xmm6, [esi+ebx+DRAWVERT_XYZ_OFFSET+8] - subss xmm6, [esi+ecx+DRAWVERT_XYZ_OFFSET+8] + movss xmm6, [esi + ebx + DRAWVERT_XYZ_OFFSET + 8] + subss xmm6, [esi + ecx + DRAWVERT_XYZ_OFFSET + 8] movss xmm2, xmm6 - mov ebx, [edi+eax-2*12+8] + mov ebx, [edi + eax - 2 * 12 + 8] imul ebx, DRAWVERT_SIZE shufps xmm0, xmm0, R_SHUFFLEPS( 3, 0, 1, 2 ) shufps xmm1, xmm1, R_SHUFFLEPS( 3, 0, 1, 2 ) shufps xmm2, xmm2, R_SHUFFLEPS( 3, 0, 1, 2 ) - movss xmm7, [esi+ebx+DRAWVERT_XYZ_OFFSET+0] - subss xmm7, [esi+ecx+DRAWVERT_XYZ_OFFSET+0] + movss xmm7, [esi + ebx + DRAWVERT_XYZ_OFFSET + 0] + subss xmm7, [esi + ecx + DRAWVERT_XYZ_OFFSET + 0] movss xmm3, xmm7 - movss xmm6, [esi+ebx+DRAWVERT_XYZ_OFFSET+4] - subss xmm6, [esi+ecx+DRAWVERT_XYZ_OFFSET+4] + movss xmm6, [esi + ebx + DRAWVERT_XYZ_OFFSET + 4] + subss xmm6, [esi + ecx + DRAWVERT_XYZ_OFFSET + 4] movss xmm4, xmm6 - movss xmm7, [esi+ebx+DRAWVERT_XYZ_OFFSET+8] - subss xmm7, [esi+ecx+DRAWVERT_XYZ_OFFSET+8] + movss xmm7, [esi + ebx + DRAWVERT_XYZ_OFFSET + 8] + subss xmm7, [esi + ecx + DRAWVERT_XYZ_OFFSET + 8] movss xmm5, xmm7 - mov ebx, [edi+eax-1*12+4] + mov ebx, [edi + eax - 1 * 12 + 4] imul ebx, DRAWVERT_SIZE - mov ecx, [edi+eax-1*12+0] + mov ecx, [edi + eax - 1 * 12 + 0] imul ecx, DRAWVERT_SIZE shufps xmm3, xmm3, R_SHUFFLEPS( 3, 0, 1, 2 ) shufps xmm4, xmm4, R_SHUFFLEPS( 3, 0, 1, 2 ) shufps xmm5, xmm5, R_SHUFFLEPS( 3, 0, 1, 2 ) - movss xmm6, [esi+ebx+DRAWVERT_XYZ_OFFSET+0] - subss xmm6, [esi+ecx+DRAWVERT_XYZ_OFFSET+0] + movss xmm6, [esi + ebx + DRAWVERT_XYZ_OFFSET + 0] + subss xmm6, [esi + ecx + DRAWVERT_XYZ_OFFSET + 0] movss xmm0, xmm6 - movss xmm7, [esi+ebx+DRAWVERT_XYZ_OFFSET+4] - subss xmm7, [esi+ecx+DRAWVERT_XYZ_OFFSET+4] + movss xmm7, [esi + ebx + DRAWVERT_XYZ_OFFSET + 4] + subss xmm7, [esi + ecx + DRAWVERT_XYZ_OFFSET + 4] movss xmm1, xmm7 - movss xmm6, [esi+ebx+DRAWVERT_XYZ_OFFSET+8] - subss xmm6, [esi+ecx+DRAWVERT_XYZ_OFFSET+8] + movss xmm6, [esi + ebx + DRAWVERT_XYZ_OFFSET + 8] + subss xmm6, [esi + ecx + DRAWVERT_XYZ_OFFSET + 8] movss xmm2, xmm6 - mov ebx, [edi+eax-1*12+8] + mov ebx, [edi + eax - 1 * 12 + 8] imul ebx, DRAWVERT_SIZE - movss xmm7, [esi+ebx+DRAWVERT_XYZ_OFFSET+0] - subss xmm7, [esi+ecx+DRAWVERT_XYZ_OFFSET+0] + movss xmm7, [esi + ebx + DRAWVERT_XYZ_OFFSET + 0] + subss xmm7, [esi + ecx + DRAWVERT_XYZ_OFFSET + 0] movss xmm3, xmm7 - movss xmm6, [esi+ebx+DRAWVERT_XYZ_OFFSET+4] - subss xmm6, [esi+ecx+DRAWVERT_XYZ_OFFSET+4] + movss xmm6, [esi + ebx + DRAWVERT_XYZ_OFFSET + 4] + subss xmm6, [esi + ecx + DRAWVERT_XYZ_OFFSET + 4] movss xmm4, xmm6 - movss xmm7, [esi+ebx+DRAWVERT_XYZ_OFFSET+8] - subss xmm7, [esi+ecx+DRAWVERT_XYZ_OFFSET+8] + movss xmm7, [esi + ebx + DRAWVERT_XYZ_OFFSET + 8] + subss xmm7, [esi + ecx + DRAWVERT_XYZ_OFFSET + 8] movss xmm5, xmm7 movaps xmm6, xmm4 @@ -13320,121 +13477,121 @@ void VPCALL idSIMD_SSE::DeriveTriPlanes( idPlane *planes, const idDrawVert *vert addps xmm3, xmm6 rsqrtps xmm3, xmm3 - add edx, 4*16 - mov ecx, [edi+eax-1*12+0] + add edx, 4 * 16 + mov ecx, [edi + eax - 1 * 12 + 0] imul ecx, DRAWVERT_SIZE mulps xmm0, xmm3 mulps xmm1, xmm3 mulps xmm2, xmm3 - movss [edx-1*16+0], xmm0 - movss [edx-1*16+4], xmm1 - movss [edx-1*16+8], xmm2 + movss [edx - 1 * 16 + 0], xmm0 + movss [edx - 1 * 16 + 4], xmm1 + movss [edx - 1 * 16 + 8], xmm2 - mulss xmm0, [esi+ecx+DRAWVERT_XYZ_OFFSET+0] - mulss xmm1, [esi+ecx+DRAWVERT_XYZ_OFFSET+4] - mulss xmm2, [esi+ecx+DRAWVERT_XYZ_OFFSET+8] + mulss xmm0, [esi + ecx + DRAWVERT_XYZ_OFFSET + 0] + mulss xmm1, [esi + ecx + DRAWVERT_XYZ_OFFSET + 4] + mulss xmm2, [esi + ecx + DRAWVERT_XYZ_OFFSET + 8] xorps xmm0, SIMD_SP_singleSignBitMask subss xmm0, xmm1 subss xmm0, xmm2 - movss [edx-1*16+12], xmm0 + movss [edx - 1 * 16 + 12], xmm0 - mov ecx, [edi+eax-2*12+0] + mov ecx, [edi + eax - 2 * 12 + 0] imul ecx, DRAWVERT_SIZE shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [edx-2*16+0], xmm0 - movss [edx-2*16+4], xmm1 - movss [edx-2*16+8], xmm2 + movss [edx - 2 * 16 + 0], xmm0 + movss [edx - 2 * 16 + 4], xmm1 + movss [edx - 2 * 16 + 8], xmm2 - mulss xmm0, [esi+ecx+DRAWVERT_XYZ_OFFSET+0] - mulss xmm1, [esi+ecx+DRAWVERT_XYZ_OFFSET+4] - mulss xmm2, [esi+ecx+DRAWVERT_XYZ_OFFSET+8] + mulss xmm0, [esi + ecx + DRAWVERT_XYZ_OFFSET + 0] + mulss xmm1, [esi + ecx + DRAWVERT_XYZ_OFFSET + 4] + mulss xmm2, [esi + ecx + DRAWVERT_XYZ_OFFSET + 8] xorps xmm0, SIMD_SP_singleSignBitMask subss xmm0, xmm1 subss xmm0, xmm2 - movss [edx-2*16+12], xmm0 + movss [edx - 2 * 16 + 12], xmm0 - mov ecx, [edi+eax-3*12+0] + mov ecx, [edi + eax - 3 * 12 + 0] imul ecx, DRAWVERT_SIZE shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [edx-3*16+0], xmm0 - movss [edx-3*16+4], xmm1 - movss [edx-3*16+8], xmm2 + movss [edx - 3 * 16 + 0], xmm0 + movss [edx - 3 * 16 + 4], xmm1 + movss [edx - 3 * 16 + 8], xmm2 - mulss xmm0, [esi+ecx+DRAWVERT_XYZ_OFFSET+0] - mulss xmm1, [esi+ecx+DRAWVERT_XYZ_OFFSET+4] - mulss xmm2, [esi+ecx+DRAWVERT_XYZ_OFFSET+8] + mulss xmm0, [esi + ecx + DRAWVERT_XYZ_OFFSET + 0] + mulss xmm1, [esi + ecx + DRAWVERT_XYZ_OFFSET + 4] + mulss xmm2, [esi + ecx + DRAWVERT_XYZ_OFFSET + 8] xorps xmm0, SIMD_SP_singleSignBitMask subss xmm0, xmm1 subss xmm0, xmm2 - movss [edx-3*16+12], xmm0 + movss [edx - 3 * 16 + 12], xmm0 - mov ecx, [edi+eax-4*12+0] + mov ecx, [edi + eax - 4 * 12 + 0] imul ecx, DRAWVERT_SIZE shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [edx-4*16+0], xmm0 - movss [edx-4*16+4], xmm1 - movss [edx-4*16+8], xmm2 + movss [edx - 4 * 16 + 0], xmm0 + movss [edx - 4 * 16 + 4], xmm1 + movss [edx - 4 * 16 + 8], xmm2 - mulss xmm0, [esi+ecx+DRAWVERT_XYZ_OFFSET+0] - mulss xmm1, [esi+ecx+DRAWVERT_XYZ_OFFSET+4] - mulss xmm2, [esi+ecx+DRAWVERT_XYZ_OFFSET+8] + mulss xmm0, [esi + ecx + DRAWVERT_XYZ_OFFSET + 0] + mulss xmm1, [esi + ecx + DRAWVERT_XYZ_OFFSET + 4] + mulss xmm2, [esi + ecx + DRAWVERT_XYZ_OFFSET + 8] xorps xmm0, SIMD_SP_singleSignBitMask subss xmm0, xmm1 subss xmm0, xmm2 - movss [edx-4*16+12], xmm0 + movss [edx - 4 * 16 + 12], xmm0 - add eax, 4*12 + add eax, 4 * 12 jle loopPlane4 - done4: + done4: - sub eax, 4*12 + sub eax, 4 * 12 jge done - loopPlane1: - mov ebx, [edi+eax+4] + loopPlane1: + mov ebx, [edi + eax + 4] imul ebx, DRAWVERT_SIZE - mov ecx, [edi+eax+0] + mov ecx, [edi + eax + 0] imul ecx, DRAWVERT_SIZE - movss xmm0, [esi+ebx+DRAWVERT_XYZ_OFFSET+0] - subss xmm0, [esi+ecx+DRAWVERT_XYZ_OFFSET+0] + movss xmm0, [esi + ebx + DRAWVERT_XYZ_OFFSET + 0] + subss xmm0, [esi + ecx + DRAWVERT_XYZ_OFFSET + 0] - movss xmm1, [esi+ebx+DRAWVERT_XYZ_OFFSET+4] - subss xmm1, [esi+ecx+DRAWVERT_XYZ_OFFSET+4] + movss xmm1, [esi + ebx + DRAWVERT_XYZ_OFFSET + 4] + subss xmm1, [esi + ecx + DRAWVERT_XYZ_OFFSET + 4] - movss xmm2, [esi+ebx+DRAWVERT_XYZ_OFFSET+8] - subss xmm2, [esi+ecx+DRAWVERT_XYZ_OFFSET+8] + movss xmm2, [esi + ebx + DRAWVERT_XYZ_OFFSET + 8] + subss xmm2, [esi + ecx + DRAWVERT_XYZ_OFFSET + 8] - mov ebx, [edi+eax+8] + mov ebx, [edi + eax + 8] imul ebx, DRAWVERT_SIZE - movss xmm3, [esi+ebx+DRAWVERT_XYZ_OFFSET+0] - subss xmm3, [esi+ecx+DRAWVERT_XYZ_OFFSET+0] + movss xmm3, [esi + ebx + DRAWVERT_XYZ_OFFSET + 0] + subss xmm3, [esi + ecx + DRAWVERT_XYZ_OFFSET + 0] - movss xmm4, [esi+ebx+DRAWVERT_XYZ_OFFSET+4] - subss xmm4, [esi+ecx+DRAWVERT_XYZ_OFFSET+4] + movss xmm4, [esi + ebx + DRAWVERT_XYZ_OFFSET + 4] + subss xmm4, [esi + ecx + DRAWVERT_XYZ_OFFSET + 4] - movss xmm5, [esi+ebx+DRAWVERT_XYZ_OFFSET+8] - subss xmm5, [esi+ecx+DRAWVERT_XYZ_OFFSET+8] + movss xmm5, [esi + ebx + DRAWVERT_XYZ_OFFSET + 8] + subss xmm5, [esi + ecx + DRAWVERT_XYZ_OFFSET + 8] movss xmm6, xmm4 mulss xmm6, xmm2 @@ -13461,29 +13618,29 @@ void VPCALL idSIMD_SSE::DeriveTriPlanes( idPlane *planes, const idDrawVert *vert addss xmm3, xmm6 rsqrtss xmm3, xmm3 - add edx, 1*16 + add edx, 1 * 16 mulss xmm0, xmm3 mulss xmm1, xmm3 mulss xmm2, xmm3 - movss [edx-1*16+0], xmm0 - movss [edx-1*16+4], xmm1 - movss [edx-1*16+8], xmm2 + movss [edx - 1 * 16 + 0], xmm0 + movss [edx - 1 * 16 + 4], xmm1 + movss [edx - 1 * 16 + 8], xmm2 - mulss xmm0, [esi+ecx+DRAWVERT_XYZ_OFFSET+0] - mulss xmm1, [esi+ecx+DRAWVERT_XYZ_OFFSET+4] - mulss xmm2, [esi+ecx+DRAWVERT_XYZ_OFFSET+8] + mulss xmm0, [esi + ecx + DRAWVERT_XYZ_OFFSET + 0] + mulss xmm1, [esi + ecx + DRAWVERT_XYZ_OFFSET + 4] + mulss xmm2, [esi + ecx + DRAWVERT_XYZ_OFFSET + 8] xorps xmm0, SIMD_SP_singleSignBitMask subss xmm0, xmm1 subss xmm0, xmm2 - movss [edx-1*16+12], xmm0 + movss [edx - 1 * 16 + 12], xmm0 - add eax, 1*12 + add eax, 1 * 12 jl loopPlane1 - done: + done: } #else @@ -13649,9 +13806,9 @@ void VPCALL idSIMD_SSE::DeriveTangents( idPlane *planes, idDrawVert *verts, cons int i; assert( sizeof( idDrawVert ) == DRAWVERT_SIZE ); - assert( (int)&((idDrawVert *)0)->normal == DRAWVERT_NORMAL_OFFSET ); - assert( (int)&((idDrawVert *)0)->tangents[0] == DRAWVERT_TANGENT0_OFFSET ); - assert( (int)&((idDrawVert *)0)->tangents[1] == DRAWVERT_TANGENT1_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->normal == DRAWVERT_NORMAL_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->tangents[0] == DRAWVERT_TANGENT0_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->tangents[1] == DRAWVERT_TANGENT1_OFFSET ); assert( planes != NULL ); assert( verts != NULL ); @@ -13664,7 +13821,7 @@ void VPCALL idSIMD_SSE::DeriveTangents( idPlane *planes, idDrawVert *verts, cons } #endif - bool *used = (bool *)_alloca16( numVerts * sizeof( used[0] ) ); + bool *used = ( bool * )_alloca16( numVerts * sizeof( used[0] ) ); memset( used, 0, numVerts * sizeof( used[0] ) ); for ( i = 0; i <= numIndexes - 12; i += 12 ) { @@ -13972,10 +14129,10 @@ void VPCALL idSIMD_SSE::DeriveTangents( idPlane *planes, idDrawVert *verts, cons tmp[2] -= d4[2] * d8[2]; tmp[3] -= d4[3] * d8[3]; - signBit[0] = ( *(unsigned int *)&tmp[0] ) & ( 1 << 31 ); - signBit[1] = ( *(unsigned int *)&tmp[1] ) & ( 1 << 31 ); - signBit[2] = ( *(unsigned int *)&tmp[2] ) & ( 1 << 31 ); - signBit[3] = ( *(unsigned int *)&tmp[3] ) & ( 1 << 31 ); + signBit[0] = ( *( unsigned int * )&tmp[0] ) & ( 1 << 31 ); + signBit[1] = ( *( unsigned int * )&tmp[1] ) & ( 1 << 31 ); + signBit[2] = ( *( unsigned int * )&tmp[2] ) & ( 1 << 31 ); + signBit[3] = ( *( unsigned int * )&tmp[3] ) & ( 1 << 31 ); // first tangent t0[0] = d0[0] * d9[0]; @@ -14028,10 +14185,10 @@ void VPCALL idSIMD_SSE::DeriveTangents( idPlane *planes, idDrawVert *verts, cons tmp[2] = idMath::RSqrt( tmp[2] ); tmp[3] = idMath::RSqrt( tmp[3] ); - *(unsigned int *)&tmp[0] ^= signBit[0]; - *(unsigned int *)&tmp[1] ^= signBit[1]; - *(unsigned int *)&tmp[2] ^= signBit[2]; - *(unsigned int *)&tmp[3] ^= signBit[3]; + *( unsigned int * )&tmp[0] ^= signBit[0]; + *( unsigned int * )&tmp[1] ^= signBit[1]; + *( unsigned int * )&tmp[2] ^= signBit[2]; + *( unsigned int * )&tmp[3] ^= signBit[3]; t0[0] *= tmp[0]; t0[1] *= tmp[1]; @@ -14099,10 +14256,10 @@ void VPCALL idSIMD_SSE::DeriveTangents( idPlane *planes, idDrawVert *verts, cons tmp[2] = idMath::RSqrt( tmp[2] ); tmp[3] = idMath::RSqrt( tmp[3] ); - *(unsigned int *)&tmp[0] ^= signBit[0]; - *(unsigned int *)&tmp[1] ^= signBit[1]; - *(unsigned int *)&tmp[2] ^= signBit[2]; - *(unsigned int *)&tmp[3] ^= signBit[3]; + *( unsigned int * )&tmp[0] ^= signBit[0]; + *( unsigned int * )&tmp[1] ^= signBit[1]; + *( unsigned int * )&tmp[2] ^= signBit[2]; + *( unsigned int * )&tmp[3] ^= signBit[3]; t3[0] *= tmp[0]; t3[1] *= tmp[1]; @@ -14451,7 +14608,7 @@ void VPCALL idSIMD_SSE::DeriveTangents( idPlane *planes, idDrawVert *verts, cons // area sign bit tmp = d3 * d9 - d4 * d8; - signBit[0] = ( *(unsigned int *)&tmp ) & ( 1 << 31 ); + signBit[0] = ( *( unsigned int * )&tmp ) & ( 1 << 31 ); // first tangent t0 = d0 * d9 - d4 * d5; @@ -14459,7 +14616,7 @@ void VPCALL idSIMD_SSE::DeriveTangents( idPlane *planes, idDrawVert *verts, cons t2 = d2 * d9 - d4 * d7; tmp = idMath::RSqrt( t0 * t0 + t1 * t1 + t2 * t2 ); - *(unsigned int *)&tmp ^= signBit[0]; + *( unsigned int * )&tmp ^= signBit[0]; t0 *= tmp; t1 *= tmp; @@ -14471,7 +14628,7 @@ void VPCALL idSIMD_SSE::DeriveTangents( idPlane *planes, idDrawVert *verts, cons t5 = d3 * d7 - d2 * d8; tmp = idMath::RSqrt( t3 * t3 + t4 * t4 + t5 * t5 ); - *(unsigned int *)&tmp ^= signBit[0]; + *( unsigned int * )&tmp ^= signBit[0]; t3 *= tmp; t4 *= tmp; @@ -14608,7 +14765,7 @@ void VPCALL idSIMD_SSE::DeriveUnsmoothedTangents( idDrawVert *verts, const domin for ( j = 0; j < 4; j++ ) { const idDrawVert *a, *b, *c; - const dominantTri_s &dt = dominantTris[i+j]; + const dominantTri_s &dt = dominantTris[i + j]; s0[j] = dt.normalizationScale[0]; s1[j] = dt.normalizationScale[1]; @@ -15100,9 +15257,9 @@ void VPCALL idSIMD_SSE::NormalizeTangents( idDrawVert *verts, const int numVerts ALIGN16( float normal[12] ); assert( sizeof( idDrawVert ) == DRAWVERT_SIZE ); - assert( (int)&((idDrawVert *)0)->normal == DRAWVERT_NORMAL_OFFSET ); - assert( (int)&((idDrawVert *)0)->tangents[0] == DRAWVERT_TANGENT0_OFFSET ); - assert( (int)&((idDrawVert *)0)->tangents[1] == DRAWVERT_TANGENT1_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->normal == DRAWVERT_NORMAL_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->tangents[0] == DRAWVERT_TANGENT0_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->tangents[1] == DRAWVERT_TANGENT1_OFFSET ); assert( verts != NULL ); assert( numVerts >= 0 ); @@ -15125,7 +15282,7 @@ void VPCALL idSIMD_SSE::NormalizeTangents( idDrawVert *verts, const int numVerts sub eax, DRAWVERT_SIZE*4 jl loopVert1 - loopVert4: + loopVert4: sub eax, DRAWVERT_SIZE*4 @@ -15175,48 +15332,48 @@ void VPCALL idSIMD_SSE::NormalizeTangents( idDrawVert *verts, const int numVerts // save the 4 idDrawVert::normal to project the tangents - movaps [normal+ 0], xmm0 - movaps [normal+16], xmm1 - movaps [normal+32], xmm2 + movaps [normal + 0], xmm0 + movaps [normal + 16], xmm1 + movaps [normal + 32], xmm2 - movss [esi+eax+DRAWVERT_SIZE*0+DRAWVERT_NORMAL_OFFSET+0], xmm0 - movss [esi+eax+DRAWVERT_SIZE*0+DRAWVERT_NORMAL_OFFSET+4], xmm1 - movss [esi+eax+DRAWVERT_SIZE*0+DRAWVERT_NORMAL_OFFSET+8], xmm2 + movss [esi + eax + DRAWVERT_SIZE * 0 + DRAWVERT_NORMAL_OFFSET + 0], xmm0 + movss [esi + eax + DRAWVERT_SIZE * 0 + DRAWVERT_NORMAL_OFFSET + 4], xmm1 + movss [esi + eax + DRAWVERT_SIZE * 0 + DRAWVERT_NORMAL_OFFSET + 8], xmm2 shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [esi+eax+DRAWVERT_SIZE*1+DRAWVERT_NORMAL_OFFSET+0], xmm0 - movss [esi+eax+DRAWVERT_SIZE*1+DRAWVERT_NORMAL_OFFSET+4], xmm1 - movss [esi+eax+DRAWVERT_SIZE*1+DRAWVERT_NORMAL_OFFSET+8], xmm2 + movss [esi + eax + DRAWVERT_SIZE * 1 + DRAWVERT_NORMAL_OFFSET + 0], xmm0 + movss [esi + eax + DRAWVERT_SIZE * 1 + DRAWVERT_NORMAL_OFFSET + 4], xmm1 + movss [esi + eax + DRAWVERT_SIZE * 1 + DRAWVERT_NORMAL_OFFSET + 8], xmm2 shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [esi+eax+DRAWVERT_SIZE*2+DRAWVERT_NORMAL_OFFSET+0], xmm0 - movss [esi+eax+DRAWVERT_SIZE*2+DRAWVERT_NORMAL_OFFSET+4], xmm1 - movss [esi+eax+DRAWVERT_SIZE*2+DRAWVERT_NORMAL_OFFSET+8], xmm2 + movss [esi + eax + DRAWVERT_SIZE * 2 + DRAWVERT_NORMAL_OFFSET + 0], xmm0 + movss [esi + eax + DRAWVERT_SIZE * 2 + DRAWVERT_NORMAL_OFFSET + 4], xmm1 + movss [esi + eax + DRAWVERT_SIZE * 2 + DRAWVERT_NORMAL_OFFSET + 8], xmm2 shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [esi+eax+DRAWVERT_SIZE*3+DRAWVERT_NORMAL_OFFSET+0], xmm0 - movss [esi+eax+DRAWVERT_SIZE*3+DRAWVERT_NORMAL_OFFSET+4], xmm1 - movss [esi+eax+DRAWVERT_SIZE*3+DRAWVERT_NORMAL_OFFSET+8], xmm2 + movss [esi + eax + DRAWVERT_SIZE * 3 + DRAWVERT_NORMAL_OFFSET + 0], xmm0 + movss [esi + eax + DRAWVERT_SIZE * 3 + DRAWVERT_NORMAL_OFFSET + 4], xmm1 + movss [esi + eax + DRAWVERT_SIZE * 3 + DRAWVERT_NORMAL_OFFSET + 8], xmm2 // project and normalize 4 idDrawVert::tangent[0] - movss xmm0, [esi+eax+DRAWVERT_SIZE*0+DRAWVERT_TANGENT0_OFFSET+0] // 0, X, X, X - movhps xmm0, [esi+eax+DRAWVERT_SIZE*1+DRAWVERT_TANGENT0_OFFSET+0] // 0, X, 3, 4 - movss xmm2, [esi+eax+DRAWVERT_SIZE*1+DRAWVERT_TANGENT0_OFFSET+8] // 5, X, X, X - movhps xmm2, [esi+eax+DRAWVERT_SIZE*0+DRAWVERT_TANGENT0_OFFSET+4] // 5, X, 1, 2 - movss xmm4, [esi+eax+DRAWVERT_SIZE*2+DRAWVERT_TANGENT0_OFFSET+0] // 6, X, X, X - movhps xmm4, [esi+eax+DRAWVERT_SIZE*3+DRAWVERT_TANGENT0_OFFSET+0] // 6, X, 9, 10 - movss xmm3, [esi+eax+DRAWVERT_SIZE*3+DRAWVERT_TANGENT0_OFFSET+8] // 11, X, X, X - movhps xmm3, [esi+eax+DRAWVERT_SIZE*2+DRAWVERT_TANGENT0_OFFSET+4] // 11, X, 7, 8 + movss xmm0, [esi + eax + DRAWVERT_SIZE * 0 + DRAWVERT_TANGENT0_OFFSET + 0] // 0, X, X, X + movhps xmm0, [esi + eax + DRAWVERT_SIZE * 1 + DRAWVERT_TANGENT0_OFFSET + 0] // 0, X, 3, 4 + movss xmm2, [esi + eax + DRAWVERT_SIZE * 1 + DRAWVERT_TANGENT0_OFFSET + 8] // 5, X, X, X + movhps xmm2, [esi + eax + DRAWVERT_SIZE * 0 + DRAWVERT_TANGENT0_OFFSET + 4] // 5, X, 1, 2 + movss xmm4, [esi + eax + DRAWVERT_SIZE * 2 + DRAWVERT_TANGENT0_OFFSET + 0] // 6, X, X, X + movhps xmm4, [esi + eax + DRAWVERT_SIZE * 3 + DRAWVERT_TANGENT0_OFFSET + 0] // 6, X, 9, 10 + movss xmm3, [esi + eax + DRAWVERT_SIZE * 3 + DRAWVERT_TANGENT0_OFFSET + 8] // 11, X, X, X + movhps xmm3, [esi + eax + DRAWVERT_SIZE * 2 + DRAWVERT_TANGENT0_OFFSET + 4] // 11, X, 7, 8 movaps xmm1, xmm0 movaps xmm5, xmm2 @@ -15230,17 +15387,17 @@ void VPCALL idSIMD_SSE::NormalizeTangents( idDrawVert *verts, const int numVerts movaps xmm4, xmm1 movaps xmm5, xmm2 - mulps xmm3, [normal+ 0] - mulps xmm4, [normal+16] - mulps xmm5, [normal+32] + mulps xmm3, [normal + 0] + mulps xmm4, [normal + 16] + mulps xmm5, [normal + 32] addps xmm3, xmm4 addps xmm3, xmm5 movaps xmm4, xmm3 movaps xmm5, xmm3 - mulps xmm3, [normal+ 0] - mulps xmm4, [normal+16] - mulps xmm5, [normal+32] + mulps xmm3, [normal + 0] + mulps xmm4, [normal + 16] + mulps xmm5, [normal + 32] subps xmm0, xmm3 subps xmm1, xmm4 subps xmm2, xmm5 @@ -15270,44 +15427,44 @@ void VPCALL idSIMD_SSE::NormalizeTangents( idDrawVert *verts, const int numVerts mulps xmm1, xmm3 mulps xmm2, xmm3 - movss [esi+eax+DRAWVERT_SIZE*0+DRAWVERT_TANGENT0_OFFSET+0], xmm0 - movss [esi+eax+DRAWVERT_SIZE*0+DRAWVERT_TANGENT0_OFFSET+4], xmm1 - movss [esi+eax+DRAWVERT_SIZE*0+DRAWVERT_TANGENT0_OFFSET+8], xmm2 + movss [esi + eax + DRAWVERT_SIZE * 0 + DRAWVERT_TANGENT0_OFFSET + 0], xmm0 + movss [esi + eax + DRAWVERT_SIZE * 0 + DRAWVERT_TANGENT0_OFFSET + 4], xmm1 + movss [esi + eax + DRAWVERT_SIZE * 0 + DRAWVERT_TANGENT0_OFFSET + 8], xmm2 shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [esi+eax+DRAWVERT_SIZE*1+DRAWVERT_TANGENT0_OFFSET+0], xmm0 - movss [esi+eax+DRAWVERT_SIZE*1+DRAWVERT_TANGENT0_OFFSET+4], xmm1 - movss [esi+eax+DRAWVERT_SIZE*1+DRAWVERT_TANGENT0_OFFSET+8], xmm2 + movss [esi + eax + DRAWVERT_SIZE * 1 + DRAWVERT_TANGENT0_OFFSET + 0], xmm0 + movss [esi + eax + DRAWVERT_SIZE * 1 + DRAWVERT_TANGENT0_OFFSET + 4], xmm1 + movss [esi + eax + DRAWVERT_SIZE * 1 + DRAWVERT_TANGENT0_OFFSET + 8], xmm2 shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [esi+eax+DRAWVERT_SIZE*2+DRAWVERT_TANGENT0_OFFSET+0], xmm0 - movss [esi+eax+DRAWVERT_SIZE*2+DRAWVERT_TANGENT0_OFFSET+4], xmm1 - movss [esi+eax+DRAWVERT_SIZE*2+DRAWVERT_TANGENT0_OFFSET+8], xmm2 + movss [esi + eax + DRAWVERT_SIZE * 2 + DRAWVERT_TANGENT0_OFFSET + 0], xmm0 + movss [esi + eax + DRAWVERT_SIZE * 2 + DRAWVERT_TANGENT0_OFFSET + 4], xmm1 + movss [esi + eax + DRAWVERT_SIZE * 2 + DRAWVERT_TANGENT0_OFFSET + 8], xmm2 shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [esi+eax+DRAWVERT_SIZE*3+DRAWVERT_TANGENT0_OFFSET+0], xmm0 - movss [esi+eax+DRAWVERT_SIZE*3+DRAWVERT_TANGENT0_OFFSET+4], xmm1 - movss [esi+eax+DRAWVERT_SIZE*3+DRAWVERT_TANGENT0_OFFSET+8], xmm2 + movss [esi + eax + DRAWVERT_SIZE * 3 + DRAWVERT_TANGENT0_OFFSET + 0], xmm0 + movss [esi + eax + DRAWVERT_SIZE * 3 + DRAWVERT_TANGENT0_OFFSET + 4], xmm1 + movss [esi + eax + DRAWVERT_SIZE * 3 + DRAWVERT_TANGENT0_OFFSET + 8], xmm2 // project and normalize 4 idDrawVert::tangent[1] - movss xmm0, [esi+eax+DRAWVERT_SIZE*0+DRAWVERT_TANGENT1_OFFSET+0] // 0, X, X, X - movhps xmm0, [esi+eax+DRAWVERT_SIZE*1+DRAWVERT_TANGENT1_OFFSET+0] // 0, X, 3, 4 - movss xmm2, [esi+eax+DRAWVERT_SIZE*1+DRAWVERT_TANGENT1_OFFSET+8] // 5, X, X, X - movhps xmm2, [esi+eax+DRAWVERT_SIZE*0+DRAWVERT_TANGENT1_OFFSET+4] // 5, X, 1, 2 - movss xmm4, [esi+eax+DRAWVERT_SIZE*2+DRAWVERT_TANGENT1_OFFSET+0] // 6, X, X, X - movhps xmm4, [esi+eax+DRAWVERT_SIZE*3+DRAWVERT_TANGENT1_OFFSET+0] // 6, X, 9, 10 - movss xmm3, [esi+eax+DRAWVERT_SIZE*3+DRAWVERT_TANGENT1_OFFSET+8] // 11, X, X, X - movhps xmm3, [esi+eax+DRAWVERT_SIZE*2+DRAWVERT_TANGENT1_OFFSET+4] // 11, X, 7, 8 + movss xmm0, [esi + eax + DRAWVERT_SIZE * 0 + DRAWVERT_TANGENT1_OFFSET + 0] // 0, X, X, X + movhps xmm0, [esi + eax + DRAWVERT_SIZE * 1 + DRAWVERT_TANGENT1_OFFSET + 0] // 0, X, 3, 4 + movss xmm2, [esi + eax + DRAWVERT_SIZE * 1 + DRAWVERT_TANGENT1_OFFSET + 8] // 5, X, X, X + movhps xmm2, [esi + eax + DRAWVERT_SIZE * 0 + DRAWVERT_TANGENT1_OFFSET + 4] // 5, X, 1, 2 + movss xmm4, [esi + eax + DRAWVERT_SIZE * 2 + DRAWVERT_TANGENT1_OFFSET + 0] // 6, X, X, X + movhps xmm4, [esi + eax + DRAWVERT_SIZE * 3 + DRAWVERT_TANGENT1_OFFSET + 0] // 6, X, 9, 10 + movss xmm3, [esi + eax + DRAWVERT_SIZE * 3 + DRAWVERT_TANGENT1_OFFSET + 8] // 11, X, X, X + movhps xmm3, [esi + eax + DRAWVERT_SIZE * 2 + DRAWVERT_TANGENT1_OFFSET + 4] // 11, X, 7, 8 movaps xmm1, xmm0 movaps xmm5, xmm2 @@ -15321,17 +15478,17 @@ void VPCALL idSIMD_SSE::NormalizeTangents( idDrawVert *verts, const int numVerts movaps xmm4, xmm1 movaps xmm5, xmm2 - mulps xmm3, [normal+ 0] - mulps xmm4, [normal+16] - mulps xmm5, [normal+32] + mulps xmm3, [normal + 0] + mulps xmm4, [normal + 16] + mulps xmm5, [normal + 32] addps xmm3, xmm4 addps xmm3, xmm5 movaps xmm4, xmm3 movaps xmm5, xmm3 - mulps xmm3, [normal+ 0] - mulps xmm4, [normal+16] - mulps xmm5, [normal+32] + mulps xmm3, [normal + 0] + mulps xmm4, [normal + 16] + mulps xmm5, [normal + 32] subps xmm0, xmm3 subps xmm1, xmm4 subps xmm2, xmm5 @@ -15361,48 +15518,48 @@ void VPCALL idSIMD_SSE::NormalizeTangents( idDrawVert *verts, const int numVerts mulps xmm1, xmm3 mulps xmm2, xmm3 - movss [esi+eax+DRAWVERT_SIZE*0+DRAWVERT_TANGENT1_OFFSET+0], xmm0 - movss [esi+eax+DRAWVERT_SIZE*0+DRAWVERT_TANGENT1_OFFSET+4], xmm1 - movss [esi+eax+DRAWVERT_SIZE*0+DRAWVERT_TANGENT1_OFFSET+8], xmm2 + movss [esi + eax + DRAWVERT_SIZE * 0 + DRAWVERT_TANGENT1_OFFSET + 0], xmm0 + movss [esi + eax + DRAWVERT_SIZE * 0 + DRAWVERT_TANGENT1_OFFSET + 4], xmm1 + movss [esi + eax + DRAWVERT_SIZE * 0 + DRAWVERT_TANGENT1_OFFSET + 8], xmm2 shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [esi+eax+DRAWVERT_SIZE*1+DRAWVERT_TANGENT1_OFFSET+0], xmm0 - movss [esi+eax+DRAWVERT_SIZE*1+DRAWVERT_TANGENT1_OFFSET+4], xmm1 - movss [esi+eax+DRAWVERT_SIZE*1+DRAWVERT_TANGENT1_OFFSET+8], xmm2 + movss [esi + eax + DRAWVERT_SIZE * 1 + DRAWVERT_TANGENT1_OFFSET + 0], xmm0 + movss [esi + eax + DRAWVERT_SIZE * 1 + DRAWVERT_TANGENT1_OFFSET + 4], xmm1 + movss [esi + eax + DRAWVERT_SIZE * 1 + DRAWVERT_TANGENT1_OFFSET + 8], xmm2 shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [esi+eax+DRAWVERT_SIZE*2+DRAWVERT_TANGENT1_OFFSET+0], xmm0 - movss [esi+eax+DRAWVERT_SIZE*2+DRAWVERT_TANGENT1_OFFSET+4], xmm1 - movss [esi+eax+DRAWVERT_SIZE*2+DRAWVERT_TANGENT1_OFFSET+8], xmm2 + movss [esi + eax + DRAWVERT_SIZE * 2 + DRAWVERT_TANGENT1_OFFSET + 0], xmm0 + movss [esi + eax + DRAWVERT_SIZE * 2 + DRAWVERT_TANGENT1_OFFSET + 4], xmm1 + movss [esi + eax + DRAWVERT_SIZE * 2 + DRAWVERT_TANGENT1_OFFSET + 8], xmm2 shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm1, xmm1, R_SHUFFLEPS( 1, 2, 3, 0 ) shufps xmm2, xmm2, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [esi+eax+DRAWVERT_SIZE*3+DRAWVERT_TANGENT1_OFFSET+0], xmm0 - movss [esi+eax+DRAWVERT_SIZE*3+DRAWVERT_TANGENT1_OFFSET+4], xmm1 - movss [esi+eax+DRAWVERT_SIZE*3+DRAWVERT_TANGENT1_OFFSET+8], xmm2 + movss [esi + eax + DRAWVERT_SIZE * 3 + DRAWVERT_TANGENT1_OFFSET + 0], xmm0 + movss [esi + eax + DRAWVERT_SIZE * 3 + DRAWVERT_TANGENT1_OFFSET + 4], xmm1 + movss [esi + eax + DRAWVERT_SIZE * 3 + DRAWVERT_TANGENT1_OFFSET + 8], xmm2 - add eax, DRAWVERT_SIZE*8 + add eax, DRAWVERT_SIZE * 8 jle loopVert4 - sub eax, DRAWVERT_SIZE*4 + sub eax, DRAWVERT_SIZE * 4 jge done - loopVert1: + loopVert1: // normalize one idDrawVert::normal - movss xmm0, [esi+eax+DRAWVERT_NORMAL_OFFSET+0] - movss xmm1, [esi+eax+DRAWVERT_NORMAL_OFFSET+4] - movss xmm2, [esi+eax+DRAWVERT_NORMAL_OFFSET+8] + movss xmm0, [esi + eax + DRAWVERT_NORMAL_OFFSET + 0] + movss xmm1, [esi + eax + DRAWVERT_NORMAL_OFFSET + 4] + movss xmm2, [esi + eax + DRAWVERT_NORMAL_OFFSET + 8] movss xmm3, xmm0 movss xmm4, xmm1 movss xmm5, xmm2 @@ -15428,30 +15585,30 @@ void VPCALL idSIMD_SSE::NormalizeTangents( idDrawVert *verts, const int numVerts mulss xmm1, xmm3 mulss xmm2, xmm3 - movss [esi+eax+DRAWVERT_NORMAL_OFFSET+0], xmm0 - movss [esi+eax+DRAWVERT_NORMAL_OFFSET+4], xmm1 - movss [esi+eax+DRAWVERT_NORMAL_OFFSET+8], xmm2 + movss [esi + eax + DRAWVERT_NORMAL_OFFSET + 0], xmm0 + movss [esi + eax + DRAWVERT_NORMAL_OFFSET + 4], xmm1 + movss [esi + eax + DRAWVERT_NORMAL_OFFSET + 8], xmm2 // project and normalize one idDrawVert::tangent[0] - movss xmm0, [esi+eax+DRAWVERT_TANGENT0_OFFSET+0] - movss xmm1, [esi+eax+DRAWVERT_TANGENT0_OFFSET+4] - movss xmm2, [esi+eax+DRAWVERT_TANGENT0_OFFSET+8] + movss xmm0, [esi + eax + DRAWVERT_TANGENT0_OFFSET + 0] + movss xmm1, [esi + eax + DRAWVERT_TANGENT0_OFFSET + 4] + movss xmm2, [esi + eax + DRAWVERT_TANGENT0_OFFSET + 8] movss xmm3, xmm0 movss xmm4, xmm1 movss xmm5, xmm2 - mulss xmm3, [esi+eax+DRAWVERT_NORMAL_OFFSET+0] - mulss xmm4, [esi+eax+DRAWVERT_NORMAL_OFFSET+4] - mulss xmm5, [esi+eax+DRAWVERT_NORMAL_OFFSET+8] + mulss xmm3, [esi + eax + DRAWVERT_NORMAL_OFFSET + 0] + mulss xmm4, [esi + eax + DRAWVERT_NORMAL_OFFSET + 4] + mulss xmm5, [esi + eax + DRAWVERT_NORMAL_OFFSET + 8] addss xmm3, xmm4 addss xmm3, xmm5 movss xmm4, xmm3 movss xmm5, xmm3 - mulss xmm3, [esi+eax+DRAWVERT_NORMAL_OFFSET+0] - mulss xmm4, [esi+eax+DRAWVERT_NORMAL_OFFSET+4] - mulss xmm5, [esi+eax+DRAWVERT_NORMAL_OFFSET+8] + mulss xmm3, [esi + eax + DRAWVERT_NORMAL_OFFSET + 0] + mulss xmm4, [esi + eax + DRAWVERT_NORMAL_OFFSET + 4] + mulss xmm5, [esi + eax + DRAWVERT_NORMAL_OFFSET + 8] subss xmm0, xmm3 subss xmm1, xmm4 subss xmm2, xmm5 @@ -15481,30 +15638,30 @@ void VPCALL idSIMD_SSE::NormalizeTangents( idDrawVert *verts, const int numVerts mulss xmm1, xmm3 mulss xmm2, xmm3 - movss [esi+eax+DRAWVERT_TANGENT0_OFFSET+0], xmm0 - movss [esi+eax+DRAWVERT_TANGENT0_OFFSET+4], xmm1 - movss [esi+eax+DRAWVERT_TANGENT0_OFFSET+8], xmm2 + movss [esi + eax + DRAWVERT_TANGENT0_OFFSET + 0], xmm0 + movss [esi + eax + DRAWVERT_TANGENT0_OFFSET + 4], xmm1 + movss [esi + eax + DRAWVERT_TANGENT0_OFFSET + 8], xmm2 // project and normalize one idDrawVert::tangent[1] - movss xmm0, [esi+eax+DRAWVERT_TANGENT1_OFFSET+0] - movss xmm1, [esi+eax+DRAWVERT_TANGENT1_OFFSET+4] - movss xmm2, [esi+eax+DRAWVERT_TANGENT1_OFFSET+8] + movss xmm0, [esi + eax + DRAWVERT_TANGENT1_OFFSET + 0] + movss xmm1, [esi + eax + DRAWVERT_TANGENT1_OFFSET + 4] + movss xmm2, [esi + eax + DRAWVERT_TANGENT1_OFFSET + 8] movss xmm3, xmm0 movss xmm4, xmm1 movss xmm5, xmm2 - mulss xmm3, [esi+eax+DRAWVERT_NORMAL_OFFSET+0] - mulss xmm4, [esi+eax+DRAWVERT_NORMAL_OFFSET+4] - mulss xmm5, [esi+eax+DRAWVERT_NORMAL_OFFSET+8] + mulss xmm3, [esi + eax + DRAWVERT_NORMAL_OFFSET + 0] + mulss xmm4, [esi + eax + DRAWVERT_NORMAL_OFFSET + 4] + mulss xmm5, [esi + eax + DRAWVERT_NORMAL_OFFSET + 8] addss xmm3, xmm4 addss xmm3, xmm5 movss xmm4, xmm3 movss xmm5, xmm3 - mulss xmm3, [esi+eax+DRAWVERT_NORMAL_OFFSET+0] - mulss xmm4, [esi+eax+DRAWVERT_NORMAL_OFFSET+4] - mulss xmm5, [esi+eax+DRAWVERT_NORMAL_OFFSET+8] + mulss xmm3, [esi + eax + DRAWVERT_NORMAL_OFFSET + 0] + mulss xmm4, [esi + eax + DRAWVERT_NORMAL_OFFSET + 4] + mulss xmm5, [esi + eax + DRAWVERT_NORMAL_OFFSET + 8] subss xmm0, xmm3 subss xmm1, xmm4 subss xmm2, xmm5 @@ -15534,14 +15691,14 @@ void VPCALL idSIMD_SSE::NormalizeTangents( idDrawVert *verts, const int numVerts mulss xmm1, xmm3 mulss xmm2, xmm3 - movss [esi+eax+DRAWVERT_TANGENT1_OFFSET+0], xmm0 - movss [esi+eax+DRAWVERT_TANGENT1_OFFSET+4], xmm1 - movss [esi+eax+DRAWVERT_TANGENT1_OFFSET+8], xmm2 + movss [esi + eax + DRAWVERT_TANGENT1_OFFSET + 0], xmm0 + movss [esi + eax + DRAWVERT_TANGENT1_OFFSET + 4], xmm1 + movss [esi + eax + DRAWVERT_TANGENT1_OFFSET + 8], xmm2 add eax, DRAWVERT_SIZE jl loopVert1 - done: + done: } } @@ -15553,12 +15710,12 @@ idSIMD_SSE::CreateTextureSpaceLightVectors void VPCALL idSIMD_SSE::CreateTextureSpaceLightVectors( idVec3 *lightVectors, const idVec3 &lightOrigin, const idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes ) { assert( sizeof( idDrawVert ) == DRAWVERT_SIZE ); - assert( (int)&((idDrawVert *)0)->xyz == DRAWVERT_XYZ_OFFSET ); - assert( (int)&((idDrawVert *)0)->normal == DRAWVERT_NORMAL_OFFSET ); - assert( (int)&((idDrawVert *)0)->tangents[0] == DRAWVERT_TANGENT0_OFFSET ); - assert( (int)&((idDrawVert *)0)->tangents[1] == DRAWVERT_TANGENT1_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->xyz == DRAWVERT_XYZ_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->normal == DRAWVERT_NORMAL_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->tangents[0] == DRAWVERT_TANGENT0_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->tangents[1] == DRAWVERT_TANGENT1_OFFSET ); - bool *used = (bool *)_alloca16( numVerts * sizeof( used[0] ) ); + bool *used = ( bool * )_alloca16( numVerts * sizeof( used[0] ) ); memset( used, 0, numVerts * sizeof( used[0] ) ); for ( int i = numIndexes - 1; i >= 0; i-- ) { @@ -15587,7 +15744,7 @@ void VPCALL idSIMD_SSE::CreateTextureSpaceLightVectors( idVec3 *lightVectors, co mov ecx, lightVectors sub ecx, 3*4 - loopVert: + loopVert: inc eax jge done @@ -15628,13 +15785,13 @@ void VPCALL idSIMD_SSE::CreateTextureSpaceLightVectors( idVec3 *lightVectors, co addps xmm5, xmm4 addps xmm5, xmm2 - movlps [ecx+0], xmm5 + movlps [ecx + 0], xmm5 shufps xmm5, xmm5, R_SHUFFLEPS( 2, 3, 0, 1 ) - movss [ecx+8], xmm5 + movss [ecx + 8], xmm5 jmp loopVert - done: + done: } #elif 1 @@ -15687,7 +15844,7 @@ void VPCALL idSIMD_SSE::CreateTextureSpaceLightVectors( idVec3 *lightVectors, co neg eax dec eax - loopVert4: + loopVert4: inc eax jge done4 @@ -15786,9 +15943,9 @@ void VPCALL idSIMD_SSE::CreateTextureSpaceLightVectors( idVec3 *lightVectors, co imul edx, 12 shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [ecx+edx+0], xmm5 - movss [ecx+edx+4], xmm6 - movss [ecx+edx+8], xmm0 + movss [ecx + edx + 0], xmm5 + movss [ecx + edx + 4], xmm6 + movss [ecx + edx + 8], xmm0 shufps xmm5, xmm5, R_SHUFFLEPS( 1, 2, 3, 0 ) mov edx, usedVertNums[8] @@ -15796,9 +15953,9 @@ void VPCALL idSIMD_SSE::CreateTextureSpaceLightVectors( idVec3 *lightVectors, co imul edx, 12 shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [ecx+edx+0], xmm5 - movss [ecx+edx+4], xmm6 - movss [ecx+edx+8], xmm0 + movss [ecx + edx + 0], xmm5 + movss [ecx + edx + 4], xmm6 + movss [ecx + edx + 8], xmm0 shufps xmm5, xmm5, R_SHUFFLEPS( 1, 2, 3, 0 ) mov edx, usedVertNums[12] @@ -15806,14 +15963,14 @@ void VPCALL idSIMD_SSE::CreateTextureSpaceLightVectors( idVec3 *lightVectors, co imul edx, 12 shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [ecx+edx+0], xmm5 - movss [ecx+edx+4], xmm6 - movss [ecx+edx+8], xmm0 + movss [ecx + edx + 0], xmm5 + movss [ecx + edx + 4], xmm6 + movss [ecx + edx + 8], xmm0 xor ecx, ecx jmp loopVert4 - done4: + done4: test ecx, ecx jz done xor eax, eax @@ -15821,49 +15978,49 @@ void VPCALL idSIMD_SSE::CreateTextureSpaceLightVectors( idVec3 *lightVectors, co imul edi, 12 add edi, lightVectors - loopVert1: - movss xmm0, lightDir0[eax*4] - movss xmm1, lightDir1[eax*4] - movss xmm2, lightDir2[eax*4] + loopVert1: + movss xmm0, lightDir0[eax * 4] + movss xmm1, lightDir1[eax * 4] + movss xmm2, lightDir2[eax * 4] - mov edx, usedVertNums[eax*4] + mov edx, usedVertNums[eax * 4] imul edx, 12 - movss xmm3, tangent0[eax*4] + movss xmm3, tangent0[eax * 4] mulss xmm3, xmm0 - movss xmm4, tangent1[eax*4] + movss xmm4, tangent1[eax * 4] mulss xmm4, xmm1 - movss xmm5, tangent2[eax*4] + movss xmm5, tangent2[eax * 4] mulss xmm5, xmm2 addss xmm3, xmm4 addss xmm5, xmm3 - movss [edi+edx+0], xmm5 + movss [edi + edx + 0], xmm5 - movss xmm3, tangent3[eax*4] + movss xmm3, tangent3[eax * 4] mulss xmm3, xmm0 - movss xmm4, tangent4[eax*4] + movss xmm4, tangent4[eax * 4] mulss xmm4, xmm1 - movss xmm6, tangent5[eax*4] + movss xmm6, tangent5[eax * 4] mulss xmm6, xmm2 addss xmm3, xmm4 addss xmm6, xmm3 - movss [edi+edx+4], xmm6 + movss [edi + edx + 4], xmm6 - mulss xmm0, normal0[eax*4] - mulss xmm1, normal1[eax*4] - mulss xmm2, normal2[eax*4] + mulss xmm0, normal0[eax * 4] + mulss xmm1, normal1[eax * 4] + mulss xmm2, normal2[eax * 4] addss xmm0, xmm1 addss xmm0, xmm2 - movss [edi+edx+8], xmm0 + movss [edi + edx + 8], xmm0 inc eax dec ecx jg loopVert1 - done: + done: } #else @@ -15981,12 +16138,12 @@ idSIMD_SSE::CreateSpecularTextureCoords void VPCALL idSIMD_SSE::CreateSpecularTextureCoords( idVec4 *texCoords, const idVec3 &lightOrigin, const idVec3 &viewOrigin, const idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes ) { assert( sizeof( idDrawVert ) == DRAWVERT_SIZE ); - assert( (int)&((idDrawVert *)0)->xyz == DRAWVERT_XYZ_OFFSET ); - assert( (int)&((idDrawVert *)0)->normal == DRAWVERT_NORMAL_OFFSET ); - assert( (int)&((idDrawVert *)0)->tangents[0] == DRAWVERT_TANGENT0_OFFSET ); - assert( (int)&((idDrawVert *)0)->tangents[1] == DRAWVERT_TANGENT1_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->xyz == DRAWVERT_XYZ_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->normal == DRAWVERT_NORMAL_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->tangents[0] == DRAWVERT_TANGENT0_OFFSET ); + assert( ( int ) & ( ( idDrawVert * )0 )->tangents[1] == DRAWVERT_TANGENT1_OFFSET ); - bool *used = (bool *)_alloca16( numVerts * sizeof( used[0] ) ); + bool *used = ( bool * )_alloca16( numVerts * sizeof( used[0] ) ); memset( used, 0, numVerts * sizeof( used[0] ) ); for ( int i = numIndexes - 1; i >= 0; i-- ) { @@ -16019,7 +16176,7 @@ void VPCALL idSIMD_SSE::CreateSpecularTextureCoords( idVec4 *texCoords, const id mov ecx, texCoords sub ecx, 4*4 - loopVert: + loopVert: inc eax jge done @@ -16062,16 +16219,16 @@ void VPCALL idSIMD_SSE::CreateSpecularTextureCoords( idVec4 *texCoords, const id mulps xmm1, xmm5 addps xmm0, xmm1 - movss xmm2, [edi+DRAWVERT_TANGENT0_OFFSET+0] - movhps xmm2, [edi+DRAWVERT_TANGENT0_OFFSET+4] + movss xmm2, [edi + DRAWVERT_TANGENT0_OFFSET + 0] + movhps xmm2, [edi + DRAWVERT_TANGENT0_OFFSET + 4] mulps xmm2, xmm0 - movss xmm3, [edi+DRAWVERT_TANGENT1_OFFSET+0] - movhps xmm3, [edi+DRAWVERT_TANGENT1_OFFSET+4] + movss xmm3, [edi + DRAWVERT_TANGENT1_OFFSET + 0] + movhps xmm3, [edi + DRAWVERT_TANGENT1_OFFSET + 4] mulps xmm3, xmm0 - movss xmm4, [edi+DRAWVERT_NORMAL_OFFSET+0] - movhps xmm4, [edi+DRAWVERT_NORMAL_OFFSET+4] + movss xmm4, [edi + DRAWVERT_NORMAL_OFFSET + 0] + movhps xmm4, [edi + DRAWVERT_NORMAL_OFFSET + 4] mulps xmm4, xmm0 movaps xmm5, xmm2 // xmm5 = 0, X, 1, 2 @@ -16086,12 +16243,12 @@ void VPCALL idSIMD_SSE::CreateSpecularTextureCoords( idVec4 *texCoords, const id addps xmm5, xmm4 addps xmm5, xmm2 - movaps [ecx+0], xmm5 - movss [ecx+12], xmm3 + movaps [ecx + 0], xmm5 + movss [ecx + 12], xmm3 jmp loopVert - done: + done: } #elif 0 @@ -16162,7 +16319,7 @@ void VPCALL idSIMD_SSE::CreateSpecularTextureCoords( idVec4 *texCoords, const id neg eax dec eax - loopVert4: + loopVert4: inc eax jge done4 @@ -16305,10 +16462,10 @@ void VPCALL idSIMD_SSE::CreateSpecularTextureCoords( idVec4 *texCoords, const id shl edx, 4 shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [ecx+edx+0], xmm5 - movss [ecx+edx+4], xmm6 - movss [ecx+edx+8], xmm0 - movss [ecx+edx+12], xmm3 + movss [ecx + edx + 0], xmm5 + movss [ecx + edx + 4], xmm6 + movss [ecx + edx + 8], xmm0 + movss [ecx + edx + 12], xmm3 shufps xmm5, xmm5, R_SHUFFLEPS( 1, 2, 3, 0 ) mov edx, usedVertNums[8] @@ -16316,10 +16473,10 @@ void VPCALL idSIMD_SSE::CreateSpecularTextureCoords( idVec4 *texCoords, const id shl edx, 4 shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [ecx+edx+0], xmm5 - movss [ecx+edx+4], xmm6 - movss [ecx+edx+8], xmm0 - movss [ecx+edx+12], xmm3 + movss [ecx + edx + 0], xmm5 + movss [ecx + edx + 4], xmm6 + movss [ecx + edx + 8], xmm0 + movss [ecx + edx + 12], xmm3 shufps xmm5, xmm5, R_SHUFFLEPS( 1, 2, 3, 0 ) mov edx, usedVertNums[12] @@ -16327,15 +16484,15 @@ void VPCALL idSIMD_SSE::CreateSpecularTextureCoords( idVec4 *texCoords, const id shl edx, 4 shufps xmm0, xmm0, R_SHUFFLEPS( 1, 2, 3, 0 ) - movss [ecx+edx+0], xmm5 - movss [ecx+edx+4], xmm6 - movss [ecx+edx+8], xmm0 - movss [ecx+edx+12], xmm3 + movss [ecx + edx + 0], xmm5 + movss [ecx + edx + 4], xmm6 + movss [ecx + edx + 8], xmm0 + movss [ecx + edx + 12], xmm3 xor ecx, ecx jmp loopVert4 - done4: + done4: test ecx, ecx jz done xor eax, eax @@ -16343,15 +16500,15 @@ void VPCALL idSIMD_SSE::CreateSpecularTextureCoords( idVec4 *texCoords, const id shl edi, 4 add edi, texCoords - loopVert1: - movss xmm6, lightDir0[eax*4] + loopVert1: + movss xmm6, lightDir0[eax * 4] movss xmm0, xmm6 mulss xmm6, xmm6 - movss xmm7, lightDir1[eax*4] + movss xmm7, lightDir1[eax * 4] movss xmm1, xmm7 mulss xmm7, xmm7 addss xmm6, xmm7 - movss xmm5, lightDir2[eax*4] + movss xmm5, lightDir2[eax * 4] movss xmm2, xmm5 mulss xmm5, xmm5 addss xmm6, xmm5 @@ -16361,14 +16518,14 @@ void VPCALL idSIMD_SSE::CreateSpecularTextureCoords( idVec4 *texCoords, const id mulss xmm1, xmm6 mulss xmm2, xmm6 - movss xmm3, viewDir0[eax*4] + movss xmm3, viewDir0[eax * 4] movss xmm7, xmm3 mulss xmm7, xmm7 - movss xmm4, viewDir1[eax*4] + movss xmm4, viewDir1[eax * 4] movss xmm6, xmm4 mulss xmm6, xmm6 addss xmm7, xmm6 - movss xmm5, viewDir2[eax*4] + movss xmm5, viewDir2[eax * 4] movss xmm6, xmm5 mulss xmm6, xmm6 addss xmm7, xmm6 @@ -16381,44 +16538,44 @@ void VPCALL idSIMD_SSE::CreateSpecularTextureCoords( idVec4 *texCoords, const id mulss xmm5, xmm7 addss xmm2, xmm5 - mov edx, usedVertNums[eax*4] + mov edx, usedVertNums[eax * 4] shl edx, 4 - movss xmm3, tangent0[eax*4] + movss xmm3, tangent0[eax * 4] mulss xmm3, xmm0 - movss xmm4, tangent1[eax*4] + movss xmm4, tangent1[eax * 4] mulss xmm4, xmm1 addss xmm3, xmm4 - movss xmm5, tangent2[eax*4] + movss xmm5, tangent2[eax * 4] mulss xmm5, xmm2 addss xmm5, xmm3 - movss [edi+edx+0], xmm5 + movss [edi + edx + 0], xmm5 - movss xmm3, tangent3[eax*4] + movss xmm3, tangent3[eax * 4] mulss xmm3, xmm0 - movss xmm4, tangent4[eax*4] + movss xmm4, tangent4[eax * 4] mulss xmm4, xmm1 addss xmm3, xmm4 - movss xmm6, tangent5[eax*4] + movss xmm6, tangent5[eax * 4] mulss xmm6, xmm2 addss xmm6, xmm3 - movss [edi+edx+4], xmm6 + movss [edi + edx + 4], xmm6 - mulss xmm0, normal0[eax*4] - mulss xmm1, normal1[eax*4] + mulss xmm0, normal0[eax * 4] + mulss xmm1, normal1[eax * 4] addss xmm0, xmm1 - mulss xmm2, normal2[eax*4] + mulss xmm2, normal2[eax * 4] addss xmm0, xmm2 - movss [edi+edx+8], xmm0 + movss [edi + edx + 8], xmm0 movss xmm3, SIMD_SP_one - movss [edi+edx+12], xmm3 + movss [edi + edx + 12], xmm3 inc eax dec ecx jg loopVert1 - done: + done: } #else @@ -16690,75 +16847,75 @@ int VPCALL idSIMD_SSE::CreateShadowCache( idVec4 *vertexCache, int *vertRemap, c add edx, eax neg eax - loop4: - prefetchnta [edx+128] - prefetchnta [esi+4*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET] + loop4: + prefetchnta [edx + 128] + prefetchnta [esi + 4 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET] - cmp dword ptr [edx+eax+0], ebx + cmp dword ptr [edx + eax + 0], ebx jne skip1 - mov dword ptr [edx+eax+0], ecx - movss xmm0, [esi+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] - movhps xmm0, [esi+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] + mov dword ptr [edx + eax + 0], ecx + movss xmm0, [esi + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] + movhps xmm0, [esi + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] add ecx, 2 shufps xmm0, xmm0, R_SHUFFLEPS( 2, 3, 0, 1 ); orps xmm0, xmm5 - movaps [edi+0*16], xmm0 + movaps [edi + 0 * 16], xmm0 subps xmm0, xmm6 - movaps [edi+1*16], xmm0 - add edi, 2*16 + movaps [edi + 1 * 16], xmm0 + add edi, 2 * 16 - skip1: - cmp dword ptr [edx+eax+4], ebx + skip1: + cmp dword ptr [edx + eax + 4], ebx jne skip2 - mov dword ptr [edx+eax+4], ecx - movss xmm1, [esi+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] - movhps xmm1, [esi+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] + mov dword ptr [edx + eax + 4], ecx + movss xmm1, [esi + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] + movhps xmm1, [esi + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4] add ecx, 2 shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 3, 1 ) orps xmm1, xmm5 - movaps [edi+0*16], xmm1 + movaps [edi + 0 * 16], xmm1 subps xmm1, xmm7 - movaps [edi+1*16], xmm1 - add edi, 2*16 + movaps [edi + 1 * 16], xmm1 + add edi, 2 * 16 - skip2: - cmp dword ptr [edx+eax+8], ebx + skip2: + cmp dword ptr [edx + eax + 8], ebx jne skip3 - mov dword ptr [edx+eax+8], ecx - movss xmm2, [esi+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] - movhps xmm2, [esi+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] + mov dword ptr [edx + eax + 8], ecx + movss xmm2, [esi + 2 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] + movhps xmm2, [esi + 2 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] add ecx, 2 shufps xmm2, xmm2, R_SHUFFLEPS( 2, 3, 0, 1 ); orps xmm2, xmm5 - movaps [edi+0*16], xmm2 + movaps [edi + 0 * 16], xmm2 subps xmm2, xmm6 - movaps [edi+1*16], xmm2 - add edi, 2*16 + movaps [edi + 1 * 16], xmm2 + add edi, 2 * 16 - skip3: - cmp dword ptr [edx+eax+12], ebx + skip3: + cmp dword ptr [edx + eax + 12], ebx jne skip4 - mov dword ptr [edx+eax+12], ecx - movss xmm3, [esi+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] - movhps xmm3, [esi+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] + mov dword ptr [edx + eax + 12], ecx + movss xmm3, [esi + 3 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] + movhps xmm3, [esi + 3 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4] add ecx, 2 shufps xmm3, xmm3, R_SHUFFLEPS( 0, 2, 3, 1 ) orps xmm3, xmm5 - movaps [edi+0*16], xmm3 + movaps [edi + 0 * 16], xmm3 subps xmm3, xmm7 - movaps [edi+1*16], xmm3 - add edi, 2*16 + movaps [edi + 1 * 16], xmm3 + add edi, 2 * 16 - skip4: - add esi, 4*DRAWVERT_SIZE - add eax, 4*4 + skip4: + add esi, 4 * DRAWVERT_SIZE + add eax, 4 * 4 jl loop4 - done4: + done4: mov eax, numVerts and eax, 3 jz done1 @@ -16766,28 +16923,28 @@ int VPCALL idSIMD_SSE::CreateShadowCache( idVec4 *vertexCache, int *vertRemap, c add edx, eax neg eax - loop1: - cmp dword ptr [edx+eax+0], ebx + loop1: + cmp dword ptr [edx + eax + 0], ebx jne skip0 - mov dword ptr [edx+eax+0], ecx - movss xmm0, [esi+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] - movhps xmm0, [esi+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] + mov dword ptr [edx + eax + 0], ecx + movss xmm0, [esi + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] + movhps xmm0, [esi + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] add ecx, 2 shufps xmm0, xmm0, R_SHUFFLEPS( 2, 3, 0, 1 ) orps xmm0, xmm5 - movaps [edi+0*16], xmm0 + movaps [edi + 0 * 16], xmm0 subps xmm0, xmm6 - movaps [edi+1*16], xmm0 - add edi, 2*16 + movaps [edi + 1 * 16], xmm0 + add edi, 2 * 16 - skip0: + skip0: add esi, DRAWVERT_SIZE add eax, 4 jl loop1 - done1: + done1: pop ebx mov outVerts, ecx } @@ -16801,18 +16958,18 @@ int VPCALL idSIMD_SSE::CreateShadowCache( idVec4 *vertexCache, int *vertRemap, c continue; } const float *v = verts[i].xyz.ToFloatPtr(); - vertexCache[outVerts+0][0] = v[0]; - vertexCache[outVerts+0][1] = v[1]; - vertexCache[outVerts+0][2] = v[2]; - vertexCache[outVerts+0][3] = 1.0f; + vertexCache[outVerts + 0][0] = v[0]; + vertexCache[outVerts + 0][1] = v[1]; + vertexCache[outVerts + 0][2] = v[2]; + vertexCache[outVerts + 0][3] = 1.0f; // R_SetupProjection() builds the projection matrix with a slight crunch // for depth, which keeps this w=0 division from rasterizing right at the // wrap around point and causing depth fighting with the rear caps - vertexCache[outVerts+1][0] = v[0] - lightOrigin[0]; - vertexCache[outVerts+1][1] = v[1] - lightOrigin[1]; - vertexCache[outVerts+1][2] = v[2] - lightOrigin[2]; - vertexCache[outVerts+1][3] = 0.0f; + vertexCache[outVerts + 1][0] = v[0] - lightOrigin[0]; + vertexCache[outVerts + 1][1] = v[1] - lightOrigin[1]; + vertexCache[outVerts + 1][2] = v[2] - lightOrigin[2]; + vertexCache[outVerts + 1][3] = 0.0f; vertRemap[i] = outVerts; outVerts += 2; } @@ -16844,42 +17001,42 @@ int VPCALL idSIMD_SSE::CreateVertexProgramShadowCache( idVec4 *vertexCache, cons add edi, eax neg eax - loop4: + loop4: prefetchnta [esi+4*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET] movss xmm0, [esi+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] movhps xmm0, [esi+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] shufps xmm0, xmm0, R_SHUFFLEPS( 2, 3, 0, 1 ); - movaps [edi+eax+1*16], xmm0 + movaps [edi + eax + 1 * 16], xmm0 orps xmm0, xmm4 - movaps [edi+eax+0*16], xmm0 + movaps [edi + eax + 0 * 16], xmm0 - movss xmm1, [esi+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] - movhps xmm1, [esi+1*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] + movss xmm1, [esi + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] + movhps xmm1, [esi + 1 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4] shufps xmm1, xmm1, R_SHUFFLEPS( 0, 2, 3, 1 ) - movaps [edi+eax+3*16], xmm1 + movaps [edi + eax + 3 * 16], xmm1 orps xmm1, xmm5 - movaps [edi+eax+2*16], xmm1 + movaps [edi + eax + 2 * 16], xmm1 - movss xmm2, [esi+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] - movhps xmm2, [esi+2*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] + movss xmm2, [esi + 2 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] + movhps xmm2, [esi + 2 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] shufps xmm2, xmm2, R_SHUFFLEPS( 2, 3, 0, 1 ); - movaps [edi+eax+5*16], xmm2 + movaps [edi + eax + 5 * 16], xmm2 orps xmm2, xmm6 - movaps [edi+eax+4*16], xmm2 + movaps [edi + eax + 4 * 16], xmm2 - movss xmm3, [esi+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] - movhps xmm3, [esi+3*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+4] + movss xmm3, [esi + 3 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] + movhps xmm3, [esi + 3 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 4] shufps xmm3, xmm3, R_SHUFFLEPS( 0, 2, 3, 1 ) - movaps [edi+eax+7*16], xmm3 + movaps [edi + eax + 7 * 16], xmm3 orps xmm3, xmm7 - movaps [edi+eax+6*16], xmm3 + movaps [edi + eax + 6 * 16], xmm3 - add esi, 4*DRAWVERT_SIZE - add eax, 4*8*4 + add esi, 4 * DRAWVERT_SIZE + add eax, 4 * 8 * 4 jl loop4 - done4: + done4: mov eax, numVerts and eax, 3 jz done1 @@ -16887,19 +17044,19 @@ int VPCALL idSIMD_SSE::CreateVertexProgramShadowCache( idVec4 *vertexCache, cons add edi, eax neg eax - loop1: - movss xmm0, [esi+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+8] - movhps xmm0, [esi+0*DRAWVERT_SIZE+DRAWVERT_XYZ_OFFSET+0] + loop1: + movss xmm0, [esi + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 8] + movhps xmm0, [esi + 0 * DRAWVERT_SIZE + DRAWVERT_XYZ_OFFSET + 0] shufps xmm0, xmm0, R_SHUFFLEPS( 2, 3, 0, 1 ); - movaps [edi+eax+1*16], xmm0 + movaps [edi + eax + 1 * 16], xmm0 orps xmm0, xmm4 - movaps [edi+eax+0*16], xmm0 + movaps [edi + eax + 0 * 16], xmm0 add esi, DRAWVERT_SIZE - add eax, 8*4 + add eax, 8 * 4 jl loop1 - done1: + done1: } return numVerts * 2; @@ -16907,15 +17064,15 @@ int VPCALL idSIMD_SSE::CreateVertexProgramShadowCache( idVec4 *vertexCache, cons for ( int i = 0; i < numVerts; i++ ) { const float *v = verts[i].xyz.ToFloatPtr(); - vertexCache[i*2+0][0] = v[0]; - vertexCache[i*2+0][1] = v[1]; - vertexCache[i*2+0][2] = v[2]; - vertexCache[i*2+0][3] = 1.0f; - - vertexCache[i*2+1][0] = v[0]; - vertexCache[i*2+1][1] = v[1]; - vertexCache[i*2+1][2] = v[2]; - vertexCache[i*2+1][3] = 0.0f; + vertexCache[i * 2 + 0][0] = v[0]; + vertexCache[i * 2 + 0][1] = v[1]; + vertexCache[i * 2 + 0][2] = v[2]; + vertexCache[i * 2 + 0][3] = 1.0f; + + vertexCache[i * 2 + 1][0] = v[0]; + vertexCache[i * 2 + 1][1] = v[1]; + vertexCache[i * 2 + 1][2] = v[2]; + vertexCache[i * 2 + 1][3] = 0.0f; } return numVerts * 2; @@ -16940,25 +17097,25 @@ static void SSE_UpSample11kHzMonoPCMTo44kHz( float *dest, const short *src, cons neg eax align 16 - loop2: + loop2: add edi, 2*4*4 movsx ecx, word ptr [esi+eax+0] cvtsi2ss xmm0, ecx shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps [edi-2*4*4+0], xmm0 - movhps [edi-2*4*4+8], xmm0 + movlps [edi - 2 * 4 * 4 + 0], xmm0 + movhps [edi - 2 * 4 * 4 + 8], xmm0 - movsx edx, word ptr [esi+eax+2] + movsx edx, word ptr [esi + eax + 2] cvtsi2ss xmm1, edx shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps [edi-1*4*4+0], xmm1 - movhps [edi-1*4*4+8], xmm1 + movlps [edi - 1 * 4 * 4 + 0], xmm1 + movhps [edi - 1 * 4 * 4 + 8], xmm1 - add eax, 2*2 + add eax, 2 * 2 jl loop2 - done2: + done2: mov eax, numSamples and eax, 1 jz done @@ -16966,10 +17123,10 @@ static void SSE_UpSample11kHzMonoPCMTo44kHz( float *dest, const short *src, cons movsx ecx, word ptr [esi] cvtsi2ss xmm0, ecx shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps [edi+0], xmm0 - movhps [edi+8], xmm0 + movlps [edi + 0], xmm0 + movhps [edi + 8], xmm0 - done: + done: } } @@ -16991,7 +17148,7 @@ static void SSE_UpSample11kHzStereoPCMTo44kHz( float *dest, const short *src, co neg eax align 16 - loop2: + loop2: add edi, 8*4 movsx ecx, word ptr [esi+eax+0] @@ -17010,7 +17167,7 @@ static void SSE_UpSample11kHzStereoPCMTo44kHz( float *dest, const short *src, co add eax, 2*2 jl loop2 - done2: + done2: } } @@ -17032,7 +17189,7 @@ static void SSE_UpSample22kHzMonoPCMTo44kHz( float *dest, const short *src, cons neg eax align 16 - loop2: + loop2: add edi, 4*4 movsx ecx, word ptr [esi+eax+0] @@ -17042,13 +17199,13 @@ static void SSE_UpSample22kHzMonoPCMTo44kHz( float *dest, const short *src, cons cvtsi2ss xmm1, edx shufps xmm0, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps [edi-4*4+0], xmm0 - movhps [edi-4*4+8], xmm0 + movlps [edi - 4 * 4 + 0], xmm0 + movhps [edi - 4 * 4 + 8], xmm0 - add eax, 2*2 + add eax, 2 * 2 jl loop2 - done2: + done2: mov eax, numSamples and eax, 1 jz done @@ -17058,7 +17215,7 @@ static void SSE_UpSample22kHzMonoPCMTo44kHz( float *dest, const short *src, cons shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) movlps [edi], xmm0 - done: + done: } } @@ -17080,7 +17237,7 @@ static void SSE_UpSample22kHzStereoPCMTo44kHz( float *dest, const short *src, co neg eax align 16 - loop2: + loop2: add edi, 4*4 movsx ecx, word ptr [esi+eax+0] @@ -17096,7 +17253,7 @@ static void SSE_UpSample22kHzStereoPCMTo44kHz( float *dest, const short *src, co add eax, 2*2 jl loop2 - done2: + done2: } } @@ -17118,7 +17275,7 @@ static void SSE_UpSample44kHzMonoPCMTo44kHz( float *dest, const short *src, cons neg eax align 16 - loop2: + loop2: add edi, 2*4 movsx ecx, word ptr [esi+eax+0] @@ -17132,7 +17289,7 @@ static void SSE_UpSample44kHzMonoPCMTo44kHz( float *dest, const short *src, cons add eax, 2*2 jl loop2 - done2: + done2: mov eax, numSamples and eax, 1 jz done @@ -17141,7 +17298,7 @@ static void SSE_UpSample44kHzMonoPCMTo44kHz( float *dest, const short *src, cons cvtsi2ss xmm0, ecx movss [edi], xmm0 - done: + done: } } @@ -17197,25 +17354,25 @@ static void SSE_UpSample11kHzMonoOGGTo44kHz( float *dest, const float *src, cons neg eax align 16 - loop2: - add edi, 2*16 + loop2: + add edi, 2 * 16 - movss xmm0, [esi+eax+0] + movss xmm0, [esi + eax + 0] mulss xmm0, xmm7 shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps [edi-32], xmm0 - movlps [edi-24], xmm0 + movlps [edi - 32], xmm0 + movlps [edi - 24], xmm0 - movss xmm1, [esi+eax+4] + movss xmm1, [esi + eax + 4] mulss xmm1, xmm7 shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps [edi-16], xmm1 - movlps [edi- 8], xmm1 + movlps [edi - 16], xmm1 + movlps [edi - 8], xmm1 - add eax, 2*4 + add eax, 2 * 4 jl loop2 - done2: + done2: mov eax, numSamples and eax, 1 jz done @@ -17223,10 +17380,10 @@ static void SSE_UpSample11kHzMonoOGGTo44kHz( float *dest, const float *src, cons movss xmm0, [esi] mulss xmm0, xmm7 shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps [edi+0], xmm0 - movlps [edi+8], xmm0 + movlps [edi + 0], xmm0 + movlps [edi + 8], xmm0 - done: + done: } } @@ -17235,7 +17392,7 @@ static void SSE_UpSample11kHzMonoOGGTo44kHz( float *dest, const float *src, cons SSE_UpSample11kHzStereoOGGTo44kHz ============ */ -static void SSE_UpSample11kHzStereoOGGTo44kHz( float *dest, const float * const *src, const int numSamples ) { +static void SSE_UpSample11kHzStereoOGGTo44kHz( float *dest, const float *const *src, const int numSamples ) { float constant = 32768.0f; __asm { mov esi, src @@ -17254,26 +17411,26 @@ static void SSE_UpSample11kHzStereoOGGTo44kHz( float *dest, const float * const neg eax align 16 - loop2: - add edi, 4*16 + loop2: + add edi, 4 * 16 - movlps xmm0, [ecx+eax] - movlps xmm1, [edx+eax] + movlps xmm0, [ecx + eax] + movlps xmm1, [edx + eax] unpcklps xmm0, xmm1 mulps xmm0, xmm7 - movlps [edi-8*8], xmm0 - movlps [edi-7*8], xmm0 - movlps [edi-6*8], xmm0 - movlps [edi-5*8], xmm0 - movhps [edi-4*8], xmm0 - movhps [edi-3*8], xmm0 - movhps [edi-2*8], xmm0 - movhps [edi-1*8], xmm0 - - add eax, 2*4 + movlps [edi - 8 * 8], xmm0 + movlps [edi - 7 * 8], xmm0 + movlps [edi - 6 * 8], xmm0 + movlps [edi - 5 * 8], xmm0 + movhps [edi - 4 * 8], xmm0 + movhps [edi - 3 * 8], xmm0 + movhps [edi - 2 * 8], xmm0 + movhps [edi - 1 * 8], xmm0 + + add eax, 2 * 4 jl loop2 - done2: + done2: mov eax, numSamples and eax, 1 jz done @@ -17282,12 +17439,12 @@ static void SSE_UpSample11kHzStereoOGGTo44kHz( float *dest, const float * const movss xmm1, [edx] unpcklps xmm0, xmm1 mulps xmm0, xmm7 - movlps [edi+0*8], xmm0 - movlps [edi+1*8], xmm0 - movlps [edi+2*8], xmm0 - movlps [edi+3*8], xmm0 + movlps [edi + 0 * 8], xmm0 + movlps [edi + 1 * 8], xmm0 + movlps [edi + 2 * 8], xmm0 + movlps [edi + 3 * 8], xmm0 - done: + done: } } @@ -17312,20 +17469,20 @@ static void SSE_UpSample22kHzMonoOGGTo44kHz( float *dest, const float *src, cons neg eax align 16 - loop2: - add edi, 2*8 + loop2: + add edi, 2 * 8 - movss xmm0, [esi+eax+0] - movss xmm1, [esi+eax+4] + movss xmm0, [esi + eax + 0] + movss xmm1, [esi + eax + 4] shufps xmm0, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm0, xmm7 - movlps [edi-16], xmm0 - movhps [edi- 8], xmm0 + movlps [edi - 16], xmm0 + movhps [edi - 8], xmm0 - add eax, 2*4 + add eax, 2 * 4 jl loop2 - done2: + done2: mov eax, numSamples and eax, 1 jz done @@ -17333,9 +17490,9 @@ static void SSE_UpSample22kHzMonoOGGTo44kHz( float *dest, const float *src, cons movss xmm0, [esi] mulss xmm0, xmm7 shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 0, 0 ) - movlps [edi+0], xmm0 + movlps [edi + 0], xmm0 - done: + done: } } @@ -17344,7 +17501,7 @@ static void SSE_UpSample22kHzMonoOGGTo44kHz( float *dest, const float *src, cons SSE_UpSample22kHzStereoOGGTo44kHz ============ */ -static void SSE_UpSample22kHzStereoOGGTo44kHz( float *dest, const float * const *src, const int numSamples ) { +static void SSE_UpSample22kHzStereoOGGTo44kHz( float *dest, const float *const *src, const int numSamples ) { float constant = 32768.0f; __asm { mov esi, src @@ -17363,22 +17520,22 @@ static void SSE_UpSample22kHzStereoOGGTo44kHz( float *dest, const float * const neg eax align 16 - loop2: - add edi, 2*16 + loop2: + add edi, 2 * 16 - movlps xmm0, [ecx+eax] - movlps xmm1, [edx+eax] + movlps xmm0, [ecx + eax] + movlps xmm1, [edx + eax] unpcklps xmm0, xmm1 mulps xmm0, xmm7 - movlps [edi-4*8], xmm0 - movlps [edi-3*8], xmm0 - movhps [edi-2*8], xmm0 - movhps [edi-1*8], xmm0 + movlps [edi - 4 * 8], xmm0 + movlps [edi - 3 * 8], xmm0 + movhps [edi - 2 * 8], xmm0 + movhps [edi - 1 * 8], xmm0 - add eax, 2*4 + add eax, 2 * 4 jl loop2 - done2: + done2: mov eax, numSamples and eax, 1 jz done @@ -17387,10 +17544,10 @@ static void SSE_UpSample22kHzStereoOGGTo44kHz( float *dest, const float * const movss xmm1, [edx] unpcklps xmm0, xmm1 mulps xmm0, xmm7 - movlps [edi+0*8], xmm0 - movlps [edi+1*8], xmm0 + movlps [edi + 0 * 8], xmm0 + movlps [edi + 1 * 8], xmm0 - done: + done: } } @@ -17409,7 +17566,7 @@ static void SSE_UpSample44kHzMonoOGGTo44kHz( float *dest, const float *src, cons SSE_UpSample44kHzStereoOGGTo44kHz ============ */ -static void SSE_UpSample44kHzStereoOGGTo44kHz( float *dest, const float * const *src, const int numSamples ) { +static void SSE_UpSample44kHzStereoOGGTo44kHz( float *dest, const float *const *src, const int numSamples ) { float constant = 32768.0f; __asm { mov esi, src @@ -17428,20 +17585,20 @@ static void SSE_UpSample44kHzStereoOGGTo44kHz( float *dest, const float * const neg eax align 16 - loop2: + loop2: add edi, 16 - movlps xmm0, [ecx+eax] - movlps xmm1, [edx+eax] + movlps xmm0, [ecx + eax] + movlps xmm1, [edx + eax] unpcklps xmm0, xmm1 mulps xmm0, xmm7 - movlps [edi-2*8], xmm0 - movhps [edi-1*8], xmm0 + movlps [edi - 2 * 8], xmm0 + movhps [edi - 1 * 8], xmm0 - add eax, 2*4 + add eax, 2 * 4 jl loop2 - done2: + done2: mov eax, numSamples and eax, 1 jz done @@ -17450,9 +17607,9 @@ static void SSE_UpSample44kHzStereoOGGTo44kHz( float *dest, const float * const movss xmm1, [edx] unpcklps xmm0, xmm1 mulps xmm0, xmm7 - movlps [edi+0*8], xmm0 + movlps [edi + 0 * 8], xmm0 - done: + done: } } @@ -17463,7 +17620,7 @@ idSIMD_SSE::UpSampleOGGTo44kHz Duplicate samples for 44kHz output. ============ */ -void idSIMD_SSE::UpSampleOGGTo44kHz( float *dest, const float * const *ogg, const int numSamples, const int kHz, const int numChannels ) { +void idSIMD_SSE::UpSampleOGGTo44kHz( float *dest, const float *const *ogg, const int numSamples, const int kHz, const int numChannels ) { if ( kHz == 11025 ) { if ( numChannels == 1 ) { SSE_UpSample11kHzMonoOGGTo44kHz( dest, ogg[0], numSamples ); @@ -17520,38 +17677,38 @@ void VPCALL idSIMD_SSE::MixSoundTwoSpeakerMono( float *mixBuffer, const float *s shufps xmm7, xmm7, R_SHUFFLEPS( 2, 3, 2, 3 ) addps xmm7, xmm7 - loop16: - add edi, 4*4*4 + loop16: + add edi, 4 * 4 * 4 - movaps xmm0, [esi+eax+0*4*4] + movaps xmm0, [esi + eax + 0 * 4 * 4] movaps xmm1, xmm0 shufps xmm0, xmm0, R_SHUFFLEPS( 0, 0, 1, 1 ) mulps xmm0, xmm6 - addps xmm0, [edi-4*4*4] + addps xmm0, [edi - 4 * 4 * 4] addps xmm6, xmm7 - movaps [edi-4*4*4], xmm0 + movaps [edi - 4 * 4 * 4], xmm0 shufps xmm1, xmm1, R_SHUFFLEPS( 2, 2, 3, 3 ) mulps xmm1, xmm6 - addps xmm1, [edi-3*4*4] + addps xmm1, [edi - 3 * 4 * 4] addps xmm6, xmm7 - movaps [edi-3*4*4], xmm1 + movaps [edi - 3 * 4 * 4], xmm1 - movaps xmm2, [esi+eax+1*4*4] + movaps xmm2, [esi + eax + 1 * 4 * 4] movaps xmm3, xmm2 shufps xmm2, xmm2, R_SHUFFLEPS( 0, 0, 1, 1 ) mulps xmm2, xmm6 - addps xmm2, [edi-2*4*4] + addps xmm2, [edi - 2 * 4 * 4] addps xmm6, xmm7 - movaps [edi-2*4*4], xmm2 + movaps [edi - 2 * 4 * 4], xmm2 shufps xmm3, xmm3, R_SHUFFLEPS( 2, 2, 3, 3 ) mulps xmm3, xmm6 - addps xmm3, [edi-1*4*4] + addps xmm3, [edi - 1 * 4 * 4] addps xmm6, xmm7 - movaps [edi-1*4*4], xmm3 + movaps [edi - 1 * 4 * 4], xmm3 - add eax, 2*4*4 + add eax, 2 * 4 * 4 jl loop16 } @@ -17577,11 +17734,11 @@ void VPCALL idSIMD_SSE::MixSoundTwoSpeakerMono( float *mixBuffer, const float *s incL *= 2; incR *= 2; - for( i = 0; i < MIXBUFFER_SAMPLES; i += 2 ) { - mixBuffer[i*2+0] += samples[i+0] * sL0; - mixBuffer[i*2+1] += samples[i+0] * sR0; - mixBuffer[i*2+2] += samples[i+1] * sL1; - mixBuffer[i*2+3] += samples[i+1] * sR1; + for ( i = 0; i < MIXBUFFER_SAMPLES; i += 2 ) { + mixBuffer[i * 2 + 0] += samples[i + 0] * sL0; + mixBuffer[i * 2 + 1] += samples[i + 0] * sR0; + mixBuffer[i * 2 + 2] += samples[i + 1] * sL1; + mixBuffer[i * 2 + 3] += samples[i + 1] * sR1; sL0 += incL; sR0 += incR; sL1 += incL; @@ -17623,34 +17780,34 @@ void VPCALL idSIMD_SSE::MixSoundTwoSpeakerStereo( float *mixBuffer, const float shufps xmm7, xmm7, R_SHUFFLEPS( 2, 3, 2, 3 ) addps xmm7, xmm7 - loop16: - add edi, 4*4*4 + loop16: + add edi, 4 * 4 * 4 - movaps xmm0, [esi+eax+0*4*4] + movaps xmm0, [esi + eax + 0 * 4 * 4] mulps xmm0, xmm6 - addps xmm0, [edi-4*4*4] + addps xmm0, [edi - 4 * 4 * 4] addps xmm6, xmm7 - movaps [edi-4*4*4], xmm0 + movaps [edi - 4 * 4 * 4], xmm0 - movaps xmm2, [esi+eax+1*4*4] + movaps xmm2, [esi + eax + 1 * 4 * 4] mulps xmm2, xmm6 - addps xmm2, [edi-3*4*4] + addps xmm2, [edi - 3 * 4 * 4] addps xmm6, xmm7 - movaps [edi-3*4*4], xmm2 + movaps [edi - 3 * 4 * 4], xmm2 - movaps xmm3, [esi+eax+2*4*4] + movaps xmm3, [esi + eax + 2 * 4 * 4] mulps xmm3, xmm6 - addps xmm3, [edi-2*4*4] + addps xmm3, [edi - 2 * 4 * 4] addps xmm6, xmm7 - movaps [edi-2*4*4], xmm3 + movaps [edi - 2 * 4 * 4], xmm3 - movaps xmm4, [esi+eax+3*4*4] + movaps xmm4, [esi + eax + 3 * 4 * 4] mulps xmm4, xmm6 - addps xmm4, [edi-1*4*4] + addps xmm4, [edi - 1 * 4 * 4] addps xmm6, xmm7 - movaps [edi-1*4*4], xmm4 + movaps [edi - 1 * 4 * 4], xmm4 - add eax, 4*4*4 + add eax, 4 * 4 * 4 jl loop16 } @@ -17676,11 +17833,11 @@ void VPCALL idSIMD_SSE::MixSoundTwoSpeakerStereo( float *mixBuffer, const float incL *= 2; incR *= 2; - for( i = 0; i < MIXBUFFER_SAMPLES; i += 2 ) { - mixBuffer[i*2+0] += samples[i*2+0] * sL0; - mixBuffer[i*2+1] += samples[i*2+1] * sR0; - mixBuffer[i*2+2] += samples[i*2+2] * sL1; - mixBuffer[i*2+3] += samples[i*2+3] * sR1; + for ( i = 0; i < MIXBUFFER_SAMPLES; i += 2 ) { + mixBuffer[i * 2 + 0] += samples[i * 2 + 0] * sL0; + mixBuffer[i * 2 + 1] += samples[i * 2 + 1] * sR0; + mixBuffer[i * 2 + 2] += samples[i * 2 + 2] * sL1; + mixBuffer[i * 2 + 3] += samples[i * 2 + 3] * sR1; sL0 += incL; sR0 += incR; sL1 += incL; @@ -17727,8 +17884,8 @@ void VPCALL idSIMD_SSE::MixSoundSixSpeakerMono( float *mixBuffer, const float *s xorps xmm5, xmm5 movhps xmm5, incs - movlps xmm7, incs+8 - movhps xmm7, incs+16 + movlps xmm7, incs + 8 + movhps xmm7, incs + 16 addps xmm3, xmm5 addps xmm4, xmm7 shufps xmm5, xmm7, R_SHUFFLEPS( 2, 3, 0, 1 ) @@ -17738,53 +17895,53 @@ void VPCALL idSIMD_SSE::MixSoundSixSpeakerMono( float *mixBuffer, const float *s addps xmm6, xmm6 addps xmm7, xmm7 - loop24: - add edi, 6*16 + loop24: + add edi, 6 * 16 - movaps xmm0, [esi+eax] + movaps xmm0, [esi + eax] movaps xmm1, xmm0 shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 0, 0 ) mulps xmm1, xmm2 - addps xmm1, [edi-6*16] + addps xmm1, [edi - 6 * 16] addps xmm2, xmm5 - movaps [edi-6*16], xmm1 + movaps [edi - 6 * 16], xmm1 movaps xmm1, xmm0 shufps xmm1, xmm1, R_SHUFFLEPS( 0, 0, 1, 1 ) mulps xmm1, xmm3 - addps xmm1, [edi-5*16] + addps xmm1, [edi - 5 * 16] addps xmm3, xmm6 - movaps [edi-5*16], xmm1 + movaps [edi - 5 * 16], xmm1 movaps xmm1, xmm0 shufps xmm1, xmm1, R_SHUFFLEPS( 1, 1, 1, 1 ) mulps xmm1, xmm4 - addps xmm1, [edi-4*16] + addps xmm1, [edi - 4 * 16] addps xmm4, xmm7 - movaps [edi-4*16], xmm1 + movaps [edi - 4 * 16], xmm1 movaps xmm1, xmm0 shufps xmm1, xmm1, R_SHUFFLEPS( 2, 2, 2, 2 ) mulps xmm1, xmm2 - addps xmm1, [edi-3*16] + addps xmm1, [edi - 3 * 16] addps xmm2, xmm5 - movaps [edi-3*16], xmm1 + movaps [edi - 3 * 16], xmm1 movaps xmm1, xmm0 shufps xmm1, xmm1, R_SHUFFLEPS( 2, 2, 3, 3 ) mulps xmm1, xmm3 - addps xmm1, [edi-2*16] + addps xmm1, [edi - 2 * 16] addps xmm3, xmm6 - movaps [edi-2*16], xmm1 + movaps [edi - 2 * 16], xmm1 shufps xmm0, xmm0, R_SHUFFLEPS( 3, 3, 3, 3 ) mulps xmm0, xmm4 - addps xmm0, [edi-1*16] + addps xmm0, [edi - 1 * 16] addps xmm4, xmm7 - movaps [edi-1*16], xmm0 + movaps [edi - 1 * 16], xmm0 - add eax, 4*4 + add eax, 4 * 4 jl loop24 } @@ -17825,21 +17982,21 @@ void VPCALL idSIMD_SSE::MixSoundSixSpeakerMono( float *mixBuffer, const float *s incL4 *= 2; incL5 *= 2; - for( i = 0; i <= MIXBUFFER_SAMPLES - 2; i += 2 ) { - mixBuffer[i*6+ 0] += samples[i+0] * sL0; - mixBuffer[i*6+ 1] += samples[i+0] * sL1; - mixBuffer[i*6+ 2] += samples[i+0] * sL2; - mixBuffer[i*6+ 3] += samples[i+0] * sL3; + for ( i = 0; i <= MIXBUFFER_SAMPLES - 2; i += 2 ) { + mixBuffer[i * 6 + 0] += samples[i + 0] * sL0; + mixBuffer[i * 6 + 1] += samples[i + 0] * sL1; + mixBuffer[i * 6 + 2] += samples[i + 0] * sL2; + mixBuffer[i * 6 + 3] += samples[i + 0] * sL3; - mixBuffer[i*6+ 4] += samples[i+0] * sL4; - mixBuffer[i*6+ 5] += samples[i+0] * sL5; - mixBuffer[i*6+ 6] += samples[i+1] * sL6; - mixBuffer[i*6+ 7] += samples[i+1] * sL7; + mixBuffer[i * 6 + 4] += samples[i + 0] * sL4; + mixBuffer[i * 6 + 5] += samples[i + 0] * sL5; + mixBuffer[i * 6 + 6] += samples[i + 1] * sL6; + mixBuffer[i * 6 + 7] += samples[i + 1] * sL7; - mixBuffer[i*6+ 8] += samples[i+1] * sL8; - mixBuffer[i*6+ 9] += samples[i+1] * sL9; - mixBuffer[i*6+10] += samples[i+1] * sL10; - mixBuffer[i*6+11] += samples[i+1] * sL11; + mixBuffer[i * 6 + 8] += samples[i + 1] * sL8; + mixBuffer[i * 6 + 9] += samples[i + 1] * sL9; + mixBuffer[i * 6 + 10] += samples[i + 1] * sL10; + mixBuffer[i * 6 + 11] += samples[i + 1] * sL11; sL0 += incL0; sL1 += incL1; @@ -17899,8 +18056,8 @@ void VPCALL idSIMD_SSE::MixSoundSixSpeakerStereo( float *mixBuffer, const float xorps xmm5, xmm5 movhps xmm5, incs - movlps xmm7, incs+ 8 - movhps xmm7, incs+16 + movlps xmm7, incs + 8 + movhps xmm7, incs + 16 addps xmm3, xmm5 addps xmm4, xmm7 shufps xmm5, xmm7, R_SHUFFLEPS( 2, 3, 0, 1 ) @@ -17910,32 +18067,32 @@ void VPCALL idSIMD_SSE::MixSoundSixSpeakerStereo( float *mixBuffer, const float addps xmm6, xmm6 addps xmm7, xmm7 - loop12: - add edi, 3*16 + loop12: + add edi, 3 * 16 - movaps xmm0, [esi+eax+0] + movaps xmm0, [esi + eax + 0] movaps xmm1, xmm0 shufps xmm1, xmm1, R_SHUFFLEPS( 0, 1, 0, 0 ) mulps xmm1, xmm2 - addps xmm1, [edi-3*16] + addps xmm1, [edi - 3 * 16] addps xmm2, xmm5 - movaps [edi-3*16], xmm1 + movaps [edi - 3 * 16], xmm1 movaps xmm1, xmm0 shufps xmm1, xmm1, R_SHUFFLEPS( 0, 1, 2, 3 ) mulps xmm1, xmm3 - addps xmm1, [edi-2*16] + addps xmm1, [edi - 2 * 16] addps xmm3, xmm6 - movaps [edi-2*16], xmm1 + movaps [edi - 2 * 16], xmm1 - add eax, 4*4 + add eax, 4 * 4 shufps xmm0, xmm0, R_SHUFFLEPS( 2, 2, 2, 3 ) mulps xmm0, xmm4 - addps xmm0, [edi-1*16] + addps xmm0, [edi - 1 * 16] addps xmm4, xmm7 - movaps [edi-1*16], xmm0 + movaps [edi - 1 * 16], xmm0 jl loop12 @@ -17980,21 +18137,21 @@ void VPCALL idSIMD_SSE::MixSoundSixSpeakerStereo( float *mixBuffer, const float incL4 *= 2; incL5 *= 2; - for( i = 0; i <= MIXBUFFER_SAMPLES - 2; i += 2 ) { - mixBuffer[i*6+ 0] += samples[i*2+0+0] * sL0; - mixBuffer[i*6+ 1] += samples[i*2+0+1] * sL1; - mixBuffer[i*6+ 2] += samples[i*2+0+0] * sL2; - mixBuffer[i*6+ 3] += samples[i*2+0+0] * sL3; + for ( i = 0; i <= MIXBUFFER_SAMPLES - 2; i += 2 ) { + mixBuffer[i * 6 + 0] += samples[i * 2 + 0 + 0] * sL0; + mixBuffer[i * 6 + 1] += samples[i * 2 + 0 + 1] * sL1; + mixBuffer[i * 6 + 2] += samples[i * 2 + 0 + 0] * sL2; + mixBuffer[i * 6 + 3] += samples[i * 2 + 0 + 0] * sL3; - mixBuffer[i*6+ 4] += samples[i*2+0+0] * sL4; - mixBuffer[i*6+ 5] += samples[i*2+0+1] * sL5; - mixBuffer[i*6+ 6] += samples[i*2+2+0] * sL6; - mixBuffer[i*6+ 7] += samples[i*2+2+1] * sL7; + mixBuffer[i * 6 + 4] += samples[i * 2 + 0 + 0] * sL4; + mixBuffer[i * 6 + 5] += samples[i * 2 + 0 + 1] * sL5; + mixBuffer[i * 6 + 6] += samples[i * 2 + 2 + 0] * sL6; + mixBuffer[i * 6 + 7] += samples[i * 2 + 2 + 1] * sL7; - mixBuffer[i*6+ 8] += samples[i*2+2+0] * sL8; - mixBuffer[i*6+ 9] += samples[i*2+2+0] * sL9; - mixBuffer[i*6+10] += samples[i*2+2+0] * sL10; - mixBuffer[i*6+11] += samples[i*2+2+1] * sL11; + mixBuffer[i * 6 + 8] += samples[i * 2 + 2 + 0] * sL8; + mixBuffer[i * 6 + 9] += samples[i * 2 + 2 + 0] * sL9; + mixBuffer[i * 6 + 10] += samples[i * 2 + 2 + 0] * sL10; + mixBuffer[i * 6 + 11] += samples[i * 2 + 2 + 1] * sL11; sL0 += incL0; sL1 += incL1; @@ -18034,7 +18191,7 @@ void VPCALL idSIMD_SSE::MixedSoundToSamples( short *samples, const float *mixBuf add edi, eax neg eax - loop16: + loop16: movaps xmm0, [edi+eax+0*16] movaps xmm2, [edi+eax+1*16] @@ -18087,11 +18244,229 @@ void VPCALL idSIMD_SSE::MixedSoundToSamples( short *samples, const float *mixBuf } else if ( mixBuffer[i] >= 32767.0f ) { samples[i] = 32767; } else { - samples[i] = (short) mixBuffer[i]; + samples[i] = ( short ) mixBuffer[i]; } } #endif } -#endif /* _MSC_VER */ +/* +============ +idSIMD_SSE::CullByFrustum +============ +*/ +void VPCALL idSIMD_SSE::CullByFrustum( idDrawVert *verts, const int numVerts, const idPlane frustum[6], byte *pointCull, float epsilon ) { + __m128 fA14 = _mm_set_ps( frustum[3][0], frustum[2][0], frustum[1][0], frustum[0][0] ); + __m128 fA56 = _mm_set_ps( 0, 0, frustum[5][0], frustum[4][0] ); + __m128 fB14 = _mm_set_ps( frustum[3][1], frustum[2][1], frustum[1][1], frustum[0][1] ); + __m128 fB56 = _mm_set_ps( 0, 0, frustum[5][1], frustum[4][1] ); + __m128 fC14 = _mm_set_ps( frustum[3][2], frustum[2][2], frustum[1][2], frustum[0][2] ); + __m128 fC56 = _mm_set_ps( 0, 0, frustum[5][2], frustum[4][2] ); + __m128 fD14 = _mm_set_ps( frustum[3][3], frustum[2][3], frustum[1][3], frustum[0][3] ); + __m128 fD56 = _mm_set_ps( 0, 0, frustum[5][3], frustum[4][3] ); + + for ( int j = 0; j < numVerts; j++ ) { + idVec3 &vec = verts[j].xyz; + __m128 vX = _mm_set1_ps( vec.x ); + __m128 vY = _mm_set1_ps( vec.y ); + __m128 vZ = _mm_set1_ps( vec.z ); + __m128 d14 = _mm_add_ps( + _mm_add_ps( + _mm_mul_ps( fA14, vX ), + _mm_mul_ps( fB14, vY ) + ), + _mm_add_ps( + _mm_mul_ps( fC14, vZ ), + fD14 + ) + ); + __m128 d56 = _mm_add_ps( + _mm_add_ps( + _mm_mul_ps( fA56, vX ), + _mm_mul_ps( fB56, vY ) + ), + _mm_add_ps( + _mm_mul_ps( fC56, vZ ), + fD56 + ) + ); + const short mask6 = ( 1 << 6 ) - 1; + __m128 eps = _mm_set1_ps( epsilon ); + int mask_lo14 = _mm_movemask_ps( _mm_cmplt_ps( d14, eps ) ); + int mask_lo56 = _mm_movemask_ps( _mm_cmplt_ps( d56, eps ) ); + int mask_lo = mask_lo14 | mask_lo56 << 4; + pointCull[j] = ( mask_lo & mask6 ); // gcc compiler warning + } +} + +/* +============ +idSIMD_SSE::CullByFrustum2 +============ +*/ +void VPCALL idSIMD_SSE::CullByFrustum2( idDrawVert *verts, const int numVerts, const idPlane frustum[6], unsigned short *pointCull, float epsilon ) { + __m128 fA14 = _mm_set_ps( frustum[3][0], frustum[2][0], frustum[1][0], frustum[0][0] ); + __m128 fA56 = _mm_set_ps( 0, 0, frustum[5][0], frustum[4][0] ); + __m128 fB14 = _mm_set_ps( frustum[3][1], frustum[2][1], frustum[1][1], frustum[0][1] ); + __m128 fB56 = _mm_set_ps( 0, 0, frustum[5][1], frustum[4][1] ); + __m128 fC14 = _mm_set_ps( frustum[3][2], frustum[2][2], frustum[1][2], frustum[0][2] ); + __m128 fC56 = _mm_set_ps( 0, 0, frustum[5][2], frustum[4][2] ); + __m128 fD14 = _mm_set_ps( frustum[3][3], frustum[2][3], frustum[1][3], frustum[0][3] ); + __m128 fD56 = _mm_set_ps( 0, 0, frustum[5][3], frustum[4][3] ); + + for ( int j = 0; j < numVerts; j++ ) { + idVec3 &vec = verts[j].xyz; + __m128 vX = _mm_set1_ps( vec.x ); + __m128 vY = _mm_set1_ps( vec.y ); + __m128 vZ = _mm_set1_ps( vec.z ); + __m128 d14 = _mm_add_ps( + _mm_add_ps( + _mm_mul_ps( fA14, vX ), + _mm_mul_ps( fB14, vY ) + ), + _mm_add_ps( + _mm_mul_ps( fC14, vZ ), + fD14 + ) + ); + __m128 d56 = _mm_add_ps( + _mm_add_ps( + _mm_mul_ps( fA56, vX ), + _mm_mul_ps( fB56, vY ) + ), + _mm_add_ps( + _mm_mul_ps( fC56, vZ ), + fD56 + ) + ); + const short mask6 = ( 1 << 6 ) - 1; + __m128 eps = _mm_set1_ps( epsilon ); + int mask_lo14 = _mm_movemask_ps( _mm_cmplt_ps( d14, eps ) ); + int mask_lo56 = _mm_movemask_ps( _mm_cmplt_ps( d56, eps ) ); + eps = _mm_set1_ps( -epsilon ); + int mask_hi14 = _mm_movemask_ps( _mm_cmpgt_ps( d14, eps ) ); + int mask_hi56 = _mm_movemask_ps( _mm_cmpgt_ps( d56, eps ) ); + int mask_lo = mask_lo14 | mask_lo56 << 4; + int mask_hi = mask_hi14 | mask_hi56 << 4; + pointCull[j] = ( ( mask_lo & mask6 ) | ( mask_hi & mask6 ) << 6 ); // gcc compiler warning + } +} + +// Revelator: these work whether in gcc clang or msvc x86 or x64 (no inline assembly used) +#elif defined(_MSC_VER) && defined(_M_X64) + +#include + +/* +============ +idSIMD_SSE::GetName +============ +*/ +const char *idSIMD_SSE::GetName( void ) const { + return "MMX & SSE"; +} + +/* +============ +idSIMD_SSE::CullByFrustum +============ +*/ +void VPCALL idSIMD_SSE::CullByFrustum( idDrawVert *verts, const int numVerts, const idPlane frustum[6], byte *pointCull, float epsilon ) { + __m128 fA14 = _mm_set_ps( frustum[3][0], frustum[2][0], frustum[1][0], frustum[0][0] ); + __m128 fA56 = _mm_set_ps( 0, 0, frustum[5][0], frustum[4][0] ); + __m128 fB14 = _mm_set_ps( frustum[3][1], frustum[2][1], frustum[1][1], frustum[0][1] ); + __m128 fB56 = _mm_set_ps( 0, 0, frustum[5][1], frustum[4][1] ); + __m128 fC14 = _mm_set_ps( frustum[3][2], frustum[2][2], frustum[1][2], frustum[0][2] ); + __m128 fC56 = _mm_set_ps( 0, 0, frustum[5][2], frustum[4][2] ); + __m128 fD14 = _mm_set_ps( frustum[3][3], frustum[2][3], frustum[1][3], frustum[0][3] ); + __m128 fD56 = _mm_set_ps( 0, 0, frustum[5][3], frustum[4][3] ); + + for ( int j = 0; j < numVerts; j++ ) { + idVec3 &vec = verts[j].xyz; + __m128 vX = _mm_set1_ps( vec.x ); + __m128 vY = _mm_set1_ps( vec.y ); + __m128 vZ = _mm_set1_ps( vec.z ); + __m128 d14 = _mm_add_ps( + _mm_add_ps( + _mm_mul_ps( fA14, vX ), + _mm_mul_ps( fB14, vY ) + ), + _mm_add_ps( + _mm_mul_ps( fC14, vZ ), + fD14 + ) + ); + __m128 d56 = _mm_add_ps( + _mm_add_ps( + _mm_mul_ps( fA56, vX ), + _mm_mul_ps( fB56, vY ) + ), + _mm_add_ps( + _mm_mul_ps( fC56, vZ ), + fD56 + ) + ); + const short mask6 = ( 1 << 6 ) - 1; + __m128 eps = _mm_set1_ps( epsilon ); + int mask_lo14 = _mm_movemask_ps( _mm_cmplt_ps( d14, eps ) ); + int mask_lo56 = _mm_movemask_ps( _mm_cmplt_ps( d56, eps ) ); + int mask_lo = mask_lo14 | mask_lo56 << 4; + pointCull[j] = ( mask_lo & mask6 ); // gcc compiler warning + } +} + +/* +============ +idSIMD_SSE::CullByFrustum2 +============ +*/ +void VPCALL idSIMD_SSE::CullByFrustum2( idDrawVert *verts, const int numVerts, const idPlane frustum[6], unsigned short *pointCull, float epsilon ) { + __m128 fA14 = _mm_set_ps( frustum[3][0], frustum[2][0], frustum[1][0], frustum[0][0] ); + __m128 fA56 = _mm_set_ps( 0, 0, frustum[5][0], frustum[4][0] ); + __m128 fB14 = _mm_set_ps( frustum[3][1], frustum[2][1], frustum[1][1], frustum[0][1] ); + __m128 fB56 = _mm_set_ps( 0, 0, frustum[5][1], frustum[4][1] ); + __m128 fC14 = _mm_set_ps( frustum[3][2], frustum[2][2], frustum[1][2], frustum[0][2] ); + __m128 fC56 = _mm_set_ps( 0, 0, frustum[5][2], frustum[4][2] ); + __m128 fD14 = _mm_set_ps( frustum[3][3], frustum[2][3], frustum[1][3], frustum[0][3] ); + __m128 fD56 = _mm_set_ps( 0, 0, frustum[5][3], frustum[4][3] ); + + for ( int j = 0; j < numVerts; j++ ) { + idVec3 &vec = verts[j].xyz; + __m128 vX = _mm_set1_ps( vec.x ); + __m128 vY = _mm_set1_ps( vec.y ); + __m128 vZ = _mm_set1_ps( vec.z ); + __m128 d14 = _mm_add_ps( + _mm_add_ps( + _mm_mul_ps( fA14, vX ), + _mm_mul_ps( fB14, vY ) + ), + _mm_add_ps( + _mm_mul_ps( fC14, vZ ), + fD14 + ) + ); + __m128 d56 = _mm_add_ps( + _mm_add_ps( + _mm_mul_ps( fA56, vX ), + _mm_mul_ps( fB56, vY ) + ), + _mm_add_ps( + _mm_mul_ps( fC56, vZ ), + fD56 + ) + ); + const short mask6 = ( 1 << 6 ) - 1; + __m128 eps = _mm_set1_ps( epsilon ); + int mask_lo14 = _mm_movemask_ps( _mm_cmplt_ps( d14, eps ) ); + int mask_lo56 = _mm_movemask_ps( _mm_cmplt_ps( d56, eps ) ); + eps = _mm_set1_ps( -epsilon ); + int mask_hi14 = _mm_movemask_ps( _mm_cmpgt_ps( d14, eps ) ); + int mask_hi56 = _mm_movemask_ps( _mm_cmpgt_ps( d56, eps ) ); + int mask_lo = mask_lo14 | mask_lo56 << 4; + int mask_hi = mask_hi14 | mask_hi56 << 4; + pointCull[j] = ( ( mask_lo & mask6 ) | ( mask_hi & mask6 ) << 6 ); // gcc compiler warning + } +} + +#endif /* _MSC_VER */ diff --git a/neo/idlib/math/Simd_SSE.h b/neo/idlib/math/Simd_SSE.h index 385bac89d..7cf8d9548 100644 --- a/neo/idlib/math/Simd_SSE.h +++ b/neo/idlib/math/Simd_SSE.h @@ -45,13 +45,17 @@ class idSIMD_SSE : public idSIMD_MMX { using idSIMD_MMX::Dot; using idSIMD_MMX::MinMax; - virtual const char * VPCALL GetName( void ) const; - virtual void VPCALL Dot( float *dst, const idPlane &constant,const idDrawVert *src, const int count ); + virtual const char *VPCALL GetName( void ) const; + + virtual void VPCALL Dot( float *dst, const idPlane &constant, const idDrawVert *src, const int count ); virtual void VPCALL MinMax( idVec3 &min, idVec3 &max, const idDrawVert *src, const int *indexes, const int count ); virtual void VPCALL Dot( float *dst, const idVec3 &constant, const idPlane *src, const int count ); + virtual void VPCALL CullByFrustum( idDrawVert *verts, const int numVerts, const idPlane frustum[6], byte *pointCull, float epsilon ); + virtual void VPCALL CullByFrustum2( idDrawVert *verts, const int numVerts, const idPlane frustum[6], unsigned short *pointCull, float epsilon ); + #elif defined(_MSC_VER) && defined(_M_IX86) - virtual const char * VPCALL GetName( void ) const; + virtual const char *VPCALL GetName( void ) const; virtual void VPCALL Add( float *dst, const float constant, const float *src, const int count ); virtual void VPCALL Add( float *dst, const float *src0, const float *src1, const int count ); @@ -69,9 +73,9 @@ class idSIMD_SSE : public idSIMD_MMX { virtual void VPCALL Dot( float *dst, const idVec3 &constant, const idVec3 *src, const int count ); virtual void VPCALL Dot( float *dst, const idVec3 &constant, const idPlane *src, const int count ); virtual void VPCALL Dot( float *dst, const idVec3 &constant, const idDrawVert *src, const int count ); - virtual void VPCALL Dot( float *dst, const idPlane &constant,const idVec3 *src, const int count ); - virtual void VPCALL Dot( float *dst, const idPlane &constant,const idPlane *src, const int count ); - virtual void VPCALL Dot( float *dst, const idPlane &constant,const idDrawVert *src, const int count ); + virtual void VPCALL Dot( float *dst, const idPlane &constant, const idVec3 *src, const int count ); + virtual void VPCALL Dot( float *dst, const idPlane &constant, const idPlane *src, const int count ); + virtual void VPCALL Dot( float *dst, const idPlane &constant, const idDrawVert *src, const int count ); virtual void VPCALL Dot( float *dst, const idVec3 *src0, const idVec3 *src1, const int count ); virtual void VPCALL Dot( float &dot, const float *src1, const float *src2, const int count ); @@ -143,7 +147,19 @@ class idSIMD_SSE : public idSIMD_MMX { virtual void VPCALL MixSoundSixSpeakerStereo( float *mixBuffer, const float *samples, const int numSamples, const float lastV[6], const float currentV[6] ); virtual void VPCALL MixedSoundToSamples( short *samples, const float *mixBuffer, const int numSamples ); -#endif + // revelator: we got tree of these and all are the same but some compilers choke on not having guards, yeah not a beauty contest luckily + virtual void VPCALL CullByFrustum( idDrawVert *verts, const int numVerts, const idPlane frustum[6], byte *pointCull, float epsilon ); + virtual void VPCALL CullByFrustum2( idDrawVert *verts, const int numVerts, const idPlane frustum[6], unsigned short *pointCull, float epsilon ); + +// Revelator: these work whether in gcc clang or msvc x86 or x64 (no inline assembly used) +#elif defined(_MSC_VER) && defined(_M_X64) + + virtual const char *VPCALL GetName( void ) const; + + virtual void VPCALL CullByFrustum( idDrawVert *verts, const int numVerts, const idPlane frustum[6], byte *pointCull, float epsilon ); + virtual void VPCALL CullByFrustum2( idDrawVert *verts, const int numVerts, const idPlane frustum[6], unsigned short *pointCull, float epsilon ); + +#endif /* _MSC_VER */ }; #endif /* !__MATH_SIMD_SSE_H__ */ diff --git a/neo/idlib/math/Simd_SSE2.cpp b/neo/idlib/math/Simd_SSE2.cpp index 1954913f7..a235f03ee 100644 --- a/neo/idlib/math/Simd_SSE2.cpp +++ b/neo/idlib/math/Simd_SSE2.cpp @@ -27,7 +27,6 @@ If you have questions concerning this license or the applicable additional terms */ #include "sys/platform.h" - #include "idlib/math/Simd_SSE2.h" //=============================================================== @@ -47,7 +46,7 @@ If you have questions concerning this license or the applicable additional terms idSIMD_SSE2::GetName ============ */ -const char * idSIMD_SSE2::GetName( void ) const { +const char *idSIMD_SSE2::GetName( void ) const { return "MMX & SSE & SSE2"; } @@ -283,547 +282,10 @@ ALIGN4_INIT1( float SIMD_SP_infinity, idMath::INFINITY ); idSIMD_SSE2::GetName ============ */ -const char * idSIMD_SSE2::GetName( void ) const { +const char *idSIMD_SSE2::GetName( void ) const { return "MMX & SSE & SSE2"; } -#if 0 // the SSE2 code is ungodly slow - -/* -============ -idSIMD_SSE2::MatX_LowerTriangularSolve - - solves x in Lx = b for the n * n sub-matrix of L - if skip > 0 the first skip elements of x are assumed to be valid already - L has to be a lower triangular matrix with (implicit) ones on the diagonal - x == b is allowed -============ -*/ -void VPCALL idSIMD_SSE2::MatX_LowerTriangularSolve( const idMatX &L, float *x, const float *b, const int n, int skip ) { - int nc; - const float *lptr; - - if ( skip >= n ) { - return; - } - - lptr = L[skip]; - nc = L.GetNumColumns(); - - // unrolled cases for n < 8 - if ( n < 8 ) { - #define NSKIP( n, s ) ((n<<3)|(s&7)) - switch( NSKIP( n, skip ) ) { - case NSKIP( 1, 0 ): x[0] = b[0]; - return; - case NSKIP( 2, 0 ): x[0] = b[0]; - case NSKIP( 2, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - return; - case NSKIP( 3, 0 ): x[0] = b[0]; - case NSKIP( 3, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - case NSKIP( 3, 2 ): x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - return; - case NSKIP( 4, 0 ): x[0] = b[0]; - case NSKIP( 4, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - case NSKIP( 4, 2 ): x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - case NSKIP( 4, 3 ): x[3] = b[3] - lptr[3*nc+0] * x[0] - lptr[3*nc+1] * x[1] - lptr[3*nc+2] * x[2]; - return; - case NSKIP( 5, 0 ): x[0] = b[0]; - case NSKIP( 5, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - case NSKIP( 5, 2 ): x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - case NSKIP( 5, 3 ): x[3] = b[3] - lptr[3*nc+0] * x[0] - lptr[3*nc+1] * x[1] - lptr[3*nc+2] * x[2]; - case NSKIP( 5, 4 ): x[4] = b[4] - lptr[4*nc+0] * x[0] - lptr[4*nc+1] * x[1] - lptr[4*nc+2] * x[2] - lptr[4*nc+3] * x[3]; - return; - case NSKIP( 6, 0 ): x[0] = b[0]; - case NSKIP( 6, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - case NSKIP( 6, 2 ): x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - case NSKIP( 6, 3 ): x[3] = b[3] - lptr[3*nc+0] * x[0] - lptr[3*nc+1] * x[1] - lptr[3*nc+2] * x[2]; - case NSKIP( 6, 4 ): x[4] = b[4] - lptr[4*nc+0] * x[0] - lptr[4*nc+1] * x[1] - lptr[4*nc+2] * x[2] - lptr[4*nc+3] * x[3]; - case NSKIP( 6, 5 ): x[5] = b[5] - lptr[5*nc+0] * x[0] - lptr[5*nc+1] * x[1] - lptr[5*nc+2] * x[2] - lptr[5*nc+3] * x[3] - lptr[5*nc+4] * x[4]; - return; - case NSKIP( 7, 0 ): x[0] = b[0]; - case NSKIP( 7, 1 ): x[1] = b[1] - lptr[1*nc+0] * x[0]; - case NSKIP( 7, 2 ): x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - case NSKIP( 7, 3 ): x[3] = b[3] - lptr[3*nc+0] * x[0] - lptr[3*nc+1] * x[1] - lptr[3*nc+2] * x[2]; - case NSKIP( 7, 4 ): x[4] = b[4] - lptr[4*nc+0] * x[0] - lptr[4*nc+1] * x[1] - lptr[4*nc+2] * x[2] - lptr[4*nc+3] * x[3]; - case NSKIP( 7, 5 ): x[5] = b[5] - lptr[5*nc+0] * x[0] - lptr[5*nc+1] * x[1] - lptr[5*nc+2] * x[2] - lptr[5*nc+3] * x[3] - lptr[5*nc+4] * x[4]; - case NSKIP( 7, 6 ): x[6] = b[6] - lptr[6*nc+0] * x[0] - lptr[6*nc+1] * x[1] - lptr[6*nc+2] * x[2] - lptr[6*nc+3] * x[3] - lptr[6*nc+4] * x[4] - lptr[6*nc+5] * x[5]; - return; - } - return; - } - - // process first 4 rows - switch( skip ) { - case 0: x[0] = b[0]; - case 1: x[1] = b[1] - lptr[1*nc+0] * x[0]; - case 2: x[2] = b[2] - lptr[2*nc+0] * x[0] - lptr[2*nc+1] * x[1]; - case 3: x[3] = b[3] - lptr[3*nc+0] * x[0] - lptr[3*nc+1] * x[1] - lptr[3*nc+2] * x[2]; - skip = 4; - } - - lptr = L[skip]; - - __asm { - push ebx - mov eax, skip // eax = i - shl eax, 2 // eax = i*4 - mov edx, n // edx = n - shl edx, 2 // edx = n*4 - mov esi, x // esi = x - mov edi, lptr // edi = lptr - add esi, eax - add edi, eax - mov ebx, b // ebx = b - // aligned - looprow: - mov ecx, eax - neg ecx - cvtps2pd xmm0, [esi+ecx] - cvtps2pd xmm2, [edi+ecx] - mulpd xmm0, xmm2 - cvtps2pd xmm1, [esi+ecx+8] - cvtps2pd xmm3, [edi+ecx+8] - mulpd xmm1, xmm3 - add ecx, 20*4 - jg donedot16 - dot16: - cvtps2pd xmm2, [esi+ecx-(16*4)] - cvtps2pd xmm3, [edi+ecx-(16*4)] - cvtps2pd xmm4, [esi+ecx-(14*4)] - mulpd xmm2, xmm3 - cvtps2pd xmm5, [edi+ecx-(14*4)] - addpd xmm0, xmm2 - cvtps2pd xmm2, [esi+ecx-(12*4)] - mulpd xmm4, xmm5 - cvtps2pd xmm3, [edi+ecx-(12*4)] - addpd xmm1, xmm4 - cvtps2pd xmm4, [esi+ecx-(10*4)] - mulpd xmm2, xmm3 - cvtps2pd xmm5, [edi+ecx-(10*4)] - addpd xmm0, xmm2 - cvtps2pd xmm2, [esi+ecx-(8*4)] - mulpd xmm4, xmm5 - cvtps2pd xmm3, [edi+ecx-(8*4)] - addpd xmm1, xmm4 - cvtps2pd xmm4, [esi+ecx-(6*4)] - mulpd xmm2, xmm3 - cvtps2pd xmm5, [edi+ecx-(6*4)] - addpd xmm0, xmm2 - cvtps2pd xmm2, [esi+ecx-(4*4)] - mulpd xmm4, xmm5 - cvtps2pd xmm3, [edi+ecx-(4*4)] - addpd xmm1, xmm4 - cvtps2pd xmm4, [esi+ecx-(2*4)] - mulpd xmm2, xmm3 - cvtps2pd xmm5, [edi+ecx-(2*4)] - addpd xmm0, xmm2 - add ecx, 16*4 - mulpd xmm4, xmm5 - addpd xmm1, xmm4 - jle dot16 - donedot16: - sub ecx, 8*4 - jg donedot8 - dot8: - cvtps2pd xmm2, [esi+ecx-(8*4)] - cvtps2pd xmm3, [edi+ecx-(8*4)] - cvtps2pd xmm7, [esi+ecx-(6*4)] - mulpd xmm2, xmm3 - cvtps2pd xmm5, [edi+ecx-(6*4)] - addpd xmm0, xmm2 - cvtps2pd xmm6, [esi+ecx-(4*4)] - mulpd xmm7, xmm5 - cvtps2pd xmm3, [edi+ecx-(4*4)] - addpd xmm1, xmm7 - cvtps2pd xmm4, [esi+ecx-(2*4)] - mulpd xmm6, xmm3 - cvtps2pd xmm7, [edi+ecx-(2*4)] - addpd xmm0, xmm6 - add ecx, 8*4 - mulpd xmm4, xmm7 - addpd xmm1, xmm4 - donedot8: - sub ecx, 4*4 - jg donedot4 - dot4: - cvtps2pd xmm2, [esi+ecx-(4*4)] - cvtps2pd xmm3, [edi+ecx-(4*4)] - cvtps2pd xmm4, [esi+ecx-(2*4)] - mulpd xmm2, xmm3 - cvtps2pd xmm5, [edi+ecx-(2*4)] - addpd xmm0, xmm2 - add ecx, 4*4 - mulpd xmm4, xmm5 - addpd xmm1, xmm4 - donedot4: - addpd xmm0, xmm1 - movaps xmm1, xmm0 - shufpd xmm1, xmm1, R_SHUFFLEPD( 1, 0 ) - addsd xmm0, xmm1 - sub ecx, 4*4 - jz dot0 - add ecx, 4 - jz dot1 - add ecx, 4 - jz dot2 - //dot3: - cvtss2sd xmm1, [esi-(3*4)] - cvtss2sd xmm2, [edi-(3*4)] - mulsd xmm1, xmm2 - addsd xmm0, xmm1 - dot2: - cvtss2sd xmm3, [esi-(2*4)] - cvtss2sd xmm4, [edi-(2*4)] - mulsd xmm3, xmm4 - addsd xmm0, xmm3 - dot1: - cvtss2sd xmm5, [esi-(1*4)] - cvtss2sd xmm6, [edi-(1*4)] - mulsd xmm5, xmm6 - addsd xmm0, xmm5 - dot0: - cvtss2sd xmm1, [ebx+eax] - subsd xmm1, xmm0 - cvtsd2ss xmm0, xmm1 - movss [esi], xmm0 - add eax, 4 - cmp eax, edx - jge done - add esi, 4 - mov ecx, nc - shl ecx, 2 - add edi, ecx - add edi, 4 - jmp looprow - // done - done: - pop ebx - } -} - -/* -============ -idSIMD_SSE2::MatX_LowerTriangularSolveTranspose - - solves x in L'x = b for the n * n sub-matrix of L - L has to be a lower triangular matrix with (implicit) ones on the diagonal - x == b is allowed -============ -*/ -void VPCALL idSIMD_SSE2::MatX_LowerTriangularSolveTranspose( const idMatX &L, float *x, const float *b, const int n ) { - int nc; - const float *lptr; - - lptr = L.ToFloatPtr(); - nc = L.GetNumColumns(); - - // unrolled cases for n < 8 - if ( n < 8 ) { - switch( n ) { - case 0: - return; - case 1: - x[0] = b[0]; - return; - case 2: - x[1] = b[1]; - x[0] = b[0] - lptr[1*nc+0] * x[1]; - return; - case 3: - x[2] = b[2]; - x[1] = b[1] - lptr[2*nc+1] * x[2]; - x[0] = b[0] - lptr[2*nc+0] * x[2] - lptr[1*nc+0] * x[1]; - return; - case 4: - x[3] = b[3]; - x[2] = b[2] - lptr[3*nc+2] * x[3]; - x[1] = b[1] - lptr[3*nc+1] * x[3] - lptr[2*nc+1] * x[2]; - x[0] = b[0] - lptr[3*nc+0] * x[3] - lptr[2*nc+0] * x[2] - lptr[1*nc+0] * x[1]; - return; - case 5: - x[4] = b[4]; - x[3] = b[3] - lptr[4*nc+3] * x[4]; - x[2] = b[2] - lptr[4*nc+2] * x[4] - lptr[3*nc+2] * x[3]; - x[1] = b[1] - lptr[4*nc+1] * x[4] - lptr[3*nc+1] * x[3] - lptr[2*nc+1] * x[2]; - x[0] = b[0] - lptr[4*nc+0] * x[4] - lptr[3*nc+0] * x[3] - lptr[2*nc+0] * x[2] - lptr[1*nc+0] * x[1]; - return; - case 6: - x[5] = b[5]; - x[4] = b[4] - lptr[5*nc+4] * x[5]; - x[3] = b[3] - lptr[5*nc+3] * x[5] - lptr[4*nc+3] * x[4]; - x[2] = b[2] - lptr[5*nc+2] * x[5] - lptr[4*nc+2] * x[4] - lptr[3*nc+2] * x[3]; - x[1] = b[1] - lptr[5*nc+1] * x[5] - lptr[4*nc+1] * x[4] - lptr[3*nc+1] * x[3] - lptr[2*nc+1] * x[2]; - x[0] = b[0] - lptr[5*nc+0] * x[5] - lptr[4*nc+0] * x[4] - lptr[3*nc+0] * x[3] - lptr[2*nc+0] * x[2] - lptr[1*nc+0] * x[1]; - return; - case 7: - x[6] = b[6]; - x[5] = b[5] - lptr[6*nc+5] * x[6]; - x[4] = b[4] - lptr[6*nc+4] * x[6] - lptr[5*nc+4] * x[5]; - x[3] = b[3] - lptr[6*nc+3] * x[6] - lptr[5*nc+3] * x[5] - lptr[4*nc+3] * x[4]; - x[2] = b[2] - lptr[6*nc+2] * x[6] - lptr[5*nc+2] * x[5] - lptr[4*nc+2] * x[4] - lptr[3*nc+2] * x[3]; - x[1] = b[1] - lptr[6*nc+1] * x[6] - lptr[5*nc+1] * x[5] - lptr[4*nc+1] * x[4] - lptr[3*nc+1] * x[3] - lptr[2*nc+1] * x[2]; - x[0] = b[0] - lptr[6*nc+0] * x[6] - lptr[5*nc+0] * x[5] - lptr[4*nc+0] * x[4] - lptr[3*nc+0] * x[3] - lptr[2*nc+0] * x[2] - lptr[1*nc+0] * x[1]; - return; - } - return; - } - - int i, j, m; - float *xptr; - double s0; - - // if the number of columns is not a multiple of 2 we're screwed for alignment. - // however, if the number of columns is a multiple of 2 but the number of to be - // processed rows is not a multiple of 2 we can still run 8 byte aligned - m = n; - if ( m & 1 ) { - m--; - x[m] = b[m]; - - lptr = L[m] + m - 4; - xptr = x + m; - __asm { - push ebx - mov eax, m // eax = i - mov esi, xptr // esi = xptr - mov edi, lptr // edi = lptr - mov ebx, b // ebx = b - mov edx, nc // edx = nc*sizeof(float) - shl edx, 2 - process4rows_1: - cvtps2pd xmm0, [ebx+eax*4-16] // load b[i-2], b[i-1] - cvtps2pd xmm2, [ebx+eax*4-8] // load b[i-4], b[i-3] - xor ecx, ecx - sub eax, m - neg eax - jz done4x4_1 - process4x4_1: // process 4x4 blocks - cvtps2pd xmm3, [edi] - cvtps2pd xmm4, [edi+8] - add edi, edx - cvtss2sd xmm5, [esi+4*ecx+0] - shufpd xmm5, xmm5, R_SHUFFLEPD( 0, 0 ) - mulpd xmm3, xmm5 - cvtps2pd xmm1, [edi] - mulpd xmm4, xmm5 - cvtps2pd xmm6, [edi+8] - subpd xmm0, xmm3 - subpd xmm2, xmm4 - add edi, edx - cvtss2sd xmm7, [esi+4*ecx+4] - shufpd xmm7, xmm7, R_SHUFFLEPD( 0, 0 ) - mulpd xmm1, xmm7 - cvtps2pd xmm3, [edi] - mulpd xmm6, xmm7 - cvtps2pd xmm4, [edi+8] - subpd xmm0, xmm1 - subpd xmm2, xmm6 - add edi, edx - cvtss2sd xmm5, [esi+4*ecx+8] - shufpd xmm5, xmm5, R_SHUFFLEPD( 0, 0 ) - mulpd xmm3, xmm5 - cvtps2pd xmm1, [edi] - mulpd xmm4, xmm5 - cvtps2pd xmm6, [edi+8] - subpd xmm0, xmm3 - subpd xmm2, xmm4 - add edi, edx - cvtss2sd xmm7, [esi+4*ecx+12] - shufpd xmm7, xmm7, R_SHUFFLEPD( 0, 0 ) - mulpd xmm1, xmm7 - add ecx, 4 - mulpd xmm6, xmm7 - cmp ecx, eax - subpd xmm0, xmm1 - subpd xmm2, xmm6 - jl process4x4_1 - done4x4_1: // process left over of the 4 rows - cvtps2pd xmm3, [edi] - cvtps2pd xmm4, [edi+8] - cvtss2sd xmm5, [esi+4*ecx] - shufpd xmm5, xmm5, R_SHUFFLEPD( 0, 0 ) - mulpd xmm3, xmm5 - mulpd xmm4, xmm5 - subpd xmm0, xmm3 - subpd xmm2, xmm4 - imul ecx, edx - sub edi, ecx - neg eax - - add eax, m - sub eax, 4 - movapd xmm1, xmm0 - shufpd xmm1, xmm1, R_SHUFFLEPD( 1, 1 ) - movapd xmm3, xmm2 - shufpd xmm3, xmm3, R_SHUFFLEPD( 1, 1 ) - sub edi, edx - cvtsd2ss xmm7, xmm3 - movss [esi-4], xmm7 // xptr[-1] = s3 - movsd xmm4, xmm3 - movsd xmm5, xmm3 - cvtss2sd xmm7, [edi+8] - mulsd xmm3, xmm7 // lptr[-1*nc+2] * s3 - cvtss2sd xmm7, [edi+4] - mulsd xmm4, xmm7 // lptr[-1*nc+1] * s3 - cvtss2sd xmm7, [edi] - mulsd xmm5, xmm7 // lptr[-1*nc+0] * s3 - subsd xmm2, xmm3 - cvtsd2ss xmm7, xmm2 - movss [esi-8], xmm7 // xptr[-2] = s2 - movsd xmm6, xmm2 - sub edi, edx - subsd xmm0, xmm5 - subsd xmm1, xmm4 - cvtss2sd xmm7, [edi+4] - mulsd xmm2, xmm7 // lptr[-2*nc+1] * s2 - cvtss2sd xmm7, [edi] - mulsd xmm6, xmm7 // lptr[-2*nc+0] * s2 - subsd xmm1, xmm2 - cvtsd2ss xmm7, xmm1 - movss [esi-12], xmm7 // xptr[-3] = s1 - subsd xmm0, xmm6 - sub edi, edx - cmp eax, 4 - cvtss2sd xmm7, [edi] - mulsd xmm1, xmm7 // lptr[-3*nc+0] * s1 - subsd xmm0, xmm1 - cvtsd2ss xmm7, xmm0 - movss [esi-16], xmm7 // xptr[-4] = s0 - jl done4rows_1 - sub edi, edx - sub edi, 16 - sub esi, 16 - jmp process4rows_1 - done4rows_1: - pop ebx - } - } - else { - lptr = L.ToFloatPtr() + m * L.GetNumColumns() + m - 4; - xptr = x + m; - __asm { - push ebx - mov eax, m // eax = i - mov esi, xptr // esi = xptr - mov edi, lptr // edi = lptr - mov ebx, b // ebx = b - mov edx, nc // edx = nc*sizeof(float) - shl edx, 2 - process4rows: - cvtps2pd xmm0, [ebx+eax*4-16] // load b[i-2], b[i-1] - cvtps2pd xmm2, [ebx+eax*4-8] // load b[i-4], b[i-3] - sub eax, m - jz done4x4 - neg eax - xor ecx, ecx - process4x4: // process 4x4 blocks - cvtps2pd xmm3, [edi] - cvtps2pd xmm4, [edi+8] - add edi, edx - cvtss2sd xmm5, [esi+4*ecx+0] - shufpd xmm5, xmm5, R_SHUFFLEPD( 0, 0 ) - mulpd xmm3, xmm5 - cvtps2pd xmm1, [edi] - mulpd xmm4, xmm5 - cvtps2pd xmm6, [edi+8] - subpd xmm0, xmm3 - subpd xmm2, xmm4 - add edi, edx - cvtss2sd xmm7, [esi+4*ecx+4] - shufpd xmm7, xmm7, R_SHUFFLEPD( 0, 0 ) - mulpd xmm1, xmm7 - cvtps2pd xmm3, [edi] - mulpd xmm6, xmm7 - cvtps2pd xmm4, [edi+8] - subpd xmm0, xmm1 - subpd xmm2, xmm6 - add edi, edx - cvtss2sd xmm5, [esi+4*ecx+8] - shufpd xmm5, xmm5, R_SHUFFLEPD( 0, 0 ) - mulpd xmm3, xmm5 - cvtps2pd xmm1, [edi] - mulpd xmm4, xmm5 - cvtps2pd xmm6, [edi+8] - subpd xmm0, xmm3 - subpd xmm2, xmm4 - add edi, edx - cvtss2sd xmm7, [esi+4*ecx+12] - shufpd xmm7, xmm7, R_SHUFFLEPD( 0, 0 ) - mulpd xmm1, xmm7 - add ecx, 4 - mulpd xmm6, xmm7 - cmp ecx, eax - subpd xmm0, xmm1 - subpd xmm2, xmm6 - jl process4x4 - imul ecx, edx - sub edi, ecx - neg eax - done4x4: // process left over of the 4 rows - add eax, m - sub eax, 4 - movapd xmm1, xmm0 - shufpd xmm1, xmm1, R_SHUFFLEPD( 1, 1 ) - movapd xmm3, xmm2 - shufpd xmm3, xmm3, R_SHUFFLEPD( 1, 1 ) - sub edi, edx - cvtsd2ss xmm7, xmm3 - movss [esi-4], xmm7 // xptr[-1] = s3 - movsd xmm4, xmm3 - movsd xmm5, xmm3 - cvtss2sd xmm7, [edi+8] - mulsd xmm3, xmm7 // lptr[-1*nc+2] * s3 - cvtss2sd xmm7, [edi+4] - mulsd xmm4, xmm7 // lptr[-1*nc+1] * s3 - cvtss2sd xmm7, [edi] - mulsd xmm5, xmm7 // lptr[-1*nc+0] * s3 - subsd xmm2, xmm3 - cvtsd2ss xmm7, xmm2 - movss [esi-8], xmm7 // xptr[-2] = s2 - movsd xmm6, xmm2 - sub edi, edx - subsd xmm0, xmm5 - subsd xmm1, xmm4 - cvtss2sd xmm7, [edi+4] - mulsd xmm2, xmm7 // lptr[-2*nc+1] * s2 - cvtss2sd xmm7, [edi] - mulsd xmm6, xmm7 // lptr[-2*nc+0] * s2 - subsd xmm1, xmm2 - cvtsd2ss xmm7, xmm1 - movss [esi-12], xmm7 // xptr[-3] = s1 - subsd xmm0, xmm6 - sub edi, edx - cmp eax, 4 - cvtss2sd xmm7, [edi] - mulsd xmm1, xmm7 // lptr[-3*nc+0] * s1 - subsd xmm0, xmm1 - cvtsd2ss xmm7, xmm0 - movss [esi-16], xmm7 // xptr[-4] = s0 - jl done4rows - sub edi, edx - sub edi, 16 - sub esi, 16 - jmp process4rows - done4rows: - pop ebx - } - } - - // process left over rows - for ( i = (m&3)-1; i >= 0; i-- ) { - s0 = b[i]; - lptr = L[i+1] + i; - for ( j = i + 1; j < m; j++ ) { - s0 -= lptr[0] * x[j]; - lptr += nc; - } - x[i] = s0; - } -} - -#endif - /* ============ idSIMD_SSE2::MixedSoundToSamples diff --git a/neo/idlib/math/Simd_SSE2.h b/neo/idlib/math/Simd_SSE2.h index 6a149c986..0e1a74183 100644 --- a/neo/idlib/math/Simd_SSE2.h +++ b/neo/idlib/math/Simd_SSE2.h @@ -44,17 +44,11 @@ class idSIMD_SSE2 : public idSIMD_SSE { #if defined(__GNUC__) && defined(__SSE2__) using idSIMD_SSE::CmpLT; - virtual const char * VPCALL GetName( void ) const; + virtual const char *VPCALL GetName( void ) const; virtual void VPCALL CmpLT( byte *dst, const byte bitNum, const float *src0, const float constant, const int count ); - #elif defined(_MSC_VER) && defined(_M_IX86) - virtual const char * VPCALL GetName( void ) const; - - //virtual void VPCALL MatX_LowerTriangularSolve( const idMatX &L, float *x, const float *b, const int n, int skip = 0 ); - //virtual void VPCALL MatX_LowerTriangularSolveTranspose( const idMatX &L, float *x, const float *b, const int n ); - + virtual const char *VPCALL GetName( void ) const; virtual void VPCALL MixedSoundToSamples( short *samples, const float *mixBuffer, const int numSamples ); - #endif }; diff --git a/neo/idlib/math/Simd_SSE3.cpp b/neo/idlib/math/Simd_SSE3.cpp index b177a6540..ced430113 100644 --- a/neo/idlib/math/Simd_SSE3.cpp +++ b/neo/idlib/math/Simd_SSE3.cpp @@ -27,7 +27,6 @@ If you have questions concerning this license or the applicable additional terms */ #include "sys/platform.h" - #include "idlib/math/Simd_SSE3.h" //=============================================================== @@ -43,7 +42,7 @@ If you have questions concerning this license or the applicable additional terms idSIMD_SSE3::GetName ============ */ -const char * idSIMD_SSE3::GetName( void ) const { +const char *idSIMD_SSE3::GetName( void ) const { return "MMX & SSE & SSE2 & SSE3"; } @@ -257,7 +256,7 @@ float SSE3_Dot( const idVec4 &v1, const idVec4 &v2 ) { idSIMD_SSE3::GetName ============ */ -const char * idSIMD_SSE3::GetName( void ) const { +const char *idSIMD_SSE3::GetName( void ) const { return "MMX & SSE & SSE2 & SSE3"; } diff --git a/neo/idlib/math/Simd_SSE3.h b/neo/idlib/math/Simd_SSE3.h index c3d87da37..65c84e802 100644 --- a/neo/idlib/math/Simd_SSE3.h +++ b/neo/idlib/math/Simd_SSE3.h @@ -42,13 +42,10 @@ If you have questions concerning this license or the applicable additional terms class idSIMD_SSE3 : public idSIMD_SSE2 { public: #if defined(__GNUC__) && defined(__SSE3__) - virtual const char * VPCALL GetName( void ) const; - + virtual const char *VPCALL GetName( void ) const; #elif defined(_MSC_VER) && defined(_M_IX86) - virtual const char * VPCALL GetName( void ) const; - + virtual const char *VPCALL GetName( void ) const; virtual void VPCALL TransformVerts( idDrawVert *verts, const int numVerts, const idJointMat *joints, const idVec4 *weights, const int *index, const int numWeights ); - #endif }; diff --git a/neo/renderer/GuiModel.cpp b/neo/renderer/GuiModel.cpp index 3af7f02e6..555023ad2 100644 --- a/neo/renderer/GuiModel.cpp +++ b/neo/renderer/GuiModel.cpp @@ -39,8 +39,8 @@ idGuiModel::idGuiModel ================ */ idGuiModel::idGuiModel() { - indexes.SetGranularity( 1000 ); - verts.SetGranularity( 1000 ); + indexes.SetGranularity( 1000 ); + verts.SetGranularity( 1000 ); } /* @@ -51,10 +51,10 @@ Begins collecting draw commands into surfaces ================ */ void idGuiModel::Clear() { - surfaces.SetNum( 0, false ); - indexes.SetNum( 0, false ); - verts.SetNum( 0, false ); - AdvanceSurf(); + surfaces.SetNum( 0, false ); + indexes.SetNum( 0, false ); + verts.SetNum( 0, false ); + AdvanceSurf(); } /* @@ -63,45 +63,48 @@ idGuiModel::WriteToDemo ================ */ void idGuiModel::WriteToDemo( idDemoFile *demo ) { - int i, j; - - i = verts.Num(); - demo->WriteInt( i ); - for ( j = 0; j < i; j++ ) - { - demo->WriteVec3( verts[j].xyz ); - demo->WriteVec2( verts[j].st ); - demo->WriteVec3( verts[j].normal ); - demo->WriteVec3( verts[j].tangents[0] ); - demo->WriteVec3( verts[j].tangents[1] ); - demo->WriteUnsignedChar( verts[j].color[0] ); - demo->WriteUnsignedChar( verts[j].color[1] ); - demo->WriteUnsignedChar( verts[j].color[2] ); - demo->WriteUnsignedChar( verts[j].color[3] ); - } - - i = indexes.Num(); - demo->WriteInt( i ); - for ( j = 0; j < i; j++ ) { - demo->WriteInt(indexes[j] ); - } - - i = surfaces.Num(); - demo->WriteInt( i ); - for ( j = 0 ; j < i ; j++ ) { - guiModelSurface_t *surf = &surfaces[j]; - - demo->WriteInt( (int&)surf->material ); - demo->WriteFloat( surf->color[0] ); - demo->WriteFloat( surf->color[1] ); - demo->WriteFloat( surf->color[2] ); - demo->WriteFloat( surf->color[3] ); - demo->WriteInt( surf->firstVert ); - demo->WriteInt( surf->numVerts ); - demo->WriteInt( surf->firstIndex ); - demo->WriteInt( surf->numIndexes ); - demo->WriteHashString( surf->material->GetName() ); - } + int i, j; + + i = verts.Num(); + + demo->WriteInt( i ); + + for ( j = 0; j < i; j++ ) { + demo->WriteVec3( verts[j].xyz ); + demo->WriteVec2( verts[j].st ); + demo->WriteVec3( verts[j].normal ); + demo->WriteVec3( verts[j].tangents[0] ); + demo->WriteVec3( verts[j].tangents[1] ); + demo->WriteUnsignedChar( verts[j].color[0] ); + demo->WriteUnsignedChar( verts[j].color[1] ); + demo->WriteUnsignedChar( verts[j].color[2] ); + demo->WriteUnsignedChar( verts[j].color[3] ); + } + i = indexes.Num(); + + demo->WriteInt( i ); + + for ( j = 0; j < i; j++ ) { + demo->WriteInt( indexes[j] ); + } + i = surfaces.Num(); + + demo->WriteInt( i ); + + for ( j = 0 ; j < i ; j++ ) { + guiModelSurface_t *surf = &surfaces[j]; + + demo->WriteInt( ( int & )surf->material ); + demo->WriteFloat( surf->color[0] ); + demo->WriteFloat( surf->color[1] ); + demo->WriteFloat( surf->color[2] ); + demo->WriteFloat( surf->color[3] ); + demo->WriteInt( surf->firstVert ); + demo->WriteInt( surf->numVerts ); + demo->WriteInt( surf->firstIndex ); + demo->WriteInt( surf->numIndexes ); + demo->WriteHashString( surf->material->GetName() ); + } } /* @@ -110,48 +113,54 @@ idGuiModel::ReadFromDemo ================ */ void idGuiModel::ReadFromDemo( idDemoFile *demo ) { - int i, j; - - i = verts.Num(); - demo->ReadInt( i ); - verts.SetNum( i, false ); - for ( j = 0; j < i; j++ ) - { - demo->ReadVec3( verts[j].xyz ); - demo->ReadVec2( verts[j].st ); - demo->ReadVec3( verts[j].normal ); - demo->ReadVec3( verts[j].tangents[0] ); - demo->ReadVec3( verts[j].tangents[1] ); - demo->ReadUnsignedChar( verts[j].color[0] ); - demo->ReadUnsignedChar( verts[j].color[1] ); - demo->ReadUnsignedChar( verts[j].color[2] ); - demo->ReadUnsignedChar( verts[j].color[3] ); - } - - i = indexes.Num(); - demo->ReadInt( i ); - indexes.SetNum( i, false ); - for ( j = 0; j < i; j++ ) { - demo->ReadInt(indexes[j] ); - } - - i = surfaces.Num(); - demo->ReadInt( i ); - surfaces.SetNum( i, false ); - for ( j = 0 ; j < i ; j++ ) { - guiModelSurface_t *surf = &surfaces[j]; - - demo->ReadInt( (int&)surf->material ); - demo->ReadFloat( surf->color[0] ); - demo->ReadFloat( surf->color[1] ); - demo->ReadFloat( surf->color[2] ); - demo->ReadFloat( surf->color[3] ); - demo->ReadInt( surf->firstVert ); - demo->ReadInt( surf->numVerts ); - demo->ReadInt( surf->firstIndex ); - demo->ReadInt( surf->numIndexes ); - surf->material = declManager->FindMaterial( demo->ReadHashString() ); - } + int i, j; + + i = verts.Num(); + + demo->ReadInt( i ); + + verts.SetNum( i, false ); + + for ( j = 0; j < i; j++ ) { + demo->ReadVec3( verts[j].xyz ); + demo->ReadVec2( verts[j].st ); + demo->ReadVec3( verts[j].normal ); + demo->ReadVec3( verts[j].tangents[0] ); + demo->ReadVec3( verts[j].tangents[1] ); + demo->ReadUnsignedChar( verts[j].color[0] ); + demo->ReadUnsignedChar( verts[j].color[1] ); + demo->ReadUnsignedChar( verts[j].color[2] ); + demo->ReadUnsignedChar( verts[j].color[3] ); + } + i = indexes.Num(); + + demo->ReadInt( i ); + + indexes.SetNum( i, false ); + + for ( j = 0; j < i; j++ ) { + demo->ReadInt( indexes[j] ); + } + i = surfaces.Num(); + + demo->ReadInt( i ); + + surfaces.SetNum( i, false ); + + for ( j = 0 ; j < i ; j++ ) { + guiModelSurface_t *surf = &surfaces[j]; + + demo->ReadInt( ( int & )surf->material ); + demo->ReadFloat( surf->color[0] ); + demo->ReadFloat( surf->color[1] ); + demo->ReadFloat( surf->color[2] ); + demo->ReadFloat( surf->color[3] ); + demo->ReadInt( surf->firstVert ); + demo->ReadInt( surf->numVerts ); + demo->ReadInt( surf->firstIndex ); + demo->ReadInt( surf->numIndexes ); + surf->material = declManager->FindMaterial( demo->ReadHashString() ); + } } /* @@ -160,45 +169,44 @@ EmitSurface ================ */ void idGuiModel::EmitSurface( guiModelSurface_t *surf, float modelMatrix[16], float modelViewMatrix[16], bool depthHack ) { - srfTriangles_t *tri; - - if ( surf->numVerts == 0 ) { - return; // nothing in the surface - } - - // copy verts and indexes - tri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *tri ) ); - - tri->numIndexes = surf->numIndexes; - tri->numVerts = surf->numVerts; - tri->indexes = (glIndex_t *)R_FrameAlloc( tri->numIndexes * sizeof( tri->indexes[0] ) ); - memcpy( tri->indexes, &indexes[surf->firstIndex], tri->numIndexes * sizeof( tri->indexes[0] ) ); - - // we might be able to avoid copying these and just let them reference the list vars - // but some things, like deforms and recursive - // guis, need to access the verts in cpu space, not just through the vertex range - tri->verts = (idDrawVert *)R_FrameAlloc( tri->numVerts * sizeof( tri->verts[0] ) ); - memcpy( tri->verts, &verts[surf->firstVert], tri->numVerts * sizeof( tri->verts[0] ) ); - - // move the verts to the vertex cache - tri->ambientCache = vertexCache.AllocFrameTemp( tri->verts, tri->numVerts * sizeof( tri->verts[0] ) ); - - // if we are out of vertex cache, don't create the surface - if ( !tri->ambientCache ) { - return; - } - - renderEntity_t renderEntity; - memset( &renderEntity, 0, sizeof( renderEntity ) ); - memcpy( renderEntity.shaderParms, surf->color, sizeof( surf->color ) ); - - viewEntity_t *guiSpace = (viewEntity_t *)R_ClearedFrameAlloc( sizeof( *guiSpace ) ); - memcpy( guiSpace->modelMatrix, modelMatrix, sizeof( guiSpace->modelMatrix ) ); - memcpy( guiSpace->modelViewMatrix, modelViewMatrix, sizeof( guiSpace->modelViewMatrix ) ); - guiSpace->weaponDepthHack = depthHack; - - // add the surface, which might recursively create another gui - R_AddDrawSurf( tri, guiSpace, &renderEntity, surf->material, tr.viewDef->scissor ); + srfTriangles_t *tri; + + if ( surf->numVerts == 0 ) { + return; // nothing in the surface + } + + // copy verts and indexes + tri = ( srfTriangles_t * )R_ClearedFrameAlloc( sizeof( *tri ) ); + + tri->numIndexes = surf->numIndexes; + tri->numVerts = surf->numVerts; + tri->indexes = ( glIndex_t * )R_FrameAlloc( tri->numIndexes * sizeof( tri->indexes[0] ) ); + memcpy( tri->indexes, &indexes[surf->firstIndex], tri->numIndexes * sizeof( tri->indexes[0] ) ); + + // we might be able to avoid copying these and just let them reference the list vars + // but some things, like deforms and recursive + // guis, need to access the verts in cpu space, not just through the vertex range + tri->verts = ( idDrawVert * )R_FrameAlloc( tri->numVerts * sizeof( tri->verts[0] ) ); + memcpy( tri->verts, &verts[surf->firstVert], tri->numVerts * sizeof( tri->verts[0] ) ); + + // move the verts to the vertex cache + tri->ambientCache = vertexCache.AllocFrameTemp( tri->verts, tri->numVerts * sizeof( tri->verts[0] ) ); + + // if we are out of vertex cache, don't create the surface + if ( !tri->ambientCache ) { + return; + } + renderEntity_t renderEntity; + memset( &renderEntity, 0, sizeof( renderEntity ) ); + memcpy( renderEntity.shaderParms, surf->color, sizeof( surf->color ) ); + + viewEntity_t *guiSpace = ( viewEntity_t * )R_ClearedFrameAlloc( sizeof( *guiSpace ) ); + memcpy( guiSpace->modelMatrix, modelMatrix, sizeof( guiSpace->modelMatrix ) ); + memcpy( guiSpace->modelViewMatrix, modelViewMatrix, sizeof( guiSpace->modelViewMatrix ) ); + guiSpace->weaponDepthHack = depthHack; + + // add the surface, which might recursively create another gui + R_AddDrawSurf( tri, guiSpace, &renderEntity, surf->material, tr.viewDef->scissor ); } /* @@ -207,20 +215,19 @@ EmitToCurrentView ==================== */ void idGuiModel::EmitToCurrentView( float modelMatrix[16], bool depthHack ) { - float modelViewMatrix[16]; - - const float* worldMVM = tr.viewDef->worldSpace.modelViewMatrix; - // DG: for r_lockSurfaces use the real world modelViewMatrix - // so GUIs don't float around - if(r_lockSurfaces.GetBool() && tr.viewDef == tr.primaryView) { - worldMVM = tr.lockSurfacesRealViewDef.worldSpace.modelViewMatrix; - } - - myGlMultMatrix( modelMatrix, worldMVM, modelViewMatrix ); - - for ( int i = 0 ; i < surfaces.Num() ; i++ ) { - EmitSurface( &surfaces[i], modelMatrix, modelViewMatrix, depthHack ); - } + float modelViewMatrix[16]; + const float *worldMVM = tr.viewDef->worldSpace.modelViewMatrix; + + // DG: for r_lockSurfaces use the real world modelViewMatrix + // so GUIs don't float around + if ( r_lockSurfaces.GetBool() && tr.viewDef == tr.primaryView ) { + worldMVM = tr.lockSurfacesRealViewDef.worldSpace.modelViewMatrix; + } + R_MatrixMultiply( modelMatrix, worldMVM, modelViewMatrix ); + + for ( int i = 0 ; i < surfaces.Num() ; i++ ) { + EmitSurface( &surfaces[i], modelMatrix, modelViewMatrix, depthHack ); + } } /* @@ -231,76 +238,73 @@ Creates a view that covers the screen and emit the surfaces ================ */ void idGuiModel::EmitFullScreen( void ) { - viewDef_t *viewDef; - - if ( surfaces[0].numVerts == 0 ) { - return; - } - - viewDef = (viewDef_t *)R_ClearedFrameAlloc( sizeof( *viewDef ) ); - - // for gui editor - if ( !tr.viewDef || !tr.viewDef->isEditor ) { - viewDef->renderView.x = 0; - viewDef->renderView.y = 0; - viewDef->renderView.width = SCREEN_WIDTH; - viewDef->renderView.height = SCREEN_HEIGHT; - - tr.RenderViewToViewport( &viewDef->renderView, &viewDef->viewport ); - - viewDef->scissor.x1 = 0; - viewDef->scissor.y1 = 0; - viewDef->scissor.x2 = viewDef->viewport.x2 - viewDef->viewport.x1; - viewDef->scissor.y2 = viewDef->viewport.y2 - viewDef->viewport.y1; - } else { - viewDef->renderView.x = tr.viewDef->renderView.x; - viewDef->renderView.y = tr.viewDef->renderView.y; - viewDef->renderView.width = tr.viewDef->renderView.width; - viewDef->renderView.height = tr.viewDef->renderView.height; - - viewDef->viewport.x1 = tr.viewDef->renderView.x; - viewDef->viewport.x2 = tr.viewDef->renderView.x + tr.viewDef->renderView.width; - viewDef->viewport.y1 = tr.viewDef->renderView.y; - viewDef->viewport.y2 = tr.viewDef->renderView.y + tr.viewDef->renderView.height; - - viewDef->scissor.x1 = tr.viewDef->scissor.x1; - viewDef->scissor.y1 = tr.viewDef->scissor.y1; - viewDef->scissor.x2 = tr.viewDef->scissor.x2; - viewDef->scissor.y2 = tr.viewDef->scissor.y2; - } - - viewDef->floatTime = tr.frameShaderTime; - - // qglOrtho( 0, 640, 480, 0, 0, 1 ); // always assume 640x480 virtual coordinates - viewDef->projectionMatrix[0] = 2.0f / 640.0f; - viewDef->projectionMatrix[5] = -2.0f / 480.0f; - viewDef->projectionMatrix[10] = -2.0f / 1.0f; - viewDef->projectionMatrix[12] = -1.0f; - viewDef->projectionMatrix[13] = 1.0f; - viewDef->projectionMatrix[14] = -1.0f; - viewDef->projectionMatrix[15] = 1.0f; - - viewDef->worldSpace.modelViewMatrix[0] = 1.0f; - viewDef->worldSpace.modelViewMatrix[5] = 1.0f; - viewDef->worldSpace.modelViewMatrix[10] = 1.0f; - viewDef->worldSpace.modelViewMatrix[15] = 1.0f; - - viewDef->maxDrawSurfs = surfaces.Num(); - viewDef->drawSurfs = (drawSurf_t **)R_FrameAlloc( viewDef->maxDrawSurfs * sizeof( viewDef->drawSurfs[0] ) ); - viewDef->numDrawSurfs = 0; - - viewDef_t *oldViewDef = tr.viewDef; - tr.viewDef = viewDef; - - // add the surfaces to this view - for ( int i = 0 ; i < surfaces.Num() ; i++ ) { - EmitSurface( &surfaces[i], viewDef->worldSpace.modelMatrix, viewDef->worldSpace.modelViewMatrix, false ); - } - - tr.viewDef = oldViewDef; - - // add the command to draw this view - R_AddDrawViewCmd( viewDef ); + viewDef_t *viewDef; + + if ( surfaces[0].numVerts == 0 ) { + return; + } + viewDef = ( viewDef_t * )R_ClearedFrameAlloc( sizeof( *viewDef ) ); + + // for gui editor + if ( !tr.viewDef || !tr.viewDef->isEditor ) { + viewDef->renderView.x = 0; + viewDef->renderView.y = 0; + viewDef->renderView.width = SCREEN_WIDTH; + viewDef->renderView.height = SCREEN_HEIGHT; + + tr.RenderViewToViewport( &viewDef->renderView, &viewDef->viewport ); + + viewDef->scissor.x1 = 0; + viewDef->scissor.y1 = 0; + viewDef->scissor.x2 = viewDef->viewport.x2 - viewDef->viewport.x1; + viewDef->scissor.y2 = viewDef->viewport.y2 - viewDef->viewport.y1; + } else { + viewDef->renderView.x = tr.viewDef->renderView.x; + viewDef->renderView.y = tr.viewDef->renderView.y; + viewDef->renderView.width = tr.viewDef->renderView.width; + viewDef->renderView.height = tr.viewDef->renderView.height; + + viewDef->viewport.x1 = tr.viewDef->renderView.x; + viewDef->viewport.x2 = tr.viewDef->renderView.x + tr.viewDef->renderView.width; + viewDef->viewport.y1 = tr.viewDef->renderView.y; + viewDef->viewport.y2 = tr.viewDef->renderView.y + tr.viewDef->renderView.height; + + viewDef->scissor.x1 = tr.viewDef->scissor.x1; + viewDef->scissor.y1 = tr.viewDef->scissor.y1; + viewDef->scissor.x2 = tr.viewDef->scissor.x2; + viewDef->scissor.y2 = tr.viewDef->scissor.y2; + } + viewDef->floatTime = tr.frameShaderTime; + + // qglOrtho( 0, 640, 480, 0, 0, 1 ); // always assume 640x480 virtual coordinates + viewDef->projectionMatrix[0] = 2.0f / 640.0f; + viewDef->projectionMatrix[5] = -2.0f / 480.0f; + viewDef->projectionMatrix[10] = -2.0f / 1.0f; + viewDef->projectionMatrix[12] = -1.0f; + viewDef->projectionMatrix[13] = 1.0f; + viewDef->projectionMatrix[14] = -1.0f; + viewDef->projectionMatrix[15] = 1.0f; + + viewDef->worldSpace.modelViewMatrix[0] = 1.0f; + viewDef->worldSpace.modelViewMatrix[5] = 1.0f; + viewDef->worldSpace.modelViewMatrix[10] = 1.0f; + viewDef->worldSpace.modelViewMatrix[15] = 1.0f; + + viewDef->maxDrawSurfs = surfaces.Num(); + viewDef->drawSurfs = ( drawSurf_t ** )R_FrameAlloc( viewDef->maxDrawSurfs * sizeof( viewDef->drawSurfs[0] ) ); + viewDef->numDrawSurfs = 0; + + viewDef_t *oldViewDef = tr.viewDef; + tr.viewDef = viewDef; + + // add the surfaces to this view + for ( int i = 0 ; i < surfaces.Num() ; i++ ) { + EmitSurface( &surfaces[i], viewDef->worldSpace.modelMatrix, viewDef->worldSpace.modelViewMatrix, false ); + } + tr.viewDef = oldViewDef; + + // add the command to draw this view + R_AddDrawViewCmd( viewDef ); } /* @@ -309,28 +313,28 @@ AdvanceSurf ============= */ void idGuiModel::AdvanceSurf() { - guiModelSurface_t s; - - if ( surfaces.Num() ) { - s.color[0] = surf->color[0]; - s.color[1] = surf->color[1]; - s.color[2] = surf->color[2]; - s.color[3] = surf->color[3]; - s.material = surf->material; - } else { - s.color[0] = 1; - s.color[1] = 1; - s.color[2] = 1; - s.color[3] = 1; - s.material = tr.defaultMaterial; - } - s.numIndexes = 0; - s.firstIndex = indexes.Num(); - s.numVerts = 0; - s.firstVert = verts.Num(); - - surfaces.Append( s ); - surf = &surfaces[ surfaces.Num() - 1 ]; + guiModelSurface_t s; + + if ( surfaces.Num() ) { + s.color[0] = surf->color[0]; + s.color[1] = surf->color[1]; + s.color[2] = surf->color[2]; + s.color[3] = surf->color[3]; + s.material = surf->material; + } else { + s.color[0] = 1; + s.color[1] = 1; + s.color[2] = 1; + s.color[3] = 1; + s.material = tr.defaultMaterial; + } + s.numIndexes = 0; + s.firstIndex = indexes.Num(); + s.numVerts = 0; + s.firstVert = verts.Num(); + + surfaces.Append( s ); + surf = &surfaces[ surfaces.Num() - 1 ]; } /* @@ -339,23 +343,24 @@ SetColor ============= */ void idGuiModel::SetColor( float r, float g, float b, float a ) { - if ( !glConfig.isInitialized ) { - return; - } - if ( r == surf->color[0] && g == surf->color[1] - && b == surf->color[2] && a == surf->color[3] ) { - return; // no change - } - - if ( surf->numVerts ) { - AdvanceSurf(); - } - - // change the parms - surf->color[0] = r; - surf->color[1] = g; - surf->color[2] = b; - surf->color[3] = a; + if ( !glConfig.isInitialized ) { + return; + } + + if ( r == surf->color[0] && g == surf->color[1] && + b == surf->color[2] && a == surf->color[3] ) { + return; // no change + } + + if ( surf->numVerts ) { + AdvanceSurf(); + } + + // change the parms + surf->color[0] = r; + surf->color[1] = g; + surf->color[2] = b; + surf->color[3] = a; } /* @@ -364,96 +369,103 @@ DrawStretchPic ============= */ void idGuiModel::DrawStretchPic( const idDrawVert *dverts, const glIndex_t *dindexes, int vertCount, int indexCount, const idMaterial *hShader, - bool clip, float min_x, float min_y, float max_x, float max_y ) { - if ( !glConfig.isInitialized ) { - return; - } - if ( !( dverts && dindexes && vertCount && indexCount && hShader ) ) { - return; - } - - // break the current surface if we are changing to a new material - if ( hShader != surf->material ) { - if ( surf->numVerts ) { - AdvanceSurf(); - } - const_cast(hShader)->EnsureNotPurged(); // in case it was a gui item started before a level change - surf->material = hShader; - } - - // add the verts and indexes to the current surface - - if ( clip ) { - int i, j; - - // FIXME: this is grim stuff, and should be rewritten if we have any significant - // number of guis asking for clipping - idFixedWinding w; - for ( i = 0; i < indexCount; i += 3 ) { - w.Clear(); - w.AddPoint(idVec5(dverts[dindexes[i]].xyz.x, dverts[dindexes[i]].xyz.y, dverts[dindexes[i]].xyz.z, dverts[dindexes[i]].st.x, dverts[dindexes[i]].st.y)); - w.AddPoint(idVec5(dverts[dindexes[i+1]].xyz.x, dverts[dindexes[i+1]].xyz.y, dverts[dindexes[i+1]].xyz.z, dverts[dindexes[i+1]].st.x, dverts[dindexes[i+1]].st.y)); - w.AddPoint(idVec5(dverts[dindexes[i+2]].xyz.x, dverts[dindexes[i+2]].xyz.y, dverts[dindexes[i+2]].xyz.z, dverts[dindexes[i+2]].st.x, dverts[dindexes[i+2]].st.y)); - - for ( j = 0; j < 3; j++ ) { - if ( w[j].x < min_x || w[j].x > max_x || - w[j].y < min_y || w[j].y > max_y ) { - break; - } - } - if ( j < 3 ) { - idPlane p; - p.Normal().y = p.Normal().z = 0.0f; p.Normal().x = 1.0f; p.SetDist( min_x ); - w.ClipInPlace( p ); - p.Normal().y = p.Normal().z = 0.0f; p.Normal().x = -1.0f; p.SetDist( -max_x ); - w.ClipInPlace( p ); - p.Normal().x = p.Normal().z = 0.0f; p.Normal().y = 1.0f; p.SetDist( min_y ); - w.ClipInPlace( p ); - p.Normal().x = p.Normal().z = 0.0f; p.Normal().y = -1.0f; p.SetDist( -max_y ); - w.ClipInPlace( p ); - } - - int numVerts = verts.Num(); - verts.SetNum( numVerts + w.GetNumPoints(), false ); - for ( j = 0 ; j < w.GetNumPoints() ; j++ ) { - idDrawVert *dv = &verts[numVerts+j]; - - dv->xyz.x = w[j].x; - dv->xyz.y = w[j].y; - dv->xyz.z = w[j].z; - dv->st.x = w[j].s; - dv->st.y = w[j].t; - dv->normal.Set(0, 0, 1); - dv->tangents[0].Set(1, 0, 0); - dv->tangents[1].Set(0, 1, 0); - } - surf->numVerts += w.GetNumPoints(); - - for ( j = 2; j < w.GetNumPoints(); j++ ) { - indexes.Append( numVerts - surf->firstVert ); - indexes.Append( numVerts + j - 1 - surf->firstVert ); - indexes.Append( numVerts + j - surf->firstVert ); - surf->numIndexes += 3; - } - } - - } else { - - int numVerts = verts.Num(); - int numIndexes = indexes.Num(); - - verts.AssureSize( numVerts + vertCount ); - indexes.AssureSize( numIndexes + indexCount ); - - surf->numVerts += vertCount; - surf->numIndexes += indexCount; - - for ( int i = 0; i < indexCount; i++ ) { - indexes[numIndexes + i] = numVerts + dindexes[i] - surf->firstVert; - } - - memcpy( &verts[numVerts], dverts, vertCount * sizeof( verts[0] ) ); - } + bool clip, float min_x, float min_y, float max_x, float max_y ) { + if ( !glConfig.isInitialized ) { + return; + } + + if ( !( dverts && dindexes && vertCount && indexCount && hShader ) ) { + return; + } + + // break the current surface if we are changing to a new material + if ( hShader != surf->material ) { + if ( surf->numVerts ) { + AdvanceSurf(); + } + const_cast( hShader )->EnsureNotPurged(); // in case it was a gui item started before a level change + surf->material = hShader; + } + + // add the verts and indexes to the current surface + if ( clip ) { + int i, j; + + // FIXME: this is grim stuff, and should be rewritten if we have any significant + // number of guis asking for clipping + idFixedWinding w; + for ( i = 0; i < indexCount; i += 3 ) { + w.Clear(); + w.AddPoint( idVec5( dverts[dindexes[i]].xyz.x, dverts[dindexes[i]].xyz.y, dverts[dindexes[i]].xyz.z, dverts[dindexes[i]].st.x, dverts[dindexes[i]].st.y ) ); + w.AddPoint( idVec5( dverts[dindexes[i + 1]].xyz.x, dverts[dindexes[i + 1]].xyz.y, dverts[dindexes[i + 1]].xyz.z, dverts[dindexes[i + 1]].st.x, dverts[dindexes[i + 1]].st.y ) ); + w.AddPoint( idVec5( dverts[dindexes[i + 2]].xyz.x, dverts[dindexes[i + 2]].xyz.y, dverts[dindexes[i + 2]].xyz.z, dverts[dindexes[i + 2]].st.x, dverts[dindexes[i + 2]].st.y ) ); + + for ( j = 0; j < 3; j++ ) { + if ( w[j].x < min_x || w[j].x > max_x || + w[j].y < min_y || w[j].y > max_y ) { + break; + } + } + + if ( j < 3 ) { + idPlane p; + p.Normal().y = p.Normal().z = 0.0f; + p.Normal().x = 1.0f; + p.SetDist( min_x ); + w.ClipInPlace( p ); + p.Normal().y = p.Normal().z = 0.0f; + p.Normal().x = -1.0f; + p.SetDist( -max_x ); + w.ClipInPlace( p ); + p.Normal().x = p.Normal().z = 0.0f; + p.Normal().y = 1.0f; + p.SetDist( min_y ); + w.ClipInPlace( p ); + p.Normal().x = p.Normal().z = 0.0f; + p.Normal().y = -1.0f; + p.SetDist( -max_y ); + w.ClipInPlace( p ); + } + int numVerts = verts.Num(); + + verts.SetNum( numVerts + w.GetNumPoints(), false ); + + for ( j = 0 ; j < w.GetNumPoints() ; j++ ) { + idDrawVert *dv = &verts[numVerts + j]; + + dv->xyz.x = w[j].x; + dv->xyz.y = w[j].y; + dv->xyz.z = w[j].z; + dv->st.x = w[j].s; + dv->st.y = w[j].t; + dv->normal.Set( 0, 0, 1 ); + dv->tangents[0].Set( 1, 0, 0 ); + dv->tangents[1].Set( 0, 1, 0 ); + } + surf->numVerts += w.GetNumPoints(); + + for ( j = 2; j < w.GetNumPoints(); j++ ) { + indexes.Append( numVerts - surf->firstVert ); + indexes.Append( numVerts + j - 1 - surf->firstVert ); + indexes.Append( numVerts + j - surf->firstVert ); + surf->numIndexes += 3; + } + } + } else { + int numVerts = verts.Num(); + int numIndexes = indexes.Num(); + + verts.AssureSize( numVerts + vertCount ); + indexes.AssureSize( numIndexes + indexCount ); + + surf->numVerts += vertCount; + surf->numIndexes += indexCount; + + for ( int i = 0; i < indexCount; i++ ) { + indexes[numIndexes + i] = numVerts + dindexes[i] - surf->firstVert; + } + memcpy( &verts[numVerts], dverts, vertCount * sizeof( verts[0] ) ); + } } /* @@ -464,105 +476,109 @@ x/y/w/h are in the 0,0 to 640,480 range ============= */ void idGuiModel::DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial *hShader ) { - idDrawVert verts[4]; - glIndex_t indexes[6]; - - if ( !glConfig.isInitialized ) { - return; - } - if ( !hShader ) { - return; - } - - // clip to edges, because the pic may be going into a guiShader - // instead of full screen - if ( x < 0 ) { - s1 += ( s2 - s1 ) * -x / w; - w += x; - x = 0; - } - if ( y < 0 ) { - t1 += ( t2 - t1 ) * -y / h; - h += y; - y = 0; - } - if ( x + w > 640 ) { - s2 -= ( s2 - s1 ) * ( x + w - 640 ) / w; - w = 640 - x; - } - if ( y + h > 480 ) { - t2 -= ( t2 - t1 ) * ( y + h - 480 ) / h; - h = 480 - y; - } - - if ( w <= 0 || h <= 0 ) { - return; // completely clipped away - } - - indexes[0] = 3; - indexes[1] = 0; - indexes[2] = 2; - indexes[3] = 2; - indexes[4] = 0; - indexes[5] = 1; - verts[0].xyz[0] = x; - verts[0].xyz[1] = y; - verts[0].xyz[2] = 0; - verts[0].st[0] = s1; - verts[0].st[1] = t1; - verts[0].normal[0] = 0; - verts[0].normal[1] = 0; - verts[0].normal[2] = 1; - verts[0].tangents[0][0] = 1; - verts[0].tangents[0][1] = 0; - verts[0].tangents[0][2] = 0; - verts[0].tangents[1][0] = 0; - verts[0].tangents[1][1] = 1; - verts[0].tangents[1][2] = 0; - verts[1].xyz[0] = x + w; - verts[1].xyz[1] = y; - verts[1].xyz[2] = 0; - verts[1].st[0] = s2; - verts[1].st[1] = t1; - verts[1].normal[0] = 0; - verts[1].normal[1] = 0; - verts[1].normal[2] = 1; - verts[1].tangents[0][0] = 1; - verts[1].tangents[0][1] = 0; - verts[1].tangents[0][2] = 0; - verts[1].tangents[1][0] = 0; - verts[1].tangents[1][1] = 1; - verts[1].tangents[1][2] = 0; - verts[2].xyz[0] = x + w; - verts[2].xyz[1] = y + h; - verts[2].xyz[2] = 0; - verts[2].st[0] = s2; - verts[2].st[1] = t2; - verts[2].normal[0] = 0; - verts[2].normal[1] = 0; - verts[2].normal[2] = 1; - verts[2].tangents[0][0] = 1; - verts[2].tangents[0][1] = 0; - verts[2].tangents[0][2] = 0; - verts[2].tangents[1][0] = 0; - verts[2].tangents[1][1] = 1; - verts[2].tangents[1][2] = 0; - verts[3].xyz[0] = x; - verts[3].xyz[1] = y + h; - verts[3].xyz[2] = 0; - verts[3].st[0] = s1; - verts[3].st[1] = t2; - verts[3].normal[0] = 0; - verts[3].normal[1] = 0; - verts[3].normal[2] = 1; - verts[3].tangents[0][0] = 1; - verts[3].tangents[0][1] = 0; - verts[3].tangents[0][2] = 0; - verts[3].tangents[1][0] = 0; - verts[3].tangents[1][1] = 1; - verts[3].tangents[1][2] = 0; - - DrawStretchPic( &verts[0], &indexes[0], 4, 6, hShader, false, 0.0f, 0.0f, 640.0f, 480.0f ); + idDrawVert verts[4]; + glIndex_t indexes[6]; + + if ( !glConfig.isInitialized ) { + return; + } + + if ( !hShader ) { + return; + } + + // clip to edges, because the pic may be going into a guiShader + // instead of full screen + if ( x < 0 ) { + s1 += ( s2 - s1 ) * -x / w; + w += x; + x = 0; + } + + if ( y < 0 ) { + t1 += ( t2 - t1 ) * -y / h; + h += y; + y = 0; + } + + if ( x + w > 640 ) { + s2 -= ( s2 - s1 ) * ( x + w - 640 ) / w; + w = 640 - x; + } + + if ( y + h > 480 ) { + t2 -= ( t2 - t1 ) * ( y + h - 480 ) / h; + h = 480 - y; + } + + if ( w <= 0 || h <= 0 ) { + return; // completely clipped away + } + indexes[0] = 3; + indexes[1] = 0; + indexes[2] = 2; + indexes[3] = 2; + indexes[4] = 0; + indexes[5] = 1; + + verts[0].xyz[0] = x; + verts[0].xyz[1] = y; + verts[0].xyz[2] = 0; + verts[0].st[0] = s1; + verts[0].st[1] = t1; + verts[0].normal[0] = 0; + verts[0].normal[1] = 0; + verts[0].normal[2] = 1; + verts[0].tangents[0][0] = 1; + verts[0].tangents[0][1] = 0; + verts[0].tangents[0][2] = 0; + verts[0].tangents[1][0] = 0; + verts[0].tangents[1][1] = 1; + verts[0].tangents[1][2] = 0; + verts[1].xyz[0] = x + w; + verts[1].xyz[1] = y; + verts[1].xyz[2] = 0; + verts[1].st[0] = s2; + verts[1].st[1] = t1; + verts[1].normal[0] = 0; + verts[1].normal[1] = 0; + verts[1].normal[2] = 1; + verts[1].tangents[0][0] = 1; + verts[1].tangents[0][1] = 0; + verts[1].tangents[0][2] = 0; + verts[1].tangents[1][0] = 0; + verts[1].tangents[1][1] = 1; + verts[1].tangents[1][2] = 0; + verts[2].xyz[0] = x + w; + verts[2].xyz[1] = y + h; + verts[2].xyz[2] = 0; + verts[2].st[0] = s2; + verts[2].st[1] = t2; + verts[2].normal[0] = 0; + verts[2].normal[1] = 0; + verts[2].normal[2] = 1; + verts[2].tangents[0][0] = 1; + verts[2].tangents[0][1] = 0; + verts[2].tangents[0][2] = 0; + verts[2].tangents[1][0] = 0; + verts[2].tangents[1][1] = 1; + verts[2].tangents[1][2] = 0; + verts[3].xyz[0] = x; + verts[3].xyz[1] = y + h; + verts[3].xyz[2] = 0; + verts[3].st[0] = s1; + verts[3].st[1] = t2; + verts[3].normal[0] = 0; + verts[3].normal[1] = 0; + verts[3].normal[2] = 1; + verts[3].tangents[0][0] = 1; + verts[3].tangents[0][1] = 0; + verts[3].tangents[0][2] = 0; + verts[3].tangents[1][0] = 0; + verts[3].tangents[1][1] = 1; + verts[3].tangents[1][2] = 0; + + DrawStretchPic( &verts[0], &indexes[0], 4, 6, hShader, false, 0.0f, 0.0f, 640.0f, 480.0f ); } /* @@ -573,86 +589,84 @@ x/y/w/h are in the 0,0 to 640,480 range ============= */ void idGuiModel::DrawStretchTri( idVec2 p1, idVec2 p2, idVec2 p3, idVec2 t1, idVec2 t2, idVec2 t3, const idMaterial *material ) { - idDrawVert tempVerts[3]; - glIndex_t tempIndexes[3]; - int vertCount = 3; - int indexCount = 3; - - if ( !glConfig.isInitialized ) { - return; - } - if ( !material ) { - return; - } - - tempIndexes[0] = 1; - tempIndexes[1] = 0; - tempIndexes[2] = 2; - tempVerts[0].xyz[0] = p1.x; - tempVerts[0].xyz[1] = p1.y; - tempVerts[0].xyz[2] = 0; - tempVerts[0].st[0] = t1.x; - tempVerts[0].st[1] = t1.y; - tempVerts[0].normal[0] = 0; - tempVerts[0].normal[1] = 0; - tempVerts[0].normal[2] = 1; - tempVerts[0].tangents[0][0] = 1; - tempVerts[0].tangents[0][1] = 0; - tempVerts[0].tangents[0][2] = 0; - tempVerts[0].tangents[1][0] = 0; - tempVerts[0].tangents[1][1] = 1; - tempVerts[0].tangents[1][2] = 0; - tempVerts[1].xyz[0] = p2.x; - tempVerts[1].xyz[1] = p2.y; - tempVerts[1].xyz[2] = 0; - tempVerts[1].st[0] = t2.x; - tempVerts[1].st[1] = t2.y; - tempVerts[1].normal[0] = 0; - tempVerts[1].normal[1] = 0; - tempVerts[1].normal[2] = 1; - tempVerts[1].tangents[0][0] = 1; - tempVerts[1].tangents[0][1] = 0; - tempVerts[1].tangents[0][2] = 0; - tempVerts[1].tangents[1][0] = 0; - tempVerts[1].tangents[1][1] = 1; - tempVerts[1].tangents[1][2] = 0; - tempVerts[2].xyz[0] = p3.x; - tempVerts[2].xyz[1] = p3.y; - tempVerts[2].xyz[2] = 0; - tempVerts[2].st[0] = t3.x; - tempVerts[2].st[1] = t3.y; - tempVerts[2].normal[0] = 0; - tempVerts[2].normal[1] = 0; - tempVerts[2].normal[2] = 1; - tempVerts[2].tangents[0][0] = 1; - tempVerts[2].tangents[0][1] = 0; - tempVerts[2].tangents[0][2] = 0; - tempVerts[2].tangents[1][0] = 0; - tempVerts[2].tangents[1][1] = 1; - tempVerts[2].tangents[1][2] = 0; - - // break the current surface if we are changing to a new material - if ( material != surf->material ) { - if ( surf->numVerts ) { - AdvanceSurf(); - } - const_cast(material)->EnsureNotPurged(); // in case it was a gui item started before a level change - surf->material = material; - } - - - int numVerts = verts.Num(); - int numIndexes = indexes.Num(); - - verts.AssureSize( numVerts + vertCount ); - indexes.AssureSize( numIndexes + indexCount ); - - surf->numVerts += vertCount; - surf->numIndexes += indexCount; - - for ( int i = 0; i < indexCount; i++ ) { - indexes[numIndexes + i] = numVerts + tempIndexes[i] - surf->firstVert; - } - - memcpy( &verts[numVerts], tempVerts, vertCount * sizeof( verts[0] ) ); + idDrawVert tempVerts[3]; + glIndex_t tempIndexes[3]; + int vertCount = 3; + int indexCount = 3; + + if ( !glConfig.isInitialized ) { + return; + } + + if ( !material ) { + return; + } + tempIndexes[0] = 1; + tempIndexes[1] = 0; + tempIndexes[2] = 2; + + tempVerts[0].xyz[0] = p1.x; + tempVerts[0].xyz[1] = p1.y; + tempVerts[0].xyz[2] = 0; + tempVerts[0].st[0] = t1.x; + tempVerts[0].st[1] = t1.y; + tempVerts[0].normal[0] = 0; + tempVerts[0].normal[1] = 0; + tempVerts[0].normal[2] = 1; + tempVerts[0].tangents[0][0] = 1; + tempVerts[0].tangents[0][1] = 0; + tempVerts[0].tangents[0][2] = 0; + tempVerts[0].tangents[1][0] = 0; + tempVerts[0].tangents[1][1] = 1; + tempVerts[0].tangents[1][2] = 0; + tempVerts[1].xyz[0] = p2.x; + tempVerts[1].xyz[1] = p2.y; + tempVerts[1].xyz[2] = 0; + tempVerts[1].st[0] = t2.x; + tempVerts[1].st[1] = t2.y; + tempVerts[1].normal[0] = 0; + tempVerts[1].normal[1] = 0; + tempVerts[1].normal[2] = 1; + tempVerts[1].tangents[0][0] = 1; + tempVerts[1].tangents[0][1] = 0; + tempVerts[1].tangents[0][2] = 0; + tempVerts[1].tangents[1][0] = 0; + tempVerts[1].tangents[1][1] = 1; + tempVerts[1].tangents[1][2] = 0; + tempVerts[2].xyz[0] = p3.x; + tempVerts[2].xyz[1] = p3.y; + tempVerts[2].xyz[2] = 0; + tempVerts[2].st[0] = t3.x; + tempVerts[2].st[1] = t3.y; + tempVerts[2].normal[0] = 0; + tempVerts[2].normal[1] = 0; + tempVerts[2].normal[2] = 1; + tempVerts[2].tangents[0][0] = 1; + tempVerts[2].tangents[0][1] = 0; + tempVerts[2].tangents[0][2] = 0; + tempVerts[2].tangents[1][0] = 0; + tempVerts[2].tangents[1][1] = 1; + tempVerts[2].tangents[1][2] = 0; + + // break the current surface if we are changing to a new material + if ( material != surf->material ) { + if ( surf->numVerts ) { + AdvanceSurf(); + } + const_cast( material )->EnsureNotPurged(); // in case it was a gui item started before a level change + surf->material = material; + } + int numVerts = verts.Num(); + int numIndexes = indexes.Num(); + + verts.AssureSize( numVerts + vertCount ); + indexes.AssureSize( numIndexes + indexCount ); + + surf->numVerts += vertCount; + surf->numIndexes += indexCount; + + for ( int i = 0; i < indexCount; i++ ) { + indexes[numIndexes + i] = numVerts + tempIndexes[i] - surf->firstVert; + } + memcpy( &verts[numVerts], tempVerts, vertCount * sizeof( verts[0] ) ); } diff --git a/neo/renderer/Image.h b/neo/renderer/Image.h index 34515a378..9b366a783 100644 --- a/neo/renderer/Image.h +++ b/neo/renderer/Image.h @@ -125,7 +125,6 @@ typedef struct unsigned int dwReserved2[3]; } ddsFileHeader_t; - // increasing numeric values imply more information is stored typedef enum { TD_SPECULAR, // may be compressed, and always zeros the alpha channel diff --git a/neo/renderer/Image_files.cpp b/neo/renderer/Image_files.cpp index 174d544d6..1d03bffe5 100644 --- a/neo/renderer/Image_files.cpp +++ b/neo/renderer/Image_files.cpp @@ -31,12 +31,10 @@ If you have questions concerning this license or the applicable additional terms #define STBI_NO_LINEAR #define STBI_ONLY_JPEG // at least for now, only use it for JPEG #define STBI_NO_STDIO // images are passed as buffers -#include "stb_image.h" +#include "stb_image.h" #include "sys/platform.h" - #include "renderer/tr_local.h" - #include "renderer/Image.h" /* @@ -55,35 +53,34 @@ R_WriteTGA void R_WriteTGA( const char *filename, const byte *data, int width, int height, bool flipVertical ) { byte *buffer; int i; - int bufferSize = width*height*4 + 18; + int bufferSize = width * height * 4 + 18; int imgStart = 18; - buffer = (byte *)Mem_Alloc( bufferSize ); + buffer = ( byte * )Mem_Alloc( bufferSize ); memset( buffer, 0, 18 ); buffer[2] = 2; // uncompressed type - buffer[12] = width&255; - buffer[13] = width>>8; - buffer[14] = height&255; - buffer[15] = height>>8; + buffer[12] = width & 255; + buffer[13] = width >> 8; + buffer[14] = height & 255; + buffer[15] = height >> 8; buffer[16] = 32; // pixel size + if ( !flipVertical ) { - buffer[17] = (1<<5); // flip bit, for normal top to bottom raster order + buffer[17] = ( 1 << 5 ); // flip bit, for normal top to bottom raster order } // swap rgb to bgr - for ( i=imgStart ; iWriteFile( filename, buffer, bufferSize ); - Mem_Free (buffer); + Mem_Free( buffer ); } - /* ================ R_WritePalTGA @@ -92,48 +89,46 @@ R_WritePalTGA void R_WritePalTGA( const char *filename, const byte *data, const byte *palette, int width, int height, bool flipVertical ) { byte *buffer; int i; - int bufferSize = (width * height) + (256 * 3) + 18; + int bufferSize = ( width * height ) + ( 256 * 3 ) + 18; int palStart = 18; - int imgStart = 18 + (256 * 3); + int imgStart = 18 + ( 256 * 3 ); - buffer = (byte *)Mem_Alloc( bufferSize ); + buffer = ( byte * )Mem_Alloc( bufferSize ); memset( buffer, 0, 18 ); buffer[1] = 1; // color map type buffer[2] = 1; // uncompressed color mapped image buffer[5] = 0; // number of palette entries (lo) buffer[6] = 1; // number of palette entries (hi) buffer[7] = 24; // color map bpp - buffer[12] = width&255; - buffer[13] = width>>8; - buffer[14] = height&255; - buffer[15] = height>>8; + buffer[12] = width & 255; + buffer[13] = width >> 8; + buffer[14] = height & 255; + buffer[15] = height >> 8; buffer[16] = 8; // pixel size + if ( !flipVertical ) { - buffer[17] = (1<<5); // flip bit, for normal top to bottom raster order + buffer[17] = ( 1 << 5 ); // flip bit, for normal top to bottom raster order } // store palette, swapping rgb to bgr - for ( i=palStart ; iWriteFile( filename, buffer, bufferSize ); - Mem_Free (buffer); + Mem_Free( buffer ); } - -static void LoadBMP( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp ); -static void LoadTGA( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp ); -static void LoadJPG( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp ); - +static void LoadBMP( const char *filename, byte **pic, int *width, int *height, ID_TIME_T *timestamp ); +static void LoadTGA( const char *filename, byte **pic, int *width, int *height, ID_TIME_T *timestamp ); +static void LoadJPG( const char *filename, byte **pic, int *width, int *height, ID_TIME_T *timestamp ); /* ======================================================================== @@ -148,8 +143,8 @@ typedef struct { char version; char encoding; char bits_per_pixel; - unsigned short xmin,ymin,xmax,ymax; - unsigned short hres,vres; + unsigned short xmin, ymin, xmax, ymax; + unsigned short hres, vres; unsigned char palette[48]; char reserved; char color_planes; @@ -159,7 +154,6 @@ typedef struct { unsigned char data; // unbounded } pcx_t; - /* ======================================================================== @@ -168,16 +162,36 @@ TGA files are used for 24/32 bit images ======================================================================== */ -typedef struct _TargaHeader { - unsigned char id_length, colormap_type, image_type; - unsigned short colormap_index, colormap_length; - unsigned char colormap_size; - unsigned short x_origin, y_origin, width, height; - unsigned char pixel_size, attributes; +#define TGA_MAXCOLORS 16384 + +/* Definitions for image types. */ +#define TGA_Null 0 /* no image data */ +#define TGA_Map 1 /* Uncompressed, color-mapped images. */ +#define TGA_RGB 2 /* Uncompressed, RGB images. */ +#define TGA_Mono 3 /* Uncompressed, black and white images. */ +#define TGA_RLEMap 9 /* Runlength encoded color-mapped images. */ +#define TGA_RLERGB 10 /* Runlength encoded RGB images. */ +#define TGA_RLEMono 11 /* Compressed, black and white images. */ +#define TGA_CompMap 32 /* Compressed color-mapped data, using Huffman, Delta, and runlength encoding. */ +#define TGA_CompMap4 33 /* Compressed color-mapped data, using Huffman, Delta, and runlength encoding. 4-pass quadtree-type process. */ + +/* Definitions for interleave flag. */ +#define TGA_IL_None 0 /* non-interleaved. */ +#define TGA_IL_Two 1 /* two-way (even/odd) interleaving */ +#define TGA_IL_Four 2 /* four way interleaving */ +#define TGA_IL_Reserved 3 /* reserved */ + +/* Definitions for origin flag */ +#define TGA_O_UPPER 0 /* Origin in lower left-hand corner. */ +#define TGA_O_LOWER 1 /* Origin in upper left-hand corner. */ + +typedef struct _TargaHeader { + unsigned char id_length, colormap_type, colormap_size, image_type; + unsigned char pixel_size, attributes; + unsigned short colormap_index, colormap_length; + unsigned short x_origin, y_origin, width, height; } TargaHeader; - - /* ========================================================= @@ -185,8 +199,7 @@ BMP LOADING ========================================================= */ -typedef struct -{ +typedef struct { char id[2]; unsigned int fileSize; unsigned int reserved0; @@ -210,32 +223,30 @@ typedef struct LoadBMP ============== */ -static void LoadBMP( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp ) -{ - int columns, rows, numPixels; - byte *pixbuf; - int row, column; - byte *buf_p; - byte *buffer; - int length; +static void LoadBMP( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp ) { + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + byte *buf_p; + byte *buffer; + int length; BMPHeader_t bmpHeader; byte *bmpRGBA; if ( !pic ) { - fileSystem->ReadFile ( name, NULL, timestamp ); + fileSystem->ReadFile( name, NULL, timestamp ); return; // just getting timestamp } - *pic = NULL; // // load the file // - length = fileSystem->ReadFile( name, (void **)&buffer, timestamp ); + length = fileSystem->ReadFile( name, ( void ** )&buffer, timestamp ); + if ( !buffer ) { return; } - buf_p = buffer; bmpHeader.id[0] = *buf_p++; @@ -271,53 +282,56 @@ static void LoadBMP( const char *name, byte **pic, int *width, int *height, ID_T memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) ); - if ( bmpHeader.bitsPerPixel == 8 ) + if ( bmpHeader.bitsPerPixel == 8 ) { buf_p += 1024; - - if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) - { - common->Error( "LoadBMP: only Windows-style BMP files supported (%s)\n", name ); } - if ( bmpHeader.fileSize != length ) - { - common->Error( "LoadBMP: header size does not match file size (%u vs. %d) (%s)\n", bmpHeader.fileSize, length, name ); + + if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) { + common->Printf( "LoadBMP: only Windows-style BMP files supported (%s)\n", name ); + return; } - if ( bmpHeader.compression != 0 ) - { - common->Error( "LoadBMP: only uncompressed BMP files supported (%s)\n", name ); + + if ( bmpHeader.fileSize != length ) { + common->Printf( "LoadBMP: header size does not match file size (%u vs. %d) (%s)\n", bmpHeader.fileSize, length, name ); + return; } - if ( bmpHeader.bitsPerPixel < 8 ) - { - common->Error( "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name ); + + if ( bmpHeader.compression != 0 ) { + common->Printf( "LoadBMP: only uncompressed BMP files supported (%s)\n", name ); + return; } + if ( bmpHeader.bitsPerPixel < 8 ) { + common->Printf( "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name ); + return; + } columns = bmpHeader.width; rows = bmpHeader.height; - if ( rows < 0 ) + + if ( rows < 0 ) { rows = -rows; + } numPixels = columns * rows; - if ( width ) + if ( width ) { *width = columns; - if ( height ) - *height = rows; + } - bmpRGBA = (byte *)R_StaticAlloc( numPixels * 4 ); + if ( height ) { + *height = rows; + } + bmpRGBA = ( byte * )R_StaticAlloc( numPixels * 4 ); *pic = bmpRGBA; + for ( row = rows - 1; row >= 0; row-- ) { + pixbuf = bmpRGBA + row * columns * 4; - for ( row = rows-1; row >= 0; row-- ) - { - pixbuf = bmpRGBA + row*columns*4; - - for ( column = 0; column < columns; column++ ) - { + for ( column = 0; column < columns; column++ ) { unsigned char red, green, blue, alpha; int palIndex; unsigned short shortPixel; - switch ( bmpHeader.bitsPerPixel ) - { + switch ( bmpHeader.bitsPerPixel ) { case 8: palIndex = *buf_p++; *pixbuf++ = bmpHeader.palette[palIndex][2]; @@ -359,12 +373,9 @@ static void LoadBMP( const char *name, byte **pic, int *width, int *height, ID_T } } } - fileSystem->FreeFile( buffer ); - } - /* ================================================================= @@ -373,14 +384,12 @@ PCX LOADING ================================================================= */ - /* ============== LoadPCX ============== */ -static void LoadPCX ( const char *filename, byte **pic, byte **palette, int *width, int *height, - ID_TIME_T *timestamp ) { +static void LoadPCX( const char *filename, byte **pic, byte **palette, int *width, int *height, ID_TIME_T *timestamp ) { byte *raw; pcx_t *pcx; int x, y; @@ -393,93 +402,85 @@ static void LoadPCX ( const char *filename, byte **pic, byte **palette, int *wid fileSystem->ReadFile( filename, NULL, timestamp ); return; // just getting timestamp } - *pic = NULL; *palette = NULL; // // load the file // - len = fileSystem->ReadFile( filename, (void **)&raw, timestamp ); - if (!raw) { + len = fileSystem->ReadFile( filename, ( void ** )&raw, timestamp ); + + if ( !raw ) { return; } // // parse the PCX file // - pcx = (pcx_t *)raw; + pcx = ( pcx_t * )raw; raw = &pcx->data; - xmax = LittleShort(pcx->xmax); - ymax = LittleShort(pcx->ymax); - - if (pcx->manufacturer != 0x0a - || pcx->version != 5 - || pcx->encoding != 1 - || pcx->bits_per_pixel != 8 - || xmax >= 1024 - || ymax >= 1024) - { - common->Printf( "Bad pcx file %s (%i x %i) (%i x %i)\n", filename, xmax+1, ymax+1, pcx->xmax, pcx->ymax); + xmax = LittleShort( pcx->xmax ); + ymax = LittleShort( pcx->ymax ); + + if ( pcx->manufacturer != 0x0a || + pcx->version != 5 || + pcx->encoding != 1 || + pcx->bits_per_pixel != 8 || + xmax >= 1024 || + ymax >= 1024 ) { + common->Printf( "Bad pcx file %s (%i x %i) (%i x %i)\n", filename, xmax + 1, ymax + 1, pcx->xmax, pcx->ymax ); return; } - - out = (byte *)R_StaticAlloc( (ymax+1) * (xmax+1) ); - + out = ( byte * )R_StaticAlloc( ( ymax + 1 ) * ( xmax + 1 ) ); *pic = out; - pix = out; - if (palette) - { - *palette = (byte *)R_StaticAlloc(768); - memcpy (*palette, (byte *)pcx + len - 768, 768); + if ( palette ) { + *palette = ( byte * )R_StaticAlloc( 768 ); + memcpy( *palette, ( byte * )pcx + len - 768, 768 ); } - if (width) - *width = xmax+1; - if (height) - *height = ymax+1; -// FIXME: use bytes_per_line here? + if ( width ) { + *width = xmax + 1; + } + + if ( height ) { + *height = ymax + 1; + } - for (y=0 ; y<=ymax ; y++, pix += xmax+1) - { - for (x=0 ; x<=xmax ; ) - { + // FIXME: use bytes_per_line here? + for ( y = 0 ; y <= ymax ; y++, pix += xmax + 1 ) { + for ( x = 0 ; x <= xmax ; ) { dataByte = *raw++; - if((dataByte & 0xC0) == 0xC0) - { + if ( ( dataByte & 0xC0 ) == 0xC0 ) { runLength = dataByte & 0x3F; dataByte = *raw++; - } - else + } else { runLength = 1; + } - while(runLength-- > 0) - pix[x++] = dataByte; + while ( runLength-- > 0 ) { + pix[ x++ ] = dataByte; + } } - } - if ( raw - (byte *)pcx > len) - { + if ( raw - ( byte * )pcx > len ) { common->Printf( "PCX file %s was malformed", filename ); - R_StaticFree (*pic); + R_StaticFree( *pic ); *pic = NULL; } - fileSystem->FreeFile( pcx ); } - /* ============== LoadPCX32 ============== */ -static void LoadPCX32 ( const char *filename, byte **pic, int *width, int *height, ID_TIME_T *timestamp) { +static void LoadPCX32( const char *filename, byte **pic, int *width, int *height, ID_TIME_T *timestamp ) { byte *palette; byte *pic8; int i, c, p; @@ -489,23 +490,23 @@ static void LoadPCX32 ( const char *filename, byte **pic, int *width, int *heigh fileSystem->ReadFile( filename, NULL, timestamp ); return; // just getting timestamp } - LoadPCX (filename, &pic8, &palette, width, height, timestamp); - if (!pic8) { + LoadPCX( filename, &pic8, &palette, width, height, timestamp ); + + if ( !pic8 ) { *pic = NULL; return; } + c = ( *width ) * ( *height ); + pic32 = *pic = ( byte * )R_StaticAlloc( 4 * c ); - c = (*width) * (*height); - pic32 = *pic = (byte *)R_StaticAlloc(4 * c ); - for (i = 0 ; i < c ; i++) { + for ( i = 0 ; i < c ; i++ ) { p = pic8[i]; - pic32[0] = palette[p*3]; - pic32[1] = palette[p*3 + 1]; - pic32[2] = palette[p*3 + 2]; + pic32[0] = palette[p * 3]; + pic32[1] = palette[p * 3 + 1]; + pic32[2] = palette[p * 3 + 2]; pic32[3] = 255; pic32 += 4; } - R_StaticFree( pic8 ); R_StaticFree( palette ); } @@ -513,7 +514,7 @@ static void LoadPCX32 ( const char *filename, byte **pic, int *width, int *heigh /* ========================================================= -TARGA LOADING +TARGA LOADING TGA2 ========================================================= */ @@ -523,236 +524,316 @@ TARGA LOADING LoadTGA ============= */ -static void LoadTGA( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp ) { - int columns, rows, numPixels, fileSize, numBytes; - byte *pixbuf; - int row, column; - byte *buf_p; - byte *buffer; - TargaHeader targa_header; - byte *targa_rgba; - - if ( !pic ) { - fileSystem->ReadFile( name, NULL, timestamp ); - return; // just getting timestamp - } - - *pic = NULL; - - // - // load the file - // - fileSize = fileSystem->ReadFile( name, (void **)&buffer, timestamp ); - if ( !buffer ) { - return; - } - - buf_p = buffer; - - targa_header.id_length = *buf_p++; - targa_header.colormap_type = *buf_p++; - targa_header.image_type = *buf_p++; - - targa_header.colormap_index = LittleShort ( *(short *)buf_p ); - buf_p += 2; - targa_header.colormap_length = LittleShort ( *(short *)buf_p ); - buf_p += 2; - targa_header.colormap_size = *buf_p++; - targa_header.x_origin = LittleShort ( *(short *)buf_p ); - buf_p += 2; - targa_header.y_origin = LittleShort ( *(short *)buf_p ); - buf_p += 2; - targa_header.width = LittleShort ( *(short *)buf_p ); - buf_p += 2; - targa_header.height = LittleShort ( *(short *)buf_p ); - buf_p += 2; - targa_header.pixel_size = *buf_p++; - targa_header.attributes = *buf_p++; - - if ( targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3 ) { - common->Error( "LoadTGA( %s ): Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n", name ); - } - - if ( targa_header.colormap_type != 0 ) { - common->Error( "LoadTGA( %s ): colormaps not supported\n", name ); - } - - if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 ) { - common->Error( "LoadTGA( %s ): Only 32 or 24 bit images supported (no colormaps)\n", name ); - } - - if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) { - numBytes = targa_header.width * targa_header.height * ( targa_header.pixel_size >> 3 ); - if ( numBytes > fileSize - 18 - targa_header.id_length ) { - common->Error( "LoadTGA( %s ): incomplete file\n", name ); - } - } - - columns = targa_header.width; - rows = targa_header.height; - numPixels = columns * rows; - - if ( width ) { - *width = columns; - } - if ( height ) { - *height = rows; - } - - targa_rgba = (byte *)R_StaticAlloc(numPixels*4); - *pic = targa_rgba; - - if ( targa_header.id_length != 0 ) { - buf_p += targa_header.id_length; // skip TARGA image comment - } - - if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) - { - // Uncompressed RGB or gray scale image - for( row = rows - 1; row >= 0; row-- ) - { - pixbuf = targa_rgba + row*columns*4; - for( column = 0; column < columns; column++) - { - unsigned char red,green,blue,alphabyte; - switch( targa_header.pixel_size ) - { - - case 8: - blue = *buf_p++; - green = blue; - red = blue; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = 255; - break; - - case 24: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = 255; - break; - case 32: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alphabyte = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = alphabyte; - break; - default: - common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size ); - break; - } - } - } - } - else if ( targa_header.image_type == 10 ) { // Runlength encoded RGB images - unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j; - - red = 0; - green = 0; - blue = 0; - alphabyte = 0xff; - - for( row = rows - 1; row >= 0; row-- ) { - pixbuf = targa_rgba + row*columns*4; - for( column = 0; column < columns; ) { - packetHeader= *buf_p++; - packetSize = 1 + (packetHeader & 0x7f); - if ( packetHeader & 0x80 ) { // run-length packet - switch( targa_header.pixel_size ) { - case 24: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alphabyte = 255; - break; - case 32: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alphabyte = *buf_p++; - break; - default: - common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size ); - break; - } - - for( j = 0; j < packetSize; j++ ) { - *pixbuf++=red; - *pixbuf++=green; - *pixbuf++=blue; - *pixbuf++=alphabyte; - column++; - if ( column == columns ) { // run spans across rows - column = 0; - if ( row > 0) { - row--; - } - else { - goto breakOut; - } - pixbuf = targa_rgba + row*columns*4; - } - } - } - else { // non run-length packet - for( j = 0; j < packetSize; j++ ) { - switch( targa_header.pixel_size ) { - case 24: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = 255; - break; - case 32: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alphabyte = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = alphabyte; - break; - default: - common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size ); - break; - } - column++; - if ( column == columns ) { // pixel packet run spans across rows - column = 0; - if ( row > 0 ) { - row--; - } - else { - goto breakOut; - } - pixbuf = targa_rgba + row*columns*4; - } - } - } - } - breakOut: ; - } - } - - if ( (targa_header.attributes & (1<<5)) ) { // image flp bit +static void LoadTGA( const char *filename, byte **pic, int *width, int *height, ID_TIME_T *timestamp ) { + int w, h, x, y, len, realrow, truerow, baserow, i, temp1, temp2, pixel_size, map_idx; + int RLE_count, RLE_flag, size, interleave, origin; + bool mapped, rlencoded; + byte *data, *dst, r, g, b, a, j, k, l, *ColorMap; + byte *buf_p; + byte *buffer; + TargaHeader header; + + if ( !pic ) { + fileSystem->ReadFile( filename, NULL, timestamp ); + return; // just getting timestamp + } + *pic = NULL; + + // + // load the file + // + len = fileSystem->ReadFile( filename, ( void ** )&buffer, timestamp ); + + if ( !buffer || len <= 0 ) { + return; + } + buf_p = buffer; + + header.id_length = *buf_p++; + header.colormap_type = *buf_p++; + header.image_type = *buf_p++; + + header.colormap_index = LittleShort( *( short * )buf_p ); + buf_p += 2; + + header.colormap_length = LittleShort( *( short * )buf_p ); + buf_p += 2; + + header.colormap_size = *buf_p++; + + header.x_origin = LittleShort( *( short * )buf_p ); + buf_p += 2; + + header.y_origin = LittleShort( *( short * )buf_p ); + buf_p += 2; + + header.width = LittleShort( *( short * )buf_p ); + buf_p += 2; + + header.height = LittleShort( *( short * )buf_p ); + buf_p += 2; + + header.pixel_size = *buf_p++; + header.attributes = *buf_p++; + + if ( header.id_length != 0 ) { + buf_p += header.id_length; + } + + /* validate TGA type */ + switch ( header.image_type ) { + case TGA_Map: + case TGA_RGB: + case TGA_Mono: + case TGA_RLEMap: + case TGA_RLERGB: + case TGA_RLEMono: + break; + default: + common->Printf( "%s : Only type 1 (map), 2 (RGB), 3 (mono), 9 (RLEmap), 10 (RLERGB), 11 (RLEmono) TGA " + "images supported\n", filename ); + return; + } + + /* validate color depth */ + switch ( header.pixel_size ) { + case 8: + case 15: + case 16: + case 24: + case 32: + break; + default: + common->Printf( "%s : Only 8, 15, 16, 24 or 32 bit images (with colormaps) supported\n", filename ); + return; + } + r = g = b = a = l = 0; + + /* if required, read the color map information. */ + ColorMap = nullptr; + mapped = ( header.image_type == TGA_Map || header.image_type == TGA_RLEMap ) && header.colormap_type == 1; + + if ( mapped ) { + /* validate colormap size */ + switch ( header.colormap_size ) { + case 8: + case 15: + case 16: + case 32: + case 24: + break; + default: + common->Printf( "%s : Only 8, 15, 16, 24 or 32 bit colormaps supported\n", filename ); + return; + } + temp1 = header.colormap_index; + temp2 = header.colormap_length; + + if ( ( temp1 + temp2 + 1 ) >= TGA_MAXCOLORS ) { + return; + } + ColorMap = ( byte * )R_StaticAlloc( TGA_MAXCOLORS * 4 ); + map_idx = 0; + + for ( i = temp1; i < temp1 + temp2; ++i, map_idx += 4 ) { + /* read appropriate number of bytes, break into rgb & put in map. */ + switch ( header.colormap_size ) { + case 8: /* grey scale, read and triplicate. */ + r = g = b = *buf_p++; + a = 255; + break; + case 15: /* 5 bits each of red green and blue. */ + /* watch byte order. */ + j = *buf_p++; + k = *buf_p++; + l = ( ( unsigned int )k << 8 ) + j; + r = ( byte )( ( ( k & 0x7C ) >> 2 ) << 3 ); + g = ( byte )( ( ( ( k & 0x03 ) << 3 ) + ( ( j & 0xE0 ) >> 5 ) ) << 3 ); + b = ( byte )( ( j & 0x1F ) << 3 ); + a = 255; + break; + case 16: /* 5 bits each of red green and blue, 1 alpha bit. */ + /* watch byte order. */ + j = *buf_p++; + k = *buf_p++; + l = ( ( unsigned int )k << 8 ) + j; + r = ( byte )( ( ( k & 0x7C ) >> 2 ) << 3 ); + g = ( byte )( ( ( ( k & 0x03 ) << 3 ) + ( ( j & 0xE0 ) >> 5 ) ) << 3 ); + b = ( byte )( ( j & 0x1F ) << 3 ); + a = ( k & 0x80 ) ? 255 : 0; + break; + case 24: /* 8 bits each of blue, green and red. */ + b = *buf_p++; + g = *buf_p++; + r = *buf_p++; + a = 255; + l = 0; + break; + case 32: /* 8 bits each of blue, green, red and alpha. */ + b = *buf_p++; + g = *buf_p++; + r = *buf_p++; + a = *buf_p++; + l = 0; + break; + } + ColorMap[map_idx + 0] = r; + ColorMap[map_idx + 1] = g; + ColorMap[map_idx + 2] = b; + ColorMap[map_idx + 3] = a; + } + } + + /* check run-length encoding. */ + rlencoded = ( header.image_type == TGA_RLEMap || header.image_type == TGA_RLERGB || header.image_type == TGA_RLEMono ); + RLE_count = RLE_flag = 0; + w = header.width; + h = header.height; + size = w * h * 4; + + if ( width ) { + *width = w; + } + + if ( height ) { + *height = h; + } + data = ( byte * )R_StaticAlloc( size ); + *pic = data; + + /* read the Targa file body and convert to portable format. */ + pixel_size = header.pixel_size; + origin = ( header.attributes & 0x20 ) >> 5; + interleave = ( header.attributes & 0xC0 ) >> 6; + truerow = 0; + baserow = 0; + + for ( y = 0; y < h; y++ ) { + realrow = truerow; + + if ( origin == TGA_O_UPPER ) { + realrow = h - realrow - 1; + } + dst = data + realrow * w * 4; + + for ( x = 0; x < w; x++ ) { + /* check if run length encoded. */ + if ( rlencoded ) { + if ( !RLE_count ) { + /* have to restart run. */ + i = *buf_p++; + RLE_flag = ( i & 0x80 ); + + if ( !RLE_flag ) { + // stream of unencoded pixels + RLE_count = i + 1; + } else { + // single pixel replicated + RLE_count = i - 127; + } + + /* decrement count & get pixel. */ + --RLE_count; + } else { + /* have already read count & (at least) first pixel. */ + --RLE_count; + + if ( RLE_flag ) { + /* replicated pixels. */ + goto PixEncode; + } + } + } + + /* read appropriate number of bytes, break into RGB. */ + switch ( pixel_size ) { + case 8: /* grey scale, read and triplicate. */ + r = g = b = l = *buf_p++; + a = 255; + break; + case 15: /* 5 bits each of red green and blue. */ + /* watch byte order. */ + j = *buf_p++; + k = *buf_p++; + l = ( ( unsigned int )k << 8 ) + j; + r = ( byte )( ( ( k & 0x7C ) >> 2 ) << 3 ); + g = ( byte )( ( ( ( k & 0x03 ) << 3 ) + ( ( j & 0xE0 ) >> 5 ) ) << 3 ); + b = ( byte )( ( j & 0x1F ) << 3 ); + a = 255; + break; + case 16: /* 5 bits each of red green and blue, 1 alpha bit. */ + /* watch byte order. */ + j = *buf_p++; + k = *buf_p++; + l = ( ( unsigned int )k << 8 ) + j; + r = ( byte )( ( ( k & 0x7C ) >> 2 ) << 3 ); + g = ( byte )( ( ( ( k & 0x03 ) << 3 ) + ( ( j & 0xE0 ) >> 5 ) ) << 3 ); + b = ( byte )( ( j & 0x1F ) << 3 ); + a = ( k & 0x80 ) ? 255 : 0; + break; + case 24: /* 8 bits each of blue, green and red. */ + b = *buf_p++; + g = *buf_p++; + r = *buf_p++; + a = 255; + l = 0; + break; + case 32: /* 8 bits each of blue, green, red and alpha. */ + b = *buf_p++; + g = *buf_p++; + r = *buf_p++; + a = *buf_p++; + l = 0; + break; + default: + common->Printf( "%s : Illegal pixel_size '%d'\n", filename, pixel_size ); + + R_StaticFree( data ); + + if ( mapped ) { + R_StaticFree( ColorMap ); + } + return; + } + PixEncode: + if ( mapped ) { + map_idx = l * 4; + *dst++ = ColorMap[map_idx + 0]; + *dst++ = ColorMap[map_idx + 1]; + *dst++ = ColorMap[map_idx + 2]; + *dst++ = ColorMap[map_idx + 3]; + } else { + *dst++ = r; + *dst++ = g; + *dst++ = b; + *dst++ = a; + } + } + + if ( interleave == TGA_IL_Four ) { + truerow += 4; + } else if ( interleave == TGA_IL_Two ) { + truerow += 2; + } else { + truerow++; + } + + if ( truerow >= h ) { + truerow = ++baserow; + } + } + + if ( mapped ) { + R_StaticFree( ColorMap ); + } + +#if 0 + // image flp bit (no longer needed with type 2 TGA) + if ( ( header.attributes & ( 1 << 5 ) ) ) { R_VerticalFlip( *pic, *width, *height ); - } - - fileSystem->FreeFile( buffer ); + } +#endif + fileSystem->FreeFile( buffer ); } /* @@ -760,47 +841,51 @@ static void LoadTGA( const char *name, byte **pic, int *width, int *height, ID_T LoadJPG ============= */ -static void LoadJPG( const char *filename, unsigned char **pic, int *width, int *height, ID_TIME_T *timestamp ) { - +static void LoadJPG( const char *filename, byte **pic, int *width, int *height, ID_TIME_T *timestamp ) { if ( pic ) { *pic = NULL; // until proven otherwise } - idFile *f = fileSystem->OpenFileRead( filename ); + if ( !f ) { return; } int len = f->Length(); + if ( timestamp ) { *timestamp = f->Timestamp(); } + if ( !pic ) { fileSystem->CloseFile( f ); return; // just getting timestamp } - byte *fbuffer = (byte *)Mem_ClearedAlloc( len ); + byte *fbuffer = ( byte * )Mem_ClearedAlloc( len ); f->Read( fbuffer, len ); fileSystem->CloseFile( f ); - int w=0, h=0, comp=0; - byte* decodedImageData = stbi_load_from_memory( fbuffer, len, &w, &h, &comp, 4 ); + int w = 0, h = 0, comp = 0; + byte *decodedImageData = stbi_load_from_memory( fbuffer, len, &w, &h, &comp, 4 ); Mem_Free( fbuffer ); if ( decodedImageData == NULL ) { common->Warning( "stb_image was unable to load JPG %s : %s\n", - filename, stbi_failure_reason()); + filename, stbi_failure_reason() ); return; } // *pic must be allocated with R_StaticAlloc(), but stb_image allocates with malloc() // (and as there is no R_StaticRealloc(), #define STBI_MALLOC etc won't help) // so the decoded data must be copied once - int size = w*h*4; - *pic = (byte *)R_StaticAlloc( size ); + int size = w * h * 4; + + *pic = ( byte * )R_StaticAlloc( size ); memcpy( *pic, decodedImageData, size ); + *width = w; *height = h; + // now that decodedImageData has been copied into *pic, it's not needed anymore stbi_image_free( decodedImageData ); } @@ -837,28 +922,30 @@ void R_LoadImage( const char *cname, byte **pic, int *width, int *height, ID_TIM if ( pic ) { *pic = NULL; } + if ( timestamp ) { *timestamp = FILE_NOT_FOUND_TIMESTAMP; } + if ( width ) { *width = 0; } + if ( height ) { *height = 0; } - name.DefaultFileExtension( ".tga" ); - if (name.Length()<5) { + if ( name.Length() < 5 ) { return; } - name.ToLower(); idStr ext; name.ExtractFileExtension( ext ); if ( ext == "tga" ) { LoadTGA( name.c_str(), pic, width, height, timestamp ); // try tga first + if ( ( pic && *pic == 0 ) || ( timestamp && *timestamp == FILE_NOT_FOUND_TIMESTAMP ) ) { name.StripFileExtension(); name.DefaultFileExtension( ".jpg" ); @@ -890,19 +977,17 @@ void R_LoadImage( const char *cname, byte **pic, int *width, int *height, ID_TIM w = *width; h = *height; - for (scaled_width = 1 ; scaled_width < w ; scaled_width<<=1) - ; - for (scaled_height = 1 ; scaled_height < h ; scaled_height<<=1) - ; + for ( scaled_width = 1 ; scaled_width < w ; scaled_width <<= 1 ); + for ( scaled_height = 1 ; scaled_height < h ; scaled_height <<= 1 ); if ( scaled_width != w || scaled_height != h ) { if ( globalImages->image_roundDown.GetBool() && scaled_width > w ) { scaled_width >>= 1; } + if ( globalImages->image_roundDown.GetBool() && scaled_height > h ) { scaled_height >>= 1; } - resampledBuffer = R_ResampleTexture( *pic, w, h, scaled_width, scaled_height ); R_StaticFree( *pic ); *pic = resampledBuffer; @@ -912,7 +997,6 @@ void R_LoadImage( const char *cname, byte **pic, int *width, int *height, ID_TIM } } - /* ======================= R_LoadCubeImages @@ -923,9 +1007,11 @@ Loads six files with proper extensions bool R_LoadCubeImages( const char *imgName, cubeFiles_t extensions, byte *pics[6], int *outSize, ID_TIME_T *timestamp ) { int i, j; const char *cameraSides[6] = { "_forward.tga", "_back.tga", "_left.tga", "_right.tga", - "_up.tga", "_down.tga" }; + "_up.tga", "_down.tga" + }; const char *axisSides[6] = { "_px.tga", "_nx.tga", "_py.tga", "_ny.tga", - "_pz.tga", "_nz.tga" }; + "_pz.tga", "_nz.tga" + }; const char **sides; char fullName[MAX_IMAGE_NAME]; int width, height, size = 0; @@ -938,7 +1024,7 @@ bool R_LoadCubeImages( const char *imgName, cubeFiles_t extensions, byte *pics[6 // FIXME: precompressed cube map files if ( pics ) { - memset( pics, 0, 6*sizeof(pics[0]) ); + memset( pics, 0, 6 * sizeof( pics[0] ) ); } if ( timestamp ) { *timestamp = 0; @@ -954,29 +1040,34 @@ bool R_LoadCubeImages( const char *imgName, cubeFiles_t extensions, byte *pics[6 } else { R_LoadImageProgram( fullName, &pics[i], &width, &height, &thisTime ); } + if ( thisTime == FILE_NOT_FOUND_TIMESTAMP ) { break; } + if ( i == 0 ) { size = width; } + if ( width != size || height != size ) { common->Warning( "Mismatched sizes on cube map '%s'", imgName ); break; } + if ( timestamp ) { if ( thisTime > *timestamp ) { *timestamp = thisTime; } } + if ( pics && extensions == CF_CAMERA ) { // convert from "camera" images to native cube map images - switch( i ) { + switch ( i ) { case 0: // forward - R_RotatePic( pics[i], width); + R_RotatePic( pics[i], width ); break; case 1: // back - R_RotatePic( pics[i], width); + R_RotatePic( pics[i], width ); R_HorizontalFlip( pics[i], width, height ); R_VerticalFlip( pics[i], width, height ); break; @@ -987,10 +1078,10 @@ bool R_LoadCubeImages( const char *imgName, cubeFiles_t extensions, byte *pics[6 R_HorizontalFlip( pics[i], width, height ); break; case 4: // up - R_RotatePic( pics[i], width); + R_RotatePic( pics[i], width ); break; case 5: // down - R_RotatePic( pics[i], width); + R_RotatePic( pics[i], width ); break; } } diff --git a/neo/renderer/Image_init.cpp b/neo/renderer/Image_init.cpp index 89d9c578a..8401c954a 100644 --- a/neo/renderer/Image_init.cpp +++ b/neo/renderer/Image_init.cpp @@ -113,11 +113,9 @@ const imageClassificate_t IC_Info[] = { { "", "Other", IC_OTHER, 256, 256 } }; - - static int ClassifyImage( const char *name ) { - idStr str; - str = name; + idStr str = name; + for ( int i = 0; i < IC_COUNT; i++ ) { if ( str.Find( IC_Info[i].rootPath, false ) == 0 ) { return IC_Info[i].type; @@ -137,15 +135,13 @@ static void R_RampImage( idImage *image ) { int x; byte data[256][4]; - for (x=0 ; x<256 ; x++) { + for ( x = 0 ; x < 256 ; x++ ) { data[x][0] = data[x][1] = data[x][2] = data[x][3] = x; } - - image->GenerateImage( (byte *)data, 256, 1, - TF_NEAREST, false, TR_CLAMP, TD_HIGH_QUALITY ); + image->GenerateImage( ( byte * )data, 256, 1, TF_NEAREST, false, TR_CLAMP, TD_HIGH_QUALITY ); } /* @@ -159,32 +155,30 @@ static void R_SpecularTableImage( idImage *image ) { int x; byte data[256][4]; - for (x=0 ; x<256 ; x++) { - float f = x/255.f; + for ( x = 0 ; x < 256 ; x++ ) { + float f = x / 255.f; #if 0 - f = pow(f, 16); + f = pow( f, 16 ); #else // this is the behavior of the hacked up fragment programs that // can't really do a power function - f = (f-0.75)*4; + f = ( f - 0.75 ) * 4; + if ( f < 0 ) { f = 0; } f = f * f; #endif - int b = (int)(f * 255); + int b = ( int )( f * 255 ); data[x][0] = data[x][1] = data[x][2] = data[x][3] = b; } - - image->GenerateImage( (byte *)data, 256, 1, - TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY ); + image->GenerateImage( ( byte * )data, 256, 1, TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY ); } - /* ================ R_Specular2DTableImage @@ -197,29 +191,25 @@ static void R_Specular2DTableImage( idImage *image ) { byte data[256][256][4]; memset( data, 0, sizeof( data ) ); - for ( x = 0 ; x < 256 ; x++ ) { - float f = x / 255.0f; - for ( y = 0; y < 256; y++ ) { - int b = (int)( pow( f, y ) * 255.0f ); + for ( x = 0 ; x < 256 ; x++ ) { + float f = x / 255.0f; + for ( y = 0; y < 256; y++ ) { + int b = ( int )( pow( f, y ) * 255.0f ); if ( b == 0 ) { // as soon as b equals zero all remaining values in this column are going to be zero // we early out to avoid pow() underflows break; } - data[y][x][0] = data[y][x][1] = data[y][x][2] = data[y][x][3] = b; } } - - image->GenerateImage( (byte *)data, 256, 256, TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY ); + image->GenerateImage( ( byte * )data, 256, 256, TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY ); } - - /* ================ R_AlphaRampImage @@ -232,20 +222,16 @@ static void R_AlphaRampImage( idImage *image ) { int x; byte data[256][4]; - for (x=0 ; x<256 ; x++) { + for ( x = 0 ; x < 256 ; x++ ) { data[x][0] = data[x][1] = data[x][2] = 255; data[x][3] = x; } - - image->GenerateImage( (byte *)data, 256, 1, - TF_NEAREST, false, TR_CLAMP, TD_HIGH_QUALITY ); + image->GenerateImage( ( byte * )data, 256, 1, TF_NEAREST, false, TR_CLAMP, TD_HIGH_QUALITY ); } #endif - - /* ================== R_CreateDefaultImage @@ -273,24 +259,24 @@ void idImage::MakeDefault() { // white border for ( x = 0 ; x < DEFAULT_SIZE ; x++ ) { data[0][x][0] = - data[0][x][1] = - data[0][x][2] = - data[0][x][3] = 255; + data[0][x][1] = + data[0][x][2] = + data[0][x][3] = 255; data[x][0][0] = - data[x][0][1] = - data[x][0][2] = - data[x][0][3] = 255; - - data[DEFAULT_SIZE-1][x][0] = - data[DEFAULT_SIZE-1][x][1] = - data[DEFAULT_SIZE-1][x][2] = - data[DEFAULT_SIZE-1][x][3] = 255; - - data[x][DEFAULT_SIZE-1][0] = - data[x][DEFAULT_SIZE-1][1] = - data[x][DEFAULT_SIZE-1][2] = - data[x][DEFAULT_SIZE-1][3] = 255; + data[x][0][1] = + data[x][0][2] = + data[x][0][3] = 255; + + data[DEFAULT_SIZE - 1][x][0] = + data[DEFAULT_SIZE - 1][x][1] = + data[DEFAULT_SIZE - 1][x][2] = + data[DEFAULT_SIZE - 1][x][3] = 255; + + data[x][DEFAULT_SIZE - 1][0] = + data[x][DEFAULT_SIZE - 1][1] = + data[x][DEFAULT_SIZE - 1][2] = + data[x][DEFAULT_SIZE - 1][3] = 255; } } else { for ( y = 0 ; y < DEFAULT_SIZE ; y++ ) { @@ -302,10 +288,7 @@ void idImage::MakeDefault() { } } } - - GenerateImage( (byte *)data, - DEFAULT_SIZE, DEFAULT_SIZE, - TF_DEFAULT, true, TR_REPEAT, TD_DEFAULT ); + GenerateImage( ( byte * )data, DEFAULT_SIZE, DEFAULT_SIZE, TF_DEFAULT, true, TR_REPEAT, TD_DEFAULT ); defaulted = true; } @@ -319,8 +302,7 @@ static void R_WhiteImage( idImage *image ) { // solid white texture memset( data, 255, sizeof( data ) ); - image->GenerateImage( (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, - TF_DEFAULT, false, TR_REPEAT, TD_DEFAULT ); + image->GenerateImage( ( byte * )data, DEFAULT_SIZE, DEFAULT_SIZE, TF_DEFAULT, false, TR_REPEAT, TD_DEFAULT ); } static void R_BlackImage( idImage *image ) { @@ -328,11 +310,9 @@ static void R_BlackImage( idImage *image ) { // solid black texture memset( data, 0, sizeof( data ) ); - image->GenerateImage( (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, - TF_DEFAULT, false, TR_REPEAT, TD_DEFAULT ); + image->GenerateImage( ( byte * )data, DEFAULT_SIZE, DEFAULT_SIZE, TF_DEFAULT, false, TR_REPEAT, TD_DEFAULT ); } - // the size determines how far away from the edge the blocks start fading static const int BORDER_CLAMP_SIZE = 32; static void R_BorderClampImage( idImage *image ) { @@ -340,39 +320,44 @@ static void R_BorderClampImage( idImage *image ) { // solid white texture with a single pixel black border memset( data, 255, sizeof( data ) ); + for ( int i = 0 ; i < BORDER_CLAMP_SIZE ; i++ ) { data[i][0][0] = data[i][0][1] = data[i][0][2] = data[i][0][3] = - data[i][BORDER_CLAMP_SIZE-1][0] = - data[i][BORDER_CLAMP_SIZE-1][1] = - data[i][BORDER_CLAMP_SIZE-1][2] = - data[i][BORDER_CLAMP_SIZE-1][3] = + data[i][BORDER_CLAMP_SIZE - 1][0] = + data[i][BORDER_CLAMP_SIZE - 1][1] = + data[i][BORDER_CLAMP_SIZE - 1][2] = + data[i][BORDER_CLAMP_SIZE - 1][3] = data[0][i][0] = data[0][i][1] = data[0][i][2] = data[0][i][3] = - data[BORDER_CLAMP_SIZE-1][i][0] = - data[BORDER_CLAMP_SIZE-1][i][1] = - data[BORDER_CLAMP_SIZE-1][i][2] = - data[BORDER_CLAMP_SIZE-1][i][3] = 0; + data[BORDER_CLAMP_SIZE - 1][i][0] = + data[BORDER_CLAMP_SIZE - 1][i][1] = + data[BORDER_CLAMP_SIZE - 1][i][2] = + data[BORDER_CLAMP_SIZE - 1][i][3] = 0; } - - image->GenerateImage( (byte *)data, BORDER_CLAMP_SIZE, BORDER_CLAMP_SIZE, - TF_LINEAR /* TF_NEAREST */, false, TR_CLAMP_TO_BORDER, TD_DEFAULT ); + image->GenerateImage( ( byte * )data, BORDER_CLAMP_SIZE, BORDER_CLAMP_SIZE, TF_LINEAR, false, TR_CLAMP_TO_BORDER, TD_DEFAULT ); if ( !glConfig.isInitialized ) { // can't call qglTexParameterfv yet return; } + // explicit zero border - float color[4]; - color[0] = color[1] = color[2] = color[3] = 0; - qglTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color ); + float color[4]; + + color[0] = + color[1] = + color[2] = + color[3] = 0; + + qglTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color ); } static void R_RGBA8Image( idImage *image ) { @@ -384,8 +369,7 @@ static void R_RGBA8Image( idImage *image ) { data[0][0][2] = 48; data[0][0][3] = 96; - image->GenerateImage( (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, - TF_DEFAULT, false, TR_REPEAT, TD_HIGH_QUALITY ); + image->GenerateImage( ( byte * )data, DEFAULT_SIZE, DEFAULT_SIZE, TF_DEFAULT, false, TR_REPEAT, TD_HIGH_QUALITY ); } static void R_DepthImage( idImage *image ) { @@ -397,8 +381,7 @@ static void R_DepthImage( idImage *image ) { data[0][0][2] = 48; data[0][0][3] = 96; - image->GenerateImage( (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, - TF_NEAREST, false, TR_CLAMP, TD_HIGH_QUALITY ); + image->GenerateImage( ( byte * )data, DEFAULT_SIZE, DEFAULT_SIZE, TF_NEAREST, false, TR_CLAMP, TD_HIGH_QUALITY ); } #if 0 @@ -411,8 +394,7 @@ static void R_RGB8Image( idImage *image ) { data[0][0][2] = 48; data[0][0][3] = 255; - image->GenerateImage( (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, - TF_DEFAULT, false, TR_REPEAT, TD_HIGH_QUALITY ); + image->GenerateImage( ( byte * )data, DEFAULT_SIZE, DEFAULT_SIZE, TF_DEFAULT, false, TR_REPEAT, TD_HIGH_QUALITY ); } #endif @@ -420,22 +402,20 @@ static void R_AlphaNotchImage( idImage *image ) { byte data[2][4]; // this is used for alpha test clip planes - data[0][0] = data[0][1] = data[0][2] = 255; data[0][3] = 0; data[1][0] = data[1][1] = data[1][2] = 255; data[1][3] = 255; - image->GenerateImage( (byte *)data, 2, 1, - TF_NEAREST, false, TR_CLAMP, TD_HIGH_QUALITY ); + image->GenerateImage( ( byte * )data, 2, 1, TF_NEAREST, false, TR_CLAMP, TD_HIGH_QUALITY ); } static void R_FlatNormalImage( idImage *image ) { byte data[DEFAULT_SIZE][DEFAULT_SIZE][4]; int i; + int red = ( globalImages->image_useNormalCompression.GetInteger() == 1 ) ? 0 : 3; + int alpha = ( red == 0 ) ? 3 : 0; - int red = ( globalImages->image_useNormalCompression.GetInteger() == 1 ) ? 0 : 3; - int alpha = ( red == 0 ) ? 3 : 0; // flat normal map for default bunp mapping for ( i = 0 ; i < 4 ; i++ ) { data[0][i][red] = 128; @@ -443,32 +423,32 @@ static void R_FlatNormalImage( idImage *image ) { data[0][i][2] = 255; data[0][i][alpha] = 255; } - image->GenerateImage( (byte *)data, 2, 2, - TF_DEFAULT, true, TR_REPEAT, TD_HIGH_QUALITY ); + image->GenerateImage( ( byte * )data, 2, 2, TF_DEFAULT, true, TR_REPEAT, TD_HIGH_QUALITY ); } static void R_AmbientNormalImage( idImage *image ) { - byte data[DEFAULT_SIZE][DEFAULT_SIZE][4]; - int i; + byte data[DEFAULT_SIZE][DEFAULT_SIZE][4]; + int i; + int red = ( globalImages->image_useNormalCompression.GetInteger() == 1 ) ? 0 : 3; + int alpha = ( red == 0 ) ? 3 : 0; - int red = ( globalImages->image_useNormalCompression.GetInteger() == 1 ) ? 0 : 3; - int alpha = ( red == 0 ) ? 3 : 0; // flat normal map for default bunp mapping for ( i = 0 ; i < 4 ; i++ ) { - data[0][i][red] = (byte)(255 * tr.ambientLightVector[0]); - data[0][i][1] = (byte)(255 * tr.ambientLightVector[1]); - data[0][i][2] = (byte)(255 * tr.ambientLightVector[2]); + data[0][i][red] = ( byte )( 255 * tr.ambientLightVector[0] ); + data[0][i][1] = ( byte )( 255 * tr.ambientLightVector[1] ); + data[0][i][2] = ( byte )( 255 * tr.ambientLightVector[2] ); data[0][i][alpha] = 255; } const byte *pics[6]; + for ( i = 0 ; i < 6 ; i++ ) { pics[i] = data[0][0]; } + // this must be a cube map for fragment programs to simply substitute for the normalization cube map image->GenerateCubeImage( pics, 2, TF_DEFAULT, true, TD_HIGH_QUALITY ); } - #if 0 static void CreateSquareLight( void ) { byte *buffer; @@ -479,7 +459,7 @@ static void CreateSquareLight( void ) { width = height = 128; - buffer = (byte *)R_StaticAlloc( 128 * 128 * 4 ); + buffer = ( byte * )R_StaticAlloc( 128 * 128 * 4 ); for ( x = 0 ; x < 128 ; x++ ) { if ( x < 32 ) { @@ -489,6 +469,7 @@ static void CreateSquareLight( void ) { } else { dx = 0; } + for ( y = 0 ; y < 128 ; y++ ) { if ( y < 32 ) { dy = 32 - y; @@ -497,21 +478,22 @@ static void CreateSquareLight( void ) { } else { dy = 0; } - d = (byte)idMath::Sqrt( dx * dx + dy * dy ); + d = ( byte )idMath::Sqrt( dx * dx + dy * dy ); + if ( d > 32 ) { d = 32; } d = 255 - d * 8; + if ( d < 0 ) { d = 0; } - buffer[(y*128+x)*4+0] = - buffer[(y*128+x)*4+1] = - buffer[(y*128+x)*4+2] = d; - buffer[(y*128+x)*4+3] = 255; + buffer[( y * 128 + x ) * 4 + 0] = + buffer[( y * 128 + x ) * 4 + 1] = + buffer[( y * 128 + x ) * 4 + 2] = d; + buffer[( y * 128 + x ) * 4 + 3] = 255; } } - R_WriteTGA( "lights/squarelight.tga", buffer, width, height ); R_StaticFree( buffer ); @@ -526,25 +508,23 @@ static void CreateFlashOff( void ) { width = 256; height = 4; - buffer = (byte *)R_StaticAlloc( width * height * 4 ); + buffer = ( byte * )R_StaticAlloc( width * height * 4 ); for ( x = 0 ; x < width ; x++ ) { for ( y = 0 ; y < height ; y++ ) { d = 255 - ( x * 256 / width ); - buffer[(y*width+x)*4+0] = - buffer[(y*width+x)*4+1] = - buffer[(y*width+x)*4+2] = d; - buffer[(y*width+x)*4+3] = 255; + buffer[( y * width + x ) * 4 + 0] = + buffer[( y * width + x ) * 4 + 1] = + buffer[( y * width + x ) * 4 + 2] = d; + buffer[( y * width + x ) * 4 + 3] = 255; } } - R_WriteTGA( "lights/flashoff.tga", buffer, width, height ); R_StaticFree( buffer ); } #endif - /* =============== CreatePitFogImage @@ -555,19 +535,11 @@ void CreatePitFogImage( void ) { int i, j; memset( data, 0, sizeof( data ) ); - for ( i = 0 ; i < 16 ; i++ ) { - int a; -#if 0 - if ( i > 14 ) { - a = 0; - } else -#endif - { - a = i * 255 / 15; - if ( a > 255 ) { - a = 255; - } + for ( i = 0 ; i < 16 ; i++ ) { + int a = i * 255 / 15; + if ( a > 255 ) { + a = 255; } for ( j = 0 ; j < 16 ; j++ ) { @@ -577,7 +549,6 @@ void CreatePitFogImage( void ) { data[j][i][3] = a; } } - R_WriteTGA( "shapes/pitFalloff.tga", data[0][0], 16, 16 ); } @@ -591,8 +562,7 @@ void CreatealphaSquareImage( void ) { int i, j; for ( i = 0 ; i < 16 ; i++ ) { - int a; - + int a; for ( j = 0 ; j < 16 ; j++ ) { if ( i == 0 || i == 15 || j == 0 || j == 15 ) { a = 0; @@ -605,7 +575,6 @@ void CreatealphaSquareImage( void ) { data[j][i][3] = a; } } - R_WriteTGA( "shapes/alphaSquare.tga", data[0][0], 16, 16 ); } @@ -616,54 +585,55 @@ void CreatealphaSquareImage( void ) { /* Given a cube map face index, cube map size, and integer 2D face position, * return the cooresponding normalized vector. */ -static void getCubeVector(int i, int cubesize, int x, int y, float *vector) { - float s, t, sc, tc, mag; - - s = ((float)x + 0.5) / (float)cubesize; - t = ((float)y + 0.5) / (float)cubesize; - sc = s*2.0 - 1.0; - tc = t*2.0 - 1.0; - - switch (i) { - case 0: - vector[0] = 1.0; - vector[1] = -tc; - vector[2] = -sc; - break; - case 1: - vector[0] = -1.0; - vector[1] = -tc; - vector[2] = sc; - break; - case 2: - vector[0] = sc; - vector[1] = 1.0; - vector[2] = tc; - break; - case 3: - vector[0] = sc; - vector[1] = -1.0; - vector[2] = -tc; - break; - case 4: - vector[0] = sc; - vector[1] = -tc; - vector[2] = 1.0; - break; - case 5: - vector[0] = -sc; - vector[1] = -tc; - vector[2] = -1.0; - break; - default: - common->Error ("getCubeVector: invalid cube map face index"); - return; - } - - mag = idMath::InvSqrt(vector[0]*vector[0] + vector[1]*vector[1] + vector[2]*vector[2]); - vector[0] *= mag; - vector[1] *= mag; - vector[2] *= mag; +static void getCubeVector( int i, int cubesize, int x, int y, float *vector ) { + float s, t, sc, tc, mag; + + s = ( ( float )x + 0.5 ) / ( float )cubesize; + t = ( ( float )y + 0.5 ) / ( float )cubesize; + + sc = s * 2.0 - 1.0; + tc = t * 2.0 - 1.0; + + switch ( i ) { + case 0: + vector[0] = 1.0; + vector[1] = -tc; + vector[2] = -sc; + break; + case 1: + vector[0] = -1.0; + vector[1] = -tc; + vector[2] = sc; + break; + case 2: + vector[0] = sc; + vector[1] = 1.0; + vector[2] = tc; + break; + case 3: + vector[0] = sc; + vector[1] = -1.0; + vector[2] = -tc; + break; + case 4: + vector[0] = sc; + vector[1] = -tc; + vector[2] = 1.0; + break; + case 5: + vector[0] = -sc; + vector[1] = -tc; + vector[2] = -1.0; + break; + default: + common->Error( "getCubeVector: invalid cube map face index" ); + return; + } + mag = idMath::InvSqrt( vector[0] * vector[0] + vector[1] * vector[1] + vector[2] * vector[2] ); + + vector[0] *= mag; + vector[1] *= mag; + vector[2] *= mag; } /* Initialize a cube map texture object that generates RGB values @@ -679,30 +649,26 @@ static void makeNormalizeVectorCubeMap( idImage *image ) { size = NORMAL_MAP_SIZE; - pixels[0] = (GLubyte*) Mem_Alloc(size*size*4*6); - - for (i = 0; i < 6; i++) { - pixels[i] = pixels[0] + i*size*size*4; - for (y = 0; y < size; y++) { - for (x = 0; x < size; x++) { - getCubeVector(i, size, x, y, vector); - pixels[i][4*(y*size+x) + 0] = (byte)(128 + 127*vector[0]); - pixels[i][4*(y*size+x) + 1] = (byte)(128 + 127*vector[1]); - pixels[i][4*(y*size+x) + 2] = (byte)(128 + 127*vector[2]); - pixels[i][4*(y*size+x) + 3] = 255; - } + pixels[0] = ( GLubyte * ) Mem_Alloc( size * size * 4 * 6 ); + + for ( i = 0; i < 6; i++ ) { + pixels[i] = pixels[0] + i * size * size * 4; + + for ( y = 0; y < size; y++ ) { + for ( x = 0; x < size; x++ ) { + getCubeVector( i, size, x, y, vector ); + pixels[i][4 * ( y * size + x ) + 0] = ( byte )( 128 + 127 * vector[0] ); + pixels[i][4 * ( y * size + x ) + 1] = ( byte )( 128 + 127 * vector[1] ); + pixels[i][4 * ( y * size + x ) + 2] = ( byte )( 128 + 127 * vector[2] ); + pixels[i][4 * ( y * size + x ) + 3] = 255; + } } } + image->GenerateCubeImage( ( const byte ** )pixels, size, TF_LINEAR, false, TD_HIGH_QUALITY ); - image->GenerateCubeImage( (const byte **)pixels, size, - TF_LINEAR, false, TD_HIGH_QUALITY ); - - Mem_Free(pixels[0]); + Mem_Free( pixels[0] ); } - - - /* ================ R_CreateNoFalloffImage @@ -711,23 +677,22 @@ This is a solid white texture that is zero clamped. ================ */ static void R_CreateNoFalloffImage( idImage *image ) { - int x,y; + int x, y; byte data[16][FALLOFF_TEXTURE_SIZE][4]; memset( data, 0, sizeof( data ) ); - for (x=1 ; xGenerateImage( (byte *)data, FALLOFF_TEXTURE_SIZE, 16, - TF_DEFAULT, false, TR_CLAMP_TO_ZERO, TD_HIGH_QUALITY ); + image->GenerateImage( ( byte * )data, FALLOFF_TEXTURE_SIZE, 16, TF_DEFAULT, false, TR_CLAMP_TO_ZERO, TD_HIGH_QUALITY ); } - /* ================ R_FogImage @@ -739,34 +704,34 @@ third will still be projection based const int FOG_SIZE = 128; void R_FogImage( idImage *image ) { - int x,y; + int x, y; byte data[FOG_SIZE][FOG_SIZE][4]; int b; + float step[256]; + int i; + float remaining = 1.0f; -float step[256]; -int i; -float remaining = 1.0; -for ( i = 0 ; i < 256 ; i++ ) { - step[i] = remaining; - remaining *= 0.982f; -} + for ( i = 0 ; i < 256 ; i++ ) { + step[i] = remaining; + remaining *= 0.982f; + } - for (x=0 ; x 255 ) { b = 255; } -b = (byte)(255 * ( 1.0 - step[b] )); - if ( x == 0 || x == FOG_SIZE-1 || y == 0 || y == FOG_SIZE-1 ) { + b = ( byte )( 255 * ( 1.0 - step[b] ) ); + + if ( x == 0 || x == FOG_SIZE - 1 || y == 0 || y == FOG_SIZE - 1 ) { b = 255; // avoid clamping issues } data[y][x][0] = @@ -775,12 +740,9 @@ b = (byte)(255 * ( 1.0 - step[b] )); data[y][x][3] = b; } } - - image->GenerateImage( (byte *)data, FOG_SIZE, FOG_SIZE, - TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY ); + image->GenerateImage( ( byte * )data, FOG_SIZE, FOG_SIZE, TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY ); } - /* ================ FogFraction @@ -791,19 +753,19 @@ Height values below zero are inside the fog volume static const float RAMP_RANGE = 8; static const float DEEP_RANGE = -30; static float FogFraction( float viewHeight, float targetHeight ) { - float total = idMath::Fabs( targetHeight - viewHeight ); - -// return targetHeight >= 0 ? 0 : 1.0; + // return targetHeight >= 0 ? 0 : 1.0; + float total = idMath::Fabs( targetHeight - viewHeight ); // only ranges that cross the ramp range are special if ( targetHeight > 0 && viewHeight > 0 ) { return 0.0; } + if ( targetHeight < -RAMP_RANGE && viewHeight < -RAMP_RANGE ) { return 1.0; } - float above; + if ( targetHeight > 0 ) { above = targetHeight; } else if ( viewHeight > 0 ) { @@ -811,7 +773,6 @@ static float FogFraction( float viewHeight, float targetHeight ) { } else { above = 0; } - float rampTop, rampBottom; if ( viewHeight > targetHeight ) { @@ -821,31 +782,29 @@ static float FogFraction( float viewHeight, float targetHeight ) { rampTop = targetHeight; rampBottom = viewHeight; } + if ( rampTop > 0 ) { rampTop = 0; } + if ( rampBottom < -RAMP_RANGE ) { rampBottom = -RAMP_RANGE; } - float rampSlope = 1.0 / RAMP_RANGE; if ( !total ) { return -viewHeight * rampSlope; } - float ramp = ( 1.0 - ( rampTop * rampSlope + rampBottom * rampSlope ) * -0.5 ) * ( rampTop - rampBottom ); - - float frac = ( total - above - ramp ) / total; + float frac = ( total - above - ramp ) / total; // after it gets moderately deep, always use full value float deepest = viewHeight < targetHeight ? viewHeight : targetHeight; + float deepFrac = deepest / DEEP_RANGE; - float deepFrac = deepest / DEEP_RANGE; if ( deepFrac >= 1.0 ) { return 1.0; } - frac = frac * ( 1.0 - deepFrac ) + deepFrac; return frac; @@ -860,17 +819,16 @@ start and end points to the terminator plane ================ */ void R_FogEnterImage( idImage *image ) { - int x,y; + int x, y; byte data[FOG_ENTER_SIZE][FOG_ENTER_SIZE][4]; int b; - for (x=0 ; x 255 ) { @@ -884,11 +842,9 @@ void R_FogEnterImage( idImage *image ) { } // if mipmapped, acutely viewed surfaces fade wrong - image->GenerateImage( (byte *)data, FOG_ENTER_SIZE, FOG_ENTER_SIZE, - TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY ); + image->GenerateImage( ( byte * )data, FOG_ENTER_SIZE, FOG_ENTER_SIZE, TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY ); } - /* ================ R_QuadraticImage @@ -899,24 +855,24 @@ static const int QUADRATIC_WIDTH = 32; static const int QUADRATIC_HEIGHT = 4; void R_QuadraticImage( idImage *image ) { - int x,y; + int x, y; byte data[QUADRATIC_HEIGHT][QUADRATIC_WIDTH][4]; int b; - - for (x=0 ; x 255 ) { @@ -928,21 +884,16 @@ void R_QuadraticImage( idImage *image ) { data[y][x][3] = 255; } } - - image->GenerateImage( (byte *)data, QUADRATIC_WIDTH, QUADRATIC_HEIGHT, - TF_DEFAULT, false, TR_CLAMP, TD_HIGH_QUALITY ); + image->GenerateImage( ( byte * )data, QUADRATIC_WIDTH, QUADRATIC_HEIGHT, TF_DEFAULT, false, TR_CLAMP, TD_HIGH_QUALITY ); } //===================================================================== - typedef struct { const char *name; int minimize, maximize; } filterName_t; - - /* =============== ChangeTextureFilter @@ -955,14 +906,14 @@ void idImageManager::ChangeTextureFilter( void ) { int i; idImage *glt; const char *string; -static const filterName_t textureFilters[] = { - {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, - {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}, - {"GL_NEAREST", GL_NEAREST, GL_NEAREST}, - {"GL_LINEAR", GL_LINEAR, GL_LINEAR}, - {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, - {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST} -}; + static const filterName_t textureFilters[] = { + {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, + {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}, + {"GL_NEAREST", GL_NEAREST, GL_NEAREST}, + {"GL_LINEAR", GL_LINEAR, GL_LINEAR}, + {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, + {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST} + }; // if these are changed dynamically, it will force another ChangeTextureFilter image_filter.ClearModified(); @@ -970,6 +921,7 @@ static const filterName_t textureFilters[] = { image_lodbias.ClearModified(); string = image_filter.GetString(); + for ( i = 0; i < 6; i++ ) { if ( !idStr::Icmp( textureFilters[i].name, string ) ) { break; @@ -977,7 +929,7 @@ static const filterName_t textureFilters[] = { } if ( i == 6 ) { - common->Warning( "bad r_textureFilter: '%s'", string); + common->Warning( "bad r_textureFilter: '%s'", string ); // default to LINEAR_MIPMAP_NEAREST i = 0; } @@ -986,6 +938,7 @@ static const filterName_t textureFilters[] = { textureMinFilter = textureFilters[i].minimize; textureMaxFilter = textureFilters[i].maximize; textureAnisotropy = image_anisotropy.GetFloat(); + if ( textureAnisotropy < 1 ) { textureAnisotropy = 1; } else if ( textureAnisotropy > glConfig.maxTextureAnisotropy ) { @@ -994,13 +947,12 @@ static const filterName_t textureFilters[] = { textureLODBias = image_lodbias.GetFloat(); // change all the existing mipmap texture objects with default filtering - for ( i = 0 ; i < images.Num() ; i++ ) { unsigned int texEnum = GL_TEXTURE_2D; glt = images[ i ]; - switch( glt->type ) { + switch ( glt->type ) { case TT_2D: texEnum = GL_TEXTURE_2D; break; @@ -1017,15 +969,18 @@ static const filterName_t textureFilters[] = { continue; } glt->Bind(); + if ( glt->filter == TF_DEFAULT ) { - qglTexParameterf(texEnum, GL_TEXTURE_MIN_FILTER, globalImages->textureMinFilter ); - qglTexParameterf(texEnum, GL_TEXTURE_MAG_FILTER, globalImages->textureMaxFilter ); + qglTexParameterf( texEnum, GL_TEXTURE_MIN_FILTER, globalImages->textureMinFilter ); + qglTexParameterf( texEnum, GL_TEXTURE_MAG_FILTER, globalImages->textureMaxFilter ); } + if ( glConfig.anisotropicAvailable ) { - qglTexParameterf(texEnum, GL_TEXTURE_MAX_ANISOTROPY_EXT, globalImages->textureAnisotropy ); + qglTexParameterf( texEnum, GL_TEXTURE_MAX_ANISOTROPY_EXT, globalImages->textureAnisotropy ); } + if ( glConfig.textureLODBiasAvailable ) { - qglTexParameterf(texEnum, GL_TEXTURE_LOD_BIAS_EXT, globalImages->textureLODBias ); + qglTexParameterf( texEnum, GL_TEXTURE_LOD_BIAS_EXT, globalImages->textureLODBias ); } } } @@ -1053,11 +1008,11 @@ void idImage::Reload( bool checkPrecompressed, bool force ) { // get the current values R_LoadImageProgram( imgName, NULL, NULL, NULL, ¤t ); } + if ( current <= timestamp ) { return; } } - common->DPrintf( "reloading %s.\n", imgName.c_str() ); PurgeImage(); @@ -1083,25 +1038,21 @@ reloadImages void R_ReloadImages_f( const idCmdArgs &args ) { int i; idImage *image; - bool all; - bool checkPrecompressed; + bool all = false; + bool checkPrecompressed = false; // if we are doing this as a vid_restart, look for precompressed like normal // DG: notify the game DLL about the reloadImages command - if(gameCallbacks.reloadImagesCB != NULL) - { - gameCallbacks.reloadImagesCB(gameCallbacks.reloadImagesUserArg, args); + if ( gameCallbacks.reloadImagesCB != NULL ) { + gameCallbacks.reloadImagesCB( gameCallbacks.reloadImagesUserArg, args ); } // this probably isn't necessary... globalImages->ChangeTextureFilter(); - all = false; - checkPrecompressed = false; // if we are doing this as a vid_restart, look for precompressed like normal - if ( args.Argc() == 2 ) { - if ( !idStr::Icmp( args.Argv(1), "all" ) ) { + if ( !idStr::Icmp( args.Argv( 1 ), "all" ) ) { all = true; - } else if ( !idStr::Icmp( args.Argv(1), "reload" ) ) { + } else if ( !idStr::Icmp( args.Argv( 1 ), "reload" ) ) { all = true; checkPrecompressed = true; } else { @@ -1130,12 +1081,13 @@ R_QsortImageSizes static int R_QsortImageSizes( const void *a, const void *b ) { const sortedImage_t *ea, *eb; - ea = (sortedImage_t *)a; - eb = (sortedImage_t *)b; + ea = ( sortedImage_t * )a; + eb = ( sortedImage_t * )b; if ( ea->size > eb->size ) { return -1; } + if ( ea->size < eb->size ) { return 1; } @@ -1166,7 +1118,7 @@ void R_ListImages_f( const idCmdArgs &args ) { bool overSized = false; if ( args.Argc() == 1 ) { - + /* nope */ } else if ( args.Argc() == 2 ) { if ( idStr::Icmp( args.Argv( 1 ), "uncompressed" ) == 0 ) { uncompressedOnly = true; @@ -1204,20 +1156,20 @@ void R_ListImages_f( const idCmdArgs &args ) { common->Printf( "usage: listImages [ sorted | partial | unloaded | cached | uncached | tagged | duplicated | touched | classify | showOverSized ]\n" ); return; } - const char *header = " -w-- -h-- filt -fmt-- wrap size --name-------\n"; + common->Printf( "\n%s", header ); totalSize = 0; - sortedImage_t *sortedArray = (sortedImage_t *)_alloca( sizeof( sortedImage_t ) * globalImages->images.Num() ); + sortedImage_t *sortedArray = ( sortedImage_t * )_alloca( sizeof( sortedImage_t ) * globalImages->images.Num() ); for ( i = 0 ; i < globalImages->images.Num() ; i++ ) { image = globalImages->images[ i ]; if ( uncompressedOnly ) { - if ( ( image->internalFormat >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT && image->internalFormat <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) - || image->internalFormat == GL_COLOR_INDEX8_EXT ) { + if ( ( image->internalFormat >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT && image->internalFormat <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) || + image->internalFormat == GL_COLOR_INDEX8_EXT ) { continue; } } @@ -1225,15 +1177,19 @@ void R_ListImages_f( const idCmdArgs &args ) { if ( matchTag && image->classification != matchTag ) { continue; } + if ( unloaded && image->texnum != idImage::TEXTURE_NOT_LOADED ) { continue; } + if ( partial && !image->isPartialImage ) { continue; } + if ( cached && ( !image->partialImage || image->texnum == idImage::TEXTURE_NOT_LOADED ) ) { continue; } + if ( uncached && ( !image->partialImage || image->texnum != idImage::TEXTURE_NOT_LOADED ) ) { continue; } @@ -1241,11 +1197,13 @@ void R_ListImages_f( const idCmdArgs &args ) { // only print duplicates (from mismatched wrap / clamp, etc) if ( duplicated ) { int j; - for ( j = i+1 ; j < globalImages->images.Num() ; j++ ) { + + for ( j = i + 1 ; j < globalImages->images.Num() ; j++ ) { if ( idStr::Icmp( image->imgName, globalImages->images[ j ]->imgName ) == 0 ) { break; } } + if ( j == globalImages->images.Num() ) { continue; } @@ -1273,23 +1231,23 @@ void R_ListImages_f( const idCmdArgs &args ) { if ( sorted ) { qsort( sortedArray, count, sizeof( sortedImage_t ), R_QsortImageSizes ); partialSize = 0; + for ( i = 0 ; i < count ; i++ ) { common->Printf( "%4i:", i ); sortedArray[i].image->Print(); partialSize += sortedArray[i].image->StorageSize(); - if ( ( (i+1) % 10 ) == 0 ) { + + if ( ( ( i + 1 ) % 10 ) == 0 ) { common->Printf( "-------- %5.1f of %5.1f megs --------\n", - partialSize / (1024*1024.0), totalSize / (1024*1024.0) ); + partialSize / ( 1024 * 1024.0 ), totalSize / ( 1024 * 1024.0 ) ); } } } - common->Printf( "%s", header ); common->Printf( " %i images (%i total)\n", count, globalImages->images.Num() ); - common->Printf( " %5.1f total megabytes of images\n\n\n", totalSize / (1024*1024.0) ); + common->Printf( " %5.1f total megabytes of images\n\n\n", totalSize / ( 1024 * 1024.0 ) ); if ( byClassification ) { - idList< int > classifications[IC_COUNT]; for ( i = 0 ; i < count ; i++ ) { @@ -1300,17 +1258,21 @@ void R_ListImages_f( const idCmdArgs &args ) { for ( i = 0; i < IC_COUNT; i++ ) { partialSize = 0; idList< int > overSizedList; + for ( j = 0; j < classifications[ i ].Num(); j++ ) { partialSize += sortedArray[ classifications[ i ][ j ] ].image->StorageSize(); + if ( overSized ) { if ( sortedArray[ classifications[ i ][ j ] ].image->uploadWidth > IC_Info[i].maxWidth && sortedArray[ classifications[ i ][ j ] ].image->uploadHeight > IC_Info[i].maxHeight ) { overSizedList.Append( classifications[ i ][ j ] ); } } } - common->Printf ( " Classification %s contains %i images using %5.1f megabytes\n", IC_Info[i].desc, classifications[i].Num(), partialSize / ( 1024*1024.0 ) ); + common->Printf( " Classification %s contains %i images using %5.1f megabytes\n", IC_Info[i].desc, classifications[i].Num(), partialSize / ( 1024 * 1024.0 ) ); + if ( overSized && overSizedList.Num() ) { common->Printf( " The following images may be oversized\n" ); + for ( j = 0; j < overSizedList.Num(); j++ ) { common->Printf( " " ); sortedArray[ overSizedList[ j ] ].image->Print(); @@ -1333,7 +1295,6 @@ void idImageManager::SetNormalPalette( void ) { int i, j; idVec3 v; float t; - //byte temptable[768]; byte *temptable = compressedPalette; int compressedToOriginal[16]; @@ -1345,8 +1306,8 @@ void idImageManager::SetNormalPalette( void ) { y = idMath::Sqrt( 1.0 - f * f ); y = 1.0 - y; - compressedToOriginal[7-i] = 127 - (int)( y * 127 + 0.5 ); - compressedToOriginal[8+i] = 128 + (int)( y * 127 + 0.5 ); + compressedToOriginal[7 - i] = 127 - ( int )( y * 127 + 0.5 ); + compressedToOriginal[8 + i] = 128 + ( int )( y * 127 + 0.5 ); } for ( i = 0 ; i < 256 ; i++ ) { @@ -1356,11 +1317,12 @@ void idImageManager::SetNormalPalette( void ) { originalToCompressed[i] = 15; } else { for ( j = 0 ; j < 14 ; j++ ) { - if ( i <= compressedToOriginal[j+1] ) { + if ( i <= compressedToOriginal[j + 1] ) { break; } } - if ( i - compressedToOriginal[j] < compressedToOriginal[j+1] - i ) { + + if ( i - compressedToOriginal[j] < compressedToOriginal[j + 1] - i ) { originalToCompressed[i] = j; } else { originalToCompressed[i] = j + 1; @@ -1368,59 +1330,38 @@ void idImageManager::SetNormalPalette( void ) { } } -#if 0 - for ( i = 0; i < 16; i++ ) { - for ( j = 0 ; j < 16 ; j++ ) { - - v[0] = ( i - 7.5 ) / 8; - v[1] = ( j - 7.5 ) / 8; - - t = 1.0 - ( v[0]*v[0] + v[1]*v[1] ); - if ( t < 0 ) { - t = 0; - } - v[2] = idMath::Sqrt( t ); - - temptable[(i*16+j)*3+0] = 128 + floor( 127 * v[0] + 0.5 ); - temptable[(i*16+j)*3+1] = 128 + floor( 127 * v[1] ); - temptable[(i*16+j)*3+2] = 128 + floor( 127 * v[2] ); - } - } -#else for ( i = 0; i < 16; i++ ) { for ( j = 0 ; j < 16 ; j++ ) { v[0] = ( compressedToOriginal[i] - 127.5 ) / 128; v[1] = ( compressedToOriginal[j] - 127.5 ) / 128; - t = 1.0 - ( v[0]*v[0] + v[1]*v[1] ); + t = 1.0 - ( v[0] * v[0] + v[1] * v[1] ); if ( t < 0 ) { t = 0; } v[2] = idMath::Sqrt( t ); - temptable[(i*16+j)*3+0] = (byte)(128 + floor( 127 * v[0] + 0.5 )); - temptable[(i*16+j)*3+1] = (byte)(128 + floor( 127 * v[1] )); - temptable[(i*16+j)*3+2] = (byte)(128 + floor( 127 * v[2] )); + temptable[( i * 16 + j ) * 3 + 0] = ( byte )( 128 + floor( 127 * v[0] + 0.5 ) ); + temptable[( i * 16 + j ) * 3 + 1] = ( byte )( 128 + floor( 127 * v[1] ) ); + temptable[( i * 16 + j ) * 3 + 2] = ( byte )( 128 + floor( 127 * v[2] ) ); } } -#endif // color 255 will be the "nullnormal" color for no reflection - temptable[255*3+0] = - temptable[255*3+1] = - temptable[255*3+2] = 128; + temptable[255 * 3 + 0] = + temptable[255 * 3 + 1] = + temptable[255 * 3 + 2] = 128; if ( !glConfig.sharedTexturePaletteAvailable ) { return; } - qglColorTableEXT( GL_SHARED_TEXTURE_PALETTE_EXT, - GL_RGB, - 256, - GL_RGB, - GL_UNSIGNED_BYTE, - temptable ); + GL_RGB, + 256, + GL_RGB, + GL_UNSIGNED_BYTE, + temptable ); qglEnable( GL_SHARED_TEXTURE_PALETTE_EXT ); } @@ -1435,12 +1376,11 @@ copies the name, and adds it to the hash chain. */ idImage *idImageManager::AllocImage( const char *name ) { idImage *image; - int hash; + int hash; - if (strlen(name) >= MAX_IMAGE_NAME ) { - common->Error ("idImageManager::AllocImage: \"%s\" is too long\n", name); + if ( strlen( name ) >= MAX_IMAGE_NAME ) { + common->Error( "idImageManager::AllocImage: \"%s\" is too long\n", name ); } - hash = idStr( name ).FileNameHash(); image = new idImage; @@ -1463,7 +1403,7 @@ with a callback which must work at any time, allowing the OpenGL system to be completely regenerated if needed. ================== */ -idImage *idImageManager::ImageFromFunction( const char *_name, void (*generatorFunction)( idImage *image ) ) { +idImage *idImageManager::ImageFromFunction( const char *_name, void ( *generatorFunction )( idImage *image ) ) { idStr name; idImage *image; int hash; @@ -1479,6 +1419,7 @@ idImage *idImageManager::ImageFromFunction( const char *_name, void (*generatorF // see if the image already exists hash = name.FileNameHash(); + for ( image = imageHashTable[hash] ; image; image = image->hashNext ) { if ( name.Icmp( image->imgName ) == 0 ) { if ( image->generatorFunction != generatorFunction ) { @@ -1498,7 +1439,6 @@ idImage *idImageManager::ImageFromFunction( const char *_name, void (*generatorF image->referencedOutsideLevelLoad = true; image->ActuallyLoadImage( true, false ); } - return image; } @@ -1511,7 +1451,7 @@ Loading of the image may be deferred for dynamic loading. ============== */ idImage *idImageManager::ImageFromFile( const char *_name, textureFilter_t filter, bool allowDownSize, - textureRepeat_t repeat, textureDepth_t depth, cubeFiles_t cubeMap ) { + textureRepeat_t repeat, textureDepth_t depth, cubeFiles_t cubeMap ) { idStr name; idImage *image; int hash; @@ -1531,12 +1471,14 @@ idImage *idImageManager::ImageFromFile( const char *_name, textureFilter_t filte // are in a reloadImages call // hash = name.FileNameHash(); + for ( image = imageHashTable[hash]; image; image = image->hashNext ) { if ( name.Icmp( image->imgName ) == 0 ) { // the built in's, like _white and _flat always match the other options if ( name[0] == '_' ) { return image; } + if ( image->cubeFiles != cubeMap ) { common->Error( "Image '%s' has been referenced with conflicting cube map states", _name ); } @@ -1550,6 +1492,7 @@ idImage *idImageManager::ImageFromFile( const char *_name, textureFilter_t filte if ( image->allowDownSize == allowDownSize && image->depth == depth ) { // note that it is used this level load image->levelLoadReferenced = true; + if ( image->partialImage != NULL ) { image->partialImage->levelLoadReferenced = true; } @@ -1561,24 +1504,28 @@ idImage *idImageManager::ImageFromFile( const char *_name, textureFilter_t filte if ( !image->allowDownSize ) { allowDownSize = false; } + if ( image->depth > depth ) { depth = image->depth; } + if ( image->allowDownSize == allowDownSize && image->depth == depth ) { // the already created one is already the highest quality image->levelLoadReferenced = true; + if ( image->partialImage != NULL ) { image->partialImage->levelLoadReferenced = true; } return image; } - image->allowDownSize = allowDownSize; image->depth = depth; image->levelLoadReferenced = true; + if ( image->partialImage != NULL ) { image->partialImage->levelLoadReferenced = true; } + if ( image_preload.GetBool() && !insideLevelLoad ) { image->referencedOutsideLevelLoad = true; image->ActuallyLoadImage( true, false ); // check for precompressed, load is from front end @@ -1595,17 +1542,15 @@ idImage *idImageManager::ImageFromFile( const char *_name, textureFilter_t filte // HACK: to allow keep fonts from being mip'd, as new ones will be introduced with localization // this keeps us from having to make a material for each font tga - if ( name.Find( "fontImage_") >= 0 ) { + if ( name.Find( "fontImage_" ) >= 0 ) { allowDownSize = false; } - image->allowDownSize = allowDownSize; image->repeat = repeat; image->depth = depth; image->type = TT_2D; image->cubeFiles = cubeMap; image->filter = filter; - image->levelLoadReferenced = true; // also create a shrunken version if we are going to dynamically cache the full size image @@ -1648,7 +1593,6 @@ idImage *idImageManager::ImageFromFile( const char *_name, textureFilter_t filte } else { declManager->MediaPrint( "%s\n", image->imgName.c_str() ); } - return image; } @@ -1676,12 +1620,12 @@ idImage *idImageManager::GetImage( const char *_name ) const { // look in loaded images // hash = name.FileNameHash(); + for ( image = imageHashTable[hash]; image; image = image->hashNext ) { if ( name.Icmp( image->imgName ) == 0 ) { return image; } } - return NULL; } @@ -1730,8 +1674,8 @@ void R_CombineCubeImages_f( const idCmdArgs &args ) { common->Printf( " 1: forward 2:right 3:back 4:left 5:up 6:down\n" ); return; } - idStr baseName = args.Argv( 1 ); + common->SetRefreshOnPrint( true ); for ( int frameNum = 1 ; frameNum < 10000 ; frameNum++ ) { @@ -1739,11 +1683,12 @@ void R_CombineCubeImages_f( const idCmdArgs &args ) { byte *pics[6]; int width, height; int side; - int orderRemap[6] = { 1,3,4,2,5,6 }; + int orderRemap[6] = { 1, 3, 4, 2, 5, 6 }; + for ( side = 0 ; side < 6 ; side++ ) { sprintf( filename, "%s%i%04i.tga", baseName.c_str(), orderRemap[side], frameNum ); - common->Printf( "reading %s\n", filename ); + R_LoadImage( filename, &pics[side], &width, &height, NULL, true ); if ( !pics[side] ) { @@ -1752,12 +1697,12 @@ void R_CombineCubeImages_f( const idCmdArgs &args ) { } // convert from "camera" images to native cube map images - switch( side ) { + switch ( side ) { case 0: // forward - R_RotatePic( pics[side], width); + R_RotatePic( pics[side], width ); break; case 1: // back - R_RotatePic( pics[side], width); + R_RotatePic( pics[side], width ); R_HorizontalFlip( pics[side], width, height ); R_VerticalFlip( pics[side], width, height ); break; @@ -1768,10 +1713,10 @@ void R_CombineCubeImages_f( const idCmdArgs &args ) { R_HorizontalFlip( pics[side], width, height ); break; case 4: // up - R_RotatePic( pics[side], width); + R_RotatePic( pics[side], width ); break; case 5: // down - R_RotatePic( pics[side], width); + R_RotatePic( pics[side], width ); break; } } @@ -1782,16 +1727,16 @@ void R_CombineCubeImages_f( const idCmdArgs &args ) { } break; } + byte *combined = ( byte * )Mem_Alloc( width * height * 6 * 4 ); - byte *combined = (byte *)Mem_Alloc( width*height*6*4 ); - for ( side = 0 ; side < 6 ; side++ ) { - memcpy( combined+width*height*4*side, pics[side], width*height*4 ); + for ( side = 0 ; side < 6 ; side++ ) { + memcpy( combined + width * height * 4 * side, pics[side], width * height * 4 ); Mem_Free( pics[side] ); } sprintf( filename, "%sCM%04i.tga", baseName.c_str(), frameNum ); - common->Printf( "writing %s\n", filename ); - R_WriteTGA( filename, combined, width, height*6 ); + + R_WriteTGA( filename, combined, width, height * 6 ); Mem_Free( combined ); } @@ -1808,6 +1753,7 @@ void idImage::StartBackgroundImageLoad() { if ( imageManager.numActiveBackgroundImageLoads >= idImageManager::MAX_BACKGROUND_IMAGE_LOADS ) { return; } + if ( globalImages->image_showBackgroundLoads.GetBool() ) { common->Printf( "idImage::StartBackgroundImageLoad: %s\n", imgName.c_str() ); } @@ -1817,11 +1763,10 @@ void idImage::StartBackgroundImageLoad() { common->Warning( "idImageManager::StartBackgroundImageLoad: %s wasn't a precompressed file", imgName.c_str() ); return; } - bglNext = globalImages->backgroundImageLoads; globalImages->backgroundImageLoads = this; - char filename[MAX_IMAGE_NAME]; + char filename[MAX_IMAGE_NAME]; ImageProgramStringToCompressedFileName( imgName, filename ); bgl.completed = false; @@ -1832,19 +1777,17 @@ void idImage::StartBackgroundImageLoad() { } bgl.file.position = 0; bgl.file.length = bgl.f->Length(); + if ( bgl.file.length < sizeof( ddsFileHeader_t ) ) { common->Warning( "idImageManager::StartBackgroundImageLoad: %s had a bad file length", imgName.c_str() ); return; } - bgl.file.buffer = R_StaticAlloc( bgl.file.length ); - fileSystem->BackgroundDownload( &bgl ); - imageManager.numActiveBackgroundImageLoads++; // purge some images if necessary - int totalSize = 0; + int totalSize = 0; for ( idImage *check = globalImages->cacheLRU.cacheUsageNext ; check != &globalImages->cacheLRU ; check = check->cacheUsageNext ) { totalSize += check->StorageSize(); } @@ -1853,13 +1796,16 @@ void idImage::StartBackgroundImageLoad() { while ( ( totalSize + needed ) > globalImages->image_cacheMegs.GetFloat() * 1024 * 1024 ) { // purge the least recently used idImage *check = globalImages->cacheLRU.cacheUsagePrev; + if ( check->texnum != TEXTURE_NOT_LOADED ) { totalSize -= check->StorageSize(); + if ( globalImages->image_showBackgroundLoads.GetBool() ) { common->Printf( "purging %s\n", check->imgName.c_str() ); } check->PurgeImage(); } + // remove it from the cached list check->cacheUsageNext->cacheUsagePrev = check->cacheUsagePrev; check->cacheUsagePrev->cacheUsageNext = check->cacheUsageNext; @@ -1881,12 +1827,15 @@ void idImageManager::CompleteBackgroundImageLoads() { for ( idImage *image = backgroundImageLoads ; image ; image = next ) { next = image->bglNext; + if ( image->bgl.completed ) { numActiveBackgroundImageLoads--; fileSystem->CloseFile( image->bgl.f ); + // upload the image - image->UploadPrecompressedImage( (byte *)image->bgl.file.buffer, image->bgl.file.length ); + image->UploadPrecompressedImage( ( byte * )image->bgl.file.buffer, image->bgl.file.length ); R_StaticFree( image->bgl.file.buffer ); + if ( image_showBackgroundLoads.GetBool() ) { common->Printf( "R_CompleteBackgroundImageLoad: %s\n", image->imgName.c_str() ); } @@ -1895,14 +1844,15 @@ void idImageManager::CompleteBackgroundImageLoads() { remainingList = image; } } + if ( image_showBackgroundLoads.GetBool() ) { static int prev; + if ( numActiveBackgroundImageLoads != prev ) { prev = numActiveBackgroundImageLoads; common->Printf( "background Loads: %i\n", numActiveBackgroundImageLoads ); } } - backgroundImageLoads = remainingList; } @@ -1932,13 +1882,14 @@ int idImageManager::SumOfUsedImages() { idImage *image; total = 0; + for ( i = 0; i < images.Num(); i++ ) { image = images[i]; + if ( image->frameUsed == backEnd.frameCount ) { total += image->StorageSize(); } } - return total; } @@ -1948,9 +1899,7 @@ BindNull =============== */ void idImageManager::BindNull() { - tmu_t *tmu; - - tmu = &backEnd.glState.tmu[backEnd.glState.currenttmu]; + tmu_t *tmu = &backEnd.glState.tmu[backEnd.glState.currenttmu]; if ( tmu->textureType == TT_CUBIC ) { qglDisable( GL_TEXTURE_CUBE_MAP_EXT ); @@ -1969,7 +1918,7 @@ Init */ void idImageManager::Init() { - memset(imageHashTable, 0, sizeof(imageHashTable)); + memset( imageHashTable, 0, sizeof( imageHashTable ) ); images.Resize( 1024, 1024 ); @@ -2000,12 +1949,12 @@ void idImageManager::Init() { // cinematicImage is used for cinematic drawing // scratchImage is used for screen wipes/doublevision etc.. - cinematicImage = ImageFromFunction("_cinematic", R_RGBA8Image ); - scratchImage = ImageFromFunction("_scratch", R_RGBA8Image ); - scratchImage2 = ImageFromFunction("_scratch2", R_RGBA8Image ); - accumImage = ImageFromFunction("_accum", R_RGBA8Image ); - scratchCubeMapImage = ImageFromFunction("_scratchCubeMap", makeNormalizeVectorCubeMap ); - currentRenderImage = ImageFromFunction("_currentRender", R_RGBA8Image ); + cinematicImage = ImageFromFunction( "_cinematic", R_RGBA8Image ); + scratchImage = ImageFromFunction( "_scratch", R_RGBA8Image ); + scratchImage2 = ImageFromFunction( "_scratch2", R_RGBA8Image ); + accumImage = ImageFromFunction( "_accum", R_RGBA8Image ); + scratchCubeMapImage = ImageFromFunction( "_scratchCubeMap", makeNormalizeVectorCubeMap ); + currentRenderImage = ImageFromFunction( "_currentRender", R_RGBA8Image ); currentDepthImage = ImageFromFunction( "_currentDepth", R_DepthImage ); // #3877. Allow shaders to access scene depth cmdSystem->AddCommand( "reloadImages", R_ReloadImages_f, CMD_FL_RENDERER, "reloads images" ); @@ -2089,11 +2038,11 @@ void idImageManager::EndLevelLoad() { } if ( !image->levelLoadReferenced && !image->referencedOutsideLevelLoad ) { -// common->Printf( "Purging %s\n", image->imgName.c_str() ); + // common->Printf( "Purging %s\n", image->imgName.c_str() ); purgeCount++; image->PurgeImage(); } else if ( image->texnum != idImage::TEXTURE_NOT_LOADED ) { -// common->Printf( "Keeping %s\n", image->imgName.c_str() ); + // common->Printf( "Keeping %s\n", image->imgName.c_str() ); keepCount++; } } @@ -2106,7 +2055,7 @@ void idImageManager::EndLevelLoad() { } if ( image->levelLoadReferenced && image->texnum == idImage::TEXTURE_NOT_LOADED && !image->partialImage ) { -// common->Printf( "Loading %s\n", image->imgName.c_str() ); + // common->Printf( "Loading %s\n", image->imgName.c_str() ); loadCount++; image->ActuallyLoadImage( true, false ); @@ -2120,7 +2069,7 @@ void idImageManager::EndLevelLoad() { common->Printf( "%5i purged from previous\n", purgeCount ); common->Printf( "%5i kept from previous\n", keepCount ); common->Printf( "%5i new loaded\n", loadCount ); - common->Printf( "all images loaded in %5.1f seconds\n", (end-start) * 0.001 ); + common->Printf( "all images loaded in %5.1f seconds\n", ( end - start ) * 0.001 ); } /* @@ -2143,7 +2092,7 @@ void idImageManager::FinishBuild( bool removeDups ) { if ( removeDups ) { ddsList.Clear(); char *buffer = NULL; - fileSystem->ReadFile( "makedds.bat", (void**)&buffer ); + fileSystem->ReadFile( "makedds.bat", ( void ** )&buffer ); if ( buffer ) { idStr str = buffer; while ( str.Length() ) { @@ -2167,7 +2116,7 @@ void idImageManager::FinishBuild( bool removeDups ) { for ( i = 0; i < ddsNum; i++ ) { batchFile->WriteFloatString( "%s", ddsList[ i ].c_str() ); - batchFile->Printf( "@echo Finished compressing %d of %d. %.1f percent done.\n", i+1, ddsNum, ((float)(i+1)/(float)ddsNum)*100.f ); + batchFile->Printf( "@echo Finished compressing %d of %d. %.1f percent done.\n", i + 1, ddsNum, ( ( float )( i + 1 ) / ( float )ddsNum ) * 100.f ); } fileSystem->CloseFile( batchFile ); } diff --git a/neo/renderer/Image_load.cpp b/neo/renderer/Image_load.cpp index 0702c6d5c..c2851ac15 100644 --- a/neo/renderer/Image_load.cpp +++ b/neo/renderer/Image_load.cpp @@ -35,20 +35,19 @@ If you have questions concerning this license or the applicable additional terms /* PROBLEM: compressed textures may break the zero clamp rule! */ - static bool FormatIsDXT( int internalFormat ) { - if ( internalFormat < GL_COMPRESSED_RGB_S3TC_DXT1_EXT - || internalFormat > GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) { - return false; - } - return true; + if ( internalFormat < GL_COMPRESSED_RGB_S3TC_DXT1_EXT || + internalFormat > GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) { + return false; + } + return true; } int MakePowerOfTwo( int num ) { - int pot; - for (pot = 1 ; pot < num ; pot<<=1) { - } - return pot; + int pot; + for ( pot = 1 ; pot < num ; pot <<= 1 ) { + } + return pot; } /* @@ -59,49 +58,49 @@ Used for determining memory utilization ================ */ int idImage::BitsForInternalFormat( int internalFormat ) const { - switch ( internalFormat ) { - case GL_INTENSITY8: - case 1: - return 8; - case 2: - case GL_LUMINANCE8_ALPHA8: - return 16; - case 3: - return 32; // on some future hardware, this may actually be 24, but be conservative - case 4: - return 32; - case GL_LUMINANCE8: - return 8; - case GL_ALPHA8: - return 8; - case GL_RGBA8: - return 32; - case GL_RGB8: - return 32; // on some future hardware, this may actually be 24, but be conservative - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - return 4; - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - return 4; - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - return 8; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - return 8; - case GL_RGBA4: - return 16; - case GL_RGB5: - return 16; - case GL_COLOR_INDEX8_EXT: - return 8; - case GL_COLOR_INDEX: - return 8; - case GL_COMPRESSED_RGB_ARB: - return 4; // not sure - case GL_COMPRESSED_RGBA_ARB: - return 8; // not sure - default: - common->Error( "R_BitsForInternalFormat: BAD FORMAT:%i", internalFormat ); - } - return 0; + switch ( internalFormat ) { + case GL_INTENSITY8: + case 1: + return 8; + case 2: + case GL_LUMINANCE8_ALPHA8: + return 16; + case 3: + return 32; // on some future hardware, this may actually be 24, but be conservative + case 4: + return 32; + case GL_LUMINANCE8: + return 8; + case GL_ALPHA8: + return 8; + case GL_RGBA8: + return 32; + case GL_RGB8: + return 32; // on some future hardware, this may actually be 24, but be conservative + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + return 4; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + return 4; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + return 8; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + return 8; + case GL_RGBA4: + return 16; + case GL_RGB5: + return 16; + case GL_COLOR_INDEX8_EXT: + return 8; + case GL_COLOR_INDEX: + return 8; + case GL_COMPRESSED_RGB_ARB: + return 4; // not sure + case GL_COMPRESSED_RGBA_ARB: + return 8; // not sure + default: + common->Error( "R_BitsForInternalFormat: BAD FORMAT:%i", internalFormat ); + } + return 0; } /* @@ -112,90 +111,91 @@ Create a 256 color palette to be used by compressed normal maps ================== */ void idImage::UploadCompressedNormalMap( int width, int height, const byte *rgba, int mipLevel ) { - byte *normals; - const byte *in; - byte *out; - int i, j; - int x, y, z; - int row; - - // OpenGL's pixel packing rule - row = width < 4 ? 4 : width; - - normals = (byte *)_alloca( row * height ); - if ( !normals ) { - common->Error( "R_UploadCompressedNormalMap: _alloca failed" ); - } - - in = rgba; - out = normals; - for ( i = 0 ; i < height ; i++, out += row, in += width * 4 ) { - for ( j = 0 ; j < width ; j++ ) { - x = in[ j * 4 + 0 ]; - y = in[ j * 4 + 1 ]; - z = in[ j * 4 + 2 ]; - - int c; - if ( x == 128 && y == 128 && z == 128 ) { - // the "nullnormal" color - c = 255; - } else { - c = ( globalImages->originalToCompressed[x] << 4 ) | globalImages->originalToCompressed[y]; - if ( c == 255 ) { - c = 254; // don't use the nullnormal color - } - } - out[j] = c; - } - } - - if ( mipLevel == 0 ) { - // Optionally write out the paletized normal map to a .tga - if ( globalImages->image_writeNormalTGAPalletized.GetBool() ) { - char filename[MAX_IMAGE_NAME]; - ImageProgramStringToCompressedFileName( imgName, filename ); - char *ext = strrchr(filename, '.'); - if ( ext ) { - strcpy(ext, "_pal.tga"); - R_WritePalTGA( filename, normals, globalImages->compressedPalette, width, height); - } - } - } - - if ( glConfig.sharedTexturePaletteAvailable ) { - qglTexImage2D( GL_TEXTURE_2D, - mipLevel, - GL_COLOR_INDEX8_EXT, - width, - height, - 0, - GL_COLOR_INDEX, - GL_UNSIGNED_BYTE, - normals ); - } + byte *normals; + const byte *in; + byte *out; + int i, j; + int x, y, z; + int row; + + // OpenGL's pixel packing rule + row = width < 4 ? 4 : width; + normals = ( byte * )_alloca( row * height ); + + if ( !normals ) { + common->Error( "R_UploadCompressedNormalMap: _alloca failed" ); + } + in = rgba; + out = normals; + + for ( i = 0 ; i < height ; i++, out += row, in += width * 4 ) { + for ( j = 0 ; j < width ; j++ ) { + int c; + + x = in[ j * 4 + 0 ]; + y = in[ j * 4 + 1 ]; + z = in[ j * 4 + 2 ]; + + if ( x == 128 && y == 128 && z == 128 ) { + // the "nullnormal" color + c = 255; + } else { + c = ( globalImages->originalToCompressed[x] << 4 ) | globalImages->originalToCompressed[y]; + if ( c == 255 ) { + c = 254; // don't use the nullnormal color + } + } + out[j] = c; + } + } + + if ( mipLevel == 0 ) { + // Optionally write out the paletized normal map to a .tga + if ( globalImages->image_writeNormalTGAPalletized.GetBool() ) { + char filename[MAX_IMAGE_NAME]; + ImageProgramStringToCompressedFileName( imgName, filename ); + char *ext = strrchr( filename, '.' ); + if ( ext ) { + strcpy( ext, "_pal.tga" ); + R_WritePalTGA( filename, normals, globalImages->compressedPalette, width, height ); + } + } + } + + if ( glConfig.sharedTexturePaletteAvailable ) { + qglTexImage2D( GL_TEXTURE_2D, + mipLevel, + GL_COLOR_INDEX8_EXT, + width, + height, + 0, + GL_COLOR_INDEX, + GL_UNSIGNED_BYTE, + normals ); + } } //======================================================================= -static byte mipBlendColors[16][4] = { - {0,0,0,0}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, - {255,0,0,128}, - {0,255,0,128}, - {0,0,255,128}, +static byte mipBlendColors[16][4] = { + {0, 0, 0, 0}, + {255, 0, 0, 128}, + {0, 255, 0, 128}, + {0, 0, 255, 128}, + {255, 0, 0, 128}, + {0, 255, 0, 128}, + {0, 0, 255, 128}, + {255, 0, 0, 128}, + {0, 255, 0, 128}, + {0, 0, 255, 128}, + {255, 0, 0, 128}, + {0, 255, 0, 128}, + {0, 0, 255, 128}, + {255, 0, 0, 128}, + {0, 255, 0, 128}, + {0, 0, 255, 128}, }; /* @@ -206,149 +206,155 @@ This may need to scan six cube map images =============== */ GLenum idImage::SelectInternalFormat( const byte **dataPtrs, int numDataPtrs, int width, int height, - textureDepth_t minimumDepth ) const { - int i, c; - const byte *scan; - int rgbOr, rgbAnd, aOr, aAnd; - int rgbDiffer, rgbaDiffer; - - // determine if the rgb channels are all the same - // and if either all rgb or all alpha are 255 - c = width*height; - rgbDiffer = 0; - rgbaDiffer = 0; - rgbOr = 0; - rgbAnd = -1; - aOr = 0; - aAnd = -1; - - for ( int side = 0 ; side < numDataPtrs ; side++ ) { - scan = dataPtrs[side]; - for ( i = 0; i < c; i++, scan += 4 ) { - int cor, cand; - - aOr |= scan[3]; - aAnd &= scan[3]; - - cor = scan[0] | scan[1] | scan[2]; - cand = scan[0] & scan[1] & scan[2]; - - // if rgb are all the same, the or and and will match - rgbDiffer |= ( cor ^ cand ); - - rgbOr |= cor; - rgbAnd &= cand; - - cor |= scan[3]; - cand &= scan[3]; - - rgbaDiffer |= ( cor ^ cand ); - } - } - - // we assume that all 0 implies that the alpha channel isn't needed, - // because some tools will spit out 32 bit images with a 0 alpha instead - // of 255 alpha, but if the alpha actually is referenced, there will be - // different behavior in the compressed vs uncompressed states. - bool needAlpha; - if ( aAnd == 255 || aOr == 0 ) { - needAlpha = false; - } else { - needAlpha = true; - } - - // catch normal maps first - if ( minimumDepth == TD_BUMP ) { - if ( globalImages->image_useCompression.GetBool() && globalImages->image_useNormalCompression.GetInteger() == 1 && glConfig.sharedTexturePaletteAvailable ) { - // image_useNormalCompression should only be set to 1 on nv_10 and nv_20 paths - return GL_COLOR_INDEX8_EXT; - } else if ( globalImages->image_useCompression.GetBool() && globalImages->image_useNormalCompression.GetInteger() && glConfig.textureCompressionAvailable ) { - // image_useNormalCompression == 2 uses rxgb format which produces really good quality for medium settings - return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - } else { - // we always need the alpha channel for bump maps for swizzling - return GL_RGBA8; - } - } - - // allow a complete override of image compression with a cvar - if ( !globalImages->image_useCompression.GetBool() ) { - minimumDepth = TD_HIGH_QUALITY; - } - - if ( minimumDepth == TD_SPECULAR ) { - // we are assuming that any alpha channel is unintentional - if ( glConfig.textureCompressionAvailable ) { - return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; - } else { - return GL_RGB5; - } - } - if ( minimumDepth == TD_DIFFUSE ) { - // we might intentionally have an alpha channel for alpha tested textures - if ( glConfig.textureCompressionAvailable ) { - if ( !needAlpha ) { - return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; - } else { - return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - } - } else if ( ( aAnd == 255 || aOr == 0 ) ) { - return GL_RGB5; - } else { - return GL_RGBA4; - } - } - - // there will probably be some drivers that don't - // correctly handle the intensity/alpha/luminance/luminance+alpha - // formats, so provide a fallback that only uses the rgb/rgba formats - if ( !globalImages->image_useAllFormats.GetBool() ) { - // pretend rgb is varying and inconsistant, which - // prevents any of the more compact forms - rgbDiffer = 1; - rgbaDiffer = 1; - rgbAnd = 0; - } - - // cases without alpha - if ( !needAlpha ) { - if ( minimumDepth == TD_HIGH_QUALITY ) { - return GL_RGB8; // four bytes - } - if ( glConfig.textureCompressionAvailable ) { - return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; // half byte - } - return GL_RGB5; // two bytes - } - - // cases with alpha - if ( !rgbaDiffer ) { - if ( minimumDepth != TD_HIGH_QUALITY && glConfig.textureCompressionAvailable ) { - return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; // one byte - } - return GL_INTENSITY8; // single byte for all channels - } + textureDepth_t minimumDepth ) const { + int i, c; + const byte *scan; + int rgbOr, rgbAnd, aOr, aAnd; + int rgbDiffer, rgbaDiffer; + + // determine if the rgb channels are all the same + // and if either all rgb or all alpha are 255 + c = width * height; + rgbDiffer = 0; + rgbaDiffer = 0; + rgbOr = 0; + rgbAnd = -1; + aOr = 0; + aAnd = -1; + + for ( int side = 0 ; side < numDataPtrs ; side++ ) { + scan = dataPtrs[side]; + + for ( i = 0; i < c; i++, scan += 4 ) { + int cor, cand; + + aOr |= scan[3]; + aAnd &= scan[3]; + + cor = scan[0] | scan[1] | scan[2]; + cand = scan[0] & scan[1] & scan[2]; + + // if rgb are all the same, the or and and will match + rgbDiffer |= ( cor ^ cand ); + + rgbOr |= cor; + rgbAnd &= cand; + + cor |= scan[3]; + cand &= scan[3]; + + rgbaDiffer |= ( cor ^ cand ); + } + } + + // we assume that all 0 implies that the alpha channel isn't needed, + // because some tools will spit out 32 bit images with a 0 alpha instead + // of 255 alpha, but if the alpha actually is referenced, there will be + // different behavior in the compressed vs uncompressed states. + bool needAlpha; + + if ( aAnd == 255 || aOr == 0 ) { + needAlpha = false; + } else { + needAlpha = true; + } + + // catch normal maps first + if ( minimumDepth == TD_BUMP ) { + if ( globalImages->image_useCompression.GetBool() && globalImages->image_useNormalCompression.GetInteger() == 1 && glConfig.sharedTexturePaletteAvailable ) { + // image_useNormalCompression should only be set to 1 on nv_10 and nv_20 paths + return GL_COLOR_INDEX8_EXT; + } else if ( globalImages->image_useCompression.GetBool() && globalImages->image_useNormalCompression.GetInteger() && glConfig.textureCompressionAvailable ) { + // image_useNormalCompression == 2 uses rxgb format which produces really good quality for medium settings + return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + } else { + // we always need the alpha channel for bump maps for swizzling + return GL_RGBA8; + } + } + + // allow a complete override of image compression with a cvar + if ( !globalImages->image_useCompression.GetBool() ) { + minimumDepth = TD_HIGH_QUALITY; + } + + if ( minimumDepth == TD_SPECULAR ) { + // we are assuming that any alpha channel is unintentional + if ( glConfig.textureCompressionAvailable ) { + return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + } else { + return GL_RGB5; + } + } + + if ( minimumDepth == TD_DIFFUSE ) { + // we might intentionally have an alpha channel for alpha tested textures + if ( glConfig.textureCompressionAvailable ) { + if ( !needAlpha ) { + return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + } else { + return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + } + } else if ( ( aAnd == 255 || aOr == 0 ) ) { + return GL_RGB5; + } else { + return GL_RGBA4; + } + } + + // there will probably be some drivers that don't + // correctly handle the intensity/alpha/luminance/luminance+alpha + // formats, so provide a fallback that only uses the rgb/rgba formats + if ( !globalImages->image_useAllFormats.GetBool() ) { + // pretend rgb is varying and inconsistant, which + // prevents any of the more compact forms + rgbDiffer = 1; + rgbaDiffer = 1; + rgbAnd = 0; + } + + // cases without alpha + if ( !needAlpha ) { + if ( minimumDepth == TD_HIGH_QUALITY ) { + return GL_RGB8; // four bytes + } + + if ( glConfig.textureCompressionAvailable ) { + return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; // half byte + } + return GL_RGB5; // two bytes + } + + // cases with alpha + if ( !rgbaDiffer ) { + if ( minimumDepth != TD_HIGH_QUALITY && glConfig.textureCompressionAvailable ) { + return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; // one byte + } + return GL_INTENSITY8; // single byte for all channels + } #if 0 - // we don't support alpha textures any more, because there - // is a discrepancy in the definition of TEX_ENV_COMBINE that - // causes them to be treated as 0 0 0 A, instead of 1 1 1 A as - // normal texture modulation treats them - if ( rgbAnd == 255 ) { - return GL_ALPHA8; // single byte, only alpha - } + // we don't support alpha textures any more, because there + // is a discrepancy in the definition of TEX_ENV_COMBINE that + // causes them to be treated as 0 0 0 A, instead of 1 1 1 A as + // normal texture modulation treats them + if ( rgbAnd == 255 ) { + return GL_ALPHA8; // single byte, only alpha + } #endif - if ( minimumDepth == TD_HIGH_QUALITY ) { - return GL_RGBA8; // four bytes - } - if ( glConfig.textureCompressionAvailable ) { - return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; // one byte - } - if ( !rgbDiffer ) { - return GL_LUMINANCE8_ALPHA8; // two bytes, max quality - } - return GL_RGBA4; // two bytes + if ( minimumDepth == TD_HIGH_QUALITY ) { + return GL_RGBA8; // four bytes + } + + if ( glConfig.textureCompressionAvailable ) { + return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; // one byte + } + + if ( !rgbDiffer ) { + return GL_LUMINANCE8_ALPHA8; // two bytes, max quality + } + return GL_RGBA4; // two bytes } /* @@ -357,55 +363,56 @@ SetImageFilterAndRepeat ================== */ void idImage::SetImageFilterAndRepeat() const { - // set the minimize / maximize filtering - switch( filter ) { - case TF_DEFAULT: - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, globalImages->textureMinFilter ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, globalImages->textureMaxFilter ); - break; - case TF_LINEAR: - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - break; - case TF_NEAREST: - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - break; - default: - common->FatalError( "R_CreateImage: bad texture filter" ); - } - - if ( glConfig.anisotropicAvailable ) { - // only do aniso filtering on mip mapped images - if ( filter == TF_DEFAULT ) { - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, globalImages->textureAnisotropy ); - } else { - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 ); - } - } - if ( glConfig.textureLODBiasAvailable ) { - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_EXT, globalImages->textureLODBias ); - } - - // set the wrap/clamp modes - switch( repeat ) { - case TR_REPEAT: - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); - break; - case TR_CLAMP_TO_BORDER: - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); - break; - case TR_CLAMP_TO_ZERO: - case TR_CLAMP_TO_ZERO_ALPHA: - case TR_CLAMP: - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - break; - default: - common->FatalError( "R_CreateImage: bad texture repeat" ); - } + // set the minimize / maximize filtering + switch ( filter ) { + case TF_DEFAULT: + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, globalImages->textureMinFilter ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, globalImages->textureMaxFilter ); + break; + case TF_LINEAR: + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + break; + case TF_NEAREST: + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + break; + default: + common->FatalError( "R_CreateImage: bad texture filter" ); + } + + if ( glConfig.anisotropicAvailable ) { + // only do aniso filtering on mip mapped images + if ( filter == TF_DEFAULT ) { + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, globalImages->textureAnisotropy ); + } else { + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 ); + } + } + + if ( glConfig.textureLODBiasAvailable ) { + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_EXT, globalImages->textureLODBias ); + } + + // set the wrap/clamp modes + switch ( repeat ) { + case TR_REPEAT: + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + break; + case TR_CLAMP_TO_BORDER: + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); + break; + case TR_CLAMP_TO_ZERO: + case TR_CLAMP_TO_ZERO_ALPHA: + case TR_CLAMP: + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + break; + default: + common->FatalError( "R_CreateImage: bad texture repeat" ); + } } /* @@ -415,55 +422,58 @@ helper function that takes the current width/height and might make them smaller ================ */ void idImage::GetDownsize( int &scaled_width, int &scaled_height ) const { - int size = 0; - - // perform optional picmip operation to save texture memory - if ( depth == TD_SPECULAR && globalImages->image_downSizeSpecular.GetInteger() ) { - size = globalImages->image_downSizeSpecularLimit.GetInteger(); - if ( size == 0 ) { - size = 64; - } - } else if ( depth == TD_BUMP && globalImages->image_downSizeBump.GetInteger() ) { - size = globalImages->image_downSizeBumpLimit.GetInteger(); - if ( size == 0 ) { - size = 64; - } - } else if ( ( allowDownSize || globalImages->image_forceDownSize.GetBool() ) && globalImages->image_downSize.GetInteger() ) { - size = globalImages->image_downSizeLimit.GetInteger(); - if ( size == 0 ) { - size = 256; - } - } - - if ( size > 0 ) { - while ( scaled_width > size || scaled_height > size ) { - if ( scaled_width > 1 ) { - scaled_width >>= 1; - } - if ( scaled_height > 1 ) { - scaled_height >>= 1; - } - } - } - - // clamp to minimum size - if ( scaled_width < 1 ) { - scaled_width = 1; - } - if ( scaled_height < 1 ) { - scaled_height = 1; - } - - // clamp size to the hardware specific upper limit - // scale both axis down equally so we don't have to - // deal with a half mip resampling - // This causes a 512*256 texture to sample down to - // 256*128 on a voodoo3, even though it could be 256*256 - while ( scaled_width > glConfig.maxTextureSize - || scaled_height > glConfig.maxTextureSize ) { - scaled_width >>= 1; - scaled_height >>= 1; - } + int size = 0; + + // perform optional picmip operation to save texture memory + if ( depth == TD_SPECULAR && globalImages->image_downSizeSpecular.GetInteger() ) { + size = globalImages->image_downSizeSpecularLimit.GetInteger(); + + if ( size == 0 ) { + size = 64; + } + } else if ( depth == TD_BUMP && globalImages->image_downSizeBump.GetInteger() ) { + size = globalImages->image_downSizeBumpLimit.GetInteger(); + + if ( size == 0 ) { + size = 64; + } + } else if ( ( allowDownSize || globalImages->image_forceDownSize.GetBool() ) && globalImages->image_downSize.GetInteger() ) { + size = globalImages->image_downSizeLimit.GetInteger(); + + if ( size == 0 ) { + size = 256; + } + } + + if ( size > 0 ) { + while ( scaled_width > size || scaled_height > size ) { + if ( scaled_width > 1 ) { + scaled_width >>= 1; + } + if ( scaled_height > 1 ) { + scaled_height >>= 1; + } + } + } + + // clamp to minimum size + if ( scaled_width < 1 ) { + scaled_width = 1; + } + + if ( scaled_height < 1 ) { + scaled_height = 1; + } + + // clamp size to the hardware specific upper limit + // scale both axis down equally so we don't have to + // deal with a half mip resampling + // This causes a 512*256 texture to sample down to + // 256*128 on a voodoo3, even though it could be 256*256 + while ( scaled_width > glConfig.maxTextureSize || scaled_height > glConfig.maxTextureSize ) { + scaled_width >>= 1; + scaled_height >>= 1; + } } /* @@ -496,355 +506,357 @@ There is no way to specify explicit mip map levels ================ */ void idImage::GenerateImage( const byte *pic, int width, int height, - textureFilter_t filterParm, bool allowDownSizeParm, - textureRepeat_t repeatParm, textureDepth_t depthParm ) { - bool preserveBorder; - byte *scaledBuffer; - int scaled_width, scaled_height; - byte *shrunk; - - PurgeImage(); - - filter = filterParm; - allowDownSize = allowDownSizeParm; - repeat = repeatParm; - depth = depthParm; - - // if we don't have a rendering context, just return after we - // have filled in the parms. We must have the values set, or - // an image match from a shader before OpenGL starts would miss - // the generated texture - if ( !glConfig.isInitialized ) { - return; - } - - // don't let mip mapping smear the texture into the clamped border - if ( repeat == TR_CLAMP_TO_ZERO ) { - preserveBorder = true; - } else { - preserveBorder = false; - } - - // make sure it is a power of 2 - scaled_width = MakePowerOfTwo( width ); - scaled_height = MakePowerOfTwo( height ); - - if ( scaled_width != width || scaled_height != height ) { - common->Error( "R_CreateImage: not a power of 2 image" ); - } - - // Optionally modify our width/height based on options/hardware - GetDownsize( scaled_width, scaled_height ); - - scaledBuffer = NULL; - - // generate the texture number - qglGenTextures( 1, &texnum ); - - // select proper internal format before we resample - internalFormat = SelectInternalFormat( &pic, 1, width, height, depth ); - - // copy or resample data as appropriate for first MIP level - if ( ( scaled_width == width ) && ( scaled_height == height ) ) { - // we must copy even if unchanged, because the border zeroing - // would otherwise modify const data - scaledBuffer = (byte *)R_StaticAlloc( sizeof( unsigned ) * scaled_width * scaled_height ); - memcpy (scaledBuffer, pic, width*height*4); - } else { - // resample down as needed (FIXME: this doesn't seem like it resamples anymore!) - // scaledBuffer = R_ResampleTexture( pic, width, height, width >>= 1, height >>= 1 ); - scaledBuffer = R_MipMap( pic, width, height, preserveBorder ); - width >>= 1; - height >>= 1; - if ( width < 1 ) { - width = 1; - } - if ( height < 1 ) { - height = 1; - } - - while ( width > scaled_width || height > scaled_height ) { - shrunk = R_MipMap( scaledBuffer, width, height, preserveBorder ); - R_StaticFree( scaledBuffer ); - scaledBuffer = shrunk; - - width >>= 1; - height >>= 1; - if ( width < 1 ) { - width = 1; - } - if ( height < 1 ) { - height = 1; - } - } - - // one might have shrunk down below the target size - scaled_width = width; - scaled_height = height; - } - - uploadHeight = scaled_height; - uploadWidth = scaled_width; - type = TT_2D; - - // zero the border if desired, allowing clamped projection textures - // even after picmip resampling or careless artists. - if ( repeat == TR_CLAMP_TO_ZERO ) { - byte rgba[4]; - - rgba[0] = rgba[1] = rgba[2] = 0; - rgba[3] = 255; - R_SetBorderTexels( (byte *)scaledBuffer, width, height, rgba ); - } - if ( repeat == TR_CLAMP_TO_ZERO_ALPHA ) { - byte rgba[4]; - - rgba[0] = rgba[1] = rgba[2] = 255; - rgba[3] = 0; - R_SetBorderTexels( (byte *)scaledBuffer, width, height, rgba ); - } - - if ( generatorFunction == NULL && ( (depth == TD_BUMP && globalImages->image_writeNormalTGA.GetBool()) || (depth != TD_BUMP && globalImages->image_writeTGA.GetBool()) ) ) { - // Optionally write out the texture to a .tga - char filename[MAX_IMAGE_NAME]; - ImageProgramStringToCompressedFileName( imgName, filename ); - char *ext = strrchr(filename, '.'); - if ( ext ) { - strcpy( ext, ".tga" ); - // swap the red/alpha for the write - /* - if ( depth == TD_BUMP ) { - for ( int i = 0; i < scaled_width * scaled_height * 4; i += 4 ) { - scaledBuffer[ i ] = scaledBuffer[ i + 3 ]; - scaledBuffer[ i + 3 ] = 0; - } - } - */ - R_WriteTGA( filename, scaledBuffer, scaled_width, scaled_height, false ); - - // put it back - /* - if ( depth == TD_BUMP ) { - for ( int i = 0; i < scaled_width * scaled_height * 4; i += 4 ) { - scaledBuffer[ i + 3 ] = scaledBuffer[ i ]; - scaledBuffer[ i ] = 0; - } - } - */ - } - } - - // swap the red and alpha for rxgb support - // do this even on tga normal maps so we only have to use - // one fragment program - // if the image is precompressed ( either in palletized mode or true rxgb mode ) - // then it is loaded above and the swap never happens here - if ( depth == TD_BUMP && globalImages->image_useNormalCompression.GetInteger() != 1 ) { - for ( int i = 0; i < scaled_width * scaled_height * 4; i += 4 ) { - scaledBuffer[ i + 3 ] = scaledBuffer[ i ]; - scaledBuffer[ i ] = 0; - } - } - // upload the main image level - Bind(); - - - if ( internalFormat == GL_COLOR_INDEX8_EXT ) { - /* - if ( depth == TD_BUMP ) { - for ( int i = 0; i < scaled_width * scaled_height * 4; i += 4 ) { - scaledBuffer[ i ] = scaledBuffer[ i + 3 ]; - scaledBuffer[ i + 3 ] = 0; - } - } - */ - UploadCompressedNormalMap( scaled_width, scaled_height, scaledBuffer, 0 ); - } else { - qglTexImage2D( GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer ); - } - - // create and upload the mip map levels, which we do in all cases, even if we don't think they are needed - int miplevel; - - miplevel = 0; - while ( scaled_width > 1 || scaled_height > 1 ) { - // preserve the border after mip map unless repeating - shrunk = R_MipMap( scaledBuffer, scaled_width, scaled_height, preserveBorder ); - R_StaticFree( scaledBuffer ); - scaledBuffer = shrunk; - - scaled_width >>= 1; - scaled_height >>= 1; - if ( scaled_width < 1 ) { - scaled_width = 1; - } - if ( scaled_height < 1 ) { - scaled_height = 1; - } - miplevel++; - - // this is a visualization tool that shades each mip map - // level with a different color so you can see the - // rasterizer's texture level selection algorithm - // Changing the color doesn't help with lumminance/alpha/intensity formats... - if ( depth == TD_DIFFUSE && globalImages->image_colorMipLevels.GetBool() ) { - R_BlendOverTexture( (byte *)scaledBuffer, scaled_width * scaled_height, mipBlendColors[miplevel] ); - } - - // upload the mip map - if ( internalFormat == GL_COLOR_INDEX8_EXT ) { - UploadCompressedNormalMap( scaled_width, scaled_height, scaledBuffer, miplevel ); - } else { - qglTexImage2D( GL_TEXTURE_2D, miplevel, internalFormat, scaled_width, scaled_height, - 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer ); - } - } - - if ( scaledBuffer != 0 ) { - R_StaticFree( scaledBuffer ); - } - - SetImageFilterAndRepeat(); - - // see if we messed anything up - GL_CheckErrors(); + textureFilter_t filterParm, bool allowDownSizeParm, + textureRepeat_t repeatParm, textureDepth_t depthParm ) { + bool preserveBorder; + byte *scaledBuffer; + int scaled_width, scaled_height; + byte *shrunk; + + PurgeImage(); + + filter = filterParm; + allowDownSize = allowDownSizeParm; + repeat = repeatParm; + depth = depthParm; + + // if we don't have a rendering context, just return after we + // have filled in the parms. We must have the values set, or + // an image match from a shader before OpenGL starts would miss + // the generated texture + if ( !glConfig.isInitialized ) { + return; + } + + // don't let mip mapping smear the texture into the clamped border + if ( repeat == TR_CLAMP_TO_ZERO ) { + preserveBorder = true; + } else { + preserveBorder = false; + } + + // make sure it is a power of 2 + scaled_width = MakePowerOfTwo( width ); + scaled_height = MakePowerOfTwo( height ); + + if ( scaled_width != width || scaled_height != height ) { + common->Error( "R_CreateImage: not a power of 2 image" ); + } + + // Optionally modify our width/height based on options/hardware + GetDownsize( scaled_width, scaled_height ); + + scaledBuffer = NULL; + + // generate the texture number + qglGenTextures( 1, &texnum ); + + // select proper internal format before we resample + internalFormat = SelectInternalFormat( &pic, 1, width, height, depth ); + + // copy or resample data as appropriate for first MIP level + if ( ( scaled_width == width ) && ( scaled_height == height ) ) { + // we must copy even if unchanged, because the border zeroing + // would otherwise modify const data + scaledBuffer = ( byte * )R_StaticAlloc( sizeof( unsigned ) * scaled_width * scaled_height ); + memcpy( scaledBuffer, pic, width * height * 4 ); + } else { + // resample down as needed (FIXME: this doesn't seem like it resamples anymore!) + // scaledBuffer = R_ResampleTexture( pic, width, height, width >>= 1, height >>= 1 ); + scaledBuffer = R_MipMap( pic, width, height, preserveBorder ); + + width >>= 1; + height >>= 1; + + if ( width < 1 ) { + width = 1; + } + + if ( height < 1 ) { + height = 1; + } + + while ( width > scaled_width || height > scaled_height ) { + shrunk = R_MipMap( scaledBuffer, width, height, preserveBorder ); + R_StaticFree( scaledBuffer ); + scaledBuffer = shrunk; + + width >>= 1; + height >>= 1; + + if ( width < 1 ) { + width = 1; + } + + if ( height < 1 ) { + height = 1; + } + } + + // one might have shrunk down below the target size + scaled_width = width; + scaled_height = height; + } + uploadHeight = scaled_height; + uploadWidth = scaled_width; + type = TT_2D; + + // zero the border if desired, allowing clamped projection textures + // even after picmip resampling or careless artists. + if ( repeat == TR_CLAMP_TO_ZERO ) { + byte rgba[4]; + + rgba[0] = + rgba[1] = + rgba[2] = 0; + rgba[3] = 255; + + R_SetBorderTexels( ( byte * )scaledBuffer, width, height, rgba ); + } + + if ( repeat == TR_CLAMP_TO_ZERO_ALPHA ) { + byte rgba[4]; + + rgba[0] = + rgba[1] = + rgba[2] = 255; + rgba[3] = 0; + + R_SetBorderTexels( ( byte * )scaledBuffer, width, height, rgba ); + } + + if ( generatorFunction == NULL && ( ( depth == TD_BUMP && globalImages->image_writeNormalTGA.GetBool() ) || ( depth != TD_BUMP && globalImages->image_writeTGA.GetBool() ) ) ) { + // Optionally write out the texture to a .tga + char filename[MAX_IMAGE_NAME]; + ImageProgramStringToCompressedFileName( imgName, filename ); + char *ext = strrchr( filename, '.' ); + + if ( ext ) { + strcpy( ext, ".tga" ); + // swap the red/alpha for the write + /* + if ( depth == TD_BUMP ) { + for ( int i = 0; i < scaled_width * scaled_height * 4; i += 4 ) { + scaledBuffer[ i ] = scaledBuffer[ i + 3 ]; + scaledBuffer[ i + 3 ] = 0; + } + } + */ + R_WriteTGA( filename, scaledBuffer, scaled_width, scaled_height, false ); + // put it back + /* + if ( depth == TD_BUMP ) { + for ( int i = 0; i < scaled_width * scaled_height * 4; i += 4 ) { + scaledBuffer[ i + 3 ] = scaledBuffer[ i ]; + scaledBuffer[ i ] = 0; + } + } + */ + } + } + + // swap the red and alpha for rxgb support + // do this even on tga normal maps so we only have to use + // one fragment program + // if the image is precompressed ( either in palletized mode or true rxgb mode ) + // then it is loaded above and the swap never happens here + if ( depth == TD_BUMP && globalImages->image_useNormalCompression.GetInteger() != 1 ) { + for ( int i = 0; i < scaled_width * scaled_height * 4; i += 4 ) { + scaledBuffer[ i + 3 ] = scaledBuffer[ i ]; + scaledBuffer[ i ] = 0; + } + } + + // upload the main image level + Bind(); + + if ( internalFormat == GL_COLOR_INDEX8_EXT ) { + UploadCompressedNormalMap( scaled_width, scaled_height, scaledBuffer, 0 ); + } else { + qglTexImage2D( GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer ); + } + + // create and upload the mip map levels, which we do in all cases, even if we don't think they are needed + int miplevel = 0; + + while ( scaled_width > 1 || scaled_height > 1 ) { + // preserve the border after mip map unless repeating + shrunk = R_MipMap( scaledBuffer, scaled_width, scaled_height, preserveBorder ); + R_StaticFree( scaledBuffer ); + scaledBuffer = shrunk; + + scaled_width >>= 1; + scaled_height >>= 1; + + if ( scaled_width < 1 ) { + scaled_width = 1; + } + + if ( scaled_height < 1 ) { + scaled_height = 1; + } + miplevel++; + + // this is a visualization tool that shades each mip map + // level with a different color so you can see the + // rasterizer's texture level selection algorithm + // Changing the color doesn't help with lumminance/alpha/intensity formats... + if ( depth == TD_DIFFUSE && globalImages->image_colorMipLevels.GetBool() ) { + R_BlendOverTexture( ( byte * )scaledBuffer, scaled_width * scaled_height, mipBlendColors[miplevel] ); + } + + // upload the mip map + if ( internalFormat == GL_COLOR_INDEX8_EXT ) { + UploadCompressedNormalMap( scaled_width, scaled_height, scaledBuffer, miplevel ); + } else { + qglTexImage2D( GL_TEXTURE_2D, miplevel, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer ); + } + } + + if ( scaledBuffer != 0 ) { + R_StaticFree( scaledBuffer ); + } + SetImageFilterAndRepeat(); + + // see if we messed anything up + GL_CheckErrors(); } - /* ================== Generate3DImage ================== */ void idImage::Generate3DImage( const byte *pic, int width, int height, int picDepth, - textureFilter_t filterParm, bool allowDownSizeParm, - textureRepeat_t repeatParm, textureDepth_t minDepthParm ) { - int scaled_width, scaled_height, scaled_depth; - - PurgeImage(); - - filter = filterParm; - allowDownSize = allowDownSizeParm; - repeat = repeatParm; - depth = minDepthParm; - - // if we don't have a rendering context, just return after we - // have filled in the parms. We must have the values set, or - // an image match from a shader before OpenGL starts would miss - // the generated texture - if ( !glConfig.isInitialized ) { - return; - } - - // make sure it is a power of 2 - scaled_width = MakePowerOfTwo( width ); - scaled_height = MakePowerOfTwo( height ); - scaled_depth = MakePowerOfTwo( picDepth ); - if ( scaled_width != width || scaled_height != height || scaled_depth != picDepth ) { - common->Error( "R_Create3DImage: not a power of 2 image" ); - } - - // FIXME: allow picmip here - - // generate the texture number - qglGenTextures( 1, &texnum ); - - // select proper internal format before we resample - // this function doesn't need to know it is 3D, so just make it very "tall" - internalFormat = SelectInternalFormat( &pic, 1, width, height * picDepth, minDepthParm ); - - uploadHeight = scaled_height; - uploadWidth = scaled_width; - uploadDepth = scaled_depth; - - - type = TT_3D; - - // upload the main image level - Bind(); - - qglTexImage3D(GL_TEXTURE_3D, 0, internalFormat, scaled_width, scaled_height, scaled_depth, - 0, GL_RGBA, GL_UNSIGNED_BYTE, pic ); - - // create and upload the mip map levels - int miplevel; - byte *scaledBuffer, *shrunk; - - scaledBuffer = (byte *)R_StaticAlloc( scaled_width * scaled_height * scaled_depth * 4 ); - memcpy( scaledBuffer, pic, scaled_width * scaled_height * scaled_depth * 4 ); - miplevel = 0; - while ( scaled_width > 1 || scaled_height > 1 || scaled_depth > 1 ) { - // preserve the border after mip map unless repeating - shrunk = R_MipMap3D( scaledBuffer, scaled_width, scaled_height, scaled_depth, - (bool)(repeat != TR_REPEAT) ); - R_StaticFree( scaledBuffer ); - scaledBuffer = shrunk; - - scaled_width >>= 1; - scaled_height >>= 1; - scaled_depth >>= 1; - if ( scaled_width < 1 ) { - scaled_width = 1; - } - if ( scaled_height < 1 ) { - scaled_height = 1; - } - if ( scaled_depth < 1 ) { - scaled_depth = 1; - } - miplevel++; - - // upload the mip map - qglTexImage3D(GL_TEXTURE_3D, miplevel, internalFormat, scaled_width, scaled_height, scaled_depth, - 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer ); - } - R_StaticFree( scaledBuffer ); - - // set the minimize / maximize filtering - switch( filter ) { - case TF_DEFAULT: - qglTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, globalImages->textureMinFilter ); - qglTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, globalImages->textureMaxFilter ); - break; - case TF_LINEAR: - qglTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - break; - case TF_NEAREST: - qglTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - qglTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - break; - default: - common->FatalError( "R_CreateImage: bad texture filter" ); - } - - // set the wrap/clamp modes - switch( repeat ) { - case TR_REPEAT: - qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT ); - qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT ); - qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT ); - break; - case TR_CLAMP_TO_BORDER: - qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); - qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); - break; - case TR_CLAMP_TO_ZERO: - case TR_CLAMP_TO_ZERO_ALPHA: - case TR_CLAMP: - qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); - break; - default: - common->FatalError( "R_CreateImage: bad texture repeat" ); - } - - // see if we messed anything up - GL_CheckErrors(); + textureFilter_t filterParm, bool allowDownSizeParm, + textureRepeat_t repeatParm, textureDepth_t minDepthParm ) { + int scaled_width, scaled_height, scaled_depth; + + PurgeImage(); + + filter = filterParm; + allowDownSize = allowDownSizeParm; + repeat = repeatParm; + depth = minDepthParm; + + // if we don't have a rendering context, just return after we + // have filled in the parms. We must have the values set, or + // an image match from a shader before OpenGL starts would miss + // the generated texture + if ( !glConfig.isInitialized ) { + return; + } + + // make sure it is a power of 2 + scaled_width = MakePowerOfTwo( width ); + scaled_height = MakePowerOfTwo( height ); + scaled_depth = MakePowerOfTwo( picDepth ); + + if ( scaled_width != width || scaled_height != height || scaled_depth != picDepth ) { + common->Error( "R_Create3DImage: not a power of 2 image" ); + } + + // FIXME: allow picmip here + + // generate the texture number + qglGenTextures( 1, &texnum ); + + // select proper internal format before we resample + // this function doesn't need to know it is 3D, so just make it very "tall" + internalFormat = SelectInternalFormat( &pic, 1, width, height * picDepth, minDepthParm ); + + uploadHeight = scaled_height; + uploadWidth = scaled_width; + uploadDepth = scaled_depth; + + type = TT_3D; + + // upload the main image level + Bind(); + + qglTexImage3D( GL_TEXTURE_3D, 0, internalFormat, scaled_width, scaled_height, scaled_depth, 0, GL_RGBA, GL_UNSIGNED_BYTE, pic ); + + // create and upload the mip map levels + int miplevel; + byte *scaledBuffer, *shrunk; + + scaledBuffer = ( byte * )R_StaticAlloc( scaled_width * scaled_height * scaled_depth * 4 ); + memcpy( scaledBuffer, pic, scaled_width * scaled_height * scaled_depth * 4 ); + miplevel = 0; + + while ( scaled_width > 1 || scaled_height > 1 || scaled_depth > 1 ) { + // preserve the border after mip map unless repeating + shrunk = R_MipMap3D( scaledBuffer, scaled_width, scaled_height, scaled_depth, ( bool )( repeat != TR_REPEAT ) ); + R_StaticFree( scaledBuffer ); + scaledBuffer = shrunk; + + scaled_width >>= 1; + scaled_height >>= 1; + scaled_depth >>= 1; + + if ( scaled_width < 1 ) { + scaled_width = 1; + } + + if ( scaled_height < 1 ) { + scaled_height = 1; + } + + if ( scaled_depth < 1 ) { + scaled_depth = 1; + } + miplevel++; + + // upload the mip map + qglTexImage3D( GL_TEXTURE_3D, miplevel, internalFormat, scaled_width, scaled_height, scaled_depth, + 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer ); + } + R_StaticFree( scaledBuffer ); + + // set the minimize / maximize filtering + switch ( filter ) { + case TF_DEFAULT: + qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, globalImages->textureMinFilter ); + qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, globalImages->textureMaxFilter ); + break; + case TF_LINEAR: + qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + break; + case TF_NEAREST: + qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + break; + default: + common->FatalError( "R_CreateImage: bad texture filter" ); + } + + // set the wrap/clamp modes + switch ( repeat ) { + case TR_REPEAT: + qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT ); + break; + case TR_CLAMP_TO_BORDER: + qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); + qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); + break; + case TR_CLAMP_TO_ZERO: + case TR_CLAMP_TO_ZERO_ALPHA: + case TR_CLAMP: + qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); + break; + default: + common->FatalError( "R_CreateImage: bad texture repeat" ); + } + + // see if we messed anything up + GL_CheckErrors(); } - /* ==================== GenerateCubeImage @@ -853,113 +865,108 @@ Non-square cube sides are not allowed ==================== */ void idImage::GenerateCubeImage( const byte *pic[6], int size, - textureFilter_t filterParm, bool allowDownSizeParm, - textureDepth_t depthParm ) { - int scaled_width, scaled_height; - int width, height; - int i; - - PurgeImage(); - - filter = filterParm; - allowDownSize = allowDownSizeParm; - depth = depthParm; - - type = TT_CUBIC; - - // if we don't have a rendering context, just return after we - // have filled in the parms. We must have the values set, or - // an image match from a shader before OpenGL starts would miss - // the generated texture - if ( !glConfig.isInitialized ) { - return; - } - - if ( ! glConfig.cubeMapAvailable ) { - return; - } - - width = height = size; - - // generate the texture number - qglGenTextures( 1, &texnum ); - - // select proper internal format before we resample - internalFormat = SelectInternalFormat( pic, 6, width, height, depth ); - - // don't bother with downsample for now - scaled_width = width; - scaled_height = height; - - uploadHeight = scaled_height; - uploadWidth = scaled_width; - - Bind(); - - // no other clamp mode makes sense - qglTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - qglTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - // set the minimize / maximize filtering - switch( filter ) { - case TF_DEFAULT: - qglTexParameterf(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, globalImages->textureMinFilter ); - qglTexParameterf(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, globalImages->textureMaxFilter ); - break; - case TF_LINEAR: - qglTexParameterf(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - break; - case TF_NEAREST: - qglTexParameterf(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - qglTexParameterf(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - break; - default: - common->FatalError( "R_CreateImage: bad texture filter" ); - } - - // upload the base level - // FIXME: support GL_COLOR_INDEX8_EXT? - for ( i = 0 ; i < 6 ; i++ ) { - qglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT+i, 0, internalFormat, scaled_width, scaled_height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, pic[i] ); - } - - - // create and upload the mip map levels - int miplevel; - byte *shrunk[6]; - - for ( i = 0 ; i < 6 ; i++ ) { - shrunk[i] = R_MipMap( pic[i], scaled_width, scaled_height, false ); - } - - miplevel = 1; - while ( scaled_width > 1 ) { - for ( i = 0 ; i < 6 ; i++ ) { - byte *shrunken; - - qglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT+i, miplevel, internalFormat, - scaled_width / 2, scaled_height / 2, 0, - GL_RGBA, GL_UNSIGNED_BYTE, shrunk[i] ); - - if ( scaled_width > 2 ) { - shrunken = R_MipMap( shrunk[i], scaled_width/2, scaled_height/2, false ); - } else { - shrunken = NULL; - } - - R_StaticFree( shrunk[i] ); - shrunk[i] = shrunken; - } - - scaled_width >>= 1; - scaled_height >>= 1; - miplevel++; - } - - // see if we messed anything up - GL_CheckErrors(); + textureFilter_t filterParm, bool allowDownSizeParm, + textureDepth_t depthParm ) { + int scaled_width, scaled_height; + int width, height; + int i; + + PurgeImage(); + + filter = filterParm; + allowDownSize = allowDownSizeParm; + depth = depthParm; + + type = TT_CUBIC; + + // if we don't have a rendering context, just return after we + // have filled in the parms. We must have the values set, or + // an image match from a shader before OpenGL starts would miss + // the generated texture + if ( !glConfig.isInitialized ) { + return; + } + + if ( !glConfig.cubeMapAvailable ) { + return; + } + width = height = size; + + // generate the texture number + qglGenTextures( 1, &texnum ); + + // select proper internal format before we resample + internalFormat = SelectInternalFormat( pic, 6, width, height, depth ); + + // don't bother with downsample for now + scaled_width = width; + scaled_height = height; + + uploadHeight = scaled_height; + uploadWidth = scaled_width; + + Bind(); + + // no other clamp mode makes sense + qglTexParameteri( GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + qglTexParameteri( GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + + // set the minimize / maximize filtering + switch ( filter ) { + case TF_DEFAULT: + qglTexParameterf( GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, globalImages->textureMinFilter ); + qglTexParameterf( GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, globalImages->textureMaxFilter ); + break; + case TF_LINEAR: + qglTexParameterf( GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + qglTexParameterf( GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + break; + case TF_NEAREST: + qglTexParameterf( GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + qglTexParameterf( GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + break; + default: + common->FatalError( "R_CreateImage: bad texture filter" ); + } + + // upload the base level + // FIXME: support GL_COLOR_INDEX8_EXT? + for ( i = 0 ; i < 6 ; i++ ) { + qglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT + i, 0, internalFormat, scaled_width, scaled_height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, pic[i] ); + } + + // create and upload the mip map levels + int miplevel; + byte *shrunk[6]; + + for ( i = 0 ; i < 6 ; i++ ) { + shrunk[i] = R_MipMap( pic[i], scaled_width, scaled_height, false ); + } + miplevel = 1; + + while ( scaled_width > 1 ) { + for ( i = 0 ; i < 6 ; i++ ) { + byte *shrunken; + + qglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT + i, miplevel, internalFormat, scaled_width / 2, scaled_height / 2, 0, + GL_RGBA, GL_UNSIGNED_BYTE, shrunk[i] ); + + if ( scaled_width > 2 ) { + shrunken = R_MipMap( shrunk[i], scaled_width / 2, scaled_height / 2, false ); + } else { + shrunken = NULL; + } + R_StaticFree( shrunk[i] ); + shrunk[i] = shrunken; + } + scaled_width >>= 1; + scaled_height >>= 1; + miplevel++; + } + + // see if we messed anything up + GL_CheckErrors(); } @@ -969,37 +976,38 @@ ImageProgramStringToFileCompressedFileName ================ */ void idImage::ImageProgramStringToCompressedFileName( const char *imageProg, char *fileName ) const { - const char *s; - char *f; - - strcpy( fileName, "dds/" ); - f = fileName + strlen( fileName ); - - int depth = 0; - - // convert all illegal characters to underscores - // this could conceivably produce a duplicated mapping, but we aren't going to worry about it - for ( s = imageProg ; *s ; s++ ) { - if ( *s == '/' || *s == '\\' || *s == '(') { - if ( depth < 4 ) { - *f = '/'; - depth ++; - } else { - *f = ' '; - } - f++; - } else if ( *s == '<' || *s == '>' || *s == ':' || *s == '|' || *s == '"' || *s == '.' ) { - *f = '_'; - f++; - } else if ( *s == ' ' && *(f-1) == '/' ) { // ignore a space right after a slash - } else if ( *s == ')' || *s == ',' ) { // always ignore these - } else { - *f = *s; - f++; - } - } - *f++ = 0; - strcat( fileName, ".dds" ); + int depth = 0; + const char *s; + char *f; + + strcpy( fileName, "dds/" ); + f = fileName + strlen( fileName ); + + // convert all illegal characters to underscores + // this could conceivably produce a duplicated mapping, but we aren't going to worry about it + for ( s = imageProg ; *s ; s++ ) { + if ( *s == '/' || *s == '\\' || *s == '(' ) { + if ( depth < 4 ) { + *f = '/'; + depth ++; + } else { + *f = ' '; + } + f++; + } else if ( *s == '<' || *s == '>' || *s == ':' || *s == '|' || *s == '"' || *s == '.' ) { + *f = '_'; + f++; + } else if ( *s == ' ' && *( f - 1 ) == '/' ) { // ignore a space right after a slash + /* ignore */ + } else if ( *s == ')' || *s == ',' ) { // always ignore these + /* ignore */ + } else { + *f = *s; + f++; + } + } + *f++ = 0; + strcat( fileName, ".dds" ); } /* @@ -1007,16 +1015,15 @@ void idImage::ImageProgramStringToCompressedFileName( const char *imageProg, cha NumLevelsForImageSize ================== */ -int idImage::NumLevelsForImageSize( int width, int height ) const { - int numLevels = 1; - - while ( width > 1 || height > 1 ) { - numLevels++; - width >>= 1; - height >>= 1; - } - - return numLevels; +int idImage::NumLevelsForImageSize( int width, int height ) const { + int numLevels = 1; + + while ( width > 1 || height > 1 ) { + numLevels++; + width >>= 1; + height >>= 1; + } + return numLevels; } /* @@ -1028,226 +1035,223 @@ versions of everything to speed future load times. ================ */ void idImage::WritePrecompressedImage() { - - // Always write the precompressed image if we're making a build - if ( !com_makingBuild.GetBool() ) { - if ( !globalImages->image_writePrecompressedTextures.GetBool() || !globalImages->image_usePrecompressedTextures.GetBool() ) { - return; - } - } - - if ( !glConfig.isInitialized ) { - return; - } - - char filename[MAX_IMAGE_NAME]; - ImageProgramStringToCompressedFileName( imgName, filename ); - - - - int numLevels = NumLevelsForImageSize( uploadWidth, uploadHeight ); - if ( numLevels > MAX_TEXTURE_LEVELS ) { - common->Warning( "R_WritePrecompressedImage: level > MAX_TEXTURE_LEVELS for image %s", filename ); - return; - } - - // glGetTexImage only supports a small subset of all the available internal formats - // We have to use BGRA because DDS is a windows based format - int altInternalFormat = 0; - int bitSize = 0; - switch ( internalFormat ) { - case GL_COLOR_INDEX8_EXT: - case GL_COLOR_INDEX: - // this will not work with dds viewers but we need it in this format to save disk - // load speed ( i.e. size ) - altInternalFormat = GL_COLOR_INDEX; - bitSize = 24; - break; - case 1: - case GL_INTENSITY8: - case GL_LUMINANCE8: - case 3: - case GL_RGB8: - altInternalFormat = GL_BGR_EXT; - bitSize = 24; - break; - case GL_LUMINANCE8_ALPHA8: - case 4: - case GL_RGBA8: - altInternalFormat = GL_BGRA_EXT; - bitSize = 32; - break; - case GL_ALPHA8: - altInternalFormat = GL_ALPHA; - bitSize = 8; - break; - default: - if ( FormatIsDXT( internalFormat ) ) { - altInternalFormat = internalFormat; - } else { - common->Warning("Unknown or unsupported format for %s", filename); - return; - } - } - - if ( globalImages->image_useOffLineCompression.GetBool() && FormatIsDXT( altInternalFormat ) ) { - idStr outFile = fileSystem->RelativePathToOSPath( filename, "fs_basepath" ); - idStr inFile = outFile; - inFile.StripFileExtension(); - inFile.SetFileExtension( "tga" ); - idStr format; - if ( depth == TD_BUMP ) { - format = "RXGB +red 0.0 +green 0.5 +blue 0.5"; - } else { - switch ( altInternalFormat ) { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - format = "DXT1"; - break; - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - format = "DXT1 -alpha_threshold"; - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - format = "DXT3"; - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - format = "DXT5"; - break; - } - } - globalImages->AddDDSCommand( va( "z:/d3xp/compressonator/thecompressonator -convert \"%s\" \"%s\" %s -mipmaps\n", inFile.c_str(), outFile.c_str(), format.c_str() ) ); - return; - } - - - ddsFileHeader_t header; - memset( &header, 0, sizeof(header) ); - header.dwSize = sizeof(header); - header.dwFlags = DDSF_CAPS | DDSF_PIXELFORMAT | DDSF_WIDTH | DDSF_HEIGHT; - header.dwHeight = uploadHeight; - header.dwWidth = uploadWidth; - - if ( FormatIsDXT( altInternalFormat ) ) { - // size (in bytes) of the compressed base image - header.dwFlags |= DDSF_LINEARSIZE; - header.dwPitchOrLinearSize = ( ( uploadWidth + 3 ) / 4 ) * ( ( uploadHeight + 3 ) / 4 )* - (altInternalFormat <= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16); - } - else { - // 4 Byte aligned line width (from nv_dds) - header.dwFlags |= DDSF_PITCH; - header.dwPitchOrLinearSize = ( ( uploadWidth * bitSize + 31 ) & -32 ) >> 3; - } - - header.dwCaps1 = DDSF_TEXTURE; - - if ( numLevels > 1 ) { - header.dwMipMapCount = numLevels; - header.dwFlags |= DDSF_MIPMAPCOUNT; - header.dwCaps1 |= DDSF_MIPMAP | DDSF_COMPLEX; - } - - header.ddspf.dwSize = sizeof(header.ddspf); - if ( FormatIsDXT( altInternalFormat ) ) { - header.ddspf.dwFlags = DDSF_FOURCC; - switch ( altInternalFormat ) { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - header.ddspf.dwFourCC = DDS_MAKEFOURCC('D','X','T','1'); - break; - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - header.ddspf.dwFlags |= DDSF_ALPHAPIXELS; - header.ddspf.dwFourCC = DDS_MAKEFOURCC('D','X','T','1'); - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - header.ddspf.dwFourCC = DDS_MAKEFOURCC('D','X','T','3'); - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - header.ddspf.dwFourCC = DDS_MAKEFOURCC('D','X','T','5'); - break; - } - } else { - header.ddspf.dwFlags = ( internalFormat == GL_COLOR_INDEX8_EXT ) ? DDSF_RGB | DDSF_ID_INDEXCOLOR : DDSF_RGB; - header.ddspf.dwRGBBitCount = bitSize; - switch ( altInternalFormat ) { - case GL_BGRA_EXT: - case GL_LUMINANCE_ALPHA: - header.ddspf.dwFlags |= DDSF_ALPHAPIXELS; - header.ddspf.dwABitMask = 0xFF000000; - // Fall through - case GL_BGR_EXT: - case GL_LUMINANCE: - case GL_COLOR_INDEX: - header.ddspf.dwRBitMask = 0x00FF0000; - header.ddspf.dwGBitMask = 0x0000FF00; - header.ddspf.dwBBitMask = 0x000000FF; - break; - case GL_ALPHA: - header.ddspf.dwFlags = DDSF_ALPHAPIXELS; - header.ddspf.dwABitMask = 0xFF000000; - break; - default: - common->Warning( "Unknown or unsupported format for %s", filename ); - return; - } - } - - idFile *f = fileSystem->OpenFileWrite( filename ); - if ( f == NULL ) { - common->Warning( "Could not open %s trying to write precompressed image", filename ); - return; - } - common->Printf( "Writing precompressed image: %s\n", filename ); - - f->Write( "DDS ", 4 ); - f->Write( &header, sizeof(header) ); - - // bind to the image so we can read back the contents - Bind(); - - qglPixelStorei( GL_PACK_ALIGNMENT, 1 ); // otherwise small rows get padded to 32 bits - - int uw = uploadWidth; - int uh = uploadHeight; - - // Will be allocated first time through the loop - byte *data = NULL; - - for ( int level = 0 ; level < numLevels ; level++ ) { - - int size = 0; - if ( FormatIsDXT( altInternalFormat ) ) { - size = ( ( uw + 3 ) / 4 ) * ( ( uh + 3 ) / 4 ) * - (altInternalFormat <= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16); - } else { - size = uw * uh * (bitSize / 8); - } - - if (data == NULL) { - data = (byte *)R_StaticAlloc( size ); - } - - if ( FormatIsDXT( altInternalFormat ) ) { - qglGetCompressedTexImageARB( GL_TEXTURE_2D, level, data ); - } else { - qglGetTexImage( GL_TEXTURE_2D, level, altInternalFormat, GL_UNSIGNED_BYTE, data ); - } - - f->Write( data, size ); - - uw /= 2; - uh /= 2; - if (uw < 1) { - uw = 1; - } - if (uh < 1) { - uh = 1; - } - } - - if (data != NULL) { - R_StaticFree( data ); - } - - fileSystem->CloseFile( f ); + // Always write the precompressed image if we're making a build + if ( !com_makingBuild.GetBool() ) { + if ( !globalImages->image_writePrecompressedTextures.GetBool() || !globalImages->image_usePrecompressedTextures.GetBool() ) { + return; + } + } + + if ( !glConfig.isInitialized ) { + return; + } + char filename[MAX_IMAGE_NAME]; + + ImageProgramStringToCompressedFileName( imgName, filename ); + + int numLevels = NumLevelsForImageSize( uploadWidth, uploadHeight ); + if ( numLevels > MAX_TEXTURE_LEVELS ) { + common->Warning( "R_WritePrecompressedImage: level > MAX_TEXTURE_LEVELS for image %s", filename ); + return; + } + + // glGetTexImage only supports a small subset of all the available internal formats + // We have to use BGRA because DDS is a windows based format + int altInternalFormat = 0; + int bitSize = 0; + switch ( internalFormat ) { + case GL_COLOR_INDEX8_EXT: + case GL_COLOR_INDEX: + // this will not work with dds viewers but we need it in this format to save disk + // load speed ( i.e. size ) + altInternalFormat = GL_COLOR_INDEX; + bitSize = 24; + break; + case 1: + case GL_INTENSITY8: + case GL_LUMINANCE8: + case 3: + case GL_RGB8: + altInternalFormat = GL_BGR_EXT; + bitSize = 24; + break; + case GL_LUMINANCE8_ALPHA8: + case 4: + case GL_RGBA8: + altInternalFormat = GL_BGRA_EXT; + bitSize = 32; + break; + case GL_ALPHA8: + altInternalFormat = GL_ALPHA; + bitSize = 8; + break; + default: + if ( FormatIsDXT( internalFormat ) ) { + altInternalFormat = internalFormat; + } else { + common->Warning( "Unknown or unsupported format for %s", filename ); + return; + } + } + + if ( globalImages->image_useOffLineCompression.GetBool() && FormatIsDXT( altInternalFormat ) ) { + idStr outFile = fileSystem->RelativePathToOSPath( filename, "fs_basepath" ); + idStr inFile = outFile; + inFile.StripFileExtension(); + inFile.SetFileExtension( "tga" ); + idStr format; + + if ( depth == TD_BUMP ) { + format = "RXGB +red 0.0 +green 0.5 +blue 0.5"; + } else { + switch ( altInternalFormat ) { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + format = "DXT1"; + break; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + format = "DXT1 -alpha_threshold"; + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + format = "DXT3"; + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + format = "DXT5"; + break; + } + } + globalImages->AddDDSCommand( va( "z:/d3xp/compressonator/thecompressonator -convert \"%s\" \"%s\" %s -mipmaps\n", inFile.c_str(), outFile.c_str(), format.c_str() ) ); + return; + } + ddsFileHeader_t header; + + memset( &header, 0, sizeof( header ) ); + header.dwSize = sizeof( header ); + header.dwFlags = DDSF_CAPS | DDSF_PIXELFORMAT | DDSF_WIDTH | DDSF_HEIGHT; + header.dwHeight = uploadHeight; + header.dwWidth = uploadWidth; + + if ( FormatIsDXT( altInternalFormat ) ) { + // size (in bytes) of the compressed base image + header.dwFlags |= DDSF_LINEARSIZE; + header.dwPitchOrLinearSize = ( ( uploadWidth + 3 ) / 4 ) * ( ( uploadHeight + 3 ) / 4 ) * + ( altInternalFormat <= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16 ); + } else { + // 4 Byte aligned line width (from nv_dds) + header.dwFlags |= DDSF_PITCH; + header.dwPitchOrLinearSize = ( ( uploadWidth * bitSize + 31 ) & -32 ) >> 3; + } + header.dwCaps1 = DDSF_TEXTURE; + + if ( numLevels > 1 ) { + header.dwMipMapCount = numLevels; + header.dwFlags |= DDSF_MIPMAPCOUNT; + header.dwCaps1 |= DDSF_MIPMAP | DDSF_COMPLEX; + } + header.ddspf.dwSize = sizeof( header.ddspf ); + + if ( FormatIsDXT( altInternalFormat ) ) { + header.ddspf.dwFlags = DDSF_FOURCC; + + switch ( altInternalFormat ) { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + header.ddspf.dwFourCC = DDS_MAKEFOURCC( 'D', 'X', 'T', '1' ); + break; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + header.ddspf.dwFlags |= DDSF_ALPHAPIXELS; + header.ddspf.dwFourCC = DDS_MAKEFOURCC( 'D', 'X', 'T', '1' ); + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + header.ddspf.dwFourCC = DDS_MAKEFOURCC( 'D', 'X', 'T', '3' ); + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + header.ddspf.dwFourCC = DDS_MAKEFOURCC( 'D', 'X', 'T', '5' ); + break; + } + } else { + header.ddspf.dwFlags = ( internalFormat == GL_COLOR_INDEX8_EXT ) ? DDSF_RGB | DDSF_ID_INDEXCOLOR : DDSF_RGB; + header.ddspf.dwRGBBitCount = bitSize; + + switch ( altInternalFormat ) { + case GL_BGRA_EXT: + case GL_LUMINANCE_ALPHA: + header.ddspf.dwFlags |= DDSF_ALPHAPIXELS; + header.ddspf.dwABitMask = 0xFF000000; + // Fall through + case GL_BGR_EXT: + case GL_LUMINANCE: + case GL_COLOR_INDEX: + header.ddspf.dwRBitMask = 0x00FF0000; + header.ddspf.dwGBitMask = 0x0000FF00; + header.ddspf.dwBBitMask = 0x000000FF; + break; + case GL_ALPHA: + header.ddspf.dwFlags = DDSF_ALPHAPIXELS; + header.ddspf.dwABitMask = 0xFF000000; + break; + default: + common->Warning( "Unknown or unsupported format for %s", filename ); + return; + } + } + idFile *f = fileSystem->OpenFileWrite( filename ); + + if ( f == NULL ) { + common->Warning( "Could not open %s trying to write precompressed image", filename ); + return; + } + common->Printf( "Writing precompressed image: %s\n", filename ); + + f->Write( "DDS ", 4 ); + f->Write( &header, sizeof( header ) ); + + // bind to the image so we can read back the contents + Bind(); + + qglPixelStorei( GL_PACK_ALIGNMENT, 1 ); // otherwise small rows get padded to 32 bits + + int uw = uploadWidth; + int uh = uploadHeight; + + // Will be allocated first time through the loop + byte *data = NULL; + + for ( int level = 0 ; level < numLevels ; level++ ) { + + int size = 0; + + if ( FormatIsDXT( altInternalFormat ) ) { + size = ( ( uw + 3 ) / 4 ) * ( ( uh + 3 ) / 4 ) * ( altInternalFormat <= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16 ); + } else { + size = uw * uh * ( bitSize / 8 ); + } + + if ( data == NULL ) { + data = ( byte * )R_StaticAlloc( size ); + } + + if ( FormatIsDXT( altInternalFormat ) ) { + qglGetCompressedTexImageARB( GL_TEXTURE_2D, level, data ); + } else { + qglGetTexImage( GL_TEXTURE_2D, level, altInternalFormat, GL_UNSIGNED_BYTE, data ); + } + f->Write( data, size ); + + uw /= 2; + uh /= 2; + + if ( uw < 1 ) { + uw = 1; + } + + if ( uh < 1 ) { + uh = 1; + } + } + + if ( data != NULL ) { + R_StaticFree( data ); + } + fileSystem->CloseFile( f ); } /* @@ -1259,55 +1263,53 @@ to be worth caching ================ */ bool idImage::ShouldImageBePartialCached() { - if ( !glConfig.textureCompressionAvailable ) { - return false; - } - - if ( !globalImages->image_useCache.GetBool() ) { - return false; - } + if ( !glConfig.textureCompressionAvailable ) { + return false; + } - // the allowDownSize flag does double-duty as don't-partial-load - if ( !allowDownSize ) { - return false; - } + if ( !globalImages->image_useCache.GetBool() ) { + return false; + } - if ( globalImages->image_cacheMinK.GetInteger() <= 0 ) { - return false; - } + // the allowDownSize flag does double-duty as don't-partial-load + if ( !allowDownSize ) { + return false; + } - // if we are doing a copyFiles, make sure the original images are referenced - if ( fileSystem->PerformingCopyFiles() ) { - return false; - } + if ( globalImages->image_cacheMinK.GetInteger() <= 0 ) { + return false; + } - char filename[MAX_IMAGE_NAME]; - ImageProgramStringToCompressedFileName( imgName, filename ); + // if we are doing a copyFiles, make sure the original images are referenced + if ( fileSystem->PerformingCopyFiles() ) { + return false; + } + char filename[MAX_IMAGE_NAME]; - // get the file timestamp - fileSystem->ReadFile( filename, NULL, ×tamp ); + ImageProgramStringToCompressedFileName( imgName, filename ); - if ( timestamp == FILE_NOT_FOUND_TIMESTAMP ) { - return false; - } + // get the file timestamp + fileSystem->ReadFile( filename, NULL, ×tamp ); - // open it and get the file size - idFile *f; + if ( timestamp == FILE_NOT_FOUND_TIMESTAMP ) { + return false; + } - f = fileSystem->OpenFileRead( filename ); - if ( !f ) { - return false; - } + // open it and get the file size + idFile *f = fileSystem->OpenFileRead( filename ); + if ( !f ) { + return false; + } + int len = f->Length(); - int len = f->Length(); - fileSystem->CloseFile( f ); + fileSystem->CloseFile( f ); - if ( len <= globalImages->image_cacheMinK.GetInteger() * 1024 ) { - return false; - } + if ( len <= globalImages->image_cacheMinK.GetInteger() * 1024 ) { + return false; + } - // we do want to do a partial load - return true; + // we do want to do a partial load + return true; } /* @@ -1318,100 +1320,86 @@ If fullLoad is false, only the small mip levels of the image will be loaded ================ */ bool idImage::CheckPrecompressedImage( bool fullLoad ) { - if ( !glConfig.isInitialized || !glConfig.textureCompressionAvailable ) { - return false; - } + if ( !glConfig.isInitialized || !glConfig.textureCompressionAvailable ) { + return false; + } #if 1 // ( _D3XP had disabled ) - Allow grabbing of DDS's from original Doom pak files - // if we are doing a copyFiles, make sure the original images are referenced - if ( fileSystem->PerformingCopyFiles() ) { - return false; - } + // if we are doing a copyFiles, make sure the original images are referenced + if ( fileSystem->PerformingCopyFiles() ) { + return false; + } #endif - if ( depth == TD_BUMP && globalImages->image_useNormalCompression.GetInteger() != 2 ) { - return false; - } - - // god i love last minute hacks :-) - if ( com_machineSpec.GetInteger() >= 1 && imgName.Icmpn( "lights/", 7 ) == 0 ) { - return false; - } - - char filename[MAX_IMAGE_NAME]; - ImageProgramStringToCompressedFileName( imgName, filename ); - - // get the file timestamp - ID_TIME_T precompTimestamp; - fileSystem->ReadFile( filename, NULL, &precompTimestamp ); - - - if ( precompTimestamp == FILE_NOT_FOUND_TIMESTAMP ) { - return false; - } - - if ( !generatorFunction && timestamp != FILE_NOT_FOUND_TIMESTAMP ) { - if ( precompTimestamp < timestamp ) { - // The image has changed after being precompressed - return false; - } - } - - timestamp = precompTimestamp; - - // open it and just read the header - idFile *f; - - f = fileSystem->OpenFileRead( filename ); - if ( !f ) { - return false; - } - - int len = f->Length(); - if ( len < sizeof( ddsFileHeader_t ) ) { - fileSystem->CloseFile( f ); - return false; - } - -#if 0 // DG: no idea what this was exactly meant to achieve, but it's definitely a bad idea: - // we might try to load the lower mipmap levels of the image, but we'd still have - // to load the whole .dds file first. - // What's even weirder: idImage::ShouldImageBePartiallyCached() returns false - // if the file size is LESS THAN image_cacheMinK * 1024... - if ( !fullLoad && len > globalImages->image_cacheMinK.GetInteger() * 1024 ) { - len = globalImages->image_cacheMinK.GetInteger() * 1024; - } -#endif + if ( depth == TD_BUMP && globalImages->image_useNormalCompression.GetInteger() != 2 ) { + return false; + } + + // god i love last minute hacks :-) + if ( com_machineSpec.GetInteger() >= 1 && imgName.Icmpn( "lights/", 7 ) == 0 ) { + return false; + } + char filename[MAX_IMAGE_NAME]; + + ImageProgramStringToCompressedFileName( imgName, filename ); + + // get the file timestamp + ID_TIME_T precompTimestamp; + + fileSystem->ReadFile( filename, NULL, &precompTimestamp ); - byte *data = (byte *)R_StaticAlloc( len ); + if ( precompTimestamp == FILE_NOT_FOUND_TIMESTAMP ) { + return false; + } - f->Read( data, len ); + if ( !generatorFunction && timestamp != FILE_NOT_FOUND_TIMESTAMP ) { + if ( precompTimestamp < timestamp ) { + // The image has changed after being precompressed + return false; + } + } + timestamp = precompTimestamp; - fileSystem->CloseFile( f ); + // open it and just read the header + idFile *f = fileSystem->OpenFileRead( filename ); - unsigned int magic = LittleInt( *(unsigned int *)data ); - ddsFileHeader_t *_header = (ddsFileHeader_t *)(data + 4); - int ddspf_dwFlags = LittleInt( _header->ddspf.dwFlags ); + if ( !f ) { + return false; + } + int len = f->Length(); - if ( magic != DDS_MAKEFOURCC('D', 'D', 'S', ' ')) { - common->Printf( "CheckPrecompressedImage( %s ): magic != 'DDS '\n", imgName.c_str() ); - R_StaticFree( data ); - return false; - } + if ( len < sizeof( ddsFileHeader_t ) ) { + fileSystem->CloseFile( f ); + return false; + } + byte *data = ( byte * )R_StaticAlloc( len ); - // if we don't support color index textures, we must load the full image - // should we just expand the 256 color image to 32 bit for upload? - if ( ddspf_dwFlags & DDSF_ID_INDEXCOLOR && !glConfig.sharedTexturePaletteAvailable ) { - R_StaticFree( data ); - return false; - } + f->Read( data, len ); - // upload all the levels - UploadPrecompressedImage( data, len ); + fileSystem->CloseFile( f ); - R_StaticFree( data ); + unsigned int magic = LittleInt( *( unsigned int * )data ); + ddsFileHeader_t *_header = ( ddsFileHeader_t * )( data + 4 ); + int ddspf_dwFlags = LittleInt( _header->ddspf.dwFlags ); + if ( magic != DDS_MAKEFOURCC( 'D', 'D', 'S', ' ' ) ) { + common->Printf( "CheckPrecompressedImage( %s ): magic != 'DDS '\n", imgName.c_str() ); + R_StaticFree( data ); + return false; + } - return true; + // if we don't support color index textures, we must load the full image + // should we just expand the 256 color image to 32 bit for upload? + if ( ddspf_dwFlags & DDSF_ID_INDEXCOLOR && !glConfig.sharedTexturePaletteAvailable ) { + R_StaticFree( data ); + return false; + } + + // upload all the levels + UploadPrecompressedImage( data, len ); + + R_StaticFree( data ); + + return true; } /* @@ -1424,130 +1412,131 @@ has completed =================== */ void idImage::UploadPrecompressedImage( byte *data, int len ) { - ddsFileHeader_t *header = (ddsFileHeader_t *)(data + 4); - - // ( not byte swapping dwReserved1 dwReserved2 ) - header->dwSize = LittleInt( header->dwSize ); - header->dwFlags = LittleInt( header->dwFlags ); - header->dwHeight = LittleInt( header->dwHeight ); - header->dwWidth = LittleInt( header->dwWidth ); - header->dwPitchOrLinearSize = LittleInt( header->dwPitchOrLinearSize ); - header->dwDepth = LittleInt( header->dwDepth ); - header->dwMipMapCount = LittleInt( header->dwMipMapCount ); - header->dwCaps1 = LittleInt( header->dwCaps1 ); - header->dwCaps2 = LittleInt( header->dwCaps2 ); - - header->ddspf.dwSize = LittleInt( header->ddspf.dwSize ); - header->ddspf.dwFlags = LittleInt( header->ddspf.dwFlags ); - header->ddspf.dwFourCC = LittleInt( header->ddspf.dwFourCC ); - header->ddspf.dwRGBBitCount = LittleInt( header->ddspf.dwRGBBitCount ); - header->ddspf.dwRBitMask = LittleInt( header->ddspf.dwRBitMask ); - header->ddspf.dwGBitMask = LittleInt( header->ddspf.dwGBitMask ); - header->ddspf.dwBBitMask = LittleInt( header->ddspf.dwBBitMask ); - header->ddspf.dwABitMask = LittleInt( header->ddspf.dwABitMask ); - - // generate the texture number - qglGenTextures( 1, &texnum ); - - int externalFormat = 0; - - precompressedFile = true; - - uploadWidth = header->dwWidth; - uploadHeight = header->dwHeight; - if ( header->ddspf.dwFlags & DDSF_FOURCC ) { - switch ( header->ddspf.dwFourCC ) { - case DDS_MAKEFOURCC( 'D', 'X', 'T', '1' ): - if ( header->ddspf.dwFlags & DDSF_ALPHAPIXELS ) { - internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - } else { - internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; - } - break; - case DDS_MAKEFOURCC( 'D', 'X', 'T', '3' ): - internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - break; - case DDS_MAKEFOURCC( 'D', 'X', 'T', '5' ): - internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - break; - case DDS_MAKEFOURCC( 'R', 'X', 'G', 'B' ): - internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - break; - default: - common->Warning( "Invalid compressed internal format\n" ); - return; - } - } else if ( ( header->ddspf.dwFlags & DDSF_RGBA ) && header->ddspf.dwRGBBitCount == 32 ) { - externalFormat = GL_BGRA_EXT; - internalFormat = GL_RGBA8; - } else if ( ( header->ddspf.dwFlags & DDSF_RGB ) && header->ddspf.dwRGBBitCount == 32 ) { - externalFormat = GL_BGRA_EXT; - internalFormat = GL_RGBA8; - } else if ( ( header->ddspf.dwFlags & DDSF_RGB ) && header->ddspf.dwRGBBitCount == 24 ) { - if ( header->ddspf.dwFlags & DDSF_ID_INDEXCOLOR ) { - externalFormat = GL_COLOR_INDEX; - internalFormat = GL_COLOR_INDEX8_EXT; - } else { - externalFormat = GL_BGR_EXT; - internalFormat = GL_RGB8; - } - } else if ( header->ddspf.dwRGBBitCount == 8 ) { - externalFormat = GL_ALPHA; - internalFormat = GL_ALPHA8; - } else { - common->Warning( "Invalid uncompressed internal format\n" ); - return; - } - - type = TT_2D; // FIXME: we may want to support pre-compressed cube maps in the future - - Bind(); - - int numMipmaps = 1; - if ( header->dwFlags & DDSF_MIPMAPCOUNT ) { - numMipmaps = header->dwMipMapCount; - } - - int uw = uploadWidth; - int uh = uploadHeight; - - // We may skip some mip maps if we are downsizing - int skipMip = 0; - GetDownsize( uploadWidth, uploadHeight ); - - byte *imagedata = data + sizeof(ddsFileHeader_t) + 4; - - for ( int i = 0 ; i < numMipmaps; i++ ) { - int size = 0; - if ( FormatIsDXT( internalFormat ) ) { - size = ( ( uw + 3 ) / 4 ) * ( ( uh + 3 ) / 4 ) * - (internalFormat <= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16); - } else { - size = uw * uh * (header->ddspf.dwRGBBitCount / 8); - } - - if ( uw > uploadWidth || uh > uploadHeight ) { - skipMip++; - } else { - if ( FormatIsDXT( internalFormat ) ) { - qglCompressedTexImage2DARB( GL_TEXTURE_2D, i - skipMip, internalFormat, uw, uh, 0, size, imagedata ); - } else { - qglTexImage2D( GL_TEXTURE_2D, i - skipMip, internalFormat, uw, uh, 0, externalFormat, GL_UNSIGNED_BYTE, imagedata ); - } - } - - imagedata += size; - uw /= 2; - uh /= 2; - if (uw < 1) { - uw = 1; - } - if (uh < 1) { - uh = 1; - } - } - - SetImageFilterAndRepeat(); + ddsFileHeader_t *header = ( ddsFileHeader_t * )( data + 4 ); + + // ( not byte swapping dwReserved1 dwReserved2 ) + header->dwSize = LittleInt( header->dwSize ); + header->dwFlags = LittleInt( header->dwFlags ); + header->dwHeight = LittleInt( header->dwHeight ); + header->dwWidth = LittleInt( header->dwWidth ); + header->dwPitchOrLinearSize = LittleInt( header->dwPitchOrLinearSize ); + header->dwDepth = LittleInt( header->dwDepth ); + header->dwMipMapCount = LittleInt( header->dwMipMapCount ); + header->dwCaps1 = LittleInt( header->dwCaps1 ); + header->dwCaps2 = LittleInt( header->dwCaps2 ); + + header->ddspf.dwSize = LittleInt( header->ddspf.dwSize ); + header->ddspf.dwFlags = LittleInt( header->ddspf.dwFlags ); + header->ddspf.dwFourCC = LittleInt( header->ddspf.dwFourCC ); + header->ddspf.dwRGBBitCount = LittleInt( header->ddspf.dwRGBBitCount ); + header->ddspf.dwRBitMask = LittleInt( header->ddspf.dwRBitMask ); + header->ddspf.dwGBitMask = LittleInt( header->ddspf.dwGBitMask ); + header->ddspf.dwBBitMask = LittleInt( header->ddspf.dwBBitMask ); + header->ddspf.dwABitMask = LittleInt( header->ddspf.dwABitMask ); + + // generate the texture number + qglGenTextures( 1, &texnum ); + + int externalFormat = 0; + + precompressedFile = true; + + uploadWidth = header->dwWidth; + uploadHeight = header->dwHeight; + + if ( header->ddspf.dwFlags & DDSF_FOURCC ) { + switch ( header->ddspf.dwFourCC ) { + case DDS_MAKEFOURCC( 'D', 'X', 'T', '1' ): + if ( header->ddspf.dwFlags & DDSF_ALPHAPIXELS ) { + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + } else { + internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + } + break; + case DDS_MAKEFOURCC( 'D', 'X', 'T', '3' ): + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + case DDS_MAKEFOURCC( 'D', 'X', 'T', '5' ): + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + case DDS_MAKEFOURCC( 'R', 'X', 'G', 'B' ): + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + default: + common->Warning( "Invalid compressed internal format\n" ); + return; + } + } else if ( ( header->ddspf.dwFlags & DDSF_RGBA ) && header->ddspf.dwRGBBitCount == 32 ) { + externalFormat = GL_BGRA_EXT; + internalFormat = GL_RGBA8; + } else if ( ( header->ddspf.dwFlags & DDSF_RGB ) && header->ddspf.dwRGBBitCount == 32 ) { + externalFormat = GL_BGRA_EXT; + internalFormat = GL_RGBA8; + } else if ( ( header->ddspf.dwFlags & DDSF_RGB ) && header->ddspf.dwRGBBitCount == 24 ) { + if ( header->ddspf.dwFlags & DDSF_ID_INDEXCOLOR ) { + externalFormat = GL_COLOR_INDEX; + internalFormat = GL_COLOR_INDEX8_EXT; + } else { + externalFormat = GL_BGR_EXT; + internalFormat = GL_RGB8; + } + } else if ( header->ddspf.dwRGBBitCount == 8 ) { + externalFormat = GL_ALPHA; + internalFormat = GL_ALPHA8; + } else { + common->Warning( "Invalid uncompressed internal format\n" ); + return; + } + type = TT_2D; // FIXME: we may want to support pre-compressed cube maps in the future + + Bind(); + + int numMipmaps = 1; + + if ( header->dwFlags & DDSF_MIPMAPCOUNT ) { + numMipmaps = header->dwMipMapCount; + } + int uw = uploadWidth; + int uh = uploadHeight; + + // We may skip some mip maps if we are downsizing + int skipMip = 0; + + GetDownsize( uploadWidth, uploadHeight ); + + byte *imagedata = data + sizeof( ddsFileHeader_t ) + 4; + for ( int i = 0 ; i < numMipmaps; i++ ) { + int size = 0; + + if ( FormatIsDXT( internalFormat ) ) { + size = ( ( uw + 3 ) / 4 ) * ( ( uh + 3 ) / 4 ) * ( internalFormat <= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16 ); + } else { + size = uw * uh * ( header->ddspf.dwRGBBitCount / 8 ); + } + + if ( uw > uploadWidth || uh > uploadHeight ) { + skipMip++; + } else { + if ( FormatIsDXT( internalFormat ) ) { + qglCompressedTexImage2DARB( GL_TEXTURE_2D, i - skipMip, internalFormat, uw, uh, 0, size, imagedata ); + } else { + qglTexImage2D( GL_TEXTURE_2D, i - skipMip, internalFormat, uw, uh, 0, externalFormat, GL_UNSIGNED_BYTE, imagedata ); + } + } + imagedata += size; + + uw /= 2; + uh /= 2; + + if ( uw < 1 ) { + uw = 1; + } + + if ( uh < 1 ) { + uh = 1; + } + } + SetImageFilterAndRepeat(); } /* @@ -1558,94 +1547,93 @@ Absolutely every image goes through this path On exit, the idImage will have a valid OpenGL texture number that can be bound =============== */ -void idImage::ActuallyLoadImage( bool checkForPrecompressed, bool fromBackEnd ) { - int width, height; - byte *pic; - - // this is the ONLY place generatorFunction will ever be called - if ( generatorFunction ) { - generatorFunction( this ); - return; - } - - // if we are a partial image, we are only going to load from a compressed file - if ( isPartialImage ) { - if ( CheckPrecompressedImage( false ) ) { - return; - } - // this is an error -- the partial image failed to load - MakeDefault(); - return; - } - - // - // load the image from disk - // - if ( cubeFiles != CF_2D ) { - byte *pics[6]; - - // we don't check for pre-compressed cube images currently - R_LoadCubeImages( imgName, cubeFiles, pics, &width, ×tamp ); - - if ( pics[0] == NULL ) { - common->Warning( "Couldn't load cube image: %s", imgName.c_str() ); - MakeDefault(); - return; - } - - GenerateCubeImage( (const byte **)pics, width, filter, allowDownSize, depth ); - precompressedFile = false; - - for ( int i = 0 ; i < 6 ; i++ ) { - if ( pics[i] ) { - R_StaticFree( pics[i] ); - } - } - } else { - // see if we have a pre-generated image file that is - // already image processed and compressed - if ( checkForPrecompressed && globalImages->image_usePrecompressedTextures.GetBool() ) { - if ( CheckPrecompressedImage( true ) ) { - // we got the precompressed image - return; - } - // fall through to load the normal image - } - - R_LoadImageProgram( imgName, &pic, &width, &height, ×tamp, &depth ); - - if ( pic == NULL ) { - common->Warning( "Couldn't load image: %s", imgName.c_str() ); - MakeDefault(); - return; - } -/* - // swap the red and alpha for rxgb support - // do this even on tga normal maps so we only have to use - // one fragment program - // if the image is precompressed ( either in palletized mode or true rxgb mode ) - // then it is loaded above and the swap never happens here - if ( depth == TD_BUMP && globalImages->image_useNormalCompression.GetInteger() != 1 ) { - for ( int i = 0; i < width * height * 4; i += 4 ) { - pic[ i + 3 ] = pic[ i ]; - pic[ i ] = 0; - } - } -*/ - // build a hash for checking duplicate image files - // NOTE: takes about 10% of image load times (SD) - // may not be strictly necessary, but some code uses it, so let's leave it in - imageHash = MD4_BlockChecksum( pic, width * height * 4 ); - - GenerateImage( pic, width, height, filter, allowDownSize, repeat, depth ); - timestamp = timestamp; - precompressedFile = false; - - R_StaticFree( pic ); - - // write out the precompressed version of this file if needed - WritePrecompressedImage(); - } +void idImage::ActuallyLoadImage( bool checkForPrecompressed, bool fromBackEnd ) { + int width, height; + byte *pic; + + // this is the ONLY place generatorFunction will ever be called + if ( generatorFunction ) { + generatorFunction( this ); + return; + } + + // if we are a partial image, we are only going to load from a compressed file + if ( isPartialImage ) { + if ( CheckPrecompressedImage( false ) ) { + return; + } + + // this is an error -- the partial image failed to load + MakeDefault(); + return; + } + + // + // load the image from disk + // + if ( cubeFiles != CF_2D ) { + byte *pics[6]; + + // we don't check for pre-compressed cube images currently + R_LoadCubeImages( imgName, cubeFiles, pics, &width, ×tamp ); + + if ( pics[0] == NULL ) { + common->Warning( "Couldn't load cube image: %s", imgName.c_str() ); + MakeDefault(); + return; + } + GenerateCubeImage( ( const byte ** )pics, width, filter, allowDownSize, depth ); + precompressedFile = false; + + for ( int i = 0 ; i < 6 ; i++ ) { + if ( pics[i] ) { + R_StaticFree( pics[i] ); + } + } + } else { + // see if we have a pre-generated image file that is + // already image processed and compressed + if ( checkForPrecompressed && globalImages->image_usePrecompressedTextures.GetBool() ) { + if ( CheckPrecompressedImage( true ) ) { + // we got the precompressed image + return; + } + // fall through to load the normal image + } + R_LoadImageProgram( imgName, &pic, &width, &height, ×tamp, &depth ); + + if ( pic == NULL ) { + common->Warning( "Couldn't load image: %s", imgName.c_str() ); + MakeDefault(); + return; + } + /* + // swap the red and alpha for rxgb support + // do this even on tga normal maps so we only have to use + // one fragment program + // if the image is precompressed ( either in palletized mode or true rxgb mode ) + // then it is loaded above and the swap never happens here + if ( depth == TD_BUMP && globalImages->image_useNormalCompression.GetInteger() != 1 ) { + for ( int i = 0; i < width * height * 4; i += 4 ) { + pic[ i + 3 ] = pic[ i ]; + pic[ i ] = 0; + } + } + */ + + // build a hash for checking duplicate image files + // NOTE: takes about 10% of image load times (SD) + // may not be strictly necessary, but some code uses it, so let's leave it in + imageHash = MD4_BlockChecksum( pic, width * height * 4 ); + GenerateImage( pic, width, height, filter, allowDownSize, repeat, depth ); + timestamp = timestamp; + precompressedFile = false; + + R_StaticFree( pic ); + + // write out the precompressed version of this file if needed + WritePrecompressedImage(); + } } //========================================================================================================= @@ -1656,17 +1644,17 @@ PurgeImage =============== */ void idImage::PurgeImage() { - if ( texnum != TEXTURE_NOT_LOADED ) { - qglDeleteTextures( 1, &texnum ); // this should be the ONLY place it is ever called! - texnum = TEXTURE_NOT_LOADED; - } - - // clear all the current binding caches, so the next bind will do a real one - for ( int i = 0 ; i < MAX_MULTITEXTURE_UNITS ; i++ ) { - backEnd.glState.tmu[i].current2DMap = -1; - backEnd.glState.tmu[i].current3DMap = -1; - backEnd.glState.tmu[i].currentCubeMap = -1; - } + if ( texnum != TEXTURE_NOT_LOADED ) { + qglDeleteTextures( 1, &texnum ); // this should be the ONLY place it is ever called! + texnum = TEXTURE_NOT_LOADED; + } + + // clear all the current binding caches, so the next bind will do a real one + for ( int i = 0 ; i < MAX_MULTITEXTURE_UNITS ; i++ ) { + backEnd.glState.tmu[i].current2DMap = -1; + backEnd.glState.tmu[i].current3DMap = -1; + backEnd.glState.tmu[i].currentCubeMap = -1; + } } /* @@ -1677,87 +1665,87 @@ Automatically enables 2D mapping, cube mapping, or 3D texturing if needed ============== */ void idImage::Bind() { - // if this is an image that we are caching, move it to the front of the LRU chain - if ( partialImage ) { - if ( cacheUsageNext ) { - // unlink from old position - cacheUsageNext->cacheUsagePrev = cacheUsagePrev; - cacheUsagePrev->cacheUsageNext = cacheUsageNext; - } - // link in at the head of the list - cacheUsageNext = globalImages->cacheLRU.cacheUsageNext; - cacheUsagePrev = &globalImages->cacheLRU; - - cacheUsageNext->cacheUsagePrev = this; - cacheUsagePrev->cacheUsageNext = this; - } - - // load the image if necessary (FIXME: not SMP safe!) - if ( texnum == TEXTURE_NOT_LOADED ) { - if ( partialImage ) { - // if we have a partial image, go ahead and use that - this->partialImage->Bind(); - - // start a background load of the full thing if it isn't already in the queue - if ( !backgroundLoadInProgress ) { - StartBackgroundImageLoad(); - } - return; - } - - // load the image on demand here, which isn't our normal game operating mode - ActuallyLoadImage( true, true ); // check for precompressed, load is from back end - } - - - // bump our statistic counters - frameUsed = backEnd.frameCount; - bindCount++; - - tmu_t *tmu = &backEnd.glState.tmu[backEnd.glState.currenttmu]; - - // enable or disable apropriate texture modes - if ( tmu->textureType != type && ( backEnd.glState.currenttmu < glConfig.maxTextureUnits ) ) { - if ( tmu->textureType == TT_CUBIC ) { - qglDisable( GL_TEXTURE_CUBE_MAP_EXT ); - } else if ( tmu->textureType == TT_3D ) { - qglDisable( GL_TEXTURE_3D ); - } else if ( tmu->textureType == TT_2D ) { - qglDisable( GL_TEXTURE_2D ); - } - - if ( type == TT_CUBIC ) { - qglEnable( GL_TEXTURE_CUBE_MAP_EXT ); - } else if ( type == TT_3D ) { - qglEnable( GL_TEXTURE_3D ); - } else if ( type == TT_2D ) { - qglEnable( GL_TEXTURE_2D ); - } - tmu->textureType = type; - } - - // bind the texture - if ( type == TT_2D ) { - if ( tmu->current2DMap != texnum ) { - tmu->current2DMap = texnum; - qglBindTexture( GL_TEXTURE_2D, texnum ); - } - } else if ( type == TT_CUBIC ) { - if ( tmu->currentCubeMap != texnum ) { - tmu->currentCubeMap = texnum; - qglBindTexture( GL_TEXTURE_CUBE_MAP_EXT, texnum ); - } - } else if ( type == TT_3D ) { - if ( tmu->current3DMap != texnum ) { - tmu->current3DMap = texnum; - qglBindTexture( GL_TEXTURE_3D, texnum ); - } - } - - if ( com_purgeAll.GetBool() ) { - GLclampf priority = 1.0f; - qglPrioritizeTextures( 1, &texnum, &priority ); - } + // if this is an image that we are caching, move it to the front of the LRU chain + if ( partialImage ) { + if ( cacheUsageNext ) { + // unlink from old position + cacheUsageNext->cacheUsagePrev = cacheUsagePrev; + cacheUsagePrev->cacheUsageNext = cacheUsageNext; + } + + // link in at the head of the list + cacheUsageNext = globalImages->cacheLRU.cacheUsageNext; + cacheUsagePrev = &globalImages->cacheLRU; + + cacheUsageNext->cacheUsagePrev = this; + cacheUsagePrev->cacheUsageNext = this; + } + + // load the image if necessary (FIXME: not SMP safe!) + if ( texnum == TEXTURE_NOT_LOADED ) { + if ( partialImage ) { + // if we have a partial image, go ahead and use that + this->partialImage->Bind(); + + // start a background load of the full thing if it isn't already in the queue + if ( !backgroundLoadInProgress ) { + StartBackgroundImageLoad(); + } + return; + } + + // load the image on demand here, which isn't our normal game operating mode + ActuallyLoadImage( true, true ); // check for precompressed, load is from back end + } + + // bump our statistic counters + frameUsed = backEnd.frameCount; + bindCount++; + + tmu_t *tmu = &backEnd.glState.tmu[backEnd.glState.currenttmu]; + + // enable or disable apropriate texture modes + if ( tmu->textureType != type && ( backEnd.glState.currenttmu < glConfig.maxTextureUnits ) ) { + if ( tmu->textureType == TT_CUBIC ) { + qglDisable( GL_TEXTURE_CUBE_MAP_EXT ); + } else if ( tmu->textureType == TT_3D ) { + qglDisable( GL_TEXTURE_3D ); + } else if ( tmu->textureType == TT_2D ) { + qglDisable( GL_TEXTURE_2D ); + } + + if ( type == TT_CUBIC ) { + qglEnable( GL_TEXTURE_CUBE_MAP_EXT ); + } else if ( type == TT_3D ) { + qglEnable( GL_TEXTURE_3D ); + } else if ( type == TT_2D ) { + qglEnable( GL_TEXTURE_2D ); + } + tmu->textureType = type; + } + + // bind the texture + if ( type == TT_2D ) { + if ( tmu->current2DMap != texnum ) { + tmu->current2DMap = texnum; + qglBindTexture( GL_TEXTURE_2D, texnum ); + } + } else if ( type == TT_CUBIC ) { + if ( tmu->currentCubeMap != texnum ) { + tmu->currentCubeMap = texnum; + qglBindTexture( GL_TEXTURE_CUBE_MAP_EXT, texnum ); + } + } else if ( type == TT_3D ) { + if ( tmu->current3DMap != texnum ) { + tmu->current3DMap = texnum; + qglBindTexture( GL_TEXTURE_3D, texnum ); + } + } + + if ( com_purgeAll.GetBool() ) { + GLclampf priority = 1.0f; + qglPrioritizeTextures( 1, &texnum, &priority ); + } } /* @@ -1769,126 +1757,121 @@ do any enable / disable changes ============== */ void idImage::BindFragment() { - // if this is an image that we are caching, move it to the front of the LRU chain - if ( partialImage ) { - if ( cacheUsageNext ) { - // unlink from old position - cacheUsageNext->cacheUsagePrev = cacheUsagePrev; - cacheUsagePrev->cacheUsageNext = cacheUsageNext; - } - // link in at the head of the list - cacheUsageNext = globalImages->cacheLRU.cacheUsageNext; - cacheUsagePrev = &globalImages->cacheLRU; - - cacheUsageNext->cacheUsagePrev = this; - cacheUsagePrev->cacheUsageNext = this; - } - - // load the image if necessary (FIXME: not SMP safe!) - if ( texnum == TEXTURE_NOT_LOADED ) { - if ( partialImage ) { - // if we have a partial image, go ahead and use that - this->partialImage->BindFragment(); - - // start a background load of the full thing if it isn't already in the queue - if ( !backgroundLoadInProgress ) { - StartBackgroundImageLoad(); - } - return; - } - - // load the image on demand here, which isn't our normal game operating mode - ActuallyLoadImage( true, true ); // check for precompressed, load is from back end - } - - - // bump our statistic counters - frameUsed = backEnd.frameCount; - bindCount++; - - // bind the texture - if ( type == TT_2D ) { - qglBindTexture( GL_TEXTURE_2D, texnum ); - } else if ( type == TT_RECT ) { - qglBindTexture( GL_TEXTURE_RECTANGLE_NV, texnum ); - } else if ( type == TT_CUBIC ) { - qglBindTexture( GL_TEXTURE_CUBE_MAP_EXT, texnum ); - } else if ( type == TT_3D ) { - qglBindTexture( GL_TEXTURE_3D, texnum ); - } + // if this is an image that we are caching, move it to the front of the LRU chain + if ( partialImage ) { + if ( cacheUsageNext ) { + // unlink from old position + cacheUsageNext->cacheUsagePrev = cacheUsagePrev; + cacheUsagePrev->cacheUsageNext = cacheUsageNext; + } + + // link in at the head of the list + cacheUsageNext = globalImages->cacheLRU.cacheUsageNext; + cacheUsagePrev = &globalImages->cacheLRU; + + cacheUsageNext->cacheUsagePrev = this; + cacheUsagePrev->cacheUsageNext = this; + } + + // load the image if necessary (FIXME: not SMP safe!) + if ( texnum == TEXTURE_NOT_LOADED ) { + if ( partialImage ) { + // if we have a partial image, go ahead and use that + this->partialImage->BindFragment(); + + // start a background load of the full thing if it isn't already in the queue + if ( !backgroundLoadInProgress ) { + StartBackgroundImageLoad(); + } + return; + } + + // load the image on demand here, which isn't our normal game operating mode + ActuallyLoadImage( true, true ); // check for precompressed, load is from back end + } + + // bump our statistic counters + frameUsed = backEnd.frameCount; + bindCount++; + + // bind the texture + if ( type == TT_2D ) { + qglBindTexture( GL_TEXTURE_2D, texnum ); + } else if ( type == TT_RECT ) { + qglBindTexture( GL_TEXTURE_RECTANGLE_NV, texnum ); + } else if ( type == TT_CUBIC ) { + qglBindTexture( GL_TEXTURE_CUBE_MAP_EXT, texnum ); + } else if ( type == TT_3D ) { + qglBindTexture( GL_TEXTURE_3D, texnum ); + } } - /* ==================== CopyFramebuffer ==================== */ void idImage::CopyFramebuffer( int x, int y, int imageWidth, int imageHeight, bool useOversizedBuffer ) { - Bind(); - - if ( cvarSystem->GetCVarBool( "g_lowresFullscreenFX" ) ) { - imageWidth = 512; - imageHeight = 512; - } - - // if the size isn't a power of 2, the image must be increased in size - int potWidth, potHeight; - - potWidth = MakePowerOfTwo( imageWidth ); - potHeight = MakePowerOfTwo( imageHeight ); - - GetDownsize( imageWidth, imageHeight ); - GetDownsize( potWidth, potHeight ); - - qglReadBuffer( GL_BACK ); - - // only resize if the current dimensions can't hold it at all, - // otherwise subview renderings could thrash this - if ( ( useOversizedBuffer && ( uploadWidth < potWidth || uploadHeight < potHeight ) ) - || ( !useOversizedBuffer && ( uploadWidth != potWidth || uploadHeight != potHeight ) ) ) { - uploadWidth = potWidth; - uploadHeight = potHeight; - if ( potWidth == imageWidth && potHeight == imageHeight ) { - qglCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, x, y, imageWidth, imageHeight, 0 ); - } else { - byte *junk; - // we need to create a dummy image with power of two dimensions, - // then do a qglCopyTexSubImage2D of the data we want - // this might be a 16+ meg allocation, which could fail on _alloca - junk = (byte *)Mem_Alloc( potWidth * potHeight * 4 ); - memset( junk, 0, potWidth * potHeight * 4 ); //!@# -#if 0 // Disabling because it's unnecessary and introduces a green strip on edge of _currentRender - for ( int i = 0 ; i < potWidth * potHeight * 4 ; i+=4 ) { - junk[i+1] = 255; - } -#endif - qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, potWidth, potHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, junk ); - Mem_Free( junk ); - - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, x, y, imageWidth, imageHeight ); - } - } else { - // otherwise, just subimage upload it so that drivers can tell we are going to be changing - // it and don't try and do a texture compression or some other silliness - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, x, y, imageWidth, imageHeight ); - } - - // if the image isn't a full power of two, duplicate an extra row and/or column to fix bilerps - if ( imageWidth != potWidth ) { - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, imageWidth, 0, x+imageWidth-1, y, 1, imageHeight ); - } - if ( imageHeight != potHeight ) { - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, imageHeight, x, y+imageHeight-1, imageWidth, 1 ); - } - - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - - backEnd.c_copyFrameBuffer++; + this->Bind(); + + if ( cvarSystem->GetCVarBool( "g_lowresFullscreenFX" ) ) { + imageWidth = 512; + imageHeight = 512; + } + + // if the size isn't a power of 2, the image must be increased in size + int potWidth, potHeight; + + potWidth = MakePowerOfTwo( imageWidth ); + potHeight = MakePowerOfTwo( imageHeight ); + + GetDownsize( imageWidth, imageHeight ); + GetDownsize( potWidth, potHeight ); + + qglReadBuffer( GL_BACK ); + + // only resize if the current dimensions can't hold it at all, + // otherwise subview renderings could thrash this + if ( ( useOversizedBuffer && ( uploadWidth < potWidth || uploadHeight < potHeight ) ) || + ( !useOversizedBuffer && ( uploadWidth != potWidth || uploadHeight != potHeight ) ) ) { + uploadWidth = potWidth; + uploadHeight = potHeight; + + if ( potWidth == imageWidth && potHeight == imageHeight ) { + qglCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, x, y, imageWidth, imageHeight, 0 ); + } else { + byte *dummyimg; + // we need to create a dummy image with power of two dimensions, + // then do a qglCopyTexSubImage2D of the data we want + // this might be a 16+ meg allocation, which could fail on _alloca + dummyimg = ( byte * )Mem_Alloc( potWidth * potHeight * 4 ); + memset( dummyimg, 0, potWidth * potHeight * 4 ); //!@# + qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, potWidth, potHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, dummyimg ); + Mem_Free( dummyimg ); + + qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, x, y, imageWidth, imageHeight ); + } + } else { + // otherwise, just subimage upload it so that drivers can tell we are going to be changing + // it and don't try and do a texture compression or some other silliness + qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, x, y, imageWidth, imageHeight ); + } + + // if the image isn't a full power of two, duplicate an extra row and/or column to fix bilerps + if ( imageWidth != potWidth ) { + qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, imageWidth, 0, x + imageWidth - 1, y, 1, imageHeight ); + } + + if ( imageHeight != potHeight ) { + qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, imageHeight, x, y + imageHeight - 1, imageWidth, 1 ); + } + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + + backEnd.c_copyFrameBuffer++; } /* @@ -1898,41 +1881,43 @@ CopyDepthbuffer This should just be part of copyFramebuffer once we have a proper image type field ==================== */ -void idImage::CopyDepthbuffer( int x, int y, int imageWidth, int imageHeight, bool useOversizedBuffer ) -{ - this->Bind(); - // if the size isn't a power of 2, the image must be increased in size - int potWidth, potHeight; - - potWidth = MakePowerOfTwo( imageWidth ); - potHeight = MakePowerOfTwo( imageHeight ); - GetDownsize( imageWidth, imageHeight ); - GetDownsize( potWidth, potHeight ); - // Ensure we are reading from the back buffer: - qglReadBuffer( GL_BACK ); - // only resize if the current dimensions can't hold it at all, - // otherwise subview renderings could thrash this - if ( ( useOversizedBuffer && ( uploadWidth < potWidth || uploadHeight < potHeight ) ) || ( !useOversizedBuffer && ( uploadWidth != potWidth || uploadHeight != potHeight ) ) ) - { - uploadWidth = potWidth; - uploadHeight = potHeight; - // This bit runs once only at map start, because it tests whether the image is too small to hold the screen. - // It resizes the texture to a power of two that can hold the screen, - // and then subsequent captures to the texture put the depth component into the RGB channels - qglTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24_ARB, potWidth, potHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL ); - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, x, y, imageWidth, imageHeight ); - - } else { - // otherwise, just subimage upload it so that drivers can tell we are going to be changing - // it and don't try and do a texture compression or some other silliness - qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, x, y, imageWidth, imageHeight ); - } - - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); +void idImage::CopyDepthbuffer( int x, int y, int imageWidth, int imageHeight, bool useOversizedBuffer ) { + this->Bind(); + + // if the size isn't a power of 2, the image must be increased in size + int potWidth, potHeight; + + potWidth = MakePowerOfTwo( imageWidth ); + potHeight = MakePowerOfTwo( imageHeight ); + + GetDownsize( imageWidth, imageHeight ); + GetDownsize( potWidth, potHeight ); + + // Ensure we are reading from the back buffer: + qglReadBuffer( GL_BACK ); + + // only resize if the current dimensions can't hold it at all, + // otherwise subview renderings could thrash this + if ( ( useOversizedBuffer && ( uploadWidth < potWidth || uploadHeight < potHeight ) ) || ( !useOversizedBuffer && ( uploadWidth != potWidth || uploadHeight != potHeight ) ) ) { + uploadWidth = potWidth; + uploadHeight = potHeight; + + // This bit runs once only at map start, because it tests whether the image is too small to hold the screen. + // It resizes the texture to a power of two that can hold the screen, + // and then subsequent captures to the texture put the depth component into the RGB channels + qglTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24_ARB, potWidth, potHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL ); + qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, x, y, imageWidth, imageHeight ); + + } else { + // otherwise, just subimage upload it so that drivers can tell we are going to be changing + // it and don't try and do a texture compression or some other silliness + qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, x, y, imageWidth, imageHeight ); + } + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); } /* @@ -1943,78 +1928,78 @@ if rows = cols * 6, assume it is a cube map animation ============= */ void idImage::UploadScratch( const byte *data, int cols, int rows ) { - int i; - - // if rows = cols * 6, assume it is a cube map animation - if ( rows == cols * 6 ) { - if ( type != TT_CUBIC ) { - type = TT_CUBIC; - uploadWidth = -1; // for a non-sub upload - } - - Bind(); - - rows /= 6; - // if the scratchImage isn't in the format we want, specify it as a new texture - if ( cols != uploadWidth || rows != uploadHeight ) { - uploadWidth = cols; - uploadHeight = rows; - - // upload the base level - for ( i = 0 ; i < 6 ; i++ ) { - qglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT+i, 0, GL_RGB8, cols, rows, 0, - GL_RGBA, GL_UNSIGNED_BYTE, data + cols*rows*4*i ); - } - } else { - // otherwise, just subimage upload it so that drivers can tell we are going to be changing - // it and don't try and do a texture compression - for ( i = 0 ; i < 6 ; i++ ) { - qglTexSubImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT+i, 0, 0, 0, cols, rows, - GL_RGBA, GL_UNSIGNED_BYTE, data + cols*rows*4*i ); - } - } - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - // no other clamp mode makes sense - qglTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - qglTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } else { - // otherwise, it is a 2D image - if ( type != TT_2D ) { - type = TT_2D; - uploadWidth = -1; // for a non-sub upload - } - - Bind(); - - // if the scratchImage isn't in the format we want, specify it as a new texture - if ( cols != uploadWidth || rows != uploadHeight ) { - uploadWidth = cols; - uploadHeight = rows; - qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); - } else { - // otherwise, just subimage upload it so that drivers can tell we are going to be changing - // it and don't try and do a texture compression - qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); - } - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - // these probably should be clamp, but we have a lot of issues with editor - // geometry coming out with texcoords slightly off one side, resulting in - // a smear across the entire polygon -#if 1 - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); -#else - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); -#endif - } + int i; + + // if rows = cols * 6, assume it is a cube map animation + if ( rows == cols * 6 ) { + if ( type != TT_CUBIC ) { + type = TT_CUBIC; + uploadWidth = -1; // for a non-sub upload + } + Bind(); + + rows /= 6; + + // if the scratchImage isn't in the format we want, specify it as a new texture + if ( cols != uploadWidth || rows != uploadHeight ) { + uploadWidth = cols; + uploadHeight = rows; + + // upload the base level + for ( i = 0 ; i < 6 ; i++ ) { + qglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT + i, 0, GL_RGB8, cols, rows, 0, + GL_RGBA, GL_UNSIGNED_BYTE, data + cols * rows * 4 * i ); + } + } else { + // otherwise, just subimage upload it so that drivers can tell we are going to be changing + // it and don't try and do a texture compression + for ( i = 0 ; i < 6 ; i++ ) { + qglTexSubImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT + i, 0, 0, 0, cols, rows, + GL_RGBA, GL_UNSIGNED_BYTE, data + cols * rows * 4 * i ); + } + } + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + // no other clamp mode makes sense + qglTexParameteri( GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + qglTexParameteri( GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + } else { + // otherwise, it is a 2D image + if ( type != TT_2D ) { + type = TT_2D; + uploadWidth = -1; // for a non-sub upload + } + Bind(); + + // if the scratchImage isn't in the format we want, specify it as a new texture + if ( cols != uploadWidth || rows != uploadHeight ) { + uploadWidth = cols; + uploadHeight = rows; + qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); + } else { + // otherwise, just subimage upload it so that drivers can tell we are going to be changing + // it and don't try and do a texture compression + qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); + } + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + // these probably should be clamp, but we have a lot of issues with editor + // geometry coming out with texcoords slightly off one side, resulting in + // a smear across the entire polygon + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + } } - +/* +================== +SetClassification +================== +*/ void idImage::SetClassification( int tag ) { - classification = tag; + classification = tag; } /* @@ -2023,33 +2008,31 @@ StorageSize ================== */ int idImage::StorageSize() const { - int baseSize; - - if ( texnum == TEXTURE_NOT_LOADED ) { - return 0; - } - - switch ( type ) { - default: - case TT_2D: - baseSize = uploadWidth*uploadHeight; - break; - case TT_3D: - baseSize = uploadWidth*uploadHeight*uploadDepth; - break; - case TT_CUBIC: - baseSize = 6 * uploadWidth*uploadHeight; - break; - } - - baseSize *= BitsForInternalFormat( internalFormat ); - - baseSize /= 8; - - // account for mip mapping - baseSize = baseSize * 4 / 3; - - return baseSize; + int baseSize; + + if ( texnum == TEXTURE_NOT_LOADED ) { + return 0; + } + + switch ( type ) { + default: + case TT_2D: + baseSize = uploadWidth * uploadHeight; + break; + case TT_3D: + baseSize = uploadWidth * uploadHeight * uploadDepth; + break; + case TT_CUBIC: + baseSize = 6 * uploadWidth * uploadHeight; + break; + } + baseSize *= BitsForInternalFormat( internalFormat ); + baseSize /= 8; + + // account for mip mapping + baseSize = baseSize * 4 / 3; + + return baseSize; } /* @@ -2058,133 +2041,130 @@ Print ================== */ void idImage::Print() const { - if ( precompressedFile ) { - common->Printf( "P" ); - } else if ( generatorFunction ) { - common->Printf( "F" ); - } else { - common->Printf( " " ); - } - - switch ( type ) { - case TT_2D: - common->Printf( " " ); - break; - case TT_3D: - common->Printf( "3" ); - break; - case TT_CUBIC: - common->Printf( "C" ); - break; - case TT_RECT: - common->Printf( "R" ); - break; - default: - common->Printf( "", type ); - break; - } - - common->Printf( "%4i %4i ", uploadWidth, uploadHeight ); - - switch( filter ) { - case TF_DEFAULT: - common->Printf( "dflt " ); - break; - case TF_LINEAR: - common->Printf( "linr " ); - break; - case TF_NEAREST: - common->Printf( "nrst " ); - break; - default: - common->Printf( "", filter ); - break; - } - - switch ( internalFormat ) { - case GL_INTENSITY8: - case 1: - common->Printf( "I " ); - break; - case 2: - case GL_LUMINANCE8_ALPHA8: - common->Printf( "LA " ); - break; - case 3: - common->Printf( "RGB " ); - break; - case 4: - common->Printf( "RGBA " ); - break; - case GL_LUMINANCE8: - common->Printf( "L " ); - break; - case GL_ALPHA8: - common->Printf( "A " ); - break; - case GL_RGBA8: - common->Printf( "RGBA8 " ); - break; - case GL_RGB8: - common->Printf( "RGB8 " ); - break; - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - common->Printf( "DXT1 " ); - break; - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - common->Printf( "DXT1A " ); - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - common->Printf( "DXT3 " ); - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - common->Printf( "DXT5 " ); - break; - case GL_RGBA4: - common->Printf( "RGBA4 " ); - break; - case GL_RGB5: - common->Printf( "RGB5 " ); - break; - case GL_COLOR_INDEX8_EXT: - common->Printf( "CI8 " ); - break; - case GL_COLOR_INDEX: - common->Printf( "CI " ); - break; - case GL_COMPRESSED_RGB_ARB: - common->Printf( "RGBC " ); - break; - case GL_COMPRESSED_RGBA_ARB: - common->Printf( "RGBAC " ); - break; - case 0: - common->Printf( " " ); - break; - default: - common->Printf( "", internalFormat ); - break; - } - - switch ( repeat ) { - case TR_REPEAT: - common->Printf( "rept " ); - break; - case TR_CLAMP_TO_ZERO: - common->Printf( "zero " ); - break; - case TR_CLAMP_TO_ZERO_ALPHA: - common->Printf( "azro " ); - break; - case TR_CLAMP: - common->Printf( "clmp " ); - break; - default: - common->Printf( "", repeat ); - break; - } - - common->Printf( "%4ik ", StorageSize() / 1024 ); - - common->Printf( " %s\n", imgName.c_str() ); + if ( precompressedFile ) { + common->Printf( "P" ); + } else if ( generatorFunction ) { + common->Printf( "F" ); + } else { + common->Printf( " " ); + } + + switch ( type ) { + case TT_2D: + common->Printf( " " ); + break; + case TT_3D: + common->Printf( "3" ); + break; + case TT_CUBIC: + common->Printf( "C" ); + break; + case TT_RECT: + common->Printf( "R" ); + break; + default: + common->Printf( "", type ); + break; + } + common->Printf( "%4i %4i ", uploadWidth, uploadHeight ); + + switch ( filter ) { + case TF_DEFAULT: + common->Printf( "dflt " ); + break; + case TF_LINEAR: + common->Printf( "linr " ); + break; + case TF_NEAREST: + common->Printf( "nrst " ); + break; + default: + common->Printf( "", filter ); + break; + } + + switch ( internalFormat ) { + case GL_INTENSITY8: + case 1: + common->Printf( "I " ); + break; + case 2: + case GL_LUMINANCE8_ALPHA8: + common->Printf( "LA " ); + break; + case 3: + common->Printf( "RGB " ); + break; + case 4: + common->Printf( "RGBA " ); + break; + case GL_LUMINANCE8: + common->Printf( "L " ); + break; + case GL_ALPHA8: + common->Printf( "A " ); + break; + case GL_RGBA8: + common->Printf( "RGBA8 " ); + break; + case GL_RGB8: + common->Printf( "RGB8 " ); + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + common->Printf( "DXT1 " ); + break; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + common->Printf( "DXT1A " ); + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + common->Printf( "DXT3 " ); + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + common->Printf( "DXT5 " ); + break; + case GL_RGBA4: + common->Printf( "RGBA4 " ); + break; + case GL_RGB5: + common->Printf( "RGB5 " ); + break; + case GL_COLOR_INDEX8_EXT: + common->Printf( "CI8 " ); + break; + case GL_COLOR_INDEX: + common->Printf( "CI " ); + break; + case GL_COMPRESSED_RGB_ARB: + common->Printf( "RGBC " ); + break; + case GL_COMPRESSED_RGBA_ARB: + common->Printf( "RGBAC " ); + break; + case 0: + common->Printf( " " ); + break; + default: + common->Printf( "", internalFormat ); + break; + } + + switch ( repeat ) { + case TR_REPEAT: + common->Printf( "rept " ); + break; + case TR_CLAMP_TO_ZERO: + common->Printf( "zero " ); + break; + case TR_CLAMP_TO_ZERO_ALPHA: + common->Printf( "azro " ); + break; + case TR_CLAMP: + common->Printf( "clmp " ); + break; + default: + common->Printf( "", repeat ); + break; + } + common->Printf( "%4ik ", StorageSize() / 1024 ); + common->Printf( " %s\n", imgName.c_str() ); } diff --git a/neo/renderer/Image_program.cpp b/neo/renderer/Image_program.cpp index 1a02b8729..7f187ef72 100644 --- a/neo/renderer/Image_program.cpp +++ b/neo/renderer/Image_program.cpp @@ -78,9 +78,11 @@ static void R_HeightmapToNormalMap( byte *data, int width, int height, float sca // copy and convert to grey scale j = width * height; - depth = (byte *)R_StaticAlloc( j ); + + depth = ( byte * )R_StaticAlloc( j ); + for ( i = 0 ; i < j ; i++ ) { - depth[i] = ( data[i*4] + data[i*4+1] + data[i*4+2] ) / 3; + depth[i] = ( data[i * 4] + data[i * 4 + 1] + data[i * 4 + 2] ) / 3; } idVec3 dir, dir2; @@ -92,10 +94,10 @@ static void R_HeightmapToNormalMap( byte *data, int width, int height, float sca // FIXME: look at five points? // look at three points to estimate the gradient - a1 = d1 = depth[ ( i * width + j ) ]; - d2 = depth[ ( i * width + ( ( j + 1 ) & ( width - 1 ) ) ) ]; - a3 = d3 = depth[ ( ( ( i + 1 ) & ( height - 1 ) ) * width + j ) ]; - a4 = d4 = depth[ ( ( ( i + 1 ) & ( height - 1 ) ) * width + ( ( j + 1 ) & ( width - 1 ) ) ) ]; + a1 = d1 = depth[( i * width + j ) ]; + d2 = depth[( i * width + ( ( j + 1 ) & ( width - 1 ) ) ) ]; + a3 = d3 = depth[( ( ( i + 1 ) & ( height - 1 ) ) * width + j ) ]; + a4 = d4 = depth[( ( ( i + 1 ) & ( height - 1 ) ) * width + ( ( j + 1 ) & ( width - 1 ) ) ) ]; d2 -= d1; d3 -= d1; @@ -117,14 +119,12 @@ static void R_HeightmapToNormalMap( byte *data, int width, int height, float sca dir.NormalizeFast(); a1 = ( i * width + j ) * 4; - data[ a1 + 0 ] = (byte)(dir[0] * 127 + 128); - data[ a1 + 1 ] = (byte)(dir[1] * 127 + 128); - data[ a1 + 2 ] = (byte)(dir[2] * 127 + 128); + data[ a1 + 0 ] = ( byte )( dir[0] * 127 + 128 ); + data[ a1 + 1 ] = ( byte )( dir[1] * 127 + 128 ); + data[ a1 + 2 ] = ( byte )( dir[2] * 127 + 128 ); data[ a1 + 3 ] = 255; } } - - R_StaticFree( depth ); } @@ -141,7 +141,8 @@ static void R_ImageScale( byte *data, int width, int height, float scale[4] ) { c = width * height * 4; for ( i = 0 ; i < c ; i++ ) { - j = (byte)(data[i] * scale[i&3]); + j = ( byte )( data[i] * scale[i & 3] ); + if ( j < 0 ) { j = 0; } else if ( j > 255 ) { @@ -160,10 +161,10 @@ static void R_InvertAlpha( byte *data, int width, int height ) { int i; int c; - c = width * height* 4; + c = width * height * 4; - for ( i = 0 ; i < c ; i+=4 ) { - data[i+3] = 255 - data[i+3]; + for ( i = 0 ; i < c ; i += 4 ) { + data[i + 3] = 255 - data[i + 3]; } } @@ -176,12 +177,12 @@ static void R_InvertColor( byte *data, int width, int height ) { int i; int c; - c = width * height* 4; + c = width * height * 4; - for ( i = 0 ; i < c ; i+=4 ) { - data[i+0] = 255 - data[i+0]; - data[i+1] = 255 - data[i+1]; - data[i+2] = 255 - data[i+2]; + for ( i = 0 ; i < c ; i += 4 ) { + data[i + 0] = 255 - data[i + 0]; + data[i + 1] = 255 - data[i + 1]; + data[i + 2] = 255 - data[i + 2]; } } @@ -221,17 +222,18 @@ static void R_AddNormalMaps( byte *data1, int width1, int height1, byte *data2, // There are some normal maps that blend to 0,0,0 at the edges // this screws up compression, so we try to correct that here by instead fading it to 0,0,1 len = n.LengthFast(); + if ( len < 1.0f ) { - n[2] = idMath::Sqrt(1.0 - (n[0]*n[0]) - (n[1]*n[1])); + n[2] = idMath::Sqrt( 1.0 - ( n[0] * n[0] ) - ( n[1] * n[1] ) ); } - n[0] += ( d2[0] - 128 ) / 127.0; n[1] += ( d2[1] - 128 ) / 127.0; + n.Normalize(); - d1[0] = (byte)(n[0] * 127 + 128); - d1[1] = (byte)(n[1] * 127 + 128); - d1[2] = (byte)(n[2] * 127 + 128); + d1[0] = ( byte )( n[0] * 127 + 128 ); + d1[1] = ( byte )( n[1] * 127 + 128 ); + d1[2] = ( byte )( n[2] * 127 + 128 ); d1[3] = 255; } } @@ -257,39 +259,39 @@ static void R_SmoothNormalMap( byte *data, int width, int height ) { { 1, 1, 1 } }; - orig = (byte *)R_StaticAlloc( width * height * 4 ); + orig = ( byte * )R_StaticAlloc( width * height * 4 ); memcpy( orig, data, width * height * 4 ); for ( i = 0 ; i < width ; i++ ) { for ( j = 0 ; j < height ; j++ ) { normal = vec3_origin; + for ( k = -1 ; k < 2 ; k++ ) { for ( l = -1 ; l < 2 ; l++ ) { byte *in; - in = orig + ( ((j+l)&(height-1))*width + ((i+k)&(width-1)) ) * 4; + in = orig + ( ( ( j + l ) & ( height - 1 ) ) * width + ( ( i + k ) & ( width - 1 ) ) ) * 4; // ignore 000 and -1 -1 -1 if ( in[0] == 0 && in[1] == 0 && in[2] == 0 ) { continue; } + if ( in[0] == 128 && in[1] == 128 && in[2] == 128 ) { continue; } - - normal[0] += factors[k+1][l+1] * ( in[0] - 128 ); - normal[1] += factors[k+1][l+1] * ( in[1] - 128 ); - normal[2] += factors[k+1][l+1] * ( in[2] - 128 ); + normal[0] += factors[k + 1][l + 1] * ( in[0] - 128 ); + normal[1] += factors[k + 1][l + 1] * ( in[1] - 128 ); + normal[2] += factors[k + 1][l + 1] * ( in[2] - 128 ); } } normal.Normalize(); out = data + ( j * width + i ) * 4; - out[0] = (byte)(128 + 127 * normal[0]); - out[1] = (byte)(128 + 127 * normal[1]); - out[2] = (byte)(128 + 127 * normal[2]); + out[0] = ( byte )( 128 + 127 * normal[0] ); + out[1] = ( byte )( 128 + 127 * normal[1] ); + out[2] = ( byte )( 128 + 127 * normal[2] ); } } - R_StaticFree( orig ); } @@ -312,12 +314,11 @@ static void R_ImageAdd( byte *data1, int width1, int height1, byte *data2, int w } else { newMap = NULL; } - - c = width1 * height1 * 4; for ( i = 0 ; i < c ; i++ ) { j = data1[i] + data2[i]; + if ( j > 255 ) { j = 255; } @@ -329,7 +330,6 @@ static void R_ImageAdd( byte *data1, int width1, int height1, byte *data2, int w } } - // we build a canonical token form of the image program here static char parseBuffer[MAX_IMAGE_NAME]; @@ -355,6 +355,7 @@ static void MatchAndAppendToken( idLexer &src, const char *match ) { if ( !src.ExpectTokenString( match ) ) { return; } + // a matched token won't need a leading space idStr::Append( parseBuffer, MAX_IMAGE_NAME, match ); } @@ -369,7 +370,7 @@ used to parse an image program from a text stream. =================== */ static bool R_ParseImageProgram_r( idLexer &src, byte **pic, int *width, int *height, - ID_TIME_T *timestamps, textureDepth_t *depth ) { + ID_TIME_T *timestamps, textureDepth_t *depth ) { idToken token; float scale; ID_TIME_T timestamp; @@ -383,7 +384,6 @@ static bool R_ParseImageProgram_r( idLexer &src, byte **pic, int *width, int *he if ( !R_ParseImageProgram_r( src, pic, width, height, timestamps, depth ) ) { return false; } - MatchAndAppendToken( src, "," ); src.ReadToken( &token ); @@ -393,11 +393,11 @@ static bool R_ParseImageProgram_r( idLexer &src, byte **pic, int *width, int *he // process it if ( pic ) { R_HeightmapToNormalMap( *pic, *width, *height, scale ); + if ( depth ) { *depth = TD_BUMP; } } - MatchAndAppendToken( src, ")" ); return true; } @@ -411,7 +411,6 @@ static bool R_ParseImageProgram_r( idLexer &src, byte **pic, int *width, int *he if ( !R_ParseImageProgram_r( src, pic, width, height, timestamps, depth ) ) { return false; } - MatchAndAppendToken( src, "," ); if ( !R_ParseImageProgram_r( src, pic ? &pic2 : NULL, &width2, &height2, timestamps, depth ) ) { @@ -426,11 +425,11 @@ static bool R_ParseImageProgram_r( idLexer &src, byte **pic, int *width, int *he if ( pic ) { R_AddNormalMaps( *pic, *width, *height, pic2, width2, height2 ); R_StaticFree( pic2 ); + if ( depth ) { *depth = TD_BUMP; } } - MatchAndAppendToken( src, ")" ); return true; } @@ -444,11 +443,11 @@ static bool R_ParseImageProgram_r( idLexer &src, byte **pic, int *width, int *he if ( pic ) { R_SmoothNormalMap( *pic, *width, *height ); + if ( depth ) { *depth = TD_BUMP; } } - MatchAndAppendToken( src, ")" ); return true; } @@ -462,7 +461,6 @@ static bool R_ParseImageProgram_r( idLexer &src, byte **pic, int *width, int *he if ( !R_ParseImageProgram_r( src, pic, width, height, timestamps, depth ) ) { return false; } - MatchAndAppendToken( src, "," ); if ( !R_ParseImageProgram_r( src, pic ? &pic2 : NULL, &width2, &height2, timestamps, depth ) ) { @@ -478,7 +476,6 @@ static bool R_ParseImageProgram_r( idLexer &src, byte **pic, int *width, int *he R_ImageAdd( *pic, *width, *height, pic2, width2, height2 ); R_StaticFree( pic2 ); } - MatchAndAppendToken( src, ")" ); return true; } @@ -502,7 +499,6 @@ static bool R_ParseImageProgram_r( idLexer &src, byte **pic, int *width, int *he if ( pic ) { R_ImageScale( *pic, *width, *height, scale ); } - MatchAndAppendToken( src, ")" ); return true; } @@ -516,7 +512,6 @@ static bool R_ParseImageProgram_r( idLexer &src, byte **pic, int *width, int *he if ( pic ) { R_InvertAlpha( *pic, *width, *height ); } - MatchAndAppendToken( src, ")" ); return true; } @@ -530,13 +525,12 @@ static bool R_ParseImageProgram_r( idLexer &src, byte **pic, int *width, int *he if ( pic ) { R_InvertColor( *pic, *width, *height ); } - MatchAndAppendToken( src, ")" ); return true; } if ( !token.Icmp( "makeIntensity" ) ) { - int i; + int i; MatchAndAppendToken( src, "(" ); @@ -544,15 +538,13 @@ static bool R_ParseImageProgram_r( idLexer &src, byte **pic, int *width, int *he // copy red to green, blue, and alpha if ( pic ) { - int c; - c = *width * *height * 4; - for ( i = 0 ; i < c ; i+=4 ) { - (*pic)[i+1] = - (*pic)[i+2] = - (*pic)[i+3] = (*pic)[i]; + int c = *width * *height * 4; + for ( i = 0 ; i < c ; i += 4 ) { + ( *pic )[i + 1] = + ( *pic )[i + 2] = + ( *pic )[i + 3] = ( *pic )[i]; } } - MatchAndAppendToken( src, ")" ); return true; } @@ -566,16 +558,14 @@ static bool R_ParseImageProgram_r( idLexer &src, byte **pic, int *width, int *he // average RGB into alpha, then set RGB to white if ( pic ) { - int c; - c = *width * *height * 4; - for ( i = 0 ; i < c ; i+=4 ) { - (*pic)[i+3] = ( (*pic)[i+0] + (*pic)[i+1] + (*pic)[i+2] ) / 3; - (*pic)[i+0] = - (*pic)[i+1] = - (*pic)[i+2] = 255; + int c = *width * *height * 4; + for ( i = 0 ; i < c ; i += 4 ) { + ( *pic )[i + 3] = ( ( *pic )[i + 0] + ( *pic )[i + 1] + ( *pic )[i + 2] ) / 3; + ( *pic )[i + 0] = + ( *pic )[i + 1] = + ( *pic )[i + 2] = 255; } } - MatchAndAppendToken( src, ")" ); return true; } @@ -599,11 +589,9 @@ static bool R_ParseImageProgram_r( idLexer &src, byte **pic, int *width, int *he *timestamps = timestamp; } } - return true; } - /* =================== R_LoadImageProgram @@ -612,14 +600,14 @@ R_LoadImageProgram void R_LoadImageProgram( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamps, textureDepth_t *depth ) { idLexer src; - src.LoadMemory( name, strlen(name), name ); + src.LoadMemory( name, strlen( name ), name ); src.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ); parseBuffer[0] = 0; + if ( timestamps ) { *timestamps = 0; } - R_ParseImageProgram_r( src, pic, width, height, timestamps, depth ); src.FreeSource(); diff --git a/neo/renderer/Interaction.cpp b/neo/renderer/Interaction.cpp index 6f215d8ca..2bb87d8be 100644 --- a/neo/renderer/Interaction.cpp +++ b/neo/renderer/Interaction.cpp @@ -30,7 +30,6 @@ If you have questions concerning this license or the applicable additional terms #include "renderer/tr_local.h" #include "renderer/RenderWorld_local.h" #include "renderer/VertexCache.h" - #include "renderer/Interaction.h" /* @@ -55,30 +54,28 @@ edge silhouettes. ================ */ void R_CalcInteractionFacing( const idRenderEntityLocal *ent, const srfTriangles_t *tri, const idRenderLightLocal *light, srfCullInfo_t &cullInfo ) { - idVec3 localLightOrigin; - - if ( cullInfo.facing != NULL ) { - return; - } - - R_GlobalPointToLocal( ent->modelMatrix, light->globalLightOrigin, localLightOrigin ); + idVec3 localLightOrigin; - int numFaces = tri->numIndexes / 3; + if ( cullInfo.facing != NULL ) { + return; + } + R_GlobalPointToLocal( ent->modelMatrix, light->globalLightOrigin, localLightOrigin ); - if ( !tri->facePlanes || !tri->facePlanesCalculated ) { - R_DeriveFacePlanes( const_cast(tri) ); - } + int numFaces = tri->numIndexes / 3; - cullInfo.facing = (byte *) R_StaticAlloc( ( numFaces + 1 ) * sizeof( cullInfo.facing[0] ) ); + if ( !tri->facePlanes || !tri->facePlanesCalculated ) { + R_DeriveFacePlanes( const_cast( tri ) ); + } + cullInfo.facing = ( byte * ) R_StaticAlloc( ( numFaces + 1 ) * sizeof( cullInfo.facing[0] ) ); - // calculate back face culling - float *planeSide = (float *) _alloca16( numFaces * sizeof( float ) ); + // calculate back face culling + float *planeSide = ( float * ) _alloca16( numFaces * sizeof( float ) ); - // exact geometric cull against face - SIMDProcessor->Dot( planeSide, localLightOrigin, tri->facePlanes, numFaces ); - SIMDProcessor->CmpGE( cullInfo.facing, planeSide, 0.0f, numFaces ); + // exact geometric cull against face + SIMDProcessor->Dot( planeSide, localLightOrigin, tri->facePlanes, numFaces ); + SIMDProcessor->CmpGE( cullInfo.facing, planeSide, 0.0f, numFaces ); - cullInfo.facing[ numFaces ] = 1; // for dangling edges to reference + cullInfo.facing[ numFaces ] = 1; // for dangling edges to reference } /* @@ -92,44 +89,31 @@ vertex is clearly inside, the entire triangle will be accepted. ===================== */ void R_CalcInteractionCullBits( const idRenderEntityLocal *ent, const srfTriangles_t *tri, const idRenderLightLocal *light, srfCullInfo_t &cullInfo ) { - int i, frontBits; - - if ( cullInfo.cullBits != NULL ) { - return; - } - - frontBits = 0; - - // cull the triangle surface bounding box - for ( i = 0; i < 6; i++ ) { - - R_GlobalPlaneToLocal( ent->modelMatrix, -light->frustum[i], cullInfo.localClipPlanes[i] ); - - // get front bits for the whole surface - if ( tri->bounds.PlaneDistance( cullInfo.localClipPlanes[i] ) >= LIGHT_CLIP_EPSILON ) { - frontBits |= 1<numVerts * sizeof( cullInfo.cullBits[0] ) ); - SIMDProcessor->Memset( cullInfo.cullBits, 0, tri->numVerts * sizeof( cullInfo.cullBits[0] ) ); - - float *planeSide = (float *) _alloca16( tri->numVerts * sizeof( float ) ); - - for ( i = 0; i < 6; i++ ) { - // if completely infront of this clipping plane - if ( frontBits & ( 1 << i ) ) { - continue; - } - SIMDProcessor->Dot( planeSide, cullInfo.localClipPlanes[i], tri->verts, tri->numVerts ); - SIMDProcessor->CmpLT( cullInfo.cullBits, i, planeSide, LIGHT_CLIP_EPSILON, tri->numVerts ); - } + int i, frontBits; + + if ( cullInfo.cullBits != NULL ) { + return; + } + frontBits = 0; + + // cull the triangle surface bounding box + for ( i = 0; i < 6; i++ ) { + + R_GlobalPlaneToLocal( ent->modelMatrix, -light->frustum[i], cullInfo.localClipPlanes[i] ); + + // get front bits for the whole surface + if ( tri->bounds.PlaneDistance( cullInfo.localClipPlanes[i] ) >= LIGHT_CLIP_EPSILON ) { + frontBits |= 1 << i; + } + } + + // if the surface is completely inside the light frustum + if ( frontBits == ( ( 1 << 6 ) - 1 ) ) { + cullInfo.cullBits = LIGHT_CULL_ALL_FRONT; + return; + } + cullInfo.cullBits = ( byte * )R_StaticAlloc( tri->numVerts * sizeof( cullInfo.cullBits[0] ) ); + SIMDProcessor->CullByFrustum( tri->verts, tri->numVerts, cullInfo.localClipPlanes, cullInfo.cullBits, LIGHT_CLIP_EPSILON ); } /* @@ -138,22 +122,23 @@ R_FreeInteractionCullInfo ================ */ void R_FreeInteractionCullInfo( srfCullInfo_t &cullInfo ) { - if ( cullInfo.facing != NULL ) { - R_StaticFree( cullInfo.facing ); - cullInfo.facing = NULL; - } - if ( cullInfo.cullBits != NULL ) { - if ( cullInfo.cullBits != LIGHT_CULL_ALL_FRONT ) { - R_StaticFree( cullInfo.cullBits ); - } - cullInfo.cullBits = NULL; - } + if ( cullInfo.facing != NULL ) { + R_StaticFree( cullInfo.facing ); + cullInfo.facing = NULL; + } + + if ( cullInfo.cullBits != NULL ) { + if ( cullInfo.cullBits != LIGHT_CULL_ALL_FRONT ) { + R_StaticFree( cullInfo.cullBits ); + } + cullInfo.cullBits = NULL; + } } -#define MAX_CLIPPED_POINTS 20 +#define MAX_CLIPPED_POINTS 20 typedef struct { - int numVerts; - idVec3 verts[MAX_CLIPPED_POINTS]; + int numVerts; + idVec3 verts[MAX_CLIPPED_POINTS]; } clipTri_t; /* @@ -169,76 +154,78 @@ multiple times near the epsilon. ============= */ static int R_ChopWinding( clipTri_t clipTris[2], int inNum, const idPlane plane ) { - clipTri_t *in, *out; - float dists[MAX_CLIPPED_POINTS]; - int sides[MAX_CLIPPED_POINTS]; - int counts[3]; - float dot; - int i, j; - idVec3 mid; - bool front; - - in = &clipTris[inNum]; - out = &clipTris[inNum^1]; - counts[0] = counts[1] = counts[2] = 0; - - // determine sides for each point - front = false; - for ( i = 0; i < in->numVerts; i++ ) { - dot = in->verts[i] * plane.Normal() + plane[3]; - dists[i] = dot; - if ( dot < LIGHT_CLIP_EPSILON ) { // slop onto the back - sides[i] = SIDE_BACK; - } else { - sides[i] = SIDE_FRONT; - if ( dot > LIGHT_CLIP_EPSILON ) { - front = true; - } - } - counts[sides[i]]++; - } - - // if none in front, it is completely clipped away - if ( !front ) { - in->numVerts = 0; - return inNum; - } - if ( !counts[SIDE_BACK] ) { - return inNum; // inout stays the same - } - - // avoid wrapping checks by duplicating first value to end - sides[i] = sides[0]; - dists[i] = dists[0]; - in->verts[in->numVerts] = in->verts[0]; - - out->numVerts = 0; - for ( i = 0 ; i < in->numVerts ; i++ ) { - idVec3 &p1 = in->verts[i]; - - if ( sides[i] == SIDE_FRONT ) { - out->verts[out->numVerts] = p1; - out->numVerts++; - } - - if ( sides[i+1] == sides[i] ) { - continue; - } - - // generate a split point - idVec3 &p2 = in->verts[i+1]; - - dot = dists[i] / ( dists[i] - dists[i+1] ); - for ( j = 0; j < 3; j++ ) { - mid[j] = p1[j] + dot * ( p2[j] - p1[j] ); - } - - out->verts[out->numVerts] = mid; - - out->numVerts++; - } - - return inNum ^ 1; + clipTri_t *in, *out; + float dists[MAX_CLIPPED_POINTS]; + int sides[MAX_CLIPPED_POINTS]; + int counts[3]; + float dot; + int i, j; + idVec3 mid; + bool front; + + in = &clipTris[inNum]; + out = &clipTris[inNum ^ 1]; + counts[0] = counts[1] = counts[2] = 0; + + // determine sides for each point + front = false; + + for ( i = 0; i < in->numVerts; i++ ) { + dot = in->verts[i] * plane.Normal() + plane[3]; + dists[i] = dot; + + if ( dot < LIGHT_CLIP_EPSILON ) { // slop onto the back + sides[i] = SIDE_BACK; + } else { + sides[i] = SIDE_FRONT; + + if ( dot > LIGHT_CLIP_EPSILON ) { + front = true; + } + } + counts[sides[i]]++; + } + + // if none in front, it is completely clipped away + if ( !front ) { + in->numVerts = 0; + return inNum; + } + + if ( !counts[SIDE_BACK] ) { + return inNum; // inout stays the same + } + + // avoid wrapping checks by duplicating first value to end + sides[i] = sides[0]; + dists[i] = dists[0]; + in->verts[in->numVerts] = in->verts[0]; + out->numVerts = 0; + + for ( i = 0 ; i < in->numVerts ; i++ ) { + idVec3 &p1 = in->verts[i]; + + if ( sides[i] == SIDE_FRONT ) { + out->verts[out->numVerts] = p1; + out->numVerts++; + } + + if ( sides[i + 1] == sides[i] ) { + continue; + } + + // generate a split point + idVec3 &p2 = in->verts[i + 1]; + + dot = dists[i] / ( dists[i] - dists[i + 1] ); + + for ( j = 0; j < 3; j++ ) { + mid[j] = p1[j] + dot * ( p2[j] - p1[j] ); + } + out->verts[out->numVerts] = mid; + out->numVerts++; + } + return inNum ^ 1; } /* @@ -248,27 +235,28 @@ R_ClipTriangleToLight Returns false if nothing is left after clipping =================== */ -static bool R_ClipTriangleToLight( const idVec3 &a, const idVec3 &b, const idVec3 &c, int planeBits, const idPlane frustum[6] ) { - int i; - clipTri_t pingPong[2]; - int p; - - pingPong[0].numVerts = 3; - pingPong[0].verts[0] = a; - pingPong[0].verts[1] = b; - pingPong[0].verts[2] = c; - - p = 0; - for ( i = 0 ; i < 6 ; i++ ) { - if ( planeBits & ( 1 << i ) ) { - p = R_ChopWinding( pingPong, p, frustum[i] ); - if ( pingPong[p].numVerts < 1 ) { - return false; - } - } - } - - return true; +static bool R_ClipTriangleToLight( const idVec3 &a, const idVec3 &b, const idVec3 &c, int planeBits, const idPlane frustum[6] ) { + int i; + clipTri_t pingPong[2]; + int p; + + pingPong[0].numVerts = 3; + pingPong[0].verts[0] = a; + pingPong[0].verts[1] = b; + pingPong[0].verts[2] = c; + + p = 0; + + for ( i = 0 ; i < 6 ; i++ ) { + if ( planeBits & ( 1 << i ) ) { + p = R_ChopWinding( pingPong, p, frustum[i] ); + + if ( pingPong[p].numVerts < 1 ) { + return false; + } + } + } + return true; } /* @@ -280,158 +268,156 @@ it will never clip triangles, but it may cull on a per-triangle basis. ==================== */ static srfTriangles_t *R_CreateLightTris( const idRenderEntityLocal *ent, - const srfTriangles_t *tri, const idRenderLightLocal *light, - const idMaterial *shader, srfCullInfo_t &cullInfo ) { - int i; - int numIndexes; - glIndex_t *indexes; - srfTriangles_t *newTri; - int c_backfaced; - int c_distance; - idBounds bounds; - bool includeBackFaces; - int faceNum; - - tr.pc.c_createLightTris++; - c_backfaced = 0; - c_distance = 0; - - numIndexes = 0; - indexes = NULL; - - // it is debatable if non-shadowing lights should light back faces. we aren't at the moment - if ( r_lightAllBackFaces.GetBool() || light->lightShader->LightEffectsBackSides() - || shader->ReceivesLightingOnBackSides() - || ent->parms.noSelfShadow || ent->parms.noShadow ) { - includeBackFaces = true; - } else { - includeBackFaces = false; - } - - // allocate a new surface for the lit triangles - newTri = R_AllocStaticTriSurf(); - - // save a reference to the original surface - newTri->ambientSurface = const_cast(tri); - - // the light surface references the verts of the ambient surface - newTri->numVerts = tri->numVerts; - R_ReferenceStaticTriSurfVerts( newTri, tri ); - - // calculate cull information - if ( !includeBackFaces ) { - R_CalcInteractionFacing( ent, tri, light, cullInfo ); - } - R_CalcInteractionCullBits( ent, tri, light, cullInfo ); - - // if the surface is completely inside the light frustum - if ( cullInfo.cullBits == LIGHT_CULL_ALL_FRONT ) { - - // if we aren't self shadowing, let back facing triangles get - // through so the smooth shaded bump maps light all the way around - if ( includeBackFaces ) { - - // the whole surface is lit so the light surface just references the indexes of the ambient surface - R_ReferenceStaticTriSurfIndexes( newTri, tri ); - numIndexes = tri->numIndexes; - bounds = tri->bounds; - - } else { - - // the light tris indexes are going to be a subset of the original indexes so we generally - // allocate too much memory here but we decrease the memory block when the number of indexes is known - R_AllocStaticTriSurfIndexes( newTri, tri->numIndexes ); - - // back face cull the individual triangles - indexes = newTri->indexes; - const byte *facing = cullInfo.facing; - for ( faceNum = i = 0; i < tri->numIndexes; i += 3, faceNum++ ) { - if ( !facing[ faceNum ] ) { - c_backfaced++; - continue; - } - indexes[numIndexes+0] = tri->indexes[i+0]; - indexes[numIndexes+1] = tri->indexes[i+1]; - indexes[numIndexes+2] = tri->indexes[i+2]; - numIndexes += 3; - } - - // get bounds for the surface - SIMDProcessor->MinMax( bounds[0], bounds[1], tri->verts, indexes, numIndexes ); - - // decrease the size of the memory block to the size of the number of used indexes - R_ResizeStaticTriSurfIndexes( newTri, numIndexes ); - } - - } else { - - // the light tris indexes are going to be a subset of the original indexes so we generally - // allocate too much memory here but we decrease the memory block when the number of indexes is known - R_AllocStaticTriSurfIndexes( newTri, tri->numIndexes ); - - // cull individual triangles - indexes = newTri->indexes; - const byte *facing = cullInfo.facing; - const byte *cullBits = cullInfo.cullBits; - for ( faceNum = i = 0; i < tri->numIndexes; i += 3, faceNum++ ) { - int i1, i2, i3; - - // if we aren't self shadowing, let back facing triangles get - // through so the smooth shaded bump maps light all the way around - if ( !includeBackFaces ) { - // back face cull - if ( !facing[ faceNum ] ) { - c_backfaced++; - continue; - } - } - - i1 = tri->indexes[i+0]; - i2 = tri->indexes[i+1]; - i3 = tri->indexes[i+2]; - - // fast cull outside the frustum - // if all three points are off one plane side, it definately isn't visible - if ( cullBits[i1] & cullBits[i2] & cullBits[i3] ) { - c_distance++; - continue; - } - - if ( r_usePreciseTriangleInteractions.GetBool() ) { - // do a precise clipped cull if none of the points is completely inside the frustum - // note that we do not actually use the clipped triangle, which would have Z fighting issues. - if ( cullBits[i1] && cullBits[i2] && cullBits[i3] ) { - int cull = cullBits[i1] | cullBits[i2] | cullBits[i3]; - if ( !R_ClipTriangleToLight( tri->verts[i1].xyz, tri->verts[i2].xyz, tri->verts[i3].xyz, cull, cullInfo.localClipPlanes ) ) { - continue; - } - } - } - - // add to the list - indexes[numIndexes+0] = i1; - indexes[numIndexes+1] = i2; - indexes[numIndexes+2] = i3; - numIndexes += 3; - } - - // get bounds for the surface - SIMDProcessor->MinMax( bounds[0], bounds[1], tri->verts, indexes, numIndexes ); - - // decrease the size of the memory block to the size of the number of used indexes - R_ResizeStaticTriSurfIndexes( newTri, numIndexes ); - } - - if ( !numIndexes ) { - R_ReallyFreeStaticTriSurf( newTri ); - return NULL; - } - - newTri->numIndexes = numIndexes; - - newTri->bounds = bounds; - - return newTri; + const srfTriangles_t *tri, const idRenderLightLocal *light, + const idMaterial *shader, srfCullInfo_t &cullInfo ) { + int i; + int numIndexes; + glIndex_t *indexes; + srfTriangles_t *newTri; + int c_backfaced; + int c_distance; + idBounds bounds; + bool includeBackFaces; + int faceNum; + + tr.pc.c_createLightTris++; + c_backfaced = 0; + c_distance = 0; + + numIndexes = 0; + indexes = NULL; + + // it is debatable if non-shadowing lights should light back faces. we aren't at the moment + if ( r_lightAllBackFaces.GetBool() || + light->lightShader->LightEffectsBackSides() || + shader->ReceivesLightingOnBackSides() || + ent->parms.noSelfShadow || ent->parms.noShadow ) { + includeBackFaces = true; + } else { + includeBackFaces = false; + } + + // allocate a new surface for the lit triangles + newTri = R_AllocStaticTriSurf(); + + // save a reference to the original surface + newTri->ambientSurface = const_cast( tri ); + + // the light surface references the verts of the ambient surface + newTri->numVerts = tri->numVerts; + R_ReferenceStaticTriSurfVerts( newTri, tri ); + + // calculate cull information + if ( !includeBackFaces ) { + R_CalcInteractionFacing( ent, tri, light, cullInfo ); + } + R_CalcInteractionCullBits( ent, tri, light, cullInfo ); + + // if the surface is completely inside the light frustum + if ( cullInfo.cullBits == LIGHT_CULL_ALL_FRONT ) { + + // if we aren't self shadowing, let back facing triangles get + // through so the smooth shaded bump maps light all the way around + if ( includeBackFaces ) { + + // the whole surface is lit so the light surface just references the indexes of the ambient surface + R_ReferenceStaticTriSurfIndexes( newTri, tri ); + numIndexes = tri->numIndexes; + bounds = tri->bounds; + + } else { + + // the light tris indexes are going to be a subset of the original indexes so we generally + // allocate too much memory here but we decrease the memory block when the number of indexes is known + R_AllocStaticTriSurfIndexes( newTri, tri->numIndexes ); + + // back face cull the individual triangles + indexes = newTri->indexes; + + const byte *facing = cullInfo.facing; + for ( faceNum = i = 0; i < tri->numIndexes; i += 3, faceNum++ ) { + if ( !facing[ faceNum ] ) { + c_backfaced++; + continue; + } + indexes[numIndexes + 0] = tri->indexes[i + 0]; + indexes[numIndexes + 1] = tri->indexes[i + 1]; + indexes[numIndexes + 2] = tri->indexes[i + 2]; + numIndexes += 3; + } + + // get bounds for the surface + SIMDProcessor->MinMax( bounds[0], bounds[1], tri->verts, indexes, numIndexes ); + + // decrease the size of the memory block to the size of the number of used indexes + R_ResizeStaticTriSurfIndexes( newTri, numIndexes ); + } + } else { + // the light tris indexes are going to be a subset of the original indexes so we generally + // allocate too much memory here but we decrease the memory block when the number of indexes is known + R_AllocStaticTriSurfIndexes( newTri, tri->numIndexes ); + + // cull individual triangles + indexes = newTri->indexes; + + const byte *facing = cullInfo.facing; + const byte *cullBits = cullInfo.cullBits; + for ( faceNum = i = 0; i < tri->numIndexes; i += 3, faceNum++ ) { + int i1, i2, i3; + + // if we aren't self shadowing, let back facing triangles get + // through so the smooth shaded bump maps light all the way around + if ( !includeBackFaces ) { + // back face cull + if ( !facing[ faceNum ] ) { + c_backfaced++; + continue; + } + } + i1 = tri->indexes[i + 0]; + i2 = tri->indexes[i + 1]; + i3 = tri->indexes[i + 2]; + + // fast cull outside the frustum + // if all three points are off one plane side, it definately isn't visible + if ( cullBits[i1] & cullBits[i2] & cullBits[i3] ) { + c_distance++; + continue; + } + + if ( r_usePreciseTriangleInteractions.GetBool() ) { + // do a precise clipped cull if none of the points is completely inside the frustum + // note that we do not actually use the clipped triangle, which would have Z fighting issues. + if ( cullBits[i1] && cullBits[i2] && cullBits[i3] ) { + int cull = cullBits[i1] | cullBits[i2] | cullBits[i3]; + if ( !R_ClipTriangleToLight( tri->verts[i1].xyz, tri->verts[i2].xyz, tri->verts[i3].xyz, cull, cullInfo.localClipPlanes ) ) { + continue; + } + } + } + + // add to the list + indexes[numIndexes + 0] = i1; + indexes[numIndexes + 1] = i2; + indexes[numIndexes + 2] = i3; + numIndexes += 3; + } + + // get bounds for the surface + SIMDProcessor->MinMax( bounds[0], bounds[1], tri->verts, indexes, numIndexes ); + + // decrease the size of the memory block to the size of the number of used indexes + R_ResizeStaticTriSurfIndexes( newTri, numIndexes ); + } + + if ( !numIndexes ) { + R_ReallyFreeStaticTriSurf( newTri ); + return NULL; + } + newTri->numIndexes = numIndexes; + newTri->bounds = bounds; + + return newTri; } /* @@ -440,17 +426,17 @@ idInteraction::idInteraction =============== */ idInteraction::idInteraction( void ) { - numSurfaces = 0; - surfaces = NULL; - entityDef = NULL; - lightDef = NULL; - lightNext = NULL; - lightPrev = NULL; - entityNext = NULL; - entityPrev = NULL; - dynamicModelFrameCount = 0; - frustumState = FRUSTUM_UNINITIALIZED; - frustumAreas = NULL; + numSurfaces = 0; + surfaces = NULL; + entityDef = NULL; + lightDef = NULL; + lightNext = NULL; + lightPrev = NULL; + entityNext = NULL; + entityPrev = NULL; + dynamicModelFrameCount = 0; + frustumState = FRUSTUM_UNINITIALIZED; + frustumAreas = NULL; } /* @@ -459,56 +445,56 @@ idInteraction::AllocAndLink =============== */ idInteraction *idInteraction::AllocAndLink( idRenderEntityLocal *edef, idRenderLightLocal *ldef ) { - if ( !edef || !ldef ) { - common->Error( "idInteraction::AllocAndLink: NULL parm" ); - } - - idRenderWorldLocal *renderWorld = edef->world; - - idInteraction *interaction = renderWorld->interactionAllocator.Alloc(); - - // link and initialize - interaction->dynamicModelFrameCount = 0; - - interaction->lightDef = ldef; - interaction->entityDef = edef; - - interaction->numSurfaces = -1; // not checked yet - interaction->surfaces = NULL; - - interaction->frustumState = idInteraction::FRUSTUM_UNINITIALIZED; - interaction->frustumAreas = NULL; - - // link at the start of the entity's list - interaction->lightNext = ldef->firstInteraction; - interaction->lightPrev = NULL; - ldef->firstInteraction = interaction; - if ( interaction->lightNext != NULL ) { - interaction->lightNext->lightPrev = interaction; - } else { - ldef->lastInteraction = interaction; - } - - // link at the start of the light's list - interaction->entityNext = edef->firstInteraction; - interaction->entityPrev = NULL; - edef->firstInteraction = interaction; - if ( interaction->entityNext != NULL ) { - interaction->entityNext->entityPrev = interaction; - } else { - edef->lastInteraction = interaction; - } - - // update the interaction table - if ( renderWorld->interactionTable ) { - int index = ldef->index * renderWorld->interactionTableWidth + edef->index; - if ( renderWorld->interactionTable[index] != NULL ) { - common->Error( "idInteraction::AllocAndLink: non NULL table entry" ); - } - renderWorld->interactionTable[ index ] = interaction; - } - - return interaction; + if ( !edef || !ldef ) { + common->Error( "idInteraction::AllocAndLink: NULL parm" ); + } + idRenderWorldLocal *renderWorld = edef->world; + idInteraction *interaction = renderWorld->interactionAllocator.Alloc(); + + // link and initialize + interaction->dynamicModelFrameCount = 0; + + interaction->lightDef = ldef; + interaction->entityDef = edef; + + interaction->numSurfaces = -1; // not checked yet + interaction->surfaces = NULL; + + interaction->frustumState = idInteraction::FRUSTUM_UNINITIALIZED; + interaction->frustumAreas = NULL; + + // link at the start of the entity's list + interaction->lightNext = ldef->firstInteraction; + interaction->lightPrev = NULL; + ldef->firstInteraction = interaction; + + if ( interaction->lightNext != NULL ) { + interaction->lightNext->lightPrev = interaction; + } else { + ldef->lastInteraction = interaction; + } + + // link at the start of the light's list + interaction->entityNext = edef->firstInteraction; + interaction->entityPrev = NULL; + edef->firstInteraction = interaction; + + if ( interaction->entityNext != NULL ) { + interaction->entityNext->entityPrev = interaction; + } else { + edef->lastInteraction = interaction; + } + + // update the interaction table + if ( renderWorld->interactionTable ) { + int index = ldef->index * renderWorld->interactionTableWidth + edef->index; + + if ( renderWorld->interactionTable[index] != NULL ) { + common->Error( "idInteraction::AllocAndLink: non NULL table entry" ); + } + renderWorld->interactionTable[ index ] = interaction; + } + return interaction; } /* @@ -520,31 +506,31 @@ will be regenerated automatically =============== */ void idInteraction::FreeSurfaces( void ) { - if ( this->surfaces ) { - for ( int i = 0 ; i < this->numSurfaces ; i++ ) { - surfaceInteraction_t *sint = &this->surfaces[i]; - - if ( sint->lightTris ) { - if ( sint->lightTris != LIGHT_TRIS_DEFERRED ) { - R_FreeStaticTriSurf( sint->lightTris ); - } - sint->lightTris = NULL; - } - if ( sint->shadowTris ) { - // if it doesn't have an entityDef, it is part of a prelight - // model, not a generated interaction - if ( this->entityDef ) { - R_FreeStaticTriSurf( sint->shadowTris ); - sint->shadowTris = NULL; - } - } - R_FreeInteractionCullInfo( sint->cullInfo ); - } - - R_StaticFree( this->surfaces ); - this->surfaces = NULL; - } - this->numSurfaces = -1; + if ( this->surfaces ) { + for ( int i = 0 ; i < this->numSurfaces ; i++ ) { + surfaceInteraction_t *sint = &this->surfaces[i]; + + if ( sint->lightTris ) { + if ( sint->lightTris != LIGHT_TRIS_DEFERRED ) { + R_FreeStaticTriSurf( sint->lightTris ); + } + sint->lightTris = NULL; + } + + if ( sint->shadowTris ) { + // if it doesn't have an entityDef, it is part of a prelight + // model, not a generated interaction + if ( this->entityDef ) { + R_FreeStaticTriSurf( sint->shadowTris ); + sint->shadowTris = NULL; + } + } + R_FreeInteractionCullInfo( sint->cullInfo ); + } + R_StaticFree( this->surfaces ); + this->surfaces = NULL; + } + this->numSurfaces = -1; } /* @@ -554,31 +540,33 @@ idInteraction::Unlink */ void idInteraction::Unlink( void ) { - // unlink from the entity's list - if ( this->entityPrev ) { - this->entityPrev->entityNext = this->entityNext; - } else { - this->entityDef->firstInteraction = this->entityNext; - } - if ( this->entityNext ) { - this->entityNext->entityPrev = this->entityPrev; - } else { - this->entityDef->lastInteraction = this->entityPrev; - } - this->entityNext = this->entityPrev = NULL; - - // unlink from the light's list - if ( this->lightPrev ) { - this->lightPrev->lightNext = this->lightNext; - } else { - this->lightDef->firstInteraction = this->lightNext; - } - if ( this->lightNext ) { - this->lightNext->lightPrev = this->lightPrev; - } else { - this->lightDef->lastInteraction = this->lightPrev; - } - this->lightNext = this->lightPrev = NULL; + // unlink from the entity's list + if ( this->entityPrev ) { + this->entityPrev->entityNext = this->entityNext; + } else { + this->entityDef->firstInteraction = this->entityNext; + } + + if ( this->entityNext ) { + this->entityNext->entityPrev = this->entityPrev; + } else { + this->entityDef->lastInteraction = this->entityPrev; + } + this->entityNext = this->entityPrev = NULL; + + // unlink from the light's list + if ( this->lightPrev ) { + this->lightPrev->lightNext = this->lightNext; + } else { + this->lightDef->firstInteraction = this->lightNext; + } + + if ( this->lightNext ) { + this->lightNext->lightPrev = this->lightPrev; + } else { + this->lightDef->lastInteraction = this->lightPrev; + } + this->lightNext = this->lightPrev = NULL; } /* @@ -590,29 +578,29 @@ Removes links and puts it back on the free list. */ void idInteraction::UnlinkAndFree( void ) { - // clear the table pointer - idRenderWorldLocal *renderWorld = this->lightDef->world; - if ( renderWorld->interactionTable ) { - int index = this->lightDef->index * renderWorld->interactionTableWidth + this->entityDef->index; - if ( renderWorld->interactionTable[index] != this ) { - common->Error( "idInteraction::UnlinkAndFree: interactionTable wasn't set" ); - } - renderWorld->interactionTable[index] = NULL; - } - - Unlink(); - - FreeSurfaces(); - - // free the interaction area references - areaNumRef_t *area, *nextArea; - for ( area = frustumAreas; area; area = nextArea ) { - nextArea = area->next; - renderWorld->areaNumRefAllocator.Free( area ); - } - - // put it back on the free list - renderWorld->interactionAllocator.Free( this ); + // clear the table pointer + idRenderWorldLocal *renderWorld = this->lightDef->world; + if ( renderWorld->interactionTable ) { + int index = this->lightDef->index * renderWorld->interactionTableWidth + this->entityDef->index; + if ( renderWorld->interactionTable[index] != this ) { + common->Error( "idInteraction::UnlinkAndFree: interactionTable wasn't set" ); + } + renderWorld->interactionTable[index] = NULL; + } + Unlink(); + + FreeSurfaces(); + + // free the interaction area references + areaNumRef_t *area, *nextArea; + + for ( area = frustumAreas; area; area = nextArea ) { + nextArea = area->next; + renderWorld->areaNumRefAllocator.Free( area ); + } + + // put it back on the free list + renderWorld->interactionAllocator.Free( this ); } /* @@ -624,30 +612,32 @@ Makes the interaction empty and links it at the end of the entity's and light's */ void idInteraction::MakeEmpty( void ) { - // an empty interaction has no surfaces - numSurfaces = 0; - - Unlink(); - - // relink at the end of the entity's list - this->entityNext = NULL; - this->entityPrev = this->entityDef->lastInteraction; - this->entityDef->lastInteraction = this; - if ( this->entityPrev ) { - this->entityPrev->entityNext = this; - } else { - this->entityDef->firstInteraction = this; - } - - // relink at the end of the light's list - this->lightNext = NULL; - this->lightPrev = this->lightDef->lastInteraction; - this->lightDef->lastInteraction = this; - if ( this->lightPrev ) { - this->lightPrev->lightNext = this; - } else { - this->lightDef->firstInteraction = this; - } + // an empty interaction has no surfaces + numSurfaces = 0; + + Unlink(); + + // relink at the end of the entity's list + this->entityNext = NULL; + this->entityPrev = this->entityDef->lastInteraction; + this->entityDef->lastInteraction = this; + + if ( this->entityPrev ) { + this->entityPrev->entityNext = this; + } else { + this->entityDef->firstInteraction = this; + } + + // relink at the end of the light's list + this->lightNext = NULL; + this->lightPrev = this->lightDef->lastInteraction; + this->lightDef->lastInteraction = this; + + if ( this->lightPrev ) { + this->lightPrev->lightNext = this; + } else { + this->lightDef->firstInteraction = this; + } } /* @@ -656,7 +646,7 @@ idInteraction::HasShadows =============== */ ID_INLINE bool idInteraction::HasShadows( void ) const { - return ( !lightDef->parms.noShadows && !entityDef->parms.noShadow && lightDef->lightShader->LightCastsShadows() ); + return ( !lightDef->parms.noShadows && !entityDef->parms.noShadow && lightDef->lightShader->LightCastsShadows() ); } /* @@ -668,16 +658,15 @@ will be used to determine when we need to start purging old interactions. =============== */ int idInteraction::MemoryUsed( void ) { - int total = 0; + int total = 0; - for ( int i = 0 ; i < numSurfaces ; i++ ) { - surfaceInteraction_t *inter = &surfaces[i]; + for ( int i = 0 ; i < numSurfaces ; i++ ) { + surfaceInteraction_t *inter = &surfaces[i]; - total += R_TriSurfMemory( inter->lightTris ); - total += R_TriSurfMemory( inter->shadowTris ); - } - - return total; + total += R_TriSurfMemory( inter->lightTris ); + total += R_TriSurfMemory( inter->shadowTris ); + } + return total; } /* @@ -686,78 +675,77 @@ idInteraction::CalcInteractionScissorRectangle ================== */ idScreenRect idInteraction::CalcInteractionScissorRectangle( const idFrustum &viewFrustum ) { - idBounds projectionBounds; - idScreenRect portalRect; - idScreenRect scissorRect; - - if ( r_useInteractionScissors.GetInteger() == 0 ) { - return lightDef->viewLight->scissorRect; - } - - if ( r_useInteractionScissors.GetInteger() < 0 ) { - // this is the code from Cass at nvidia, it is more precise, but slower - return R_CalcIntersectionScissor( lightDef, entityDef, tr.viewDef ); - } - - // the following is Mr.E's code - - // frustum must be initialized and valid - if ( frustumState == idInteraction::FRUSTUM_UNINITIALIZED || frustumState == idInteraction::FRUSTUM_INVALID ) { - return lightDef->viewLight->scissorRect; - } - - // calculate scissors for the portals through which the interaction is visible - if ( r_useInteractionScissors.GetInteger() > 1 ) { - areaNumRef_t *area; - - if ( frustumState == idInteraction::FRUSTUM_VALID ) { - // retrieve all the areas the interaction frustum touches - for ( areaReference_t *ref = entityDef->entityRefs; ref; ref = ref->ownerNext ) { - area = entityDef->world->areaNumRefAllocator.Alloc(); - area->areaNum = ref->area->areaNum; - area->next = frustumAreas; - frustumAreas = area; - } - frustumAreas = tr.viewDef->renderWorld->FloodFrustumAreas( frustum, frustumAreas ); - frustumState = idInteraction::FRUSTUM_VALIDAREAS; - } - - portalRect.Clear(); - for ( area = frustumAreas; area; area = area->next ) { - portalRect.Union( entityDef->world->GetAreaScreenRect( area->areaNum ) ); - } - portalRect.Intersect( lightDef->viewLight->scissorRect ); - } else { - portalRect = lightDef->viewLight->scissorRect; - } - - // early out if the interaction is not visible through any portals - if ( portalRect.IsEmpty() ) { - return portalRect; - } - - // calculate bounds of the interaction frustum projected into the view frustum - if ( lightDef->parms.pointLight ) { - viewFrustum.ClippedProjectionBounds( frustum, idBox( lightDef->parms.origin, lightDef->parms.lightRadius, lightDef->parms.axis ), projectionBounds ); - } else { - viewFrustum.ClippedProjectionBounds( frustum, idBox( lightDef->frustumTris->bounds ), projectionBounds ); - } - - if ( projectionBounds.IsCleared() ) { - return portalRect; - } - - // derive a scissor rectangle from the projection bounds - scissorRect = R_ScreenRectFromViewFrustumBounds( projectionBounds ); - - // intersect with the portal crossing scissor rectangle - scissorRect.Intersect( portalRect ); - - if ( r_showInteractionScissors.GetInteger() > 0 ) { - R_ShowColoredScreenRect( scissorRect, lightDef->index ); - } - - return scissorRect; + idBounds projectionBounds; + idScreenRect portalRect; + idScreenRect scissorRect; + + if ( r_useInteractionScissors.GetInteger() == 0 ) { + return lightDef->viewLight->scissorRect; + } + + if ( r_useInteractionScissors.GetInteger() < 0 ) { + // this is the code from Cass at nvidia, it is more precise, but slower + return R_CalcIntersectionScissor( lightDef, entityDef, tr.viewDef ); + } + + // the following is Mr.E's code + + // frustum must be initialized and valid + if ( frustumState == idInteraction::FRUSTUM_UNINITIALIZED || frustumState == idInteraction::FRUSTUM_INVALID ) { + return lightDef->viewLight->scissorRect; + } + + // calculate scissors for the portals through which the interaction is visible + if ( r_useInteractionScissors.GetInteger() > 1 ) { + areaNumRef_t *area; + + if ( frustumState == idInteraction::FRUSTUM_VALID ) { + // retrieve all the areas the interaction frustum touches + for ( areaReference_t *ref = entityDef->entityRefs; ref; ref = ref->ownerNext ) { + area = entityDef->world->areaNumRefAllocator.Alloc(); + area->areaNum = ref->area->areaNum; + area->next = frustumAreas; + frustumAreas = area; + } + frustumAreas = tr.viewDef->renderWorld->FloodFrustumAreas( frustum, frustumAreas ); + frustumState = idInteraction::FRUSTUM_VALIDAREAS; + } + portalRect.Clear(); + + for ( area = frustumAreas; area; area = area->next ) { + portalRect.Union( entityDef->world->GetAreaScreenRect( area->areaNum ) ); + } + portalRect.Intersect( lightDef->viewLight->scissorRect ); + } else { + portalRect = lightDef->viewLight->scissorRect; + } + + // early out if the interaction is not visible through any portals + if ( portalRect.IsEmpty() ) { + return portalRect; + } + + // calculate bounds of the interaction frustum projected into the view frustum + if ( lightDef->parms.pointLight ) { + viewFrustum.ClippedProjectionBounds( frustum, idBox( lightDef->parms.origin, lightDef->parms.lightRadius, lightDef->parms.axis ), projectionBounds ); + } else { + viewFrustum.ClippedProjectionBounds( frustum, idBox( lightDef->frustumTris->bounds ), projectionBounds ); + } + + if ( projectionBounds.IsCleared() ) { + return portalRect; + } + + // derive a scissor rectangle from the projection bounds + scissorRect = R_ScreenRectFromViewFrustumBounds( projectionBounds ); + + // intersect with the portal crossing scissor rectangle + scissorRect.Intersect( portalRect ); + + if ( r_showInteractionScissors.GetInteger() > 0 ) { + R_ShowColoredScreenRect( scissorRect, lightDef->index ); + } + return scissorRect; } /* @@ -767,45 +755,44 @@ idInteraction::CullInteractionByViewFrustum */ bool idInteraction::CullInteractionByViewFrustum( const idFrustum &viewFrustum ) { - if ( !r_useInteractionCulling.GetBool() ) { - return false; - } - - if ( frustumState == idInteraction::FRUSTUM_INVALID ) { - return false; - } + if ( !r_useInteractionCulling.GetBool() ) { + return false; + } - if ( frustumState == idInteraction::FRUSTUM_UNINITIALIZED ) { + if ( frustumState == idInteraction::FRUSTUM_INVALID ) { + return false; + } - frustum.FromProjection( idBox( entityDef->referenceBounds, entityDef->parms.origin, entityDef->parms.axis ), lightDef->globalLightOrigin, MAX_WORLD_SIZE ); + if ( frustumState == idInteraction::FRUSTUM_UNINITIALIZED ) { - if ( !frustum.IsValid() ) { - frustumState = idInteraction::FRUSTUM_INVALID; - return false; - } + frustum.FromProjection( idBox( entityDef->referenceBounds, entityDef->parms.origin, entityDef->parms.axis ), lightDef->globalLightOrigin, MAX_WORLD_SIZE ); - if ( lightDef->parms.pointLight ) { - frustum.ConstrainToBox( idBox( lightDef->parms.origin, lightDef->parms.lightRadius, lightDef->parms.axis ) ); - } else { - frustum.ConstrainToBox( idBox( lightDef->frustumTris->bounds ) ); - } + if ( !frustum.IsValid() ) { + frustumState = idInteraction::FRUSTUM_INVALID; + return false; + } - frustumState = idInteraction::FRUSTUM_VALID; - } + if ( lightDef->parms.pointLight ) { + frustum.ConstrainToBox( idBox( lightDef->parms.origin, lightDef->parms.lightRadius, lightDef->parms.axis ) ); + } else { + frustum.ConstrainToBox( idBox( lightDef->frustumTris->bounds ) ); + } + frustumState = idInteraction::FRUSTUM_VALID; + } - if ( !viewFrustum.IntersectsFrustum( frustum ) ) { - return true; - } + if ( !viewFrustum.IntersectsFrustum( frustum ) ) { + return true; + } - if ( r_showInteractionFrustums.GetInteger() ) { - static idVec4 colors[] = { colorRed, colorGreen, colorBlue, colorYellow, colorMagenta, colorCyan, colorWhite, colorPurple }; - tr.viewDef->renderWorld->DebugFrustum( colors[lightDef->index & 7], frustum, ( r_showInteractionFrustums.GetInteger() > 1 ) ); - if ( r_showInteractionFrustums.GetInteger() > 2 ) { - tr.viewDef->renderWorld->DebugBox( colorWhite, idBox( entityDef->referenceBounds, entityDef->parms.origin, entityDef->parms.axis ) ); - } - } + if ( r_showInteractionFrustums.GetInteger() ) { + static idVec4 colors[] = { colorRed, colorGreen, colorBlue, colorYellow, colorMagenta, colorCyan, colorWhite, colorPurple }; + tr.viewDef->renderWorld->DebugFrustum( colors[lightDef->index & 7], frustum, ( r_showInteractionFrustums.GetInteger() > 1 ) ); - return false; + if ( r_showInteractionFrustums.GetInteger() > 2 ) { + tr.viewDef->renderWorld->DebugBox( colorWhite, idBox( entityDef->referenceBounds, entityDef->parms.origin, entityDef->parms.axis ) ); + } + } + return false; } /* @@ -823,120 +810,120 @@ The results of this are cached and valid until the light or entity change. ==================== */ void idInteraction::CreateInteraction( const idRenderModel *model ) { - const idMaterial * lightShader = lightDef->lightShader; - const idMaterial* shader; - bool interactionGenerated; - idBounds bounds; - - tr.pc.c_createInteractions++; - - bounds = model->Bounds( &entityDef->parms ); - - // if it doesn't contact the light frustum, none of the surfaces will - if ( R_CullLocalBox( bounds, entityDef->modelMatrix, 6, lightDef->frustum ) ) { - MakeEmpty(); - return; - } - - // use the turbo shadow path - shadowGen_t shadowGen = SG_DYNAMIC; - - // really large models, like outside terrain meshes, should use - // the more exactly culled static shadow path instead of the turbo shadow path. - // FIXME: this is a HACK, we should probably have a material flag. - if ( bounds[1][0] - bounds[0][0] > 3000 ) { - shadowGen = SG_STATIC; - } - - // - // create slots for each of the model's surfaces - // - numSurfaces = model->NumSurfaces(); - surfaces = (surfaceInteraction_t *)R_ClearedStaticAlloc( sizeof( *surfaces ) * numSurfaces ); - - interactionGenerated = false; - - // check each surface in the model - for ( int c = 0 ; c < model->NumSurfaces() ; c++ ) { - const modelSurface_t *surf; - srfTriangles_t *tri; - - surf = model->Surface( c ); - - tri = surf->geometry; - if ( !tri ) { - continue; - } - - // determine the shader for this surface, possibly by skinning - shader = surf->shader; - shader = R_RemapShaderBySkin( shader, entityDef->parms.customSkin, entityDef->parms.customShader ); - - if ( !shader ) { - continue; - } - - // try to cull each surface - if ( R_CullLocalBox( tri->bounds, entityDef->modelMatrix, 6, lightDef->frustum ) ) { - continue; - } - - surfaceInteraction_t *sint = &surfaces[c]; - - sint->shader = shader; - - // save the ambient tri pointer so we can reject lightTri interactions - // when the ambient surface isn't in view, and we can get shared vertex - // and shadow data from the source surface - sint->ambientTris = tri; - - // "invisible ink" lights and shaders - if ( shader->Spectrum() != lightShader->Spectrum() ) { - continue; - } - - // generate a lighted surface and add it - if ( shader->ReceivesLighting() ) { - if ( tri->ambientViewCount == tr.viewCount ) { - sint->lightTris = R_CreateLightTris( entityDef, tri, lightDef, shader, sint->cullInfo ); - } else { - // this will be calculated when sint->ambientTris is actually in view - sint->lightTris = LIGHT_TRIS_DEFERRED; - } - interactionGenerated = true; - } - - // if the interaction has shadows and this surface casts a shadow - if ( HasShadows() && shader->SurfaceCastsShadow() && tri->silEdges != NULL ) { - - // if the light has an optimized shadow volume, don't create shadows for any models that are part of the base areas - if ( lightDef->parms.prelightModel == NULL || !model->IsStaticWorldModel() || !r_useOptimizedShadows.GetBool() ) { - - // this is the only place during gameplay (outside the utilities) that R_CreateShadowVolume() is called - sint->shadowTris = R_CreateShadowVolume( entityDef, tri, lightDef, shadowGen, sint->cullInfo ); - if ( sint->shadowTris ) { - if ( shader->Coverage() != MC_OPAQUE || ( !r_skipSuppress.GetBool() && entityDef->parms.suppressSurfaceInViewID ) ) { - // if any surface is a shadow-casting perforated or translucent surface, or the - // base surface is suppressed in the view (world weapon shadows) we can't use - // the external shadow optimizations because we can see through some of the faces - sint->shadowTris->numShadowIndexesNoCaps = sint->shadowTris->numIndexes; - sint->shadowTris->numShadowIndexesNoFrontCaps = sint->shadowTris->numIndexes; - } - } - interactionGenerated = true; - } - } - - // free the cull information when it's no longer needed - if ( sint->lightTris != LIGHT_TRIS_DEFERRED ) { - R_FreeInteractionCullInfo( sint->cullInfo ); - } - } - - // if none of the surfaces generated anything, don't even bother checking? - if ( !interactionGenerated ) { - MakeEmpty(); - } + const idMaterial *lightShader = lightDef->lightShader; + const idMaterial *shader; + bool interactionGenerated; + idBounds bounds; + + tr.pc.c_createInteractions++; + + bounds = model->Bounds( &entityDef->parms ); + + // if it doesn't contact the light frustum, none of the surfaces will + if ( R_CullLocalBox( bounds, entityDef->modelMatrix, 6, lightDef->frustum ) ) { + MakeEmpty(); + return; + } + + // use the turbo shadow path + shadowGen_t shadowGen = SG_DYNAMIC; + + // really large models, like outside terrain meshes, should use + // the more exactly culled static shadow path instead of the turbo shadow path. + // FIXME: this is a HACK, we should probably have a material flag. + if ( bounds[1][0] - bounds[0][0] > 3000 ) { + shadowGen = SG_STATIC; + } + + // + // create slots for each of the model's surfaces + // + numSurfaces = model->NumSurfaces(); + surfaces = ( surfaceInteraction_t * )R_ClearedStaticAlloc( sizeof( *surfaces ) * numSurfaces ); + + interactionGenerated = false; + + // check each surface in the model + for ( int c = 0 ; c < model->NumSurfaces() ; c++ ) { + const modelSurface_t *surf; + srfTriangles_t *tri; + + surf = model->Surface( c ); + tri = surf->geometry; + + if ( !tri ) { + continue; + } + + // determine the shader for this surface, possibly by skinning + shader = surf->shader; + shader = R_RemapShaderBySkin( shader, entityDef->parms.customSkin, entityDef->parms.customShader ); + + if ( !shader ) { + continue; + } + + // try to cull each surface + if ( R_CullLocalBox( tri->bounds, entityDef->modelMatrix, 6, lightDef->frustum ) ) { + continue; + } + surfaceInteraction_t *sint = &surfaces[c]; + + sint->shader = shader; + + // save the ambient tri pointer so we can reject lightTri interactions + // when the ambient surface isn't in view, and we can get shared vertex + // and shadow data from the source surface + sint->ambientTris = tri; + + // "invisible ink" lights and shaders + if ( shader->Spectrum() != lightShader->Spectrum() ) { + continue; + } + + // generate a lighted surface and add it + if ( shader->ReceivesLighting() ) { + if ( tri->ambientViewCount == tr.viewCount ) { + sint->lightTris = R_CreateLightTris( entityDef, tri, lightDef, shader, sint->cullInfo ); + } else { + // this will be calculated when sint->ambientTris is actually in view + sint->lightTris = LIGHT_TRIS_DEFERRED; + } + interactionGenerated = true; + } + + // if the interaction has shadows and this surface casts a shadow + if ( HasShadows() && shader->SurfaceCastsShadow() && tri->silEdges != NULL ) { + + // if the light has an optimized shadow volume, don't create shadows for any models that are part of the base areas + if ( lightDef->parms.prelightModel == NULL || !model->IsStaticWorldModel() || !r_useOptimizedShadows.GetBool() ) { + + // this is the only place during gameplay (outside the utilities) that R_CreateShadowVolume() is called + sint->shadowTris = R_CreateShadowVolume( entityDef, tri, lightDef, shadowGen, sint->cullInfo ); + + if ( sint->shadowTris ) { + if ( shader->Coverage() != MC_OPAQUE || ( !r_skipSuppress.GetBool() && entityDef->parms.suppressSurfaceInViewID ) ) { + // if any surface is a shadow-casting perforated or translucent surface, or the + // base surface is suppressed in the view (world weapon shadows) we can't use + // the external shadow optimizations because we can see through some of the faces + sint->shadowTris->numShadowIndexesNoCaps = sint->shadowTris->numIndexes; + sint->shadowTris->numShadowIndexesNoFrontCaps = sint->shadowTris->numIndexes; + } + } + interactionGenerated = true; + } + } + + // free the cull information when it's no longer needed + if ( sint->lightTris != LIGHT_TRIS_DEFERRED ) { + R_FreeInteractionCullInfo( sint->cullInfo ); + } + } + + // if none of the surfaces generated anything, don't even bother checking? + if ( !interactionGenerated ) { + MakeEmpty(); + } } /* @@ -948,68 +935,70 @@ we can draw it without caps in zpass mode ====================== */ static bool R_PotentiallyInsideInfiniteShadow( const srfTriangles_t *occluder, - const idVec3 &localView, const idVec3 &localLight ) { - idBounds exp; - - // expand the bounds to account for the near clip plane, because the - // view could be mathematically outside, but if the near clip plane - // chops a volume edge, the zpass rendering would fail. - float znear = r_znear.GetFloat(); - if ( tr.viewDef->renderView.cramZNear ) { - znear *= 0.25f; - } - float stretch = znear * 2; // in theory, should vary with FOV - exp[0][0] = occluder->bounds[0][0] - stretch; - exp[0][1] = occluder->bounds[0][1] - stretch; - exp[0][2] = occluder->bounds[0][2] - stretch; - exp[1][0] = occluder->bounds[1][0] + stretch; - exp[1][1] = occluder->bounds[1][1] + stretch; - exp[1][2] = occluder->bounds[1][2] + stretch; - - if ( exp.ContainsPoint( localView ) ) { - return true; - } - if ( exp.ContainsPoint( localLight ) ) { - return true; - } - - // if the ray from localLight to localView intersects a face of the - // expanded bounds, we will be inside the projection - - idVec3 ray = localView - localLight; - - // intersect the ray from the view to the light with the near side of the bounds - for ( int axis = 0; axis < 3; axis++ ) { - float d, frac; - idVec3 hit; - - if ( localLight[axis] < exp[0][axis] ) { - if ( localView[axis] < exp[0][axis] ) { - continue; - } - d = exp[0][axis] - localLight[axis]; - frac = d / ray[axis]; - hit = localLight + frac * ray; - hit[axis] = exp[0][axis]; - } else if ( localLight[axis] > exp[1][axis] ) { - if ( localView[axis] > exp[1][axis] ) { - continue; - } - d = exp[1][axis] - localLight[axis]; - frac = d / ray[axis]; - hit = localLight + frac * ray; - hit[axis] = exp[1][axis]; - } else { - continue; - } - - if ( exp.ContainsPoint( hit ) ) { - return true; - } - } - - // the view is definitely not inside the projected shadow - return false; + const idVec3 &localView, const idVec3 &localLight ) { + idBounds exp; + + // expand the bounds to account for the near clip plane, because the + // view could be mathematically outside, but if the near clip plane + // chops a volume edge, the zpass rendering would fail. + float znear = r_znear.GetFloat(); + + if ( tr.viewDef->renderView.cramZNear ) { + znear *= 0.25f; + } + float stretch = znear * 2; // in theory, should vary with FOV + + exp[0][0] = occluder->bounds[0][0] - stretch; + exp[0][1] = occluder->bounds[0][1] - stretch; + exp[0][2] = occluder->bounds[0][2] - stretch; + exp[1][0] = occluder->bounds[1][0] + stretch; + exp[1][1] = occluder->bounds[1][1] + stretch; + exp[1][2] = occluder->bounds[1][2] + stretch; + + if ( exp.ContainsPoint( localView ) ) { + return true; + } + + if ( exp.ContainsPoint( localLight ) ) { + return true; + } + + // if the ray from localLight to localView intersects a face of the + // expanded bounds, we will be inside the projection + idVec3 ray = localView - localLight; + + // intersect the ray from the view to the light with the near side of the bounds + for ( int axis = 0; axis < 3; axis++ ) { + float d, frac; + idVec3 hit; + + if ( localLight[axis] < exp[0][axis] ) { + if ( localView[axis] < exp[0][axis] ) { + continue; + } + d = exp[0][axis] - localLight[axis]; + frac = d / ray[axis]; + hit = localLight + frac * ray; + hit[axis] = exp[0][axis]; + } else if ( localLight[axis] > exp[1][axis] ) { + if ( localView[axis] > exp[1][axis] ) { + continue; + } + d = exp[1][axis] - localLight[axis]; + frac = d / ray[axis]; + hit = localLight + frac * ray; + hit[axis] = exp[1][axis]; + } else { + continue; + } + + if ( exp.ContainsPoint( hit ) ) { + return true; + } + } + + // the view is definitely not inside the projected shadow + return false; } /* @@ -1024,225 +1013,224 @@ instantiate the dynamic model to find out ================== */ void idInteraction::AddActiveInteraction( void ) { - viewLight_t * vLight; - viewEntity_t * vEntity; - idScreenRect shadowScissor; - idScreenRect lightScissor; - idVec3 localLightOrigin; - idVec3 localViewOrigin; - - vLight = lightDef->viewLight; - vEntity = entityDef->viewEntity; - - // do not waste time culling the interaction frustum if there will be no shadows - if ( !HasShadows() ) { - - // use the entity scissor rectangle - shadowScissor = vEntity->scissorRect; - - // culling does not seem to be worth it for static world models - } else if ( entityDef->parms.hModel->IsStaticWorldModel() ) { - - // use the light scissor rectangle - shadowScissor = vLight->scissorRect; - - } else { - - // try to cull the interaction - // this will also cull the case where the light origin is inside the - // view frustum and the entity bounds are outside the view frustum - if ( CullInteractionByViewFrustum( tr.viewDef->viewFrustum ) ) { - return; - } - - // calculate the shadow scissor rectangle - shadowScissor = CalcInteractionScissorRectangle( tr.viewDef->viewFrustum ); - } - - // get out before making the dynamic model if the shadow scissor rectangle is empty - if ( shadowScissor.IsEmpty() ) { - return; - } - - // We will need the dynamic surface created to make interactions, even if the - // model itself wasn't visible. This just returns a cached value after it - // has been generated once in the view. - idRenderModel *model = R_EntityDefDynamicModel( entityDef ); - if ( model == NULL || model->NumSurfaces() <= 0 ) { - return; - } - - // the dynamic model may have changed since we built the surface list - if ( !IsDeferred() && entityDef->dynamicModelFrameCount != dynamicModelFrameCount ) { - FreeSurfaces(); - } - dynamicModelFrameCount = entityDef->dynamicModelFrameCount; - - // actually create the interaction if needed, building light and shadow surfaces as needed - if ( IsDeferred() ) { - CreateInteraction( model ); - } - - R_GlobalPointToLocal( vEntity->modelMatrix, lightDef->globalLightOrigin, localLightOrigin ); - R_GlobalPointToLocal( vEntity->modelMatrix, tr.viewDef->renderView.vieworg, localViewOrigin ); - - // calculate the scissor as the intersection of the light and model rects - // this is used for light triangles, but not for shadow triangles - lightScissor = vLight->scissorRect; - lightScissor.Intersect( vEntity->scissorRect ); - - bool lightScissorsEmpty = lightScissor.IsEmpty(); - - // for each surface of this entity / light interaction - for ( int i = 0; i < numSurfaces; i++ ) { - surfaceInteraction_t *sint = &surfaces[i]; - - // see if the base surface is visible, we may still need to add shadows even if empty - if ( !lightScissorsEmpty && sint->ambientTris && sint->ambientTris->ambientViewCount == tr.viewCount ) { - - // make sure we have created this interaction, which may have been deferred - // on a previous use that only needed the shadow - if ( sint->lightTris == LIGHT_TRIS_DEFERRED ) { - sint->lightTris = R_CreateLightTris( vEntity->entityDef, sint->ambientTris, vLight->lightDef, sint->shader, sint->cullInfo ); - R_FreeInteractionCullInfo( sint->cullInfo ); - } - - srfTriangles_t *lightTris = sint->lightTris; - - if ( lightTris ) { - - // try to cull before adding - // FIXME: this may not be worthwhile. We have already done culling on the ambient, - // but individual surfaces may still be cropped somewhat more - if ( !R_CullLocalBox( lightTris->bounds, vEntity->modelMatrix, 5, tr.viewDef->frustum ) ) { - - // make sure the original surface has its ambient cache created - srfTriangles_t *tri = sint->ambientTris; - if ( !tri->ambientCache ) { - if ( !R_CreateAmbientCache( tri, sint->shader->ReceivesLighting() ) ) { - // skip if we were out of vertex memory - continue; - } - } - - // reference the original surface's ambient cache - lightTris->ambientCache = tri->ambientCache; - - // touch the ambient surface so it won't get purged - vertexCache.Touch( lightTris->ambientCache ); - - // regenerate the lighting cache (for non-vertex program cards) if it has been purged - if ( !lightTris->lightingCache ) { - if ( !R_CreateLightingCache( entityDef, lightDef, lightTris ) ) { - // skip if we are out of vertex memory - continue; - } - } - // touch the light surface so it won't get purged - // (vertex program cards won't have a light cache at all) - if ( lightTris->lightingCache ) { - vertexCache.Touch( lightTris->lightingCache ); - } - - if ( !lightTris->indexCache && r_useIndexBuffers.GetBool() ) { - vertexCache.Alloc( lightTris->indexes, lightTris->numIndexes * sizeof( lightTris->indexes[0] ), &lightTris->indexCache, true ); - } - if ( lightTris->indexCache ) { - vertexCache.Touch( lightTris->indexCache ); - } - - // add the surface to the light list - - const idMaterial *shader = sint->shader; - R_GlobalShaderOverride( &shader ); - - // there will only be localSurfaces if the light casts shadows and - // there are surfaces with NOSELFSHADOW - if ( sint->shader->Coverage() == MC_TRANSLUCENT ) { - R_LinkLightSurf( &vLight->translucentInteractions, lightTris, - vEntity, lightDef, shader, lightScissor, false ); - } else if ( !lightDef->parms.noShadows && sint->shader->TestMaterialFlag(MF_NOSELFSHADOW) ) { - R_LinkLightSurf( &vLight->localInteractions, lightTris, - vEntity, lightDef, shader, lightScissor, false ); - } else { - R_LinkLightSurf( &vLight->globalInteractions, lightTris, - vEntity, lightDef, shader, lightScissor, false ); - } - } - } - } - - srfTriangles_t *shadowTris = sint->shadowTris; - - // the shadows will always have to be added, unless we can tell they - // are from a surface in an unconnected area - if ( shadowTris ) { - - // check for view specific shadow suppression (player shadows, etc) - if ( !r_skipSuppress.GetBool() ) { - if ( entityDef->parms.suppressShadowInViewID && - entityDef->parms.suppressShadowInViewID == tr.viewDef->renderView.viewID ) { - continue; - } - if ( entityDef->parms.suppressShadowInLightID && - entityDef->parms.suppressShadowInLightID == lightDef->parms.lightId ) { - continue; - } - } - - // cull static shadows that have a non-empty bounds - // dynamic shadows that use the turboshadow code will not have valid - // bounds, because the perspective projection extends them to infinity - if ( r_useShadowCulling.GetBool() && !shadowTris->bounds.IsCleared() ) { - if ( R_CullLocalBox( shadowTris->bounds, vEntity->modelMatrix, 5, tr.viewDef->frustum ) ) { - continue; - } - } - - // copy the shadow vertexes to the vertex cache if they have been purged - - // if we are using shared shadowVertexes and letting a vertex program fix them up, - // get the shadowCache from the parent ambient surface - if ( !shadowTris->shadowVertexes ) { - // the data may have been purged, so get the latest from the "home position" - shadowTris->shadowCache = sint->ambientTris->shadowCache; - } - - // if we have been purged, re-upload the shadowVertexes - if ( !shadowTris->shadowCache ) { - if ( shadowTris->shadowVertexes ) { - // each interaction has unique vertexes - R_CreatePrivateShadowCache( shadowTris ); - } else { - R_CreateVertexProgramShadowCache( sint->ambientTris ); - shadowTris->shadowCache = sint->ambientTris->shadowCache; - } - // if we are out of vertex cache space, skip the interaction - if ( !shadowTris->shadowCache ) { - continue; - } - } - - // touch the shadow surface so it won't get purged - vertexCache.Touch( shadowTris->shadowCache ); - - if ( !shadowTris->indexCache && r_useIndexBuffers.GetBool() ) { - vertexCache.Alloc( shadowTris->indexes, shadowTris->numIndexes * sizeof( shadowTris->indexes[0] ), &shadowTris->indexCache, true ); - vertexCache.Touch( shadowTris->indexCache ); - } - - // see if we can avoid using the shadow volume caps - bool inside = R_PotentiallyInsideInfiniteShadow( sint->ambientTris, localViewOrigin, localLightOrigin ); - - if ( sint->shader->TestMaterialFlag( MF_NOSELFSHADOW ) ) { - R_LinkLightSurf( &vLight->localShadows, - shadowTris, vEntity, lightDef, NULL, shadowScissor, inside ); - } else { - R_LinkLightSurf( &vLight->globalShadows, - shadowTris, vEntity, lightDef, NULL, shadowScissor, inside ); - } - } - } + viewLight_t *vLight; + viewEntity_t *vEntity; + idScreenRect shadowScissor; + idScreenRect lightScissor; + idVec3 localLightOrigin; + idVec3 localViewOrigin; + + vLight = lightDef->viewLight; + vEntity = entityDef->viewEntity; + + // do not waste time culling the interaction frustum if there will be no shadows + if ( !HasShadows() ) { + + // use the entity scissor rectangle + shadowScissor = vEntity->scissorRect; + + // culling does not seem to be worth it for static world models + } else if ( entityDef->parms.hModel->IsStaticWorldModel() ) { + + // use the light scissor rectangle + shadowScissor = vLight->scissorRect; + + } else { + + // try to cull the interaction + // this will also cull the case where the light origin is inside the + // view frustum and the entity bounds are outside the view frustum + if ( CullInteractionByViewFrustum( tr.viewDef->viewFrustum ) ) { + return; + } + + // calculate the shadow scissor rectangle + shadowScissor = CalcInteractionScissorRectangle( tr.viewDef->viewFrustum ); + } + + // get out before making the dynamic model if the shadow scissor rectangle is empty + if ( shadowScissor.IsEmpty() ) { + return; + } + + // We will need the dynamic surface created to make interactions, even if the + // model itself wasn't visible. This just returns a cached value after it + // has been generated once in the view. + idRenderModel *model = R_EntityDefDynamicModel( entityDef ); + + if ( model == NULL || model->NumSurfaces() <= 0 ) { + return; + } + + // the dynamic model may have changed since we built the surface list + if ( !IsDeferred() && entityDef->dynamicModelFrameCount != dynamicModelFrameCount ) { + FreeSurfaces(); + } + dynamicModelFrameCount = entityDef->dynamicModelFrameCount; + + // actually create the interaction if needed, building light and shadow surfaces as needed + if ( IsDeferred() ) { + CreateInteraction( model ); + } + R_GlobalPointToLocal( vEntity->modelMatrix, lightDef->globalLightOrigin, localLightOrigin ); + R_GlobalPointToLocal( vEntity->modelMatrix, tr.viewDef->renderView.vieworg, localViewOrigin ); + + // calculate the scissor as the intersection of the light and model rects + // this is used for light triangles, but not for shadow triangles + lightScissor = vLight->scissorRect; + lightScissor.Intersect( vEntity->scissorRect ); + + bool lightScissorsEmpty = lightScissor.IsEmpty(); + + // for each surface of this entity / light interaction + for ( int i = 0; i < numSurfaces; i++ ) { + surfaceInteraction_t *sint = &surfaces[i]; + + // see if the base surface is visible, we may still need to add shadows even if empty + if ( !lightScissorsEmpty && sint->ambientTris && sint->ambientTris->ambientViewCount == tr.viewCount ) { + + // make sure we have created this interaction, which may have been deferred + // on a previous use that only needed the shadow + if ( sint->lightTris == LIGHT_TRIS_DEFERRED ) { + sint->lightTris = R_CreateLightTris( vEntity->entityDef, sint->ambientTris, vLight->lightDef, sint->shader, sint->cullInfo ); + R_FreeInteractionCullInfo( sint->cullInfo ); + } + srfTriangles_t *lightTris = sint->lightTris; + + if ( lightTris ) { + + // try to cull before adding + // FIXME: this may not be worthwhile. We have already done culling on the ambient, + // but individual surfaces may still be cropped somewhat more + if ( !R_CullLocalBox( lightTris->bounds, vEntity->modelMatrix, 5, tr.viewDef->frustum ) ) { + + // make sure the original surface has its ambient cache created + srfTriangles_t *tri = sint->ambientTris; + if ( !tri->ambientCache ) { + if ( !R_CreateAmbientCache( tri, sint->shader->ReceivesLighting() ) ) { + // skip if we were out of vertex memory + continue; + } + } + + // reference the original surface's ambient cache + lightTris->ambientCache = tri->ambientCache; + + // touch the ambient surface so it won't get purged + vertexCache.Touch( lightTris->ambientCache ); + + // regenerate the lighting cache (for non-vertex program cards) if it has been purged + if ( !lightTris->lightingCache ) { + if ( !R_CreateLightingCache( entityDef, lightDef, lightTris ) ) { + // skip if we are out of vertex memory + continue; + } + } + + // touch the light surface so it won't get purged + // (vertex program cards won't have a light cache at all) + if ( lightTris->lightingCache ) { + vertexCache.Touch( lightTris->lightingCache ); + } + + if ( !lightTris->indexCache && r_useIndexBuffers.GetBool() ) { + vertexCache.Alloc( lightTris->indexes, lightTris->numIndexes * sizeof( lightTris->indexes[0] ), &lightTris->indexCache, true ); + } + + if ( lightTris->indexCache ) { + vertexCache.Touch( lightTris->indexCache ); + } + + // add the surface to the light list + const idMaterial *shader = sint->shader; + R_GlobalShaderOverride( &shader ); + + // there will only be localSurfaces if the light casts shadows and + // there are surfaces with NOSELFSHADOW + if ( sint->shader->Coverage() == MC_TRANSLUCENT ) { + R_LinkLightSurf( &vLight->translucentInteractions, lightTris, + vEntity, lightDef, shader, lightScissor, false ); + } else if ( !lightDef->parms.noShadows && sint->shader->TestMaterialFlag( MF_NOSELFSHADOW ) ) { + R_LinkLightSurf( &vLight->localInteractions, lightTris, + vEntity, lightDef, shader, lightScissor, false ); + } else { + R_LinkLightSurf( &vLight->globalInteractions, lightTris, + vEntity, lightDef, shader, lightScissor, false ); + } + } + } + } + srfTriangles_t *shadowTris = sint->shadowTris; + + // the shadows will always have to be added, unless we can tell they + // are from a surface in an unconnected area + if ( shadowTris ) { + // check for view specific shadow suppression (player shadows, etc) + if ( !r_skipSuppress.GetBool() ) { + if ( entityDef->parms.suppressShadowInViewID && + entityDef->parms.suppressShadowInViewID == tr.viewDef->renderView.viewID ) { + continue; + } + + if ( entityDef->parms.suppressShadowInLightID && + entityDef->parms.suppressShadowInLightID == lightDef->parms.lightId ) { + continue; + } + } + + // cull static shadows that have a non-empty bounds + // dynamic shadows that use the turboshadow code will not have valid + // bounds, because the perspective projection extends them to infinity + if ( r_useShadowCulling.GetBool() && !shadowTris->bounds.IsCleared() ) { + if ( R_CullLocalBox( shadowTris->bounds, vEntity->modelMatrix, 5, tr.viewDef->frustum ) ) { + continue; + } + } + + // copy the shadow vertexes to the vertex cache if they have been purged + // if we are using shared shadowVertexes and letting a vertex program fix them up, + // get the shadowCache from the parent ambient surface + if ( !shadowTris->shadowVertexes ) { + // the data may have been purged, so get the latest from the "home position" + shadowTris->shadowCache = sint->ambientTris->shadowCache; + } + + // if we have been purged, re-upload the shadowVertexes + if ( !shadowTris->shadowCache ) { + if ( shadowTris->shadowVertexes ) { + // each interaction has unique vertexes + R_CreatePrivateShadowCache( shadowTris ); + } else { + R_CreateVertexProgramShadowCache( sint->ambientTris ); + shadowTris->shadowCache = sint->ambientTris->shadowCache; + } + + // if we are out of vertex cache space, skip the interaction + if ( !shadowTris->shadowCache ) { + continue; + } + } + + // touch the shadow surface so it won't get purged + vertexCache.Touch( shadowTris->shadowCache ); + + if ( !shadowTris->indexCache && r_useIndexBuffers.GetBool() ) { + vertexCache.Alloc( shadowTris->indexes, shadowTris->numIndexes * sizeof( shadowTris->indexes[0] ), &shadowTris->indexCache, true ); + vertexCache.Touch( shadowTris->indexCache ); + } + + // see if we can avoid using the shadow volume caps + bool inside = R_PotentiallyInsideInfiniteShadow( sint->ambientTris, localViewOrigin, localLightOrigin ); + + if ( sint->shader->TestMaterialFlag( MF_NOSELFSHADOW ) ) { + R_LinkLightSurf( &vLight->localShadows, + shadowTris, vEntity, lightDef, NULL, shadowScissor, inside ); + } else { + R_LinkLightSurf( &vLight->globalShadows, + shadowTris, vEntity, lightDef, NULL, shadowScissor, inside ); + } + } + } } /* @@ -1251,60 +1239,62 @@ R_ShowInteractionMemory_f =================== */ void R_ShowInteractionMemory_f( const idCmdArgs &args ) { - int total = 0; - int entities = 0; - int interactions = 0; - int deferredInteractions = 0; - int emptyInteractions = 0; - int lightTris = 0; - int lightTriVerts = 0; - int lightTriIndexes = 0; - int shadowTris = 0; - int shadowTriVerts = 0; - int shadowTriIndexes = 0; - - for ( int i = 0; i < tr.primaryWorld->entityDefs.Num(); i++ ) { - idRenderEntityLocal *def = tr.primaryWorld->entityDefs[i]; - if ( !def ) { - continue; - } - if ( def->firstInteraction == NULL ) { - continue; - } - entities++; - - for ( idInteraction *inter = def->firstInteraction; inter != NULL; inter = inter->entityNext ) { - interactions++; - total += inter->MemoryUsed(); - - if ( inter->IsDeferred() ) { - deferredInteractions++; - continue; - } - if ( inter->IsEmpty() ) { - emptyInteractions++; - continue; - } - - for ( int j = 0; j < inter->numSurfaces; j++ ) { - surfaceInteraction_t *srf = &inter->surfaces[j]; - - if ( srf->lightTris && srf->lightTris != LIGHT_TRIS_DEFERRED ) { - lightTris++; - lightTriVerts += srf->lightTris->numVerts; - lightTriIndexes += srf->lightTris->numIndexes; - } - if ( srf->shadowTris ) { - shadowTris++; - shadowTriVerts += srf->shadowTris->numVerts; - shadowTriIndexes += srf->shadowTris->numIndexes; - } - } - } - } - - common->Printf( "%i entities with %i total interactions totalling %ik\n", entities, interactions, total / 1024 ); - common->Printf( "%i deferred interactions, %i empty interactions\n", deferredInteractions, emptyInteractions ); - common->Printf( "%5i indexes %5i verts in %5i light tris\n", lightTriIndexes, lightTriVerts, lightTris ); - common->Printf( "%5i indexes %5i verts in %5i shadow tris\n", shadowTriIndexes, shadowTriVerts, shadowTris ); + int total = 0; + int entities = 0; + int interactions = 0; + int deferredInteractions = 0; + int emptyInteractions = 0; + int lightTris = 0; + int lightTriVerts = 0; + int lightTriIndexes = 0; + int shadowTris = 0; + int shadowTriVerts = 0; + int shadowTriIndexes = 0; + + for ( int i = 0; i < tr.primaryWorld->entityDefs.Num(); i++ ) { + idRenderEntityLocal *def = tr.primaryWorld->entityDefs[i]; + + if ( !def ) { + continue; + } + + if ( def->firstInteraction == NULL ) { + continue; + } + entities++; + + for ( idInteraction *inter = def->firstInteraction; inter != NULL; inter = inter->entityNext ) { + interactions++; + total += inter->MemoryUsed(); + + if ( inter->IsDeferred() ) { + deferredInteractions++; + continue; + } + + if ( inter->IsEmpty() ) { + emptyInteractions++; + continue; + } + + for ( int j = 0; j < inter->numSurfaces; j++ ) { + surfaceInteraction_t *srf = &inter->surfaces[j]; + + if ( srf->lightTris && srf->lightTris != LIGHT_TRIS_DEFERRED ) { + lightTris++; + lightTriVerts += srf->lightTris->numVerts; + lightTriIndexes += srf->lightTris->numIndexes; + } + if ( srf->shadowTris ) { + shadowTris++; + shadowTriVerts += srf->shadowTris->numVerts; + shadowTriIndexes += srf->shadowTris->numIndexes; + } + } + } + } + common->Printf( "%i entities with %i total interactions totalling %ik\n", entities, interactions, total / 1024 ); + common->Printf( "%i deferred interactions, %i empty interactions\n", deferredInteractions, emptyInteractions ); + common->Printf( "%5i indexes %5i verts in %5i light tris\n", lightTriIndexes, lightTriVerts, lightTris ); + common->Printf( "%5i indexes %5i verts in %5i shadow tris\n", shadowTriIndexes, shadowTriVerts, shadowTris ); } diff --git a/neo/renderer/Material.cpp b/neo/renderer/Material.cpp index 984cb84a4..7dfec280e 100644 --- a/neo/renderer/Material.cpp +++ b/neo/renderer/Material.cpp @@ -64,13 +64,13 @@ same texture matrix calculations a half dozen times. // keep all of these on the stack, when they are static it makes material parsing non-reentrant typedef struct mtrParsingData_s { - bool registerIsTemporary[MAX_EXPRESSION_REGISTERS]; - float shaderRegisters[MAX_EXPRESSION_REGISTERS]; - expOp_t shaderOps[MAX_EXPRESSION_OPS]; - shaderStage_t parseStages[MAX_SHADER_STAGES]; + bool registerIsTemporary[MAX_EXPRESSION_REGISTERS]; + float shaderRegisters[MAX_EXPRESSION_REGISTERS]; + expOp_t shaderOps[MAX_EXPRESSION_OPS]; + shaderStage_t parseStages[MAX_SHADER_STAGES]; - bool registersAreConstant; - bool forceOverlays; + bool registersAreConstant; + bool forceOverlays; } mtrParsingData_t; @@ -80,53 +80,53 @@ idMaterial::CommonInit ============= */ void idMaterial::CommonInit() { - desc = ""; - renderBump = ""; - contentFlags = CONTENTS_SOLID; - surfaceFlags = SURFTYPE_NONE; - materialFlags = 0; - sort = SS_BAD; - coverage = MC_BAD; - cullType = CT_FRONT_SIDED; - deform = DFRM_NONE; - numOps = 0; - ops = NULL; - numRegisters = 0; - expressionRegisters = NULL; - constantRegisters = NULL; - numStages = 0; - numAmbientStages = 0; - stages = NULL; - editorImage = NULL; - lightFalloffImage = NULL; - shouldCreateBackSides = false; - entityGui = 0; - fogLight = false; - blendLight = false; - ambientLight = false; - noFog = false; - hasSubview = false; - allowOverlays = true; - unsmoothedTangents = false; - gui = NULL; - memset( deformRegisters, 0, sizeof( deformRegisters ) ); - editorAlpha = 1.0; - spectrum = 0; - polygonOffset = 0; - suppressInSubview = false; - refCount = 0; - portalSky = false; - - decalInfo.stayTime = 10000; - decalInfo.fadeTime = 4000; - decalInfo.start[0] = 1; - decalInfo.start[1] = 1; - decalInfo.start[2] = 1; - decalInfo.start[3] = 1; - decalInfo.end[0] = 0; - decalInfo.end[1] = 0; - decalInfo.end[2] = 0; - decalInfo.end[3] = 0; + desc = ""; + renderBump = ""; + contentFlags = CONTENTS_SOLID; + surfaceFlags = SURFTYPE_NONE; + materialFlags = 0; + sort = SS_BAD; + coverage = MC_BAD; + cullType = CT_FRONT_SIDED; + deform = DFRM_NONE; + numOps = 0; + ops = NULL; + numRegisters = 0; + expressionRegisters = NULL; + constantRegisters = NULL; + numStages = 0; + numAmbientStages = 0; + stages = NULL; + editorImage = NULL; + lightFalloffImage = NULL; + shouldCreateBackSides = false; + entityGui = 0; + fogLight = false; + blendLight = false; + ambientLight = false; + noFog = false; + hasSubview = false; + allowOverlays = true; + unsmoothedTangents = false; + gui = NULL; + memset( deformRegisters, 0, sizeof( deformRegisters ) ); + editorAlpha = 1.0; + spectrum = 0; + polygonOffset = 0; + suppressInSubview = false; + refCount = 0; + portalSky = false; + + decalInfo.stayTime = 10000; + decalInfo.fadeTime = 4000; + decalInfo.start[0] = 1; + decalInfo.start[1] = 1; + decalInfo.start[2] = 1; + decalInfo.start[3] = 1; + decalInfo.end[0] = 0; + decalInfo.end[1] = 0; + decalInfo.end[2] = 0; + decalInfo.end[3] = 0; } /* @@ -135,11 +135,11 @@ idMaterial::idMaterial ============= */ idMaterial::idMaterial() { - CommonInit(); + CommonInit(); - // we put this here instead of in CommonInit, because - // we don't want it cleared when a material is purged - surfaceArea = 0; + // we put this here instead of in CommonInit, because + // we don't want it cleared when a material is purged + surfaceArea = 0; } /* @@ -156,35 +156,39 @@ idMaterial::FreeData =============== */ void idMaterial::FreeData() { - int i; - - if ( stages ) { - // delete any idCinematic textures - for ( i = 0; i < numStages; i++ ) { - if ( stages[i].texture.cinematic != NULL ) { - delete stages[i].texture.cinematic; - stages[i].texture.cinematic = NULL; - } - if ( stages[i].newStage != NULL ) { - Mem_Free( stages[i].newStage ); - stages[i].newStage = NULL; - } - } - R_StaticFree( stages ); - stages = NULL; - } - if ( expressionRegisters != NULL ) { - R_StaticFree( expressionRegisters ); - expressionRegisters = NULL; - } - if ( constantRegisters != NULL ) { - R_StaticFree( constantRegisters ); - constantRegisters = NULL; - } - if ( ops != NULL ) { - R_StaticFree( ops ); - ops = NULL; - } + int i; + + if ( stages ) { + // delete any idCinematic textures + for ( i = 0; i < numStages; i++ ) { + if ( stages[i].texture.cinematic != NULL ) { + delete stages[i].texture.cinematic; + stages[i].texture.cinematic = NULL; + } + + if ( stages[i].newStage != NULL ) { + Mem_Free( stages[i].newStage ); + stages[i].newStage = NULL; + } + } + R_StaticFree( stages ); + stages = NULL; + } + + if ( expressionRegisters != NULL ) { + R_StaticFree( expressionRegisters ); + expressionRegisters = NULL; + } + + if ( constantRegisters != NULL ) { + R_StaticFree( constantRegisters ); + constantRegisters = NULL; + } + + if ( ops != NULL ) { + R_StaticFree( ops ); + ops = NULL; + } } /* @@ -193,100 +197,99 @@ idMaterial::GetEditorImage ============== */ idImage *idMaterial::GetEditorImage( void ) const { - if ( editorImage ) { - return editorImage; - } - - // if we don't have an editorImageName, use the first stage image - if ( !editorImageName.Length()) { - // _D3XP :: First check for a diffuse image, then use the first - if ( numStages && stages ) { - int i; - for( i = 0; i < numStages; i++ ) { - if ( stages[i].lighting == SL_DIFFUSE ) { - editorImage = stages[i].texture.image; - break; - } - } - if ( !editorImage ) { - editorImage = stages[0].texture.image; - } - } else { - editorImage = globalImages->defaultImage; - } - } else { - // look for an explicit one - editorImage = globalImages->ImageFromFile( editorImageName, TF_DEFAULT, true, TR_REPEAT, TD_DEFAULT ); - } - - if ( !editorImage ) { - editorImage = globalImages->defaultImage; - } - - return editorImage; + if ( editorImage ) { + return editorImage; + } + + // if we don't have an editorImageName, use the first stage image + if ( !editorImageName.Length() ) { + // _D3XP :: First check for a diffuse image, then use the first + if ( numStages && stages ) { + for ( int i = 0; i < numStages; i++ ) { + if ( stages[i].lighting == SL_DIFFUSE ) { + editorImage = stages[i].texture.image; + break; + } + } + + if ( !editorImage ) { + editorImage = stages[0].texture.image; + } + } else { + editorImage = globalImages->defaultImage; + } + } else { + // look for an explicit one + editorImage = globalImages->ImageFromFile( editorImageName, TF_DEFAULT, true, TR_REPEAT, TD_DEFAULT ); + } + + if ( !editorImage ) { + editorImage = globalImages->defaultImage; + } + return editorImage; } // info parms typedef struct { - const char *name; - int clearSolid, surfaceFlags, contents; + const char *name; + int clearSolid, surfaceFlags, contents; } infoParm_t; -static const infoParm_t infoParms[] = { - // game relevant attributes - {"solid", 0, 0, CONTENTS_SOLID }, // may need to override a clearSolid - {"water", 1, 0, CONTENTS_WATER }, // used for water - {"playerclip", 0, 0, CONTENTS_PLAYERCLIP }, // solid to players - {"monsterclip", 0, 0, CONTENTS_MONSTERCLIP }, // solid to monsters - {"moveableclip",0, 0, CONTENTS_MOVEABLECLIP },// solid to moveable entities - {"ikclip", 0, 0, CONTENTS_IKCLIP }, // solid to IK - {"blood", 0, 0, CONTENTS_BLOOD }, // used to detect blood decals - {"trigger", 0, 0, CONTENTS_TRIGGER }, // used for triggers - {"aassolid", 0, 0, CONTENTS_AAS_SOLID }, // solid for AAS - {"aasobstacle", 0, 0, CONTENTS_AAS_OBSTACLE },// used to compile an obstacle into AAS that can be enabled/disabled - {"flashlight_trigger", 0, 0, CONTENTS_FLASHLIGHT_TRIGGER }, // used for triggers that are activated by the flashlight - {"nonsolid", 1, 0, 0 }, // clears the solid flag - {"nullNormal", 0, SURF_NULLNORMAL,0 }, // renderbump will draw as 0x80 0x80 0x80 - - // utility relevant attributes - {"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas - {"qer_nocarve", 1, 0, CONTENTS_NOCSG}, // don't cut brushes in editor - - {"discrete", 1, SURF_DISCRETE, 0 }, // surfaces should not be automatically merged together or - // clipped to the world, - // because they represent discrete objects like gui shaders - // mirrors, or autosprites - {"noFragment", 0, SURF_NOFRAGMENT, 0 }, - - {"slick", 0, SURF_SLICK, 0 }, - {"collision", 0, SURF_COLLISION, 0 }, - {"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks - {"nodamage", 0, SURF_NODAMAGE, 0 }, // no falling damage when hitting - {"ladder", 0, SURF_LADDER, 0 }, // climbable - {"nosteps", 0, SURF_NOSTEPS, 0 }, // no footsteps - - // material types for particle, sound, footstep feedback - {"metal", 0, SURFTYPE_METAL, 0 }, // metal - {"stone", 0, SURFTYPE_STONE, 0 }, // stone - {"flesh", 0, SURFTYPE_FLESH, 0 }, // flesh - {"wood", 0, SURFTYPE_WOOD, 0 }, // wood - {"cardboard", 0, SURFTYPE_CARDBOARD, 0 }, // cardboard - {"liquid", 0, SURFTYPE_LIQUID, 0 }, // liquid - {"glass", 0, SURFTYPE_GLASS, 0 }, // glass - {"plastic", 0, SURFTYPE_PLASTIC, 0 }, // plastic - {"ricochet", 0, SURFTYPE_RICOCHET, 0 }, // behaves like metal but causes a ricochet sound - - // unassigned surface types - {"surftype10", 0, SURFTYPE_10, 0 }, - {"surftype11", 0, SURFTYPE_11, 0 }, - {"surftype12", 0, SURFTYPE_12, 0 }, - {"surftype13", 0, SURFTYPE_13, 0 }, - {"surftype14", 0, SURFTYPE_14, 0 }, - {"surftype15", 0, SURFTYPE_15, 0 }, +static const infoParm_t infoParms[] = { + // game relevant attributes + {"solid", 0, 0, CONTENTS_SOLID }, // may need to override a clearSolid + {"water", 1, 0, CONTENTS_WATER }, // used for water + {"playerclip", 0, 0, CONTENTS_PLAYERCLIP }, // solid to players + {"monsterclip", 0, 0, CONTENTS_MONSTERCLIP }, // solid to monsters + {"moveableclip", 0, 0, CONTENTS_MOVEABLECLIP }, // solid to moveable entities + {"ikclip", 0, 0, CONTENTS_IKCLIP }, // solid to IK + {"blood", 0, 0, CONTENTS_BLOOD }, // used to detect blood decals + {"trigger", 0, 0, CONTENTS_TRIGGER }, // used for triggers + {"aassolid", 0, 0, CONTENTS_AAS_SOLID }, // solid for AAS + {"aasobstacle", 0, 0, CONTENTS_AAS_OBSTACLE }, // used to compile an obstacle into AAS that can be enabled/disabled + {"flashlight_trigger", 0, 0, CONTENTS_FLASHLIGHT_TRIGGER }, // used for triggers that are activated by the flashlight + {"nonsolid", 1, 0, 0 }, // clears the solid flag + {"nullNormal", 0, SURF_NULLNORMAL, 0 }, // renderbump will draw as 0x80 0x80 0x80 + + // utility relevant attributes + {"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas + {"qer_nocarve", 1, 0, CONTENTS_NOCSG}, // don't cut brushes in editor + + {"discrete", 1, SURF_DISCRETE, 0 }, // surfaces should not be automatically merged together or + // clipped to the world, + // because they represent discrete objects like gui shaders + // mirrors, or autosprites + {"noFragment", 0, SURF_NOFRAGMENT, 0 }, + + {"slick", 0, SURF_SLICK, 0 }, + {"collision", 0, SURF_COLLISION, 0 }, + {"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks + {"nodamage", 0, SURF_NODAMAGE, 0 }, // no falling damage when hitting + {"ladder", 0, SURF_LADDER, 0 }, // climbable + {"nosteps", 0, SURF_NOSTEPS, 0 }, // no footsteps + + // material types for particle, sound, footstep feedback + {"metal", 0, SURFTYPE_METAL, 0 }, // metal + {"stone", 0, SURFTYPE_STONE, 0 }, // stone + {"flesh", 0, SURFTYPE_FLESH, 0 }, // flesh + {"wood", 0, SURFTYPE_WOOD, 0 }, // wood + {"cardboard", 0, SURFTYPE_CARDBOARD, 0 }, // cardboard + {"liquid", 0, SURFTYPE_LIQUID, 0 }, // liquid + {"glass", 0, SURFTYPE_GLASS, 0 }, // glass + {"plastic", 0, SURFTYPE_PLASTIC, 0 }, // plastic + {"ricochet", 0, SURFTYPE_RICOCHET, 0 }, // behaves like metal but causes a ricochet sound + + // unassigned surface types + {"surftype10", 0, SURFTYPE_10, 0 }, + {"surftype11", 0, SURFTYPE_11, 0 }, + {"surftype12", 0, SURFTYPE_12, 0 }, + {"surftype13", 0, SURFTYPE_13, 0 }, + {"surftype14", 0, SURFTYPE_14, 0 }, + {"surftype15", 0, SURFTYPE_15, 0 }, }; -static const int numInfoParms = sizeof(infoParms) / sizeof (infoParms[0]); +static const int numInfoParms = sizeof( infoParms ) / sizeof( infoParms[0] ); /* @@ -298,21 +301,22 @@ See if the current token matches one of the surface parm bit flags */ bool idMaterial::CheckSurfaceParm( idToken *token ) { - for ( int i = 0 ; i < numInfoParms ; i++ ) { - if ( !token->Icmp( infoParms[i].name ) ) { - if ( infoParms[i].surfaceFlags & SURF_TYPE_MASK ) { - // ensure we only have one surface type set - surfaceFlags &= ~SURF_TYPE_MASK; - } - surfaceFlags |= infoParms[i].surfaceFlags; - contentFlags |= infoParms[i].contents; - if ( infoParms[i].clearSolid ) { - contentFlags &= ~CONTENTS_SOLID; - } - return true; - } - } - return false; + for ( int i = 0 ; i < numInfoParms ; i++ ) { + if ( !token->Icmp( infoParms[i].name ) ) { + if ( infoParms[i].surfaceFlags & SURF_TYPE_MASK ) { + // ensure we only have one surface type set + surfaceFlags &= ~SURF_TYPE_MASK; + } + surfaceFlags |= infoParms[i].surfaceFlags; + contentFlags |= infoParms[i].contents; + + if ( infoParms[i].clearSolid ) { + contentFlags &= ~CONTENTS_SOLID; + } + return true; + } + } + return false; } /* @@ -323,11 +327,11 @@ Sets defaultShader and returns false if the next token doesn't match =============== */ bool idMaterial::MatchToken( idLexer &src, const char *match ) { - if ( !src.ExpectTokenString( match ) ) { - SetMaterialFlag( MF_DEFAULTED ); - return false; - } - return true; + if ( !src.ExpectTokenString( match ) ) { + SetMaterialFlag( MF_DEFAULTED ); + return false; + } + return true; } /* @@ -336,37 +340,37 @@ idMaterial::ParseSort ================= */ void idMaterial::ParseSort( idLexer &src ) { - idToken token; - - if ( !src.ReadTokenOnLine( &token ) ) { - src.Warning( "missing sort parameter" ); - SetMaterialFlag( MF_DEFAULTED ); - return; - } - - if ( !token.Icmp( "subview" ) ) { - sort = SS_SUBVIEW; - } else if ( !token.Icmp( "opaque" ) ) { - sort = SS_OPAQUE; - }else if ( !token.Icmp( "decal" ) ) { - sort = SS_DECAL; - } else if ( !token.Icmp( "far" ) ) { - sort = SS_FAR; - } else if ( !token.Icmp( "medium" ) ) { - sort = SS_MEDIUM; - } else if ( !token.Icmp( "close" ) ) { - sort = SS_CLOSE; - } else if ( !token.Icmp( "almostNearest" ) ) { - sort = SS_ALMOST_NEAREST; - } else if ( !token.Icmp( "nearest" ) ) { - sort = SS_NEAREST; - } else if ( !token.Icmp( "postProcess" ) ) { - sort = SS_POST_PROCESS; - } else if ( !token.Icmp( "portalSky" ) ) { - sort = SS_PORTAL_SKY; - } else { - sort = atof( token ); - } + idToken token; + + if ( !src.ReadTokenOnLine( &token ) ) { + src.Warning( "missing sort parameter" ); + SetMaterialFlag( MF_DEFAULTED ); + return; + } + + if ( !token.Icmp( "subview" ) ) { + sort = SS_SUBVIEW; + } else if ( !token.Icmp( "opaque" ) ) { + sort = SS_OPAQUE; + } else if ( !token.Icmp( "decal" ) ) { + sort = SS_DECAL; + } else if ( !token.Icmp( "far" ) ) { + sort = SS_FAR; + } else if ( !token.Icmp( "medium" ) ) { + sort = SS_MEDIUM; + } else if ( !token.Icmp( "close" ) ) { + sort = SS_CLOSE; + } else if ( !token.Icmp( "almostNearest" ) ) { + sort = SS_ALMOST_NEAREST; + } else if ( !token.Icmp( "nearest" ) ) { + sort = SS_NEAREST; + } else if ( !token.Icmp( "postProcess" ) ) { + sort = SS_POST_PROCESS; + } else if ( !token.Icmp( "portalSky" ) ) { + sort = SS_PORTAL_SKY; + } else { + sort = atof( token ); + } } /* @@ -375,17 +379,19 @@ idMaterial::ParseDecalInfo ================= */ void idMaterial::ParseDecalInfo( idLexer &src ) { - idToken token; - - decalInfo.stayTime = src.ParseFloat() * 1000; - decalInfo.fadeTime = src.ParseFloat() * 1000; - float start[4], end[4]; - src.Parse1DMatrix( 4, start ); - src.Parse1DMatrix( 4, end ); - for ( int i = 0 ; i < 4 ; i++ ) { - decalInfo.start[i] = start[i]; - decalInfo.end[i] = end[i]; - } + idToken token; + + decalInfo.stayTime = src.ParseFloat() * 1000; + decalInfo.fadeTime = src.ParseFloat() * 1000; + + float start[4], end[4]; + src.Parse1DMatrix( 4, start ); + src.Parse1DMatrix( 4, end ); + + for ( int i = 0 ; i < 4 ; i++ ) { + decalInfo.start[i] = start[i]; + decalInfo.end[i] = end[i]; + } } /* @@ -394,23 +400,24 @@ idMaterial::GetExpressionConstant ============= */ int idMaterial::GetExpressionConstant( float f ) { - int i; - - for ( i = EXP_REG_NUM_PREDEFINED ; i < numRegisters ; i++ ) { - if ( !pd->registerIsTemporary[i] && pd->shaderRegisters[i] == f ) { - return i; - } - } - if ( numRegisters == MAX_EXPRESSION_REGISTERS ) { - common->Warning( "GetExpressionConstant: material '%s' hit MAX_EXPRESSION_REGISTERS", GetName() ); - SetMaterialFlag( MF_DEFAULTED ); - return 0; - } - pd->registerIsTemporary[i] = false; - pd->shaderRegisters[i] = f; - numRegisters++; - - return i; + int i; + + for ( i = EXP_REG_NUM_PREDEFINED ; i < numRegisters ; i++ ) { + if ( !pd->registerIsTemporary[i] && pd->shaderRegisters[i] == f ) { + return i; + } + } + + if ( numRegisters == MAX_EXPRESSION_REGISTERS ) { + common->Warning( "GetExpressionConstant: material '%s' hit MAX_EXPRESSION_REGISTERS", GetName() ); + SetMaterialFlag( MF_DEFAULTED ); + return 0; + } + pd->registerIsTemporary[i] = false; + pd->shaderRegisters[i] = f; + numRegisters++; + + return i; } /* @@ -419,14 +426,14 @@ idMaterial::GetExpressionTemporary ============= */ int idMaterial::GetExpressionTemporary( void ) { - if ( numRegisters == MAX_EXPRESSION_REGISTERS ) { - common->Warning( "GetExpressionTemporary: material '%s' hit MAX_EXPRESSION_REGISTERS", GetName() ); - SetMaterialFlag( MF_DEFAULTED ); - return 0; - } - pd->registerIsTemporary[numRegisters] = true; - numRegisters++; - return numRegisters - 1; + if ( numRegisters == MAX_EXPRESSION_REGISTERS ) { + common->Warning( "GetExpressionTemporary: material '%s' hit MAX_EXPRESSION_REGISTERS", GetName() ); + SetMaterialFlag( MF_DEFAULTED ); + return 0; + } + pd->registerIsTemporary[numRegisters] = true; + numRegisters++; + return numRegisters - 1; } /* @@ -434,14 +441,13 @@ int idMaterial::GetExpressionTemporary( void ) { idMaterial::GetExpressionOp ============= */ -expOp_t *idMaterial::GetExpressionOp( void ) { - if ( numOps == MAX_EXPRESSION_OPS ) { - common->Warning( "GetExpressionOp: material '%s' hit MAX_EXPRESSION_OPS", GetName() ); - SetMaterialFlag( MF_DEFAULTED ); - return &pd->shaderOps[0]; - } - - return &pd->shaderOps[numOps++]; +expOp_t *idMaterial::GetExpressionOp( void ) { + if ( numOps == MAX_EXPRESSION_OPS ) { + common->Warning( "GetExpressionOp: material '%s' hit MAX_EXPRESSION_OPS", GetName() ); + SetMaterialFlag( MF_DEFAULTED ); + return &pd->shaderOps[0]; + } + return &pd->shaderOps[numOps++]; } /* @@ -450,45 +456,51 @@ idMaterial::EmitOp ================= */ int idMaterial::EmitOp( int a, int b, expOpType_t opType ) { - expOp_t *op; - - // optimize away identity operations - if ( opType == OP_TYPE_ADD ) { - if ( !pd->registerIsTemporary[a] && pd->shaderRegisters[a] == 0 ) { - return b; - } - if ( !pd->registerIsTemporary[b] && pd->shaderRegisters[b] == 0 ) { - return a; - } - if ( !pd->registerIsTemporary[a] && !pd->registerIsTemporary[b] ) { - return GetExpressionConstant( pd->shaderRegisters[a] + pd->shaderRegisters[b] ); - } - } - if ( opType == OP_TYPE_MULTIPLY ) { - if ( !pd->registerIsTemporary[a] && pd->shaderRegisters[a] == 1 ) { - return b; - } - if ( !pd->registerIsTemporary[a] && pd->shaderRegisters[a] == 0 ) { - return a; - } - if ( !pd->registerIsTemporary[b] && pd->shaderRegisters[b] == 1 ) { - return a; - } - if ( !pd->registerIsTemporary[b] && pd->shaderRegisters[b] == 0 ) { - return b; - } - if ( !pd->registerIsTemporary[a] && !pd->registerIsTemporary[b] ) { - return GetExpressionConstant( pd->shaderRegisters[a] * pd->shaderRegisters[b] ); - } - } - - op = GetExpressionOp(); - op->opType = opType; - op->a = a; - op->b = b; - op->c = GetExpressionTemporary(); - - return op->c; + expOp_t *op; + + // optimize away identity operations + if ( opType == OP_TYPE_ADD ) { + if ( !pd->registerIsTemporary[a] && pd->shaderRegisters[a] == 0 ) { + return b; + } + + if ( !pd->registerIsTemporary[b] && pd->shaderRegisters[b] == 0 ) { + return a; + } + + if ( !pd->registerIsTemporary[a] && !pd->registerIsTemporary[b] ) { + return GetExpressionConstant( pd->shaderRegisters[a] + pd->shaderRegisters[b] ); + } + } + + if ( opType == OP_TYPE_MULTIPLY ) { + if ( !pd->registerIsTemporary[a] && pd->shaderRegisters[a] == 1 ) { + return b; + } + + if ( !pd->registerIsTemporary[a] && pd->shaderRegisters[a] == 0 ) { + return a; + } + + if ( !pd->registerIsTemporary[b] && pd->shaderRegisters[b] == 1 ) { + return a; + } + + if ( !pd->registerIsTemporary[b] && pd->shaderRegisters[b] == 0 ) { + return b; + } + + if ( !pd->registerIsTemporary[a] && !pd->registerIsTemporary[b] ) { + return GetExpressionConstant( pd->shaderRegisters[a] * pd->shaderRegisters[b] ); + } + } + op = GetExpressionOp(); + op->opType = opType; + op->a = a; + op->b = b; + op->c = GetExpressionTemporary(); + + return op->c; } /* @@ -497,10 +509,8 @@ idMaterial::ParseEmitOp ================= */ int idMaterial::ParseEmitOp( idLexer &src, int a, expOpType_t opType, int priority ) { - int b; - - b = ParseExpressionPriority( src, priority ); - return EmitOp( a, b, opType ); + int b = ParseExpressionPriority( src, priority ); + return EmitOp( a, b, opType ); } /* @@ -511,141 +521,163 @@ Returns a register index ================= */ int idMaterial::ParseTerm( idLexer &src ) { - idToken token; - int a, b; - - src.ReadToken( &token ); - - if ( token == "(" ) { - a = ParseExpression( src ); - MatchToken( src, ")" ); - return a; - } - - if ( !token.Icmp( "time" ) ) { - pd->registersAreConstant = false; - return EXP_REG_TIME; - } - if ( !token.Icmp( "parm0" ) ) { - pd->registersAreConstant = false; - return EXP_REG_PARM0; - } - if ( !token.Icmp( "parm1" ) ) { - pd->registersAreConstant = false; - return EXP_REG_PARM1; - } - if ( !token.Icmp( "parm2" ) ) { - pd->registersAreConstant = false; - return EXP_REG_PARM2; - } - if ( !token.Icmp( "parm3" ) ) { - pd->registersAreConstant = false; - return EXP_REG_PARM3; - } - if ( !token.Icmp( "parm4" ) ) { - pd->registersAreConstant = false; - return EXP_REG_PARM4; - } - if ( !token.Icmp( "parm5" ) ) { - pd->registersAreConstant = false; - return EXP_REG_PARM5; - } - if ( !token.Icmp( "parm6" ) ) { - pd->registersAreConstant = false; - return EXP_REG_PARM6; - } - if ( !token.Icmp( "parm7" ) ) { - pd->registersAreConstant = false; - return EXP_REG_PARM7; - } - if ( !token.Icmp( "parm8" ) ) { - pd->registersAreConstant = false; - return EXP_REG_PARM8; - } - if ( !token.Icmp( "parm9" ) ) { - pd->registersAreConstant = false; - return EXP_REG_PARM9; - } - if ( !token.Icmp( "parm10" ) ) { - pd->registersAreConstant = false; - return EXP_REG_PARM10; - } - if ( !token.Icmp( "parm11" ) ) { - pd->registersAreConstant = false; - return EXP_REG_PARM11; - } - if ( !token.Icmp( "global0" ) ) { - pd->registersAreConstant = false; - return EXP_REG_GLOBAL0; - } - if ( !token.Icmp( "global1" ) ) { - pd->registersAreConstant = false; - return EXP_REG_GLOBAL1; - } - if ( !token.Icmp( "global2" ) ) { - pd->registersAreConstant = false; - return EXP_REG_GLOBAL2; - } - if ( !token.Icmp( "global3" ) ) { - pd->registersAreConstant = false; - return EXP_REG_GLOBAL3; - } - if ( !token.Icmp( "global4" ) ) { - pd->registersAreConstant = false; - return EXP_REG_GLOBAL4; - } - if ( !token.Icmp( "global5" ) ) { - pd->registersAreConstant = false; - return EXP_REG_GLOBAL5; - } - if ( !token.Icmp( "global6" ) ) { - pd->registersAreConstant = false; - return EXP_REG_GLOBAL6; - } - if ( !token.Icmp( "global7" ) ) { - pd->registersAreConstant = false; - return EXP_REG_GLOBAL7; - } - if ( !token.Icmp( "fragmentPrograms" ) ) { - return GetExpressionConstant( (float) glConfig.ARBFragmentProgramAvailable ); - } - - if ( !token.Icmp( "sound" ) ) { - pd->registersAreConstant = false; - return EmitOp( 0, 0, OP_TYPE_SOUND ); - } - - // parse negative numbers - if ( token == "-" ) { - src.ReadToken( &token ); - if ( token.type == TT_NUMBER || token == "." ) { - return GetExpressionConstant( -(float) token.GetFloatValue() ); - } - src.Warning( "Bad negative number '%s'", token.c_str() ); - SetMaterialFlag( MF_DEFAULTED ); - return 0; - } - - if ( token.type == TT_NUMBER || token == "." || token == "-" ) { - return GetExpressionConstant( (float) token.GetFloatValue() ); - } - - // see if it is a table name - const idDeclTable *table = static_cast( declManager->FindType( DECL_TABLE, token.c_str(), false ) ); - if ( !table ) { - src.Warning( "Bad term '%s'", token.c_str() ); - SetMaterialFlag( MF_DEFAULTED ); - return 0; - } - - // parse a table expression - MatchToken( src, "[" ); - - b = ParseExpression( src ); - - MatchToken( src, "]" ); - - return EmitOp( table->Index(), b, OP_TYPE_TABLE ); + idToken token; + int a, b; + + src.ReadToken( &token ); + + if ( token == "(" ) { + a = ParseExpression( src ); + MatchToken( src, ")" ); + return a; + } + + if ( !token.Icmp( "time" ) ) { + pd->registersAreConstant = false; + return EXP_REG_TIME; + } + + if ( !token.Icmp( "parm0" ) ) { + pd->registersAreConstant = false; + return EXP_REG_PARM0; + } + + if ( !token.Icmp( "parm1" ) ) { + pd->registersAreConstant = false; + return EXP_REG_PARM1; + } + + if ( !token.Icmp( "parm2" ) ) { + pd->registersAreConstant = false; + return EXP_REG_PARM2; + } + + if ( !token.Icmp( "parm3" ) ) { + pd->registersAreConstant = false; + return EXP_REG_PARM3; + } + + if ( !token.Icmp( "parm4" ) ) { + pd->registersAreConstant = false; + return EXP_REG_PARM4; + } + + if ( !token.Icmp( "parm5" ) ) { + pd->registersAreConstant = false; + return EXP_REG_PARM5; + } + + if ( !token.Icmp( "parm6" ) ) { + pd->registersAreConstant = false; + return EXP_REG_PARM6; + } + + if ( !token.Icmp( "parm7" ) ) { + pd->registersAreConstant = false; + return EXP_REG_PARM7; + } + + if ( !token.Icmp( "parm8" ) ) { + pd->registersAreConstant = false; + return EXP_REG_PARM8; + } + + if ( !token.Icmp( "parm9" ) ) { + pd->registersAreConstant = false; + return EXP_REG_PARM9; + } + + if ( !token.Icmp( "parm10" ) ) { + pd->registersAreConstant = false; + return EXP_REG_PARM10; + } + + if ( !token.Icmp( "parm11" ) ) { + pd->registersAreConstant = false; + return EXP_REG_PARM11; + } + + if ( !token.Icmp( "global0" ) ) { + pd->registersAreConstant = false; + return EXP_REG_GLOBAL0; + } + + if ( !token.Icmp( "global1" ) ) { + pd->registersAreConstant = false; + return EXP_REG_GLOBAL1; + } + + if ( !token.Icmp( "global2" ) ) { + pd->registersAreConstant = false; + return EXP_REG_GLOBAL2; + } + + if ( !token.Icmp( "global3" ) ) { + pd->registersAreConstant = false; + return EXP_REG_GLOBAL3; + } + + if ( !token.Icmp( "global4" ) ) { + pd->registersAreConstant = false; + return EXP_REG_GLOBAL4; + } + + if ( !token.Icmp( "global5" ) ) { + pd->registersAreConstant = false; + return EXP_REG_GLOBAL5; + } + + if ( !token.Icmp( "global6" ) ) { + pd->registersAreConstant = false; + return EXP_REG_GLOBAL6; + } + + if ( !token.Icmp( "global7" ) ) { + pd->registersAreConstant = false; + return EXP_REG_GLOBAL7; + } + + if ( !token.Icmp( "fragmentPrograms" ) ) { + return GetExpressionConstant( ( float ) glConfig.ARBFragmentProgramAvailable ); + } + + if ( !token.Icmp( "sound" ) ) { + pd->registersAreConstant = false; + return EmitOp( 0, 0, OP_TYPE_SOUND ); + } + + // parse negative numbers + if ( token == "-" ) { + src.ReadToken( &token ); + + if ( token.type == TT_NUMBER || token == "." ) { + return GetExpressionConstant( -( float ) token.GetFloatValue() ); + } + src.Warning( "Bad negative number '%s'", token.c_str() ); + SetMaterialFlag( MF_DEFAULTED ); + return 0; + } + + if ( token.type == TT_NUMBER || token == "." || token == "-" ) { + return GetExpressionConstant( ( float ) token.GetFloatValue() ); + } + + // see if it is a table name + const idDeclTable *table = static_cast( declManager->FindType( DECL_TABLE, token.c_str(), false ) ); + if ( !table ) { + src.Warning( "Bad term '%s'", token.c_str() ); + SetMaterialFlag( MF_DEFAULTED ); + return 0; + } + + // parse a table expression + MatchToken( src, "[" ); + + b = ParseExpression( src ); + + MatchToken( src, "]" ); + + return EmitOp( table->Index(), b, OP_TYPE_TABLE ); } /* @@ -655,73 +687,83 @@ idMaterial::ParseExpressionPriority Returns a register index ================= */ -#define TOP_PRIORITY 4 +#define TOP_PRIORITY 4 int idMaterial::ParseExpressionPriority( idLexer &src, int priority ) { - idToken token; - int a; - - if ( priority == 0 ) { - return ParseTerm( src ); - } - - a = ParseExpressionPriority( src, priority - 1 ); - - if ( TestMaterialFlag( MF_DEFAULTED ) ) { // we have a parse error - return 0; - } - - if ( !src.ReadToken( &token ) ) { - // we won't get EOF in a real file, but we can - // when parsing from generated strings - return a; - } - - if ( priority == 1 && token == "*" ) { - return ParseEmitOp( src, a, OP_TYPE_MULTIPLY, priority ); - } - if ( priority == 1 && token == "/" ) { - return ParseEmitOp( src, a, OP_TYPE_DIVIDE, priority ); - } - if ( priority == 1 && token == "%" ) { // implied truncate both to integer - return ParseEmitOp( src, a, OP_TYPE_MOD, priority ); - } - if ( priority == 2 && token == "+" ) { - return ParseEmitOp( src, a, OP_TYPE_ADD, priority ); - } - if ( priority == 2 && token == "-" ) { - return ParseEmitOp( src, a, OP_TYPE_SUBTRACT, priority ); - } - if ( priority == 3 && token == ">" ) { - return ParseEmitOp( src, a, OP_TYPE_GT, priority ); - } - if ( priority == 3 && token == ">=" ) { - return ParseEmitOp( src, a, OP_TYPE_GE, priority ); - } - if ( priority == 3 && token == "<" ) { - return ParseEmitOp( src, a, OP_TYPE_LT, priority ); - } - if ( priority == 3 && token == "<=" ) { - return ParseEmitOp( src, a, OP_TYPE_LE, priority ); - } - if ( priority == 3 && token == "==" ) { - return ParseEmitOp( src, a, OP_TYPE_EQ, priority ); - } - if ( priority == 3 && token == "!=" ) { - return ParseEmitOp( src, a, OP_TYPE_NE, priority ); - } - if ( priority == 4 && token == "&&" ) { - return ParseEmitOp( src, a, OP_TYPE_AND, priority ); - } - if ( priority == 4 && token == "||" ) { - return ParseEmitOp( src, a, OP_TYPE_OR, priority ); - } - - // assume that anything else terminates the expression - // not too robust error checking... - - src.UnreadToken( &token ); - - return a; + idToken token; + int a; + + if ( priority == 0 ) { + return ParseTerm( src ); + } + a = ParseExpressionPriority( src, priority - 1 ); + + if ( TestMaterialFlag( MF_DEFAULTED ) ) { // we have a parse error + return 0; + } + + if ( !src.ReadToken( &token ) ) { + // we won't get EOF in a real file, but we can + // when parsing from generated strings + return a; + } + + if ( priority == 1 && token == "*" ) { + return ParseEmitOp( src, a, OP_TYPE_MULTIPLY, priority ); + } + + if ( priority == 1 && token == "/" ) { + return ParseEmitOp( src, a, OP_TYPE_DIVIDE, priority ); + } + + if ( priority == 1 && token == "%" ) { // implied truncate both to integer + return ParseEmitOp( src, a, OP_TYPE_MOD, priority ); + } + + if ( priority == 2 && token == "+" ) { + return ParseEmitOp( src, a, OP_TYPE_ADD, priority ); + } + + if ( priority == 2 && token == "-" ) { + return ParseEmitOp( src, a, OP_TYPE_SUBTRACT, priority ); + } + + if ( priority == 3 && token == ">" ) { + return ParseEmitOp( src, a, OP_TYPE_GT, priority ); + } + + if ( priority == 3 && token == ">=" ) { + return ParseEmitOp( src, a, OP_TYPE_GE, priority ); + } + + if ( priority == 3 && token == "<" ) { + return ParseEmitOp( src, a, OP_TYPE_LT, priority ); + } + + if ( priority == 3 && token == "<=" ) { + return ParseEmitOp( src, a, OP_TYPE_LE, priority ); + } + + if ( priority == 3 && token == "==" ) { + return ParseEmitOp( src, a, OP_TYPE_EQ, priority ); + } + + if ( priority == 3 && token == "!=" ) { + return ParseEmitOp( src, a, OP_TYPE_NE, priority ); + } + + if ( priority == 4 && token == "&&" ) { + return ParseEmitOp( src, a, OP_TYPE_AND, priority ); + } + + if ( priority == 4 && token == "||" ) { + return ParseEmitOp( src, a, OP_TYPE_OR, priority ); + } + + // assume that anything else terminates the expression + // not too robust error checking... + src.UnreadToken( &token ); + + return a; } /* @@ -732,7 +774,7 @@ Returns a register index ================= */ int idMaterial::ParseExpression( idLexer &src ) { - return ParseExpressionPriority( src, TOP_PRIORITY ); + return ParseExpressionPriority( src, TOP_PRIORITY ); } @@ -742,12 +784,12 @@ idMaterial::ClearStage =============== */ void idMaterial::ClearStage( shaderStage_t *ss ) { - ss->drawStateBits = 0; - ss->conditionRegister = GetExpressionConstant( 1 ); - ss->color.registers[0] = - ss->color.registers[1] = - ss->color.registers[2] = - ss->color.registers[3] = GetExpressionConstant( 1 ); + ss->drawStateBits = 0; + ss->conditionRegister = GetExpressionConstant( 1 ); + ss->color.registers[0] = + ss->color.registers[1] = + ss->color.registers[2] = + ss->color.registers[3] = GetExpressionConstant( 1 ); } /* @@ -756,30 +798,29 @@ idMaterial::NameToSrcBlendMode =============== */ int idMaterial::NameToSrcBlendMode( const idStr &name ) { - if ( !name.Icmp( "GL_ONE" ) ) { - return GLS_SRCBLEND_ONE; - } else if ( !name.Icmp( "GL_ZERO" ) ) { - return GLS_SRCBLEND_ZERO; - } else if ( !name.Icmp( "GL_DST_COLOR" ) ) { - return GLS_SRCBLEND_DST_COLOR; - } else if ( !name.Icmp( "GL_ONE_MINUS_DST_COLOR" ) ) { - return GLS_SRCBLEND_ONE_MINUS_DST_COLOR; - } else if ( !name.Icmp( "GL_SRC_ALPHA" ) ) { - return GLS_SRCBLEND_SRC_ALPHA; - } else if ( !name.Icmp( "GL_ONE_MINUS_SRC_ALPHA" ) ) { - return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA; - } else if ( !name.Icmp( "GL_DST_ALPHA" ) ) { - return GLS_SRCBLEND_DST_ALPHA; - } else if ( !name.Icmp( "GL_ONE_MINUS_DST_ALPHA" ) ) { - return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA; - } else if ( !name.Icmp( "GL_SRC_ALPHA_SATURATE" ) ) { - return GLS_SRCBLEND_ALPHA_SATURATE; - } - - common->Warning( "unknown blend mode '%s' in material '%s'", name.c_str(), GetName() ); - SetMaterialFlag( MF_DEFAULTED ); - - return GLS_SRCBLEND_ONE; + if ( !name.Icmp( "GL_ONE" ) ) { + return GLS_SRCBLEND_ONE; + } else if ( !name.Icmp( "GL_ZERO" ) ) { + return GLS_SRCBLEND_ZERO; + } else if ( !name.Icmp( "GL_DST_COLOR" ) ) { + return GLS_SRCBLEND_DST_COLOR; + } else if ( !name.Icmp( "GL_ONE_MINUS_DST_COLOR" ) ) { + return GLS_SRCBLEND_ONE_MINUS_DST_COLOR; + } else if ( !name.Icmp( "GL_SRC_ALPHA" ) ) { + return GLS_SRCBLEND_SRC_ALPHA; + } else if ( !name.Icmp( "GL_ONE_MINUS_SRC_ALPHA" ) ) { + return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA; + } else if ( !name.Icmp( "GL_DST_ALPHA" ) ) { + return GLS_SRCBLEND_DST_ALPHA; + } else if ( !name.Icmp( "GL_ONE_MINUS_DST_ALPHA" ) ) { + return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA; + } else if ( !name.Icmp( "GL_SRC_ALPHA_SATURATE" ) ) { + return GLS_SRCBLEND_ALPHA_SATURATE; + } + common->Warning( "unknown blend mode '%s' in material '%s'", name.c_str(), GetName() ); + SetMaterialFlag( MF_DEFAULTED ); + + return GLS_SRCBLEND_ONE; } /* @@ -788,28 +829,27 @@ idMaterial::NameToDstBlendMode =============== */ int idMaterial::NameToDstBlendMode( const idStr &name ) { - if ( !name.Icmp( "GL_ONE" ) ) { - return GLS_DSTBLEND_ONE; - } else if ( !name.Icmp( "GL_ZERO" ) ) { - return GLS_DSTBLEND_ZERO; - } else if ( !name.Icmp( "GL_SRC_ALPHA" ) ) { - return GLS_DSTBLEND_SRC_ALPHA; - } else if ( !name.Icmp( "GL_ONE_MINUS_SRC_ALPHA" ) ) { - return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - } else if ( !name.Icmp( "GL_DST_ALPHA" ) ) { - return GLS_DSTBLEND_DST_ALPHA; - } else if ( !name.Icmp( "GL_ONE_MINUS_DST_ALPHA" ) ) { - return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA; - } else if ( !name.Icmp( "GL_SRC_COLOR" ) ) { - return GLS_DSTBLEND_SRC_COLOR; - } else if ( !name.Icmp( "GL_ONE_MINUS_SRC_COLOR" ) ) { - return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR; - } - - common->Warning( "unknown blend mode '%s' in material '%s'", name.c_str(), GetName() ); - SetMaterialFlag( MF_DEFAULTED ); - - return GLS_DSTBLEND_ONE; + if ( !name.Icmp( "GL_ONE" ) ) { + return GLS_DSTBLEND_ONE; + } else if ( !name.Icmp( "GL_ZERO" ) ) { + return GLS_DSTBLEND_ZERO; + } else if ( !name.Icmp( "GL_SRC_ALPHA" ) ) { + return GLS_DSTBLEND_SRC_ALPHA; + } else if ( !name.Icmp( "GL_ONE_MINUS_SRC_ALPHA" ) ) { + return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; + } else if ( !name.Icmp( "GL_DST_ALPHA" ) ) { + return GLS_DSTBLEND_DST_ALPHA; + } else if ( !name.Icmp( "GL_ONE_MINUS_DST_ALPHA" ) ) { + return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA; + } else if ( !name.Icmp( "GL_SRC_COLOR" ) ) { + return GLS_DSTBLEND_SRC_COLOR; + } else if ( !name.Icmp( "GL_ONE_MINUS_SRC_COLOR" ) ) { + return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR; + } + common->Warning( "unknown blend mode '%s' in material '%s'", name.c_str(), GetName() ); + SetMaterialFlag( MF_DEFAULTED ); + + return GLS_DSTBLEND_ONE; } /* @@ -818,53 +858,59 @@ idMaterial::ParseBlend ================ */ void idMaterial::ParseBlend( idLexer &src, shaderStage_t *stage ) { - idToken token; - int srcBlend, dstBlend; - - if ( !src.ReadToken( &token ) ) { - return; - } - - // blending combinations - if ( !token.Icmp( "blend" ) ) { - stage->drawStateBits = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; - return; - } - if ( !token.Icmp( "add" ) ) { - stage->drawStateBits = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE; - return; - } - if ( !token.Icmp( "filter" ) || !token.Icmp( "modulate" ) ) { - stage->drawStateBits = GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - return; - } - if ( !token.Icmp( "none" ) ) { - // none is used when defining an alpha mask that doesn't draw - stage->drawStateBits = GLS_SRCBLEND_ZERO | GLS_DSTBLEND_ONE; - return; - } - if ( !token.Icmp( "bumpmap" ) ) { - stage->lighting = SL_BUMP; - return; - } - if ( !token.Icmp( "diffusemap" ) ) { - stage->lighting = SL_DIFFUSE; - return; - } - if ( !token.Icmp( "specularmap" ) ) { - stage->lighting = SL_SPECULAR; - return; - } - - srcBlend = NameToSrcBlendMode( token ); - - MatchToken( src, "," ); - if ( !src.ReadToken( &token ) ) { - return; - } - dstBlend = NameToDstBlendMode( token ); - - stage->drawStateBits = srcBlend | dstBlend; + idToken token; + int srcBlend, dstBlend; + + if ( !src.ReadToken( &token ) ) { + return; + } + + // blending combinations + if ( !token.Icmp( "blend" ) ) { + stage->drawStateBits = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; + return; + } + + if ( !token.Icmp( "add" ) ) { + stage->drawStateBits = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE; + return; + } + + if ( !token.Icmp( "filter" ) || !token.Icmp( "modulate" ) ) { + stage->drawStateBits = GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; + return; + } + + if ( !token.Icmp( "none" ) ) { + // none is used when defining an alpha mask that doesn't draw + stage->drawStateBits = GLS_SRCBLEND_ZERO | GLS_DSTBLEND_ONE; + return; + } + + if ( !token.Icmp( "bumpmap" ) ) { + stage->lighting = SL_BUMP; + return; + } + + if ( !token.Icmp( "diffusemap" ) ) { + stage->lighting = SL_DIFFUSE; + return; + } + + if ( !token.Icmp( "specularmap" ) ) { + stage->lighting = SL_SPECULAR; + return; + } + srcBlend = NameToSrcBlendMode( token ); + + MatchToken( src, "," ); + + if ( !src.ReadToken( &token ) ) { + return; + } + dstBlend = NameToDstBlendMode( token ); + + stage->drawStateBits = srcBlend | dstBlend; } /* @@ -877,47 +923,48 @@ if there are three values, 4 = 1.0 ================ */ void idMaterial::ParseVertexParm( idLexer &src, newShaderStage_t *newStage ) { - idToken token; - - src.ReadTokenOnLine( &token ); - int parm = token.GetIntValue(); - if ( !token.IsNumeric() || parm < 0 || parm >= MAX_VERTEX_PARMS ) { - common->Warning( "bad vertexParm number\n" ); - SetMaterialFlag( MF_DEFAULTED ); - return; - } - if ( parm >= newStage->numVertexParms ) { - newStage->numVertexParms = parm+1; - } - - newStage->vertexParms[parm][0] = ParseExpression( src ); - - src.ReadTokenOnLine( &token ); - if ( !token[0] || token.Icmp( "," ) ) { - newStage->vertexParms[parm][1] = - newStage->vertexParms[parm][2] = - newStage->vertexParms[parm][3] = newStage->vertexParms[parm][0]; - return; - } - - newStage->vertexParms[parm][1] = ParseExpression( src ); - - src.ReadTokenOnLine( &token ); - if ( !token[0] || token.Icmp( "," ) ) { - newStage->vertexParms[parm][2] = GetExpressionConstant( 0 ); - newStage->vertexParms[parm][3] = GetExpressionConstant( 1 ); - return; - } - - newStage->vertexParms[parm][2] = ParseExpression( src ); - - src.ReadTokenOnLine( &token ); - if ( !token[0] || token.Icmp( "," ) ) { - newStage->vertexParms[parm][3] = GetExpressionConstant( 1 ); - return; - } - - newStage->vertexParms[parm][3] = ParseExpression( src ); + idToken token; + + src.ReadTokenOnLine( &token ); + + int parm = token.GetIntValue(); + if ( !token.IsNumeric() || parm < 0 || parm >= MAX_VERTEX_PARMS ) { + common->Warning( "bad vertexParm number\n" ); + SetMaterialFlag( MF_DEFAULTED ); + return; + } + + if ( parm >= newStage->numVertexParms ) { + newStage->numVertexParms = parm + 1; + } + newStage->vertexParms[parm][0] = ParseExpression( src ); + + src.ReadTokenOnLine( &token ); + + if ( !token[0] || token.Icmp( "," ) ) { + newStage->vertexParms[parm][1] = + newStage->vertexParms[parm][2] = + newStage->vertexParms[parm][3] = newStage->vertexParms[parm][0]; + return; + } + newStage->vertexParms[parm][1] = ParseExpression( src ); + + src.ReadTokenOnLine( &token ); + + if ( !token[0] || token.Icmp( "," ) ) { + newStage->vertexParms[parm][2] = GetExpressionConstant( 0 ); + newStage->vertexParms[parm][3] = GetExpressionConstant( 1 ); + return; + } + newStage->vertexParms[parm][2] = ParseExpression( src ); + + src.ReadTokenOnLine( &token ); + + if ( !token[0] || token.Icmp( "," ) ) { + newStage->vertexParms[parm][3] = GetExpressionConstant( 1 ); + return; + } + newStage->vertexParms[parm][3] = ParseExpression( src ); } @@ -927,99 +974,109 @@ idMaterial::ParseFragmentMap ================ */ void idMaterial::ParseFragmentMap( idLexer &src, newShaderStage_t *newStage ) { - const char *str; - textureFilter_t tf; - textureRepeat_t trp; - textureDepth_t td; - cubeFiles_t cubeMap; - bool allowPicmip; - idToken token; - - tf = TF_DEFAULT; - trp = TR_REPEAT; - td = TD_DEFAULT; - allowPicmip = true; - cubeMap = CF_2D; - - src.ReadTokenOnLine( &token ); - int unit = token.GetIntValue(); - if ( !token.IsNumeric() || unit < 0 || unit >= MAX_FRAGMENT_IMAGES ) { - common->Warning( "bad fragmentMap number\n" ); - SetMaterialFlag( MF_DEFAULTED ); - return; - } - - // unit 1 is the normal map.. make sure it gets flagged as the proper depth - if ( unit == 1 ) { - td = TD_BUMP; - } - - if ( unit >= newStage->numFragmentProgramImages ) { - newStage->numFragmentProgramImages = unit+1; - } - - while( 1 ) { - src.ReadTokenOnLine( &token ); - - if ( !token.Icmp( "cubeMap" ) ) { - cubeMap = CF_NATIVE; - continue; - } - if ( !token.Icmp( "cameraCubeMap" ) ) { - cubeMap = CF_CAMERA; - continue; - } - if ( !token.Icmp( "nearest" ) ) { - tf = TF_NEAREST; - continue; - } - if ( !token.Icmp( "linear" ) ) { - tf = TF_LINEAR; - continue; - } - if ( !token.Icmp( "clamp" ) ) { - trp = TR_CLAMP; - continue; - } - if ( !token.Icmp( "noclamp" ) ) { - trp = TR_REPEAT; - continue; - } - if ( !token.Icmp( "zeroclamp" ) ) { - trp = TR_CLAMP_TO_ZERO; - continue; - } - if ( !token.Icmp( "alphazeroclamp" ) ) { - trp = TR_CLAMP_TO_ZERO_ALPHA; - continue; - } - if ( !token.Icmp( "forceHighQuality" ) ) { - td = TD_HIGH_QUALITY; - continue; - } - - if ( !token.Icmp( "uncompressed" ) || !token.Icmp( "highquality" ) ) { - if ( !globalImages->image_ignoreHighQuality.GetInteger() ) { - td = TD_HIGH_QUALITY; - } - continue; - } - if ( !token.Icmp( "nopicmip" ) ) { - allowPicmip = false; - continue; - } - - // assume anything else is the image name - src.UnreadToken( &token ); - break; - } - str = R_ParsePastImageProgram( src ); - - newStage->fragmentProgramImages[unit] = - globalImages->ImageFromFile( str, tf, allowPicmip, trp, td, cubeMap ); - if ( !newStage->fragmentProgramImages[unit] ) { - newStage->fragmentProgramImages[unit] = globalImages->defaultImage; - } + const char *str; + textureFilter_t tf; + textureRepeat_t trp; + textureDepth_t td; + cubeFiles_t cubeMap; + bool allowPicmip; + idToken token; + + tf = TF_DEFAULT; + trp = TR_REPEAT; + td = TD_DEFAULT; + allowPicmip = true; + cubeMap = CF_2D; + + src.ReadTokenOnLine( &token ); + + int unit = token.GetIntValue(); + if ( !token.IsNumeric() || unit < 0 || unit >= MAX_FRAGMENT_IMAGES ) { + common->Warning( "bad fragmentMap number\n" ); + SetMaterialFlag( MF_DEFAULTED ); + return; + } + + // unit 1 is the normal map.. make sure it gets flagged as the proper depth + if ( unit == 1 ) { + td = TD_BUMP; + } + + if ( unit >= newStage->numFragmentProgramImages ) { + newStage->numFragmentProgramImages = unit + 1; + } + + while ( 1 ) { + src.ReadTokenOnLine( &token ); + + if ( !token.Icmp( "cubeMap" ) ) { + cubeMap = CF_NATIVE; + continue; + } + + if ( !token.Icmp( "cameraCubeMap" ) ) { + cubeMap = CF_CAMERA; + continue; + } + + if ( !token.Icmp( "nearest" ) ) { + tf = TF_NEAREST; + continue; + } + + if ( !token.Icmp( "linear" ) ) { + tf = TF_LINEAR; + continue; + } + + if ( !token.Icmp( "clamp" ) ) { + trp = TR_CLAMP; + continue; + } + + if ( !token.Icmp( "noclamp" ) ) { + trp = TR_REPEAT; + continue; + } + + if ( !token.Icmp( "zeroclamp" ) ) { + trp = TR_CLAMP_TO_ZERO; + continue; + } + + if ( !token.Icmp( "alphazeroclamp" ) ) { + trp = TR_CLAMP_TO_ZERO_ALPHA; + continue; + } + + if ( !token.Icmp( "forceHighQuality" ) ) { + td = TD_HIGH_QUALITY; + continue; + } + + if ( !token.Icmp( "uncompressed" ) || !token.Icmp( "highquality" ) ) { + if ( !globalImages->image_ignoreHighQuality.GetInteger() ) { + td = TD_HIGH_QUALITY; + } + continue; + } + + if ( !token.Icmp( "nopicmip" ) ) { + allowPicmip = false; + continue; + } + + // assume anything else is the image name + src.UnreadToken( &token ); + break; + } + str = R_ParsePastImageProgram( src ); + + newStage->fragmentProgramImages[unit] = globalImages->ImageFromFile( str, tf, allowPicmip, trp, td, cubeMap ); + + if ( !newStage->fragmentProgramImages[unit] ) { + newStage->fragmentProgramImages[unit] = globalImages->defaultImage; + } } /* @@ -1028,41 +1085,39 @@ idMaterial::MultiplyTextureMatrix =============== */ void idMaterial::MultiplyTextureMatrix( textureStage_t *ts, int registers[2][3] ) { - int old[2][3]; - - if ( !ts->hasMatrix ) { - ts->hasMatrix = true; - memcpy( ts->matrix, registers, sizeof( ts->matrix ) ); - return; - } - - memcpy( old, ts->matrix, sizeof( old ) ); - - // multiply the two maticies - ts->matrix[0][0] = EmitOp( - EmitOp( old[0][0], registers[0][0], OP_TYPE_MULTIPLY ), - EmitOp( old[0][1], registers[1][0], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ); - ts->matrix[0][1] = EmitOp( - EmitOp( old[0][0], registers[0][1], OP_TYPE_MULTIPLY ), - EmitOp( old[0][1], registers[1][1], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ); - ts->matrix[0][2] = EmitOp( - EmitOp( - EmitOp( old[0][0], registers[0][2], OP_TYPE_MULTIPLY ), - EmitOp( old[0][1], registers[1][2], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ), - old[0][2], OP_TYPE_ADD ); - - ts->matrix[1][0] = EmitOp( - EmitOp( old[1][0], registers[0][0], OP_TYPE_MULTIPLY ), - EmitOp( old[1][1], registers[1][0], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ); - ts->matrix[1][1] = EmitOp( - EmitOp( old[1][0], registers[0][1], OP_TYPE_MULTIPLY ), - EmitOp( old[1][1], registers[1][1], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ); - ts->matrix[1][2] = EmitOp( - EmitOp( - EmitOp( old[1][0], registers[0][2], OP_TYPE_MULTIPLY ), - EmitOp( old[1][1], registers[1][2], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ), - old[1][2], OP_TYPE_ADD ); - + int old[2][3]; + + if ( !ts->hasMatrix ) { + ts->hasMatrix = true; + memcpy( ts->matrix, registers, sizeof( ts->matrix ) ); + return; + } + memcpy( old, ts->matrix, sizeof( old ) ); + + // multiply the two maticies + ts->matrix[0][0] = EmitOp( + EmitOp( old[0][0], registers[0][0], OP_TYPE_MULTIPLY ), + EmitOp( old[0][1], registers[1][0], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ); + ts->matrix[0][1] = EmitOp( + EmitOp( old[0][0], registers[0][1], OP_TYPE_MULTIPLY ), + EmitOp( old[0][1], registers[1][1], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ); + ts->matrix[0][2] = EmitOp( + EmitOp( + EmitOp( old[0][0], registers[0][2], OP_TYPE_MULTIPLY ), + EmitOp( old[0][1], registers[1][2], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ), + old[0][2], OP_TYPE_ADD ); + + ts->matrix[1][0] = EmitOp( + EmitOp( old[1][0], registers[0][0], OP_TYPE_MULTIPLY ), + EmitOp( old[1][1], registers[1][0], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ); + ts->matrix[1][1] = EmitOp( + EmitOp( old[1][0], registers[0][1], OP_TYPE_MULTIPLY ), + EmitOp( old[1][1], registers[1][1], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ); + ts->matrix[1][2] = EmitOp( + EmitOp( + EmitOp( old[1][0], registers[0][2], OP_TYPE_MULTIPLY ), + EmitOp( old[1][1], registers[1][2], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ), + old[1][2], OP_TYPE_ADD ); } /* @@ -1073,516 +1128,554 @@ An open brace has been parsed { - if - map - "nearest" "linear" "clamp" "zeroclamp" "uncompressed" "highquality" "nopicmip" - scroll, scale, rotate + if + map + "nearest" "linear" "clamp" "zeroclamp" "uncompressed" "highquality" "nopicmip" + scroll, scale, rotate } ================= */ void idMaterial::ParseStage( idLexer &src, const textureRepeat_t trpDefault ) { - idToken token; - const char *str; - shaderStage_t *ss; - textureStage_t *ts; - textureFilter_t tf; - textureRepeat_t trp; - textureDepth_t td; - cubeFiles_t cubeMap; - bool allowPicmip; - char imageName[MAX_IMAGE_NAME]; - int a, b; - int matrix[2][3]; - newShaderStage_t newStage; - - if ( numStages >= MAX_SHADER_STAGES ) { - SetMaterialFlag( MF_DEFAULTED ); - common->Warning( "material '%s' exceeded %i stages", GetName(), MAX_SHADER_STAGES ); - } - - tf = TF_DEFAULT; - trp = trpDefault; - td = TD_DEFAULT; - allowPicmip = true; - cubeMap = CF_2D; - - imageName[0] = 0; - - memset( &newStage, 0, sizeof( newStage ) ); - - ss = &pd->parseStages[numStages]; - ts = &ss->texture; - - ClearStage( ss ); - - while ( 1 ) { - if ( TestMaterialFlag( MF_DEFAULTED ) ) { // we have a parse error - return; - } - if ( !src.ExpectAnyToken( &token ) ) { - SetMaterialFlag( MF_DEFAULTED ); - return; - } - - // the close brace for the entire material ends the draw block - if ( token == "}" ) { - break; - } - - //BSM Nerve: Added for stage naming in the material editor - if( !token.Icmp( "name") ) { - src.SkipRestOfLine(); - continue; - } - - // image options - if ( !token.Icmp( "blend" ) ) { - ParseBlend( src, ss ); - continue; - } - - if ( !token.Icmp( "map" ) ) { - str = R_ParsePastImageProgram( src ); - idStr::Copynz( imageName, str, sizeof( imageName ) ); - continue; - } - - if ( !token.Icmp( "remoteRenderMap" ) ) { - ts->dynamic = DI_REMOTE_RENDER; - ts->width = src.ParseInt(); - ts->height = src.ParseInt(); - continue; - } - - if ( !token.Icmp( "mirrorRenderMap" ) ) { - ts->dynamic = DI_MIRROR_RENDER; - ts->width = src.ParseInt(); - ts->height = src.ParseInt(); - ts->texgen = TG_SCREEN; - continue; - } - - if ( !token.Icmp( "xrayRenderMap" ) ) { - ts->dynamic = DI_XRAY_RENDER; - ts->width = src.ParseInt(); - ts->height = src.ParseInt(); - ts->texgen = TG_SCREEN; - continue; - } - if ( !token.Icmp( "screen" ) ) { - ts->texgen = TG_SCREEN; - continue; - } - if ( !token.Icmp( "screen2" ) ) { - ts->texgen = TG_SCREEN2; - continue; - } - if ( !token.Icmp( "glassWarp" ) ) { - ts->texgen = TG_GLASSWARP; - continue; - } - - if ( !token.Icmp( "videomap" ) ) { - // note that videomaps will always be in clamp mode, so texture - // coordinates had better be in the 0 to 1 range - if ( !src.ReadToken( &token ) ) { - common->Warning( "missing parameter for 'videoMap' keyword in material '%s'", GetName() ); - continue; - } - bool loop = false; - if ( !token.Icmp( "loop" ) ) { - loop = true; - if ( !src.ReadToken( &token ) ) { - common->Warning( "missing parameter for 'videoMap' keyword in material '%s'", GetName() ); - continue; - } - } - ts->cinematic = idCinematic::Alloc(); - ts->cinematic->InitFromFile( token.c_str(), loop ); - continue; - } - - if ( !token.Icmp( "soundmap" ) ) { - if ( !src.ReadToken( &token ) ) { - common->Warning( "missing parameter for 'soundmap' keyword in material '%s'", GetName() ); - continue; - } - ts->cinematic = new idSndWindow(); - ts->cinematic->InitFromFile( token.c_str(), true ); - continue; - } - - if ( !token.Icmp( "cubeMap" ) ) { - str = R_ParsePastImageProgram( src ); - idStr::Copynz( imageName, str, sizeof( imageName ) ); - cubeMap = CF_NATIVE; - continue; - } - - if ( !token.Icmp( "cameraCubeMap" ) ) { - str = R_ParsePastImageProgram( src ); - idStr::Copynz( imageName, str, sizeof( imageName ) ); - cubeMap = CF_CAMERA; - continue; - } - - if ( !token.Icmp( "ignoreAlphaTest" ) ) { - ss->ignoreAlphaTest = true; - continue; - } - if ( !token.Icmp( "nearest" ) ) { - tf = TF_NEAREST; - continue; - } - if ( !token.Icmp( "linear" ) ) { - tf = TF_LINEAR; - continue; - } - if ( !token.Icmp( "clamp" ) ) { - trp = TR_CLAMP; - continue; - } - if ( !token.Icmp( "noclamp" ) ) { - trp = TR_REPEAT; - continue; - } - if ( !token.Icmp( "zeroclamp" ) ) { - trp = TR_CLAMP_TO_ZERO; - continue; - } - if ( !token.Icmp( "alphazeroclamp" ) ) { - trp = TR_CLAMP_TO_ZERO_ALPHA; - continue; - } - if ( !token.Icmp( "uncompressed" ) || !token.Icmp( "highquality" ) ) { - if ( !globalImages->image_ignoreHighQuality.GetInteger() ) { - td = TD_HIGH_QUALITY; - } - continue; - } - if ( !token.Icmp( "forceHighQuality" ) ) { - td = TD_HIGH_QUALITY; - continue; - } - if ( !token.Icmp( "nopicmip" ) ) { - allowPicmip = false; - continue; - } - if ( !token.Icmp( "vertexColor" ) ) { - ss->vertexColor = SVC_MODULATE; - continue; - } - if ( !token.Icmp( "inverseVertexColor" ) ) { - ss->vertexColor = SVC_INVERSE_MODULATE; - continue; - } - - // privatePolygonOffset - else if ( !token.Icmp( "privatePolygonOffset" ) ) { - if ( !src.ReadTokenOnLine( &token ) ) { - ss->privatePolygonOffset = 1; - continue; - } - // explict larger (or negative) offset - src.UnreadToken( &token ); - ss->privatePolygonOffset = src.ParseFloat(); - continue; - } - - // texture coordinate generation - if ( !token.Icmp( "texGen" ) ) { - src.ExpectAnyToken( &token ); - if ( !token.Icmp( "normal" ) ) { - ts->texgen = TG_DIFFUSE_CUBE; - } else if ( !token.Icmp( "reflect" ) ) { - ts->texgen = TG_REFLECT_CUBE; - } else if ( !token.Icmp( "skybox" ) ) { - ts->texgen = TG_SKYBOX_CUBE; - } else if ( !token.Icmp( "wobbleSky" ) ) { - ts->texgen = TG_WOBBLESKY_CUBE; - texGenRegisters[0] = ParseExpression( src ); - texGenRegisters[1] = ParseExpression( src ); - texGenRegisters[2] = ParseExpression( src ); - } else { - common->Warning( "bad texGen '%s' in material %s", token.c_str(), GetName() ); - SetMaterialFlag( MF_DEFAULTED ); - } - continue; - } - if ( !token.Icmp( "scroll" ) || !token.Icmp( "translate" ) ) { - a = ParseExpression( src ); - MatchToken( src, "," ); - b = ParseExpression( src ); - matrix[0][0] = GetExpressionConstant( 1 ); - matrix[0][1] = GetExpressionConstant( 0 ); - matrix[0][2] = a; - matrix[1][0] = GetExpressionConstant( 0 ); - matrix[1][1] = GetExpressionConstant( 1 ); - matrix[1][2] = b; - - MultiplyTextureMatrix( ts, matrix ); - continue; - } - if ( !token.Icmp( "scale" ) ) { - a = ParseExpression( src ); - MatchToken( src, "," ); - b = ParseExpression( src ); - // this just scales without a centering - matrix[0][0] = a; - matrix[0][1] = GetExpressionConstant( 0 ); - matrix[0][2] = GetExpressionConstant( 0 ); - matrix[1][0] = GetExpressionConstant( 0 ); - matrix[1][1] = b; - matrix[1][2] = GetExpressionConstant( 0 ); - - MultiplyTextureMatrix( ts, matrix ); - continue; - } - if ( !token.Icmp( "centerScale" ) ) { - a = ParseExpression( src ); - MatchToken( src, "," ); - b = ParseExpression( src ); - // this subtracts 0.5, then scales, then adds 0.5 - matrix[0][0] = a; - matrix[0][1] = GetExpressionConstant( 0 ); - matrix[0][2] = EmitOp( GetExpressionConstant( 0.5 ), EmitOp( GetExpressionConstant( 0.5 ), a, OP_TYPE_MULTIPLY ), OP_TYPE_SUBTRACT ); - matrix[1][0] = GetExpressionConstant( 0 ); - matrix[1][1] = b; - matrix[1][2] = EmitOp( GetExpressionConstant( 0.5 ), EmitOp( GetExpressionConstant( 0.5 ), b, OP_TYPE_MULTIPLY ), OP_TYPE_SUBTRACT ); - - MultiplyTextureMatrix( ts, matrix ); - continue; - } - if ( !token.Icmp( "shear" ) ) { - a = ParseExpression( src ); - MatchToken( src, "," ); - b = ParseExpression( src ); - // this subtracts 0.5, then shears, then adds 0.5 - matrix[0][0] = GetExpressionConstant( 1 ); - matrix[0][1] = a; - matrix[0][2] = EmitOp( GetExpressionConstant( -0.5 ), a, OP_TYPE_MULTIPLY ); - matrix[1][0] = b; - matrix[1][1] = GetExpressionConstant( 1 ); - matrix[1][2] = EmitOp( GetExpressionConstant( -0.5 ), b, OP_TYPE_MULTIPLY ); - - MultiplyTextureMatrix( ts, matrix ); - continue; - } - if ( !token.Icmp( "rotate" ) ) { - const idDeclTable *table; - int sinReg, cosReg; - - // in cycles - a = ParseExpression( src ); - - table = static_cast( declManager->FindType( DECL_TABLE, "sinTable", false ) ); - if ( !table ) { - common->Warning( "no sinTable for rotate defined" ); - SetMaterialFlag( MF_DEFAULTED ); - return; - } - sinReg = EmitOp( table->Index(), a, OP_TYPE_TABLE ); - - table = static_cast( declManager->FindType( DECL_TABLE, "cosTable", false ) ); - if ( !table ) { - common->Warning( "no cosTable for rotate defined" ); - SetMaterialFlag( MF_DEFAULTED ); - return; - } - cosReg = EmitOp( table->Index(), a, OP_TYPE_TABLE ); - - // this subtracts 0.5, then rotates, then adds 0.5 - matrix[0][0] = cosReg; - matrix[0][1] = EmitOp( GetExpressionConstant( 0 ), sinReg, OP_TYPE_SUBTRACT ); - matrix[0][2] = EmitOp( EmitOp( EmitOp( GetExpressionConstant( -0.5 ), cosReg, OP_TYPE_MULTIPLY ), - EmitOp( GetExpressionConstant( 0.5 ), sinReg, OP_TYPE_MULTIPLY ), OP_TYPE_ADD ), - GetExpressionConstant( 0.5 ), OP_TYPE_ADD ); - - matrix[1][0] = sinReg; - matrix[1][1] = cosReg; - matrix[1][2] = EmitOp( EmitOp( EmitOp( GetExpressionConstant( -0.5 ), sinReg, OP_TYPE_MULTIPLY ), - EmitOp( GetExpressionConstant( -0.5 ), cosReg, OP_TYPE_MULTIPLY ), OP_TYPE_ADD ), - GetExpressionConstant( 0.5 ), OP_TYPE_ADD ); - - MultiplyTextureMatrix( ts, matrix ); - continue; - } - - // color mask options - if ( !token.Icmp( "maskRed" ) ) { - ss->drawStateBits |= GLS_REDMASK; - continue; - } - if ( !token.Icmp( "maskGreen" ) ) { - ss->drawStateBits |= GLS_GREENMASK; - continue; - } - if ( !token.Icmp( "maskBlue" ) ) { - ss->drawStateBits |= GLS_BLUEMASK; - continue; - } - if ( !token.Icmp( "maskAlpha" ) ) { - ss->drawStateBits |= GLS_ALPHAMASK; - continue; - } - if ( !token.Icmp( "maskColor" ) ) { - ss->drawStateBits |= GLS_COLORMASK; - continue; - } - if ( !token.Icmp( "maskDepth" ) ) { - ss->drawStateBits |= GLS_DEPTHMASK; - continue; - } - if ( !token.Icmp( "ignoreDepth" ) ) { // Added in #3877. - ss->drawStateBits |= GLS_DEPTHFUNC_ALWAYS; - continue; - } - if ( !token.Icmp( "alphaTest" ) ) { - ss->hasAlphaTest = true; - ss->alphaTestRegister = ParseExpression( src ); - coverage = MC_PERFORATED; - continue; - } - - // shorthand for 2D modulated - if ( !token.Icmp( "colored" ) ) { - ss->color.registers[0] = EXP_REG_PARM0; - ss->color.registers[1] = EXP_REG_PARM1; - ss->color.registers[2] = EXP_REG_PARM2; - ss->color.registers[3] = EXP_REG_PARM3; - pd->registersAreConstant = false; - continue; - } - - if ( !token.Icmp( "color" ) ) { - ss->color.registers[0] = ParseExpression( src ); - MatchToken( src, "," ); - ss->color.registers[1] = ParseExpression( src ); - MatchToken( src, "," ); - ss->color.registers[2] = ParseExpression( src ); - MatchToken( src, "," ); - ss->color.registers[3] = ParseExpression( src ); - continue; - } - if ( !token.Icmp( "red" ) ) { - ss->color.registers[0] = ParseExpression( src ); - continue; - } - if ( !token.Icmp( "green" ) ) { - ss->color.registers[1] = ParseExpression( src ); - continue; - } - if ( !token.Icmp( "blue" ) ) { - ss->color.registers[2] = ParseExpression( src ); - continue; - } - if ( !token.Icmp( "alpha" ) ) { - ss->color.registers[3] = ParseExpression( src ); - continue; - } - if ( !token.Icmp( "rgb" ) ) { - ss->color.registers[0] = ss->color.registers[1] = - ss->color.registers[2] = ParseExpression( src ); - continue; - } - if ( !token.Icmp( "rgba" ) ) { - ss->color.registers[0] = ss->color.registers[1] = - ss->color.registers[2] = ss->color.registers[3] = ParseExpression( src ); - continue; - } - - if ( !token.Icmp( "if" ) ) { - ss->conditionRegister = ParseExpression( src ); - continue; - } - if ( !token.Icmp( "program" ) ) { - if ( src.ReadTokenOnLine( &token ) ) { - newStage.vertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, token.c_str() ); - newStage.fragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, token.c_str() ); - } - continue; - } - if ( !token.Icmp( "fragmentProgram" ) ) { - if ( src.ReadTokenOnLine( &token ) ) { - newStage.fragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, token.c_str() ); - } - continue; - } - if ( !token.Icmp( "vertexProgram" ) ) { - if ( src.ReadTokenOnLine( &token ) ) { - newStage.vertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, token.c_str() ); - } - continue; - } - if ( !token.Icmp( "megaTexture" ) ) { - if ( src.ReadTokenOnLine( &token ) ) { - newStage.megaTexture = new idMegaTexture; - if ( !newStage.megaTexture->InitFromMegaFile( token.c_str() ) ) { - delete newStage.megaTexture; - SetMaterialFlag( MF_DEFAULTED ); - continue; - } - newStage.vertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "megaTexture.vfp" ); - newStage.fragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "megaTexture.vfp" ); - continue; - } - } - - - if ( !token.Icmp( "vertexParm" ) ) { - ParseVertexParm( src, &newStage ); - continue; - } - - if ( !token.Icmp( "fragmentMap" ) ) { - ParseFragmentMap( src, &newStage ); - continue; - } - - - common->Warning( "unknown token '%s' in material '%s'", token.c_str(), GetName() ); - SetMaterialFlag( MF_DEFAULTED ); - return; - } - - - // if we are using newStage, allocate a copy of it - if ( newStage.fragmentProgram || newStage.vertexProgram ) { - ss->newStage = (newShaderStage_t *)Mem_Alloc( sizeof( newStage ) ); - *(ss->newStage) = newStage; - } - - // successfully parsed a stage - numStages++; - - // select a compressed depth based on what the stage is - if ( td == TD_DEFAULT ) { - switch( ss->lighting ) { - case SL_BUMP: - td = TD_BUMP; - break; - case SL_DIFFUSE: - td = TD_DIFFUSE; - break; - case SL_SPECULAR: - td = TD_SPECULAR; - break; - default: - break; - } - } - - // now load the image with all the parms we parsed - if ( imageName[0] ) { - ts->image = globalImages->ImageFromFile( imageName, tf, allowPicmip, trp, td, cubeMap ); - if ( !ts->image ) { - ts->image = globalImages->defaultImage; - } - } else if ( !ts->cinematic && !ts->dynamic && !ss->newStage ) { - common->Warning( "material '%s' had stage with no image", GetName() ); - ts->image = globalImages->defaultImage; - } + idToken token; + const char *str; + shaderStage_t *ss; + textureStage_t *ts; + textureFilter_t tf; + textureRepeat_t trp; + textureDepth_t td; + cubeFiles_t cubeMap; + bool allowPicmip; + char imageName[MAX_IMAGE_NAME]; + int a, b; + int matrix[2][3]; + newShaderStage_t newStage; + + if ( numStages >= MAX_SHADER_STAGES ) { + SetMaterialFlag( MF_DEFAULTED ); + common->Warning( "material '%s' exceeded %i stages", GetName(), MAX_SHADER_STAGES ); + } + tf = TF_DEFAULT; + trp = trpDefault; + td = TD_DEFAULT; + allowPicmip = true; + cubeMap = CF_2D; + + imageName[0] = 0; + + memset( &newStage, 0, sizeof( newStage ) ); + + ss = &pd->parseStages[numStages]; + ts = &ss->texture; + + ClearStage( ss ); + + while ( 1 ) { + if ( TestMaterialFlag( MF_DEFAULTED ) ) { // we have a parse error + return; + } + + if ( !src.ExpectAnyToken( &token ) ) { + SetMaterialFlag( MF_DEFAULTED ); + return; + } + + // the close brace for the entire material ends the draw block + if ( token == "}" ) { + break; + } + + //BSM Nerve: Added for stage naming in the material editor + if ( !token.Icmp( "name" ) ) { + src.SkipRestOfLine(); + continue; + } + + // image options + if ( !token.Icmp( "blend" ) ) { + ParseBlend( src, ss ); + continue; + } + + if ( !token.Icmp( "map" ) ) { + str = R_ParsePastImageProgram( src ); + idStr::Copynz( imageName, str, sizeof( imageName ) ); + continue; + } + + if ( !token.Icmp( "remoteRenderMap" ) ) { + ts->dynamic = DI_REMOTE_RENDER; + ts->width = src.ParseInt(); + ts->height = src.ParseInt(); + continue; + } + + if ( !token.Icmp( "mirrorRenderMap" ) ) { + ts->dynamic = DI_MIRROR_RENDER; + ts->width = src.ParseInt(); + ts->height = src.ParseInt(); + ts->texgen = TG_SCREEN; + continue; + } + + if ( !token.Icmp( "xrayRenderMap" ) ) { + ts->dynamic = DI_XRAY_RENDER; + ts->width = src.ParseInt(); + ts->height = src.ParseInt(); + ts->texgen = TG_SCREEN; + continue; + } + + if ( !token.Icmp( "screen" ) ) { + ts->texgen = TG_SCREEN; + continue; + } + + if ( !token.Icmp( "screen2" ) ) { + ts->texgen = TG_SCREEN2; + continue; + } + + if ( !token.Icmp( "glassWarp" ) ) { + ts->texgen = TG_GLASSWARP; + continue; + } + + if ( !token.Icmp( "videomap" ) ) { + // note that videomaps will always be in clamp mode, so texture + // coordinates had better be in the 0 to 1 range + if ( !src.ReadToken( &token ) ) { + common->Warning( "missing parameter for 'videoMap' keyword in material '%s'", GetName() ); + continue; + } + bool loop = false; + + if ( !token.Icmp( "loop" ) ) { + loop = true; + + if ( !src.ReadToken( &token ) ) { + common->Warning( "missing parameter for 'videoMap' keyword in material '%s'", GetName() ); + continue; + } + } + ts->cinematic = idCinematic::Alloc(); + ts->cinematic->InitFromFile( token.c_str(), loop ); + continue; + } + + if ( !token.Icmp( "soundmap" ) ) { + if ( !src.ReadToken( &token ) ) { + common->Warning( "missing parameter for 'soundmap' keyword in material '%s'", GetName() ); + continue; + } + ts->cinematic = new idSndWindow(); + ts->cinematic->InitFromFile( token.c_str(), true ); + continue; + } + + if ( !token.Icmp( "cubeMap" ) ) { + str = R_ParsePastImageProgram( src ); + idStr::Copynz( imageName, str, sizeof( imageName ) ); + cubeMap = CF_NATIVE; + continue; + } + + if ( !token.Icmp( "cameraCubeMap" ) ) { + str = R_ParsePastImageProgram( src ); + idStr::Copynz( imageName, str, sizeof( imageName ) ); + cubeMap = CF_CAMERA; + continue; + } + + if ( !token.Icmp( "ignoreAlphaTest" ) ) { + ss->ignoreAlphaTest = true; + continue; + } + + if ( !token.Icmp( "nearest" ) ) { + tf = TF_NEAREST; + continue; + } + + if ( !token.Icmp( "linear" ) ) { + tf = TF_LINEAR; + continue; + } + + if ( !token.Icmp( "clamp" ) ) { + trp = TR_CLAMP; + continue; + } + + if ( !token.Icmp( "noclamp" ) ) { + trp = TR_REPEAT; + continue; + } + + if ( !token.Icmp( "zeroclamp" ) ) { + trp = TR_CLAMP_TO_ZERO; + continue; + } + + if ( !token.Icmp( "alphazeroclamp" ) ) { + trp = TR_CLAMP_TO_ZERO_ALPHA; + continue; + } + + if ( !token.Icmp( "uncompressed" ) || !token.Icmp( "highquality" ) ) { + if ( !globalImages->image_ignoreHighQuality.GetInteger() ) { + td = TD_HIGH_QUALITY; + } + continue; + } + + if ( !token.Icmp( "forceHighQuality" ) ) { + td = TD_HIGH_QUALITY; + continue; + } + + if ( !token.Icmp( "nopicmip" ) ) { + allowPicmip = false; + continue; + } + + if ( !token.Icmp( "vertexColor" ) ) { + ss->vertexColor = SVC_MODULATE; + continue; + } + + if ( !token.Icmp( "inverseVertexColor" ) ) { + ss->vertexColor = SVC_INVERSE_MODULATE; + continue; + } else if ( !token.Icmp( "privatePolygonOffset" ) ) { + // privatePolygonOffset + if ( !src.ReadTokenOnLine( &token ) ) { + ss->privatePolygonOffset = 1; + continue; + } + + // explict larger (or negative) offset + src.UnreadToken( &token ); + ss->privatePolygonOffset = src.ParseFloat(); + continue; + } + + // texture coordinate generation + if ( !token.Icmp( "texGen" ) ) { + src.ExpectAnyToken( &token ); + if ( !token.Icmp( "normal" ) ) { + ts->texgen = TG_DIFFUSE_CUBE; + } else if ( !token.Icmp( "reflect" ) ) { + ts->texgen = TG_REFLECT_CUBE; + } else if ( !token.Icmp( "skybox" ) ) { + ts->texgen = TG_SKYBOX_CUBE; + } else if ( !token.Icmp( "wobbleSky" ) ) { + ts->texgen = TG_WOBBLESKY_CUBE; + texGenRegisters[0] = ParseExpression( src ); + texGenRegisters[1] = ParseExpression( src ); + texGenRegisters[2] = ParseExpression( src ); + } else { + common->Warning( "bad texGen '%s' in material %s", token.c_str(), GetName() ); + SetMaterialFlag( MF_DEFAULTED ); + } + continue; + } + + if ( !token.Icmp( "scroll" ) || !token.Icmp( "translate" ) ) { + a = ParseExpression( src ); + MatchToken( src, "," ); + b = ParseExpression( src ); + matrix[0][0] = GetExpressionConstant( 1 ); + matrix[0][1] = GetExpressionConstant( 0 ); + matrix[0][2] = a; + matrix[1][0] = GetExpressionConstant( 0 ); + matrix[1][1] = GetExpressionConstant( 1 ); + matrix[1][2] = b; + + MultiplyTextureMatrix( ts, matrix ); + continue; + } + + if ( !token.Icmp( "scale" ) ) { + a = ParseExpression( src ); + MatchToken( src, "," ); + b = ParseExpression( src ); + // this just scales without a centering + matrix[0][0] = a; + matrix[0][1] = GetExpressionConstant( 0 ); + matrix[0][2] = GetExpressionConstant( 0 ); + matrix[1][0] = GetExpressionConstant( 0 ); + matrix[1][1] = b; + matrix[1][2] = GetExpressionConstant( 0 ); + + MultiplyTextureMatrix( ts, matrix ); + continue; + } + + if ( !token.Icmp( "centerScale" ) ) { + a = ParseExpression( src ); + MatchToken( src, "," ); + b = ParseExpression( src ); + // this subtracts 0.5, then scales, then adds 0.5 + matrix[0][0] = a; + matrix[0][1] = GetExpressionConstant( 0 ); + matrix[0][2] = EmitOp( GetExpressionConstant( 0.5 ), EmitOp( GetExpressionConstant( 0.5 ), a, OP_TYPE_MULTIPLY ), OP_TYPE_SUBTRACT ); + matrix[1][0] = GetExpressionConstant( 0 ); + matrix[1][1] = b; + matrix[1][2] = EmitOp( GetExpressionConstant( 0.5 ), EmitOp( GetExpressionConstant( 0.5 ), b, OP_TYPE_MULTIPLY ), OP_TYPE_SUBTRACT ); + + MultiplyTextureMatrix( ts, matrix ); + continue; + } + + if ( !token.Icmp( "shear" ) ) { + a = ParseExpression( src ); + MatchToken( src, "," ); + b = ParseExpression( src ); + // this subtracts 0.5, then shears, then adds 0.5 + matrix[0][0] = GetExpressionConstant( 1 ); + matrix[0][1] = a; + matrix[0][2] = EmitOp( GetExpressionConstant( -0.5 ), a, OP_TYPE_MULTIPLY ); + matrix[1][0] = b; + matrix[1][1] = GetExpressionConstant( 1 ); + matrix[1][2] = EmitOp( GetExpressionConstant( -0.5 ), b, OP_TYPE_MULTIPLY ); + + MultiplyTextureMatrix( ts, matrix ); + continue; + } + + if ( !token.Icmp( "rotate" ) ) { + const idDeclTable *table; + int sinReg, cosReg; + + // in cycles + a = ParseExpression( src ); + + table = static_cast( declManager->FindType( DECL_TABLE, "sinTable", false ) ); + + if ( !table ) { + common->Warning( "no sinTable for rotate defined" ); + SetMaterialFlag( MF_DEFAULTED ); + return; + } + sinReg = EmitOp( table->Index(), a, OP_TYPE_TABLE ); + + table = static_cast( declManager->FindType( DECL_TABLE, "cosTable", false ) ); + + if ( !table ) { + common->Warning( "no cosTable for rotate defined" ); + SetMaterialFlag( MF_DEFAULTED ); + return; + } + cosReg = EmitOp( table->Index(), a, OP_TYPE_TABLE ); + + // this subtracts 0.5, then rotates, then adds 0.5 + matrix[0][0] = cosReg; + matrix[0][1] = EmitOp( GetExpressionConstant( 0 ), sinReg, OP_TYPE_SUBTRACT ); + matrix[0][2] = EmitOp( EmitOp( + EmitOp( GetExpressionConstant( -0.5 ), cosReg, OP_TYPE_MULTIPLY ), + EmitOp( GetExpressionConstant( 0.5 ), sinReg, OP_TYPE_MULTIPLY ), OP_TYPE_ADD ), + GetExpressionConstant( 0.5 ), OP_TYPE_ADD ); + + matrix[1][0] = sinReg; + matrix[1][1] = cosReg; + matrix[1][2] = EmitOp( EmitOp( + EmitOp( GetExpressionConstant( -0.5 ), sinReg, OP_TYPE_MULTIPLY ), + EmitOp( GetExpressionConstant( -0.5 ), cosReg, OP_TYPE_MULTIPLY ), OP_TYPE_ADD ), + GetExpressionConstant( 0.5 ), OP_TYPE_ADD ); + + MultiplyTextureMatrix( ts, matrix ); + continue; + } + + // color mask options + if ( !token.Icmp( "maskRed" ) ) { + ss->drawStateBits |= GLS_REDMASK; + continue; + } + + if ( !token.Icmp( "maskGreen" ) ) { + ss->drawStateBits |= GLS_GREENMASK; + continue; + } + + if ( !token.Icmp( "maskBlue" ) ) { + ss->drawStateBits |= GLS_BLUEMASK; + continue; + } + + if ( !token.Icmp( "maskAlpha" ) ) { + ss->drawStateBits |= GLS_ALPHAMASK; + continue; + } + + if ( !token.Icmp( "maskColor" ) ) { + ss->drawStateBits |= GLS_COLORMASK; + continue; + } + + if ( !token.Icmp( "maskDepth" ) ) { + ss->drawStateBits |= GLS_DEPTHMASK; + continue; + } + + if ( !token.Icmp( "ignoreDepth" ) ) { // Added in #3877. + ss->drawStateBits |= GLS_DEPTHFUNC_ALWAYS; + continue; + } + + if ( !token.Icmp( "alphaTest" ) ) { + ss->hasAlphaTest = true; + ss->alphaTestRegister = ParseExpression( src ); + coverage = MC_PERFORATED; + continue; + } + + // shorthand for 2D modulated + if ( !token.Icmp( "colored" ) ) { + ss->color.registers[0] = EXP_REG_PARM0; + ss->color.registers[1] = EXP_REG_PARM1; + ss->color.registers[2] = EXP_REG_PARM2; + ss->color.registers[3] = EXP_REG_PARM3; + pd->registersAreConstant = false; + continue; + } + + if ( !token.Icmp( "color" ) ) { + ss->color.registers[0] = ParseExpression( src ); + MatchToken( src, "," ); + ss->color.registers[1] = ParseExpression( src ); + MatchToken( src, "," ); + ss->color.registers[2] = ParseExpression( src ); + MatchToken( src, "," ); + ss->color.registers[3] = ParseExpression( src ); + continue; + } + + if ( !token.Icmp( "red" ) ) { + ss->color.registers[0] = ParseExpression( src ); + continue; + } + + if ( !token.Icmp( "green" ) ) { + ss->color.registers[1] = ParseExpression( src ); + continue; + } + + if ( !token.Icmp( "blue" ) ) { + ss->color.registers[2] = ParseExpression( src ); + continue; + } + + if ( !token.Icmp( "alpha" ) ) { + ss->color.registers[3] = ParseExpression( src ); + continue; + } + + if ( !token.Icmp( "rgb" ) ) { + ss->color.registers[0] = ss->color.registers[1] = + ss->color.registers[2] = ParseExpression( src ); + continue; + } + + if ( !token.Icmp( "rgba" ) ) { + ss->color.registers[0] = ss->color.registers[1] = + ss->color.registers[2] = ss->color.registers[3] = ParseExpression( src ); + continue; + } + + if ( !token.Icmp( "if" ) ) { + ss->conditionRegister = ParseExpression( src ); + continue; + } + + if ( !token.Icmp( "program" ) ) { + if ( src.ReadTokenOnLine( &token ) ) { + newStage.vertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, token.c_str() ); + newStage.fragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, token.c_str() ); + } + continue; + } + + if ( !token.Icmp( "fragmentProgram" ) ) { + if ( src.ReadTokenOnLine( &token ) ) { + newStage.fragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, token.c_str() ); + } + continue; + } + + if ( !token.Icmp( "vertexProgram" ) ) { + if ( src.ReadTokenOnLine( &token ) ) { + newStage.vertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, token.c_str() ); + } + continue; + } + + if ( !token.Icmp( "megaTexture" ) ) { + if ( src.ReadTokenOnLine( &token ) ) { + newStage.megaTexture = new idMegaTexture; + if ( !newStage.megaTexture->InitFromMegaFile( token.c_str() ) ) { + delete newStage.megaTexture; + SetMaterialFlag( MF_DEFAULTED ); + continue; + } + newStage.vertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "megaTexture.vfp" ); + newStage.fragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "megaTexture.vfp" ); + continue; + } + } + + if ( !token.Icmp( "vertexParm" ) ) { + ParseVertexParm( src, &newStage ); + continue; + } + + if ( !token.Icmp( "fragmentMap" ) ) { + ParseFragmentMap( src, &newStage ); + continue; + } + common->Warning( "unknown token '%s' in material '%s'", token.c_str(), GetName() ); + SetMaterialFlag( MF_DEFAULTED ); + return; + } + + // if we are using newStage, allocate a copy of it + if ( newStage.fragmentProgram || newStage.vertexProgram ) { + ss->newStage = ( newShaderStage_t * )Mem_Alloc( sizeof( newStage ) ); + *( ss->newStage ) = newStage; + } + + // successfully parsed a stage + numStages++; + + // select a compressed depth based on what the stage is + if ( td == TD_DEFAULT ) { + switch ( ss->lighting ) { + case SL_BUMP: + td = TD_BUMP; + break; + case SL_DIFFUSE: + td = TD_DIFFUSE; + break; + case SL_SPECULAR: + td = TD_SPECULAR; + break; + default: + break; + } + } + + // now load the image with all the parms we parsed + if ( imageName[0] ) { + ts->image = globalImages->ImageFromFile( imageName, tf, allowPicmip, trp, td, cubeMap ); + + if ( !ts->image ) { + ts->image = globalImages->defaultImage; + } + } else if ( !ts->cinematic && !ts->dynamic && !ss->newStage ) { + common->Warning( "material '%s' had stage with no image", GetName() ); + ts->image = globalImages->defaultImage; + } } /* @@ -1591,82 +1684,92 @@ idMaterial::ParseDeform =============== */ void idMaterial::ParseDeform( idLexer &src ) { - idToken token; - - if ( !src.ExpectAnyToken( &token ) ) { - return; - } - - if ( !token.Icmp( "sprite" ) ) { - deform = DFRM_SPRITE; - cullType = CT_TWO_SIDED; - SetMaterialFlag( MF_NOSHADOWS ); - return; - } - if ( !token.Icmp( "tube" ) ) { - deform = DFRM_TUBE; - cullType = CT_TWO_SIDED; - SetMaterialFlag( MF_NOSHADOWS ); - return; - } - if ( !token.Icmp( "flare" ) ) { - deform = DFRM_FLARE; - cullType = CT_TWO_SIDED; - deformRegisters[0] = ParseExpression( src ); - SetMaterialFlag( MF_NOSHADOWS ); - return; - } - if ( !token.Icmp( "expand" ) ) { - deform = DFRM_EXPAND; - deformRegisters[0] = ParseExpression( src ); - return; - } - if ( !token.Icmp( "move" ) ) { - deform = DFRM_MOVE; - deformRegisters[0] = ParseExpression( src ); - return; - } - if ( !token.Icmp( "turbulent" ) ) { - deform = DFRM_TURB; - - if ( !src.ExpectAnyToken( &token ) ) { - src.Warning( "deform particle missing particle name" ); - SetMaterialFlag( MF_DEFAULTED ); - return; - } - deformDecl = declManager->FindType( DECL_TABLE, token.c_str(), true ); - - deformRegisters[0] = ParseExpression( src ); - deformRegisters[1] = ParseExpression( src ); - deformRegisters[2] = ParseExpression( src ); - return; - } - if ( !token.Icmp( "eyeBall" ) ) { - deform = DFRM_EYEBALL; - return; - } - if ( !token.Icmp( "particle" ) ) { - deform = DFRM_PARTICLE; - if ( !src.ExpectAnyToken( &token ) ) { - src.Warning( "deform particle missing particle name" ); - SetMaterialFlag( MF_DEFAULTED ); - return; - } - deformDecl = declManager->FindType( DECL_PARTICLE, token.c_str(), true ); - return; - } - if ( !token.Icmp( "particle2" ) ) { - deform = DFRM_PARTICLE2; - if ( !src.ExpectAnyToken( &token ) ) { - src.Warning( "deform particle missing particle name" ); - SetMaterialFlag( MF_DEFAULTED ); - return; - } - deformDecl = declManager->FindType( DECL_PARTICLE, token.c_str(), true ); - return; - } - src.Warning( "Bad deform type '%s'", token.c_str() ); - SetMaterialFlag( MF_DEFAULTED ); + idToken token; + + if ( !src.ExpectAnyToken( &token ) ) { + return; + } + + if ( !token.Icmp( "sprite" ) ) { + deform = DFRM_SPRITE; + cullType = CT_TWO_SIDED; + SetMaterialFlag( MF_NOSHADOWS ); + return; + } + + if ( !token.Icmp( "tube" ) ) { + deform = DFRM_TUBE; + cullType = CT_TWO_SIDED; + SetMaterialFlag( MF_NOSHADOWS ); + return; + } + + if ( !token.Icmp( "flare" ) ) { + deform = DFRM_FLARE; + cullType = CT_TWO_SIDED; + deformRegisters[0] = ParseExpression( src ); + SetMaterialFlag( MF_NOSHADOWS ); + return; + } + + if ( !token.Icmp( "expand" ) ) { + deform = DFRM_EXPAND; + deformRegisters[0] = ParseExpression( src ); + return; + } + + if ( !token.Icmp( "move" ) ) { + deform = DFRM_MOVE; + deformRegisters[0] = ParseExpression( src ); + return; + } + + if ( !token.Icmp( "turbulent" ) ) { + deform = DFRM_TURB; + + if ( !src.ExpectAnyToken( &token ) ) { + src.Warning( "deform particle missing particle name" ); + SetMaterialFlag( MF_DEFAULTED ); + return; + } + deformDecl = declManager->FindType( DECL_TABLE, token.c_str(), true ); + + deformRegisters[0] = ParseExpression( src ); + deformRegisters[1] = ParseExpression( src ); + deformRegisters[2] = ParseExpression( src ); + return; + } + + if ( !token.Icmp( "eyeBall" ) ) { + deform = DFRM_EYEBALL; + return; + } + + if ( !token.Icmp( "particle" ) ) { + deform = DFRM_PARTICLE; + + if ( !src.ExpectAnyToken( &token ) ) { + src.Warning( "deform particle missing particle name" ); + SetMaterialFlag( MF_DEFAULTED ); + return; + } + deformDecl = declManager->FindType( DECL_PARTICLE, token.c_str(), true ); + return; + } + + if ( !token.Icmp( "particle2" ) ) { + deform = DFRM_PARTICLE2; + + if ( !src.ExpectAnyToken( &token ) ) { + src.Warning( "deform particle missing particle name" ); + SetMaterialFlag( MF_DEFAULTED ); + return; + } + deformDecl = declManager->FindType( DECL_PARTICLE, token.c_str(), true ); + return; + } + src.Warning( "Bad deform type '%s'", token.c_str() ); + SetMaterialFlag( MF_DEFAULTED ); } @@ -1686,52 +1789,55 @@ It is valid to have a reflection map and a bump map for bumpy reflection ============== */ void idMaterial::AddImplicitStages( const textureRepeat_t trpDefault /* = TR_REPEAT */ ) { - char buffer[1024]; - idLexer newSrc; - bool hasDiffuse = false; - bool hasSpecular = false; - bool hasBump = false; - bool hasReflection = false; - - for ( int i = 0 ; i < numStages ; i++ ) { - if ( pd->parseStages[i].lighting == SL_BUMP ) { - hasBump = true; - } - if ( pd->parseStages[i].lighting == SL_DIFFUSE ) { - hasDiffuse = true; - } - if ( pd->parseStages[i].lighting == SL_SPECULAR ) { - hasSpecular = true; - } - if ( pd->parseStages[i].texture.texgen == TG_REFLECT_CUBE ) { - hasReflection = true; - } - } - - // if it doesn't have an interaction at all, don't add anything - if ( !hasBump && !hasDiffuse && !hasSpecular ) { - return; - } - - if ( numStages == MAX_SHADER_STAGES ) { - return; - } - - if ( !hasBump ) { - idStr::snPrintf( buffer, sizeof( buffer ), "blend bumpmap\nmap _flat\n}\n" ); - newSrc.LoadMemory( buffer, strlen(buffer), "bumpmap" ); - newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ); - ParseStage( newSrc, trpDefault ); - newSrc.FreeSource(); - } - - if ( !hasDiffuse && !hasSpecular && !hasReflection ) { - idStr::snPrintf( buffer, sizeof( buffer ), "blend diffusemap\nmap _white\n}\n" ); - newSrc.LoadMemory( buffer, strlen(buffer), "diffusemap" ); - newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ); - ParseStage( newSrc, trpDefault ); - newSrc.FreeSource(); - } + char buffer[1024]; + idLexer newSrc; + bool hasDiffuse = false; + bool hasSpecular = false; + bool hasBump = false; + bool hasReflection = false; + + for ( int i = 0 ; i < numStages ; i++ ) { + if ( pd->parseStages[i].lighting == SL_BUMP ) { + hasBump = true; + } + + if ( pd->parseStages[i].lighting == SL_DIFFUSE ) { + hasDiffuse = true; + } + + if ( pd->parseStages[i].lighting == SL_SPECULAR ) { + hasSpecular = true; + } + + if ( pd->parseStages[i].texture.texgen == TG_REFLECT_CUBE ) { + hasReflection = true; + } + } + + // if it doesn't have an interaction at all, don't add anything + if ( !hasBump && !hasDiffuse && !hasSpecular ) { + return; + } + + if ( numStages == MAX_SHADER_STAGES ) { + return; + } + + if ( !hasBump ) { + idStr::snPrintf( buffer, sizeof( buffer ), "blend bumpmap\nmap _flat\n}\n" ); + newSrc.LoadMemory( buffer, strlen( buffer ), "bumpmap" ); + newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ); + ParseStage( newSrc, trpDefault ); + newSrc.FreeSource(); + } + + if ( !hasDiffuse && !hasSpecular && !hasReflection ) { + idStr::snPrintf( buffer, sizeof( buffer ), "blend diffusemap\nmap _white\n}\n" ); + newSrc.LoadMemory( buffer, strlen( buffer ), "diffusemap" ); + newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ); + ParseStage( newSrc, trpDefault ); + newSrc.FreeSource(); + } } @@ -1749,34 +1855,32 @@ stages are ignored during ambient drawing. =============== */ void idMaterial::SortInteractionStages() { - int j; - - for ( int i = 0 ; i < numStages ; i = j ) { - // find the next bump map - for ( j = i + 1 ; j < numStages ; j++ ) { - if ( pd->parseStages[j].lighting == SL_BUMP ) { - // if the very first stage wasn't a bumpmap, - // this bumpmap is part of the first group - if ( pd->parseStages[i].lighting != SL_BUMP ) { - continue; - } - break; - } - } - - // bubble sort everything bump / diffuse / specular - for ( int l = 1 ; l < j-i ; l++ ) { - for ( int k = i ; k < j-l ; k++ ) { - if ( pd->parseStages[k].lighting > pd->parseStages[k+1].lighting ) { - shaderStage_t temp; - - temp = pd->parseStages[k]; - pd->parseStages[k] = pd->parseStages[k+1]; - pd->parseStages[k+1] = temp; - } - } - } - } + int j; + + for ( int i = 0 ; i < numStages ; i = j ) { + // find the next bump map + for ( j = i + 1 ; j < numStages ; j++ ) { + if ( pd->parseStages[j].lighting == SL_BUMP ) { + // if the very first stage wasn't a bumpmap, + // this bumpmap is part of the first group + if ( pd->parseStages[i].lighting != SL_BUMP ) { + continue; + } + break; + } + } + + // bubble sort everything bump / diffuse / specular + for ( int l = 1 ; l < j - i ; l++ ) { + for ( int k = i ; k < j - l ; k++ ) { + if ( pd->parseStages[k].lighting > pd->parseStages[k + 1].lighting ) { + shaderStage_t temp = pd->parseStages[k]; + pd->parseStages[k] = pd->parseStages[k + 1]; + pd->parseStages[k + 1] = temp; + } + } + } + } } /* @@ -1790,323 +1894,318 @@ If there is any error during parsing, defaultShader will be set. ================= */ void idMaterial::ParseMaterial( idLexer &src ) { - idToken token; - char buffer[1024]; - const char *str; - idLexer newSrc; - int i; - - numOps = 0; - numRegisters = EXP_REG_NUM_PREDEFINED; // leave space for the parms to be copied in - for ( i = 0 ; i < numRegisters ; i++ ) { - pd->registerIsTemporary[i] = true; // they aren't constants that can be folded - } - - numStages = 0; - - textureRepeat_t trpDefault = TR_REPEAT; // allow a global setting for repeat - - while ( 1 ) { - if ( TestMaterialFlag( MF_DEFAULTED ) ) { // we have a parse error - return; - } - if ( !src.ExpectAnyToken( &token ) ) { - SetMaterialFlag( MF_DEFAULTED ); - return; - } - - // end of material definition - if ( token == "}" ) { - break; - } - else if ( !token.Icmp( "qer_editorimage") ) { - src.ReadTokenOnLine( &token ); - editorImageName = token.c_str(); - src.SkipRestOfLine(); - continue; - } - // description - else if ( !token.Icmp( "description") ) { - src.ReadTokenOnLine( &token ); - desc = token.c_str(); - continue; - } - // check for the surface / content bit flags - else if ( CheckSurfaceParm( &token ) ) { - continue; - } - - - // polygonOffset - else if ( !token.Icmp( "polygonOffset" ) ) { - SetMaterialFlag( MF_POLYGONOFFSET ); - if ( !src.ReadTokenOnLine( &token ) ) { - polygonOffset = 1; - continue; - } - // explict larger (or negative) offset - polygonOffset = token.GetFloatValue(); - continue; - } - // noshadow - else if ( !token.Icmp( "noShadows" ) ) { - SetMaterialFlag( MF_NOSHADOWS ); - continue; - } - else if ( !token.Icmp( "suppressInSubview" ) ) { - suppressInSubview = true; - continue; - } - else if ( !token.Icmp( "portalSky" ) ) { - portalSky = true; - continue; - } - // noSelfShadow - else if ( !token.Icmp( "noSelfShadow" ) ) { - SetMaterialFlag( MF_NOSELFSHADOW ); - continue; - } - // noPortalFog - else if ( !token.Icmp( "noPortalFog" ) ) { - SetMaterialFlag( MF_NOPORTALFOG ); - continue; - } - // forceShadows allows nodraw surfaces to cast shadows - else if ( !token.Icmp( "forceShadows" ) ) { - SetMaterialFlag( MF_FORCESHADOWS ); - continue; - } - // overlay / decal suppression - else if ( !token.Icmp( "noOverlays" ) ) { - allowOverlays = false; - continue; - } - // moster blood overlay forcing for alpha tested or translucent surfaces - else if ( !token.Icmp( "forceOverlays" ) ) { - pd->forceOverlays = true; - continue; - } - // translucent - else if ( !token.Icmp( "translucent" ) ) { - coverage = MC_TRANSLUCENT; - continue; - } - // global zero clamp - else if ( !token.Icmp( "zeroclamp" ) ) { - trpDefault = TR_CLAMP_TO_ZERO; - continue; - } - // global clamp - else if ( !token.Icmp( "clamp" ) ) { - trpDefault = TR_CLAMP; - continue; - } - // global clamp - else if ( !token.Icmp( "alphazeroclamp" ) ) { - trpDefault = TR_CLAMP_TO_ZERO; - continue; - } - // forceOpaque is used for skies-behind-windows - else if ( !token.Icmp( "forceOpaque" ) ) { - coverage = MC_OPAQUE; - continue; - } - // twoSided - else if ( !token.Icmp( "twoSided" ) ) { - cullType = CT_TWO_SIDED; - // twoSided implies no-shadows, because the shadow - // volume would be coplanar with the surface, giving depth fighting - // we could make this no-self-shadows, but it may be more important - // to receive shadows from no-self-shadow monsters - SetMaterialFlag( MF_NOSHADOWS ); - } - // backSided - else if ( !token.Icmp( "backSided" ) ) { - cullType = CT_BACK_SIDED; - // the shadow code doesn't handle this, so just disable shadows. - // We could fix this in the future if there was a need. - SetMaterialFlag( MF_NOSHADOWS ); - } - // foglight - else if ( !token.Icmp( "fogLight" ) ) { - fogLight = true; - continue; - } - // blendlight - else if ( !token.Icmp( "blendLight" ) ) { - blendLight = true; - continue; - } - // ambientLight - else if ( !token.Icmp( "ambientLight" ) ) { - ambientLight = true; - continue; - } - // mirror - else if ( !token.Icmp( "mirror" ) ) { - sort = SS_SUBVIEW; - coverage = MC_OPAQUE; - continue; - } - // noFog - else if ( !token.Icmp( "noFog" ) ) { - noFog = true; - continue; - } - // unsmoothedTangents - else if ( !token.Icmp( "unsmoothedTangents" ) ) { - unsmoothedTangents = true; - continue; - } - // lightFallofImage - // specifies the image to use for the third axis of projected - // light volumes - else if ( !token.Icmp( "lightFalloffImage" ) ) { - str = R_ParsePastImageProgram( src ); - idStr copy; - - copy = str; // so other things don't step on it - lightFalloffImage = globalImages->ImageFromFile( copy, TF_DEFAULT, false, TR_CLAMP /* TR_CLAMP_TO_ZERO */, TD_DEFAULT ); - continue; - } - // guisurf | guisurf entity - // an entity guisurf must have an idUserInterface - // specified in the renderEntity - else if ( !token.Icmp( "guisurf" ) ) { - src.ReadTokenOnLine( &token ); - if ( !token.Icmp( "entity" ) ) { - entityGui = 1; - } else if ( !token.Icmp( "entity2" ) ) { - entityGui = 2; - } else if ( !token.Icmp( "entity3" ) ) { - entityGui = 3; - } else { - gui = uiManager->FindGui( token.c_str(), true ); - } - continue; - } - // sort - else if ( !token.Icmp( "sort" ) ) { - ParseSort( src ); - continue; - } - // spectrum - else if ( !token.Icmp( "spectrum" ) ) { - src.ReadTokenOnLine( &token ); - spectrum = atoi( token.c_str() ); - continue; - } - // deform < sprite | tube | flare > - else if ( !token.Icmp( "deform" ) ) { - ParseDeform( src ); - continue; - } - // decalInfo ( ) ( ) - else if ( !token.Icmp( "decalInfo" ) ) { - ParseDecalInfo( src ); - continue; - } - // renderbump - else if ( !token.Icmp( "renderbump") ) { - src.ParseRestOfLine( renderBump ); - continue; - } - // diffusemap for stage shortcut - else if ( !token.Icmp( "diffusemap" ) ) { - str = R_ParsePastImageProgram( src ); - idStr::snPrintf( buffer, sizeof( buffer ), "blend diffusemap\nmap %s\n}\n", str ); - newSrc.LoadMemory( buffer, strlen(buffer), "diffusemap" ); - newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ); - ParseStage( newSrc, trpDefault ); - newSrc.FreeSource(); - continue; - } - // specularmap for stage shortcut - else if ( !token.Icmp( "specularmap" ) ) { - str = R_ParsePastImageProgram( src ); - idStr::snPrintf( buffer, sizeof( buffer ), "blend specularmap\nmap %s\n}\n", str ); - newSrc.LoadMemory( buffer, strlen(buffer), "specularmap" ); - newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ); - ParseStage( newSrc, trpDefault ); - newSrc.FreeSource(); - continue; - } - // normalmap for stage shortcut - else if ( !token.Icmp( "bumpmap" ) ) { - str = R_ParsePastImageProgram( src ); - idStr::snPrintf( buffer, sizeof( buffer ), "blend bumpmap\nmap %s\n}\n", str ); - newSrc.LoadMemory( buffer, strlen(buffer), "bumpmap" ); - newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ); - ParseStage( newSrc, trpDefault ); - newSrc.FreeSource(); - continue; - } - // DECAL_MACRO for backwards compatibility with the preprocessor macros - else if ( !token.Icmp( "DECAL_MACRO" ) ) { - // polygonOffset - SetMaterialFlag( MF_POLYGONOFFSET ); - polygonOffset = 1; - - // discrete - surfaceFlags |= SURF_DISCRETE; - contentFlags &= ~CONTENTS_SOLID; - - // sort decal - sort = SS_DECAL; - - // noShadows - SetMaterialFlag( MF_NOSHADOWS ); - continue; - } - else if ( token == "{" ) { - // create the new stage - ParseStage( src, trpDefault ); - continue; - } - else { - common->Warning( "unknown general material parameter '%s' in '%s'", token.c_str(), GetName() ); - SetMaterialFlag( MF_DEFAULTED ); - return; - } - } - - // add _flat or _white stages if needed - AddImplicitStages(); - - // order the diffuse / bump / specular stages properly - SortInteractionStages(); - - // if we need to do anything with normals (lighting or environment mapping) - // and two sided lighting was asked for, flag - // shouldCreateBackSides() and change culling back to single sided, - // so we get proper tangent vectors on both sides - - // we can't just call ReceivesLighting(), because the stages are still - // in temporary form - if ( cullType == CT_TWO_SIDED ) { - for ( i = 0 ; i < numStages ; i++ ) { - if ( pd->parseStages[i].lighting != SL_AMBIENT || pd->parseStages[i].texture.texgen != TG_EXPLICIT ) { - if ( cullType == CT_TWO_SIDED ) { - cullType = CT_FRONT_SIDED; - shouldCreateBackSides = true; - } - break; - } - } - } - - // currently a surface can only have one unique texgen for all the stages on old hardware - texgen_t firstGen = TG_EXPLICIT; - for ( i = 0; i < numStages; i++ ) { - if ( pd->parseStages[i].texture.texgen != TG_EXPLICIT ) { - if ( firstGen == TG_EXPLICIT ) { - firstGen = pd->parseStages[i].texture.texgen; - } else if ( firstGen != pd->parseStages[i].texture.texgen ) { - common->Warning( "material '%s' has multiple stages with a texgen", GetName() ); - break; - } - } - } + idToken token; + char buffer[1024]; + const char *str; + idLexer newSrc; + int i; + + numOps = 0; + numRegisters = EXP_REG_NUM_PREDEFINED; // leave space for the parms to be copied in + + for ( i = 0 ; i < numRegisters ; i++ ) { + pd->registerIsTemporary[i] = true; // they aren't constants that can be folded + } + + numStages = 0; + + textureRepeat_t trpDefault = TR_REPEAT; // allow a global setting for repeat + + while ( 1 ) { + if ( TestMaterialFlag( MF_DEFAULTED ) ) { // we have a parse error + return; + } + + if ( !src.ExpectAnyToken( &token ) ) { + SetMaterialFlag( MF_DEFAULTED ); + return; + } + + // end of material definition + if ( token == "}" ) { + break; + } else if ( !token.Icmp( "qer_editorimage" ) ) { + src.ReadTokenOnLine( &token ); + editorImageName = token.c_str(); + src.SkipRestOfLine(); + continue; + } + // description + else if ( !token.Icmp( "description" ) ) { + src.ReadTokenOnLine( &token ); + desc = token.c_str(); + continue; + } + // check for the surface / content bit flags + else if ( CheckSurfaceParm( &token ) ) { + continue; + } + // polygonOffset + else if ( !token.Icmp( "polygonOffset" ) ) { + SetMaterialFlag( MF_POLYGONOFFSET ); + if ( !src.ReadTokenOnLine( &token ) ) { + polygonOffset = 1; + continue; + } + // explict larger (or negative) offset + polygonOffset = token.GetFloatValue(); + continue; + } + // noshadow + else if ( !token.Icmp( "noShadows" ) ) { + SetMaterialFlag( MF_NOSHADOWS ); + continue; + } else if ( !token.Icmp( "suppressInSubview" ) ) { + suppressInSubview = true; + continue; + } else if ( !token.Icmp( "portalSky" ) ) { + portalSky = true; + continue; + } + // noSelfShadow + else if ( !token.Icmp( "noSelfShadow" ) ) { + SetMaterialFlag( MF_NOSELFSHADOW ); + continue; + } + // noPortalFog + else if ( !token.Icmp( "noPortalFog" ) ) { + SetMaterialFlag( MF_NOPORTALFOG ); + continue; + } + // forceShadows allows nodraw surfaces to cast shadows + else if ( !token.Icmp( "forceShadows" ) ) { + SetMaterialFlag( MF_FORCESHADOWS ); + continue; + } + // overlay / decal suppression + else if ( !token.Icmp( "noOverlays" ) ) { + allowOverlays = false; + continue; + } + // moster blood overlay forcing for alpha tested or translucent surfaces + else if ( !token.Icmp( "forceOverlays" ) ) { + pd->forceOverlays = true; + continue; + } + // translucent + else if ( !token.Icmp( "translucent" ) ) { + coverage = MC_TRANSLUCENT; + continue; + } + // global zero clamp + else if ( !token.Icmp( "zeroclamp" ) ) { + trpDefault = TR_CLAMP_TO_ZERO; + continue; + } + // global clamp + else if ( !token.Icmp( "clamp" ) ) { + trpDefault = TR_CLAMP; + continue; + } + // global clamp + else if ( !token.Icmp( "alphazeroclamp" ) ) { + trpDefault = TR_CLAMP_TO_ZERO; + continue; + } + // forceOpaque is used for skies-behind-windows + else if ( !token.Icmp( "forceOpaque" ) ) { + coverage = MC_OPAQUE; + continue; + } + // twoSided + else if ( !token.Icmp( "twoSided" ) ) { + cullType = CT_TWO_SIDED; + // twoSided implies no-shadows, because the shadow + // volume would be coplanar with the surface, giving depth fighting + // we could make this no-self-shadows, but it may be more important + // to receive shadows from no-self-shadow monsters + SetMaterialFlag( MF_NOSHADOWS ); + } + // backSided + else if ( !token.Icmp( "backSided" ) ) { + cullType = CT_BACK_SIDED; + // the shadow code doesn't handle this, so just disable shadows. + // We could fix this in the future if there was a need. + SetMaterialFlag( MF_NOSHADOWS ); + } + // foglight + else if ( !token.Icmp( "fogLight" ) ) { + fogLight = true; + continue; + } + // blendlight + else if ( !token.Icmp( "blendLight" ) ) { + blendLight = true; + continue; + } + // ambientLight + else if ( !token.Icmp( "ambientLight" ) ) { + ambientLight = true; + continue; + } + // mirror + else if ( !token.Icmp( "mirror" ) ) { + sort = SS_SUBVIEW; + coverage = MC_OPAQUE; + continue; + } + // noFog + else if ( !token.Icmp( "noFog" ) ) { + noFog = true; + continue; + } + // unsmoothedTangents + else if ( !token.Icmp( "unsmoothedTangents" ) ) { + unsmoothedTangents = true; + continue; + } + // lightFallofImage + // specifies the image to use for the third axis of projected + // light volumes + else if ( !token.Icmp( "lightFalloffImage" ) ) { + str = R_ParsePastImageProgram( src ); + idStr copy; + + copy = str; // so other things don't step on it + lightFalloffImage = globalImages->ImageFromFile( copy, TF_DEFAULT, false, TR_CLAMP /* TR_CLAMP_TO_ZERO */, TD_DEFAULT ); + continue; + } + // guisurf | guisurf entity + // an entity guisurf must have an idUserInterface + // specified in the renderEntity + else if ( !token.Icmp( "guisurf" ) ) { + src.ReadTokenOnLine( &token ); + if ( !token.Icmp( "entity" ) ) { + entityGui = 1; + } else if ( !token.Icmp( "entity2" ) ) { + entityGui = 2; + } else if ( !token.Icmp( "entity3" ) ) { + entityGui = 3; + } else { + gui = uiManager->FindGui( token.c_str(), true ); + } + continue; + } + // sort + else if ( !token.Icmp( "sort" ) ) { + ParseSort( src ); + continue; + } + // spectrum + else if ( !token.Icmp( "spectrum" ) ) { + src.ReadTokenOnLine( &token ); + spectrum = atoi( token.c_str() ); + continue; + } + // deform < sprite | tube | flare > + else if ( !token.Icmp( "deform" ) ) { + ParseDeform( src ); + continue; + } + // decalInfo ( ) ( ) + else if ( !token.Icmp( "decalInfo" ) ) { + ParseDecalInfo( src ); + continue; + } + // renderbump + else if ( !token.Icmp( "renderbump" ) ) { + src.ParseRestOfLine( renderBump ); + continue; + } + // diffusemap for stage shortcut + else if ( !token.Icmp( "diffusemap" ) ) { + str = R_ParsePastImageProgram( src ); + idStr::snPrintf( buffer, sizeof( buffer ), "blend diffusemap\nmap %s\n}\n", str ); + newSrc.LoadMemory( buffer, strlen( buffer ), "diffusemap" ); + newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ); + ParseStage( newSrc, trpDefault ); + newSrc.FreeSource(); + continue; + } + // specularmap for stage shortcut + else if ( !token.Icmp( "specularmap" ) ) { + str = R_ParsePastImageProgram( src ); + idStr::snPrintf( buffer, sizeof( buffer ), "blend specularmap\nmap %s\n}\n", str ); + newSrc.LoadMemory( buffer, strlen( buffer ), "specularmap" ); + newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ); + ParseStage( newSrc, trpDefault ); + newSrc.FreeSource(); + continue; + } + // normalmap for stage shortcut + else if ( !token.Icmp( "bumpmap" ) ) { + str = R_ParsePastImageProgram( src ); + idStr::snPrintf( buffer, sizeof( buffer ), "blend bumpmap\nmap %s\n}\n", str ); + newSrc.LoadMemory( buffer, strlen( buffer ), "bumpmap" ); + newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ); + ParseStage( newSrc, trpDefault ); + newSrc.FreeSource(); + continue; + } + // DECAL_MACRO for backwards compatibility with the preprocessor macros + else if ( !token.Icmp( "DECAL_MACRO" ) ) { + // polygonOffset + SetMaterialFlag( MF_POLYGONOFFSET ); + polygonOffset = 1; + + // discrete + surfaceFlags |= SURF_DISCRETE; + contentFlags &= ~CONTENTS_SOLID; + + // sort decal + sort = SS_DECAL; + + // noShadows + SetMaterialFlag( MF_NOSHADOWS ); + continue; + } else if ( token == "{" ) { + // create the new stage + ParseStage( src, trpDefault ); + continue; + } else { + common->Warning( "unknown general material parameter '%s' in '%s'", token.c_str(), GetName() ); + SetMaterialFlag( MF_DEFAULTED ); + return; + } + } + + // add _flat or _white stages if needed + AddImplicitStages(); + + // order the diffuse / bump / specular stages properly + SortInteractionStages(); + + // if we need to do anything with normals (lighting or environment mapping) + // and two sided lighting was asked for, flag + // shouldCreateBackSides() and change culling back to single sided, + // so we get proper tangent vectors on both sides + + // we can't just call ReceivesLighting(), because the stages are still + // in temporary form + if ( cullType == CT_TWO_SIDED ) { + for ( i = 0 ; i < numStages ; i++ ) { + if ( pd->parseStages[i].lighting != SL_AMBIENT || pd->parseStages[i].texture.texgen != TG_EXPLICIT ) { + if ( cullType == CT_TWO_SIDED ) { + cullType = CT_FRONT_SIDED; + shouldCreateBackSides = true; + } + break; + } + } + } + + // currently a surface can only have one unique texgen for all the stages on old hardware + texgen_t firstGen = TG_EXPLICIT; + for ( i = 0; i < numStages; i++ ) { + if ( pd->parseStages[i].texture.texgen != TG_EXPLICIT ) { + if ( firstGen == TG_EXPLICIT ) { + firstGen = pd->parseStages[i].texture.texgen; + } else if ( firstGen != pd->parseStages[i].texture.texgen ) { + common->Warning( "material '%s' has multiple stages with a texgen", GetName() ); + break; + } + } + } } /* @@ -2115,7 +2214,7 @@ idMaterial::SetGui ========================= */ void idMaterial::SetGui( const char *_gui ) const { - gui = uiManager->FindGui( _gui, true, false, true ); + gui = uiManager->FindGui( _gui, true, false, true ); } /* @@ -2126,204 +2225,205 @@ Parses the current material definition and finds all necessary images. ========================= */ bool idMaterial::Parse( const char *text, const int textLength ) { - idLexer src; - idToken token; - mtrParsingData_t parsingData; - - src.LoadMemory( text, textLength, GetFileName(), GetLineNum() ); - src.SetFlags( DECL_LEXER_FLAGS ); - src.SkipUntilString( "{" ); - - // reset to the unparsed state - CommonInit(); - - memset( &parsingData, 0, sizeof( parsingData ) ); - - pd = &parsingData; // this is only valid during parse - - // parse it - ParseMaterial( src ); - - // if we are doing an fs_copyfiles, also reference the editorImage - if ( cvarSystem->GetCVarInteger( "fs_copyFiles" ) ) { - GetEditorImage(); - } - - // - // count non-lit stages - numAmbientStages = 0; - int i; - for ( i = 0 ; i < numStages ; i++ ) { - if ( pd->parseStages[i].lighting == SL_AMBIENT ) { - numAmbientStages++; - } - } - - // see if there is a subview stage - if ( sort == SS_SUBVIEW ) { - hasSubview = true; - } else { - hasSubview = false; - for ( i = 0 ; i < numStages ; i++ ) { - if ( pd->parseStages[i].texture.dynamic ) { - hasSubview = true; - } - } - } - - // automatically determine coverage if not explicitly set - if ( coverage == MC_BAD ) { - // automatically set MC_TRANSLUCENT if we don't have any interaction stages and - // the first stage is blended and not an alpha test mask or a subview - if ( !numStages ) { - // non-visible - coverage = MC_TRANSLUCENT; - } else if ( numStages != numAmbientStages ) { - // we have an interaction draw - coverage = MC_OPAQUE; - } else if ( - ( pd->parseStages[0].drawStateBits & GLS_DSTBLEND_BITS ) != GLS_DSTBLEND_ZERO || - ( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_DST_COLOR || - ( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_ONE_MINUS_DST_COLOR || - ( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_DST_ALPHA || - ( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_ONE_MINUS_DST_ALPHA - ) { - // blended with the destination - coverage = MC_TRANSLUCENT; - } else { - coverage = MC_OPAQUE; - } - } - - // translucent automatically implies noshadows - if ( coverage == MC_TRANSLUCENT ) { - SetMaterialFlag( MF_NOSHADOWS ); - } else { - // mark the contents as opaque - contentFlags |= CONTENTS_OPAQUE; - } - - // if we are translucent, draw with an alpha in the editor - if ( coverage == MC_TRANSLUCENT ) { - editorAlpha = 0.5; - } else { - editorAlpha = 1.0; - } - - // the sorts can make reasonable defaults - if ( sort == SS_BAD ) { - if ( TestMaterialFlag(MF_POLYGONOFFSET) ) { - sort = SS_DECAL; - } else if ( coverage == MC_TRANSLUCENT ) { - sort = SS_MEDIUM; - } else { - sort = SS_OPAQUE; - } - } - - // anything that references _currentRender will automatically get sort = SS_POST_PROCESS - // and coverage = MC_TRANSLUCENT - - for ( i = 0 ; i < numStages ; i++ ) { - shaderStage_t *pStage = &pd->parseStages[i]; - if ( pStage->texture.image == globalImages->currentRenderImage ) { - if ( sort != SS_PORTAL_SKY ) { - sort = SS_POST_PROCESS; - coverage = MC_TRANSLUCENT; - } - break; - } - if ( pStage->newStage ) { - for ( int j = 0 ; j < pStage->newStage->numFragmentProgramImages ; j++ ) { - if ( pStage->newStage->fragmentProgramImages[j] == globalImages->currentRenderImage ) { - if ( sort != SS_PORTAL_SKY ) { - sort = SS_POST_PROCESS; - coverage = MC_TRANSLUCENT; - } - i = numStages; - break; - } - } - } - } - - // set the drawStateBits depth flags - for ( i = 0 ; i < numStages ; i++ ) { - shaderStage_t *pStage = &pd->parseStages[i]; - if ( sort == SS_POST_PROCESS ) { - // post-process effects fill the depth buffer as they draw, so only the - // topmost post-process effect is rendered - pStage->drawStateBits |= GLS_DEPTHFUNC_LESS; - } else if ( coverage == MC_TRANSLUCENT || pStage->ignoreAlphaTest ) { - // translucent surfaces can extend past the exactly marked depth buffer - pStage->drawStateBits |= GLS_DEPTHFUNC_LESS | GLS_DEPTHMASK; - } else { - // opaque and perforated surfaces must exactly match the depth buffer, - // which gets alpha test correct - pStage->drawStateBits |= GLS_DEPTHFUNC_EQUAL | GLS_DEPTHMASK; - } - } - - // determine if this surface will accept overlays / decals - - if ( pd->forceOverlays ) { - // explicitly flaged in material definition - allowOverlays = true; - } else { - if ( !IsDrawn() ) { - allowOverlays = false; - } - if ( Coverage() != MC_OPAQUE ) { - allowOverlays = false; - } - if ( GetSurfaceFlags() & SURF_NOIMPACT ) { - allowOverlays = false; - } - } - - // add a tiny offset to the sort orders, so that different materials - // that have the same sort value will at least sort consistantly, instead - // of flickering back and forth -/* this messed up in-game guis - if ( sort != SS_SUBVIEW ) { - int hash, l; - - l = name.Length(); - hash = 0; - for ( int i = 0 ; i < l ; i++ ) { - hash ^= name[i]; - } - sort += hash * 0.01; - } -*/ - - if (numStages) { - stages = (shaderStage_t *)R_StaticAlloc( numStages * sizeof( stages[0] ) ); - memcpy( stages, pd->parseStages, numStages * sizeof( stages[0] ) ); - } - - if ( numOps ) { - ops = (expOp_t *)R_StaticAlloc( numOps * sizeof( ops[0] ) ); - memcpy( ops, pd->shaderOps, numOps * sizeof( ops[0] ) ); - } - - if ( numRegisters ) { - expressionRegisters = (float *)R_StaticAlloc( numRegisters * sizeof( expressionRegisters[0] ) ); - memcpy( expressionRegisters, pd->shaderRegisters, numRegisters * sizeof( expressionRegisters[0] ) ); - } - - // see if the registers are completely constant, and don't need to be evaluated - // per-surface - CheckForConstantRegisters(); - - pd = NULL; // the pointer will be invalid after exiting this function - - // finish things up - if ( TestMaterialFlag( MF_DEFAULTED ) ) { - MakeDefault(); - return false; - } - return true; + idLexer src; + idToken token; + mtrParsingData_t parsingData; + + src.LoadMemory( text, textLength, GetFileName(), GetLineNum() ); + src.SetFlags( DECL_LEXER_FLAGS ); + src.SkipUntilString( "{" ); + + // reset to the unparsed state + CommonInit(); + + memset( &parsingData, 0, sizeof( parsingData ) ); + + pd = &parsingData; // this is only valid during parse + + // parse it + ParseMaterial( src ); + + // if we are doing an fs_copyfiles, also reference the editorImage + if ( cvarSystem->GetCVarInteger( "fs_copyFiles" ) ) { + GetEditorImage(); + } + int i; + + // + // count non-lit stages + numAmbientStages = 0; + + for ( i = 0 ; i < numStages ; i++ ) { + if ( pd->parseStages[i].lighting == SL_AMBIENT ) { + numAmbientStages++; + } + } + + // see if there is a subview stage + if ( sort == SS_SUBVIEW ) { + hasSubview = true; + } else { + hasSubview = false; + for ( i = 0 ; i < numStages ; i++ ) { + if ( pd->parseStages[i].texture.dynamic ) { + hasSubview = true; + } + } + } + + // automatically determine coverage if not explicitly set + if ( coverage == MC_BAD ) { + // automatically set MC_TRANSLUCENT if we don't have any interaction stages and + // the first stage is blended and not an alpha test mask or a subview + if ( !numStages ) { + // non-visible + coverage = MC_TRANSLUCENT; + } else if ( numStages != numAmbientStages ) { + // we have an interaction draw + coverage = MC_OPAQUE; + } else if ( + ( pd->parseStages[0].drawStateBits & GLS_DSTBLEND_BITS ) != GLS_DSTBLEND_ZERO || + ( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_DST_COLOR || + ( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_ONE_MINUS_DST_COLOR || + ( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_DST_ALPHA || + ( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_ONE_MINUS_DST_ALPHA + ) { + // blended with the destination + coverage = MC_TRANSLUCENT; + } else { + coverage = MC_OPAQUE; + } + } + + // translucent automatically implies noshadows + if ( coverage == MC_TRANSLUCENT ) { + SetMaterialFlag( MF_NOSHADOWS ); + } else { + // mark the contents as opaque + contentFlags |= CONTENTS_OPAQUE; + } + + // if we are translucent, draw with an alpha in the editor + if ( coverage == MC_TRANSLUCENT ) { + editorAlpha = 0.5; + } else { + editorAlpha = 1.0; + } + + // the sorts can make reasonable defaults + if ( sort == SS_BAD ) { + if ( TestMaterialFlag( MF_POLYGONOFFSET ) ) { + sort = SS_DECAL; + } else if ( coverage == MC_TRANSLUCENT ) { + sort = SS_MEDIUM; + } else { + sort = SS_OPAQUE; + } + } + + // anything that references _currentRender will automatically get sort = SS_POST_PROCESS + // and coverage = MC_TRANSLUCENT + for ( i = 0 ; i < numStages ; i++ ) { + shaderStage_t *pStage = &pd->parseStages[i]; + if ( pStage->texture.image == globalImages->currentRenderImage ) { + if ( sort != SS_PORTAL_SKY ) { + sort = SS_POST_PROCESS; + coverage = MC_TRANSLUCENT; + } + break; + } + + if ( pStage->newStage ) { + for ( int j = 0 ; j < pStage->newStage->numFragmentProgramImages ; j++ ) { + if ( pStage->newStage->fragmentProgramImages[j] == globalImages->currentRenderImage ) { + if ( sort != SS_PORTAL_SKY ) { + sort = SS_POST_PROCESS; + coverage = MC_TRANSLUCENT; + } + i = numStages; + break; + } + } + } + } + + // set the drawStateBits depth flags + for ( i = 0 ; i < numStages ; i++ ) { + shaderStage_t *pStage = &pd->parseStages[i]; + + if ( sort == SS_POST_PROCESS ) { + // post-process effects fill the depth buffer as they draw, so only the + // topmost post-process effect is rendered + pStage->drawStateBits |= GLS_DEPTHFUNC_LESS; + } else if ( coverage == MC_TRANSLUCENT || pStage->ignoreAlphaTest ) { + // translucent surfaces can extend past the exactly marked depth buffer + pStage->drawStateBits |= GLS_DEPTHFUNC_LESS | GLS_DEPTHMASK; + } else { + // opaque and perforated surfaces must exactly match the depth buffer, + // which gets alpha test correct + pStage->drawStateBits |= GLS_DEPTHFUNC_EQUAL | GLS_DEPTHMASK; + } + } + + // determine if this surface will accept overlays / decals + if ( pd->forceOverlays ) { + // explicitly flaged in material definition + allowOverlays = true; + } else { + if ( !IsDrawn() ) { + allowOverlays = false; + } + if ( Coverage() != MC_OPAQUE ) { + allowOverlays = false; + } + if ( GetSurfaceFlags() & SURF_NOIMPACT ) { + allowOverlays = false; + } + } + + // add a tiny offset to the sort orders, so that different materials + // that have the same sort value will at least sort consistantly, instead + // of flickering back and forth + /* this messed up in-game guis + if ( sort != SS_SUBVIEW ) { + int hash, l; + + l = name.Length(); + hash = 0; + for ( int i = 0 ; i < l ; i++ ) { + hash ^= name[i]; + } + sort += hash * 0.01; + } + */ + + if ( numStages ) { + stages = ( shaderStage_t * )R_StaticAlloc( numStages * sizeof( stages[0] ) ); + memcpy( stages, pd->parseStages, numStages * sizeof( stages[0] ) ); + } + + if ( numOps ) { + ops = ( expOp_t * )R_StaticAlloc( numOps * sizeof( ops[0] ) ); + memcpy( ops, pd->shaderOps, numOps * sizeof( ops[0] ) ); + } + + if ( numRegisters ) { + expressionRegisters = ( float * )R_StaticAlloc( numRegisters * sizeof( expressionRegisters[0] ) ); + memcpy( expressionRegisters, pd->shaderRegisters, numRegisters * sizeof( expressionRegisters[0] ) ); + } + + // see if the registers are completely constant, and don't need to be evaluated + // per-surface + CheckForConstantRegisters(); + + pd = NULL; // the pointer will be invalid after exiting this function + + // finish things up + if ( TestMaterialFlag( MF_DEFAULTED ) ) { + MakeDefault(); + return false; + } + return true; } /* @@ -2332,37 +2432,38 @@ idMaterial::Print =================== */ static const char *opNames[] = { - "OP_TYPE_ADD", - "OP_TYPE_SUBTRACT", - "OP_TYPE_MULTIPLY", - "OP_TYPE_DIVIDE", - "OP_TYPE_MOD", - "OP_TYPE_TABLE", - "OP_TYPE_GT", - "OP_TYPE_GE", - "OP_TYPE_LT", - "OP_TYPE_LE", - "OP_TYPE_EQ", - "OP_TYPE_NE", - "OP_TYPE_AND", - "OP_TYPE_OR" + "OP_TYPE_ADD", + "OP_TYPE_SUBTRACT", + "OP_TYPE_MULTIPLY", + "OP_TYPE_DIVIDE", + "OP_TYPE_MOD", + "OP_TYPE_TABLE", + "OP_TYPE_GT", + "OP_TYPE_GE", + "OP_TYPE_LT", + "OP_TYPE_LE", + "OP_TYPE_EQ", + "OP_TYPE_NE", + "OP_TYPE_AND", + "OP_TYPE_OR" }; void idMaterial::Print() const { - int i; - - for ( i = EXP_REG_NUM_PREDEFINED ; i < GetNumRegisters() ; i++ ) { - common->Printf( "register %i: %f\n", i, expressionRegisters[i] ); - } - common->Printf( "\n" ); - for ( i = 0 ; i < numOps ; i++ ) { - const expOp_t *op = &ops[i]; - if ( op->opType == OP_TYPE_TABLE ) { - common->Printf( "%i = %s[ %i ]\n", op->c, declManager->DeclByIndex( DECL_TABLE, op->a )->GetName(), op->b ); - } else { - common->Printf( "%i = %i %s %i\n", op->c, op->a, opNames[ op->opType ], op->b ); - } - } + int i; + + for ( i = EXP_REG_NUM_PREDEFINED ; i < GetNumRegisters() ; i++ ) { + common->Printf( "register %i: %f\n", i, expressionRegisters[i] ); + } + common->Printf( "\n" ); + + for ( i = 0 ; i < numOps ; i++ ) { + const expOp_t *op = &ops[i]; + if ( op->opType == OP_TYPE_TABLE ) { + common->Printf( "%i = %s[ %i ]\n", op->c, declManager->DeclByIndex( DECL_TABLE, op->a )->GetName(), op->b ); + } else { + common->Printf( "%i = %i %s %i\n", op->c, op->a, opNames[ op->opType ], op->b ); + } + } } /* @@ -2371,7 +2472,7 @@ idMaterial::Save =============== */ bool idMaterial::Save( const char *fileName ) { - return ReplaceSourceFileText(); + return ReplaceSourceFileText(); } /* @@ -2380,15 +2481,15 @@ idMaterial::AddReference =============== */ void idMaterial::AddReference() { - refCount++; + refCount++; - for ( int i = 0; i < numStages; i++ ) { - shaderStage_t *s = &stages[i]; + for ( int i = 0; i < numStages; i++ ) { + shaderStage_t *s = &stages[i]; - if ( s->texture.image ) { - s->texture.image->AddReference(); - } - } + if ( s->texture.image ) { + s->texture.image->AddReference(); + } + } } /* @@ -2401,100 +2502,99 @@ set to their apropriate values. =============== */ void idMaterial::EvaluateRegisters( float *registers, const float shaderParms[MAX_ENTITY_SHADER_PARMS], - const viewDef_t *view, idSoundEmitter *soundEmitter ) const { - int i, b; - expOp_t *op; - - // copy the material constants - for ( i = EXP_REG_NUM_PREDEFINED ; i < numRegisters ; i++ ) { - registers[i] = expressionRegisters[i]; - } - - // copy the local and global parameters - registers[EXP_REG_TIME] = view->floatTime; - registers[EXP_REG_PARM0] = shaderParms[0]; - registers[EXP_REG_PARM1] = shaderParms[1]; - registers[EXP_REG_PARM2] = shaderParms[2]; - registers[EXP_REG_PARM3] = shaderParms[3]; - registers[EXP_REG_PARM4] = shaderParms[4]; - registers[EXP_REG_PARM5] = shaderParms[5]; - registers[EXP_REG_PARM6] = shaderParms[6]; - registers[EXP_REG_PARM7] = shaderParms[7]; - registers[EXP_REG_PARM8] = shaderParms[8]; - registers[EXP_REG_PARM9] = shaderParms[9]; - registers[EXP_REG_PARM10] = shaderParms[10]; - registers[EXP_REG_PARM11] = shaderParms[11]; - registers[EXP_REG_GLOBAL0] = view->renderView.shaderParms[0]; - registers[EXP_REG_GLOBAL1] = view->renderView.shaderParms[1]; - registers[EXP_REG_GLOBAL2] = view->renderView.shaderParms[2]; - registers[EXP_REG_GLOBAL3] = view->renderView.shaderParms[3]; - registers[EXP_REG_GLOBAL4] = view->renderView.shaderParms[4]; - registers[EXP_REG_GLOBAL5] = view->renderView.shaderParms[5]; - registers[EXP_REG_GLOBAL6] = view->renderView.shaderParms[6]; - registers[EXP_REG_GLOBAL7] = view->renderView.shaderParms[7]; - - op = ops; - for ( i = 0 ; i < numOps ; i++, op++ ) { - switch( op->opType ) { - case OP_TYPE_ADD: - registers[op->c] = registers[op->a] + registers[op->b]; - break; - case OP_TYPE_SUBTRACT: - registers[op->c] = registers[op->a] - registers[op->b]; - break; - case OP_TYPE_MULTIPLY: - registers[op->c] = registers[op->a] * registers[op->b]; - break; - case OP_TYPE_DIVIDE: - registers[op->c] = registers[op->a] / registers[op->b]; - break; - case OP_TYPE_MOD: - b = (int)registers[op->b]; - b = b != 0 ? b : 1; - registers[op->c] = (int)registers[op->a] % b; - break; - case OP_TYPE_TABLE: - { - const idDeclTable *table = static_cast( declManager->DeclByIndex( DECL_TABLE, op->a ) ); - registers[op->c] = table->TableLookup( registers[op->b] ); - } - break; - case OP_TYPE_SOUND: - if ( soundEmitter ) { - registers[op->c] = soundEmitter->CurrentAmplitude(); - } else { - registers[op->c] = 0; - } - break; - case OP_TYPE_GT: - registers[op->c] = registers[ op->a ] > registers[op->b]; - break; - case OP_TYPE_GE: - registers[op->c] = registers[ op->a ] >= registers[op->b]; - break; - case OP_TYPE_LT: - registers[op->c] = registers[ op->a ] < registers[op->b]; - break; - case OP_TYPE_LE: - registers[op->c] = registers[ op->a ] <= registers[op->b]; - break; - case OP_TYPE_EQ: - registers[op->c] = registers[ op->a ] == registers[op->b]; - break; - case OP_TYPE_NE: - registers[op->c] = registers[ op->a ] != registers[op->b]; - break; - case OP_TYPE_AND: - registers[op->c] = registers[ op->a ] && registers[op->b]; - break; - case OP_TYPE_OR: - registers[op->c] = registers[ op->a ] || registers[op->b]; - break; - default: - common->FatalError( "R_EvaluateExpression: bad opcode" ); - } - } - + const viewDef_t *view, idSoundEmitter *soundEmitter ) const { + int i, b; + expOp_t *op; + + // copy the material constants + for ( i = EXP_REG_NUM_PREDEFINED ; i < numRegisters ; i++ ) { + registers[i] = expressionRegisters[i]; + } + + // copy the local and global parameters + registers[EXP_REG_TIME] = view->floatTime; + registers[EXP_REG_PARM0] = shaderParms[0]; + registers[EXP_REG_PARM1] = shaderParms[1]; + registers[EXP_REG_PARM2] = shaderParms[2]; + registers[EXP_REG_PARM3] = shaderParms[3]; + registers[EXP_REG_PARM4] = shaderParms[4]; + registers[EXP_REG_PARM5] = shaderParms[5]; + registers[EXP_REG_PARM6] = shaderParms[6]; + registers[EXP_REG_PARM7] = shaderParms[7]; + registers[EXP_REG_PARM8] = shaderParms[8]; + registers[EXP_REG_PARM9] = shaderParms[9]; + registers[EXP_REG_PARM10] = shaderParms[10]; + registers[EXP_REG_PARM11] = shaderParms[11]; + registers[EXP_REG_GLOBAL0] = view->renderView.shaderParms[0]; + registers[EXP_REG_GLOBAL1] = view->renderView.shaderParms[1]; + registers[EXP_REG_GLOBAL2] = view->renderView.shaderParms[2]; + registers[EXP_REG_GLOBAL3] = view->renderView.shaderParms[3]; + registers[EXP_REG_GLOBAL4] = view->renderView.shaderParms[4]; + registers[EXP_REG_GLOBAL5] = view->renderView.shaderParms[5]; + registers[EXP_REG_GLOBAL6] = view->renderView.shaderParms[6]; + registers[EXP_REG_GLOBAL7] = view->renderView.shaderParms[7]; + + op = ops; + + for ( i = 0 ; i < numOps ; i++, op++ ) { + switch ( op->opType ) { + case OP_TYPE_ADD: + registers[op->c] = registers[op->a] + registers[op->b]; + break; + case OP_TYPE_SUBTRACT: + registers[op->c] = registers[op->a] - registers[op->b]; + break; + case OP_TYPE_MULTIPLY: + registers[op->c] = registers[op->a] * registers[op->b]; + break; + case OP_TYPE_DIVIDE: + registers[op->c] = registers[op->a] / registers[op->b]; + break; + case OP_TYPE_MOD: + b = ( int )registers[op->b]; + b = b != 0 ? b : 1; + registers[op->c] = ( int )registers[op->a] % b; + break; + case OP_TYPE_TABLE: { + const idDeclTable *table = static_cast( declManager->DeclByIndex( DECL_TABLE, op->a ) ); + registers[op->c] = table->TableLookup( registers[op->b] ); + } + break; + case OP_TYPE_SOUND: + if ( soundEmitter ) { + registers[op->c] = soundEmitter->CurrentAmplitude(); + } else { + registers[op->c] = 0; + } + break; + case OP_TYPE_GT: + registers[op->c] = registers[ op->a ] > registers[op->b]; + break; + case OP_TYPE_GE: + registers[op->c] = registers[ op->a ] >= registers[op->b]; + break; + case OP_TYPE_LT: + registers[op->c] = registers[ op->a ] < registers[op->b]; + break; + case OP_TYPE_LE: + registers[op->c] = registers[ op->a ] <= registers[op->b]; + break; + case OP_TYPE_EQ: + registers[op->c] = registers[ op->a ] == registers[op->b]; + break; + case OP_TYPE_NE: + registers[op->c] = registers[ op->a ] != registers[op->b]; + break; + case OP_TYPE_AND: + registers[op->c] = registers[ op->a ] && registers[op->b]; + break; + case OP_TYPE_OR: + registers[op->c] = registers[ op->a ] || registers[op->b]; + break; + default: + common->FatalError( "R_EvaluateExpression: bad opcode" ); + } + } } /* @@ -2503,15 +2603,14 @@ idMaterial::Texgen ============= */ texgen_t idMaterial::Texgen() const { - if ( stages ) { - for ( int i = 0; i < numStages; i++ ) { - if ( stages[ i ].texture.texgen != TG_EXPLICIT ) { - return stages[ i ].texture.texgen; - } - } - } - - return TG_EXPLICIT; + if ( stages ) { + for ( int i = 0; i < numStages; i++ ) { + if ( stages[ i ].texture.texgen != TG_EXPLICIT ) { + return stages[ i ].texture.texgen; + } + } + } + return TG_EXPLICIT; } /* @@ -2520,8 +2619,8 @@ idMaterial::GetImageWidth ============= */ int idMaterial::GetImageWidth( void ) const { - assert( GetStage(0) && GetStage(0)->texture.image ); - return GetStage(0)->texture.image->uploadWidth; + assert( GetStage( 0 ) && GetStage( 0 )->texture.image ); + return GetStage( 0 )->texture.image->uploadWidth; } /* @@ -2530,8 +2629,8 @@ idMaterial::GetImageHeight ============= */ int idMaterial::GetImageHeight( void ) const { - assert( GetStage(0) && GetStage(0)->texture.image ); - return GetStage(0)->texture.image->uploadHeight; + assert( GetStage( 0 ) && GetStage( 0 )->texture.image ); + return GetStage( 0 )->texture.image->uploadHeight; } /* @@ -2539,11 +2638,11 @@ int idMaterial::GetImageHeight( void ) const { idMaterial::CinematicLength ============= */ -int idMaterial::CinematicLength() const { - if ( !stages || !stages[0].texture.cinematic ) { - return 0; - } - return stages[0].texture.cinematic->AnimationLength(); +int idMaterial::CinematicLength() const { + if ( !stages || !stages[0].texture.cinematic ) { + return 0; + } + return stages[0].texture.cinematic->AnimationLength(); } /* @@ -2552,10 +2651,10 @@ idMaterial::UpdateCinematic ============= */ void idMaterial::UpdateCinematic( int time ) const { - if ( !stages || !stages[0].texture.cinematic || !backEnd.viewDef ) { - return; - } - stages[0].texture.cinematic->ImageForTime( tr.primaryRenderView.time ); + if ( !stages || !stages[0].texture.cinematic || !backEnd.viewDef ) { + return; + } + stages[0].texture.cinematic->ImageForTime( tr.primaryRenderView.time ); } /* @@ -2564,13 +2663,13 @@ idMaterial::CloseCinematic ============= */ void idMaterial::CloseCinematic( void ) const { - for( int i = 0; i < numStages; i++ ) { - if ( stages[i].texture.cinematic ) { - stages[i].texture.cinematic->Close(); - delete stages[i].texture.cinematic; - stages[i].texture.cinematic = NULL; - } - } + for ( int i = 0; i < numStages; i++ ) { + if ( stages[i].texture.cinematic ) { + stages[i].texture.cinematic->Close(); + delete stages[i].texture.cinematic; + stages[i].texture.cinematic = NULL; + } + } } /* @@ -2579,11 +2678,11 @@ idMaterial::ResetCinematicTime ============= */ void idMaterial::ResetCinematicTime( int time ) const { - for( int i = 0; i < numStages; i++ ) { - if ( stages[i].texture.cinematic ) { - stages[i].texture.cinematic->ResetTime( time ); - } - } + for ( int i = 0; i < numStages; i++ ) { + if ( stages[i].texture.cinematic ) { + stages[i].texture.cinematic->ResetTime( time ); + } + } } /* @@ -2592,10 +2691,10 @@ idMaterial::ConstantRegisters ============= */ const float *idMaterial::ConstantRegisters() const { - if ( !r_useConstantMaterials.GetBool() ) { - return NULL; - } - return constantRegisters; + if ( !r_useConstantMaterials.GetBool() ) { + return NULL; + } + return constantRegisters; } /* @@ -2608,19 +2707,19 @@ This is probably an optimization of dubious value. ================== */ void idMaterial::CheckForConstantRegisters() { - if ( !pd->registersAreConstant ) { - return; - } + if ( !pd->registersAreConstant ) { + return; + } - // evaluate the registers once, and save them - constantRegisters = (float *)R_ClearedStaticAlloc( GetNumRegisters() * sizeof( float ) ); + // evaluate the registers once, and save them + constantRegisters = ( float * )R_ClearedStaticAlloc( GetNumRegisters() * sizeof( float ) ); - float shaderParms[MAX_ENTITY_SHADER_PARMS]; - memset( shaderParms, 0, sizeof( shaderParms ) ); - viewDef_t viewDef; - memset( &viewDef, 0, sizeof( viewDef ) ); + float shaderParms[MAX_ENTITY_SHADER_PARMS]; + memset( shaderParms, 0, sizeof( shaderParms ) ); + viewDef_t viewDef; + memset( &viewDef, 0, sizeof( viewDef ) ); - EvaluateRegisters( constantRegisters, shaderParms, &viewDef, 0 ); + EvaluateRegisters( constantRegisters, shaderParms, &viewDef, 0 ); } /* @@ -2629,14 +2728,14 @@ idMaterial::ImageName =================== */ const char *idMaterial::ImageName( void ) const { - if ( numStages == 0 ) { - return "_scratch"; - } - idImage *image = stages[0].texture.image; - if ( image ) { - return image->imgName; - } - return "_scratch"; + if ( numStages == 0 ) { + return "_scratch"; + } + idImage *image = stages[0].texture.image; + if ( image ) { + return image->imgName; + } + return "_scratch"; } /* @@ -2647,12 +2746,12 @@ Just for image resource tracking. =================== */ void idMaterial::SetImageClassifications( int tag ) const { - for ( int i = 0 ; i < numStages ; i++ ) { - idImage *image = stages[i].texture.image; - if ( image ) { - image->SetClassification( tag ); - } - } + for ( int i = 0 ; i < numStages ; i++ ) { + idImage *image = stages[i].texture.image; + if ( image ) { + image->SetClassification( tag ); + } + } } /* @@ -2661,7 +2760,7 @@ idMaterial::Size ================= */ size_t idMaterial::Size( void ) const { - return sizeof( idMaterial ); + return sizeof( idMaterial ); } /* @@ -2670,24 +2769,24 @@ idMaterial::SetDefaultText =================== */ bool idMaterial::SetDefaultText( void ) { - // if there exists an image with the same name - if ( 1 ) { //fileSystem->ReadFile( GetName(), NULL ) != -1 ) { - char generated[2048]; - idStr::snPrintf( generated, sizeof( generated ), - "material %s // IMPLICITLY GENERATED\n" - "{\n" - "{\n" - "blend blend\n" - "colored\n" - "map \"%s\"\n" - "clamp\n" - "}\n" - "}\n", GetName(), GetName() ); - SetText( generated ); - return true; - } else { - return false; - } + // if there exists an image with the same name + if ( 1 ) { //fileSystem->ReadFile( GetName(), NULL ) != -1 ) { + char generated[2048]; + idStr::snPrintf( generated, sizeof( generated ), + "material %s // IMPLICITLY GENERATED\n" + "{\n" + "{\n" + "blend blend\n" + "colored\n" + "map \"%s\"\n" + "clamp\n" + "}\n" + "}\n", GetName(), GetName() ); + SetText( generated ); + return true; + } else { + return false; + } } /* @@ -2696,28 +2795,27 @@ idMaterial::DefaultDefinition =================== */ const char *idMaterial::DefaultDefinition() const { - return - "{\n" - "\t" "{\n" - "\t\t" "blend\tblend\n" - "\t\t" "map\t\t_default\n" - "\t" "}\n" - "}"; + return + "{\n" + "\t" "{\n" + "\t\t" "blend\tblend\n" + "\t\t" "map\t\t_default\n" + "\t" "}\n" + "}"; } - /* =================== idMaterial::GetBumpStage =================== */ const shaderStage_t *idMaterial::GetBumpStage( void ) const { - for ( int i = 0 ; i < numStages ; i++ ) { - if ( stages[i].lighting == SL_BUMP ) { - return &stages[i]; - } - } - return NULL; + for ( int i = 0 ; i < numStages ; i++ ) { + if ( stages[i].lighting == SL_BUMP ) { + return &stages[i]; + } + } + return NULL; } /* @@ -2725,17 +2823,16 @@ const shaderStage_t *idMaterial::GetBumpStage( void ) const { idMaterial::ReloadImages =================== */ -void idMaterial::ReloadImages( bool force ) const -{ - for ( int i = 0 ; i < numStages ; i++ ) { - if ( stages[i].newStage ) { - for ( int j = 0 ; j < stages[i].newStage->numFragmentProgramImages ; j++ ) { - if ( stages[i].newStage->fragmentProgramImages[j] ) { - stages[i].newStage->fragmentProgramImages[j]->Reload( false, force ); - } - } - } else if ( stages[i].texture.image ) { - stages[i].texture.image->Reload( false, force ); - } - } +void idMaterial::ReloadImages( bool force ) const { + for ( int i = 0 ; i < numStages ; i++ ) { + if ( stages[i].newStage ) { + for ( int j = 0 ; j < stages[i].newStage->numFragmentProgramImages ; j++ ) { + if ( stages[i].newStage->fragmentProgramImages[j] ) { + stages[i].newStage->fragmentProgramImages[j]->Reload( false, force ); + } + } + } else if ( stages[i].texture.image ) { + stages[i].texture.image->Reload( false, force ); + } + } } diff --git a/neo/renderer/MegaTexture.cpp b/neo/renderer/MegaTexture.cpp index 876107d4c..4dfcff425 100644 --- a/neo/renderer/MegaTexture.cpp +++ b/neo/renderer/MegaTexture.cpp @@ -46,7 +46,7 @@ allow sparse population of the upper detail tiles int RoundDownToPowerOfTwo( int num ) { int pot; - for (pot = 1 ; (pot*2) <= num ; pot<<=1) { + for ( pot = 1 ; ( pot * 2 ) <= num ; pot <<= 1 ) { } return pot; } @@ -69,15 +69,15 @@ static byte colors[8][4] = { static void R_EmptyLevelImage( idImage *image ) { int c = MAX_LEVEL_WIDTH * MAX_LEVEL_WIDTH; - byte *data = (byte *)_alloca( c*4 ); + byte *data = ( byte * )_alloca( c * 4 ); for ( int i = 0 ; i < c ; i++ ) { - ((int *)data)[i] = fillColor.intVal; + ( ( int * )data )[i] = fillColor.intVal; } // FIXME: this won't live past vid mode changes image->GenerateImage( data, MAX_LEVEL_WIDTH, MAX_LEVEL_WIDTH, - TF_DEFAULT, false, TR_REPEAT, TD_HIGH_QUALITY ); + TF_DEFAULT, false, TR_REPEAT, TD_HIGH_QUALITY ); } @@ -105,7 +105,6 @@ bool idMegaTexture::InitFromMegaFile( const char *fileBase ) { common->Printf( "idMegaTexture: bad header on %s\n", name.c_str() ); return false; } - currentTriMapping = NULL; numLevels = 0; @@ -115,7 +114,7 @@ bool idMegaTexture::InitFromMegaFile( const char *fileBase ) { int tileOffset = 1; // just past the header memset( levels, 0, sizeof( levels ) ); - while( 1 ) { + while ( 1 ) { idTextureLevel *level = &levels[numLevels]; level->mega = this; @@ -125,7 +124,7 @@ bool idMegaTexture::InitFromMegaFile( const char *fileBase ) { level->parms[0] = -1; // initially mask everything level->parms[1] = 0; level->parms[2] = 0; - level->parms[3] = (float)width / TILE_PER_LEVEL; + level->parms[3] = ( float )width / TILE_PER_LEVEL; level->Invalidate(); tileOffset += level->tilesWide * level->tilesHigh; @@ -134,8 +133,8 @@ bool idMegaTexture::InitFromMegaFile( const char *fileBase ) { sprintf( str, "MEGA_%s_%i", fileBase, numLevels ); // give each level a default fill color - for (int i = 0 ; i < 4 ; i++ ) { - fillColor.color[i] = colors[numLevels+1][i]; + for ( int i = 0 ; i < 4 ; i++ ) { + fillColor.color[i] = colors[numLevels + 1][i]; } levels[numLevels].image = globalImages->ImageFromFunction( str, R_EmptyLevelImage ); @@ -202,9 +201,9 @@ void idMegaTexture::SetMappingForSurface( const srfTriangles_t *tri ) { for ( int i = 0 ; i < 2 ; i++ ) { idVec3 dir = axis[i].xyz - origin.xyz; float texLen = axis[i].st[i] - origin.st[i]; - float spaceLen = (axis[i].xyz - origin.xyz).Length(); + float spaceLen = ( axis[i].xyz - origin.xyz ).Length(); - float scale = texLen / (spaceLen*spaceLen); + float scale = texLen / ( spaceLen * spaceLen ); dir *= scale; float c = origin.xyz * dir - origin.st[i]; @@ -231,7 +230,7 @@ void idMegaTexture::BindForViewOrigin( const idVec3 viewOrigin ) { // level images in higher textures, blurriest first for ( int i = 0 ; i < 7 ; i++ ) { - GL_SelectTexture( 1+i ); + GL_SelectTexture( 1 + i ); if ( i >= numLevels ) { globalImages->whiteImage->Bind(); @@ -239,7 +238,7 @@ void idMegaTexture::BindForViewOrigin( const idVec3 viewOrigin ) { static float parms[4] = { -2, -2, 0, 1 }; // no contribution qglProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, i, parms ); } else { - idTextureLevel *level = &levels[ numLevels-1-i ]; + idTextureLevel *level = &levels[ numLevels - 1 - i ]; if ( r_showMegaTexture.GetBool() ) { if ( i & 1 ) { @@ -278,7 +277,7 @@ need tracking */ void idMegaTexture::Unbind( void ) { for ( int i = 0 ; i < numLevels ; i++ ) { - GL_SelectTexture( 1+i ); + GL_SelectTexture( 1 + i ); globalImages->BindNull(); } } @@ -313,10 +312,10 @@ void idMegaTexture::SetViewOrigin( const idVec3 viewOrigin ) { // be a different conversion for each megaTexture for ( int i = 0 ; i < 2 ; i++ ) { texCenter[i] = - viewOrigin[0] * localViewToTextureCenter[i][0] + - viewOrigin[1] * localViewToTextureCenter[i][1] + - viewOrigin[2] * localViewToTextureCenter[i][2] + - localViewToTextureCenter[i][3]; + viewOrigin[0] * localViewToTextureCenter[i][0] + + viewOrigin[1] * localViewToTextureCenter[i][1] + + viewOrigin[2] * localViewToTextureCenter[i][2] + + localViewToTextureCenter[i][3]; } for ( int i = 0 ; i < numLevels ; i++ ) { @@ -338,7 +337,7 @@ void idTextureLevel::UpdateTile( int localX, int localY, int globalX, int global if ( tile->x == globalX && tile->y == globalY ) { return; } - if ( (globalX & (TILE_PER_LEVEL-1)) != localX || (globalY & (TILE_PER_LEVEL-1)) != localY ) { + if ( ( globalX & ( TILE_PER_LEVEL - 1 ) ) != localX || ( globalY & ( TILE_PER_LEVEL - 1 ) ) != localY ) { common->Error( "idTextureLevel::UpdateTile: bad coordinate mod" ); } @@ -353,7 +352,6 @@ void idTextureLevel::UpdateTile( int localX, int localY, int globalX, int global } else { // extract the data from the full image (FIXME: background load from disk) int tileNum = tileOffset + tile->y * tilesWide + tile->x; - int tileSize = TILE_SIZE * TILE_SIZE * 4; mega->fileHandle->Seek( tileNum * tileSize, FS_SEEK_SET ); @@ -364,10 +362,10 @@ void idTextureLevel::UpdateTile( int localX, int localY, int globalX, int global if ( idMegaTexture::r_showMegaTextureLabels.GetBool() ) { // put a color marker in it // localX and localY are < TILE_PER_LEVEL => that fits perfectly into a byte. - byte color[4] = { (byte)(255 * localX / TILE_PER_LEVEL), (byte)(255 * localY / TILE_PER_LEVEL), 0, 0 }; + byte color[4] = { ( byte )( 255 * localX / TILE_PER_LEVEL ), ( byte )( 255 * localY / TILE_PER_LEVEL ), 0, 0 }; for ( int x = 0 ; x < 8 ; x++ ) { for ( int y = 0 ; y < 8 ; y++ ) { - *(int *)&data[ ( ( y + TILE_SIZE/2 - 4 ) * TILE_SIZE + x + TILE_SIZE/2 - 4 ) * 4 ] = *(int *)color; + *( int * )&data[( ( y + TILE_SIZE / 2 - 4 ) * TILE_SIZE + x + TILE_SIZE / 2 - 4 ) * 4 ] = *( int * )color; } } } @@ -391,10 +389,10 @@ void idTextureLevel::UpdateTile( int localX, int localY, int globalX, int global in2 = in + size * 8; out = data + y * size * 4; for ( int x = 0 ; x < size ; x++ ) { - out[x*4+0] = ( in[x*8+0] + in[x*8+4+0] + in2[x*8+0] + in2[x*8+4+0] ) >> 2; - out[x*4+1] = ( in[x*8+1] + in[x*8+4+1] + in2[x*8+1] + in2[x*8+4+1] ) >> 2; - out[x*4+2] = ( in[x*8+2] + in[x*8+4+2] + in2[x*8+2] + in2[x*8+4+2] ) >> 2; - out[x*4+3] = ( in[x*8+3] + in[x*8+4+3] + in2[x*8+3] + in2[x*8+4+3] ) >> 2; + out[x * 4 + 0] = ( in[x * 8 + 0] + in[x * 8 + 4 + 0] + in2[x * 8 + 0] + in2[x * 8 + 4 + 0] ) >> 2; + out[x * 4 + 1] = ( in[x * 8 + 1] + in[x * 8 + 4 + 1] + in2[x * 8 + 1] + in2[x * 8 + 4 + 1] ) >> 2; + out[x * 4 + 2] = ( in[x * 8 + 2] + in[x * 8 + 4 + 2] + in2[x * 8 + 2] + in2[x * 8 + 4 + 2] ) >> 2; + out[x * 4 + 3] = ( in[x * 8 + 3] + in[x * 8 + 4 + 3] + in2[x * 8 + 3] + in2[x * 8 + 4 + 3] ) >> 2; } } } @@ -428,13 +426,13 @@ void idTextureLevel::UpdateForCenter( float center[2] ) { // we are in the corner of the megaTexture global[i] = ( center[i] * parms[3] - 0.5 ) * TILE_PER_LEVEL; - globalTileCorner[i] = (int)( global[i] + 0.5 ); + globalTileCorner[i] = ( int )( global[i] + 0.5 ); - localTileOffset[i] = globalTileCorner[i] & (TILE_PER_LEVEL-1); + localTileOffset[i] = globalTileCorner[i] & ( TILE_PER_LEVEL - 1 ); // scaling for the mask texture to only allow the proper window // of tiles to show through - parms[i] = -globalTileCorner[i] / (float)TILE_PER_LEVEL; + parms[i] = -globalTileCorner[i] / ( float )TILE_PER_LEVEL; } } @@ -444,8 +442,8 @@ void idTextureLevel::UpdateForCenter( float center[2] ) { for ( int y = 0 ; y < TILE_PER_LEVEL ; y++ ) { int globalTile[2]; - globalTile[0] = globalTileCorner[0] + ( ( x - localTileOffset[0] ) & (TILE_PER_LEVEL-1) ); - globalTile[1] = globalTileCorner[1] + ( ( y - localTileOffset[1] ) & (TILE_PER_LEVEL-1) ); + globalTile[0] = globalTileCorner[0] + ( ( x - localTileOffset[0] ) & ( TILE_PER_LEVEL - 1 ) ); + globalTile[1] = globalTileCorner[1] + ( ( y - localTileOffset[1] ) & ( TILE_PER_LEVEL - 1 ) ); UpdateTile( x, y, globalTile[0], globalTile[1] ); } @@ -463,7 +461,7 @@ void idTextureLevel::Invalidate() { for ( int x = 0 ; x < TILE_PER_LEVEL ; x++ ) { for ( int y = 0 ; y < TILE_PER_LEVEL ; y++ ) { tileMap[x][y].x = - tileMap[x][y].y = -99999; + tileMap[x][y].y = -99999; } } } @@ -479,29 +477,24 @@ typedef struct _TargaHeader { unsigned char pixel_size, attributes; } TargaHeader; - static byte ReadByte( idFile *f ) { - byte b; - + byte b; f->Read( &b, 1 ); return b; } static short ReadShort( idFile *f ) { - byte b[2]; - + byte b[2]; f->Read( &b, 2 ); - return b[0] + ( b[1] << 8 ); } - /* ==================== GenerateMegaMipMaps ==================== */ -void idMegaTexture::GenerateMegaMipMaps( megaTextureHeader_t *header, idFile *outFile ) { +void idMegaTexture::GenerateMegaMipMaps( megaTextureHeader_t *header, idFile *outFile ) { outFile->Flush(); // out fileSystem doesn't allow read / write access... @@ -512,22 +505,23 @@ void idMegaTexture::GenerateMegaMipMaps( megaTextureHeader_t *header, idFile *ou int height = header->tilesHigh; int tileSize = header->tileSize * header->tileSize * 4; - byte *oldBlock = (byte *)_alloca( tileSize ); - byte *newBlock = (byte *)_alloca( tileSize ); + byte *oldBlock = ( byte * )_alloca( tileSize ); + byte *newBlock = ( byte * )_alloca( tileSize ); while ( width > 1 || height > 1 ) { - int newHeight = (height+1) >> 1; + int newHeight = ( height + 1 ) >> 1; + if ( newHeight < 1 ) { newHeight = 1; } - int newWidth = (width+1) >> 1; + int newWidth = ( width + 1 ) >> 1; + if ( width < 1 ) { width = 1; } common->Printf( "generating %i x %i block mip level\n", newWidth, newHeight ); - int tileNum; - + int tileNum; for ( int y = 0 ; y < newHeight ; y++ ) { common->Printf( "row %i\n", y ); session->UpdateScreen(); @@ -535,9 +529,9 @@ void idMegaTexture::GenerateMegaMipMaps( megaTextureHeader_t *header, idFile *ou for ( int x = 0 ; x < newWidth ; x++ ) { // mip map four original blocks down into a single new block for ( int yy = 0 ; yy < 2 ; yy++ ) { - for ( int xx = 0 ; xx< 2 ; xx++ ) { - int tx = x*2 + xx; - int ty = y*2 + yy; + for ( int xx = 0 ; xx < 2 ; xx++ ) { + int tx = x * 2 + xx; + int ty = y * 2 + yy; if ( tx > width || ty > height ) { // off edge, zero fill @@ -547,15 +541,17 @@ void idMegaTexture::GenerateMegaMipMaps( megaTextureHeader_t *header, idFile *ou inFile->Seek( tileNum * tileSize, FS_SEEK_SET ); inFile->Read( oldBlock, tileSize ); } + // mip map the new pixels for ( int yyy = 0 ; yyy < TILE_SIZE / 2 ; yyy++ ) { for ( int xxx = 0 ; xxx < TILE_SIZE / 2 ; xxx++ ) { - byte *in = &oldBlock[ ( yyy * 2 * TILE_SIZE + xxx * 2 ) * 4 ]; - byte *out = &newBlock[ ( ( ( TILE_SIZE/2 * yy ) + yyy ) * TILE_SIZE + ( TILE_SIZE/2 * xx ) + xxx ) * 4 ]; - out[0] = ( in[0] + in[4] + in[0+TILE_SIZE*4] + in[4+TILE_SIZE*4] ) >> 2; - out[1] = ( in[1] + in[5] + in[1+TILE_SIZE*4] + in[5+TILE_SIZE*4] ) >> 2; - out[2] = ( in[2] + in[6] + in[2+TILE_SIZE*4] + in[6+TILE_SIZE*4] ) >> 2; - out[3] = ( in[3] + in[7] + in[3+TILE_SIZE*4] + in[7+TILE_SIZE*4] ) >> 2; + byte *in = &oldBlock[( yyy * 2 * TILE_SIZE + xxx * 2 ) * 4 ]; + byte *out = &newBlock[( ( ( TILE_SIZE / 2 * yy ) + yyy ) * TILE_SIZE + ( TILE_SIZE / 2 * xx ) + xxx ) * 4 ]; + + out[0] = ( in[0] + in[4] + in[0 + TILE_SIZE * 4] + in[4 + TILE_SIZE * 4] ) >> 2; + out[1] = ( in[1] + in[5] + in[1 + TILE_SIZE * 4] + in[5 + TILE_SIZE * 4] ) >> 2; + out[2] = ( in[2] + in[6] + in[2 + TILE_SIZE * 4] + in[6 + TILE_SIZE * 4] ) >> 2; + out[3] = ( in[3] + in[7] + in[3 + TILE_SIZE * 4] + in[7 + TILE_SIZE * 4] ) >> 2; } } @@ -572,7 +568,6 @@ void idMegaTexture::GenerateMegaMipMaps( megaTextureHeader_t *header, idFile *ou width = newWidth; height = newHeight; } - delete inFile; } @@ -583,14 +578,14 @@ GenerateMegaPreview Make a 2k x 2k preview image for a mega texture that can be used in modeling programs ==================== */ -void idMegaTexture::GenerateMegaPreview( const char *fileName ) { - idFile *fileHandle = fileSystem->OpenFileRead( fileName ); +void idMegaTexture::GenerateMegaPreview( const char *fileName ) { + idFile *fileHandle = fileSystem->OpenFileRead( fileName ); + if ( !fileHandle ) { common->Printf( "idMegaTexture: failed to open %s\n", fileName ); return; } - - idStr outName = fileName; + idStr outName = fileName; outName.StripFileExtension(); outName += "_preview.tga"; @@ -599,44 +594,47 @@ void idMegaTexture::GenerateMegaPreview( const char *fileName ) { megaTextureHeader_t header; fileHandle->Read( &header, sizeof( header ) ); + if ( header.tileSize < 64 || header.tilesWide < 1 || header.tilesHigh < 1 ) { common->Printf( "idMegaTexture: bad header on %s\n", fileName ); return; } - int tileSize = header.tileSize; int width = header.tilesWide; int height = header.tilesHigh; int tileOffset = 1; int tileBytes = tileSize * tileSize * 4; + // find the level that fits while ( width * tileSize > 2048 || height * tileSize > 2048 ) { tileOffset += width * height; width >>= 1; + if ( width < 1 ) { width = 1; } height >>= 1; + if ( height < 1 ) { height = 1; } } + byte *pic = ( byte * )R_StaticAlloc( width * height * tileBytes ); + byte *oldBlock = ( byte * )_alloca( tileBytes ); - byte *pic = (byte *)R_StaticAlloc( width * height * tileBytes ); - byte *oldBlock = (byte *)_alloca( tileBytes ); for ( int y = 0 ; y < height ; y++ ) { for ( int x = 0 ; x < width ; x++ ) { int tileNum = tileOffset + y * width + x; + fileHandle->Seek( tileNum * tileBytes, FS_SEEK_SET ); fileHandle->Read( oldBlock, tileBytes ); for ( int yy = 0 ; yy < tileSize ; yy++ ) { - memcpy( pic + ( ( y * tileSize + yy ) * width * tileSize + x * tileSize ) * 4, - oldBlock + yy * tileSize * 4, tileSize * 4 ); + memcpy( pic + ( ( y * tileSize + yy ) * width * tileSize + x * tileSize ) * 4, + oldBlock + yy * tileSize * 4, tileSize * 4 ); } } } - R_WriteTGA( outName.c_str(), pic, width * tileSize, height * tileSize, false ); R_StaticFree( pic ); @@ -644,7 +642,6 @@ void idMegaTexture::GenerateMegaPreview( const char *fileName ) { delete fileHandle; } - /* ==================== MakeMegaTexture_f @@ -653,18 +650,18 @@ Incrementally load a giant tga file and process into the mega texture block form ==================== */ void idMegaTexture::MakeMegaTexture_f( const idCmdArgs &args ) { - int columns, fileSize, numBytes; - byte *pixbuf; - int row, column; + int columns, fileSize, numBytes; + byte *pixbuf; + int row, column; TargaHeader targa_header; if ( args.Argc() != 2 ) { common->Printf( "USAGE: makeMegaTexture \n" ); return; } + idStr name_s = "megaTextures/"; - idStr name_s = "megaTextures/"; - name_s += args.Argv(1); + name_s += args.Argv( 1 ); name_s.StripFileExtension(); name_s += ".tga"; @@ -675,13 +672,12 @@ void idMegaTexture::MakeMegaTexture_f( const idCmdArgs &args ) { // common->Printf( "Opening %s.\n", name ); fileSize = fileSystem->ReadFile( name, NULL, NULL ); - idFile *file = fileSystem->OpenFileRead( name ); + idFile *file = fileSystem->OpenFileRead( name ); if ( !file ) { common->Printf( "Couldn't open %s\n", name ); return; } - targa_header.id_length = ReadByte( file ); targa_header.colormap_type = ReadByte( file ); targa_header.image_type = ReadByte( file ); @@ -697,43 +693,47 @@ void idMegaTexture::MakeMegaTexture_f( const idCmdArgs &args ) { targa_header.attributes = ReadByte( file ); if ( targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3 ) { - common->Error( "LoadTGA( %s ): Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n", name ); + common->Printf( "LoadTGA( %s ): Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n", name ); + return; } if ( targa_header.colormap_type != 0 ) { - common->Error( "LoadTGA( %s ): colormaps not supported\n", name ); + common->Printf( "LoadTGA( %s ): colormaps not supported\n", name ); + return; } if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 ) { - common->Error( "LoadTGA( %s ): Only 32 or 24 bit images supported (no colormaps)\n", name ); + common->Printf( "LoadTGA( %s ): Only 32 or 24 bit images supported (no colormaps)\n", name ); + return; } if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) { numBytes = targa_header.width * targa_header.height * ( targa_header.pixel_size >> 3 ); + if ( numBytes > fileSize - 18 - targa_header.id_length ) { - common->Error( "LoadTGA( %s ): incomplete file\n", name ); + common->Printf( "LoadTGA( %s ): incomplete file\n", name ); + return; } } - columns = targa_header.width; // skip TARGA image comment if ( targa_header.id_length != 0 ) { file->Seek( targa_header.id_length, FS_SEEK_CUR ); } - - megaTextureHeader_t mtHeader; + megaTextureHeader_t mtHeader; mtHeader.tileSize = TILE_SIZE; mtHeader.tilesWide = RoundDownToPowerOfTwo( targa_header.width ) / TILE_SIZE; mtHeader.tilesHigh = RoundDownToPowerOfTwo( targa_header.height ) / TILE_SIZE; - idStr outName = name; + idStr outName = name; + outName.StripFileExtension(); outName += ".mega"; common->Printf( "Writing %i x %i size %i tiles to %s.\n", - mtHeader.tilesWide, mtHeader.tilesHigh, mtHeader.tileSize, outName.c_str() ); + mtHeader.tilesWide, mtHeader.tilesHigh, mtHeader.tileSize, outName.c_str() ); // open the output megatexture file idFile *out = fileSystem->OpenFileWrite( outName.c_str() ); @@ -743,20 +743,20 @@ void idMegaTexture::MakeMegaTexture_f( const idCmdArgs &args ) { // we will process this one row of tiles at a time, since the entire thing // won't fit in memory - byte *targa_rgba = (byte *)R_StaticAlloc( TILE_SIZE * targa_header.width * 4 ); - - int blockRowsRemaining = mtHeader.tilesHigh; + byte *targa_rgba = ( byte * )R_StaticAlloc( TILE_SIZE * targa_header.width * 4 ); + int blockRowsRemaining = mtHeader.tilesHigh; while ( blockRowsRemaining-- ) { common->Printf( "%i blockRowsRemaining\n", blockRowsRemaining ); session->UpdateScreen(); if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) { // Uncompressed RGB or gray scale image - for( row = 0 ; row < TILE_SIZE ; row++ ) { - pixbuf = targa_rgba + row*columns*4; - for( column = 0; column < columns; column++) { - unsigned char red,green,blue,alphabyte; - switch( targa_header.pixel_size ) { + for ( row = 0 ; row < TILE_SIZE ; row++ ) { + pixbuf = targa_rgba + row * columns * 4; + + for ( column = 0; column < columns; column++ ) { + unsigned char red, green, blue, alphabyte; + switch ( targa_header.pixel_size ) { case 8: blue = ReadByte( file ); green = blue; @@ -793,96 +793,101 @@ void idMegaTexture::MakeMegaTexture_f( const idCmdArgs &args ) { } } } else if ( targa_header.image_type == 10 ) { // Runlength encoded RGB images - unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j; + unsigned char red, green, blue, alphabyte, packetHeader, packetSize, j; red = 0; green = 0; blue = 0; alphabyte = 0xff; - for( row = 0 ; row < TILE_SIZE ; row++ ) { - pixbuf = targa_rgba + row*columns*4; - for( column = 0; column < columns; ) { - packetHeader= ReadByte( file ); - packetSize = 1 + (packetHeader & 0x7f); + for ( row = 0 ; row < TILE_SIZE ; row++ ) { + pixbuf = targa_rgba + row * columns * 4; + + for ( column = 0; column < columns; ) { + packetHeader = ReadByte( file ); + packetSize = 1 + ( packetHeader & 0x7f ); + if ( packetHeader & 0x80 ) { // run-length packet - switch( targa_header.pixel_size ) { - case 24: - blue = ReadByte( file ); - green = ReadByte( file ); - red = ReadByte( file ); - alphabyte = 255; - break; - case 32: - blue = ReadByte( file ); - green = ReadByte( file ); - red = ReadByte( file ); - alphabyte = ReadByte( file ); - break; - default: - common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size ); - break; + switch ( targa_header.pixel_size ) { + case 24: + blue = ReadByte( file ); + green = ReadByte( file ); + red = ReadByte( file ); + alphabyte = 255; + break; + case 32: + blue = ReadByte( file ); + green = ReadByte( file ); + red = ReadByte( file ); + alphabyte = ReadByte( file ); + break; + default: + common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size ); + break; } - for( j = 0; j < packetSize; j++ ) { - *pixbuf++=red; - *pixbuf++=green; - *pixbuf++=blue; - *pixbuf++=alphabyte; + for ( j = 0; j < packetSize; j++ ) { + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; column++; + if ( column == columns ) { // run spans across rows common->Error( "TGA had RLE across columns, probably breaks block" ); column = 0; - if ( row > 0) { + + if ( row > 0 ) { row--; - } - else { + } else { goto breakOut; } - pixbuf = targa_rgba + row*columns*4; + pixbuf = targa_rgba + row * columns * 4; } } } else { // non run-length packet - for( j = 0; j < packetSize; j++ ) { - switch( targa_header.pixel_size ) { - case 24: - blue = ReadByte( file ); - green = ReadByte( file ); - red = ReadByte( file ); - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = 255; - break; - case 32: - blue = ReadByte( file ); - green = ReadByte( file ); - red = ReadByte( file ); - alphabyte = ReadByte( file ); - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = alphabyte; - break; - default: - common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size ); - break; + for ( j = 0; j < packetSize; j++ ) { + switch ( targa_header.pixel_size ) { + case 24: + blue = ReadByte( file ); + green = ReadByte( file ); + red = ReadByte( file ); + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = ReadByte( file ); + green = ReadByte( file ); + red = ReadByte( file ); + alphabyte = ReadByte( file ); + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + break; + default: + common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size ); + break; } column++; - if ( column == columns ) { // pixel packet run spans across rows + + // pixel packet run spans across rows + if ( column == columns ) { column = 0; + if ( row > 0 ) { row--; - } - else { + } else { goto breakOut; } - pixbuf = targa_rgba + row*columns*4; + pixbuf = targa_rgba + row * columns * 4; } } } } - breakOut: ; +breakOut:; } } @@ -895,7 +900,6 @@ void idMegaTexture::MakeMegaTexture_f( const idCmdArgs &args ) { } } } - R_StaticFree( targa_rgba ); GenerateMegaMipMaps( &mtHeader, out ); @@ -905,7 +909,8 @@ void idMegaTexture::MakeMegaTexture_f( const idCmdArgs &args ) { GenerateMegaPreview( outName.c_str() ); #if 0 - if ( (targa_header.attributes & (1<<5)) ) { // image flp bit + // image flp bit + if ( ( targa_header.attributes & ( 1 << 5 ) ) ) { R_VerticalFlip( *pic, *width, *height ); } #endif diff --git a/neo/renderer/ModelOverlay.cpp b/neo/renderer/ModelOverlay.cpp index 96bdca722..2868e24a7 100644 --- a/neo/renderer/ModelOverlay.cpp +++ b/neo/renderer/ModelOverlay.cpp @@ -117,16 +117,8 @@ void idRenderModelOverlay::CreateOverlay( const idRenderModel *model, const idPl } // make temporary buffers for the building process - // DG: using Mem_MallocA() instead of alloca() to avoid stack overflows with large models - size_t vertSize = maxVerts * sizeof( overlayVertex_t ); - bool vertsOnStack; - overlayVertex_t *overlayVerts = (overlayVertex_t *)Mem_MallocA( vertSize, vertsOnStack ); - - // Note: here we have two Mem_MallocA() calls, this relies on the stack being - // big enough for two alloca(ID_MAX_ALLOCA_SIZE) calls! - size_t idxSize = maxIndexes * sizeof( glIndex_t ); - bool idxOnStack; - glIndex_t *overlayIndexes = (glIndex_t *)Mem_MallocA( idxSize, idxOnStack ); + overlayVertex_t *overlayVerts = (overlayVertex_t *)_alloca( maxVerts * sizeof( *overlayVerts ) ); + glIndex_t *overlayIndexes = (glIndex_t *)_alloca16( maxIndexes * sizeof( *overlayIndexes ) ); // pull out the triangles we need from the base surfaces for ( surfNum = 0; surfNum < model->NumBaseSurfaces(); surfNum++ ) { @@ -232,9 +224,6 @@ void idRenderModelOverlay::CreateOverlay( const idRenderModel *model, const idPl materials[i]->surfaces.RemoveIndex( 0 ); } } - - Mem_FreeA(overlayVerts, vertsOnStack); - Mem_FreeA(overlayIndexes, idxOnStack); } /* diff --git a/neo/renderer/Model_md5.cpp b/neo/renderer/Model_md5.cpp index 30b911188..59e8b3142 100644 --- a/neo/renderer/Model_md5.cpp +++ b/neo/renderer/Model_md5.cpp @@ -235,16 +235,13 @@ void idMD5Mesh::ParseMesh( idLexer &parser, int numJoints, const idJointMat *joi // build the information that will be common to all animations of this mesh: // silhouette edge connectivity and normal / tangent generation information // - bool onStack; - idDrawVert *verts = (idDrawVert*)Mem_MallocA( texCoords.Num()*sizeof(idDrawVert), onStack ); - + idDrawVert *verts = (idDrawVert *) _alloca16( texCoords.Num() * sizeof( idDrawVert ) ); for ( i = 0; i < texCoords.Num(); i++ ) { verts[i].Clear(); verts[i].st = texCoords[i]; } TransformVerts( verts, joints ); deformInfo = R_BuildDeformInfo( texCoords.Num(), verts, tris.Num(), tris.Ptr(), shader->UseUnsmoothedTangents() ); - Mem_FreeA( verts, onStack ); } /* @@ -355,15 +352,12 @@ idMD5Mesh::CalcBounds */ idBounds idMD5Mesh::CalcBounds( const idJointMat *entJoints ) { idBounds bounds; - bool onStack; - idDrawVert *verts = (idDrawVert*)Mem_MallocA( texCoords.Num()*sizeof(idDrawVert), onStack ); + idDrawVert *verts = (idDrawVert *) _alloca16( texCoords.Num() * sizeof( idDrawVert ) ); TransformVerts( verts, entJoints ); SIMDProcessor->MinMax( bounds[0], bounds[1], verts, texCoords.Num() ); - Mem_FreeA( verts, onStack ); - return bounds; } diff --git a/neo/renderer/RenderSystem.cpp b/neo/renderer/RenderSystem.cpp index bf50950ad..2595b962b 100644 --- a/neo/renderer/RenderSystem.cpp +++ b/neo/renderer/RenderSystem.cpp @@ -41,7 +41,6 @@ If you have questions concerning this license or the applicable additional terms idRenderSystemLocal tr; idRenderSystem *renderSystem = &tr; - /* ===================== R_PerformanceCounters @@ -52,48 +51,47 @@ only be called when the back end thread is idle. */ static void R_PerformanceCounters( void ) { if ( r_showPrimitives.GetInteger() != 0 ) { - - float megaBytes = globalImages->SumOfUsedImages() / ( 1024*1024.0 ); + float megaBytes = globalImages->SumOfUsedImages() / ( 1024 * 1024.0 ); if ( r_showPrimitives.GetInteger() > 1 ) { common->Printf( "v:%i ds:%i t:%i/%i v:%i/%i st:%i sv:%i image:%5.1f MB\n", - tr.pc.c_numViews, - backEnd.pc.c_drawElements + backEnd.pc.c_shadowElements, - backEnd.pc.c_drawIndexes / 3, - ( backEnd.pc.c_drawIndexes - backEnd.pc.c_drawRefIndexes ) / 3, - backEnd.pc.c_drawVertexes, - ( backEnd.pc.c_drawVertexes - backEnd.pc.c_drawRefVertexes ), - backEnd.pc.c_shadowIndexes / 3, - backEnd.pc.c_shadowVertexes, - megaBytes - ); + tr.pc.c_numViews, + backEnd.pc.c_drawElements + backEnd.pc.c_shadowElements, + backEnd.pc.c_drawIndexes / 3, + ( backEnd.pc.c_drawIndexes - backEnd.pc.c_drawRefIndexes ) / 3, + backEnd.pc.c_drawVertexes, + ( backEnd.pc.c_drawVertexes - backEnd.pc.c_drawRefVertexes ), + backEnd.pc.c_shadowIndexes / 3, + backEnd.pc.c_shadowVertexes, + megaBytes + ); } else { common->Printf( "views:%i draws:%i tris:%i (shdw:%i) (vbo:%i) image:%5.1f MB\n", - tr.pc.c_numViews, - backEnd.pc.c_drawElements + backEnd.pc.c_shadowElements, - ( backEnd.pc.c_drawIndexes + backEnd.pc.c_shadowIndexes ) / 3, - backEnd.pc.c_shadowIndexes / 3, - backEnd.pc.c_vboIndexes / 3, - megaBytes - ); + tr.pc.c_numViews, + backEnd.pc.c_drawElements + backEnd.pc.c_shadowElements, + ( backEnd.pc.c_drawIndexes + backEnd.pc.c_shadowIndexes ) / 3, + backEnd.pc.c_shadowIndexes / 3, + backEnd.pc.c_vboIndexes / 3, + megaBytes + ); } } if ( r_showDynamic.GetBool() ) { common->Printf( "callback:%i md5:%i dfrmVerts:%i dfrmTris:%i tangTris:%i guis:%i\n", - tr.pc.c_entityDefCallbacks, - tr.pc.c_generateMd5, - tr.pc.c_deformedVerts, - tr.pc.c_deformedIndexes/3, - tr.pc.c_tangentIndexes/3, - tr.pc.c_guiSurfs - ); + tr.pc.c_entityDefCallbacks, + tr.pc.c_generateMd5, + tr.pc.c_deformedVerts, + tr.pc.c_deformedIndexes / 3, + tr.pc.c_tangentIndexes / 3, + tr.pc.c_guiSurfs + ); } if ( r_showCull.GetBool() ) { common->Printf( "%i sin %i sclip %i sout %i bin %i bout\n", - tr.pc.c_sphere_cull_in, tr.pc.c_sphere_cull_clip, tr.pc.c_sphere_cull_out, - tr.pc.c_box_cull_in, tr.pc.c_box_cull_out ); + tr.pc.c_sphere_cull_in, tr.pc.c_sphere_cull_clip, tr.pc.c_sphere_cull_out, + tr.pc.c_box_cull_in, tr.pc.c_box_cull_out ); } if ( r_showAlloc.GetBool() ) { @@ -102,31 +100,32 @@ static void R_PerformanceCounters( void ) { if ( r_showInteractions.GetBool() ) { common->Printf( "createInteractions:%i createLightTris:%i createShadowVolumes:%i\n", - tr.pc.c_createInteractions, tr.pc.c_createLightTris, tr.pc.c_createShadowVolumes ); + tr.pc.c_createInteractions, tr.pc.c_createLightTris, tr.pc.c_createShadowVolumes ); } + if ( r_showDefs.GetBool() ) { common->Printf( "viewEntities:%i shadowEntities:%i viewLights:%i\n", tr.pc.c_visibleViewEntities, - tr.pc.c_shadowViewEntities, tr.pc.c_viewLights ); + tr.pc.c_shadowViewEntities, tr.pc.c_viewLights ); } + if ( r_showUpdates.GetBool() ) { common->Printf( "entityUpdates:%i entityRefs:%i lightUpdates:%i lightRefs:%i\n", - tr.pc.c_entityUpdates, tr.pc.c_entityReferences, - tr.pc.c_lightUpdates, tr.pc.c_lightReferences ); + tr.pc.c_entityUpdates, tr.pc.c_entityReferences, + tr.pc.c_lightUpdates, tr.pc.c_lightReferences ); } + if ( r_showMemory.GetBool() ) { int m1 = frameData ? frameData->memoryHighwater : 0; common->Printf( "frameData: %i (%i)\n", R_CountFrameData(), m1 ); } + if ( r_showLightScale.GetBool() ) { common->Printf( "lightScale: %f\n", backEnd.pc.maxLightValue ); } - memset( &tr.pc, 0, sizeof( tr.pc ) ); memset( &backEnd.pc, 0, sizeof( backEnd.pc ) ); } - - /* ==================== R_IssueRenderCommands @@ -135,8 +134,7 @@ Called by R_EndFrame each frame ==================== */ static void R_IssueRenderCommands( void ) { - if ( frameData->cmdHead->commandId == RC_NOP - && !frameData->cmdHead->next ) { + if ( frameData->cmdHead->commandId == RC_NOP && !frameData->cmdHead->next ) { // nothing to issue return; } @@ -152,7 +150,6 @@ static void R_IssueRenderCommands( void ) { if ( !r_skipBackEnd.GetBool() ) { RB_ExecuteBackEndCommands( frameData->cmdHead ); } - R_ClearCommandChain(); } @@ -168,12 +165,12 @@ current command chain. void *R_GetCommandBuffer( int bytes ) { emptyCommand_t *cmd; - cmd = (emptyCommand_t *)R_FrameAlloc( bytes ); + cmd = ( emptyCommand_t * )R_FrameAlloc( bytes ); cmd->next = NULL; frameData->cmdTail->next = &cmd->commandId; frameData->cmdTail = cmd; - return (void *)cmd; + return ( void * )cmd; } @@ -187,7 +184,7 @@ and by R_ToggleSmpFrame */ void R_ClearCommandChain( void ) { // clear the command chain - frameData->cmdHead = frameData->cmdTail = (emptyCommand_t *)R_FrameAlloc( sizeof( *frameData->cmdHead ) ); + frameData->cmdHead = frameData->cmdTail = ( emptyCommand_t * )R_FrameAlloc( sizeof( *frameData->cmdHead ) ); frameData->cmdHead->commandId = RC_NOP; frameData->cmdHead->next = NULL; } @@ -213,12 +210,11 @@ This is the main 3D rendering command. A single scene may have multiple views if a mirror, portal, or dynamic texture is present. ============= */ -void R_AddDrawViewCmd( viewDef_t *parms ) { +void R_AddDrawViewCmd( viewDef_t *parms ) { drawSurfsCommand_t *cmd; - cmd = (drawSurfsCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) ); + cmd = ( drawSurfsCommand_t * )R_GetCommandBuffer( sizeof( *cmd ) ); cmd->commandId = RC_DRAW_VIEW; - cmd->viewDef = parms; tr.pc.c_numViews++; @@ -247,20 +243,30 @@ static void R_CheckCvars( void ) { R_SetColorMappings(); } + // gamma / brightness if ( r_gammaInShader.IsModified() ) { r_gammaInShader.ClearModified(); + // reload shaders so they either add or remove the code for setting gamma/brightness in shader R_ReloadARBPrograms_f( idCmdArgs() ); if ( r_gammaInShader.GetBool() ) { - common->Printf( "Will apply r_gamma and r_brightness in shaders\n" ); + common->Printf( "Will apply r_gamma and r_brightness in shaders ( ARB2 only )\n" ); GLimp_ResetGamma(); // reset hardware gamma } else { - common->Printf( "Will apply r_gamma and r_brightness in hardware (possibly on all screens)\n" ); + common->Printf( "Will apply r_gamma and r_brightness in hardware ( possibly on all screens )\n" ); R_SetColorMappings(); } } + // GLSL interactions (shader gamma is not yet implemented so disable it if using this) + if ( r_useGLSL.IsModified() ) { + r_useGLSL.ClearModified(); + + // reload shaders so the backend changes + R_ReloadARBPrograms_f( idCmdArgs() ); + } + if ( r_swapInterval.IsModified() ) { GLimp_SetSwapInterval( r_swapInterval.GetInteger() ); r_swapInterval.ClearModified(); @@ -317,9 +323,8 @@ DrawStretchPic ============= */ void idRenderSystemLocal::DrawStretchPic( const idDrawVert *verts, const glIndex_t *indexes, int vertCount, int indexCount, const idMaterial *material, - bool clip, float min_x, float min_y, float max_x, float max_y ) { - guiModel->DrawStretchPic( verts, indexes, vertCount, indexCount, material, - clip, min_x, min_y, max_x, max_y ); + bool clip, float min_x, float min_y, float max_x, float max_y ) { + guiModel->DrawStretchPic( verts, indexes, vertCount, indexCount, material, clip, min_x, min_y, max_x, max_y ); } /* @@ -358,7 +363,7 @@ void idRenderSystemLocal::GlobalToNormalizedDeviceCoordinates( const idVec3 &glo GlobalToNormalizedDeviceCoordinates ============= */ -void idRenderSystemLocal::GetGLSettings( int& width, int& height ) { +void idRenderSystemLocal::GetGLSettings( int &width, int &height ) { width = glConfig.vidWidth; height = glConfig.vidHeight; } @@ -384,7 +389,6 @@ void idRenderSystemLocal::DrawSmallChar( int x, int y, int ch, const idMaterial if ( y < -SMALLCHAR_HEIGHT ) { return; } - row = ch >> 4; col = ch & 15; @@ -393,9 +397,9 @@ void idRenderSystemLocal::DrawSmallChar( int x, int y, int ch, const idMaterial size = 0.0625f; DrawStretchPic( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, - fcol, frow, - fcol + size, frow + size, - material ); + fcol, frow, + fcol + size, frow + size, + material ); } /* @@ -414,16 +418,18 @@ void idRenderSystemLocal::DrawSmallStringExt( int x, int y, const char *string, int xx; // draw the colored text - s = (const unsigned char*)string; + s = ( const unsigned char * )string; xx = x; + SetColor( setColor ); + while ( *s ) { - if ( idStr::IsColor( (const char*)s ) ) { + if ( idStr::IsColor( ( const char * )s ) ) { if ( !forceColor ) { - if ( *(s+1) == C_COLOR_DEFAULT ) { + if ( *( s + 1 ) == C_COLOR_DEFAULT ) { SetColor( setColor ); } else { - color = idStr::ColorForIndex( *(s+1) ); + color = idStr::ColorForIndex( *( s + 1 ) ); color[3] = setColor[3]; SetColor( color ); } @@ -457,7 +463,6 @@ void idRenderSystemLocal::DrawBigChar( int x, int y, int ch, const idMaterial *m if ( y < -BIGCHAR_HEIGHT ) { return; } - row = ch >> 4; col = ch & 15; @@ -466,9 +471,9 @@ void idRenderSystemLocal::DrawBigChar( int x, int y, int ch, const idMaterial *m size = 0.0625f; DrawStretchPic( x, y, BIGCHAR_WIDTH, BIGCHAR_HEIGHT, - fcol, frow, - fcol + size, frow + size, - material ); + fcol, frow, + fcol + size, frow + size, + material ); } /* @@ -489,14 +494,16 @@ void idRenderSystemLocal::DrawBigStringExt( int x, int y, const char *string, co // draw the colored text s = string; xx = x; + SetColor( setColor ); + while ( *s ) { if ( idStr::IsColor( s ) ) { if ( !forceColor ) { - if ( *(s+1) == C_COLOR_DEFAULT ) { + if ( *( s + 1 ) == C_COLOR_DEFAULT ) { SetColor( setColor ); } else { - color = idStr::ColorForIndex( *(s+1) ); + color = idStr::ColorForIndex( *( s + 1 ) ); color[3] = setColor[3]; SetColor( color ); } @@ -524,7 +531,6 @@ void idRenderSystemLocal::SetBackEndRenderer() { if ( !r_renderer.IsModified() ) { return; } - bool oldVPstate = backEndRendererHasVertexPrograms; backEndRenderer = BE_BAD; @@ -542,11 +548,10 @@ void idRenderSystemLocal::SetBackEndRenderer() { backEndRenderer = BE_ARB2; } } - backEndRendererHasVertexPrograms = false; backEndRendererMaxLight = 1.0; - switch( backEndRenderer ) { + switch ( backEndRenderer ) { case BE_ARB2: common->Printf( "using ARB2 renderSystem\n" ); backEndRendererHasVertexPrograms = true; @@ -561,11 +566,11 @@ void idRenderSystemLocal::SetBackEndRenderer() { // shadows will be different data if ( oldVPstate != backEndRendererHasVertexPrograms ) { vertexCache.PurgeAll(); + if ( primaryWorld ) { primaryWorld->FreeInteractions(); } } - r_renderer.ClearModified(); } @@ -625,7 +630,6 @@ void idRenderSystemLocal::BeginFrame( int windowWidth, int windowHeight ) { CropRenderSize( w, h ); } - // this is the ONLY place this is modified frameCount++; @@ -636,7 +640,7 @@ void idRenderSystemLocal::BeginFrame( int windowWidth, int windowHeight ) { // the first rendering will be used for commands like // screenshot, rather than a possible subsequent remote // or mirror render -// primaryWorld = NULL; + // primaryWorld = NULL; // set the time for shader effects in 2D rendering frameShaderTime = eventLoop->Milliseconds() * 0.001; @@ -644,23 +648,33 @@ void idRenderSystemLocal::BeginFrame( int windowWidth, int windowHeight ) { // // draw buffer stuff // - cmd = (setBufferCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) ); + cmd = ( setBufferCommand_t * )R_GetCommandBuffer( sizeof( *cmd ) ); cmd->commandId = RC_SET_BUFFER; cmd->frameCount = frameCount; if ( r_frontBuffer.GetBool() ) { - cmd->buffer = (int)GL_FRONT; + cmd->buffer = ( int )GL_FRONT; } else { - cmd->buffer = (int)GL_BACK; + cmd->buffer = ( int )GL_BACK; } } +/* +============= +WriteDemoPics +============= +*/ void idRenderSystemLocal::WriteDemoPics() { session->writeDemo->WriteInt( DS_RENDER ); session->writeDemo->WriteInt( DC_GUI_MODEL ); guiModel->WriteToDemo( session->writeDemo ); } +/* +============= +DrawDemoPics +============= +*/ void idRenderSystemLocal::DrawDemoPics() { demoGuiModel->EmitFullScreen(); } @@ -687,6 +701,7 @@ void idRenderSystemLocal::EndFrame( int *frontEndMsec, int *backEndMsec ) { if ( frontEndMsec ) { *frontEndMsec = pc.frontEndMsec; } + if ( backEndMsec ) { *backEndMsec = backEnd.pc.msec; } @@ -701,7 +716,7 @@ void idRenderSystemLocal::EndFrame( int *frontEndMsec, int *backEndMsec ) { GL_CheckErrors(); // add the swapbuffers command - cmd = (emptyCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) ); + cmd = ( emptyCommand_t * )R_GetCommandBuffer( sizeof( *cmd ) ); cmd->commandId = RC_SWAP_BUFFERS; // start the back end up again with the new command list @@ -709,7 +724,6 @@ void idRenderSystemLocal::EndFrame( int *frontEndMsec, int *backEndMsec ) { // use the other buffers next frame, because another CPU // may still be rendering into the current buffers - R_ToggleSmpFrame(); // we can now release the vertexes used this frame @@ -718,6 +732,7 @@ void idRenderSystemLocal::EndFrame( int *frontEndMsec, int *backEndMsec ) { if ( session->writeDemo ) { session->writeDemo->WriteInt( DS_RENDER ); session->writeDemo->WriteInt( DC_END_FRAME ); + if ( r_showDemo.GetBool() ) { common->Printf( "write DC_END_FRAME\n" ); } @@ -741,8 +756,8 @@ Converts from SCREEN_WIDTH / SCREEN_HEIGHT coordinates to current cropped pixel void idRenderSystemLocal::RenderViewToViewport( const renderView_t *renderView, idScreenRect *viewport ) { renderCrop_t *rc = &renderCrops[currentRenderCrop]; - float wRatio = (float)rc->width / SCREEN_WIDTH; - float hRatio = (float)rc->height / SCREEN_HEIGHT; + float wRatio = ( float )rc->width / SCREEN_WIDTH; + float hRatio = ( float )rc->height / SCREEN_HEIGHT; viewport->x1 = idMath::Ftoi( rc->x + renderView->x * wRatio ); viewport->x2 = idMath::Ftoi( rc->x + floor( ( renderView->x + renderView->width ) * wRatio + 0.5f ) - 1 ); @@ -750,6 +765,11 @@ void idRenderSystemLocal::RenderViewToViewport( const renderView_t *renderView, viewport->y2 = idMath::Ftoi( ( rc->y + rc->height ) - floor( renderView->y * hRatio + 0.5f ) - 1 ); } +/* +===================== +RoundDownToPowerOfTwo +===================== +*/ static int RoundDownToPowerOfTwo( int v ) { int i; @@ -757,11 +777,12 @@ static int RoundDownToPowerOfTwo( int v ) { if ( ( 1 << i ) == v ) { return v; } + if ( ( 1 << i ) > v ) { - return 1 << ( i-1 ); + return 1 << ( i - 1 ); } } - return 1< glConfig.vidWidth ) { width >>= 1; } + while ( height > glConfig.vidHeight ) { height >>= 1; } @@ -837,7 +858,6 @@ void idRenderSystemLocal::CropRenderSize( int width, int height, bool makePowerO if ( currentRenderCrop == MAX_RENDER_CROPS ) { common->Error( "idRenderSystemLocal::CropRenderSize: currentRenderCrop == MAX_RENDER_CROPS" ); } - currentRenderCrop++; rc = &renderCrops[currentRenderCrop]; @@ -902,11 +922,9 @@ void idRenderSystemLocal::CaptureRenderToImage( const char *imageName ) { // look up the image before we create the render command, because it // may need to sync to create the image - idImage *image = globalImages->ImageFromFile(imageName, TF_DEFAULT, true, TR_REPEAT, TD_DEFAULT); - - renderCrop_t *rc = &renderCrops[currentRenderCrop]; - - copyRenderCommand_t *cmd = (copyRenderCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) ); + idImage *image = globalImages->ImageFromFile( imageName, TF_DEFAULT, true, TR_REPEAT, TD_DEFAULT ); + renderCrop_t *rc = &renderCrops[currentRenderCrop]; + copyRenderCommand_t *cmd = ( copyRenderCommand_t * )R_GetCommandBuffer( sizeof( *cmd ) ); cmd->commandId = RC_COPY_RENDER; cmd->x = rc->x; cmd->y = rc->y; @@ -927,7 +945,6 @@ void idRenderSystemLocal::CaptureRenderToFile( const char *fileName, bool fixAlp if ( !glConfig.isInitialized ) { return; } - renderCrop_t *rc = &renderCrops[currentRenderCrop]; guiModel->EmitFullScreen(); @@ -938,11 +955,11 @@ void idRenderSystemLocal::CaptureRenderToFile( const char *fileName, bool fixAlp // include extra space for OpenGL padding to word boundaries int c = ( rc->width + 3 ) * rc->height; - byte *data = (byte *)R_StaticAlloc( c * 3 ); + byte *data = ( byte * )R_StaticAlloc( c * 3 ); qglReadPixels( rc->x, rc->y, rc->width, rc->height, GL_RGB, GL_UNSIGNED_BYTE, data ); - byte *data2 = (byte *)R_StaticAlloc( c * 4 ); + byte *data2 = ( byte * )R_StaticAlloc( c * 4 ); for ( int i = 0 ; i < c ; i++ ) { data2[ i * 4 ] = data[ i * 3 ]; @@ -950,14 +967,12 @@ void idRenderSystemLocal::CaptureRenderToFile( const char *fileName, bool fixAlp data2[ i * 4 + 2 ] = data[ i * 3 + 2 ]; data2[ i * 4 + 3 ] = 0xff; } - R_WriteTGA( fileName, data2, rc->width, rc->height, true ); R_StaticFree( data ); R_StaticFree( data2 ); } - /* ============== AllocRenderWorld @@ -979,7 +994,7 @@ void idRenderSystemLocal::FreeRenderWorld( idRenderWorld *rw ) { if ( primaryWorld == rw ) { primaryWorld = NULL; } - worlds.Remove( static_cast(rw) ); + worlds.Remove( static_cast( rw ) ); delete rw; } @@ -994,9 +1009,6 @@ void idRenderSystemLocal::PrintMemInfo( MemInfo_t *mi ) { // sum up model totals renderModelManager->PrintMemInfo( mi ); - - // compute render totals - } /* @@ -1004,8 +1016,9 @@ void idRenderSystemLocal::PrintMemInfo( MemInfo_t *mi ) { idRenderSystemLocal::UploadImage =============== */ -bool idRenderSystemLocal::UploadImage( const char *imageName, const byte *data, int width, int height ) { +bool idRenderSystemLocal::UploadImage( const char *imageName, const byte *data, int width, int height ) { idImage *image = globalImages->GetImage( imageName ); + if ( !image ) { return false; } diff --git a/neo/renderer/RenderSystem.h b/neo/renderer/RenderSystem.h index 1474ee4f2..d741b98ce 100644 --- a/neo/renderer/RenderSystem.h +++ b/neo/renderer/RenderSystem.h @@ -41,6 +41,12 @@ If you have questions concerning this license or the applicable additional terms =============================================================================== */ +enum glVendor_t { + glvAny, + glvAMD, + glvIntel, + glvNVIDIA, +}; // Contains variables specific to the OpenGL configuration being run right now. // These are constant once the OpenGL subsystem is initialized. @@ -51,7 +57,7 @@ typedef struct glconfig_s { const char *extensions_string; float glVersion; // atof( version_string ) - + glVendor_t vendor; int maxTextureSize; // queried from GL int maxTextureUnits; @@ -72,9 +78,11 @@ typedef struct glconfig_s { bool envDot3Available; bool texture3DAvailable; bool sharedTexturePaletteAvailable; - bool ARBVertexBufferObjectAvailable; bool ARBVertexProgramAvailable; bool ARBFragmentProgramAvailable; + bool ARBMapBufferRangeAvailable; + bool ARBShadingLanguageAvailable; + bool ARBVertexBufferObjectAvailable; bool twoSidedStencilAvailable; bool textureNonPowerOfTwoAvailable; bool depthBoundsTestAvailable; diff --git a/neo/renderer/RenderSystem_init.cpp b/neo/renderer/RenderSystem_init.cpp index 58b47a5ee..fb97139ad 100644 --- a/neo/renderer/RenderSystem_init.cpp +++ b/neo/renderer/RenderSystem_init.cpp @@ -37,9 +37,7 @@ If you have questions concerning this license or the applicable additional terms #include "renderer/GuiModel.h" #include "sound/sound.h" #include "ui/UserInterface.h" - #include "renderer/tr_local.h" - #include "framework/GameCallbacks_local.h" // Vista OpenGL wrapper check @@ -50,7 +48,6 @@ If you have questions concerning this license or the applicable additional terms #include "stb_image_write.h" // functions that are not called every frame - glconfig_t glConfig; const char *r_rendererArgs[] = { "best", "arb2", NULL }; @@ -79,8 +76,9 @@ idCVar r_useTwoSidedStencil( "r_useTwoSidedStencil", "1", CVAR_RENDERER | CVAR_B idCVar r_useDeferredTangents( "r_useDeferredTangents", "1", CVAR_RENDERER | CVAR_BOOL, "defer tangents calculations after deform" ); idCVar r_useCachedDynamicModels( "r_useCachedDynamicModels", "1", CVAR_RENDERER | CVAR_BOOL, "cache snapshots of dynamic models" ); -idCVar r_useVertexBuffers( "r_useVertexBuffers", "1", CVAR_RENDERER | CVAR_INTEGER, "use ARB_vertex_buffer_object for vertexes", 0, 1, idCmdSystem::ArgCompletion_Integer<0,1> ); -idCVar r_useIndexBuffers( "r_useIndexBuffers", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "use ARB_vertex_buffer_object for indexes", 0, 1, idCmdSystem::ArgCompletion_Integer<0,1> ); +idCVar r_useVertexBuffers( "r_useVertexBuffers", "1", CVAR_RENDERER | CVAR_INTEGER, "use ARB_vertex_buffer_object for vertexes", 0, 1, idCmdSystem::ArgCompletion_Integer<0, 1> ); +idCVar r_useIndexBuffers( "r_useIndexBuffers", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "use ARB_vertex_buffer_object for indexes", 0, 1, idCmdSystem::ArgCompletion_Integer<0, 1> ); +idCVar r_useGLSL( "r_useGLSL", "0", CVAR_RENDERER | CVAR_BOOL | CVAR_ARCHIVE, "use GLSL backend for interaction passes" ); idCVar r_useStateCaching( "r_useStateCaching", "1", CVAR_RENDERER | CVAR_BOOL, "avoid redundant state changes in GL_*() calls" ); idCVar r_useInfiniteFarZ( "r_useInfiniteFarZ", "1", CVAR_RENDERER | CVAR_BOOL, "use the no-far-clip-plane trick" ); @@ -93,7 +91,7 @@ idCVar r_swapInterval( "r_swapInterval", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVA idCVar r_gamma( "r_gamma", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "changes gamma tables", 0.5f, 3.0f ); idCVar r_brightness( "r_brightness", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "changes gamma tables", 0.5f, 2.0f ); -idCVar r_gammaInShader( "r_gammaInShader", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Set gamma and brightness in shaders instead using hardware gamma" ); +idCVar r_gammaInShader( "r_gammaInShader", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Set gamma and brightness in shaders instead using hardware gamma" ); idCVar r_renderer( "r_renderer", "best", CVAR_RENDERER | CVAR_ARCHIVE, "hardware specific renderer path to use", r_rendererArgs, idCmdSystem::ArgCompletion_String ); @@ -125,14 +123,14 @@ idCVar r_skipROQ( "r_skipROQ", "0", CVAR_RENDERER | CVAR_BOOL, "skip ROQ decodin idCVar r_ignore( "r_ignore", "0", CVAR_RENDERER, "used for random debugging without defining new vars" ); idCVar r_ignore2( "r_ignore2", "0", CVAR_RENDERER, "used for random debugging without defining new vars" ); idCVar r_usePreciseTriangleInteractions( "r_usePreciseTriangleInteractions", "0", CVAR_RENDERER | CVAR_BOOL, "1 = do winding clipping to determine if each ambiguous tri should be lit" ); -idCVar r_useCulling( "r_useCulling", "2", CVAR_RENDERER | CVAR_INTEGER, "0 = none, 1 = sphere, 2 = sphere + box", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> ); -idCVar r_useLightCulling( "r_useLightCulling", "3", CVAR_RENDERER | CVAR_INTEGER, "0 = none, 1 = box, 2 = exact clip of polyhedron faces, 3 = also areas", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> ); +idCVar r_useCulling( "r_useCulling", "2", CVAR_RENDERER | CVAR_INTEGER, "0 = none, 1 = sphere, 2 = sphere + box", 0, 2, idCmdSystem::ArgCompletion_Integer<0, 2> ); +idCVar r_useLightCulling( "r_useLightCulling", "3", CVAR_RENDERER | CVAR_INTEGER, "0 = none, 1 = box, 2 = exact clip of polyhedron faces, 3 = also areas", 0, 3, idCmdSystem::ArgCompletion_Integer<0, 3> ); idCVar r_useLightScissors( "r_useLightScissors", "1", CVAR_RENDERER | CVAR_BOOL, "1 = use custom scissor rectangle for each light" ); -idCVar r_useClippedLightScissors( "r_useClippedLightScissors", "1", CVAR_RENDERER | CVAR_INTEGER, "0 = full screen when near clipped, 1 = exact when near clipped, 2 = exact always", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> ); +idCVar r_useClippedLightScissors( "r_useClippedLightScissors", "1", CVAR_RENDERER | CVAR_INTEGER, "0 = full screen when near clipped, 1 = exact when near clipped, 2 = exact always", 0, 2, idCmdSystem::ArgCompletion_Integer<0, 2> ); idCVar r_useEntityCulling( "r_useEntityCulling", "1", CVAR_RENDERER | CVAR_BOOL, "0 = none, 1 = box" ); idCVar r_useEntityScissors( "r_useEntityScissors", "0", CVAR_RENDERER | CVAR_BOOL, "1 = use custom scissor rectangle for each entity" ); idCVar r_useInteractionCulling( "r_useInteractionCulling", "1", CVAR_RENDERER | CVAR_BOOL, "1 = cull interactions" ); -idCVar r_useInteractionScissors( "r_useInteractionScissors", "2", CVAR_RENDERER | CVAR_INTEGER, "1 = use a custom scissor rectangle for each shadow interaction, 2 = also crop using portal scissors", -2, 2, idCmdSystem::ArgCompletion_Integer<-2,2> ); +idCVar r_useInteractionScissors( "r_useInteractionScissors", "2", CVAR_RENDERER | CVAR_INTEGER, "1 = use a custom scissor rectangle for each shadow interaction, 2 = also crop using portal scissors", -2, 2, idCmdSystem::ArgCompletion_Integer < -2, 2 > ); idCVar r_useShadowCulling( "r_useShadowCulling", "1", CVAR_RENDERER | CVAR_BOOL, "try to cull shadows from partially visible lights" ); idCVar r_useFrustumFarDistance( "r_useFrustumFarDistance", "0", CVAR_RENDERER | CVAR_FLOAT, "if != 0 force the view frustum far distance to this distance" ); idCVar r_clear( "r_clear", "2", CVAR_RENDERER, "force screen clear every frame, 1 = purple, 2 = black, 'r g b' = custom" ); @@ -142,8 +140,8 @@ idCVar r_shadowPolygonOffset( "r_shadowPolygonOffset", "-1", CVAR_RENDERER | CVA idCVar r_shadowPolygonFactor( "r_shadowPolygonFactor", "0", CVAR_RENDERER | CVAR_FLOAT, "scale value for stencil shadow drawing" ); idCVar r_frontBuffer( "r_frontBuffer", "0", CVAR_RENDERER | CVAR_BOOL, "draw to front buffer for debugging" ); idCVar r_skipSubviews( "r_skipSubviews", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = don't render any gui elements on surfaces" ); -idCVar r_skipGuiShaders( "r_skipGuiShaders", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = skip all gui elements on surfaces, 2 = skip drawing but still handle events, 3 = draw but skip events", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> ); -idCVar r_skipParticles( "r_skipParticles", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = skip all particle systems", 0, 1, idCmdSystem::ArgCompletion_Integer<0,1> ); +idCVar r_skipGuiShaders( "r_skipGuiShaders", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = skip all gui elements on surfaces, 2 = skip drawing but still handle events, 3 = draw but skip events", 0, 3, idCmdSystem::ArgCompletion_Integer<0, 3> ); +idCVar r_skipParticles( "r_skipParticles", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = skip all particle systems", 0, 1, idCmdSystem::ArgCompletion_Integer<0, 1> ); idCVar r_subviewOnly( "r_subviewOnly", "0", CVAR_RENDERER | CVAR_BOOL, "1 = don't render main view, allowing subviews to be debugged" ); idCVar r_shadows( "r_shadows", "1", CVAR_RENDERER | CVAR_BOOL | CVAR_ARCHIVE, "enable shadows" ); idCVar r_testARBProgram( "r_testARBProgram", "0", CVAR_RENDERER | CVAR_BOOL, "experiment with vertex/fragment programs" ); @@ -154,7 +152,7 @@ idCVar r_lightScale( "r_lightScale", "2", CVAR_RENDERER | CVAR_FLOAT, "all light idCVar r_lightSourceRadius( "r_lightSourceRadius", "0", CVAR_RENDERER | CVAR_FLOAT, "for soft-shadow sampling" ); idCVar r_flareSize( "r_flareSize", "1", CVAR_RENDERER | CVAR_FLOAT, "scale the flare deforms from the material def" ); -idCVar r_useExternalShadows( "r_useExternalShadows", "1", CVAR_RENDERER | CVAR_INTEGER, "1 = skip drawing caps when outside the light volume, 2 = force to no caps for testing", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> ); +idCVar r_useExternalShadows( "r_useExternalShadows", "1", CVAR_RENDERER | CVAR_INTEGER, "1 = skip drawing caps when outside the light volume, 2 = force to no caps for testing", 0, 2, idCmdSystem::ArgCompletion_Integer<0, 2> ); idCVar r_useOptimizedShadows( "r_useOptimizedShadows", "1", CVAR_RENDERER | CVAR_BOOL, "use the dmap generated static shadow volumes" ); idCVar r_useScissor( "r_useScissor", "1", CVAR_RENDERER | CVAR_BOOL, "scissor clip as portals and lights are processed" ); idCVar r_useCombinerDisplayLists( "r_useCombinerDisplayLists", "1", CVAR_RENDERER | CVAR_BOOL | CVAR_NOCHEAT, "put all nvidia register combiner programming in display lists" ); @@ -181,20 +179,20 @@ idCVar r_showDemo( "r_showDemo", "0", CVAR_RENDERER | CVAR_BOOL, "report reads a idCVar r_showDynamic( "r_showDynamic", "0", CVAR_RENDERER | CVAR_BOOL, "report stats on dynamic surface generation" ); idCVar r_showLightScale( "r_showLightScale", "0", CVAR_RENDERER | CVAR_BOOL, "report the scale factor applied to drawing for overbrights" ); idCVar r_showDefs( "r_showDefs", "0", CVAR_RENDERER | CVAR_BOOL, "report the number of modeDefs and lightDefs in view" ); -idCVar r_showTrace( "r_showTrace", "0", CVAR_RENDERER | CVAR_INTEGER, "show the intersection of an eye trace with the world", idCmdSystem::ArgCompletion_Integer<0,2> ); +idCVar r_showTrace( "r_showTrace", "0", CVAR_RENDERER | CVAR_INTEGER, "show the intersection of an eye trace with the world", idCmdSystem::ArgCompletion_Integer<0, 2> ); idCVar r_showIntensity( "r_showIntensity", "0", CVAR_RENDERER | CVAR_BOOL, "draw the screen colors based on intensity, red = 0, green = 128, blue = 255" ); -idCVar r_showImages( "r_showImages", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = show all images instead of rendering, 2 = show in proportional size", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> ); +idCVar r_showImages( "r_showImages", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = show all images instead of rendering, 2 = show in proportional size", 0, 2, idCmdSystem::ArgCompletion_Integer<0, 2> ); idCVar r_showSmp( "r_showSmp", "0", CVAR_RENDERER | CVAR_BOOL, "show which end (front or back) is blocking" ); -idCVar r_showLights( "r_showLights", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = just print volumes numbers, highlighting ones covering the view, 2 = also draw planes of each volume, 3 = also draw edges of each volume", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> ); -idCVar r_showShadows( "r_showShadows", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = visualize the stencil shadow volumes, 2 = draw filled in", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> ); -idCVar r_showShadowCount( "r_showShadowCount", "0", CVAR_RENDERER | CVAR_INTEGER, "colors screen based on shadow volume depth complexity, >= 2 = print overdraw count based on stencil index values, 3 = only show turboshadows, 4 = only show static shadows", 0, 4, idCmdSystem::ArgCompletion_Integer<0,4> ); +idCVar r_showLights( "r_showLights", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = just print volumes numbers, highlighting ones covering the view, 2 = also draw planes of each volume, 3 = also draw edges of each volume", 0, 3, idCmdSystem::ArgCompletion_Integer<0, 3> ); +idCVar r_showShadows( "r_showShadows", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = visualize the stencil shadow volumes, 2 = draw filled in", 0, 3, idCmdSystem::ArgCompletion_Integer<0, 3> ); +idCVar r_showShadowCount( "r_showShadowCount", "0", CVAR_RENDERER | CVAR_INTEGER, "colors screen based on shadow volume depth complexity, >= 2 = print overdraw count based on stencil index values, 3 = only show turboshadows, 4 = only show static shadows", 0, 4, idCmdSystem::ArgCompletion_Integer<0, 4> ); idCVar r_showLightScissors( "r_showLightScissors", "0", CVAR_RENDERER | CVAR_BOOL, "show light scissor rectangles" ); idCVar r_showEntityScissors( "r_showEntityScissors", "0", CVAR_RENDERER | CVAR_BOOL, "show entity scissor rectangles" ); -idCVar r_showInteractionFrustums( "r_showInteractionFrustums", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = show a frustum for each interaction, 2 = also draw lines to light origin, 3 = also draw entity bbox", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> ); -idCVar r_showInteractionScissors( "r_showInteractionScissors", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = show screen rectangle which contains the interaction frustum, 2 = also draw construction lines", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> ); -idCVar r_showLightCount( "r_showLightCount", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = colors surfaces based on light count, 2 = also count everything through walls, 3 = also print overdraw", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> ); +idCVar r_showInteractionFrustums( "r_showInteractionFrustums", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = show a frustum for each interaction, 2 = also draw lines to light origin, 3 = also draw entity bbox", 0, 3, idCmdSystem::ArgCompletion_Integer<0, 3> ); +idCVar r_showInteractionScissors( "r_showInteractionScissors", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = show screen rectangle which contains the interaction frustum, 2 = also draw construction lines", 0, 2, idCmdSystem::ArgCompletion_Integer<0, 2> ); +idCVar r_showLightCount( "r_showLightCount", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = colors surfaces based on light count, 2 = also count everything through walls, 3 = also print overdraw", 0, 3, idCmdSystem::ArgCompletion_Integer<0, 3> ); idCVar r_showViewEntitys( "r_showViewEntitys", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = displays the bounding boxes of all view models, 2 = print index numbers" ); -idCVar r_showTris( "r_showTris", "0", CVAR_RENDERER | CVAR_INTEGER, "enables wireframe rendering of the world, 1 = only draw visible ones, 2 = draw all front facing, 3 = draw all", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> ); +idCVar r_showTris( "r_showTris", "0", CVAR_RENDERER | CVAR_INTEGER, "enables wireframe rendering of the world, 1 = only draw visible ones, 2 = draw all front facing, 3 = draw all", 0, 3, idCmdSystem::ArgCompletion_Integer<0, 3> ); idCVar r_showSurfaceInfo( "r_showSurfaceInfo", "0", CVAR_RENDERER | CVAR_BOOL, "show surface material name under crosshair" ); idCVar r_showNormals( "r_showNormals", "0", CVAR_RENDERER | CVAR_FLOAT, "draws wireframe normals" ); idCVar r_showMemory( "r_showMemory", "0", CVAR_RENDERER | CVAR_BOOL, "print frame memory utilization" ); @@ -205,16 +203,16 @@ idCVar r_showSurfaces( "r_showSurfaces", "0", CVAR_RENDERER | CVAR_BOOL, "report idCVar r_showPrimitives( "r_showPrimitives", "0", CVAR_RENDERER | CVAR_INTEGER, "report drawsurf/index/vertex counts" ); idCVar r_showEdges( "r_showEdges", "0", CVAR_RENDERER | CVAR_BOOL, "draw the sil edges" ); idCVar r_showTexturePolarity( "r_showTexturePolarity", "0", CVAR_RENDERER | CVAR_BOOL, "shade triangles by texture area polarity" ); -idCVar r_showTangentSpace( "r_showTangentSpace", "0", CVAR_RENDERER | CVAR_INTEGER, "shade triangles by tangent space, 1 = use 1st tangent vector, 2 = use 2nd tangent vector, 3 = use normal vector", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> ); +idCVar r_showTangentSpace( "r_showTangentSpace", "0", CVAR_RENDERER | CVAR_INTEGER, "shade triangles by tangent space, 1 = use 1st tangent vector, 2 = use 2nd tangent vector, 3 = use normal vector", 0, 3, idCmdSystem::ArgCompletion_Integer<0, 3> ); idCVar r_showDominantTri( "r_showDominantTri", "0", CVAR_RENDERER | CVAR_BOOL, "draw lines from vertexes to center of dominant triangles" ); idCVar r_showAlloc( "r_showAlloc", "0", CVAR_RENDERER | CVAR_BOOL, "report alloc/free counts" ); idCVar r_showTextureVectors( "r_showTextureVectors", "0", CVAR_RENDERER | CVAR_FLOAT, " if > 0 draw each triangles texture (tangent) vectors" ); -idCVar r_showOverDraw( "r_showOverDraw", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = geometry overdraw, 2 = light interaction overdraw, 3 = geometry and light interaction overdraw", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> ); +idCVar r_showOverDraw( "r_showOverDraw", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = geometry overdraw, 2 = light interaction overdraw, 3 = geometry and light interaction overdraw", 0, 3, idCmdSystem::ArgCompletion_Integer<0, 3> ); idCVar r_lockSurfaces( "r_lockSurfaces", "0", CVAR_RENDERER | CVAR_BOOL, "allow moving the view point without changing the composition of the scene, including culling" ); idCVar r_useEntityCallbacks( "r_useEntityCallbacks", "1", CVAR_RENDERER | CVAR_BOOL, "if 0, issue the callback immediately at update time, rather than defering" ); -idCVar r_showSkel( "r_showSkel", "0", CVAR_RENDERER | CVAR_INTEGER, "draw the skeleton when model animates, 1 = draw model with skeleton, 2 = draw skeleton only", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> ); +idCVar r_showSkel( "r_showSkel", "0", CVAR_RENDERER | CVAR_INTEGER, "draw the skeleton when model animates, 1 = draw model with skeleton, 2 = draw skeleton only", 0, 2, idCmdSystem::ArgCompletion_Integer<0, 2> ); idCVar r_jointNameScale( "r_jointNameScale", "0.02", CVAR_RENDERER | CVAR_FLOAT, "size of joint names when r_showskel is set to 1" ); idCVar r_jointNameOffset( "r_jointNameOffset", "0.5", CVAR_RENDERER | CVAR_FLOAT, "offset of joint names when r_showskel is set to 1" ); @@ -232,16 +230,15 @@ idCVar r_scaleMenusTo43( "r_scaleMenusTo43", "1", CVAR_RENDERER | CVAR_ARCHIVE | // DG: the fscking patent has finally expired idCVar r_useCarmacksReverse( "r_useCarmacksReverse", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Use Z-Fail (Carmack's Reverse) when rendering shadows" ); idCVar r_useStencilOpSeparate( "r_useStencilOpSeparate", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Use glStencilOpSeparate() (if available) when rendering shadows" ); -idCVar r_screenshotFormat("r_screenshotFormat", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "Screenshot format. 0 = TGA (default), 1 = BMP, 2 = PNG, 3 = JPG"); -idCVar r_screenshotJpgQuality("r_screenshotJpgQuality", "75", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "Screenshot quality for JPG images (1-100). Lower value means smaller file but worse quality"); -idCVar r_screenshotPngCompression("r_screenshotPngCompression", "3", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "Compression level when using PNG screenshots (0-9). Higher levels generate smaller files, but take noticeably longer"); +idCVar r_screenshotFormat( "r_screenshotFormat", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "Screenshot format. 0 = TGA (default), 1 = BMP, 2 = PNG, 3 = JPG" ); +idCVar r_screenshotJpgQuality( "r_screenshotJpgQuality", "75", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "Screenshot quality for JPG images (1-100). Lower value means smaller file but worse quality" ); +idCVar r_screenshotPngCompression( "r_screenshotPngCompression", "3", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "Compression level when using PNG screenshots (0-9). Higher levels generate smaller files, but take noticeably longer" ); // DG: allow freely resizing the window -idCVar r_windowResizable("r_windowResizable", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Allow resizing (and maximizing) the window (needs SDL2; with 2.0.5 or newer it's applied immediately)" ); +idCVar r_windowResizable( "r_windowResizable", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Allow resizing (and maximizing) the window (needs SDL2; with 2.0.5 or newer it's applied immediately)" ); idCVar r_vidRestartAlwaysFull( "r_vidRestartAlwaysFull", 0, CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Always do a full vid_restart (ignore 'partial' argument), e.g. when changing window size" ); // DG: for soft particles (ported from TDM) -idCVar r_enableDepthCapture( "r_enableDepthCapture", "-1", CVAR_RENDERER | CVAR_INTEGER, - "enable capturing depth buffer to texture. -1: enable automatically (if soft particles are enabled), 0: disable, 1: enable", -1, 1 ); // #3877 +idCVar r_enableDepthCapture( "r_enableDepthCapture", "-1", CVAR_RENDERER | CVAR_INTEGER, "enable capturing depth buffer to texture. -1: enable automatically (if soft particles are enabled), 0: disable, 1: enable", -1, 1 ); // #3877 idCVar r_useSoftParticles( "r_useSoftParticles", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Soften particle transitions when player walks through them or they cross solid geometry. Needs r_enableDepthCapture. Can slow down rendering!" ); // #3878 idCVar r_glDebugContext( "r_glDebugContext", "0", CVAR_RENDERER | CVAR_BOOL, "Enable OpenGL Debug context - requires vid_restart, needs SDL2" ); @@ -250,14 +247,14 @@ idCVar r_glDebugContext( "r_glDebugContext", "0", CVAR_RENDERER | CVAR_BOOL, "En #define QGLPROC(name, rettype, args) rettype (APIENTRYP q##name) args; #include "renderer/qgl_proc.h" -void ( APIENTRY * qglMultiTexCoord2fARB )( GLenum texture, GLfloat s, GLfloat t ); -void ( APIENTRY * qglMultiTexCoord2fvARB )( GLenum texture, GLfloat *st ); -void ( APIENTRY * qglActiveTextureARB )( GLenum texture ); -void ( APIENTRY * qglClientActiveTextureARB )( GLenum texture ); +void ( APIENTRY *qglMultiTexCoord2fARB )( GLenum texture, GLfloat s, GLfloat t ); +void ( APIENTRY *qglMultiTexCoord2fvARB )( GLenum texture, GLfloat *st ); +void ( APIENTRY *qglActiveTextureARB )( GLenum texture ); +void ( APIENTRY *qglClientActiveTextureARB )( GLenum texture ); -void (APIENTRY *qglTexImage3D)(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); +void ( APIENTRY *qglTexImage3D )( GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid * ); -void (APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * ); +void ( APIENTRY *qglColorTableEXT )( int, int, int, int, int, const void * ); // EXT_stencil_two_side PFNGLACTIVESTENCILFACEEXTPROC qglActiveStencilFaceEXT; @@ -266,6 +263,60 @@ PFNGLACTIVESTENCILFACEEXTPROC qglActiveStencilFaceEXT; PFNGLCOMPRESSEDTEXIMAGE2DARBPROC qglCompressedTexImage2DARB; PFNGLGETCOMPRESSEDTEXIMAGEARBPROC qglGetCompressedTexImageARB; +// ARB_MapBufferRange +PFNGLFLUSHMAPPEDBUFFERRANGEPROC qglFlushMappedBufferRange; +PFNGLMAPBUFFERRANGEPROC qglMapBufferRange; + +// ARB_shading_language_100 +PFNGLUNIFORM1FPROC qglUniform1f; +PFNGLUNIFORM1FVPROC qglUniform1fv; +PFNGLUNIFORM1IPROC qglUniform1i; +PFNGLUNIFORM1IVPROC qglUniform1iv; +PFNGLUNIFORM2FPROC qglUniform2f; +PFNGLUNIFORM2FVPROC qglUniform2fv; +PFNGLUNIFORM2IPROC qglUniform2i; +PFNGLUNIFORM2IVPROC qglUniform2iv; +PFNGLUNIFORM3FPROC qglUniform3f; +PFNGLUNIFORM3FVPROC qglUniform3fv; +PFNGLUNIFORM3IPROC qglUniform3i; +PFNGLUNIFORM3IVPROC qglUniform3iv; +PFNGLUNIFORM4FPROC qglUniform4f; +PFNGLUNIFORM4FVPROC qglUniform4fv; +PFNGLUNIFORM4IPROC qglUniform4i; +PFNGLUNIFORM4IVPROC qglUniform4iv; +PFNGLUNIFORMMATRIX2FVPROC qglUniformMatrix2fv; +PFNGLUNIFORMMATRIX3FVPROC qglUniformMatrix3fv; +PFNGLUNIFORMMATRIX4FVPROC qglUniformMatrix4fv; +PFNGLUNIFORMMATRIX2X3FVPROC qglUniformMatrix2x3fv; +PFNGLUNIFORMMATRIX2X4FVPROC qglUniformMatrix2x4fv; +PFNGLUNIFORMMATRIX3X2FVPROC qglUniformMatrix3x2fv; +PFNGLUNIFORMMATRIX3X4FVPROC qglUniformMatrix3x4fv; +PFNGLUNIFORMMATRIX4X2FVPROC qglUniformMatrix4x2fv; +PFNGLUNIFORMMATRIX4X3FVPROC qglUniformMatrix4x3fv; + +PFNGLISPROGRAMPROC qglIsProgram; +PFNGLCREATEPROGRAMPROC qglCreateProgram; +PFNGLVALIDATEPROGRAMPROC qglValidateProgram; +PFNGLLINKPROGRAMPROC qglLinkProgram; + +PFNGLISSHADERPROC qglIsShader; +PFNGLSHADERSOURCEPROC qglShaderSource; +PFNGLCREATESHADERPROC qglCreateShader; +PFNGLATTACHSHADERPROC qglAttachShader; +PFNGLBINDATTRIBLOCATIONPROC qglBindAttribLocation; +PFNGLCOMPILESHADERPROC qglCompileShader; +PFNGLDETACHSHADERPROC qglDetachShader; +PFNGLDELETESHADERPROC qglDeleteShader; + +PFNGLGETPROGRAMINFOLOGPROC qglGetProgramInfoLog; +PFNGLGETPROGRAMIVPROC qglGetProgramiv; +PFNGLGETSHADERINFOLOGPROC qglGetShaderInfoLog; +PFNGLGETSHADERSOURCEPROC qglGetShaderSource; +PFNGLGETSHADERIVPROC qglGetShaderiv; +PFNGLGETUNIFORMLOCATIONPROC qglGetUniformLocation; +PFNGLGETUNIFORMFVPROC qglGetUniformfv; +PFNGLGETUNIFORMIVPROC qglGetUniformiv; + // ARB_vertex_buffer_object PFNGLBINDBUFFERARBPROC qglBindBufferARB; PFNGLDELETEBUFFERSARBPROC qglDeleteBuffersARB; @@ -316,48 +367,43 @@ enum { */ static void APIENTRY DebugCallback( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, - const GLchar *message, const void *userParam ) -{ - const char* sourceStr = "Source: Unknown"; - const char* typeStr = "Type: Unknown"; - const char* severityStr = "Severity: Unknown"; - - switch (severity) - { + const GLchar *message, const void *userParam ) { + const char *sourceStr = "Source: Unknown"; + const char *typeStr = "Type: Unknown"; + const char *severityStr = "Severity: Unknown"; + + switch ( severity ) { #define SVRCASE(X, STR) case GL_DEBUG_SEVERITY_ ## X ## _ARB : severityStr = STR; break; - case QGL_DEBUG_SEVERITY_NOTIFICATION: return; - SVRCASE(HIGH, "Severity: High") - SVRCASE(MEDIUM, "Severity: Medium") - SVRCASE(LOW, "Severity: Low") + case QGL_DEBUG_SEVERITY_NOTIFICATION: + return; + SVRCASE( HIGH, "Severity: High" ) + SVRCASE( MEDIUM, "Severity: Medium" ) + SVRCASE( LOW, "Severity: Low" ) #undef SVRCASE } - switch (source) - { + switch ( source ) { #define SRCCASE(X) case GL_DEBUG_SOURCE_ ## X ## _ARB: sourceStr = "Source: " #X; break; - SRCCASE(API); - SRCCASE(WINDOW_SYSTEM); - SRCCASE(SHADER_COMPILER); - SRCCASE(THIRD_PARTY); - SRCCASE(APPLICATION); - SRCCASE(OTHER); + SRCCASE( API ); + SRCCASE( WINDOW_SYSTEM ); + SRCCASE( SHADER_COMPILER ); + SRCCASE( THIRD_PARTY ); + SRCCASE( APPLICATION ); + SRCCASE( OTHER ); #undef SRCCASE } - switch(type) - { + switch ( type ) { #define TYPECASE(X) case GL_DEBUG_TYPE_ ## X ## _ARB: typeStr = "Type: " #X; break; - TYPECASE(ERROR); - TYPECASE(DEPRECATED_BEHAVIOR); - TYPECASE(UNDEFINED_BEHAVIOR); - TYPECASE(PORTABILITY); - TYPECASE(PERFORMANCE); - TYPECASE(OTHER); + TYPECASE( ERROR ); + TYPECASE( DEPRECATED_BEHAVIOR ); + TYPECASE( UNDEFINED_BEHAVIOR ); + TYPECASE( PORTABILITY ); + TYPECASE( PERFORMANCE ); + TYPECASE( OTHER ); #undef TYPECASE } - common->Warning( "GLDBG %s %s %s: %s\n", sourceStr, typeStr, severityStr, message ); - } /* @@ -370,7 +416,6 @@ bool R_CheckExtension( const char *name ) { common->Printf( "X..%s not found\n", name ); return false; } - common->Printf( "...using %s\n", name ); return true; } @@ -386,20 +431,23 @@ static void R_CheckPortableExtensions( void ) { // GL_ARB_multitexture glConfig.multitextureAvailable = R_CheckExtension( "GL_ARB_multitexture" ); + if ( glConfig.multitextureAvailable ) { - qglMultiTexCoord2fARB = (void(APIENTRY *)(GLenum, GLfloat, GLfloat))GLimp_ExtensionPointer( "glMultiTexCoord2fARB" ); - qglMultiTexCoord2fvARB = (void(APIENTRY *)(GLenum, GLfloat *))GLimp_ExtensionPointer( "glMultiTexCoord2fvARB" ); - qglActiveTextureARB = (void(APIENTRY *)(GLenum))GLimp_ExtensionPointer( "glActiveTextureARB" ); - qglClientActiveTextureARB = (void(APIENTRY *)(GLenum))GLimp_ExtensionPointer( "glClientActiveTextureARB" ); - qglGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, (GLint *)&glConfig.maxTextureUnits ); + qglMultiTexCoord2fARB = ( void( APIENTRY * )( GLenum, GLfloat, GLfloat ) )GLimp_ExtensionPointer( "glMultiTexCoord2fARB" ); + qglMultiTexCoord2fvARB = ( void( APIENTRY * )( GLenum, GLfloat * ) )GLimp_ExtensionPointer( "glMultiTexCoord2fvARB" ); + qglActiveTextureARB = ( void( APIENTRY * )( GLenum ) )GLimp_ExtensionPointer( "glActiveTextureARB" ); + qglClientActiveTextureARB = ( void( APIENTRY * )( GLenum ) )GLimp_ExtensionPointer( "glClientActiveTextureARB" ); + qglGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, ( GLint * )&glConfig.maxTextureUnits ); + if ( glConfig.maxTextureUnits > MAX_MULTITEXTURE_UNITS ) { glConfig.maxTextureUnits = MAX_MULTITEXTURE_UNITS; } + if ( glConfig.maxTextureUnits < 2 ) { glConfig.multitextureAvailable = false; // shouldn't ever happen } - qglGetIntegerv( GL_MAX_TEXTURE_COORDS_ARB, (GLint *)&glConfig.maxTextureCoords ); - qglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS_ARB, (GLint *)&glConfig.maxTextureImageUnits ); + qglGetIntegerv( GL_MAX_TEXTURE_COORDS_ARB, ( GLint * )&glConfig.maxTextureCoords ); + qglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS_ARB, ( GLint * )&glConfig.maxTextureImageUnits ); } // GL_ARB_texture_env_combine @@ -421,14 +469,15 @@ static void R_CheckPortableExtensions( void ) { // DRI drivers may have GL_ARB_texture_compression but no GL_EXT_texture_compression_s3tc if ( R_CheckExtension( "GL_ARB_texture_compression" ) && R_CheckExtension( "GL_EXT_texture_compression_s3tc" ) ) { glConfig.textureCompressionAvailable = true; - qglCompressedTexImage2DARB = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)GLimp_ExtensionPointer( "glCompressedTexImage2DARB" ); - qglGetCompressedTexImageARB = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)GLimp_ExtensionPointer( "glGetCompressedTexImageARB" ); + qglCompressedTexImage2DARB = ( PFNGLCOMPRESSEDTEXIMAGE2DARBPROC )GLimp_ExtensionPointer( "glCompressedTexImage2DARB" ); + qglGetCompressedTexImageARB = ( PFNGLGETCOMPRESSEDTEXIMAGEARBPROC )GLimp_ExtensionPointer( "glGetCompressedTexImageARB" ); } else { glConfig.textureCompressionAvailable = false; } // GL_EXT_texture_filter_anisotropic glConfig.anisotropicAvailable = R_CheckExtension( "GL_EXT_texture_filter_anisotropic" ); + if ( glConfig.anisotropicAvailable ) { qglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig.maxTextureAnisotropy ); common->Printf( " maxTextureAnisotropy: %g\n", glConfig.maxTextureAnisotropy ); @@ -449,16 +498,16 @@ static void R_CheckPortableExtensions( void ) { // GL_EXT_shared_texture_palette glConfig.sharedTexturePaletteAvailable = R_CheckExtension( "GL_EXT_shared_texture_palette" ); + if ( glConfig.sharedTexturePaletteAvailable ) { - qglColorTableEXT = ( void ( APIENTRY * ) ( int, int, int, int, int, const void * ) ) GLimp_ExtensionPointer( "glColorTableEXT" ); + qglColorTableEXT = ( void ( APIENTRY * )( int, int, int, int, int, const void * ) ) GLimp_ExtensionPointer( "glColorTableEXT" ); } // GL_EXT_texture3D (not currently used for anything) glConfig.texture3DAvailable = R_CheckExtension( "GL_EXT_texture3D" ); + if ( glConfig.texture3DAvailable ) { - qglTexImage3D = - (void (APIENTRY *)(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *) ) - GLimp_ExtensionPointer( "glTexImage3D" ); + qglTexImage3D = ( void ( APIENTRY * )( GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid * ) ) GLimp_ExtensionPointer( "glTexImage3D" ); } // EXT_stencil_wrap @@ -475,49 +524,118 @@ static void R_CheckPortableExtensions( void ) { // GL_EXT_stencil_two_side glConfig.twoSidedStencilAvailable = R_CheckExtension( "GL_EXT_stencil_two_side" ); - if ( glConfig.twoSidedStencilAvailable ) - qglActiveStencilFaceEXT = (PFNGLACTIVESTENCILFACEEXTPROC)GLimp_ExtensionPointer( "glActiveStencilFaceEXT" ); - if( glConfig.glVersion >= 2.0) { + if ( glConfig.twoSidedStencilAvailable ) { + qglActiveStencilFaceEXT = ( PFNGLACTIVESTENCILFACEEXTPROC )GLimp_ExtensionPointer( "glActiveStencilFaceEXT" ); + } + + if ( glConfig.glVersion >= 2.0 ) { common->Printf( "...got GL2.0+ glStencilOpSeparate()\n" ); - qglStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)GLimp_ExtensionPointer( "glStencilOpSeparate" ); - } else if( R_CheckExtension( "GL_ATI_separate_stencil" ) ) { + qglStencilOpSeparate = ( PFNGLSTENCILOPSEPARATEPROC )GLimp_ExtensionPointer( "glStencilOpSeparate" ); + } else if ( R_CheckExtension( "GL_ATI_separate_stencil" ) ) { common->Printf( "...got glStencilOpSeparateATI() (GL_ATI_separate_stencil)\n" ); // the ATI version of glStencilOpSeparate() has the same signature and should also // behave identical to the GL2 version (in Mesa3D it's just an alias) - qglStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)GLimp_ExtensionPointer( "glStencilOpSeparateATI" ); + qglStencilOpSeparate = ( PFNGLSTENCILOPSEPARATEPROC )GLimp_ExtensionPointer( "glStencilOpSeparateATI" ); } else { common->Printf( "X..don't have glStencilOpSeparateATI() or (GL2.0+) glStencilOpSeparate()\n" ); qglStencilOpSeparate = NULL; } + // ARB_MapBufferRange + glConfig.ARBMapBufferRangeAvailable = R_CheckExtension( "GL_ARB_map_buffer_range" ); + + if ( glConfig.ARBMapBufferRangeAvailable ) { + qglFlushMappedBufferRange = ( PFNGLFLUSHMAPPEDBUFFERRANGEPROC )GLimp_ExtensionPointer( "glFlushMappedBufferRange" ); + qglMapBufferRange = ( PFNGLMAPBUFFERRANGEPROC )GLimp_ExtensionPointer( "glMapBufferRange" ); + } + + // ARB_shading_language_100 + glConfig.ARBShadingLanguageAvailable = R_CheckExtension( "GL_ARB_shading_language_100" ); + + if ( glConfig.ARBShadingLanguageAvailable ) { + qglUniform1f = ( PFNGLUNIFORM1FPROC ) GLimp_ExtensionPointer( "glUniform1f" ); + qglUniform1fv = ( PFNGLUNIFORM1FVPROC ) GLimp_ExtensionPointer( "glUniform1fv" ); + qglUniform1i = ( PFNGLUNIFORM1IPROC ) GLimp_ExtensionPointer( "glUniform1i" ); + qglUniform1iv = ( PFNGLUNIFORM1IVPROC ) GLimp_ExtensionPointer( "glUniform1iv" ); + qglUniform2f = ( PFNGLUNIFORM2FPROC ) GLimp_ExtensionPointer( "glUniform2f" ); + qglUniform2fv = ( PFNGLUNIFORM2FVPROC ) GLimp_ExtensionPointer( "glUniform2fv" ); + qglUniform2i = ( PFNGLUNIFORM2IPROC ) GLimp_ExtensionPointer( "glUniform2i" ); + qglUniform2iv = ( PFNGLUNIFORM2IVPROC ) GLimp_ExtensionPointer( "glUniform2iv" ); + qglUniform3f = ( PFNGLUNIFORM3FPROC ) GLimp_ExtensionPointer( "glUniform3f" ); + qglUniform3fv = ( PFNGLUNIFORM3FVPROC ) GLimp_ExtensionPointer( "glUniform3fv" ); + qglUniform3i = ( PFNGLUNIFORM3IPROC ) GLimp_ExtensionPointer( "glUniform3i" ); + qglUniform3iv = ( PFNGLUNIFORM3IVPROC ) GLimp_ExtensionPointer( "glUniform3iv" ); + qglUniform4f = ( PFNGLUNIFORM4FPROC ) GLimp_ExtensionPointer( "glUniform4f" ); + qglUniform4fv = ( PFNGLUNIFORM4FVPROC ) GLimp_ExtensionPointer( "glUniform4fv" ); + qglUniform4i = ( PFNGLUNIFORM4IPROC ) GLimp_ExtensionPointer( "glUniform4i" ); + qglUniform4iv = ( PFNGLUNIFORM4IVPROC ) GLimp_ExtensionPointer( "glUniform4iv" ); + + qglUniformMatrix2fv = ( PFNGLUNIFORMMATRIX2FVPROC ) GLimp_ExtensionPointer( "glUniformMatrix2fv" ); + qglUniformMatrix3fv = ( PFNGLUNIFORMMATRIX3FVPROC ) GLimp_ExtensionPointer( "glUniformMatrix3fv" ); + qglUniformMatrix4fv = ( PFNGLUNIFORMMATRIX4FVPROC ) GLimp_ExtensionPointer( "glUniformMatrix4fv" ); + qglUniformMatrix2x3fv = ( PFNGLUNIFORMMATRIX2X3FVPROC ) GLimp_ExtensionPointer( "glUniformMatrix2x3fv" ); + qglUniformMatrix2x4fv = ( PFNGLUNIFORMMATRIX2X4FVPROC ) GLimp_ExtensionPointer( "glUniformMatrix2x4fv" ); + qglUniformMatrix3x2fv = ( PFNGLUNIFORMMATRIX3X2FVPROC ) GLimp_ExtensionPointer( "glUniformMatrix3x2fv" ); + qglUniformMatrix3x4fv = ( PFNGLUNIFORMMATRIX3X4FVPROC ) GLimp_ExtensionPointer( "glUniformMatrix3x4fv" ); + qglUniformMatrix4x2fv = ( PFNGLUNIFORMMATRIX4X2FVPROC ) GLimp_ExtensionPointer( "glUniformMatrix4x2fv" ); + qglUniformMatrix4x3fv = ( PFNGLUNIFORMMATRIX4X3FVPROC ) GLimp_ExtensionPointer( "glUniformMatrix4x3fv" ); + + qglIsProgram = ( PFNGLISPROGRAMPROC ) GLimp_ExtensionPointer( "glIsProgram" ); + qglCreateProgram = ( PFNGLCREATEPROGRAMPROC ) GLimp_ExtensionPointer( "glCreateProgram" ); + qglValidateProgram = ( PFNGLVALIDATEPROGRAMPROC ) GLimp_ExtensionPointer( "glValidateProgram" ); + qglLinkProgram = ( PFNGLLINKPROGRAMPROC ) GLimp_ExtensionPointer( "glLinkProgram" ); + qglUseProgram = ( PFNGLUSEPROGRAMPROC ) GLimp_ExtensionPointer( "glUseProgram" ); + qglDeleteProgram = ( PFNGLDELETEPROGRAMPROC ) GLimp_ExtensionPointer( "glDeleteProgram" ); + + qglIsShader = ( PFNGLISSHADERPROC ) GLimp_ExtensionPointer( "glIsShader" ); + qglShaderSource = ( PFNGLSHADERSOURCEPROC ) GLimp_ExtensionPointer( "glShaderSource" ); + qglCreateShader = ( PFNGLCREATESHADERPROC ) GLimp_ExtensionPointer( "glCreateShader" ); + qglAttachShader = ( PFNGLATTACHSHADERPROC ) GLimp_ExtensionPointer( "glAttachShader" ); + qglBindAttribLocation = ( PFNGLBINDATTRIBLOCATIONPROC ) GLimp_ExtensionPointer( "glBindAttribLocation" ); + qglCompileShader = ( PFNGLCOMPILESHADERPROC ) GLimp_ExtensionPointer( "glCompileShader" ); + qglDetachShader = ( PFNGLDETACHSHADERPROC ) GLimp_ExtensionPointer( "glDetachShader" ); + qglDeleteShader = ( PFNGLDELETESHADERPROC ) GLimp_ExtensionPointer( "glDeleteShader" ); + + qglGetProgramInfoLog = ( PFNGLGETPROGRAMINFOLOGPROC ) GLimp_ExtensionPointer( "glGetProgramInfoLog" ); + qglGetProgramiv = ( PFNGLGETPROGRAMIVPROC ) GLimp_ExtensionPointer( "glGetProgramiv" ); + qglGetShaderInfoLog = ( PFNGLGETSHADERINFOLOGPROC ) GLimp_ExtensionPointer( "glGetShaderInfoLog" ); + qglGetShaderSource = ( PFNGLGETSHADERSOURCEPROC ) GLimp_ExtensionPointer( "glGetShaderSource" ); + qglGetShaderiv = ( PFNGLGETSHADERIVPROC ) GLimp_ExtensionPointer( "glGetShaderiv" ); + qglGetUniformLocation = ( PFNGLGETUNIFORMLOCATIONPROC ) GLimp_ExtensionPointer( "glGetUniformLocation" ); + qglGetUniformfv = ( PFNGLGETUNIFORMFVPROC ) GLimp_ExtensionPointer( "glGetUniformfv" ); + qglGetUniformiv = ( PFNGLGETUNIFORMIVPROC ) GLimp_ExtensionPointer( "glGetUniformiv" ); + } + // ARB_vertex_buffer_object glConfig.ARBVertexBufferObjectAvailable = R_CheckExtension( "GL_ARB_vertex_buffer_object" ); - if(glConfig.ARBVertexBufferObjectAvailable) { - qglBindBufferARB = (PFNGLBINDBUFFERARBPROC)GLimp_ExtensionPointer( "glBindBufferARB"); - qglDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)GLimp_ExtensionPointer( "glDeleteBuffersARB"); - qglGenBuffersARB = (PFNGLGENBUFFERSARBPROC)GLimp_ExtensionPointer( "glGenBuffersARB"); - qglIsBufferARB = (PFNGLISBUFFERARBPROC)GLimp_ExtensionPointer( "glIsBufferARB"); - qglBufferDataARB = (PFNGLBUFFERDATAARBPROC)GLimp_ExtensionPointer( "glBufferDataARB"); - qglBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)GLimp_ExtensionPointer( "glBufferSubDataARB"); - qglGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)GLimp_ExtensionPointer( "glGetBufferSubDataARB"); - qglMapBufferARB = (PFNGLMAPBUFFERARBPROC)GLimp_ExtensionPointer( "glMapBufferARB"); - qglUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)GLimp_ExtensionPointer( "glUnmapBufferARB"); - qglGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)GLimp_ExtensionPointer( "glGetBufferParameterivARB"); - qglGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)GLimp_ExtensionPointer( "glGetBufferPointervARB"); + + if ( glConfig.ARBVertexBufferObjectAvailable ) { + qglBindBufferARB = ( PFNGLBINDBUFFERARBPROC ) GLimp_ExtensionPointer( "glBindBufferARB" ); + qglDeleteBuffersARB = ( PFNGLDELETEBUFFERSARBPROC ) GLimp_ExtensionPointer( "glDeleteBuffersARB" ); + qglGenBuffersARB = ( PFNGLGENBUFFERSARBPROC ) GLimp_ExtensionPointer( "glGenBuffersARB" ); + qglIsBufferARB = ( PFNGLISBUFFERARBPROC ) GLimp_ExtensionPointer( "glIsBufferARB" ); + qglBufferDataARB = ( PFNGLBUFFERDATAARBPROC ) GLimp_ExtensionPointer( "glBufferDataARB" ); + qglBufferSubDataARB = ( PFNGLBUFFERSUBDATAARBPROC ) GLimp_ExtensionPointer( "glBufferSubDataARB" ); + qglGetBufferSubDataARB = ( PFNGLGETBUFFERSUBDATAARBPROC ) GLimp_ExtensionPointer( "glGetBufferSubDataARB" ); + qglMapBufferARB = ( PFNGLMAPBUFFERARBPROC ) GLimp_ExtensionPointer( "glMapBufferARB" ); + qglUnmapBufferARB = ( PFNGLUNMAPBUFFERARBPROC ) GLimp_ExtensionPointer( "glUnmapBufferARB" ); + qglGetBufferParameterivARB = ( PFNGLGETBUFFERPARAMETERIVARBPROC ) GLimp_ExtensionPointer( "glGetBufferParameterivARB" ); + qglGetBufferPointervARB = ( PFNGLGETBUFFERPOINTERVARBPROC ) GLimp_ExtensionPointer( "glGetBufferPointervARB" ); } // ARB_vertex_program glConfig.ARBVertexProgramAvailable = R_CheckExtension( "GL_ARB_vertex_program" ); - if (glConfig.ARBVertexProgramAvailable) { - qglVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC)GLimp_ExtensionPointer( "glVertexAttribPointerARB" ); - qglEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)GLimp_ExtensionPointer( "glEnableVertexAttribArrayARB" ); - qglDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)GLimp_ExtensionPointer( "glDisableVertexAttribArrayARB" ); - qglProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)GLimp_ExtensionPointer( "glProgramStringARB" ); - qglBindProgramARB = (PFNGLBINDPROGRAMARBPROC)GLimp_ExtensionPointer( "glBindProgramARB" ); - qglGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)GLimp_ExtensionPointer( "glGenProgramsARB" ); - qglProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)GLimp_ExtensionPointer( "glProgramEnvParameter4fvARB" ); - qglProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)GLimp_ExtensionPointer( "glProgramLocalParameter4fvARB" ); + + if ( glConfig.ARBVertexProgramAvailable ) { + qglVertexAttribPointerARB = ( PFNGLVERTEXATTRIBPOINTERARBPROC ) GLimp_ExtensionPointer( "glVertexAttribPointerARB" ); + qglEnableVertexAttribArrayARB = ( PFNGLENABLEVERTEXATTRIBARRAYARBPROC ) GLimp_ExtensionPointer( "glEnableVertexAttribArrayARB" ); + qglDisableVertexAttribArrayARB = ( PFNGLDISABLEVERTEXATTRIBARRAYARBPROC ) GLimp_ExtensionPointer( "glDisableVertexAttribArrayARB" ); + qglProgramStringARB = ( PFNGLPROGRAMSTRINGARBPROC ) GLimp_ExtensionPointer( "glProgramStringARB" ); + qglBindProgramARB = ( PFNGLBINDPROGRAMARBPROC ) GLimp_ExtensionPointer( "glBindProgramARB" ); + qglGenProgramsARB = ( PFNGLGENPROGRAMSARBPROC ) GLimp_ExtensionPointer( "glGenProgramsARB" ); + qglProgramEnvParameter4fvARB = ( PFNGLPROGRAMENVPARAMETER4FVARBPROC ) GLimp_ExtensionPointer( "glProgramEnvParameter4fvARB" ); + qglProgramLocalParameter4fvARB = ( PFNGLPROGRAMLOCALPARAMETER4FVARBPROC ) GLimp_ExtensionPointer( "glProgramLocalParameter4fvARB" ); } // ARB_fragment_program @@ -525,43 +643,49 @@ static void R_CheckPortableExtensions( void ) { glConfig.ARBFragmentProgramAvailable = false; } else { glConfig.ARBFragmentProgramAvailable = R_CheckExtension( "GL_ARB_fragment_program" ); - if (glConfig.ARBFragmentProgramAvailable) { + if ( glConfig.ARBFragmentProgramAvailable ) { // these are the same as ARB_vertex_program - qglProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)GLimp_ExtensionPointer( "glProgramStringARB" ); - qglBindProgramARB = (PFNGLBINDPROGRAMARBPROC)GLimp_ExtensionPointer( "glBindProgramARB" ); - qglProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)GLimp_ExtensionPointer( "glProgramEnvParameter4fvARB" ); - qglProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)GLimp_ExtensionPointer( "glProgramLocalParameter4fvARB" ); + qglProgramStringARB = ( PFNGLPROGRAMSTRINGARBPROC ) GLimp_ExtensionPointer( "glProgramStringARB" ); + qglBindProgramARB = ( PFNGLBINDPROGRAMARBPROC ) GLimp_ExtensionPointer( "glBindProgramARB" ); + qglProgramEnvParameter4fvARB = ( PFNGLPROGRAMENVPARAMETER4FVARBPROC ) GLimp_ExtensionPointer( "glProgramEnvParameter4fvARB" ); + qglProgramLocalParameter4fvARB = ( PFNGLPROGRAMLOCALPARAMETER4FVARBPROC ) GLimp_ExtensionPointer( "glProgramLocalParameter4fvARB" ); } } // check for minimum set - if ( !glConfig.multitextureAvailable || !glConfig.textureEnvCombineAvailable || !glConfig.cubeMapAvailable - || !glConfig.envDot3Available ) { - common->Error( "%s", common->GetLanguageDict()->GetString( "#str_06780" ) ); + if ( !glConfig.multitextureAvailable || + !glConfig.textureEnvCombineAvailable || + !glConfig.cubeMapAvailable || + !glConfig.envDot3Available ) { + common->Error( "%s", common->GetLanguageDict()->GetString( "#str_06780" ) ); } // GL_EXT_depth_bounds_test glConfig.depthBoundsTestAvailable = R_CheckExtension( "EXT_depth_bounds_test" ); + if ( glConfig.depthBoundsTestAvailable ) { - qglDepthBoundsEXT = (PFNGLDEPTHBOUNDSEXTPROC)GLimp_ExtensionPointer( "glDepthBoundsEXT" ); + qglDepthBoundsEXT = ( PFNGLDEPTHBOUNDSEXTPROC ) GLimp_ExtensionPointer( "glDepthBoundsEXT" ); } // GL_ARB_debug_output glConfig.glDebugOutputAvailable = false; + if ( glConfig.haveDebugContext ) { if ( strstr( glConfig.extensions_string, "GL_ARB_debug_output" ) ) { glConfig.glDebugOutputAvailable = true; - qglDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC)GLimp_ExtensionPointer( "glDebugMessageCallbackARB" ); + qglDebugMessageCallbackARB = ( PFNGLDEBUGMESSAGECALLBACKARBPROC ) GLimp_ExtensionPointer( "glDebugMessageCallbackARB" ); + if ( r_glDebugContext.GetBool() ) { common->Printf( "...using GL_ARB_debug_output (r_glDebugContext is set)\n" ); - qglDebugMessageCallbackARB(DebugCallback, NULL); - qglEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + qglDebugMessageCallbackARB( DebugCallback, NULL ); + qglEnable( GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB ); } else { common->Printf( "...found GL_ARB_debug_output, but not using it (r_glDebugContext is not set)\n" ); } } else { common->Printf( "X..GL_ARB_debug_output not found\n" ); qglDebugMessageCallbackARB = NULL; + if ( r_glDebugContext.GetBool() ) { common->Warning( "r_glDebugContext is set, but can't be used because GL_ARB_debug_output is not supported" ); } @@ -634,7 +758,7 @@ vidmode_t r_vidModes[] = { { "Mode 32: 7680x2160", 7680, 2160 }, }; // DG: made this an enum so even stupid compilers accept it as array length below -enum { s_numVidModes = sizeof( r_vidModes ) / sizeof( r_vidModes[0] ) }; +enum { s_numVidModes = sizeof( r_vidModes ) / sizeof( r_vidModes[0] ) }; bool R_GetModeInfo( int *width, int *height, int mode ) { vidmode_t *vm; @@ -642,6 +766,7 @@ bool R_GetModeInfo( int *width, int *height, int mode ) { if ( mode < -1 ) { return false; } + if ( mode >= s_numVidModes ) { return false; } @@ -651,16 +776,15 @@ bool R_GetModeInfo( int *width, int *height, int mode ) { *height = r_customHeight.GetInteger(); return true; } - vm = &r_vidModes[mode]; if ( width ) { *width = vm->width; } + if ( height ) { *height = vm->height; } - return true; } @@ -670,54 +794,47 @@ bool R_GetModeInfo( int *width, int *height, int mode ) { // sorted in the menu. struct vidModePtr { - vidmode_t* vidMode; + vidmode_t *vidMode; int modeIndex; }; static vidModePtr sortedVidModes[s_numVidModes]; -static int vidModeCmp(const void* vm1, const void* vm2) -{ - const vidModePtr* v1 = static_cast(vm1); - const vidModePtr* v2 = static_cast(vm2); +static int vidModeCmp( const void *vm1, const void *vm2 ) { + const vidModePtr *v1 = static_cast( vm1 ); + const vidModePtr *v2 = static_cast( vm2 ); // sort primarily by width, secondarily by height int wdiff = v1->vidMode->width - v2->vidMode->width; - return (wdiff != 0) ? wdiff : (v1->vidMode->height - v2->vidMode->height); + + return ( wdiff != 0 ) ? wdiff : ( v1->vidMode->height - v2->vidMode->height ); } -static void initSortedVidModes() -{ - if(sortedVidModes[0].vidMode != NULL) - { +static void initSortedVidModes() { + if ( sortedVidModes[0].vidMode != NULL ) { // already initialized return; } - for(int i=0; i= 3 && sortedVidModes[i].vidMode != NULL) - { + if ( sortedVidModes[i].modeIndex >= 3 && sortedVidModes[i].vidMode != NULL ) { idStr modeStr; - sprintf(modeStr, ";%dx%d", sortedVidModes[i].vidMode->width, sortedVidModes[i].vidMode->height); + sprintf( modeStr, ";%dx%d", sortedVidModes[i].vidMode->width, sortedVidModes[i].vidMode->height ); ret += modeStr; } } @@ -725,14 +842,12 @@ idStr R_GetVidModeListString(bool addCustom) } // r_mode values for resolutions from R_GetVidModeListString(): "-1;3;4;5;..." -idStr R_GetVidModeValsString(bool addCustom) -{ +idStr R_GetVidModeValsString( bool addCustom ) { idStr ret = addCustom ? "-1" : ""; // for custom resolutions using r_customWidth/r_customHeight - for(int i=0; i= 3 && sortedVidModes[i].vidMode != NULL) - { + if ( sortedVidModes[i].modeIndex >= 3 && sortedVidModes[i].vidMode != NULL ) { ret += ";"; ret += sortedVidModes[i].modeIndex; } @@ -807,12 +922,11 @@ void R_InitOpenGL( void ) { r_multiSamples.SetInteger( 0 ); } -// load qgl function pointers -#define QGLPROC(name, rettype, args) \ - q##name = (rettype(APIENTRYP)args)GLimp_ExtensionPointer(#name); \ - if (!q##name) \ - common->FatalError("Unable to initialize OpenGL (%s)", #name); - + // load qgl function pointers +#define QGLPROC( name, rettype, args ) \ + q##name = ( rettype( APIENTRYP )args ) GLimp_ExtensionPointer( #name ); \ + if ( !q##name ) \ + common->FatalError( "Unable to initialize OpenGL (%s)", #name ); #include "renderer/qgl_proc.h" // input and sound systems need to be tied to the new window @@ -820,10 +934,23 @@ void R_InitOpenGL( void ) { soundSystem->InitHW(); // get our config strings - glConfig.vendor_string = (const char *)qglGetString(GL_VENDOR); - glConfig.renderer_string = (const char *)qglGetString(GL_RENDERER); - glConfig.version_string = (const char *)qglGetString(GL_VERSION); - glConfig.extensions_string = (const char *)qglGetString(GL_EXTENSIONS); + glConfig.vendor_string = ( const char * )qglGetString( GL_VENDOR ); + glConfig.renderer_string = ( const char * )qglGetString( GL_RENDERER ); + glConfig.version_string = ( const char * )qglGetString( GL_VERSION ); + glConfig.extensions_string = ( const char * )qglGetString( GL_EXTENSIONS ); + + // simplify a few things + if ( idStr::Cmp( glConfig.vendor_string, "Intel" ) == 0 ) { + glConfig.vendor = glvIntel; + } else if ( idStr::Cmp( glConfig.vendor_string, "ATI Technologies Inc." ) == 0 ) { + glConfig.vendor = glvAMD; + } else if ( idStr::Cmpn( glConfig.vendor_string, "NVIDIA", 6 ) == 0 || + idStr::Cmpn( glConfig.vendor_string, "Nvidia", 6 ) == 0 || + idStr::Cmpn( glConfig.vendor_string, "nvidia", 6 ) == 0 ) { + glConfig.vendor = glvNVIDIA; + } else { + glConfig.vendor = glvAny; + } // OpenGL driver constants qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp ); @@ -833,12 +960,11 @@ void R_InitOpenGL( void ) { if ( glConfig.maxTextureSize <= 0 ) { glConfig.maxTextureSize = 256; } - glConfig.isInitialized = true; - common->Printf("OpenGL vendor: %s\n", glConfig.vendor_string ); - common->Printf("OpenGL renderer: %s\n", glConfig.renderer_string ); - common->Printf("OpenGL version: %s\n", glConfig.version_string ); + common->Printf( "OpenGL vendor: %s\n", glConfig.vendor_string ); + common->Printf( "OpenGL renderer: %s\n", glConfig.renderer_string ); + common->Printf( "OpenGL version: %s\n", glConfig.version_string ); // recheck all the extensions (FIXME: this might be dangerous) R_CheckPortableExtensions(); @@ -862,8 +988,9 @@ void R_InitOpenGL( void ) { // Reset our gamma r_gammaInShader.ClearModified(); + if ( r_gammaInShader.GetBool() ) { - common->Printf( "Will apply r_gamma and r_brightness in shaders (r_gammaInShader 1)\n" ); + common->Printf( "Will apply r_gamma and r_brightness in shaders (ARB2 only: r_gammaInShader 1)\n" ); } else { common->Printf( "Will apply r_gamma and r_brightness in hardware (possibly on all screens; r_gammaInShader 0)\n" ); R_SetColorMappings(); @@ -871,19 +998,22 @@ void R_InitOpenGL( void ) { #ifdef _WIN32 static bool glCheck = false; + if ( !glCheck && win32.osversion.dwMajorVersion == 6 ) { glCheck = true; + if ( !idStr::Icmp( glConfig.vendor_string, "Microsoft" ) && idStr::FindText( glConfig.renderer_string, "OpenGL-D3D" ) != -1 ) { if ( cvarSystem->GetCVarBool( "r_fullscreen" ) ) { cmdSystem->BufferCommandText( CMD_EXEC_NOW, "vid_restart partial windowed\n" ); Sys_GrabMouseCursor( false ); } int ret = MessageBox( NULL, "Please install OpenGL drivers from your graphics hardware vendor to run " GAME_NAME ".\nYour OpenGL functionality is limited.", - "Insufficient OpenGL capabilities", MB_OKCANCEL | MB_ICONWARNING | MB_TASKMODAL ); + "Insufficient OpenGL capabilities", MB_OKCANCEL | MB_ICONWARNING | MB_TASKMODAL ); if ( ret == IDCANCEL ) { cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "quit\n" ); cmdSystem->ExecuteCommandBuffer(); } + if ( cvarSystem->GetCVarBool( "r_fullscreen" ) ) { cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "vid_restart\n" ); } @@ -905,31 +1035,33 @@ void GL_CheckErrors( void ) { // check for up to 10 errors pending for ( i = 0 ; i < 10 ; i++ ) { err = qglGetError(); + if ( err == GL_NO_ERROR ) { return; } - switch( err ) { - case GL_INVALID_ENUM: - strcpy( s, "GL_INVALID_ENUM" ); - break; - case GL_INVALID_VALUE: - strcpy( s, "GL_INVALID_VALUE" ); - break; - case GL_INVALID_OPERATION: - strcpy( s, "GL_INVALID_OPERATION" ); - break; - case GL_STACK_OVERFLOW: - strcpy( s, "GL_STACK_OVERFLOW" ); - break; - case GL_STACK_UNDERFLOW: - strcpy( s, "GL_STACK_UNDERFLOW" ); - break; - case GL_OUT_OF_MEMORY: - strcpy( s, "GL_OUT_OF_MEMORY" ); - break; - default: - idStr::snPrintf( s, sizeof(s), "%i", err); - break; + + switch ( err ) { + case GL_INVALID_ENUM: + strcpy( s, "GL_INVALID_ENUM" ); + break; + case GL_INVALID_VALUE: + strcpy( s, "GL_INVALID_VALUE" ); + break; + case GL_INVALID_OPERATION: + strcpy( s, "GL_INVALID_OPERATION" ); + break; + case GL_STACK_OVERFLOW: + strcpy( s, "GL_STACK_OVERFLOW" ); + break; + case GL_STACK_UNDERFLOW: + strcpy( s, "GL_STACK_UNDERFLOW" ); + break; + case GL_OUT_OF_MEMORY: + strcpy( s, "GL_OUT_OF_MEMORY" ); + break; + default: + idStr::snPrintf( s, sizeof( s ), "%i", err ); + break; } if ( !r_ignoreGLErrors.GetBool() ) { @@ -952,10 +1084,10 @@ static void R_ReloadSurface_f( const idCmdArgs &args ) { // start far enough away that we don't hit the player model start = tr.primaryView->renderView.vieworg + tr.primaryView->renderView.viewaxis[0] * 16; end = start + tr.primaryView->renderView.viewaxis[0] * 1000.0f; + if ( !tr.primaryWorld->Trace( mt, start, end, 0.0f, false ) ) { return; } - common->Printf( "Reloading %s\n", mt.material->GetName() ); // reload the decl @@ -976,6 +1108,7 @@ static void R_ListModes_f( const idCmdArgs &args ) { int i; common->Printf( "\n" ); + for ( i = 0; i < s_numVidModes; i++ ) { common->Printf( "%s\n", r_vidModes[i].description ); } @@ -1006,8 +1139,9 @@ void R_TestImage_f( const idCmdArgs &args ) { return; } - if ( idStr::IsNumeric( args.Argv(1) ) ) { - imageNum = atoi( args.Argv(1) ); + if ( idStr::IsNumeric( args.Argv( 1 ) ) ) { + imageNum = atoi( args.Argv( 1 ) ); + if ( imageNum >= 0 && imageNum < globalImages->images.Num() ) { tr.testImage = globalImages->images[imageNum]; } @@ -1033,22 +1167,19 @@ void R_TestVideo_f( const idCmdArgs &args ) { if ( args.Argc() < 2 ) { return; } - tr.testImage = globalImages->ImageFromFile( "_scratch", TF_DEFAULT, false, TR_REPEAT, TD_DEFAULT ); tr.testVideo = idCinematic::Alloc(); tr.testVideo->InitFromFile( args.Argv( 1 ), true ); - cinData_t cin; - cin = tr.testVideo->ImageForTime( 0 ); + cinData_t cin = tr.testVideo->ImageForTime( 0 ); + if ( !cin.image ) { delete tr.testVideo; tr.testVideo = NULL; tr.testImage = NULL; return; } - common->Printf( "%i x %i images\n", cin.imageWidth, cin.imageHeight ); - int len = tr.testVideo->AnimationLength(); common->Printf( "%5.1f seconds of video\n", len * 0.001 ); @@ -1061,17 +1192,24 @@ void R_TestVideo_f( const idCmdArgs &args ) { session->sw->PlayShaderDirectly( wavString.c_str() ); } +/* +=================== +R_QsortSurfaceAreas +=================== +*/ static int R_QsortSurfaceAreas( const void *a, const void *b ) { const idMaterial *ea, *eb; - int ac, bc; + int ac, bc; + + ea = *( idMaterial ** )a; - ea = *(idMaterial **)a; if ( !ea->EverReferenced() ) { ac = 0; } else { ac = ea->GetSurfaceArea(); } - eb = *(idMaterial **)b; + eb = *( idMaterial ** )b; + if ( !eb->EverReferenced() ) { bc = 0; } else { @@ -1081,14 +1219,13 @@ static int R_QsortSurfaceAreas( const void *a, const void *b ) { if ( ac < bc ) { return -1; } + if ( ac > bc ) { return 1; } - return idStr::Icmp( ea->GetName(), eb->GetName() ); } - /* =================== R_ReportSurfaceAreas_f @@ -1101,12 +1238,11 @@ void R_ReportSurfaceAreas_f( const idCmdArgs &args ) { idMaterial **list; count = declManager->GetNumDecls( DECL_MATERIAL ); - list = (idMaterial **)_alloca( count * sizeof( *list ) ); + list = ( idMaterial ** )_alloca( count * sizeof( *list ) ); for ( i = 0 ; i < count ; i++ ) { - list[i] = (idMaterial *)declManager->DeclByIndex( DECL_MATERIAL, i, false ); + list[i] = ( idMaterial * )declManager->DeclByIndex( DECL_MATERIAL, i, false ); } - qsort( list, count, sizeof( list[0] ), R_QsortSurfaceAreas ); // skip over ones with 0 area @@ -1144,14 +1280,17 @@ void R_ReportImageDuplication_f( const idCmdArgs &args ) { // ignore background loading stubs continue; } + if ( image1->generatorFunction ) { // ignore procedural images continue; } + if ( image1->cubeFiles != CF_2D ) { // ignore cube maps continue; } + if ( image1->defaulted ) { continue; } @@ -1166,27 +1305,31 @@ void R_ReportImageDuplication_f( const idCmdArgs &args ) { if ( image2->isPartialImage ) { continue; } + if ( image2->generatorFunction ) { continue; } + if ( image2->cubeFiles != CF_2D ) { continue; } + if ( image2->defaulted ) { continue; } + if ( image1->imageHash != image2->imageHash ) { continue; } - if ( image2->uploadWidth != image1->uploadWidth - || image2->uploadHeight != image1->uploadHeight ) { + + if ( image2->uploadWidth != image1->uploadWidth || image2->uploadHeight != image1->uploadHeight ) { continue; } + if ( !idStr::Icmp( image1->imgName, image2->imgName ) ) { // ignore same image-with-different-parms continue; } - byte *data2; int w2, h2; @@ -1197,11 +1340,10 @@ void R_ReportImageDuplication_f( const idCmdArgs &args ) { continue; } - if ( memcmp( data1, data2, w1*h1*4 ) ) { + if ( memcmp( data1, data2, w1 * h1 * 4 ) ) { R_StaticFree( data2 ); continue; } - R_StaticFree( data2 ); common->Printf( "%s == %s\n", image1->imgName.c_str(), image2->imgName.c_str() ); @@ -1209,7 +1351,6 @@ void R_ReportImageDuplication_f( const idCmdArgs &args ) { count++; break; } - R_StaticFree( data1 ); } common->Printf( "%i / %i collisions\n", count, globalImages->images.Num() ); @@ -1236,7 +1377,7 @@ static float R_RenderingFPS( const renderView_t *renderView ) { int end; int count = 0; - while( 1 ) { + while ( 1 ) { // render renderSystem->BeginFrame( glConfig.vidWidth, glConfig.vidHeight ); tr.primaryWorld->RenderScene( renderView ); @@ -1244,11 +1385,11 @@ static float R_RenderingFPS( const renderView_t *renderView ) { qglFinish(); count++; end = Sys_Milliseconds(); + if ( end - start > SAMPLE_MSEC ) { break; } } - float fps = count * 1000.0 / ( end - start ); return fps; @@ -1293,7 +1434,6 @@ void R_Benchmark_f( const idCmdArgs &args ) { r_skipRenderContext.SetBool( false ); } - /* ============================================================================== @@ -1314,7 +1454,7 @@ If ref isn't specified, the full session UpdateScreen will be done. */ void R_ReadTiledPixels( int width, int height, byte *buffer, renderView_t *ref = NULL ) { // include extra space for OpenGL padding to word boundaries - byte *temp = (byte *)R_StaticAlloc( (glConfig.vidWidth+3) * glConfig.vidHeight * 3 ); + byte *temp = ( byte * )R_StaticAlloc( ( glConfig.vidWidth + 3 ) * glConfig.vidHeight * 3 ); int oldWidth = glConfig.vidWidth; int oldHeight = glConfig.vidHeight; @@ -1335,14 +1475,15 @@ void R_ReadTiledPixels( int width, int height, byte *buffer, renderView_t *ref = tr.primaryWorld->RenderScene( ref ); tr.EndFrame( NULL, NULL ); } else { - session->UpdateScreen(false); + session->UpdateScreen( false ); } - int w = oldWidth; + if ( xo + w > width ) { w = width - xo; } int h = oldHeight; + if ( yo + h > height ) { h = height - yo; } @@ -1363,16 +1504,13 @@ void R_ReadTiledPixels( int width, int height, byte *buffer, renderView_t *ref = qglReadBuffer( oldReadBuf ); } - int row = ( w * 3 + 3 ) & ~3; // OpenGL pads to dword boundaries for ( int y = 0 ; y < h ; y++ ) { - memcpy( buffer + ( ( yo + y )* width + xo ) * 3, - temp + y * row, w * 3 ); + memcpy( buffer + ( ( yo + y )* width + xo ) * 3, temp + y * row, w * 3 ); } } } - r_useScissor.SetBool( true ); tr.viewportOffset[0] = 0; @@ -1393,10 +1531,9 @@ WriteScreenshotForSTBIW Callback to each stbi_write_* function ================== */ -static void WriteScreenshotForSTBIW(void* context, void* data, int size) -{ - idFile* f = (idFile*)context; - f->Write(data, size); +static void WriteScreenshotForSTBIW( void *context, void *data, int size ) { + idFile *f = ( idFile * )context; + f->Write( data, size ); } /* @@ -1419,14 +1556,15 @@ void idRenderSystemLocal::TakeScreenshot( int width, int height, const char *fil int pix = width * height; int lineSize = width * 3; - buffer = (byte *)R_StaticAlloc(pix*3); - swapBuffer = (byte*)R_StaticAlloc(lineSize); + buffer = ( byte * )R_StaticAlloc( pix * 3 ); + swapBuffer = ( byte * )R_StaticAlloc( lineSize ); if ( blends <= 1 ) { R_ReadTiledPixels( width, height, buffer, ref ); } else { - unsigned short *shortBuffer = (unsigned short *)R_StaticAlloc(pix*2*3); - memset( shortBuffer, 0, pix*2*3 ); + unsigned short *shortBuffer = ( unsigned short * )R_StaticAlloc( pix * 2 * 3 ); + + memset( shortBuffer, 0, pix * 2 * 3 ); // enable anti-aliasing jitter r_jitter.SetBool( true ); @@ -1434,70 +1572,65 @@ void idRenderSystemLocal::TakeScreenshot( int width, int height, const char *fil for ( i = 0 ; i < blends ; i++ ) { R_ReadTiledPixels( width, height, buffer, ref ); - for ( j = 0 ; j < pix*3 ; j++ ) { + for ( j = 0 ; j < pix * 3 ; j++ ) { shortBuffer[j] += buffer[j]; } } // divide back to bytes - for ( i = 0 ; i < pix*3 ; i++ ) { + for ( i = 0 ; i < pix * 3 ; i++ ) { buffer[i] = shortBuffer[i] / blends; } - R_StaticFree( shortBuffer ); r_jitter.SetBool( false ); } // The buffer is upside down, we need to flip it the right way. - for (i = 0; i < height / 2; ++i) { - byte* line1 = &buffer[i * lineSize]; - byte* line2 = &buffer[(height - i - 1) * lineSize]; - memcpy(swapBuffer, line1, lineSize); - memcpy(line1, line2, lineSize); - memcpy(line2, swapBuffer, lineSize); - } - - idFile* f; - if (strstr(fileName, "viewnote")) { - f = fileSystem->OpenFileWrite( fileName, "fs_cdpath" ); + for ( i = 0; i < height / 2; ++i ) { + byte *line1 = &buffer[i * lineSize]; + byte *line2 = &buffer[( height - i - 1 ) * lineSize]; + memcpy( swapBuffer, line1, lineSize ); + memcpy( line1, line2, lineSize ); + memcpy( line2, swapBuffer, lineSize ); } - else { + idFile *f; + + if ( strstr( fileName, "viewnote" ) ) { + f = fileSystem->OpenFileWrite( fileName, "fs_cdpath" ); + } else { f = fileSystem->OpenFileWrite( fileName ); } // If no specific format is requested, default to using the CVar value. - if (g_screenshotFormat == -1) { + if ( g_screenshotFormat == -1 ) { g_screenshotFormat = cvarSystem->GetCVarInteger( "r_screenshotFormat" ); } - switch (g_screenshotFormat) { - default: - stbi_write_tga_to_func( WriteScreenshotForSTBIW, f, width, height, 3, buffer ); - break; - case 1: - stbi_write_bmp_to_func( WriteScreenshotForSTBIW, f, width, height, 3, buffer); - break; - case 2: - stbi_write_png_compression_level = idMath::ClampInt( 0, 9, r_screenshotPngCompression.GetInteger() ); - stbi_write_png_to_func( WriteScreenshotForSTBIW, f, width, height, 3, buffer, 3 * width ); - break; - case 3: - stbi_write_jpg_to_func( WriteScreenshotForSTBIW, f, width, height, 3, buffer, idMath::ClampInt( 1, 100, r_screenshotJpgQuality.GetInteger() ) ); - break; + switch ( g_screenshotFormat ) { + default: + stbi_write_tga_to_func( WriteScreenshotForSTBIW, f, width, height, 3, buffer ); + break; + case 1: + stbi_write_bmp_to_func( WriteScreenshotForSTBIW, f, width, height, 3, buffer ); + break; + case 2: + stbi_write_png_compression_level = idMath::ClampInt( 0, 9, r_screenshotPngCompression.GetInteger() ); + stbi_write_png_to_func( WriteScreenshotForSTBIW, f, width, height, 3, buffer, 3 * width ); + break; + case 3: + stbi_write_jpg_to_func( WriteScreenshotForSTBIW, f, width, height, 3, buffer, idMath::ClampInt( 1, 100, r_screenshotJpgQuality.GetInteger() ) ); + break; } - g_screenshotFormat = -1; - fileSystem->CloseFile(f); + fileSystem->CloseFile( f ); R_StaticFree( buffer ); R_StaticFree( swapBuffer ); takingScreenshot = false; - } - /* ================== R_ScreenshotFilename @@ -1509,49 +1642,51 @@ thousands of shots ================== */ void R_ScreenshotFilename( int &lastNumber, const char *base, idStr &fileName ) { - int a,b,c,d, e; + int a, b, c, d, e; bool fsrestrict = cvarSystem->GetCVarBool( "fs_restrict" ); cvarSystem->SetCVarBool( "fs_restrict", false ); - - int format = cvarSystem->GetCVarInteger("r_screenshotFormat"); + int format = cvarSystem->GetCVarInteger( "r_screenshotFormat" ); lastNumber++; + if ( lastNumber > 99999 ) { lastNumber = 99999; } + for ( ; lastNumber < 99999 ; lastNumber++ ) { int frac = lastNumber; a = frac / 10000; - frac -= a*10000; + frac -= a * 10000; b = frac / 1000; - frac -= b*1000; + frac -= b * 1000; c = frac / 100; - frac -= c*100; + frac -= c * 100; d = frac / 10; - frac -= d*10; + frac -= d * 10; e = frac; - switch (format) { - default: - sprintf(fileName, "%s%i%i%i%i%i.tga", base, a, b, c, d, e); - break; - case 1: - sprintf(fileName, "%s%i%i%i%i%i.bmp", base, a, b, c, d, e); - break; - case 2: - sprintf(fileName, "%s%i%i%i%i%i.png", base, a, b, c, d, e); - break; - case 3: - sprintf(fileName, "%s%i%i%i%i%i.jpg", base, a, b, c, d, e); - break; + switch ( format ) { + default: + sprintf( fileName, "%s%i%i%i%i%i.tga", base, a, b, c, d, e ); + break; + case 1: + sprintf( fileName, "%s%i%i%i%i%i.bmp", base, a, b, c, d, e ); + break; + case 2: + sprintf( fileName, "%s%i%i%i%i%i.png", base, a, b, c, d, e ); + break; + case 3: + sprintf( fileName, "%s%i%i%i%i%i.jpg", base, a, b, c, d, e ); + break; } - + if ( lastNumber == 99999 ) { break; } int len = fileSystem->ReadFile( fileName, NULL, NULL ); + if ( len <= 0 ) { break; } @@ -1602,9 +1737,11 @@ void R_ScreenShot_f( const idCmdArgs &args ) { width = atoi( args.Argv( 1 ) ); height = atoi( args.Argv( 2 ) ); blends = atoi( args.Argv( 3 ) ); + if ( blends < 1 ) { blends = 1; } + if ( blends > MAX_BLENDS ) { blends = MAX_BLENDS; } @@ -1635,22 +1772,21 @@ void R_StencilShot( void ) { int width = tr.GetScreenWidth(); int height = tr.GetScreenHeight(); - int pix = width * height; c = pix * 3 + 18; - buffer = (byte *)Mem_Alloc(c); - memset (buffer, 0, 18); + buffer = ( byte * )Mem_Alloc( c ); + memset( buffer, 0, 18 ); - byte *byteBuffer = (byte *)Mem_Alloc(pix); + byte *byteBuffer = ( byte * )Mem_Alloc( pix ); - qglReadPixels( 0, 0, width, height, GL_STENCIL_INDEX , GL_UNSIGNED_BYTE, byteBuffer ); + qglReadPixels( 0, 0, width, height, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, byteBuffer ); for ( i = 0 ; i < pix ; i++ ) { - buffer[18+i*3] = - buffer[18+i*3+1] = - // buffer[18+i*3+2] = ( byteBuffer[i] & 15 ) * 16; - buffer[18+i*3+2] = byteBuffer[i]; + buffer[18 + i * 3] = + buffer[18 + i * 3 + 1] = +// buffer[18+i*3+2] = ( byteBuffer[i] & 15 ) * 16; + buffer[18 + i * 3 + 2] = byteBuffer[i]; } // fill in the header (this is vertically flipped, which qglReadPixels emits) @@ -1685,7 +1821,8 @@ void R_EnvShot_f( const idCmdArgs &args ) { viewDef_t primary; int blends; const char *extensions[6] = { "_px.tga", "_nx.tga", "_py.tga", "_ny.tga", - "_pz.tga", "_nz.tga" }; + "_pz.tga", "_nz.tga" + }; int size; if ( args.Argc() != 2 && args.Argc() != 3 && args.Argc() != 4 ) { @@ -1695,6 +1832,7 @@ void R_EnvShot_f( const idCmdArgs &args ) { baseName = args.Argv( 1 ); blends = 1; + if ( args.Argc() == 4 ) { size = atoi( args.Argv( 2 ) ); blends = atoi( args.Argv( 3 ) ); @@ -1710,10 +1848,10 @@ void R_EnvShot_f( const idCmdArgs &args ) { common->Printf( "No primary view.\n" ); return; } - primary = *tr.primaryView; memset( &axis, 0, sizeof( axis ) ); + axis[0][0][0] = 1; axis[0][1][2] = 1; axis[0][2][1] = 1; @@ -1749,7 +1887,6 @@ void R_EnvShot_f( const idCmdArgs &args ) { g_screenshotFormat = 0; tr.TakeScreenshot( size, size, fullname, blends, &ref ); } - common->Printf( "Wrote %s, etc\n", fullname.c_str() ); } @@ -1757,7 +1894,6 @@ void R_EnvShot_f( const idCmdArgs &args ) { static idMat3 cubeAxis[6]; - /* ================== R_SampleCubeMap @@ -1767,9 +1903,9 @@ void R_SampleCubeMap( const idVec3 &dir, int size, byte *buffers[6], byte result float adir[3]; int axis, x, y; - adir[0] = fabs(dir[0]); - adir[1] = fabs(dir[1]); - adir[2] = fabs(dir[2]); + adir[0] = fabs( dir[0] ); + adir[1] = fabs( dir[1] ); + adir[2] = fabs( dir[2] ); if ( dir[0] >= adir[1] && dir[0] >= adir[2] ) { axis = 0; @@ -1784,29 +1920,29 @@ void R_SampleCubeMap( const idVec3 &dir, int size, byte *buffers[6], byte result } else { axis = 5; } - - float fx = (dir * cubeAxis[axis][1]) / (dir * cubeAxis[axis][0]); - float fy = (dir * cubeAxis[axis][2]) / (dir * cubeAxis[axis][0]); + float fx = ( dir * cubeAxis[axis][1] ) / ( dir * cubeAxis[axis][0] ); + float fy = ( dir * cubeAxis[axis][2] ) / ( dir * cubeAxis[axis][0] ); fx = -fx; fy = -fy; - x = size * 0.5 * (fx + 1); - y = size * 0.5 * (fy + 1); + x = size * 0.5 * ( fx + 1 ); + y = size * 0.5 * ( fy + 1 ); + if ( x < 0 ) { x = 0; } else if ( x >= size ) { - x = size-1; + x = size - 1; } + if ( y < 0 ) { y = 0; } else if ( y >= size ) { - y = size-1; + y = size - 1; } - - result[0] = buffers[axis][(y*size+x)*4+0]; - result[1] = buffers[axis][(y*size+x)*4+1]; - result[2] = buffers[axis][(y*size+x)*4+2]; - result[3] = buffers[axis][(y*size+x)*4+3]; + result[0] = buffers[axis][( y * size + x ) * 4 + 0]; + result[1] = buffers[axis][( y * size + x ) * 4 + 1]; + result[2] = buffers[axis][( y * size + x ) * 4 + 2]; + result[3] = buffers[axis][( y * size + x ) * 4 + 3]; } /* @@ -1823,7 +1959,8 @@ void R_MakeAmbientMap_f( const idCmdArgs &args ) { const char *baseName; int i; const char *extensions[6] = { "_px.tga", "_nx.tga", "_py.tga", "_ny.tga", - "_pz.tga", "_nz.tga" }; + "_pz.tga", "_nz.tga" + }; int outSize; byte *buffers[6]; int width, height; @@ -1839,8 +1976,8 @@ void R_MakeAmbientMap_f( const idCmdArgs &args ) { } else { outSize = 32; } - memset( &cubeAxis, 0, sizeof( cubeAxis ) ); + cubeAxis[0][0][0] = 1; cubeAxis[0][1][2] = 1; cubeAxis[0][2][1] = 1; @@ -1871,8 +2008,10 @@ void R_MakeAmbientMap_f( const idCmdArgs &args ) { common->Printf( "loading %s\n", fullname.c_str() ); session->UpdateScreen(); R_LoadImage( fullname, &buffers[i], &width, &height, NULL, true ); + if ( !buffers[i] ) { common->Printf( "failed.\n" ); + for ( i-- ; i >= 0 ; i-- ) { Mem_Free( buffers[i] ); } @@ -1881,9 +2020,8 @@ void R_MakeAmbientMap_f( const idCmdArgs &args ) { } // resample with hemispherical blending - int samples = 1000; - - byte *outBuffer = (byte *)_alloca( outSize * outSize * 4 ); + int samples = 1000; + byte *outBuffer = ( byte * )_alloca( outSize * outSize * 4 ); for ( int map = 0 ; map < 2 ; map++ ) { for ( i = 0 ; i < 6 ; i++ ) { @@ -1892,39 +2030,43 @@ void R_MakeAmbientMap_f( const idCmdArgs &args ) { idVec3 dir; float total[3]; - dir = cubeAxis[i][0] + -( -1 + 2.0*x/(outSize-1) ) * cubeAxis[i][1] + -( -1 + 2.0*y/(outSize-1) ) * cubeAxis[i][2]; + dir = cubeAxis[i][0] + -( -1 + 2.0 * x / ( outSize - 1 ) ) * cubeAxis[i][1] + -( -1 + 2.0 * y / ( outSize - 1 ) ) * cubeAxis[i][2]; dir.Normalize(); total[0] = total[1] = total[2] = 0; - //samples = 1; + //samples = 1; float limit = map ? 0.95 : 0.25; // small for specular, almost hemisphere for ambient for ( int s = 0 ; s < samples ; s++ ) { // pick a random direction vector that is inside the unit sphere but not behind dir, // which is a robust way to evenly sample a hemisphere idVec3 test; - while( 1 ) { + + while ( 1 ) { for ( int j = 0 ; j < 3 ; j++ ) { - test[j] = -1 + 2 * (rand()&0x7fff)/(float)0x7fff; + test[j] = -1 + 2 * ( rand() & 0x7fff ) / ( float )0x7fff; } + if ( test.Length() > 1.0 ) { continue; } test.Normalize(); + if ( test * dir > limit ) { // don't do a complete hemisphere break; } } byte result[4]; - //test = dir; + + //test = dir; R_SampleCubeMap( test, width, buffers, result ); total[0] += result[0]; total[1] += result[1]; total[2] += result[2]; } - outBuffer[(y*outSize+x)*4+0] = total[0] / samples; - outBuffer[(y*outSize+x)*4+1] = total[1] / samples; - outBuffer[(y*outSize+x)*4+2] = total[2] / samples; - outBuffer[(y*outSize+x)*4+3] = 255; + outBuffer[( y * outSize + x ) * 4 + 0] = total[0] / samples; + outBuffer[( y * outSize + x ) * 4 + 1] = total[1] / samples; + outBuffer[( y * outSize + x ) * 4 + 2] = total[2] / samples; + outBuffer[( y * outSize + x ) * 4 + 3] = 255; } } @@ -1955,61 +2097,59 @@ R_SetColorMappings =============== */ void R_SetColorMappings( void ) { - if ( r_gammaInShader.GetBool() ) { // nothing to do here return; } - - int i, j; - float g, b; - int inf; - unsigned short gammaTable[256]; + int i, j; + float g, b; + int inf; + unsigned short gammaTable[256]; b = r_brightness.GetFloat(); g = r_gamma.GetFloat(); for ( i = 0; i < 256; i++ ) { j = i * b; - if (j > 255) { + + if ( j > 255 ) { j = 255; } if ( g == 1 ) { - inf = (j<<8) | j; + inf = ( j << 8 ) | j; } else { - inf = 0xffff * pow ( j/255.0f, 1.0f / g ) + 0.5f; + inf = 0xffff * pow( j / 255.0f, 1.0f / g ) + 0.5f; } - if (inf < 0) { + + if ( inf < 0 ) { inf = 0; } - if (inf > 0xffff) { + + if ( inf > 0xffff ) { inf = 0xffff; } - gammaTable[i] = inf; } - GLimp_SetGamma( gammaTable, gammaTable, gammaTable ); } - /* ================ GfxInfo_f ================ */ static void GfxInfo_f( const idCmdArgs &args ) { - const char *fsstrings[] = - { + const char *fsstrings[] = { "windowed", "fullscreen" }; - const char* fsmode = fsstrings[r_fullscreen.GetBool()]; - if ( r_fullscreen.GetBool() && r_fullscreenDesktop.GetBool() ) - fsmode = "desktop-fullscreen"; + const char *fsmode = fsstrings[r_fullscreen.GetBool()]; + if ( r_fullscreen.GetBool() && r_fullscreenDesktop.GetBool() ) { + fsmode = "desktop-fullscreen"; + } common->Printf( "\nGL_VENDOR: %s\n", glConfig.vendor_string ); common->Printf( "GL_RENDERER: %s\n", glConfig.renderer_string ); common->Printf( "GL_VERSION: %s\n", glConfig.version_string ); @@ -2041,7 +2181,6 @@ static void GfxInfo_f( const idCmdArgs &args ) { } else { common->Printf( "glFinish not forced\n" ); } - bool tss = glConfig.twoSidedStencilAvailable; if ( !r_useTwoSidedStencil.GetBool() && tss ) { @@ -2051,12 +2190,6 @@ static void GfxInfo_f( const idCmdArgs &args ) { } else if ( tss ) { common->Printf( "Using two sided stencil\n" ); } - - if ( vertexCache.IsFast() ) { - common->Printf( "Vertex cache is fast\n" ); - } else { - common->Printf( "Vertex cache is SLOW\n" ); - } } /* @@ -2071,14 +2204,15 @@ void R_VidRestart_f( const idCmdArgs &args ) { if ( !glConfig.isInitialized ) { return; } - bool full = true; bool forceWindow = false; + for ( int i = 1 ; i < args.Argc() ; i++ ) { if ( idStr::Icmp( args.Argv( i ), "partial" ) == 0 ) { full = false; continue; } + if ( idStr::Icmp( args.Argv( i ), "windowed" ) == 0 ) { forceWindow = true; continue; @@ -2096,7 +2230,8 @@ void R_VidRestart_f( const idCmdArgs &args ) { // instead of doing a full vid_restart. Still falls back to a full vid_restart // in case this doesn't work (for example because MSAA settings have changed) if ( !full ) { - int wantedWidth=0, wantedHeight=0; + int wantedWidth = 0, wantedHeight = 0; + if ( !R_GetModeInfo( &wantedWidth, &wantedHeight, r_mode.GetInteger() ) ) { common->Warning( "vid_restart: R_GetModeInfo() failed?!\n" ); } else { @@ -2107,6 +2242,7 @@ void R_VidRestart_f( const idCmdArgs &args ) { parms.fullScreen = ( forceWindow ) ? false : r_fullscreen.GetBool(); parms.fullScreenDesktop = r_fullscreenDesktop.GetBool(); parms.displayHz = r_displayRefresh.GetInteger(); + // "vid_restart partial windowed" is used in case of errors to return to windowed mode // before things explode more. in that case just keep whatever MSAA setting is active parms.multiSamples = forceWindow ? -1 : r_multiSamples.GetInteger(); @@ -2120,9 +2256,8 @@ void R_VidRestart_f( const idCmdArgs &args ) { } // DG: notify the game DLL about the reloadImages and (non-partial) vid_restart commands - if(gameCallbacks.reloadImagesCB != NULL) - { - gameCallbacks.reloadImagesCB(gameCallbacks.reloadImagesUserArg, args); + if ( gameCallbacks.reloadImagesCB != NULL ) { + gameCallbacks.reloadImagesCB( gameCallbacks.reloadImagesUserArg, args ); } // this could take a while, so give them the cursor back ASAP @@ -2147,12 +2282,14 @@ void R_VidRestart_f( const idCmdArgs &args ) { soundSystem->ShutdownHW(); Sys_ShutdownInput(); globalImages->PurgeAllImages(); + // free the context and close the window GLimp_Shutdown(); glConfig.isInitialized = false; // create the new context and vertex cache bool latch = cvarSystem->GetCVarBool( "r_fullscreen" ); + if ( forceWindow ) { cvarSystem->SetCVarBool( "r_fullscreen", false ); } @@ -2171,6 +2308,7 @@ void R_VidRestart_f( const idCmdArgs &args ) { // check for problems err = qglGetError(); + if ( err != GL_NO_ERROR ) { common->Printf( "glGetError() = 0x%x\n", err ); } @@ -2187,6 +2325,7 @@ R_InitMaterials */ void R_InitMaterials( void ) { tr.defaultMaterial = declManager->FindMaterial( "_default", false ); + if ( !tr.defaultMaterial ) { common->FatalError( "_default material not found" ); } @@ -2213,7 +2352,6 @@ static void R_SizeUp_f( const idCmdArgs &args ) { } } - /* ================= R_SizeDown_f @@ -2229,7 +2367,6 @@ static void R_SizeDown_f( const idCmdArgs &args ) { } } - /* =============== TouchGui_f @@ -2244,7 +2381,6 @@ void R_TouchGui_f( const idCmdArgs &args ) { common->Printf( "USAGE: touchGui \n" ); return; } - common->Printf( "touchGui %s\n", gui ); session->UpdateScreen(); uiManager->Touch( gui ); @@ -2265,7 +2401,7 @@ R_InitCommands ================= */ void R_InitCommands( void ) { - cmdSystem->AddCommand( "MakeMegaTexture", idMegaTexture::MakeMegaTexture_f, CMD_FL_RENDERER|CMD_FL_CHEAT, "processes giant images" ); + cmdSystem->AddCommand( "MakeMegaTexture", idMegaTexture::MakeMegaTexture_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "processes giant images" ); cmdSystem->AddCommand( "sizeUp", R_SizeUp_f, CMD_FL_RENDERER, "makes the rendered view larger" ); cmdSystem->AddCommand( "sizeDown", R_SizeDown_f, CMD_FL_RENDERER, "makes the rendered view smaller" ); cmdSystem->AddCommand( "reloadGuis", R_ReloadGuis_f, CMD_FL_RENDERER, "reloads guis" ); @@ -2273,7 +2409,7 @@ void R_InitCommands( void ) { cmdSystem->AddCommand( "touchGui", R_TouchGui_f, CMD_FL_RENDERER, "touches a gui" ); cmdSystem->AddCommand( "screenshot", R_ScreenShot_f, CMD_FL_RENDERER, "takes a screenshot" ); cmdSystem->AddCommand( "envshot", R_EnvShot_f, CMD_FL_RENDERER, "takes an environment shot" ); - cmdSystem->AddCommand( "makeAmbientMap", R_MakeAmbientMap_f, CMD_FL_RENDERER|CMD_FL_CHEAT, "makes an ambient map" ); + cmdSystem->AddCommand( "makeAmbientMap", R_MakeAmbientMap_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "makes an ambient map" ); cmdSystem->AddCommand( "benchmark", R_Benchmark_f, CMD_FL_RENDERER, "benchmark" ); cmdSystem->AddCommand( "gfxInfo", GfxInfo_f, CMD_FL_RENDERER, "show graphics info" ); cmdSystem->AddCommand( "modulateLights", R_ModulateLights_f, CMD_FL_RENDERER | CMD_FL_CHEAT, "modifies shader parms on all lights" ); @@ -2339,10 +2475,10 @@ idRenderSystemLocal::Init */ void idRenderSystemLocal::Init( void ) { // clear all our internal state - viewCount = 1; // so cleared structures never match viewCount + viewCount = 1; + // so cleared structures never match viewCount // we used to memset tr, but now that it is a class, we can't, so // there may be other state we need to reset - ambientLightVector[0] = 0.5f; ambientLightVector[1] = 0.5f - 0.385f; ambientLightVector[2] = 0.8925f; @@ -2371,9 +2507,9 @@ void idRenderSystemLocal::Init( void ) { renderModelManager->Init(); // set the identity space - identitySpace.modelMatrix[0*4+0] = 1.0f; - identitySpace.modelMatrix[1*4+1] = 1.0f; - identitySpace.modelMatrix[2*4+2] = 1.0f; + identitySpace.modelMatrix[0 * 4 + 0] = 1.0f; + identitySpace.modelMatrix[1 * 4 + 1] = 1.0f; + identitySpace.modelMatrix[2 * 4 + 2] = 1.0f; origWidth = origHeight = 0; // DG: for resetting width/height in EndFrame() } @@ -2393,7 +2529,6 @@ void idRenderSystemLocal::Shutdown( void ) { if ( glConfig.isInitialized ) { globalImages->PurgeAllImages(); } - renderModelManager->Shutdown(); idCinematic::ShutdownCinematic( ); @@ -2436,6 +2571,7 @@ idRenderSystemLocal::EndLevelLoad void idRenderSystemLocal::EndLevelLoad( void ) { renderModelManager->EndLevelLoad(); globalImages->EndLevelLoad(); + if ( r_forceLoadImages.GetBool() ) { RB_ShowImages(); } @@ -2456,6 +2592,7 @@ void idRenderSystemLocal::InitOpenGL( void ) { globalImages->ReloadAllImages(); err = qglGetError(); + if ( err != GL_NO_ERROR ) { common->Printf( "glGetError() = 0x%x\n", err ); } @@ -2468,7 +2605,6 @@ idRenderSystemLocal::ShutdownOpenGL ======================== */ void idRenderSystemLocal::ShutdownOpenGL( void ) { - R_ShutdownFrameData(); // as the input is tied to the window, it should be shut down when the window diff --git a/neo/renderer/RenderWorld.cpp b/neo/renderer/RenderWorld.cpp index 2f77916d1..99fc5ebdc 100644 --- a/neo/renderer/RenderWorld.cpp +++ b/neo/renderer/RenderWorld.cpp @@ -1588,13 +1588,12 @@ void idRenderWorldLocal::PushVolumeIntoTree_r( idRenderEntityLocal *def, idRende if ( def ) { AddEntityRefToArea( def, area ); } + if ( light ) { AddLightRefToArea( light, area ); } - return; } - node = areaNodes + nodeNum; // if we know that all possible children nodes only touch an area diff --git a/neo/renderer/RenderWorld_portals.cpp b/neo/renderer/RenderWorld_portals.cpp index 1fbba78d0..9baa46e9d 100644 --- a/neo/renderer/RenderWorld_portals.cpp +++ b/neo/renderer/RenderWorld_portals.cpp @@ -740,8 +740,8 @@ void idRenderWorldLocal::AddAreaLightRefs( int areaNum, const portalStack_t *ps // check for being closed off behind a door // a light that doesn't cast shadows will still light even if it is behind a door if ( r_useLightCulling.GetInteger() >= 3 && - !light->parms.noShadows && light->lightShader->LightCastsShadows() - && light->areaNum != -1 && !tr.viewDef->connectedAreas[ light->areaNum ] ) { + !light->parms.noShadows && light->lightShader->LightCastsShadows() && + light->areaNum != -1 && !tr.viewDef->connectedAreas[ light->areaNum ] ) { continue; } @@ -751,7 +751,6 @@ void idRenderWorldLocal::AddAreaLightRefs( int areaNum, const portalStack_t *ps // still be visible through others continue; } - vLight = R_SetLightDefViewLight( light ); // expand the scissor rect diff --git a/neo/renderer/VertexCache.cpp b/neo/renderer/VertexCache.cpp index ec0184e59..5fba1287a 100644 --- a/neo/renderer/VertexCache.cpp +++ b/neo/renderer/VertexCache.cpp @@ -1,561 +1,627 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "framework/Common.h" -#include "renderer/tr_local.h" - -#include "renderer/VertexCache.h" - -static const int FRAME_MEMORY_BYTES = 0x200000; -static const int EXPAND_HEADERS = 1024; - -idCVar idVertexCache::r_showVertexCache( "r_showVertexCache", "0", CVAR_INTEGER|CVAR_RENDERER, "" ); -idCVar idVertexCache::r_vertexBufferMegs( "r_vertexBufferMegs", "32", CVAR_INTEGER|CVAR_RENDERER, "" ); - -idVertexCache vertexCache; - -/* -============== -R_ListVertexCache_f -============== -*/ -static void R_ListVertexCache_f( const idCmdArgs &args ) { - vertexCache.List(); -} - -/* -============== -idVertexCache::ActuallyFree -============== -*/ -void idVertexCache::ActuallyFree( vertCache_t *block ) { - if (!block) { - common->Error( "idVertexCache Free: NULL pointer" ); - } - - if ( block->user ) { - // let the owner know we have purged it - *block->user = NULL; - block->user = NULL; - } - - // temp blocks are in a shared space that won't be freed - if ( block->tag != TAG_TEMP ) { - staticAllocTotal -= block->size; - staticCountTotal--; - - if ( block->vbo ) { -#if 0 // this isn't really necessary, it will be reused soon enough - // filling with zero length data is the equivalent of freeing - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, block->vbo); - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, 0, 0, GL_DYNAMIC_DRAW_ARB); -#endif - } else if ( block->virtMem ) { - Mem_Free( block->virtMem ); - block->virtMem = NULL; - } - } - block->tag = TAG_FREE; // mark as free - - // unlink stick it back on the free list - block->next->prev = block->prev; - block->prev->next = block->next; - -#if 1 - // stick it on the front of the free list so it will be reused immediately - block->next = freeStaticHeaders.next; - block->prev = &freeStaticHeaders; -#else - // stick it on the back of the free list so it won't be reused soon (just for debugging) - block->next = &freeStaticHeaders; - block->prev = freeStaticHeaders.prev; -#endif - - block->next->prev = block; - block->prev->next = block; -} - -/* -============== -idVertexCache::Position - -this will be a real pointer with virtual memory, -but it will be an int offset cast to a pointer with -ARB_vertex_buffer_object - -The ARB_vertex_buffer_object will be bound -============== -*/ -void *idVertexCache::Position( vertCache_t *buffer ) { - if ( !buffer || buffer->tag == TAG_FREE ) { - common->FatalError( "idVertexCache::Position: bad vertCache_t" ); - } - - // the ARB vertex object just uses an offset - if ( buffer->vbo ) { - if ( r_showVertexCache.GetInteger() == 2 ) { - if ( buffer->tag == TAG_TEMP ) { - common->Printf( "GL_ARRAY_BUFFER_ARB = %i + %zd (%i bytes)\n", buffer->vbo, buffer->offset, buffer->size ); - } else { - common->Printf( "GL_ARRAY_BUFFER_ARB = %i (%i bytes)\n", buffer->vbo, buffer->size ); - } - } - if ( buffer->indexBuffer ) { - qglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, buffer->vbo ); - } else { - qglBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->vbo ); - } - return (void *)buffer->offset; - } - - // virtual memory is a real pointer - return (void *)((byte *)buffer->virtMem + buffer->offset); -} - -void idVertexCache::UnbindIndex() { - qglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); -} - - -//================================================================================ - -/* -=========== -idVertexCache::Init -=========== -*/ -void idVertexCache::Init() { - cmdSystem->AddCommand( "listVertexCache", R_ListVertexCache_f, CMD_FL_RENDERER, "lists vertex cache" ); - - if ( r_vertexBufferMegs.GetInteger() < 8 ) { - r_vertexBufferMegs.SetInteger( 8 ); - } - - virtualMemory = false; - - // use ARB_vertex_buffer_object unless explicitly disabled - if( r_useVertexBuffers.GetInteger() && glConfig.ARBVertexBufferObjectAvailable ) { - common->Printf( "using ARB_vertex_buffer_object memory\n" ); - } else { - virtualMemory = true; - r_useIndexBuffers.SetBool( false ); - common->Printf( "WARNING: vertex array range in virtual memory (SLOW)\n" ); - } - - // initialize the cache memory blocks - freeStaticHeaders.next = freeStaticHeaders.prev = &freeStaticHeaders; - staticHeaders.next = staticHeaders.prev = &staticHeaders; - freeDynamicHeaders.next = freeDynamicHeaders.prev = &freeDynamicHeaders; - dynamicHeaders.next = dynamicHeaders.prev = &dynamicHeaders; - deferredFreeList.next = deferredFreeList.prev = &deferredFreeList; - - // set up the dynamic frame memory - frameBytes = FRAME_MEMORY_BYTES; - staticAllocTotal = 0; - - byte *junk = (byte *)Mem_Alloc( frameBytes ); - for ( int i = 0 ; i < NUM_VERTEX_FRAMES ; i++ ) { - allocatingTempBuffer = true; // force the alloc to use GL_STREAM_DRAW_ARB - Alloc( junk, frameBytes, &tempBuffers[i] ); - allocatingTempBuffer = false; - tempBuffers[i]->tag = TAG_FIXED; - // unlink these from the static list, so they won't ever get purged - tempBuffers[i]->next->prev = tempBuffers[i]->prev; - tempBuffers[i]->prev->next = tempBuffers[i]->next; - } - Mem_Free( junk ); - - EndFrame(); -} - -/* -=========== -idVertexCache::PurgeAll - -Used when toggling vertex programs on or off, because -the cached data isn't valid -=========== -*/ -void idVertexCache::PurgeAll() { - while( staticHeaders.next != &staticHeaders ) { - ActuallyFree( staticHeaders.next ); - } -} - -/* -=========== -idVertexCache::Shutdown -=========== -*/ -void idVertexCache::Shutdown() { -// PurgeAll(); // !@#: also purge the temp buffers - - headerAllocator.Shutdown(); -} - -/* -=========== -idVertexCache::Alloc -=========== -*/ -void idVertexCache::Alloc( void *data, int size, vertCache_t **buffer, bool indexBuffer ) { - vertCache_t *block; - - if ( size <= 0 ) { - common->Error( "idVertexCache::Alloc: size = %i\n", size ); - } - - // if we can't find anything, it will be NULL - *buffer = NULL; - - // if we don't have any remaining unused headers, allocate some more - if ( freeStaticHeaders.next == &freeStaticHeaders ) { - - for ( int i = 0; i < EXPAND_HEADERS; i++ ) { - block = headerAllocator.Alloc(); - block->next = freeStaticHeaders.next; - block->prev = &freeStaticHeaders; - block->next->prev = block; - block->prev->next = block; - - if( !virtualMemory ) { - qglGenBuffersARB( 1, & block->vbo ); - } - } - } - - // move it from the freeStaticHeaders list to the staticHeaders list - block = freeStaticHeaders.next; - block->next->prev = block->prev; - block->prev->next = block->next; - block->next = staticHeaders.next; - block->prev = &staticHeaders; - block->next->prev = block; - block->prev->next = block; - - block->size = size; - block->offset = 0; - block->tag = TAG_USED; - - // save data for debugging - staticAllocThisFrame += block->size; - staticCountThisFrame++; - staticCountTotal++; - staticAllocTotal += block->size; - - // this will be set to zero when it is purged - block->user = buffer; - *buffer = block; - - // allocation doesn't imply used-for-drawing, because at level - // load time lots of things may be created, but they aren't - // referenced by the GPU yet, and can be purged if needed. - block->frameUsed = currentFrame - NUM_VERTEX_FRAMES; - - block->indexBuffer = indexBuffer; - - // copy the data - if ( block->vbo ) { - if ( indexBuffer ) { - qglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, block->vbo ); - qglBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, (GLsizeiptrARB)size, data, GL_STATIC_DRAW_ARB ); - } else { - qglBindBufferARB( GL_ARRAY_BUFFER_ARB, block->vbo ); - if ( allocatingTempBuffer ) { - qglBufferDataARB( GL_ARRAY_BUFFER_ARB, (GLsizeiptrARB)size, data, GL_STREAM_DRAW_ARB ); - } else { - qglBufferDataARB( GL_ARRAY_BUFFER_ARB, (GLsizeiptrARB)size, data, GL_STATIC_DRAW_ARB ); - } - } - } else { - block->virtMem = Mem_Alloc( size ); - SIMDProcessor->Memcpy( block->virtMem, data, size ); - } -} - -/* -=========== -idVertexCache::Touch -=========== -*/ -void idVertexCache::Touch( vertCache_t *block ) { - if ( !block ) { - common->Error( "idVertexCache Touch: NULL pointer" ); - } - - if ( block->tag == TAG_FREE ) { - common->FatalError( "idVertexCache Touch: freed pointer" ); - } - if ( block->tag == TAG_TEMP ) { - common->FatalError( "idVertexCache Touch: temporary pointer" ); - } - - block->frameUsed = currentFrame; - - // move to the head of the LRU list - block->next->prev = block->prev; - block->prev->next = block->next; - - block->next = staticHeaders.next; - block->prev = &staticHeaders; - staticHeaders.next->prev = block; - staticHeaders.next = block; -} - -/* -=========== -idVertexCache::Free -=========== -*/ -void idVertexCache::Free( vertCache_t *block ) { - if (!block) { - return; - } - - if ( block->tag == TAG_FREE ) { - common->FatalError( "idVertexCache Free: freed pointer" ); - } - if ( block->tag == TAG_TEMP ) { - common->FatalError( "idVertexCache Free: temporary pointer" ); - } - - // this block still can't be purged until the frame count has expired, - // but it won't need to clear a user pointer when it is - block->user = NULL; - - block->next->prev = block->prev; - block->prev->next = block->next; - - block->next = deferredFreeList.next; - block->prev = &deferredFreeList; - deferredFreeList.next->prev = block; - deferredFreeList.next = block; -} - -/* -=========== -idVertexCache::AllocFrameTemp - -A frame temp allocation must never be allowed to fail due to overflow. -We can't simply sync with the GPU and overwrite what we have, because -there may still be future references to dynamically created surfaces. -=========== -*/ -vertCache_t *idVertexCache::AllocFrameTemp( void *data, int size ) { - vertCache_t *block; - - if ( size <= 0 ) { - common->Error( "idVertexCache::AllocFrameTemp: size = %i\n", size ); - } - - if ( dynamicAllocThisFrame + size > frameBytes ) { - // if we don't have enough room in the temp block, allocate a static block, - // but immediately free it so it will get freed at the next frame - tempOverflow = true; - Alloc( data, size, &block ); - Free( block); - return block; - } - - // this data is just going on the shared dynamic list - - // if we don't have any remaining unused headers, allocate some more - if ( freeDynamicHeaders.next == &freeDynamicHeaders ) { - - for ( int i = 0; i < EXPAND_HEADERS; i++ ) { - block = headerAllocator.Alloc(); - block->next = freeDynamicHeaders.next; - block->prev = &freeDynamicHeaders; - block->next->prev = block; - block->prev->next = block; - } - } - - // move it from the freeDynamicHeaders list to the dynamicHeaders list - block = freeDynamicHeaders.next; - block->next->prev = block->prev; - block->prev->next = block->next; - block->next = dynamicHeaders.next; - block->prev = &dynamicHeaders; - block->next->prev = block; - block->prev->next = block; - - block->size = size; - block->tag = TAG_TEMP; - block->indexBuffer = false; - block->offset = dynamicAllocThisFrame; - dynamicAllocThisFrame += block->size; - dynamicCountThisFrame++; - block->user = NULL; - block->frameUsed = 0; - - // copy the data - block->virtMem = tempBuffers[listNum]->virtMem; - block->vbo = tempBuffers[listNum]->vbo; - - if ( block->vbo ) { - qglBindBufferARB( GL_ARRAY_BUFFER_ARB, block->vbo ); - qglBufferSubDataARB( GL_ARRAY_BUFFER_ARB, block->offset, (GLsizeiptrARB)size, data ); - } else { - SIMDProcessor->Memcpy( (byte *)block->virtMem + block->offset, data, size ); - } - - return block; -} - -/* -=========== -idVertexCache::EndFrame -=========== -*/ -void idVertexCache::EndFrame() { - // display debug information - if ( r_showVertexCache.GetBool() ) { - int staticUseCount = 0; - int staticUseSize = 0; - - for ( vertCache_t *block = staticHeaders.next ; block != &staticHeaders ; block = block->next ) { - if ( block->frameUsed == currentFrame ) { - staticUseCount++; - staticUseSize += block->size; - } - } - - const char *frameOverflow = tempOverflow ? "(OVERFLOW)" : ""; - - common->Printf( "vertex dynamic:%i=%ik%s, static alloc:%i=%ik used:%i=%ik total:%i=%ik\n", - dynamicCountThisFrame, dynamicAllocThisFrame/1024, frameOverflow, - staticCountThisFrame, staticAllocThisFrame/1024, - staticUseCount, staticUseSize/1024, - staticCountTotal, staticAllocTotal/1024 ); - } - -#if 0 - // if our total static count is above our working memory limit, start purging things - while ( staticAllocTotal > r_vertexBufferMegs.GetInteger() * 1024 * 1024 ) { - // free the least recently used - - } -#endif - - if( !virtualMemory ) { - // unbind vertex buffers so normal virtual memory will be used in case - // r_useVertexBuffers / r_useIndexBuffers - qglBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 ); - qglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); - } - - - currentFrame = tr.frameCount; - listNum = currentFrame % NUM_VERTEX_FRAMES; - staticAllocThisFrame = 0; - staticCountThisFrame = 0; - dynamicAllocThisFrame = 0; - dynamicCountThisFrame = 0; - tempOverflow = false; - - // free all the deferred free headers - while( deferredFreeList.next != &deferredFreeList ) { - ActuallyFree( deferredFreeList.next ); - } - - // free all the frame temp headers - vertCache_t *block = dynamicHeaders.next; - if ( block != &dynamicHeaders ) { - block->prev = &freeDynamicHeaders; - dynamicHeaders.prev->next = freeDynamicHeaders.next; - freeDynamicHeaders.next->prev = dynamicHeaders.prev; - freeDynamicHeaders.next = block; - - dynamicHeaders.next = dynamicHeaders.prev = &dynamicHeaders; - } -} - -/* -============= -idVertexCache::List -============= -*/ -void idVertexCache::List( void ) { - int numActive = 0; - int frameStatic = 0; - int totalStatic = 0; - - vertCache_t *block; - for ( block = staticHeaders.next ; block != &staticHeaders ; block = block->next) { - numActive++; - - totalStatic += block->size; - if ( block->frameUsed == currentFrame ) { - frameStatic += block->size; - } - } - - int numFreeStaticHeaders = 0; - for ( block = freeStaticHeaders.next ; block != &freeStaticHeaders ; block = block->next ) { - numFreeStaticHeaders++; - } - - int numFreeDynamicHeaders = 0; - for ( block = freeDynamicHeaders.next ; block != &freeDynamicHeaders ; block = block->next ) { - numFreeDynamicHeaders++; - } - - common->Printf( "%i megs working set\n", r_vertexBufferMegs.GetInteger() ); - common->Printf( "%i dynamic temp buffers of %ik\n", NUM_VERTEX_FRAMES, frameBytes / 1024 ); - common->Printf( "%5i active static headers\n", numActive ); - common->Printf( "%5i free static headers\n", numFreeStaticHeaders ); - common->Printf( "%5i free dynamic headers\n", numFreeDynamicHeaders ); - - if ( !virtualMemory ) { - common->Printf( "Vertex cache is in ARB_vertex_buffer_object memory (FAST).\n"); - } else { - common->Printf( "Vertex cache is in virtual memory (SLOW)\n" ); - } - - if ( r_useIndexBuffers.GetBool() ) { - common->Printf( "Index buffers are accelerated.\n" ); - } else { - common->Printf( "Index buffers are not used.\n" ); - } -} - -/* -============= -idVertexCache::IsFast - -just for gfxinfo printing -============= -*/ -bool idVertexCache::IsFast() { - if ( virtualMemory ) { - return false; - } - return true; -} +/* +=========================================================================== + +Doom 3 GPL Source Code +Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. + +This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). + +Doom 3 Source Code is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Doom 3 Source Code is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Doom 3 Source Code. If not, see . + +In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of +these additional terms immediately following the terms and conditions of the GNU General Public License which +accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address +below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id +Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ + +#include "renderer/VertexCache.h" +#include "framework/Common.h" +#include "renderer/tr_local.h" +#include "sys/platform.h" + +static const int FRAME_MEMORY_BYTES = 0x400000; +static const int EXPAND_HEADERS = 1024; + +idCVar idVertexCache::r_showVertexCache( "r_showVertexCache", "0", CVAR_INTEGER | CVAR_RENDERER, + "show vertex cache, 0 = off, 1 = vbo debug, 2 = vbo mem", + idCmdSystem::ArgCompletion_Integer<0, 2> ); +idCVar idVertexCache::r_useArbBufferRange( "r_useArbBufferRange", "1", CVAR_BOOL | CVAR_RENDERER, + "use ARB_map_buffer_range for optimization, 0 = off, 1 = on", + idCmdSystem::ArgCompletion_Integer<0, 1> ); +idCVar idVertexCache::r_reuseVertexCacheSooner( "r_reuseVertexCacheSooner", "1", CVAR_BOOL | CVAR_RENDERER, + "reuse vertex buffers as soon as possible after freeing, 0 = off, 1 = on", + idCmdSystem::ArgCompletion_Integer<0, 1> ); + +idVertexCache vertexCache; + +/* +============== +R_ShowVBOMem_f +============== +*/ +void R_ShowVBOMem_f( const idCmdArgs &args ) { + vertexCache.Show(); +} + +/* +============== +R_ListVBOMem_f +============== +*/ +void R_ListVBOMem_f( const idCmdArgs &args ) { + vertexCache.List(); +} + +/* +============== +idVertexCache::ActuallyFree +============== +*/ +void idVertexCache::ActuallyFree( vertCache_t *block ) { + if ( !block ) { + common->Error( "idVertexCache Free: NULL pointer" ); + } + + if ( block->user ) { + // let the owner know we have purged it + *block->user = NULL; + block->user = NULL; + } + + // temp blocks are in a shared space that won't be freed + if ( block->tag != TAG_TEMP ) { + staticAllocTotal -= block->size; + staticCountTotal--; + } + block->tag = TAG_FREE; // mark as free + + // unlink stick it back on the free list + block->next->prev = block->prev; + block->prev->next = block->next; + + if ( r_reuseVertexCacheSooner.GetBool() ) { + // stick it on the front of the free list so it will be reused immediately + block->next = freeStaticHeaders.next; + block->prev = &freeStaticHeaders; + } else { + // stick it on the back of the free list so it won't be reused soon (just for debugging) + block->next = &freeStaticHeaders; + block->prev = freeStaticHeaders.prev; + } + block->next->prev = block; + block->prev->next = block; +} + +/* +============== +idVertexCache::Position + +this will be a real pointer with virtual memory, +but it will be an int offset cast to a pointer with +ARB_vertex_buffer_object + +The ARB_vertex_buffer_object will be bound +============== +*/ +const void *idVertexCache::Position( vertCache_t *buffer ) { + if ( !buffer || buffer->tag == TAG_FREE ) { + common->FatalError( "idVertexCache::Position: bad vertCache_t" ); + } + + // the ARB vertex object just uses an offset + if ( buffer->vbo ) { + if ( r_showVertexCache.GetInteger() == 2 ) { + if ( buffer->tag == TAG_TEMP ) { + common->Printf( "GL_ARRAY_BUFFER_ARB = %i + %i (%i bytes)\n", buffer->vbo, buffer->offset, buffer->size ); + } else { + common->Printf( "GL_ARRAY_BUFFER_ARB = %i (%i bytes)\n", buffer->vbo, buffer->size ); + } + } + BindIndex( ( buffer->indexBuffer ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER ), buffer->vbo ); + return reinterpret_cast( buffer->offset ); + } + return NULL; +} + +//================================================================================ + +/* +=========== +idVertexCache::BindIndex + +Makes sure it only allocates the right buffers once. +=========== +*/ +void idVertexCache::BindIndex( GLenum target, GLuint vbo ) { + switch ( target ) { + case GL_ARRAY_BUFFER: + if ( vertexBuffer != vbo ) { + // this happens more often than you might think :( + qglBindBufferARB( target, vbo ); + vertexBuffer = vbo; + return; + } + break; + case GL_ELEMENT_ARRAY_BUFFER: + if ( indexBuffer != vbo ) { + // this happens more often than you might think :( + qglBindBufferARB( target, vbo ); + indexBuffer = vbo; + return; + } + break; + default: + common->FatalError( "BindIndex : unknown buffer target : %i\n", static_cast( target ) ); + break; + } +} + +/* +=========== +idVertexCache::UnbindIndex + +Pass 0 to vbo to invalidate it. +=========== +*/ +void idVertexCache::UnbindIndex( GLenum target ) { + BindIndex( target, 0 ); +} + +//================================================================================ + +/* +=========== +idVertexCache::Init +=========== +*/ +void idVertexCache::Init() { + // well this would suck... + if ( !glConfig.ARBVertexBufferObjectAvailable ) { + common->FatalError( "idVertexCache::Init: Your card is to old\n" ); + } + cmdSystem->AddCommand( "showVBOMem", R_ShowVBOMem_f, CMD_FL_RENDERER, "Shows Allocated Vertex Buffer Memory" ); + cmdSystem->AddCommand( "ListVBOMem", R_ListVBOMem_f, CMD_FL_RENDERER, "lists Objects Allocated in Vertex Cache" ); + + // initialize the buffers + vertexBuffer = 0; + indexBuffer = 0; + + // initialize the cache memory blocks + freeStaticHeaders.next = freeStaticHeaders.prev = &freeStaticHeaders; + staticHeaders.next = staticHeaders.prev = &staticHeaders; + freeDynamicHeaders.next = freeDynamicHeaders.prev = &freeDynamicHeaders; + dynamicHeaders.next = dynamicHeaders.prev = &dynamicHeaders; + deferredFreeList.next = deferredFreeList.prev = &deferredFreeList; + + // set up the dynamic frame memory + frameBytes = FRAME_MEMORY_BYTES; + staticAllocTotal = 0; + + // allocate a dummy buffer + byte *frameBuffer = new byte[frameBytes]; + for ( int i = 0; i < NUM_VERTEX_FRAMES; i++ ) { + // force the alloc to use GL_STREAM_DRAW_ARB + allocatingTempBuffer = true; + Alloc( frameBuffer, frameBytes, &tempBuffers[i] ); + allocatingTempBuffer = false; + tempBuffers[i]->tag = TAG_FIXED; + + // unlink these from the static list, so they won't ever get purged + tempBuffers[i]->next->prev = tempBuffers[i]->prev; + tempBuffers[i]->prev->next = tempBuffers[i]->next; + } + + // use C++ allocation + delete[] frameBuffer; + frameBuffer = NULL; + EndFrame(); +} + +/* +=========== +idVertexCache::PurgeAll + +Used when toggling vertex programs on or off, because +the cached data isn't valid +=========== +*/ +void idVertexCache::PurgeAll() { + while ( staticHeaders.next != &staticHeaders ) { + ActuallyFree( staticHeaders.next ); + } +} + +/* +=========== +idVertexCache::Shutdown +=========== +*/ +void idVertexCache::Shutdown() { + headerAllocator.Shutdown(); +} + +/* +=========== +idVertexCache::Alloc +=========== +*/ +void idVertexCache::Alloc( void *data, int size, vertCache_t **buffer, bool doIndex ) { + vertCache_t *block = NULL; + + if ( size <= 0 ) { + common->Error( "idVertexCache::Alloc: size = %i\n", size ); + } + + // if we can't find anything, it will be NULL + *buffer = NULL; + + // if we don't have any remaining unused headers, allocate some more + if ( freeStaticHeaders.next == &freeStaticHeaders ) { + for ( int i = 0; i < EXPAND_HEADERS; i++ ) { + block = headerAllocator.Alloc(); + qglGenBuffersARB( 1, &block->vbo ); + block->size = 0; + block->next = freeStaticHeaders.next; + block->prev = &freeStaticHeaders; + block->next->prev = block; + block->prev->next = block; + } + } + GLenum target = ( doIndex ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER ); + GLenum usage = ( allocatingTempBuffer ? GL_STREAM_DRAW : GL_STATIC_DRAW ); + + // try to find a matching block to replace so that we're not continually respecifying vbo data each frame + for ( vertCache_t *findblock = freeStaticHeaders.next; /**/; findblock = findblock->next ) { + if ( findblock == &freeStaticHeaders ) { + block = freeStaticHeaders.next; + break; + } + + if ( findblock->target != target ) { + continue; + } + + if ( findblock->usage != usage ) { + continue; + } + + if ( findblock->size != size ) { + continue; + } + block = findblock; + break; + } + + // move it from the freeStaticHeaders list to the staticHeaders list + block->target = target; + block->usage = usage; + + if ( block->vbo ) { + // orphan the buffer in case it needs respecifying (it usually will) + BindIndex( target, block->vbo ); + qglBufferDataARB( target, static_cast( size ), NULL, usage ); + qglBufferDataARB( target, static_cast( size ), data, usage ); + } + block->next->prev = block->prev; + block->prev->next = block->next; + block->next = staticHeaders.next; + block->prev = &staticHeaders; + block->next->prev = block; + block->prev->next = block; + block->size = size; + block->offset = 0; + block->tag = TAG_USED; + + // save data for debugging + staticAllocThisFrame += block->size; + staticCountThisFrame++; + staticCountTotal++; + staticAllocTotal += block->size; + + // this will be set to zero when it is purged + block->user = buffer; + *buffer = block; + + // allocation doesn't imply used-for-drawing, because at level + // load time lots of things may be created, but they aren't + // referenced by the GPU yet, and can be purged if needed. + block->frameUsed = currentFrame - NUM_VERTEX_FRAMES; + block->indexBuffer = doIndex; +} + +/* +=========== +idVertexCache::Touch +=========== +*/ +void idVertexCache::Touch( vertCache_t *block ) { + if ( !block ) { + common->Error( "idVertexCache Touch: NULL pointer" ); + } + + if ( block->tag == TAG_FREE ) { + common->FatalError( "idVertexCache Touch: freed pointer" ); + } + + if ( block->tag == TAG_TEMP ) { + common->FatalError( "idVertexCache Touch: temporary pointer" ); + } + block->frameUsed = currentFrame; + + // move to the head of the LRU list + block->next->prev = block->prev; + block->prev->next = block->next; + block->next = staticHeaders.next; + block->prev = &staticHeaders; + + staticHeaders.next->prev = block; + staticHeaders.next = block; +} + +/* +=========== +idVertexCache::Free +=========== +*/ +void idVertexCache::Free( vertCache_t *block ) { + if ( !block ) { + return; + } + + if ( block->tag == TAG_FREE ) { + common->FatalError( "idVertexCache Free: freed pointer" ); + } + + if ( block->tag == TAG_TEMP ) { + common->FatalError( "idVertexCache Free: temporary pointer" ); + } + + // this block still can't be purged until the frame count has expired, + // but it won't need to clear a user pointer when it is + block->user = NULL; + block->next->prev = block->prev; + block->prev->next = block->next; + block->next = deferredFreeList.next; + block->prev = &deferredFreeList; + + deferredFreeList.next->prev = block; + deferredFreeList.next = block; +} + +/* +=========== +idVertexCache::AllocFrameTemp + +A frame temp allocation must never be allowed to fail due to overflow. +We can't simply sync with the GPU and overwrite what we have, because +there may still be future references to dynamically created surfaces. +=========== +*/ +vertCache_t *idVertexCache::AllocFrameTemp( void *data, int size ) { + vertCache_t *block = NULL; + + if ( size <= 0 ) { + common->Error( "idVertexCache::AllocFrameTemp: size = %i\n", size ); + } + + if ( dynamicAllocThisFrame + size > frameBytes ) { + // if we don't have enough room in the temp block, allocate a static block, + // but immediately free it so it will get freed at the next frame + tempOverflow = true; + Alloc( data, size, &block ); + Free( block ); + return block; + } + + // this data is just going on the shared dynamic list + // if we don't have any remaining unused headers, allocate some more + if ( freeDynamicHeaders.next == &freeDynamicHeaders ) { + for ( int i = 0; i < EXPAND_HEADERS; i++ ) { + block = headerAllocator.Alloc(); + block->next = freeDynamicHeaders.next; + block->prev = &freeDynamicHeaders; + block->next->prev = block; + block->prev->next = block; + } + } + + // move it from the freeDynamicHeaders list to the dynamicHeaders list + block = freeDynamicHeaders.next; + block->next->prev = block->prev; + block->prev->next = block->next; + block->next = dynamicHeaders.next; + block->prev = &dynamicHeaders; + block->next->prev = block; + block->prev->next = block; + block->size = size; + block->tag = TAG_TEMP; + block->indexBuffer = false; + block->offset = dynamicAllocThisFrame; + + dynamicAllocThisFrame += block->size; + dynamicCountThisFrame++; + + block->user = NULL; + block->frameUsed = 0; + + // copy the data + block->vbo = tempBuffers[listNum]->vbo; + + // mh code start + if ( block->vbo ) { + BindIndex( GL_ARRAY_BUFFER, block->vbo ); + + // try to get an unsynchronized map if at all possible + if ( r_useArbBufferRange.GetBool() && glConfig.ARBMapBufferRangeAvailable ) { + GLbitfield access = ( GL_MAP_WRITE_BIT | ( ( block->offset == 0 ) ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_RANGE_BIT ) ); + GLvoid *dst = qglMapBufferRange( GL_ARRAY_BUFFER, block->offset, static_cast( size ), access ); + + // if the buffer has wrapped then we orphan it + if ( dst ) { + SIMDProcessor->Memcpy( reinterpret_cast( dst ), data, size ); + qglUnmapBufferARB( GL_ARRAY_BUFFER ); + return block; + } else { + qglBufferSubDataARB( GL_ARRAY_BUFFER, block->offset, static_cast( size ), data ); + } + } else { + qglBufferSubDataARB( GL_ARRAY_BUFFER, block->offset, static_cast( size ), data ); + } + } + return block; +} + +/* +=========== +idVertexCache::EndFrame +=========== +*/ +void idVertexCache::EndFrame() { + // display debug information + if ( r_showVertexCache.GetBool() == 1 ) { + int staticUseCount = 0; + int staticUseSize = 0; + + for ( vertCache_t *block = staticHeaders.next; block != &staticHeaders; block = block->next ) { + if ( block->frameUsed == currentFrame ) { + staticUseCount++; + staticUseSize += block->size; + } + } + const char *frameOverflow = tempOverflow ? "(OVERFLOW)" : ""; + common->Printf( "vertex dynamic:%i=%ik%s, static alloc:%i=%ik used:%i=%ik total:%i=%ik\n", + dynamicCountThisFrame, dynamicAllocThisFrame / 1024, frameOverflow, staticCountThisFrame, + staticAllocThisFrame / 1024, staticUseCount, staticUseSize / 1024, staticCountTotal, + staticAllocTotal / 1024 ); + } + + // unbind vertex buffers + UnbindIndex( GL_ARRAY_BUFFER_ARB ); + UnbindIndex( GL_ELEMENT_ARRAY_BUFFER_ARB ); + + currentFrame = tr.frameCount; + listNum = currentFrame % NUM_VERTEX_FRAMES; + staticAllocThisFrame = 0; + staticCountThisFrame = 0; + dynamicAllocThisFrame = 0; + dynamicCountThisFrame = 0; + tempOverflow = false; + + // free all the deferred free headers + while ( deferredFreeList.next != &deferredFreeList ) { + ActuallyFree( deferredFreeList.next ); + } + + // free all the frame temp headers + vertCache_t *block = dynamicHeaders.next; + + if ( block != &dynamicHeaders ) { + block->prev = &freeDynamicHeaders; + dynamicHeaders.prev->next = freeDynamicHeaders.next; + freeDynamicHeaders.next->prev = dynamicHeaders.prev; + freeDynamicHeaders.next = block; + dynamicHeaders.next = dynamicHeaders.prev = &dynamicHeaders; + } +} + +/* +============= +idVertexCache::List +============= +*/ +void idVertexCache::List( void ) { + int numActive = 0; + int frameStatic = 0; + int totalStatic = 0; + vertCache_t *block = NULL; + + for ( block = staticHeaders.next; block != &staticHeaders; block = block->next ) { + numActive++; + totalStatic += block->size; + + if ( block->frameUsed == currentFrame ) { + frameStatic += block->size; + } + } + int numFreeStaticHeaders = 0; + + for ( block = freeStaticHeaders.next; block != &freeStaticHeaders; block = block->next ) { + numFreeStaticHeaders++; + } + int numFreeDynamicHeaders = 0; + + for ( block = freeDynamicHeaders.next; block != &freeDynamicHeaders; block = block->next ) { + numFreeDynamicHeaders++; + } + common->Printf( "%i dynamic temp buffers of %ik\n", NUM_VERTEX_FRAMES, frameBytes / 1024 ); + common->Printf( "%5i active static headers\n", numActive ); + common->Printf( "%5i free static headers\n", numFreeStaticHeaders ); + common->Printf( "%5i free dynamic headers\n", numFreeDynamicHeaders ); +} + +/* +============= +idVertexCache::Show + +Barnes, +replaces the broken glconfig string version. +Real performance killer here, use with care. +============= +*/ +void idVertexCache::Show( void ) { + GLint mem[4]; + + if ( glConfig.vendor == glvAMD ) { + common->Printf( "\nATI/AMD specific memory info:\n" ); + common->Printf( "\n" ); + qglGetIntegerv( GL_VBO_FREE_MEMORY_ATI, mem ); + common->Printf( "VBO: total memory free in the pool %i MB\n", mem[0] >> 10 ); + common->Printf( "VBO: largest available free block in the pool %i MB\n", mem[1] >> 10 ); + common->Printf( "VBO: total auxiliary memory free %i MB\n", mem[2] >> 10 ); + common->Printf( "VBO: largest auxiliary free block %i MB\n", mem[3] >> 10 ); + qglGetIntegerv( GL_TEXTURE_FREE_MEMORY_ATI, mem ); + common->Printf( "Texture: total memory free in the pool %i MB\n", mem[0] >> 10 ); + common->Printf( "Texture: largest available free block in the pool %i MB\n", mem[1] >> 10 ); + common->Printf( "Texture: total auxiliary memory free %i MB\n", mem[2] >> 10 ); + common->Printf( "Texture: largest auxiliary free block %i MB\n", mem[3] >> 10 ); + qglGetIntegerv( GL_RENDERBUFFER_FREE_MEMORY_ATI, mem ); + common->Printf( "RenderBuffer: total memory free in the pool %i MB\n", mem[0] >> 10 ); + common->Printf( "RenderBuffer: largest available free block in the pool %i MB\n", mem[1] >> 10 ); + common->Printf( "RenderBuffer: total auxiliary memory free %i MB\n", mem[2] >> 10 ); + common->Printf( "RenderBuffer: largest auxiliary free block %i MB\n", mem[3] >> 10 ); + } else if ( glConfig.vendor == glvNVIDIA ) { + common->Printf( "\nNvidia specific memory info:\n" ); + common->Printf( "\n" ); + qglGetIntegerv( GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, mem ); + common->Printf( "dedicated video memory %i MB\n", mem[0] >> 10 ); + qglGetIntegerv( GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, mem ); + common->Printf( "total available memory %i MB\n", mem[0] >> 10 ); + qglGetIntegerv( GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, mem ); + common->Printf( "currently unused GPU memory %i MB\n", mem[0] >> 10 ); + qglGetIntegerv( GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX, mem ); + common->Printf( "count of total evictions seen by system %i MB\n", mem[0] >> 10 ); + qglGetIntegerv( GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX, mem ); + common->Printf( "total video memory evicted %i MB\n", mem[0] >> 10 ); + } else if ( glConfig.vendor == glvIntel ) { + // since the advent of they're new cards they might ? + common->Printf( "\nIntel cannot do memory info, sorry:\n" ); + } else { + common->Printf( "\nUnsupported card cannot do memory info, sorry:\n" ); + } +} diff --git a/neo/renderer/VertexCache.h b/neo/renderer/VertexCache.h index a1d0a0d56..0a65dfa65 100644 --- a/neo/renderer/VertexCache.h +++ b/neo/renderer/VertexCache.h @@ -1,146 +1,151 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "framework/CVarSystem.h" -#include "renderer/qgl.h" - -// vertex cache calls should only be made by the front end - -const int NUM_VERTEX_FRAMES = 2; - -typedef enum { - TAG_FREE, - TAG_USED, - TAG_FIXED, // for the temp buffers - TAG_TEMP // in frame temp area, not static area -} vertBlockTag_t; - -typedef struct vertCache_s { - GLuint vbo; - void *virtMem; // only one of vbo / virtMem will be set - bool indexBuffer; // holds indexes instead of vertexes - - intptr_t offset; - int size; // may be larger than the amount asked for, due - // to round up and minimum fragment sizes - int tag; // a tag of 0 is a free block - struct vertCache_s ** user; // will be set to zero when purged - struct vertCache_s *next, *prev; // may be on the static list or one of the frame lists - int frameUsed; // it can't be purged if near the current frame -} vertCache_t; - - -class idVertexCache { -public: - void Init(); - void Shutdown(); - - // just for gfxinfo printing - bool IsFast(); - - // called when vertex programs are enabled or disabled, because - // the cached data is no longer valid - void PurgeAll(); - - // Tries to allocate space for the given data in fast vertex - // memory, and copies it over. - // Alloc does NOT do a touch, which allows purging of things - // created at level load time even if a frame hasn't passed yet. - // These allocations can be purged, which will zero the pointer. - void Alloc( void *data, int bytes, vertCache_t **buffer, bool indexBuffer = false ); - - // This will be a real pointer with virtual memory, - // but it will be an int offset cast to a pointer of ARB_vertex_buffer_object - void * Position( vertCache_t *buffer ); - - // if r_useIndexBuffers is enabled, but you need to draw something without - // an indexCache, this must be called to reset GL_ELEMENT_ARRAY_BUFFER_ARB - void UnbindIndex(); - - // automatically freed at the end of the next frame - // used for specular texture coordinates and gui drawing, which - // will change every frame. - // will return NULL if the vertex cache is completely full - // As with Position(), this may not actually be a pointer you can access. - vertCache_t * AllocFrameTemp( void *data, int bytes ); - - // notes that a buffer is used this frame, so it can't be purged - // out from under the GPU - void Touch( vertCache_t *buffer ); - - // this block won't have to zero a buffer pointer when it is purged, - // but it must still wait for the frames to pass, in case the GPU - // is still referencing it - void Free( vertCache_t *buffer ); - - // updates the counter for determining which temp space to use - // and which blocks can be purged - // Also prints debugging info when enabled - void EndFrame(); - - // listVertexCache calls this - void List(); - -private: - void InitMemoryBlocks( int size ); - void ActuallyFree( vertCache_t *block ); - - static idCVar r_showVertexCache; - static idCVar r_vertexBufferMegs; - - int staticCountTotal; - int staticAllocTotal; // for end of frame purging - - int staticAllocThisFrame; // debug counter - int staticCountThisFrame; - int dynamicAllocThisFrame; - int dynamicCountThisFrame; - - int currentFrame; // for purgable block tracking - int listNum; // currentFrame % NUM_VERTEX_FRAMES, determines which tempBuffers to use - - bool virtualMemory; // not fast stuff - - bool allocatingTempBuffer; // force GL_STREAM_DRAW_ARB - - vertCache_t *tempBuffers[NUM_VERTEX_FRAMES]; // allocated at startup - bool tempOverflow; // had to alloc a temp in static memory - - idBlockAlloc headerAllocator; - - vertCache_t freeStaticHeaders; // head of doubly linked list - vertCache_t freeDynamicHeaders; // head of doubly linked list - vertCache_t dynamicHeaders; // head of doubly linked list - vertCache_t deferredFreeList; // head of doubly linked list - vertCache_t staticHeaders; // head of doubly linked list in MRU order, - // staticHeaders.next is most recently used - - int frameBytes; // for each of NUM_VERTEX_FRAMES frames -}; - -extern idVertexCache vertexCache; +/* +=========================================================================== + +Doom 3 GPL Source Code +Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. + +This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). + +Doom 3 Source Code is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Doom 3 Source Code is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Doom 3 Source Code. If not, see . + +In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of +these additional terms immediately following the terms and conditions of the GNU General Public License which +accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address +below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id +Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ + +#include "framework/CVarSystem.h" +#include "renderer/qgl.h" + +// vertex cache calls should only be made by the front end +const int NUM_VERTEX_FRAMES = 2; + +typedef enum { + TAG_FREE, + TAG_USED, + TAG_FIXED, // for the temp buffers + TAG_TEMP // in frame temp area, not static area +} vertBlockTag_t; + +typedef struct vertCache_s { + GLuint vbo; + GLenum target; + GLenum usage; + bool indexBuffer; // holds indexes instead of vertexes + + intptr_t offset; + int size; // may be larger than the amount asked for, due + // to round up and minimum fragment sizes + int tag; // a tag of 0 is a free block + struct vertCache_s **user; // will be set to zero when purged + struct vertCache_s *next, *prev; // may be on the static list or one of the frame lists + int frameUsed; // it can't be purged if near the current frame +} vertCache_t; + +class idVertexCache { +public: + void Init(); + void Shutdown(); + + // called when vertex programs are enabled or disabled, because + // the cached data is no longer valid + void PurgeAll(); + + // Tries to allocate space for the given data in fast vertex + // memory, and copies it over. + // Alloc does NOT do a touch, which allows purging of things + // created at level load time even if a frame hasn't passed yet. + // These allocations can be purged, which will zero the pointer. + void Alloc( void *data, int bytes, vertCache_t **buffer, bool indexBuffer = false ); + + // This will be a real pointer with virtual memory, + // but it will be an int offset cast to a pointer of ARB_vertex_buffer_object + const void *Position( vertCache_t *buffer ); + + // initialize the element array buffers + void BindIndex( GLenum target, GLuint vbo ); + + // if you need to draw something without an indexCache, + // this must be called to reset GL_ELEMENT_ARRAY_BUFFER_ARB + void UnbindIndex( GLenum target ); + + // automatically freed at the end of the next frame + // used for specular texture coordinates and gui drawing, which + // will change every frame. + // will return NULL if the vertex cache is completely full + // As with Position(), this may not actually be a pointer you can access. + vertCache_t *AllocFrameTemp( void *data, int bytes ); + + // notes that a buffer is used this frame, so it can't be purged + // out from under the GPU + void Touch( vertCache_t *buffer ); + + // this block won't have to zero a buffer pointer when it is purged, + // but it must still wait for the frames to pass, in case the GPU + // is still referencing it + void Free( vertCache_t *buffer ); + + // updates the counter for determining which temp space to use + // and which blocks can be purged + // Also prints debugging info when enabled + void EndFrame(); + + // listVBOMem calls this + void List(); + + // showVBOMem calls this + void Show(); + +private: + void ActuallyFree( vertCache_t *block ); + + static idCVar r_showVertexCache; + static idCVar r_useArbBufferRange; + static idCVar r_reuseVertexCacheSooner; + + GLuint vertexBuffer; // pointer into vertexbuffer + GLuint indexBuffer; // pointer into indexbuffer + + int staticCountTotal; + int staticAllocTotal; // for end of frame purging + + int staticAllocThisFrame; // debug counter + int staticCountThisFrame; + int dynamicAllocThisFrame; + int dynamicCountThisFrame; + + int currentFrame; // for purgable block tracking + int listNum; // currentFrame % NUM_VERTEX_FRAMES, determines which tempBuffers to use + + bool allocatingTempBuffer; // force GL_STREAM_DRAW_ARB + + vertCache_t *tempBuffers[NUM_VERTEX_FRAMES]; // allocated at startup + bool tempOverflow; // had to alloc a temp in static memory + + idBlockAlloc headerAllocator; + + vertCache_t freeStaticHeaders; // head of doubly linked list + vertCache_t freeDynamicHeaders; // head of doubly linked list + vertCache_t dynamicHeaders; // head of doubly linked list + vertCache_t deferredFreeList; // head of doubly linked list + vertCache_t staticHeaders; // head of doubly linked list in MRU order, staticHeaders.next is most recently used + int frameBytes; // for each of NUM_VERTEX_FRAMES frames +}; + +extern idVertexCache vertexCache; diff --git a/neo/renderer/draw_arb2.cpp b/neo/renderer/draw_arb2.cpp index c1d0d3e3e..f3cbf6362 100644 --- a/neo/renderer/draw_arb2.cpp +++ b/neo/renderer/draw_arb2.cpp @@ -1,793 +1,1306 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "renderer/VertexCache.h" - -#include "renderer/tr_local.h" - -// DG: if this is defined, the soft particle shaders will be compiled into the executable -// otherwise soft_particle.vfp will be opened as a file just like the other shaders -// (useful when tweaking that shader - when loaded from disk, you can use `reloadARBprograms` -// instead of recompiling the executable) -#ifndef D3_INTEGRATE_SOFTPART_SHADERS - #define D3_INTEGRATE_SOFTPART_SHADERS 1 -#endif - -/* -========================================================================================= - -GENERAL INTERACTION RENDERING - -========================================================================================= -*/ - -/* -==================== -GL_SelectTextureNoClient -==================== -*/ -static void GL_SelectTextureNoClient( int unit ) { - backEnd.glState.currenttmu = unit; - qglActiveTextureARB( GL_TEXTURE0_ARB + unit ); -} - -/* -================== -RB_ARB2_DrawInteraction -================== -*/ -void RB_ARB2_DrawInteraction( const drawInteraction_t *din ) { - // load all the vertex program parameters - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_ORIGIN, din->localLightOrigin.ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_VIEW_ORIGIN, din->localViewOrigin.ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_S, din->lightProjection[0].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_T, din->lightProjection[1].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_Q, din->lightProjection[2].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_FALLOFF_S, din->lightProjection[3].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_S, din->bumpMatrix[0].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_T, din->bumpMatrix[1].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_S, din->diffuseMatrix[0].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_T, din->diffuseMatrix[1].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_S, din->specularMatrix[0].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_T, din->specularMatrix[1].ToFloatPtr() ); - - // testing fragment based normal mapping - if ( r_testARBProgram.GetBool() ) { - qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 2, din->localLightOrigin.ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 3, din->localViewOrigin.ToFloatPtr() ); - } - - static const float zero[4] = { 0, 0, 0, 0 }; - static const float one[4] = { 1, 1, 1, 1 }; - static const float negOne[4] = { -1, -1, -1, -1 }; - - switch ( din->vertexColor ) { - case SVC_IGNORE: - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, zero ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, one ); - break; - case SVC_MODULATE: - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, one ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, zero ); - break; - case SVC_INVERSE_MODULATE: - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, negOne ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, one ); - break; - } - - // set the constant colors - qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, din->diffuseColor.ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 1, din->specularColor.ToFloatPtr() ); - - // DG: brightness and gamma in shader as program.env[4] - if ( r_gammaInShader.GetBool() ) { - // program.env[4].xyz are all r_brightness, program.env[4].w is 1.0/r_gamma - float parm[4]; - parm[0] = parm[1] = parm[2] = r_brightness.GetFloat(); - parm[3] = 1.0/r_gamma.GetFloat(); // 1.0/gamma so the shader doesn't have to do this calculation - qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_GAMMA_BRIGHTNESS, parm ); - } - - // set the textures - - // texture 1 will be the per-surface bump map - GL_SelectTextureNoClient( 1 ); - din->bumpImage->Bind(); - - // texture 2 will be the light falloff texture - GL_SelectTextureNoClient( 2 ); - din->lightFalloffImage->Bind(); - - // texture 3 will be the light projection texture - GL_SelectTextureNoClient( 3 ); - din->lightImage->Bind(); - - // texture 4 is the per-surface diffuse map - GL_SelectTextureNoClient( 4 ); - din->diffuseImage->Bind(); - - // texture 5 is the per-surface specular map - GL_SelectTextureNoClient( 5 ); - din->specularImage->Bind(); - - // draw it - RB_DrawElementsWithCounters( din->surf->geo ); -} - - -/* -============= -RB_ARB2_CreateDrawInteractions - -============= -*/ -void RB_ARB2_CreateDrawInteractions( const drawSurf_t *surf ) { - if ( !surf ) { - return; - } - - // perform setup here that will be constant for all interactions - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | backEnd.depthFunc ); - - // bind the vertex program - if ( r_testARBProgram.GetBool() ) { - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_TEST ); - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_TEST ); - } else { - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_INTERACTION ); - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_INTERACTION ); - } - - qglEnable(GL_VERTEX_PROGRAM_ARB); - qglEnable(GL_FRAGMENT_PROGRAM_ARB); - - // enable the vertex arrays - qglEnableVertexAttribArrayARB( 8 ); - qglEnableVertexAttribArrayARB( 9 ); - qglEnableVertexAttribArrayARB( 10 ); - qglEnableVertexAttribArrayARB( 11 ); - qglEnableClientState( GL_COLOR_ARRAY ); - - // texture 0 is the normalization cube map for the vector towards the light - GL_SelectTextureNoClient( 0 ); - if ( backEnd.vLight->lightShader->IsAmbientLight() ) { - globalImages->ambientNormalMap->Bind(); - } else { - globalImages->normalCubeMapImage->Bind(); - } - - // texture 6 is the specular lookup table - GL_SelectTextureNoClient( 6 ); - if ( r_testARBProgram.GetBool() ) { - globalImages->specular2DTableImage->Bind(); // variable specularity in alpha channel - } else { - globalImages->specularTableImage->Bind(); - } - - - for ( ; surf ; surf=surf->nextOnLight ) { - // perform setup here that will not change over multiple interaction passes - - // set the vertex pointers - idDrawVert *ac = (idDrawVert *)vertexCache.Position( surf->geo->ambientCache ); - qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), ac->color ); - qglVertexAttribPointerARB( 11, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); - qglVertexAttribPointerARB( 10, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() ); - qglVertexAttribPointerARB( 9, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() ); - qglVertexAttribPointerARB( 8, 2, GL_FLOAT, false, sizeof( idDrawVert ), ac->st.ToFloatPtr() ); - qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); - - // this may cause RB_ARB2_DrawInteraction to be exacuted multiple - // times with different colors and images if the surface or light have multiple layers - RB_CreateSingleDrawInteractions( surf, RB_ARB2_DrawInteraction ); - } - - qglDisableVertexAttribArrayARB( 8 ); - qglDisableVertexAttribArrayARB( 9 ); - qglDisableVertexAttribArrayARB( 10 ); - qglDisableVertexAttribArrayARB( 11 ); - qglDisableClientState( GL_COLOR_ARRAY ); - - // disable features - GL_SelectTextureNoClient( 6 ); - globalImages->BindNull(); - - GL_SelectTextureNoClient( 5 ); - globalImages->BindNull(); - - GL_SelectTextureNoClient( 4 ); - globalImages->BindNull(); - - GL_SelectTextureNoClient( 3 ); - globalImages->BindNull(); - - GL_SelectTextureNoClient( 2 ); - globalImages->BindNull(); - - GL_SelectTextureNoClient( 1 ); - globalImages->BindNull(); - - backEnd.glState.currenttmu = -1; - GL_SelectTexture( 0 ); - - qglDisable(GL_VERTEX_PROGRAM_ARB); - qglDisable(GL_FRAGMENT_PROGRAM_ARB); -} - - -/* -================== -RB_ARB2_DrawInteractions -================== -*/ -void RB_ARB2_DrawInteractions( void ) { - viewLight_t *vLight; - - GL_SelectTexture( 0 ); - qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - - // - // for each light, perform adding and shadowing - // - for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) { - backEnd.vLight = vLight; - - // do fogging later - if ( vLight->lightShader->IsFogLight() ) { - continue; - } - if ( vLight->lightShader->IsBlendLight() ) { - continue; - } - - if ( !vLight->localInteractions && !vLight->globalInteractions - && !vLight->translucentInteractions ) { - continue; - } - - // clear the stencil buffer if needed - if ( vLight->globalShadows || vLight->localShadows ) { - backEnd.currentScissor = vLight->scissorRect; - if ( r_useScissor.GetBool() ) { - qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, - backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, - backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, - backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); - } - qglClear( GL_STENCIL_BUFFER_BIT ); - } else { - // no shadows, so no need to read or write the stencil buffer - // we might in theory want to use GL_ALWAYS instead of disabling - // completely, to satisfy the invarience rules - qglStencilFunc( GL_ALWAYS, 128, 255 ); - } - - if ( r_useShadowVertexProgram.GetBool() ) { - qglEnable( GL_VERTEX_PROGRAM_ARB ); - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW ); - RB_StencilShadowPass( vLight->globalShadows ); - RB_ARB2_CreateDrawInteractions( vLight->localInteractions ); - qglEnable( GL_VERTEX_PROGRAM_ARB ); - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW ); - RB_StencilShadowPass( vLight->localShadows ); - RB_ARB2_CreateDrawInteractions( vLight->globalInteractions ); - qglDisable( GL_VERTEX_PROGRAM_ARB ); // if there weren't any globalInteractions, it would have stayed on - } else { - RB_StencilShadowPass( vLight->globalShadows ); - RB_ARB2_CreateDrawInteractions( vLight->localInteractions ); - RB_StencilShadowPass( vLight->localShadows ); - RB_ARB2_CreateDrawInteractions( vLight->globalInteractions ); - } - - // translucent surfaces never get stencil shadowed - if ( r_skipTranslucent.GetBool() ) { - continue; - } - - qglStencilFunc( GL_ALWAYS, 128, 255 ); - - backEnd.depthFunc = GLS_DEPTHFUNC_LESS; - RB_ARB2_CreateDrawInteractions( vLight->translucentInteractions ); - - backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL; - } - - // disable stencil shadow test - qglStencilFunc( GL_ALWAYS, 128, 255 ); - - GL_SelectTexture( 0 ); - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); -} - -//=================================================================================== - - -typedef struct { - GLenum target; - GLuint ident; - char name[64]; -} progDef_t; - -static const int MAX_GLPROGS = 200; - -// a single file can have both a vertex program and a fragment program -static progDef_t progs[MAX_GLPROGS] = { - { GL_VERTEX_PROGRAM_ARB, VPROG_TEST, "test.vfp" }, - { GL_FRAGMENT_PROGRAM_ARB, FPROG_TEST, "test.vfp" }, - { GL_VERTEX_PROGRAM_ARB, VPROG_INTERACTION, "interaction.vfp" }, - { GL_FRAGMENT_PROGRAM_ARB, FPROG_INTERACTION, "interaction.vfp" }, - { GL_VERTEX_PROGRAM_ARB, VPROG_BUMPY_ENVIRONMENT, "bumpyEnvironment.vfp" }, - { GL_FRAGMENT_PROGRAM_ARB, FPROG_BUMPY_ENVIRONMENT, "bumpyEnvironment.vfp" }, - { GL_VERTEX_PROGRAM_ARB, VPROG_AMBIENT, "ambientLight.vfp" }, - { GL_FRAGMENT_PROGRAM_ARB, FPROG_AMBIENT, "ambientLight.vfp" }, - { GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW, "shadow.vp" }, - { GL_VERTEX_PROGRAM_ARB, VPROG_ENVIRONMENT, "environment.vfp" }, - { GL_FRAGMENT_PROGRAM_ARB, FPROG_ENVIRONMENT, "environment.vfp" }, - { GL_VERTEX_PROGRAM_ARB, VPROG_GLASSWARP, "arbVP_glasswarp.txt" }, - { GL_FRAGMENT_PROGRAM_ARB, FPROG_GLASSWARP, "arbFP_glasswarp.txt" }, - - // SteveL #3878: Particle softening applied by the engine - { GL_VERTEX_PROGRAM_ARB, VPROG_SOFT_PARTICLE, "soft_particle.vfp" }, - { GL_FRAGMENT_PROGRAM_ARB, FPROG_SOFT_PARTICLE, "soft_particle.vfp" }, - - // additional programs can be dynamically specified in materials -}; - -#if D3_INTEGRATE_SOFTPART_SHADERS -// DG: the following two shaders are taken from TheDarkMod 2.04 (glprogs/soft_particle.vfp) -// (C) 2005-2016 Broken Glass Studios (The Dark Mod Team) and the individual authors -// released under a revised BSD license and GPLv3 -const char* softpartVShader = "!!ARBvp1.0 \n" - "OPTION ARB_position_invariant; \n" - "# NOTE: unlike the TDM shader, the following lines use .texcoord and .color \n" - "# instead of .attrib[8] and .attrib[3], to make it work with non-nvidia drivers \n" - "# Furthermore, I added support for a texture matrix \n" - "PARAM defaultTexCoord = { 0, 0.5, 0, 1 }; \n" - "MOV result.texcoord, defaultTexCoord; \n" - "# program.env[12] is PP_DIFFUSE_MATRIX_S, 13 is PP_DIFFUSE_MATRIX_T \n" - "DP4 result.texcoord.x, vertex.texcoord, program.env[12]; \n" - "DP4 result.texcoord.y, vertex.texcoord, program.env[13]; \n" - "MOV result.color, vertex.color; \n" - "END \n"; - -const char* softpartFShader = "!!ARBfp1.0 \n" - "# == Fragment Program == \n" - "# taken from The Dark Mod 2.04, adjusted for dhewm3 \n" - "# (C) 2005-2016 Broken Glass Studios (The Dark Mod Team) \n" - "# \n" - "# Input textures \n" - "# texture[0] particle diffusemap \n" - "# texture[1] _currentDepth \n" - "# \n" - "# Constants set by the engine: \n" - "# program.env[22] is reciprocal of _currentDepth size. Lets us convert a screen position to a texcoord in _currentDepth \n" - "# { 1.0f / depthtex.width, 1.0f / depthtex.height, float(depthtex.width)/int(depthtex.width), \n" - "# float(depthtex.height)/int(depthtex.height) } \n" - "# program.env[23] is the particle radius, given as { radius, 1/(fadeRange), 1/radius } \n" - "# fadeRange is the particle diameter for alpha blends (like smoke), but the particle radius for additive \n" - "# blends (light glares), because additive effects work differently. Fog is half as apparent when a wall \n" - "# is in the middle of it. Light glares lose no visibility when they have something to reflect off. \n" - "# program.env[24] is the color channel mask. Particles with additive blend need their RGB channels modified to blend them out. \n" - "# Particles with an alpha blend need their alpha channel modified. \n" - "# \n" - "# Hard-coded constants \n" - "# depth_consts allows us to recover the original depth in Doom units of anything in the depth \n" - "# buffer. Doom3's and thus TDM's projection matrix differs slightly from the classic projection matrix as \n" - "# it implements a \"nearly-infinite\" zFar. The matrix is hard-coded in the engine, so we use hard-coded \n" - "# constants here for efficiency. depth_consts is derived from the numbers in that matrix. \n" - "# \n" - "# next line: prevent dhewm3 from injecting gamma in shader code into this shader, \n" - "# because that looks bad when rendered with additive blending (gets too bright) \n" - "# nodhewm3gammahack \n" - "\n" - "PARAM depth_consts = { 0.33333333, -0.33316667, 0.0, 0.0 }; \n" - "PARAM particle_radius = program.env[23]; \n" - "TEMP tmp, scene_depth, particle_depth, near_fade, fade; \n" - "\n" - "# Map the fragment to a texcoord on our depth image, and sample to find scene_depth \n" - "MUL tmp.xy, fragment.position, program.env[22]; \n" - "TEX scene_depth, tmp, texture[1], 2D; \n" - "MIN scene_depth, scene_depth, 0.9994; # Required by TDM projection matrix. Equates to max recoverable \n" - " # depth of 30k units, which is enough. 0.9995 is infinite depth. \n" - " # This is needed only if there is caulk sky on show (which writes \n" - " # no depth, so leaves 1 in the depth texture). \n" - "\n" - "# Recover original depth in doom units \n" - "MAD tmp, scene_depth, depth_consts.x, depth_consts.y; \n" - "RCP scene_depth, tmp.x; \n" - "\n" - "# Convert particle depth to doom units too \n" - "MAD tmp, fragment.position.z, depth_consts.x, depth_consts.y; \n" - "RCP particle_depth, tmp.x; \n" - "\n" - "# Scale the depth difference by the particle diameter to calc an alpha \n" - "# value based on how much of the 3d volume represented by the particle \n" - "# is in front of the solid scene \n" - "ADD tmp, -scene_depth, particle_depth; # NB depth is negative. 0 at the eye, -100 at 100 units into the screen. \n" - "ADD tmp, tmp, particle_radius.x; # Add the radius so a depth difference of particle radius now equals 0 \n" - "MUL_SAT fade, tmp, particle_radius.y; # divide by the particle radius or diameter and clamp \n" - "\n" - "# Also fade if the particle is too close to our eye position, so it doesn't 'pop' in and out of view \n" - "# Start a linear fade at particle_radius distance from the particle. \n" - "MUL_SAT near_fade, particle_depth, -particle_radius.z; \n" - "\n" - "# Calculate final fade and apply the channel mask \n" - "MUL fade, near_fade, fade; \n" - "ADD_SAT fade, fade, program.env[24]; # saturate the channels that don't want modifying \n" - "\n" - "# Set the color. Multiply by vertex/fragment color as that's how the particle system fades particles in and out \n" - "TEMP oColor; \n" - "TEX oColor, fragment.texcoord, texture[0], 2D; \n" - "MUL oColor, oColor, fade; \n" - "MUL result.color, oColor, fragment.color; \n" - "\n" - "END \n"; - -#endif // D3_INTEGRATE_SOFTPART_SHADERS - -/* -================= -R_LoadARBProgram -================= -*/ - -static char* findLineThatStartsWith( char* text, const char* findMe ) { - char* res = strstr( text, findMe ); - while ( res != NULL ) { - // skip whitespace before match, if any - char* cur = res; - if ( cur > text ) { - --cur; - } - while ( cur > text && ( *cur == ' ' || *cur == '\t' ) ) { - --cur; - } - // now we should be at a newline (or at the beginning) - if ( cur == text ) { - return cur; - } - if ( *cur == '\n' || *cur == '\r' ) { - return cur+1; - } - // otherwise maybe we're in commented out text or whatever, search on - res = strstr( res+1, findMe ); - } - return NULL; -} - -static ID_INLINE bool isARBidentifierChar( int c ) { - // according to chapter 3.11.2 in ARB_fragment_program.txt identifiers can only - // contain these chars (first char mustn't be a number, but that doesn't matter here) - // NOTE: isalnum() or isalpha() apparently doesn't work, as it also matches spaces (?!) - return c == '$' || c == '_' - || (c >= '0' && c <= '9') - || (c >= 'A' && c <= 'Z') - || (c >= 'a' && c <= 'z'); -} - -void R_LoadARBProgram( int progIndex ) { - int ofs; - int err; - char *buffer; - char *start = NULL, *end; - -#if D3_INTEGRATE_SOFTPART_SHADERS - if ( progs[progIndex].ident == VPROG_SOFT_PARTICLE || progs[progIndex].ident == FPROG_SOFT_PARTICLE ) { - // these shaders are loaded directly from a string - common->Printf( " %s", progs[progIndex].name ); - const char* srcstr = (progs[progIndex].ident == VPROG_SOFT_PARTICLE) ? softpartVShader : softpartFShader; - - // copy to stack memory - buffer = (char *)_alloca( strlen( srcstr ) + 1 ); - strcpy( buffer, srcstr ); - } - else -#endif // D3_INTEGRATE_SOFTPART_SHADERS - { - idStr fullPath = "glprogs/"; - fullPath += progs[progIndex].name; - char *fileBuffer; - common->Printf( "%s", fullPath.c_str() ); - - // load the program even if we don't support it, so - // fs_copyfiles can generate cross-platform data dumps - fileSystem->ReadFile( fullPath.c_str(), (void **)&fileBuffer, NULL ); - if ( !fileBuffer ) { - common->Printf( ": File not found\n" ); - return; - } - - // copy to stack memory and free - buffer = (char *)_alloca( strlen( fileBuffer ) + 1 ); - strcpy( buffer, fileBuffer ); - fileSystem->FreeFile( fileBuffer ); - } - - if ( !glConfig.isInitialized ) { - return; - } - - // - // submit the program string at start to GL - // - if ( progs[progIndex].ident == 0 ) { - // allocate a new identifier for this program - progs[progIndex].ident = PROG_USER + progIndex; - } - - // vertex and fragment programs can both be present in a single file, so - // scan for the proper header to be the start point, and stamp a 0 in after the end - - if ( progs[progIndex].target == GL_VERTEX_PROGRAM_ARB ) { - if ( !glConfig.ARBVertexProgramAvailable ) { - common->Printf( ": GL_VERTEX_PROGRAM_ARB not available\n" ); - return; - } - start = strstr( buffer, "!!ARBvp" ); - } - if ( progs[progIndex].target == GL_FRAGMENT_PROGRAM_ARB ) { - if ( !glConfig.ARBFragmentProgramAvailable ) { - common->Printf( ": GL_FRAGMENT_PROGRAM_ARB not available\n" ); - return; - } - start = strstr( buffer, "!!ARBfp" ); - } - if ( !start ) { - common->Printf( ": !!ARB not found\n" ); - return; - } - end = strstr( start, "END" ); - - if ( !end ) { - common->Printf( ": END not found\n" ); - return; - } - end[3] = 0; - - // DG: hack gamma correction into shader - if ( r_gammaInShader.GetBool() && progs[progIndex].target == GL_FRAGMENT_PROGRAM_ARB - && strstr( start, "nodhewm3gammahack" ) == NULL ) - { - - // note that strlen("dhewm3tmpres") == strlen("result.color") - const char* tmpres = "TEMP dhewm3tmpres; # injected by dhewm3 for gamma correction\n"; - - // Note: program.env[21].xyz = r_brightness; program.env[21].w = 1.0/r_gamma - // outColor.rgb = pow(dhewm3tmpres.rgb*r_brightness, vec3(1.0/r_gamma)) - // outColor.a = dhewm3tmpres.a; - const char* extraLines = - "# gamma correction in shader, injected by dhewm3 \n" - // MUL_SAT clamps the result to [0, 1] - it must not be negative because - // POW might not work with a negative base (it looks wrong with intel's Linux driver) - // and clamping values >1 to 1 is ok because when writing to result.color - // it's clamped anyway and pow(base, exp) is always >= 1 for base >= 1 - "MUL_SAT dhewm3tmpres.xyz, program.env[21], dhewm3tmpres;\n" // first multiply with brightness - "POW result.color.x, dhewm3tmpres.x, program.env[21].w;\n" // then do pow(dhewm3tmpres.xyz, vec3(1/gamma)) - "POW result.color.y, dhewm3tmpres.y, program.env[21].w;\n" // (apparently POW only supports scalars, not whole vectors) - "POW result.color.z, dhewm3tmpres.z, program.env[21].w;\n" - "MOV result.color.w, dhewm3tmpres.w;\n" // alpha remains unmodified - "\nEND\n\n"; // we add this block right at the end, replacing the original "END" string - - int fullLen = strlen( start ) + strlen( tmpres ) + strlen( extraLines ); - char* outStr = (char*)_alloca( fullLen + 1 ); - - // add tmpres right after OPTION line (if any) - char* insertPos = findLineThatStartsWith( start, "OPTION" ); - if ( insertPos == NULL ) { - // no OPTION? then just put it after the first line (usually sth like "!!ARBfp1.0\n") - insertPos = start; - } - // but we want the position *after* that line - while( *insertPos != '\0' && *insertPos != '\n' && *insertPos != '\r' ) { - ++insertPos; - } - // skip the newline character(s) as well - while( *insertPos == '\n' || *insertPos == '\r' ) { - ++insertPos; - } - - // copy text up to insertPos - int curLen = insertPos-start; - memcpy( outStr, start, curLen ); - // copy tmpres ("TEMP dhewm3tmpres; # ..") - memcpy( outStr+curLen, tmpres, strlen( tmpres ) ); - curLen += strlen( tmpres ); - // copy remaining original shader up to (excluding) "END" - int remLen = end - insertPos; - memcpy( outStr+curLen, insertPos, remLen ); - curLen += remLen; - - outStr[curLen] = '\0'; // make sure it's NULL-terminated so normal string functions work - - // replace all existing occurrences of "result.color" with "dhewm3tmpres" - for( char* resCol = strstr( outStr, "result.color" ); - resCol != NULL; resCol = strstr( resCol+13, "result.color" ) ) { - memcpy( resCol, "dhewm3tmpres", 12 ); // both strings have the same length. - - // if this was part of "OUTPUT bla = result.color;", replace - // "OUTPUT bla" with "ALIAS bla" (so it becomes "ALIAS bla = dhewm3tmpres;") - { - char* s = resCol - 1; - // first skip whitespace before "result.color" - while( s > outStr && (*s == ' ' || *s == '\t') ) { - --s; - } - // if there's no '=' before result.color, this line can't be affected - if ( *s != '=' || s <= outStr + 8 ) { - continue; // go on with next "result.color" in the for-loop - } - --s; // we were on '=', so go to the char before and it's time to skip whitespace again - while( s > outStr && ( *s == ' ' || *s == '\t' ) ) { - --s; - } - // now we should be at the end of "bla" (or however the variable/alias is called) - if ( s <= outStr+7 || !isARBidentifierChar( *s ) ) { - continue; - } - --s; - // skip all the remaining chars that are legal in identifiers - while( s > outStr && isARBidentifierChar( *s ) ) { - --s; - } - // there should be at least one space/tab between "OUTPUT" and "bla" - if ( s <= outStr + 6 || ( *s != ' ' && *s != '\t' ) ) { - continue; - } - --s; - // skip remaining whitespace (if any) - while( s > outStr && ( *s == ' ' || *s == '\t' ) ) { - --s; - } - // now we should be at "OUTPUT" (specifically at its last 'T'), - // if this is indeed such a case - if ( s <= outStr + 5 || *s != 'T' ) { - continue; - } - s -= 5; // skip to start of "OUTPUT", if this is indeed "OUTPUT" - if ( idStr::Cmpn( s, "OUTPUT", 6 ) == 0 ) { - // it really is "OUTPUT" => replace "OUTPUT" with "ALIAS " - memcpy(s, "ALIAS ", 6); - } - } - } - - assert( curLen + strlen( extraLines ) <= fullLen ); - - // now add extraLines that calculate and set a gamma-corrected result.color - // strcat() should be safe because fullLen was calculated taking all parts into account - strcat( outStr, extraLines ); - start = outStr; - } - - qglBindProgramARB( progs[progIndex].target, progs[progIndex].ident ); - qglGetError(); - - qglProgramStringARB( progs[progIndex].target, GL_PROGRAM_FORMAT_ASCII_ARB, - strlen( start ), start ); - - err = qglGetError(); - qglGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, (GLint *)&ofs ); - if ( err == GL_INVALID_OPERATION ) { - const GLubyte *str = qglGetString( GL_PROGRAM_ERROR_STRING_ARB ); - common->Printf( "\nGL_PROGRAM_ERROR_STRING_ARB: %s\n", str ); - if ( ofs < 0 ) { - common->Printf( "GL_PROGRAM_ERROR_POSITION_ARB < 0 with error\n" ); - } else if ( ofs >= (int)strlen( start ) ) { - common->Printf( "error at end of program\n" ); - } else { - int printOfs = Max( ofs - 20, 0 ); // DG: print some more context - common->Printf( "error at %i:\n%s", ofs, start + printOfs ); - } - return; - } - if ( ofs != -1 ) { - common->Printf( "\nGL_PROGRAM_ERROR_POSITION_ARB != -1 without error\n" ); - return; - } - - common->Printf( "\n" ); -} - -/* -================== -R_FindARBProgram - -Returns a GL identifier that can be bound to the given target, parsing -a text file if it hasn't already been loaded. -================== -*/ -int R_FindARBProgram( GLenum target, const char *program ) { - int i; - idStr stripped = program; - - stripped.StripFileExtension(); - - // see if it is already loaded - for ( i = 0 ; progs[i].name[0] ; i++ ) { - if ( progs[i].target != target ) { - continue; - } - - idStr compare = progs[i].name; - compare.StripFileExtension(); - - if ( !idStr::Icmp( stripped.c_str(), compare.c_str() ) ) { - return progs[i].ident; - } - } - - if ( i == MAX_GLPROGS ) { - common->Error( "R_FindARBProgram: MAX_GLPROGS" ); - } - - // add it to the list and load it - progs[i].ident = (program_t)0; // will be gen'd by R_LoadARBProgram - progs[i].target = target; - idStr::Copynz( progs[i].name, program, sizeof( progs[i].name ) ); - - R_LoadARBProgram( i ); - - return progs[i].ident; -} - -/* -================== -R_ReloadARBPrograms_f -================== -*/ -void R_ReloadARBPrograms_f( const idCmdArgs &args ) { - int i; - - common->Printf( "----- R_ReloadARBPrograms -----\n" ); - for ( i = 0 ; progs[i].name[0] ; i++ ) { - R_LoadARBProgram( i ); - } -} - -/* -================== -R_ARB2_Init - -================== -*/ -void R_ARB2_Init( void ) { - glConfig.allowARB2Path = false; - - common->Printf( "ARB2 renderer: " ); - - if ( !glConfig.ARBVertexProgramAvailable || !glConfig.ARBFragmentProgramAvailable ) { - common->Printf( "Not available.\n" ); - return; - } - - common->Printf( "Available.\n" ); - - glConfig.allowARB2Path = true; -} +/* +=========================================================================== + +Doom 3 GPL Source Code +Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. + +This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?). + +Doom 3 Source Code is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Doom 3 Source Code is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Doom 3 Source Code. If not, see . + +In addition, the Doom 3 Source Code is also subject to certain additional terms. +You should have received a copy of these additional terms immediately following +the terms and conditions of the GNU General Public License which accompanied the +Doom 3 Source Code. If not, please request a copy in writing from id Software +at the address below. + +If you have questions concerning this license or the applicable additional terms, +you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, +Rockville, Maryland 20850 USA. + +=========================================================================== +*/ + +#include "renderer/VertexCache.h" +#include "renderer/tr_local.h" +#include "sys/platform.h" + +// DG: if this is defined, the soft particle shaders will be compiled into the executable +// otherwise soft_particle.vfp will be opened as a file just like the other shaders +// (useful when tweaking that shader - when loaded from disk, you can use `reloadARBprograms` +// instead of recompiling the executable) +#ifndef D3_INTEGRATE_SOFTPART_SHADERS +#define D3_INTEGRATE_SOFTPART_SHADERS 1 +#endif + +/* +================== +RB_GLSL_MakeMatrix +================== +*/ +static float *RB_GLSL_MakeMatrix( const float *in1 = 0, const float *in2 = 0, const float *in3 = 0, const float *in4 = 0 ) { + static float m[16]; + + if ( in1 ) { + SIMDProcessor->Memcpy( &m[0], in1, sizeof( float ) * 4 ); + } + + if ( in2 ) { + SIMDProcessor->Memcpy( &m[4], in2, sizeof( float ) * 4 ); + } + + if ( in3 ) { + SIMDProcessor->Memcpy( &m[8], in3, sizeof( float ) * 4 ); + } + + if ( in4 ) { + SIMDProcessor->Memcpy( &m[12], in4, sizeof( float ) * 4 ); + } + return m; +} + +/* Calculate matrix offsets */ +#define DIFFMATRIX( ofs ) din->diffuseMatrix[ofs].ToFloatPtr() +#define BUMPMATRIX( ofs ) din->bumpMatrix[ofs].ToFloatPtr() +#define SPECMATRIX( ofs ) din->specularMatrix[ofs].ToFloatPtr() +#define PROJMATRIX( ofs ) din->lightProjection[ofs].ToFloatPtr() + +/* +========================================================================================= + +GENERAL INTERACTION RENDERING + +========================================================================================= +*/ + +/* +================== +RB_ARB2_BindTexture +================== +*/ +void RB_ARB2_BindTexture( int unit, idImage *tex ) { + backEnd.glState.currenttmu = unit; + qglActiveTextureARB( GL_TEXTURE0_ARB + unit ); + tex->Bind(); +} + +/* +================== +RB_ARB2_UnbindTexture +================== +*/ +void RB_ARB2_UnbindTexture( int unit ) { + backEnd.glState.currenttmu = unit; + qglActiveTextureARB( GL_TEXTURE0_ARB + unit ); + globalImages->BindNull(); +} + +/* +================== +RB_ARB2_BindInteractionTextureSet +================== +*/ +void RB_ARB2_BindInteractionTextureSet( const drawInteraction_t *din ) { + // texture 1 will be the per-surface bump map + RB_ARB2_BindTexture( 1, din->bumpImage ); + + // texture 2 will be the light falloff texture + RB_ARB2_BindTexture( 2, din->lightFalloffImage ); + + // texture 3 will be the light projection texture + RB_ARB2_BindTexture( 3, din->lightImage ); + + // texture 4 is the per-surface diffuse map + RB_ARB2_BindTexture( 4, din->diffuseImage ); + + // texture 5 is the per-surface specular map + RB_ARB2_BindTexture( 5, din->specularImage ); +} + +/* +================== +RB_GLSL_DrawInteraction +================== +*/ +static void RB_GLSL_DrawInteraction( const drawInteraction_t *din ) { + /* Half Lambertian constants */ + static const float whalf[] = { 0.0f, 0.0f, 0.0f, 0.5f }; + static const float wzero[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + static const float wone[] = { 0.0f, 0.0f, 0.0f, 1.0f }; + + // load all the vertex program parameters + qglUniform4fv( u_light_origin, 1, din->localLightOrigin.ToFloatPtr() ); + qglUniform4fv( u_view_origin, 1, din->localViewOrigin.ToFloatPtr() ); + qglUniformMatrix2x4fv( u_diffMatrix, 1, GL_FALSE, RB_GLSL_MakeMatrix( DIFFMATRIX( 0 ), DIFFMATRIX( 1 ) ) ); + qglUniformMatrix2x4fv( u_bumpMatrix, 1, GL_FALSE, RB_GLSL_MakeMatrix( BUMPMATRIX( 0 ), BUMPMATRIX( 1 ) ) ); + qglUniformMatrix2x4fv( u_specMatrix, 1, GL_FALSE, RB_GLSL_MakeMatrix( SPECMATRIX( 0 ), SPECMATRIX( 1 ) ) ); + qglUniformMatrix4fv( u_projMatrix, 1, GL_FALSE, RB_GLSL_MakeMatrix( PROJMATRIX( 0 ), PROJMATRIX( 1 ), wzero, PROJMATRIX( 2 ) ) ); + qglUniformMatrix4fv( u_fallMatrix, 1, GL_FALSE, RB_GLSL_MakeMatrix( PROJMATRIX( 3 ), whalf, wzero, wone ) ); + + /* Lambertian constants */ + static const float zero[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + static const float one[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + static const float negOne[4] = { -1.0f, -1.0f, -1.0f, -1.0f }; + + switch ( din->vertexColor ) { + case SVC_IGNORE: + qglUniform4fv( u_color_modulate, 1, zero ); + qglUniform4fv( u_color_add, 1, one ); + break; + case SVC_MODULATE: + qglUniform4fv( u_color_modulate, 1, one ); + qglUniform4fv( u_color_add, 1, zero ); + break; + case SVC_INVERSE_MODULATE: + qglUniform4fv( u_color_modulate, 1, negOne ); + qglUniform4fv( u_color_add, 1, one ); + break; + } + + // set the constant colors + qglUniform4fv( u_constant_diffuse, 1, din->diffuseColor.ToFloatPtr() ); + qglUniform4fv( u_constant_specular, 1, din->specularColor.ToFloatPtr() ); + + // set the textures + RB_ARB2_BindInteractionTextureSet( din ); + + // draw it + RB_DrawElementsWithCounters( din->surf->geo ); +} + +/* +================== +RB_ARB2_DrawInteraction +================== +*/ +static void RB_ARB2_DrawInteraction( const drawInteraction_t *din ) { + // load all the vertex program parameters + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_ORIGIN, din->localLightOrigin.ToFloatPtr() ); + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_VIEW_ORIGIN, din->localViewOrigin.ToFloatPtr() ); + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_S, din->lightProjection[0].ToFloatPtr() ); + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_T, din->lightProjection[1].ToFloatPtr() ); + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_Q, din->lightProjection[2].ToFloatPtr() ); + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_FALLOFF_S, din->lightProjection[3].ToFloatPtr() ); + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_S, din->bumpMatrix[0].ToFloatPtr() ); + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_T, din->bumpMatrix[1].ToFloatPtr() ); + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_S, din->diffuseMatrix[0].ToFloatPtr() ); + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_T, din->diffuseMatrix[1].ToFloatPtr() ); + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_S, din->specularMatrix[0].ToFloatPtr() ); + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_T, din->specularMatrix[1].ToFloatPtr() ); + + // testing fragment based normal mapping + if ( r_testARBProgram.GetBool() ) { + qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 2, din->localLightOrigin.ToFloatPtr() ); + qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 3, din->localViewOrigin.ToFloatPtr() ); + } + static const float zero[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + static const float one[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + static const float negOne[4] = { -1.0f, -1.0f, -1.0f, -1.0f }; + + switch ( din->vertexColor ) { + case SVC_IGNORE: + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, zero ); + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, one ); + break; + case SVC_MODULATE: + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, one ); + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, zero ); + break; + case SVC_INVERSE_MODULATE: + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, negOne ); + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, one ); + break; + } + + // set the constant colors + qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, din->diffuseColor.ToFloatPtr() ); + qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 1, din->specularColor.ToFloatPtr() ); + + // DG: brightness and gamma in shader as program.env[4] + if ( r_gammaInShader.GetBool() ) { + // program.env[4].xyz are all r_brightness, program.env[4].w is 1.0f / r_gamma + float parm[4]; + parm[0] = parm[1] = parm[2] = r_brightness.GetFloat(); + parm[3] = 1.0f / r_gamma.GetFloat(); // 1.0f / gamma so the shader doesn't have to do this calculation + qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_GAMMA_BRIGHTNESS, parm ); + } + + // set the textures + RB_ARB2_BindInteractionTextureSet( din ); + + // draw it + RB_DrawElementsWithCounters( din->surf->geo ); +} + +/* +============= +RB_ARB2_SharedSurfaceSetup +============= +*/ +static void RB_ARB2_SharedSurfaceSetup( const drawSurf_t *surf ) { + // set the vertex pointers + idDrawVert *ac = ( idDrawVert * )vertexCache.Position( surf->geo->ambientCache ); + qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), ac->color ); + qglVertexAttribPointerARB( 11, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); + qglVertexAttribPointerARB( 10, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() ); + qglVertexAttribPointerARB( 9, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() ); + qglVertexAttribPointerARB( 8, 2, GL_FLOAT, false, sizeof( idDrawVert ), ac->st.ToFloatPtr() ); + qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); +} + +/* +============= +RB_ARB2_CreateDrawInteractions +============= +*/ +static void RB_ARB2_CreateDrawInteractions( const drawSurf_t *surf ) { + if ( !surf ) { + return; + } + + // perform setup here that will be constant for all interactions + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | backEnd.depthFunc ); + + // enable the vertex arrays + qglEnableVertexAttribArrayARB( 8 ); + qglEnableVertexAttribArrayARB( 9 ); + qglEnableVertexAttribArrayARB( 10 ); + qglEnableVertexAttribArrayARB( 11 ); + qglEnableClientState( GL_COLOR_ARRAY ); + + // check for enabled GLSL program first, if it fails go back to ARB + if ( rb_glsl_interaction_program != INVALID_PROGRAM ) { + // enable GLSL programs + qglUseProgram( rb_glsl_interaction_program ); + + // texture 0 is the normalization cube map for the vector towards the light + if ( backEnd.vLight->lightShader->IsAmbientLight() ) { + RB_ARB2_BindTexture( 0, globalImages->ambientNormalMap ); + } else { + RB_ARB2_BindTexture( 0, globalImages->normalCubeMapImage ); + } + + // no test program in GLSL renderer + RB_ARB2_BindTexture( 6, globalImages->specularTableImage ); + + for ( /**/; surf; surf = surf->nextOnLight ) { + // perform setup here that will not change over multiple interaction passes + RB_ARB2_SharedSurfaceSetup( surf ); + + // this may cause RB_ARB2_DrawInteraction to be executed multiple + // times with different colors and images if the surface or light have multiple layers + RB_CreateSingleDrawInteractions( surf, RB_GLSL_DrawInteraction ); + } + + // back to fixed (or ARB program) + qglUseProgram( INVALID_PROGRAM ); + } else { // ARB2 + // enable ASM programs + qglEnable( GL_VERTEX_PROGRAM_ARB ); + qglEnable( GL_FRAGMENT_PROGRAM_ARB ); + + // texture 0 is the normalization cube map for the vector towards the light + if ( backEnd.vLight->lightShader->IsAmbientLight() ) { + RB_ARB2_BindTexture( 0, globalImages->ambientNormalMap ); + } else { + RB_ARB2_BindTexture( 0, globalImages->normalCubeMapImage ); + } + + // bind the vertex program + if ( r_testARBProgram.GetBool() ) { + RB_ARB2_BindTexture( 6, globalImages->specular2DTableImage ); + qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_TEST ); + qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_TEST ); + } else { + RB_ARB2_BindTexture( 6, globalImages->specularTableImage ); + qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_INTERACTION ); + qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_INTERACTION ); + } + + for ( /**/; surf; surf = surf->nextOnLight ) { + // perform setup here that will not change over multiple interaction passes + RB_ARB2_SharedSurfaceSetup( surf ); + + // this may cause RB_ARB2_DrawInteraction to be exacuted multiple + // times with different colors and images if the surface or light have multiple layers + RB_CreateSingleDrawInteractions( surf, RB_ARB2_DrawInteraction ); + } + + // need to disable ASM programs again + qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, PROG_INVALID ); + qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, PROG_INVALID ); + + // back to fixed (or GLSL program) + qglDisable( GL_VERTEX_PROGRAM_ARB ); + qglDisable( GL_FRAGMENT_PROGRAM_ARB ); + } + + // disable vertex arrays + qglDisableVertexAttribArrayARB( 8 ); + qglDisableVertexAttribArrayARB( 9 ); + qglDisableVertexAttribArrayARB( 10 ); + qglDisableVertexAttribArrayARB( 11 ); + qglDisableClientState( GL_COLOR_ARRAY ); + + // disable features + RB_ARB2_UnbindTexture( 6 ); + RB_ARB2_UnbindTexture( 5 ); + RB_ARB2_UnbindTexture( 4 ); + RB_ARB2_UnbindTexture( 3 ); + RB_ARB2_UnbindTexture( 2 ); + RB_ARB2_UnbindTexture( 1 ); + + backEnd.glState.currenttmu = -1; + GL_SelectTexture( 0 ); +} + +/* +================== +RB_ARB2_InteractionPass +================== +*/ +static void RB_ARB2_InteractionPass( const drawSurf_t *shadowSurfs, const drawSurf_t *lightSurfs ) { + // save on state changes by not bothering to setup/takedown all the messy states when there are no surfs to draw + if ( shadowSurfs ) { + if ( r_useShadowVertexProgram.GetBool() ) { + // these are allway's enabled since we do not yet use GLSL shaders for the shadows. + qglEnable( GL_VERTEX_PROGRAM_ARB ); + qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW ); + + RB_StencilShadowPass( shadowSurfs ); + + // need to disable ASM programs again, we do not check for GLSL here since we do not use it for shadows. + qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, PROG_INVALID ); + qglDisable( GL_VERTEX_PROGRAM_ARB ); + } else { + // no vertex program here... + RB_StencilShadowPass( shadowSurfs ); + } + } + + if ( lightSurfs ) { + RB_ARB2_CreateDrawInteractions( lightSurfs ); + } +} + +/* +================== +RB_ARB2_DrawInteractions +================== +*/ +void RB_ARB2_DrawInteractions( void ) { + viewLight_t *vLight; + + GL_SelectTexture( 0 ); + + // for each light, perform adding and shadowing + for ( vLight = backEnd.viewDef->viewLights; vLight; vLight = vLight->next ) { + backEnd.vLight = vLight; + + // do fogging later + if ( vLight->lightShader->IsFogLight() ) { + continue; + } + + if ( vLight->lightShader->IsBlendLight() ) { + continue; + } + + // nothing to see here; these aren't the surfaces you're looking for; move along + if ( !vLight->localInteractions && !vLight->globalInteractions && !vLight->translucentInteractions ) { + continue; + } + + // set the depth bounds for the whole light + const DepthBoundsTest depthBoundsTest( vLight->scissorRect ); + + // clear the stencil buffer if needed + if ( vLight->globalShadows || vLight->localShadows ) { + backEnd.currentScissor = vLight->scissorRect; + + if ( r_useScissor.GetBool() ) { + qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, + backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, + backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, + backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); + } + qglClear( GL_STENCIL_BUFFER_BIT ); + } else { + // no shadows, so no need to read or write the stencil buffer + // we might in theory want to use GL_ALWAYS instead of disabling + // completely, to satisfy the invarience rules + qglStencilFunc( GL_ALWAYS, 128, 255 ); + } + + // run our passes for global and local + RB_ARB2_InteractionPass( vLight->globalShadows, vLight->localInteractions ); + RB_ARB2_InteractionPass( vLight->localShadows, vLight->globalInteractions ); + + // translucent surfaces never get stencil shadowed + if ( r_skipTranslucent.GetBool() ) { + continue; + } + qglStencilFunc( GL_ALWAYS, 128, 255 ); + backEnd.depthFunc = GLS_DEPTHFUNC_LESS; + RB_ARB2_CreateDrawInteractions( vLight->translucentInteractions ); + backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL; + } + + // disable stencil shadow test + qglStencilFunc( GL_ALWAYS, 128, 255 ); + GL_SelectTexture( 0 ); +} + +//=================================================================================== + +typedef struct { + GLenum target; + GLuint ident; + char name[64]; +} progDef_t; + +static const int MAX_GLPROGS = 256; + +// a single file can have both a vertex program and a fragment program +// removed old invalid shaders, ARB2 is default nowadays and we override the interaction shaders with GLSL anyway +// if availiable. +static progDef_t progs[MAX_GLPROGS] = { + { GL_VERTEX_PROGRAM_ARB, VPROG_TEST, "test.vfp" }, + { GL_FRAGMENT_PROGRAM_ARB, FPROG_TEST, "test.vfp" }, + { GL_VERTEX_PROGRAM_ARB, VPROG_INTERACTION, "interaction.vfp" }, + { GL_FRAGMENT_PROGRAM_ARB, FPROG_INTERACTION, "interaction.vfp" }, + { GL_VERTEX_PROGRAM_ARB, VPROG_BUMPY_ENVIRONMENT, "bumpyEnvironment.vfp" }, + { GL_FRAGMENT_PROGRAM_ARB, FPROG_BUMPY_ENVIRONMENT, "bumpyEnvironment.vfp" }, + { GL_VERTEX_PROGRAM_ARB, VPROG_AMBIENT, "ambientLight.vfp" }, + { GL_FRAGMENT_PROGRAM_ARB, FPROG_AMBIENT, "ambientLight.vfp" }, + { GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW, "shadow.vp" }, + { GL_VERTEX_PROGRAM_ARB, VPROG_ENVIRONMENT, "environment.vfp" }, + { GL_FRAGMENT_PROGRAM_ARB, FPROG_ENVIRONMENT, "environment.vfp" }, + // SteveL #3878: Particle softening applied by the engine + { GL_VERTEX_PROGRAM_ARB, VPROG_SOFT_PARTICLE, "soft_particle.vfp" }, + { GL_FRAGMENT_PROGRAM_ARB, FPROG_SOFT_PARTICLE, "soft_particle.vfp" }, + // additional programs can be dynamically specified in materials +}; + +#if D3_INTEGRATE_SOFTPART_SHADERS +// DG: the following two shaders are taken from TheDarkMod 2.04 (glprogs/soft_particle.vfp) +// (C) 2005-2016 Broken Glass Studios (The Dark Mod Team) and the individual authors +// released under a revised BSD license and GPLv3 +static const GLchar *softpartVShader = "!!ARBvp1.0 \n" + "OPTION ARB_position_invariant; \n" + "# NOTE: unlike the TDM shader, the following lines use .texcoord and .color \n" + "# instead of .attrib[8] and .attrib[3], to make it work with non-nvidia drivers \n" + "# Furthermore, I added support for a texture matrix \n" + "PARAM defaultTexCoord = { 0, 0.5, 0, 1 }; \n" + "MOV result.texcoord, defaultTexCoord; \n" + "# program.env[12] is PP_DIFFUSE_MATRIX_S, 13 is PP_DIFFUSE_MATRIX_T \n" + "DP4 result.texcoord.x, vertex.texcoord, program.env[12]; \n" + "DP4 result.texcoord.y, vertex.texcoord, program.env[13]; \n" + "MOV result.color, vertex.color; \n" + "END \n"; + +static const GLchar *softpartFShader = "!!ARBfp1.0 \n" + "# == Fragment Program == \n" + "# taken from The Dark Mod 2.04, adjusted for dhewm3 \n" + "# (C) 2005-2016 Broken Glass Studios (The Dark Mod Team) \n" + "# \n" + "# Input textures \n" + "# texture[0] particle diffusemap \n" + "# texture[1] _currentDepth \n" + "# \n" + "# Constants set by the engine: \n" + "# program.env[22] is reciprocal of _currentDepth size. Lets us convert a screen position to a texcoord " + "in _currentDepth \n" + "# { 1.0f / depthtex.width, 1.0f / depthtex.height, float(depthtex.width)/int(depthtex.width), \n" + "# float(depthtex.height)/int(depthtex.height) } \n" + "# program.env[23] is the particle radius, given as { radius, 1/(fadeRange), 1/radius } \n" + "# fadeRange is the particle diameter for alpha blends (like smoke), but the particle radius for " + "additive \n" + "# blends (light glares), because additive effects work differently. Fog is half as apparent when a " + "wall \n" + "# is in the middle of it. Light glares lose no visibility when they have something to reflect off. \n" + "# program.env[24] is the color channel mask. Particles with additive blend need their RGB channels " + "modified to blend them out. \n" + "# Particles with an alpha blend need their alpha channel " + "modified. \n" + "# \n" + "# Hard-coded constants \n" + "# depth_consts allows us to recover the original depth in Doom units of anything in the depth \n" + "# buffer. Doom3's and thus TDM's projection matrix differs slightly from the classic projection matrix " + "as \n" + "# it implements a \"nearly-infinite\" zFar. The matrix is hard-coded in the engine, so we use " + "hard-coded \n" + "# constants here for efficiency. depth_consts is derived from the numbers in that matrix. \n" + "# \n" + "# next line: prevent dhewm3 from injecting gamma in shader code into this shader, \n" + "# because that looks bad when rendered with additive blending (gets too bright) \n" + "# nodhewm3gammahack \n" + "\n" + "PARAM depth_consts = { 0.33333333, -0.33316667, 0.0, 0.0 }; \n" + "PARAM particle_radius = program.env[23]; \n" + "TEMP tmp, scene_depth, particle_depth, near_fade, fade; \n" + "\n" + "# Map the fragment to a texcoord on our depth image, and sample to find scene_depth \n" + "MUL tmp.xy, fragment.position, program.env[22]; \n" + "TEX scene_depth, tmp, texture[1], 2D; \n" + "MIN scene_depth, scene_depth, 0.9994; # Required by TDM projection matrix. Equates to max recoverable \n" + " # depth of 30k units, which is enough. 0.9995 is infinite depth. \n" + " # This is needed only if there is caulk sky on show (which writes " + "\n" + " # no depth, so leaves 1 in the depth texture). \n" + "\n" + "# Recover original depth in doom units \n" + "MAD tmp, scene_depth, depth_consts.x, depth_consts.y; \n" + "RCP scene_depth, tmp.x; \n" + "\n" + "# Convert particle depth to doom units too \n" + "MAD tmp, fragment.position.z, depth_consts.x, depth_consts.y; \n" + "RCP particle_depth, tmp.x; \n" + "\n" + "# Scale the depth difference by the particle diameter to calc an alpha \n" + "# value based on how much of the 3d volume represented by the particle \n" + "# is in front of the solid scene \n" + "ADD tmp, -scene_depth, particle_depth; # NB depth is negative. 0 at the eye, -100 at 100 units " + "into the screen. \n" + "ADD tmp, tmp, particle_radius.x; # Add the radius so a depth difference of particle radius " + "now equals 0 \n" + "MUL_SAT fade, tmp, particle_radius.y; # divide by the particle radius or diameter and clamp \n" + "\n" + "# Also fade if the particle is too close to our eye position, so it doesn't 'pop' in and out of view \n" + "# Start a linear fade at particle_radius distance from the particle. \n" + "MUL_SAT near_fade, particle_depth, -particle_radius.z; \n" + "\n" + "# Calculate final fade and apply the channel mask \n" + "MUL fade, near_fade, fade; \n" + "ADD_SAT fade, fade, program.env[24]; # saturate the channels that don't want modifying \n" + "\n" + "# Set the color. Multiply by vertex/fragment color as that's how the particle system fades particles in " + "and out \n" + "TEMP oColor; \n" + "TEX oColor, fragment.texcoord, texture[0], 2D; \n" + "MUL oColor, oColor, fade; \n" + "MUL result.color, oColor, fragment.color; \n" + "\n" + "END \n"; +#endif // D3_INTEGRATE_SOFTPART_SHADERS + +/* +================= +R_FindArbShaderComment +================= +*/ +static char *R_FindArbShaderComment( char *text, const char *findMe ) { + char *res = strstr( text, findMe ); + + while ( res != NULL ) { + // skip whitespace before match, if any + char *cur = res; + + if ( cur > text ) { + --cur; + } + + while ( cur > text && ( *cur == ' ' || *cur == '\t' ) ) { + --cur; + } + + // now we should be at a newline (or at the beginning) + if ( cur == text ) { + return cur; + } + + if ( *cur == '\n' || *cur == '\r' ) { + return cur + 1; + } + + // otherwise maybe we're in commented out text or whatever, search on + res = strstr( res + 1, findMe ); + } + return NULL; +} + +/* +================= +R_IsArbIdentifier +================= +*/ +static ID_INLINE bool R_IsArbIdentifier( int c ) { + // according to chapter 3.11.2 in ARB_fragment_program.txt identifiers can only + // contain these chars (first char mustn't be a number, but that doesn't matter here) + // NOTE: isalnum() or isalpha() apparently doesn't work, as it also matches spaces (?!) + return ( c == '$' || c == '_' || + ( c >= '0' && c <= '9' ) || + ( c >= 'A' && c <= 'Z' ) || + ( c >= 'a' && c <= 'z' ) ); +} + +/* +================= +R_LoadARBProgram +================= +*/ +void R_LoadARBProgram( int progIndex ) { + int ofs; + int err; + char *buffer; + char *start = NULL, *end; + +#if D3_INTEGRATE_SOFTPART_SHADERS + if ( progs[progIndex].ident == VPROG_SOFT_PARTICLE || progs[progIndex].ident == FPROG_SOFT_PARTICLE ) { + // these shaders are loaded directly from a string + common->Printf( " %s", progs[progIndex].name ); + const char *srcstr = ( progs[progIndex].ident == VPROG_SOFT_PARTICLE ) ? softpartVShader : softpartFShader; + + // copy to stack memory + buffer = ( char * )_alloca( strlen( srcstr ) + 1 ); + strcpy( buffer, srcstr ); + } else +#endif // D3_INTEGRATE_SOFTPART_SHADERS + { + idStr fullPath = "glprogs/"; + fullPath += progs[progIndex].name; + char *fileBuffer; + common->Printf( "%s", fullPath.c_str() ); + + // load the program even if we don't support it, so + // fs_copyfiles can generate cross-platform data dumps + fileSystem->ReadFile( fullPath.c_str(), ( void ** )&fileBuffer, NULL ); + + if ( !fileBuffer ) { + common->Printf( ": File not found\n" ); + return; + } + + // copy to stack memory and free + buffer = ( char * )_alloca( strlen( fileBuffer ) + 1 ); + strcpy( buffer, fileBuffer ); + fileSystem->FreeFile( fileBuffer ); + } + + if ( !glConfig.isInitialized ) { + return; + } + + // + // submit the program string at start to GL + // + if ( progs[progIndex].ident == 0 ) { + // allocate a new identifier for this program + progs[progIndex].ident = PROG_USER + progIndex; + } + + // vertex and fragment programs can both be present in a single file, so + // scan for the proper header to be the start point, and stamp a 0 in after the end + if ( progs[progIndex].target == GL_VERTEX_PROGRAM_ARB ) { + if ( !glConfig.ARBVertexProgramAvailable ) { + common->Printf( ": GL_VERTEX_PROGRAM_ARB not available\n" ); + return; + } + start = strstr( buffer, "!!ARBvp" ); + } + + if ( progs[progIndex].target == GL_FRAGMENT_PROGRAM_ARB ) { + if ( !glConfig.ARBFragmentProgramAvailable ) { + common->Printf( ": GL_FRAGMENT_PROGRAM_ARB not available\n" ); + return; + } + start = strstr( buffer, "!!ARBfp" ); + } + + if ( !start ) { + common->Printf( ": !!ARB not found\n" ); + return; + } + end = strstr( start, "END" ); + + if ( !end ) { + common->Printf( ": END not found\n" ); + return; + } + end[3] = 0; + + // DG: hack gamma correction into shader + if ( r_gammaInShader.GetBool() && progs[progIndex].target == GL_FRAGMENT_PROGRAM_ARB && strstr( start, "nodhewm3gammahack" ) == NULL ) { + // note that strlen("dhewm3tmpres") == strlen("result.color") + const char *tmpres = "TEMP dhewm3tmpres; # injected by dhewm3 for gamma correction\n"; + + // Note: program.env[21].xyz = r_brightness; program.env[21].w = 1.0/r_gamma + // outColor.rgb = pow(dhewm3tmpres.rgb*r_brightness, vec3(1.0/r_gamma)) + // outColor.a = dhewm3tmpres.a; + const char *extraLines = "# gamma correction in shader, injected by dhewm3\n" + // MUL_SAT clamps the result to [0, 1] - it must not be negative because + // POW might not work with a negative base (it looks wrong with intel's Linux driver) + // and clamping values > 1 to 1 is ok because when writing to result.color + // it's clamped anyway and pow(base, exp) is always >= 1 for base >= 1 + "MUL_SAT dhewm3tmpres.xyz, program.env[21], dhewm3tmpres;\n" // first multiply with brightness + "POW result.color.x, dhewm3tmpres.x, program.env[21].w;\n" // then do pow(dhewm3tmpres.xyz, vec3(1.0f / gamma)) + "POW result.color.y, dhewm3tmpres.y, program.env[21].w;\n" // (apparently POW only supports scalars, not whole vectors) + "POW result.color.z, dhewm3tmpres.z, program.env[21].w;\n" + "MOV result.color.w, dhewm3tmpres.w;\n" // alpha remains unmodified + "\nEND\n\n"; // we add this block right at the end, replacing the original "END" string + + int fullLen = strlen( start ) + strlen( tmpres ) + strlen( extraLines ); + char *outStr = ( char * )_alloca( fullLen + 1 ); + + // add tmpres right after OPTION line (if any) + char *insertPos = R_FindArbShaderComment( start, "OPTION" ); + + if ( insertPos == NULL ) { + // no OPTION? then just put it after the first line (usually something like "!!ARBfp1.0\n") + insertPos = start; + } + + // but we want the position *after* that line + while ( *insertPos != '\0' && *insertPos != '\n' && *insertPos != '\r' ) { + ++insertPos; + } + + // skip the newline character(s) as well + while ( *insertPos == '\n' || *insertPos == '\r' ) { + ++insertPos; + } + + // copy text up to insertPos + int curLen = insertPos - start; + memcpy( outStr, start, curLen ); + + // copy tmpres ("TEMP dhewm3tmpres; # ..") + memcpy( outStr + curLen, tmpres, strlen( tmpres ) ); + curLen += strlen( tmpres ); + + // copy remaining original shader up to (excluding) "END" + int remLen = end - insertPos; + memcpy( outStr + curLen, insertPos, remLen ); + curLen += remLen; + outStr[curLen] = '\0'; // make sure it's NULL-terminated so normal string functions work + + // replace all existing occurrences of "result.color" with "dhewm3tmpres" + for ( char *resCol = strstr( outStr, "result.color" ); resCol != NULL; resCol = strstr( resCol + 13, "result.color" ) ) { + memcpy( resCol, "dhewm3tmpres", 12 ); // both strings have the same length. + + // if this was part of "OUTPUT bla = result.color;", replace + // "OUTPUT bla" with "ALIAS bla" (so it becomes "ALIAS bla = dhewm3tmpres;") + char *s = resCol - 1; + + // first skip whitespace before "result.color" + while ( s > outStr && ( *s == ' ' || *s == '\t' ) ) { + --s; + } + + // if there's no '=' before result.color, this line can't be affected + if ( *s != '=' || s <= outStr + 8 ) { + continue; // go on with next "result.color" in the for-loop + } + --s; + + // we were on '=', so go to the char before and it's time to skip whitespace again + while ( s > outStr && ( *s == ' ' || *s == '\t' ) ) { + --s; + } + + // now we should be at the end of "bla" (or however the variable/alias is called) + if ( s <= outStr + 7 || !R_IsArbIdentifier( *s ) ) { + continue; + } + --s; + + // skip all the remaining chars that are legal in identifiers + while ( s > outStr && R_IsArbIdentifier( *s ) ) { + --s; + } + + // there should be at least one space/tab between "OUTPUT" and "bla" + if ( s <= outStr + 6 || ( *s != ' ' && *s != '\t' ) ) { + continue; + } + --s; + + // skip remaining whitespace (if any) + while ( s > outStr && ( *s == ' ' || *s == '\t' ) ) { + --s; + } + + // now we should be at "OUTPUT" (specifically at its last 'T'), + // if this is indeed such a case + if ( s <= outStr + 5 || *s != 'T' ) { + continue; + } + s -= 5; // skip to start of "OUTPUT", if this is indeed "OUTPUT" + + if ( idStr::Cmpn( s, "OUTPUT", 6 ) == 0 ) { + // it really is "OUTPUT" => replace "OUTPUT" with "ALIAS " + memcpy( s, "ALIAS ", 6 ); + } + } + assert( curLen + strlen( extraLines ) <= fullLen ); + + // now add extraLines that calculate and set a gamma-corrected result.color + // strcat() should be safe because fullLen was calculated taking all parts into account + strcat( outStr, extraLines ); + start = outStr; + } + qglBindProgramARB( progs[progIndex].target, progs[progIndex].ident ); + qglGetError(); + qglProgramStringARB( progs[progIndex].target, GL_PROGRAM_FORMAT_ASCII_ARB, strlen( start ), start ); + err = qglGetError(); + qglGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, ( GLint * )&ofs ); + + if ( err == GL_INVALID_OPERATION ) { + const GLubyte *str = qglGetString( GL_PROGRAM_ERROR_STRING_ARB ); + + common->Printf( "\nGL_PROGRAM_ERROR_STRING_ARB: %s\n", str ); + + if ( ofs < 0 ) { + common->Printf( "GL_PROGRAM_ERROR_POSITION_ARB < 0 with error\n" ); + } else if ( ofs >= ( int )strlen( start ) ) { + common->Printf( "error at end of program\n" ); + } else { + int printOfs = Max( ofs - 20, 0 ); // DG: print some more context + common->Printf( "error at %i:\n%s", ofs, start + printOfs ); + } + return; + } + + if ( ofs != -1 ) { + common->Printf( "\nGL_PROGRAM_ERROR_POSITION_ARB != -1 without error\n" ); + return; + } + common->Printf( "\n" ); +} + +/* +================== +R_FindARBProgram + +Returns a GL identifier that can be bound to the given target, parsing +a text file if it hasn't already been loaded. +================== +*/ +int R_FindARBProgram( GLenum target, const char *program ) { + int i; + idStr stripped = program; + + stripped.StripFileExtension(); + + // see if it is already loaded + for ( i = 0; progs[i].name[0]; i++ ) { + if ( progs[i].target != target ) { + continue; + } + idStr compare = progs[i].name; + + compare.StripFileExtension(); + + if ( !idStr::Icmp( stripped.c_str(), compare.c_str() ) ) { + return progs[i].ident; + } + } + + if ( i == MAX_GLPROGS ) { + common->Error( "R_FindARBProgram: MAX_GLPROGS" ); + } + + // add it to the list and load it + progs[i].ident = ( program_t )0; // will be gen'd by R_LoadARBProgram + progs[i].target = target; + idStr::Copynz( progs[i].name, program, sizeof( progs[i].name ) ); + + R_LoadARBProgram( i ); + + common->Printf( "Finding program %s\n", program ); + return progs[i].ident; +} + +//=================================================================================== + +/* +================== +GL_GetShaderInfoLog +================== +*/ +static void GL_GetShaderInfoLog( GLuint sh, GLchar *src, bool isprog ) { + static GLchar infolog[4096]; + GLsizei maxLength = 0; + + // terminate it. + infolog[0] = 0; + + if ( isprog ) { + qglGetProgramInfoLog( sh, 4095, &maxLength, infolog ); + qglDeleteProgram( sh ); + } else { + qglGetShaderInfoLog( sh, 4095, &maxLength, infolog ); + qglDeleteShader( sh ); + } + common->Printf( "Shader Source:\n\n%s\n\n%s\n\n", src, infolog ); +} + +/* +================== +GL_CompileShader +================== +*/ +static bool GL_CompileShader( GLuint sh, GLchar *src ) { + if ( sh && src ) { + GLint result = GL_FALSE; + + qglGetError(); + + qglShaderSource( sh, 1, const_cast( &src ), 0 ); + qglCompileShader( sh ); + qglGetShaderiv( sh, GL_COMPILE_STATUS, &result ); + + if ( result != GL_TRUE ) { + GL_GetShaderInfoLog( sh, src, false ); + return false; + } else if ( qglGetError() != GL_NO_ERROR ) { + GL_GetShaderInfoLog( sh, src, false ); + } + } + return true; +} + +/* +================== +GL_ValidateProgramStatus +================== +*/ +static bool GL_ValidateProgramStatus( GLuint prg, GLchar *src ) { + GLint valid = GL_FALSE; + + // validate shader program + qglValidateProgram( prg ); + qglGetProgramiv( prg, GL_VALIDATE_STATUS, &valid ); + + // the program was invalid. + if ( valid != GL_TRUE ) { + GL_GetShaderInfoLog( prg, src, true ); + return false; + } + return true; +} + +/* +================== +GL_LinkProgramStatus +================== +*/ +static bool GL_LinkProgramStatus( GLuint prg, GLchar *src ) { + GLint linked = GL_FALSE; + + // test link status + qglLinkProgram( prg ); + qglGetProgramiv( prg, GL_LINK_STATUS, &linked ); + + // the program did not link. + if ( linked != GL_TRUE ) { + GL_GetShaderInfoLog( prg, src, true ); + return false; + } + return true; +} + +//=================================================================================== + +struct glsltable_t { + GLuint slot; + const GLchar *name; +}; + +// doom actually emulates immediate function modes with quite a bit of the vertex attrib calls, like glVertex3f = +// attrPosition or glColor3/4f = attribColor etc. this is also the reason our first attempts at replacing them with +// vertex array pointers failed, because those index positions are not declared in the shader at all. the +// uncommented ones below are the ones missing from the shaders, i only left them in in case someone wanted to make +// an effort in that regard. +glsltable_t interactionAttribs[] = { + /*{ 0, "attrPosition" }, // does not exist in shader + { 2, "attrNormal" }, // ditto and we have two normal indexes (one is used to get texture coordinates for skyportals) + { 3, "attrColor" },*/ // and neither does color sigh... + { 8, "attrTexCoords" }, + { 9, "attrTangents0" }, + { 10, "attrTangents1" }, + { 11, "attrNormal" }, +}; + +/* +================== +GL_CreateGLSLProgram + +Checks and creates shader programs for GLSL +Modified to throw invalid program if ANYTHING! fails. +================== +*/ +static GLuint GL_CreateGLSLProgram( GLchar *vssrc, GLchar *fssrc, glsltable_t *attribs, GLuint numattribs ) { + GLuint progid = 0; + GLuint vs = 0; + GLuint fs = 0; + + // check error + qglGetError(); + + // we got a source create a vertex shader for it. + if ( vssrc ) { + vs = qglCreateShader( GL_VERTEX_SHADER ); + } + + // we got a source create a fragment shader for it. + if ( fssrc ) { + fs = qglCreateShader( GL_FRAGMENT_SHADER ); + } + + // vertex shader failed to compile + if ( vs && vssrc && !GL_CompileShader( vs, vssrc ) ) { + // mark it as invalid + common->Warning( "GL_CompileShader: vertex shader failed to compile\n" ); + return INVALID_PROGRAM; + } + + // fragment shader failed to compile + if ( fs && fssrc && !GL_CompileShader( fs, fssrc ) ) { + // mark it as invalid + common->Warning( "GL_CompileShader: fragment shader failed to compile\n" ); + return INVALID_PROGRAM; + } + progid = qglCreateProgram(); + + // combine vertex shader into GLSL program + if ( vs && vssrc ) { + qglAttachShader( progid, vs ); + } + + // combine fragment shader into GLSL program + if ( fs && fssrc ) { + qglAttachShader( progid, fs ); + } + + // bind attrib index numbers + // we could actually bind the emulated ones here as well and then vertex attribs should work. + if ( attribs && numattribs ) { + for ( GLuint i = 0; i < numattribs; i++ ) { + qglBindAttribLocation( progid, attribs[i].slot, attribs[i].name ); + } + } + + // GLSL vertex program linking failed. + if ( vs && vssrc && !GL_LinkProgramStatus( progid, vssrc ) ) { + // mark it as invalid + common->Warning( "GL_LinkProgramStatus: vertex shader program failed to link\n" ); + return INVALID_PROGRAM; + } + + // GLSL fragment program linking failed. + if ( fs && fssrc && !GL_LinkProgramStatus( progid, fssrc ) ) { + // mark it as invalid + common->Warning( "GL_LinkProgramStatus: fragment shader program failed to link\n" ); + return INVALID_PROGRAM; + } + + // GLSL vertex program validation failed. + if ( vs && vssrc && !GL_ValidateProgramStatus( progid, vssrc ) ) { + // mark it as invalid + common->Warning( "GL_ValidateProgramStatus: vertex shader program is invalid\n" ); + return INVALID_PROGRAM; + } + + // GLSL fragment program validation failed. + if ( fs && fssrc && !GL_ValidateProgramStatus( progid, fssrc ) ) { + // mark it as invalid + common->Warning( "GL_ValidateProgramStatus: fragment shader program is invalid\n" ); + return INVALID_PROGRAM; + } + + // flag shader sources for deletion. + qglDeleteShader( vs ); + qglDeleteShader( fs ); + + // Always detach shaders from programs after a successful link. + qglDetachShader( progid, vs ); + qglDetachShader( progid, fs ); + + return progid; +} + +//=================================================================================== + +struct sampleruniforms_t { + const GLchar *name; + GLint binding; +}; + +sampleruniforms_t rb_interactionsamplers[] = { + { "bumpImage", 1 }, + { "lightFalloffImage", 2 }, + { "lightProjectImage", 3 }, + { "diffuseImage", 4 }, + { "specularImage", 5 }, +}; + +/* +================== +GL_SetupSamplerUniforms +================== +*/ +static void GL_SetupSamplerUniforms( GLuint progid, sampleruniforms_t *uniForms, GLuint numUniforms ) { + // setup texture uniform locations - this is needed even on nvidia + qglUseProgram( progid ); + + for ( GLuint i = 0; i < numUniforms; i++ ) { + qglUniform1i( qglGetUniformLocation( progid, uniForms[i].name ), uniForms[i].binding ); + } + + // No the below are not yet parts of any shader program, DONT move this !!! + // The below are handled in RB_GLSL_DrawInteraction. + qglUseProgram( INVALID_PROGRAM ); + + // setup shader uniforms for the main renderer + u_light_origin = qglGetUniformLocation( progid, "u_light_origin" ); + u_view_origin = qglGetUniformLocation( progid, "u_view_origin" ); + + u_color_modulate = qglGetUniformLocation( progid, "u_color_modulate" ); + u_color_add = qglGetUniformLocation( progid, "u_color_add" ); + + u_constant_diffuse = qglGetUniformLocation( progid, "u_constant_diffuse" ); + u_constant_specular = qglGetUniformLocation( progid, "u_constant_specular" ); + + u_diffMatrix = qglGetUniformLocation( progid, "u_diffMatrix" ); + u_bumpMatrix = qglGetUniformLocation( progid, "u_bumpMatrix" ); + u_specMatrix = qglGetUniformLocation( progid, "u_specMatrix" ); + u_projMatrix = qglGetUniformLocation( progid, "u_projMatrix" ); + u_fallMatrix = qglGetUniformLocation( progid, "u_fallMatrix" ); + /* attrPosition attrNormal and attrColor could be set here */ +} + +/* +================== +GL_GetGLSLFromFile +================== +*/ +static GLchar *GL_GetGLSLFromFile( GLchar *name ) { + idStr fullPath = "glprogs130/"; + fullPath += name; + GLchar *fileBuffer; + GLchar *buffer; + + if ( !glConfig.isInitialized ) { + return NULL; + } + fileSystem->ReadFile( fullPath.c_str(), reinterpret_cast( &fileBuffer ), NULL ); + + if ( !fileBuffer ) { + common->Printf( "%s: File not found, using internal shaders\n", fullPath.c_str() ); + return NULL; + } + + // copy to stack memory (do not use _alloca here!!! it breaks loading the shaders) + buffer = reinterpret_cast( Mem_Alloc( strlen( fileBuffer ) + 1 ) ); + strcpy( buffer, fileBuffer ); + fileSystem->FreeFile( fileBuffer ); + common->Printf( "%s: loaded\n", fullPath.c_str() ); + return buffer; +} + +/* +================== +R_ReloadARBPrograms_f +================== +*/ +void R_ReloadARBPrograms_f( const idCmdArgs &args ) { + common->Printf( "----- R_ReloadARBPrograms -----\n" ); + + // Load material Shaders + for ( int i = 0; progs[i].name[0]; i++ ) { + R_LoadARBProgram( i ); + } + + // load GLSL interaction programs if availiable ( Replaces ARB Interaction Programs ) + if ( r_useGLSL.GetBool() ) { + + // let users know if enabled + common->Printf( "----- Will use GLSL for Interaction Passes (Overrides ARB Interaction). -----\n" ); + + // backup shader gamma value + bool previousGamma = r_gammaInShader.GetBool(); + + // disable shader gamma in GLSL if it was enabled + if ( previousGamma ) { + r_gammaInShader.SetBool( false ); + } + + // try to load from file, use internal shader if not available. + GLchar *vs = GL_GetGLSLFromFile( const_cast( "interaction.vsh" ) ); + GLchar *fs = GL_GetGLSLFromFile( const_cast( "interaction.fsh" ) ); + + // replace ARB interaction shaders with GLSL counterparts, it is possible to use external GLSL shaders as + // well (Revelator: the internal shader defines are const char * so use a const cast to get around it otherwise gcc bugs out). + rb_glsl_interaction_program = GL_CreateGLSLProgram( ( vs != NULL ) ? vs : const_cast( interaction_vs ), ( fs != NULL ) ? fs : const_cast( interaction_fs ), interactionAttribs, + sizeof( interactionAttribs ) / sizeof( interactionAttribs[0] ) ); + + // free externally loaded vertex shader. + if ( vs != NULL ) { + Mem_Free( vs ); + vs = NULL; + } + + // free externally loaded fragment shader. + if ( fs != NULL ) { + Mem_Free( fs ); + fs = NULL; + } + + // now load up uniforms for the GLSL programs. + if ( rb_glsl_interaction_program != INVALID_PROGRAM ) { + GL_SetupSamplerUniforms( rb_glsl_interaction_program, rb_interactionsamplers, + sizeof( rb_interactionsamplers ) / sizeof( rb_interactionsamplers[0] ) ); + } else { + // no shit sherlock turn it off if it fails. + r_useGLSL.SetBool( false ); + + // and set shader gamma back to previous value if it was enabled to begin with + if ( previousGamma ) { + r_gammaInShader.SetBool( previousGamma ); + } + } + common->Printf( "-------------------------------\n" ); + } + common->Printf( "-------------------------------\n" ); +} + +/* +================== +R_ARB2_Init +================== +*/ +void R_ARB2_Init( void ) { + common->Printf( "---------- R_ARB2_Init ----------\n" ); + + // check for ARB capability + if ( !glConfig.ARBVertexProgramAvailable || + !glConfig.ARBFragmentProgramAvailable || + !glConfig.ARBShadingLanguageAvailable ) { + common->Warning( "----- ARB Interaction Programs Not available. -----\n" ); + return; + } + common->Printf( "----- ARB Interaction Programs Available. -----\n" ); + + // according to khronos this might not actually delete the GLSL shader program. + // even worse it will throw an error in case the program is 0 or some other obscure value. + // so make sure it is actually active comming in here. + if ( rb_glsl_interaction_program != INVALID_PROGRAM ) { + qglDeleteProgram( rb_glsl_interaction_program ); + } + common->Printf( "-------------------------------\n" ); + + // kinda redundant we only support arb2. + glConfig.allowARB2Path = true; +} diff --git a/neo/renderer/draw_common.cpp b/neo/renderer/draw_common.cpp index 0cabbfdd0..9ba064943 100644 --- a/neo/renderer/draw_common.cpp +++ b/neo/renderer/draw_common.cpp @@ -40,40 +40,40 @@ RB_BakeTextureMatrixIntoTexgen ===================== */ void RB_BakeTextureMatrixIntoTexgen( idPlane lightProject[3], const float *textureMatrix ) { - float genMatrix[16]; - float final[16]; - - genMatrix[0] = lightProject[0][0]; - genMatrix[4] = lightProject[0][1]; - genMatrix[8] = lightProject[0][2]; - genMatrix[12] = lightProject[0][3]; - - genMatrix[1] = lightProject[1][0]; - genMatrix[5] = lightProject[1][1]; - genMatrix[9] = lightProject[1][2]; - genMatrix[13] = lightProject[1][3]; - - genMatrix[2] = 0; - genMatrix[6] = 0; - genMatrix[10] = 0; - genMatrix[14] = 0; - - genMatrix[3] = lightProject[2][0]; - genMatrix[7] = lightProject[2][1]; - genMatrix[11] = lightProject[2][2]; - genMatrix[15] = lightProject[2][3]; - - myGlMultMatrix( genMatrix, backEnd.lightTextureMatrix, final ); - - lightProject[0][0] = final[0]; - lightProject[0][1] = final[4]; - lightProject[0][2] = final[8]; - lightProject[0][3] = final[12]; - - lightProject[1][0] = final[1]; - lightProject[1][1] = final[5]; - lightProject[1][2] = final[9]; - lightProject[1][3] = final[13]; + float genMatrix[16]; + float final[16]; + + genMatrix[0] = lightProject[0][0]; + genMatrix[4] = lightProject[0][1]; + genMatrix[8] = lightProject[0][2]; + genMatrix[12] = lightProject[0][3]; + + genMatrix[1] = lightProject[1][0]; + genMatrix[5] = lightProject[1][1]; + genMatrix[9] = lightProject[1][2]; + genMatrix[13] = lightProject[1][3]; + + genMatrix[2] = 0; + genMatrix[6] = 0; + genMatrix[10] = 0; + genMatrix[14] = 0; + + genMatrix[3] = lightProject[2][0]; + genMatrix[7] = lightProject[2][1]; + genMatrix[11] = lightProject[2][2]; + genMatrix[15] = lightProject[2][3]; + + R_MatrixMultiply( genMatrix, backEnd.lightTextureMatrix, final ); + + lightProject[0][0] = final[0]; + lightProject[0][1] = final[4]; + lightProject[0][2] = final[8]; + lightProject[0][3] = final[12]; + + lightProject[1][0] = final[1]; + lightProject[1][1] = final[5]; + lightProject[1][2] = final[9]; + lightProject[1][3] = final[13]; } /* @@ -82,171 +82,172 @@ RB_PrepareStageTexturing ================ */ void RB_PrepareStageTexturing( const shaderStage_t *pStage, const drawSurf_t *surf, idDrawVert *ac ) { - // set privatePolygonOffset if necessary - if ( pStage->privatePolygonOffset ) { - qglEnable( GL_POLYGON_OFFSET_FILL ); - qglPolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * pStage->privatePolygonOffset ); - } - - // set the texture matrix if needed - if ( pStage->texture.hasMatrix ) { - RB_LoadShaderTextureMatrix( surf->shaderRegisters, &pStage->texture ); - } - - // texgens - if ( pStage->texture.texgen == TG_DIFFUSE_CUBE ) { - qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); - } - if ( pStage->texture.texgen == TG_SKYBOX_CUBE || pStage->texture.texgen == TG_WOBBLESKY_CUBE ) { - qglTexCoordPointer( 3, GL_FLOAT, 0, vertexCache.Position( surf->dynamicTexCoords ) ); - } - if ( pStage->texture.texgen == TG_SCREEN ) { - qglEnable( GL_TEXTURE_GEN_S ); - qglEnable( GL_TEXTURE_GEN_T ); - qglEnable( GL_TEXTURE_GEN_Q ); - - float mat[16], plane[4]; - myGlMultMatrix( surf->space->modelViewMatrix, backEnd.viewDef->projectionMatrix, mat ); - - plane[0] = mat[0]; - plane[1] = mat[4]; - plane[2] = mat[8]; - plane[3] = mat[12]; - qglTexGenfv( GL_S, GL_OBJECT_PLANE, plane ); - - plane[0] = mat[1]; - plane[1] = mat[5]; - plane[2] = mat[9]; - plane[3] = mat[13]; - qglTexGenfv( GL_T, GL_OBJECT_PLANE, plane ); - - plane[0] = mat[3]; - plane[1] = mat[7]; - plane[2] = mat[11]; - plane[3] = mat[15]; - qglTexGenfv( GL_Q, GL_OBJECT_PLANE, plane ); - } - - if ( pStage->texture.texgen == TG_SCREEN2 ) { - qglEnable( GL_TEXTURE_GEN_S ); - qglEnable( GL_TEXTURE_GEN_T ); - qglEnable( GL_TEXTURE_GEN_Q ); - - float mat[16], plane[4]; - myGlMultMatrix( surf->space->modelViewMatrix, backEnd.viewDef->projectionMatrix, mat ); - - plane[0] = mat[0]; - plane[1] = mat[4]; - plane[2] = mat[8]; - plane[3] = mat[12]; - qglTexGenfv( GL_S, GL_OBJECT_PLANE, plane ); - - plane[0] = mat[1]; - plane[1] = mat[5]; - plane[2] = mat[9]; - plane[3] = mat[13]; - qglTexGenfv( GL_T, GL_OBJECT_PLANE, plane ); - - plane[0] = mat[3]; - plane[1] = mat[7]; - plane[2] = mat[11]; - plane[3] = mat[15]; - qglTexGenfv( GL_Q, GL_OBJECT_PLANE, plane ); - } - - if ( pStage->texture.texgen == TG_GLASSWARP ) { - if ( tr.backEndRenderer == BE_ARB2 /*|| tr.backEndRenderer == BE_NV30*/ ) { - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_GLASSWARP ); - qglEnable( GL_FRAGMENT_PROGRAM_ARB ); - - GL_SelectTexture( 2 ); - globalImages->scratchImage->Bind(); - - GL_SelectTexture( 1 ); - globalImages->scratchImage2->Bind(); - - qglEnable( GL_TEXTURE_GEN_S ); - qglEnable( GL_TEXTURE_GEN_T ); - qglEnable( GL_TEXTURE_GEN_Q ); - - float mat[16], plane[4]; - myGlMultMatrix( surf->space->modelViewMatrix, backEnd.viewDef->projectionMatrix, mat ); - - plane[0] = mat[0]; - plane[1] = mat[4]; - plane[2] = mat[8]; - plane[3] = mat[12]; - qglTexGenfv( GL_S, GL_OBJECT_PLANE, plane ); - - plane[0] = mat[1]; - plane[1] = mat[5]; - plane[2] = mat[9]; - plane[3] = mat[13]; - qglTexGenfv( GL_T, GL_OBJECT_PLANE, plane ); - - plane[0] = mat[3]; - plane[1] = mat[7]; - plane[2] = mat[11]; - plane[3] = mat[15]; - qglTexGenfv( GL_Q, GL_OBJECT_PLANE, plane ); - - GL_SelectTexture( 0 ); - } - } - - if ( pStage->texture.texgen == TG_REFLECT_CUBE ) { - if ( tr.backEndRenderer == BE_ARB2 ) { - // see if there is also a bump map specified - const shaderStage_t *bumpStage = surf->material->GetBumpStage(); - if ( bumpStage ) { - // per-pixel reflection mapping with bump mapping - GL_SelectTexture( 1 ); - bumpStage->texture.image->Bind(); - GL_SelectTexture( 0 ); - - qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); - qglVertexAttribPointerARB( 10, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() ); - qglVertexAttribPointerARB( 9, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() ); - - qglEnableVertexAttribArrayARB( 9 ); - qglEnableVertexAttribArrayARB( 10 ); - qglEnableClientState( GL_NORMAL_ARRAY ); - - // Program env 5, 6, 7, 8 have been set in RB_SetProgramEnvironmentSpace - - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_BUMPY_ENVIRONMENT ); - qglEnable( GL_FRAGMENT_PROGRAM_ARB ); - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_BUMPY_ENVIRONMENT ); - qglEnable( GL_VERTEX_PROGRAM_ARB ); - } else { - // per-pixel reflection mapping without a normal map - qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); - qglEnableClientState( GL_NORMAL_ARRAY ); - - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_ENVIRONMENT ); - qglEnable( GL_FRAGMENT_PROGRAM_ARB ); - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_ENVIRONMENT ); - qglEnable( GL_VERTEX_PROGRAM_ARB ); - } - } else { - qglEnable( GL_TEXTURE_GEN_S ); - qglEnable( GL_TEXTURE_GEN_T ); - qglEnable( GL_TEXTURE_GEN_R ); - qglTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT ); - qglTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT ); - qglTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT ); - qglEnableClientState( GL_NORMAL_ARRAY ); - qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); - - qglMatrixMode( GL_TEXTURE ); - float mat[16]; - - R_TransposeGLMatrix( backEnd.viewDef->worldSpace.modelViewMatrix, mat ); - - qglLoadMatrixf( mat ); - qglMatrixMode( GL_MODELVIEW ); - } - } + // set privatePolygonOffset if necessary + if ( pStage->privatePolygonOffset ) { + qglEnable( GL_POLYGON_OFFSET_FILL ); + qglPolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * pStage->privatePolygonOffset ); + } + + // set the texture matrix if needed + if ( pStage->texture.hasMatrix ) { + RB_LoadShaderTextureMatrix( surf->shaderRegisters, &pStage->texture ); + } + + // texgens + if ( pStage->texture.texgen == TG_DIFFUSE_CUBE ) { + qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); + } + + if ( pStage->texture.texgen == TG_SKYBOX_CUBE || pStage->texture.texgen == TG_WOBBLESKY_CUBE ) { + qglTexCoordPointer( 3, GL_FLOAT, 0, vertexCache.Position( surf->dynamicTexCoords ) ); + } + + if ( pStage->texture.texgen == TG_SCREEN ) { + qglEnable( GL_TEXTURE_GEN_S ); + qglEnable( GL_TEXTURE_GEN_T ); + qglEnable( GL_TEXTURE_GEN_Q ); + + float mat[16], plane[4]; + R_MatrixMultiply( surf->space->modelViewMatrix, backEnd.viewDef->projectionMatrix, mat ); + + plane[0] = mat[0]; + plane[1] = mat[4]; + plane[2] = mat[8]; + plane[3] = mat[12]; + qglTexGenfv( GL_S, GL_OBJECT_PLANE, plane ); + + plane[0] = mat[1]; + plane[1] = mat[5]; + plane[2] = mat[9]; + plane[3] = mat[13]; + qglTexGenfv( GL_T, GL_OBJECT_PLANE, plane ); + + plane[0] = mat[3]; + plane[1] = mat[7]; + plane[2] = mat[11]; + plane[3] = mat[15]; + qglTexGenfv( GL_Q, GL_OBJECT_PLANE, plane ); + } + + if ( pStage->texture.texgen == TG_SCREEN2 ) { + qglEnable( GL_TEXTURE_GEN_S ); + qglEnable( GL_TEXTURE_GEN_T ); + qglEnable( GL_TEXTURE_GEN_Q ); + + float mat[16], plane[4]; + R_MatrixMultiply( surf->space->modelViewMatrix, backEnd.viewDef->projectionMatrix, mat ); + + plane[0] = mat[0]; + plane[1] = mat[4]; + plane[2] = mat[8]; + plane[3] = mat[12]; + qglTexGenfv( GL_S, GL_OBJECT_PLANE, plane ); + + plane[0] = mat[1]; + plane[1] = mat[5]; + plane[2] = mat[9]; + plane[3] = mat[13]; + qglTexGenfv( GL_T, GL_OBJECT_PLANE, plane ); + + plane[0] = mat[3]; + plane[1] = mat[7]; + plane[2] = mat[11]; + plane[3] = mat[15]; + qglTexGenfv( GL_Q, GL_OBJECT_PLANE, plane ); + } + + if ( pStage->texture.texgen == TG_GLASSWARP ) { + if ( tr.backEndRenderer == BE_ARB2 ) { + qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_GLASSWARP ); + qglEnable( GL_FRAGMENT_PROGRAM_ARB ); + + GL_SelectTexture( 2 ); + globalImages->scratchImage->Bind(); + + GL_SelectTexture( 1 ); + globalImages->scratchImage2->Bind(); + + qglEnable( GL_TEXTURE_GEN_S ); + qglEnable( GL_TEXTURE_GEN_T ); + qglEnable( GL_TEXTURE_GEN_Q ); + + float mat[16], plane[4]; + R_MatrixMultiply( surf->space->modelViewMatrix, backEnd.viewDef->projectionMatrix, mat ); + + plane[0] = mat[0]; + plane[1] = mat[4]; + plane[2] = mat[8]; + plane[3] = mat[12]; + qglTexGenfv( GL_S, GL_OBJECT_PLANE, plane ); + + plane[0] = mat[1]; + plane[1] = mat[5]; + plane[2] = mat[9]; + plane[3] = mat[13]; + qglTexGenfv( GL_T, GL_OBJECT_PLANE, plane ); + + plane[0] = mat[3]; + plane[1] = mat[7]; + plane[2] = mat[11]; + plane[3] = mat[15]; + qglTexGenfv( GL_Q, GL_OBJECT_PLANE, plane ); + + GL_SelectTexture( 0 ); + } + } + + if ( pStage->texture.texgen == TG_REFLECT_CUBE ) { + if ( tr.backEndRenderer == BE_ARB2 ) { + // see if there is also a bump map specified + const shaderStage_t *bumpStage = surf->material->GetBumpStage(); + if ( bumpStage ) { + // per-pixel reflection mapping with bump mapping + GL_SelectTexture( 1 ); + bumpStage->texture.image->Bind(); + GL_SelectTexture( 0 ); + + qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); + qglVertexAttribPointerARB( 10, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() ); + qglVertexAttribPointerARB( 9, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() ); + + qglEnableVertexAttribArrayARB( 9 ); + qglEnableVertexAttribArrayARB( 10 ); + qglEnableClientState( GL_NORMAL_ARRAY ); + + // Program env 5, 6, 7, 8 have been set in RB_SetProgramEnvironmentSpace + qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_BUMPY_ENVIRONMENT ); + qglEnable( GL_FRAGMENT_PROGRAM_ARB ); + qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_BUMPY_ENVIRONMENT ); + qglEnable( GL_VERTEX_PROGRAM_ARB ); + } else { + // per-pixel reflection mapping without a normal map + qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); + qglEnableClientState( GL_NORMAL_ARRAY ); + + qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_ENVIRONMENT ); + qglEnable( GL_FRAGMENT_PROGRAM_ARB ); + qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_ENVIRONMENT ); + qglEnable( GL_VERTEX_PROGRAM_ARB ); + } + } else { + qglEnable( GL_TEXTURE_GEN_S ); + qglEnable( GL_TEXTURE_GEN_T ); + qglEnable( GL_TEXTURE_GEN_R ); + qglTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT ); + qglTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT ); + qglTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT ); + qglEnableClientState( GL_NORMAL_ARRAY ); + qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); + + qglMatrixMode( GL_TEXTURE ); + float mat[16]; + + R_TransposeGLMatrix( backEnd.viewDef->worldSpace.modelViewMatrix, mat ); + + qglLoadMatrixf( mat ); + qglMatrixMode( GL_MODELVIEW ); + } + } } /* @@ -255,86 +256,86 @@ RB_FinishStageTexturing ================ */ void RB_FinishStageTexturing( const shaderStage_t *pStage, const drawSurf_t *surf, idDrawVert *ac ) { - // unset privatePolygonOffset if necessary - if ( pStage->privatePolygonOffset && !surf->material->TestMaterialFlag(MF_POLYGONOFFSET) ) { - qglDisable( GL_POLYGON_OFFSET_FILL ); - } - - if ( pStage->texture.texgen == TG_DIFFUSE_CUBE || pStage->texture.texgen == TG_SKYBOX_CUBE - || pStage->texture.texgen == TG_WOBBLESKY_CUBE ) { - qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), (void *)&ac->st ); - } - - if ( pStage->texture.texgen == TG_SCREEN ) { - qglDisable( GL_TEXTURE_GEN_S ); - qglDisable( GL_TEXTURE_GEN_T ); - qglDisable( GL_TEXTURE_GEN_Q ); - } - if ( pStage->texture.texgen == TG_SCREEN2 ) { - qglDisable( GL_TEXTURE_GEN_S ); - qglDisable( GL_TEXTURE_GEN_T ); - qglDisable( GL_TEXTURE_GEN_Q ); - } - - if ( pStage->texture.texgen == TG_GLASSWARP ) { - if ( tr.backEndRenderer == BE_ARB2 /*|| tr.backEndRenderer == BE_NV30*/ ) { - GL_SelectTexture( 2 ); - globalImages->BindNull(); - - GL_SelectTexture( 1 ); - if ( pStage->texture.hasMatrix ) { - RB_LoadShaderTextureMatrix( surf->shaderRegisters, &pStage->texture ); - } - qglDisable( GL_TEXTURE_GEN_S ); - qglDisable( GL_TEXTURE_GEN_T ); - qglDisable( GL_TEXTURE_GEN_Q ); - qglDisable( GL_FRAGMENT_PROGRAM_ARB ); - globalImages->BindNull(); - GL_SelectTexture( 0 ); - } - } - - if ( pStage->texture.texgen == TG_REFLECT_CUBE ) { - if ( tr.backEndRenderer == BE_ARB2 ) { - // see if there is also a bump map specified - const shaderStage_t *bumpStage = surf->material->GetBumpStage(); - if ( bumpStage ) { - // per-pixel reflection mapping with bump mapping - GL_SelectTexture( 1 ); - globalImages->BindNull(); - GL_SelectTexture( 0 ); - - qglDisableVertexAttribArrayARB( 9 ); - qglDisableVertexAttribArrayARB( 10 ); - } else { - // per-pixel reflection mapping without bump mapping - } - - qglDisableClientState( GL_NORMAL_ARRAY ); - qglDisable( GL_FRAGMENT_PROGRAM_ARB ); - qglDisable( GL_VERTEX_PROGRAM_ARB ); - // Fixme: Hack to get around an apparent bug in ATI drivers. Should remove as soon as it gets fixed. - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, 0 ); // FIXME ... - } else { - qglDisable( GL_TEXTURE_GEN_S ); - qglDisable( GL_TEXTURE_GEN_T ); - qglDisable( GL_TEXTURE_GEN_R ); - qglTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); - qglTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); - qglTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); - qglDisableClientState( GL_NORMAL_ARRAY ); - - qglMatrixMode( GL_TEXTURE ); - qglLoadIdentity(); - qglMatrixMode( GL_MODELVIEW ); - } - } - - if ( pStage->texture.hasMatrix ) { - qglMatrixMode( GL_TEXTURE ); - qglLoadIdentity(); - qglMatrixMode( GL_MODELVIEW ); - } + // unset privatePolygonOffset if necessary + if ( pStage->privatePolygonOffset && !surf->material->TestMaterialFlag( MF_POLYGONOFFSET ) ) { + qglDisable( GL_POLYGON_OFFSET_FILL ); + } + + if ( pStage->texture.texgen == TG_DIFFUSE_CUBE || + pStage->texture.texgen == TG_SKYBOX_CUBE || + pStage->texture.texgen == TG_WOBBLESKY_CUBE ) { + qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), ( void * )&ac->st ); + } + + if ( pStage->texture.texgen == TG_SCREEN ) { + qglDisable( GL_TEXTURE_GEN_S ); + qglDisable( GL_TEXTURE_GEN_T ); + qglDisable( GL_TEXTURE_GEN_Q ); + } + if ( pStage->texture.texgen == TG_SCREEN2 ) { + qglDisable( GL_TEXTURE_GEN_S ); + qglDisable( GL_TEXTURE_GEN_T ); + qglDisable( GL_TEXTURE_GEN_Q ); + } + + if ( pStage->texture.texgen == TG_GLASSWARP ) { + if ( tr.backEndRenderer == BE_ARB2 ) { + GL_SelectTexture( 2 ); + globalImages->BindNull(); + + GL_SelectTexture( 1 ); + if ( pStage->texture.hasMatrix ) { + RB_LoadShaderTextureMatrix( surf->shaderRegisters, &pStage->texture ); + } + qglDisable( GL_TEXTURE_GEN_S ); + qglDisable( GL_TEXTURE_GEN_T ); + qglDisable( GL_TEXTURE_GEN_Q ); + qglDisable( GL_FRAGMENT_PROGRAM_ARB ); + globalImages->BindNull(); + GL_SelectTexture( 0 ); + } + } + + if ( pStage->texture.texgen == TG_REFLECT_CUBE ) { + if ( tr.backEndRenderer == BE_ARB2 ) { + // see if there is also a bump map specified + const shaderStage_t *bumpStage = surf->material->GetBumpStage(); + if ( bumpStage ) { + // per-pixel reflection mapping with bump mapping + GL_SelectTexture( 1 ); + globalImages->BindNull(); + GL_SelectTexture( 0 ); + + qglDisableVertexAttribArrayARB( 9 ); + qglDisableVertexAttribArrayARB( 10 ); + } else { + // per-pixel reflection mapping without bump mapping + } + qglDisableClientState( GL_NORMAL_ARRAY ); + qglDisable( GL_FRAGMENT_PROGRAM_ARB ); + qglDisable( GL_VERTEX_PROGRAM_ARB ); + // Fixme: Hack to get around an apparent bug in ATI drivers. Should remove as soon as it gets fixed. + qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, 0 ); // FIXME ... + } else { + qglDisable( GL_TEXTURE_GEN_S ); + qglDisable( GL_TEXTURE_GEN_T ); + qglDisable( GL_TEXTURE_GEN_R ); + qglTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); + qglTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); + qglTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); + qglDisableClientState( GL_NORMAL_ARRAY ); + + qglMatrixMode( GL_TEXTURE ); + qglLoadIdentity(); + qglMatrixMode( GL_MODELVIEW ); + } + } + + if ( pStage->texture.hasMatrix ) { + qglMatrixMode( GL_TEXTURE ); + qglLoadIdentity(); + qglMatrixMode( GL_MODELVIEW ); + } } /* @@ -352,171 +353,168 @@ RB_T_FillDepthBuffer ================== */ void RB_T_FillDepthBuffer( const drawSurf_t *surf ) { - int stage; - const idMaterial *shader; - const shaderStage_t *pStage; - const float *regs; - float color[4]; - const srfTriangles_t *tri; - - tri = surf->geo; - shader = surf->material; - - // update the clip plane if needed - if ( backEnd.viewDef->numClipPlanes && surf->space != backEnd.currentSpace ) { - GL_SelectTexture( 1 ); - - idPlane plane; - - R_GlobalPlaneToLocal( surf->space->modelMatrix, backEnd.viewDef->clipPlanes[0], plane ); - plane[3] += 0.5; // the notch is in the middle - qglTexGenfv( GL_S, GL_OBJECT_PLANE, plane.ToFloatPtr() ); - GL_SelectTexture( 0 ); - } - - if ( !shader->IsDrawn() ) { - return; - } - - // some deforms may disable themselves by setting numIndexes = 0 - if ( !tri->numIndexes ) { - return; - } - - // translucent surfaces don't put anything in the depth buffer and don't - // test against it, which makes them fail the mirror clip plane operation - if ( shader->Coverage() == MC_TRANSLUCENT ) { - return; - } - - if ( !tri->ambientCache ) { - common->Printf( "RB_T_FillDepthBuffer: !tri->ambientCache\n" ); - return; - } - - // get the expressions for conditionals / color / texcoords - regs = surf->shaderRegisters; - - // if all stages of a material have been conditioned off, don't do anything - for ( stage = 0; stage < shader->GetNumStages() ; stage++ ) { - pStage = shader->GetStage(stage); - // check the stage enable condition - if ( regs[ pStage->conditionRegister ] != 0 ) { - break; - } - } - if ( stage == shader->GetNumStages() ) { - return; - } - - // set polygon offset if necessary - if ( shader->TestMaterialFlag(MF_POLYGONOFFSET) ) { - qglEnable( GL_POLYGON_OFFSET_FILL ); - qglPolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); - } - - // subviews will just down-modulate the color buffer by overbright - if ( shader->GetSort() == SS_SUBVIEW ) { - GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO | GLS_DEPTHFUNC_LESS ); - color[0] = - color[1] = - color[2] = ( 1.0 / backEnd.overBright ); - color[3] = 1; - } else { - // others just draw black - color[0] = 0; - color[1] = 0; - color[2] = 0; - color[3] = 1; - } - - idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache ); - qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); - qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), reinterpret_cast(&ac->st) ); - - bool drawSolid = false; - - if ( shader->Coverage() == MC_OPAQUE ) { - drawSolid = true; - } - - // we may have multiple alpha tested stages - if ( shader->Coverage() == MC_PERFORATED ) { - // if the only alpha tested stages are condition register omitted, - // draw a normal opaque surface - bool didDraw = false; - - qglEnable( GL_ALPHA_TEST ); - // perforated surfaces may have multiple alpha tested stages - for ( stage = 0; stage < shader->GetNumStages() ; stage++ ) { - pStage = shader->GetStage(stage); - - if ( !pStage->hasAlphaTest ) { - continue; - } - - // check the stage enable condition - if ( regs[ pStage->conditionRegister ] == 0 ) { - continue; - } - - // if we at least tried to draw an alpha tested stage, - // we won't draw the opaque surface - didDraw = true; - - // set the alpha modulate - color[3] = regs[ pStage->color.registers[3] ]; - - // skip the entire stage if alpha would be black - if ( color[3] <= 0 ) { - continue; - } - qglColor4fv( color ); - - qglAlphaFunc( GL_GREATER, regs[ pStage->alphaTestRegister ] ); - - // bind the texture - pStage->texture.image->Bind(); - - // set texture matrix and texGens - RB_PrepareStageTexturing( pStage, surf, ac ); - - // draw it - RB_DrawElementsWithCounters( tri ); - - RB_FinishStageTexturing( pStage, surf, ac ); - } - qglDisable( GL_ALPHA_TEST ); - if ( !didDraw ) { - drawSolid = true; - } - } - - // draw the entire surface solid - if ( drawSolid ) { - qglColor4fv( color ); - globalImages->whiteImage->Bind(); - - // draw it - RB_DrawElementsWithCounters( tri ); - } - - - // reset polygon offset - if ( shader->TestMaterialFlag(MF_POLYGONOFFSET) ) { - qglDisable( GL_POLYGON_OFFSET_FILL ); - } - - // reset blending - if ( shader->GetSort() == SS_SUBVIEW ) { - GL_State( GLS_DEPTHFUNC_LESS ); - } + int stage; + const idMaterial *shader; + const shaderStage_t *pStage; + const float *regs; + float color[4]; + const srfTriangles_t *tri; + + tri = surf->geo; + shader = surf->material; + + // update the clip plane if needed + if ( backEnd.viewDef->numClipPlanes && surf->space != backEnd.currentSpace ) { + GL_SelectTexture( 1 ); + + idPlane plane; + + R_GlobalPlaneToLocal( surf->space->modelMatrix, backEnd.viewDef->clipPlanes[0], plane ); + plane[3] += 0.5; // the notch is in the middle + qglTexGenfv( GL_S, GL_OBJECT_PLANE, plane.ToFloatPtr() ); + GL_SelectTexture( 0 ); + } + + if ( !shader->IsDrawn() ) { + return; + } + + // some deforms may disable themselves by setting numIndexes = 0 + if ( !tri->numIndexes ) { + return; + } + + // translucent surfaces don't put anything in the depth buffer and don't + // test against it, which makes them fail the mirror clip plane operation + if ( shader->Coverage() == MC_TRANSLUCENT ) { + return; + } + + if ( !tri->ambientCache ) { + common->Printf( "RB_T_FillDepthBuffer: !tri->ambientCache\n" ); + return; + } + + // get the expressions for conditionals / color / texcoords + regs = surf->shaderRegisters; + + // if all stages of a material have been conditioned off, don't do anything + for ( stage = 0; stage < shader->GetNumStages() ; stage++ ) { + pStage = shader->GetStage( stage ); + // check the stage enable condition + if ( regs[ pStage->conditionRegister ] != 0 ) { + break; + } + } + if ( stage == shader->GetNumStages() ) { + return; + } + + // set polygon offset if necessary + if ( shader->TestMaterialFlag( MF_POLYGONOFFSET ) ) { + qglEnable( GL_POLYGON_OFFSET_FILL ); + qglPolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); + } + + // subviews will just down-modulate the color buffer by overbright + if ( shader->GetSort() == SS_SUBVIEW ) { + GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO | GLS_DEPTHFUNC_LESS ); + color[0] = + color[1] = + color[2] = ( 1.0f / backEnd.overBright ); + color[3] = 1; + } else { + // others just draw black + color[0] = 0; + color[1] = 0; + color[2] = 0; + color[3] = 1; + } + idDrawVert *ac = ( idDrawVert * )vertexCache.Position( tri->ambientCache ); + qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); + qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), reinterpret_cast( &ac->st ) ); + + bool drawSolid = false; + + if ( shader->Coverage() == MC_OPAQUE ) { + drawSolid = true; + } + + // we may have multiple alpha tested stages + if ( shader->Coverage() == MC_PERFORATED ) { + // if the only alpha tested stages are condition register omitted, + // draw a normal opaque surface + bool didDraw = false; + + qglEnable( GL_ALPHA_TEST ); + // perforated surfaces may have multiple alpha tested stages + for ( stage = 0; stage < shader->GetNumStages() ; stage++ ) { + pStage = shader->GetStage( stage ); + + if ( !pStage->hasAlphaTest ) { + continue; + } + + // check the stage enable condition + if ( regs[ pStage->conditionRegister ] == 0 ) { + continue; + } + + // if we at least tried to draw an alpha tested stage, + // we won't draw the opaque surface + didDraw = true; + + // set the alpha modulate + color[3] = regs[ pStage->color.registers[3] ]; + + // skip the entire stage if alpha would be black + if ( color[3] <= 0 ) { + continue; + } + qglColor4fv( color ); + + qglAlphaFunc( GL_GREATER, regs[ pStage->alphaTestRegister ] ); + + // bind the texture + pStage->texture.image->Bind(); + + // set texture matrix and texGens + RB_PrepareStageTexturing( pStage, surf, ac ); + + // draw it + RB_DrawElementsWithCounters( tri ); + + RB_FinishStageTexturing( pStage, surf, ac ); + } + qglDisable( GL_ALPHA_TEST ); + + if ( !didDraw ) { + drawSolid = true; + } + } + + // draw the entire surface solid + if ( drawSolid ) { + qglColor4fv( color ); + globalImages->whiteImage->Bind(); + + // draw it + RB_DrawElementsWithCounters( tri ); + } + + + // reset polygon offset + if ( shader->TestMaterialFlag( MF_POLYGONOFFSET ) ) { + qglDisable( GL_POLYGON_OFFSET_FILL ); + } + + // reset blending + if ( shader->GetSort() == SS_SUBVIEW ) { + GL_State( GLS_DEPTHFUNC_LESS ); + } } - -void RB_SetProgramEnvironment( bool isPostProcess ); // so RB_STD_FillDepthBuffer() can use it - /* ===================== RB_STD_FillDepthBuffer @@ -526,58 +524,56 @@ to force the alpha test to fail when behind that clip plane ===================== */ void RB_STD_FillDepthBuffer( drawSurf_t **drawSurfs, int numDrawSurfs ) { - // if we are just doing 2D rendering, no need to fill the depth buffer - if ( !backEnd.viewDef->viewEntitys ) { - return; - } - - // enable the second texture for mirror plane clipping if needed - if ( backEnd.viewDef->numClipPlanes ) { - GL_SelectTexture( 1 ); - globalImages->alphaNotchImage->Bind(); - qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - qglEnable( GL_TEXTURE_GEN_S ); - qglTexCoord2f( 1, 0.5 ); - } - - // the first texture will be used for alpha tested surfaces - GL_SelectTexture( 0 ); - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - - // decal surfaces may enable polygon offset - qglPolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() ); - - GL_State( GLS_DEPTHFUNC_LESS ); - - // Enable stencil test if we are going to be using it for shadows. - // If we didn't do this, it would be legal behavior to get z fighting - // from the ambient pass and the light passes. - qglEnable( GL_STENCIL_TEST ); - qglStencilFunc( GL_ALWAYS, 1, 255 ); - - RB_RenderDrawSurfListWithFunction( drawSurfs, numDrawSurfs, RB_T_FillDepthBuffer ); - - // Make the early depth pass available to shaders. #3877 - bool getDepthCapture = r_enableDepthCapture.GetInteger() == 1 - || (r_enableDepthCapture.GetInteger() == -1 && r_useSoftParticles.GetBool()); - - if ( getDepthCapture && backEnd.viewDef->renderView.viewID >= 0 ) // Suppress for lightgem rendering passes - { - globalImages->currentDepthImage->CopyDepthbuffer( backEnd.viewDef->viewport.x1, - backEnd.viewDef->viewport.y1, - backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1, - backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1, - true ); - bool isPostProcess = false; - RB_SetProgramEnvironment( isPostProcess ); - } - - if ( backEnd.viewDef->numClipPlanes ) { - GL_SelectTexture( 1 ); - globalImages->BindNull(); - qglDisable( GL_TEXTURE_GEN_S ); - GL_SelectTexture( 0 ); - } + // if we are just doing 2D rendering, no need to fill the depth buffer + if ( !backEnd.viewDef->viewEntitys ) { + return; + } + + // enable the second texture for mirror plane clipping if needed + if ( backEnd.viewDef->numClipPlanes ) { + GL_SelectTexture( 1 ); + globalImages->alphaNotchImage->Bind(); + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + qglEnable( GL_TEXTURE_GEN_S ); + qglTexCoord2f( 1, 0.5 ); + } + + // the first texture will be used for alpha tested surfaces + GL_SelectTexture( 0 ); + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + + // decal surfaces may enable polygon offset + qglPolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() ); + + GL_State( GLS_DEPTHFUNC_LESS ); + + // Enable stencil test if we are going to be using it for shadows. + // If we didn't do this, it would be legal behavior to get z fighting + // from the ambient pass and the light passes. + qglEnable( GL_STENCIL_TEST ); + qglStencilFunc( GL_ALWAYS, 1, 255 ); + + RB_RenderDrawSurfListWithFunction( drawSurfs, numDrawSurfs, RB_T_FillDepthBuffer ); + + // Make the early depth pass available to shaders. #3877 + bool getDepthCapture = ( r_enableDepthCapture.GetInteger() == 1 ) || + ( r_enableDepthCapture.GetInteger() == -1 && r_useSoftParticles.GetBool() ); + + if ( getDepthCapture && backEnd.viewDef->renderView.viewID >= 0 ) { // Suppress for lightgem rendering passes + globalImages->currentDepthImage->CopyDepthbuffer( backEnd.viewDef->viewport.x1, + backEnd.viewDef->viewport.y1, + backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1, + backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1, + true ); + RB_SetProgramEnvironment( false ); + } + + if ( backEnd.viewDef->numClipPlanes ) { + GL_SelectTexture( 1 ); + globalImages->BindNull(); + qglDisable( GL_TEXTURE_GEN_S ); + GL_SelectTexture( 0 ); + } } @@ -609,96 +605,97 @@ Parameters 23 and 24 are used by soft particles #3878. Note these can be freely ================== */ void RB_SetProgramEnvironment( bool isPostProcess ) { - float parm[4]; - int pot; + float parm[4]; + int pot; - if ( !glConfig.ARBVertexProgramAvailable ) { - return; - } + if ( !glConfig.ARBVertexProgramAvailable ) { + return; + } #if 0 - // screen power of two correction factor, one pixel in so we don't get a bilerp - // of an uncopied pixel - int w = backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1; - pot = globalImages->currentRenderImage->uploadWidth; - if ( w == pot ) { - parm[0] = 1.0; - } else { - parm[0] = (float)(w-1) / pot; - } - - int h = backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1; - pot = globalImages->currentRenderImage->uploadHeight; - if ( h == pot ) { - parm[1] = 1.0; - } else { - parm[1] = (float)(h-1) / pot; - } - - parm[2] = 0; - parm[3] = 1; - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 0, parm ); + // screen power of two correction factor, one pixel in so we don't get a bilerp + // of an uncopied pixel + int w = backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1; + + pot = globalImages->currentRenderImage->uploadWidth; + + if ( w == pot ) { + parm[0] = 1.0; + } else { + parm[0] = ( float )( w - 1 ) / pot; + } + int h = backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1; + + pot = globalImages->currentRenderImage->uploadHeight; + + if ( h == pot ) { + parm[1] = 1.0; + } else { + parm[1] = ( float )( h - 1 ) / pot; + } + parm[2] = 0; + parm[3] = 1; + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 0, parm ); #else - // screen power of two correction factor, assuming the copy to _currentRender - // also copied an extra row and column for the bilerp - int w = backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1; - pot = globalImages->currentRenderImage->uploadWidth; - parm[0] = (float)w / pot; - - int h = backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1; - pot = globalImages->currentRenderImage->uploadHeight; - parm[1] = (float)h / pot; - - parm[2] = 0; - parm[3] = 1; - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 0, parm ); + // screen power of two correction factor, assuming the copy to _currentRender + // also copied an extra row and column for the bilerp + int w = backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1; + pot = globalImages->currentRenderImage->uploadWidth; + parm[0] = ( float )w / pot; + + int h = backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1; + pot = globalImages->currentRenderImage->uploadHeight; + parm[1] = ( float )h / pot; + + parm[2] = 0; + parm[3] = 1; + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 0, parm ); #endif - - qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm ); - - // window coord to 0.0 to 1.0 conversion - parm[0] = 1.0 / w; - parm[1] = 1.0 / h; - parm[2] = 0; - parm[3] = 1; - qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 1, parm ); - - // DG: brightness and gamma in shader as program.env[4] - if ( r_gammaInShader.GetBool() ) { - // program.env[4].xyz are all r_brightness, program.env[4].w is 1.0/r_gamma - if ( !isPostProcess ) { - parm[0] = parm[1] = parm[2] = r_brightness.GetFloat(); - parm[3] = 1.0/r_gamma.GetFloat(); // 1.0/gamma so the shader doesn't have to do this calculation - } else { - // don't apply gamma/brightness in postprocess passes to avoid applying them twice - // (setting them to 1.0 makes them no-ops) - parm[0] = parm[1] = parm[2] = parm[3] = 1.0f; - } - qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_GAMMA_BRIGHTNESS, parm ); - } - - // #3877: Allow shaders to access depth buffer. - // Two useful ratios are packed into this parm: [0] and [1] hold the x,y multipliers you need to map a screen - // coordinate (fragment position) to the depth image: those are simply the reciprocal of the depth - // image size, which has been rounded up to a power of two. Slots [3] and [4] hold the ratio of the depth image - // size to the current render image size. These sizes can differ if the game crops the render viewport temporarily - // during post-processing effects. The depth render is smaller during the effect too, but the depth image doesn't - // need to be downsized, whereas the current render image does get downsized when it's captured by the game after - // the skybox render pass. The ratio is needed to map between the two render images. - parm[0] = 1.0f / globalImages->currentDepthImage->uploadWidth; - parm[1] = 1.0f / globalImages->currentDepthImage->uploadHeight; - parm[2] = static_cast(globalImages->currentRenderImage->uploadWidth) / globalImages->currentDepthImage->uploadWidth; - parm[3] = static_cast(globalImages->currentRenderImage->uploadHeight) / globalImages->currentDepthImage->uploadHeight; - qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_CURDEPTH_RECIPR, parm ); - - // - // set eye position in global space - // - parm[0] = backEnd.viewDef->renderView.vieworg[0]; - parm[1] = backEnd.viewDef->renderView.vieworg[1]; - parm[2] = backEnd.viewDef->renderView.vieworg[2]; - parm[3] = 1.0; - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 1, parm ); + qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, parm ); + + // window coord to 0.0 to 1.0 conversion + parm[0] = 1.0 / w; + parm[1] = 1.0 / h; + parm[2] = 0; + parm[3] = 1; + qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 1, parm ); + + // DG: brightness and gamma in shader as program.env[4] + if ( r_gammaInShader.GetBool() ) { + // program.env[4].xyz are all r_brightness, program.env[4].w is 1.0/r_gamma + if ( !isPostProcess ) { + parm[0] = parm[1] = parm[2] = r_brightness.GetFloat(); + parm[3] = 1.0f / r_gamma.GetFloat(); // 1.0f / gamma so the shader doesn't have to do this calculation + } else { + // don't apply gamma/brightness in postprocess passes to avoid applying them twice + // (setting them to 1.0 makes them no-ops) + parm[0] = parm[1] = parm[2] = parm[3] = 1.0f; + } + qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_GAMMA_BRIGHTNESS, parm ); + } + + // #3877: Allow shaders to access depth buffer. + // Two useful ratios are packed into this parm: [0] and [1] hold the x,y multipliers you need to map a screen + // coordinate (fragment position) to the depth image: those are simply the reciprocal of the depth + // image size, which has been rounded up to a power of two. Slots [3] and [4] hold the ratio of the depth image + // size to the current render image size. These sizes can differ if the game crops the render viewport temporarily + // during post-processing effects. The depth render is smaller during the effect too, but the depth image doesn't + // need to be downsized, whereas the current render image does get downsized when it's captured by the game after + // the skybox render pass. The ratio is needed to map between the two render images. + parm[0] = 1.0f / globalImages->currentDepthImage->uploadWidth; + parm[1] = 1.0f / globalImages->currentDepthImage->uploadHeight; + parm[2] = static_cast( globalImages->currentRenderImage->uploadWidth ) / globalImages->currentDepthImage->uploadWidth; + parm[3] = static_cast( globalImages->currentRenderImage->uploadHeight ) / globalImages->currentDepthImage->uploadHeight; + qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_CURDEPTH_RECIPR, parm ); + + // + // set eye position in global space + // + parm[0] = backEnd.viewDef->renderView.vieworg[0]; + parm[1] = backEnd.viewDef->renderView.vieworg[1]; + parm[2] = backEnd.viewDef->renderView.vieworg[2]; + parm[3] = 1.0; + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 1, parm ); } /* @@ -709,35 +706,36 @@ Sets variables related to the current space that can be used by all vertex progr ================== */ void RB_SetProgramEnvironmentSpace( void ) { - if ( !glConfig.ARBVertexProgramAvailable ) { - return; - } - - const struct viewEntity_s *space = backEnd.currentSpace; - float parm[4]; - - // set eye position in local space - R_GlobalPointToLocal( space->modelMatrix, backEnd.viewDef->renderView.vieworg, *(idVec3 *)parm ); - parm[3] = 1.0; - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 5, parm ); - - // we need the model matrix without it being combined with the view matrix - // so we can transform local vectors to global coordinates - parm[0] = space->modelMatrix[0]; - parm[1] = space->modelMatrix[4]; - parm[2] = space->modelMatrix[8]; - parm[3] = space->modelMatrix[12]; - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 6, parm ); - parm[0] = space->modelMatrix[1]; - parm[1] = space->modelMatrix[5]; - parm[2] = space->modelMatrix[9]; - parm[3] = space->modelMatrix[13]; - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 7, parm ); - parm[0] = space->modelMatrix[2]; - parm[1] = space->modelMatrix[6]; - parm[2] = space->modelMatrix[10]; - parm[3] = space->modelMatrix[14]; - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 8, parm ); + if ( !glConfig.ARBVertexProgramAvailable ) { + return; + } + const struct viewEntity_s *space = backEnd.currentSpace; + float parm[4]; + + // set eye position in local space + R_GlobalPointToLocal( space->modelMatrix, backEnd.viewDef->renderView.vieworg, *( idVec3 * )parm ); + parm[3] = 1.0; + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 5, parm ); + + // we need the model matrix without it being combined with the view matrix + // so we can transform local vectors to global coordinates + parm[0] = space->modelMatrix[0]; + parm[1] = space->modelMatrix[4]; + parm[2] = space->modelMatrix[8]; + parm[3] = space->modelMatrix[12]; + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 6, parm ); + + parm[0] = space->modelMatrix[1]; + parm[1] = space->modelMatrix[5]; + parm[2] = space->modelMatrix[9]; + parm[3] = space->modelMatrix[13]; + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 7, parm ); + + parm[0] = space->modelMatrix[2]; + parm[1] = space->modelMatrix[6]; + parm[2] = space->modelMatrix[10]; + parm[3] = space->modelMatrix[14]; + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 8, parm ); } /* @@ -748,457 +746,445 @@ This is also called for the generated 2D rendering ================== */ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) { - int stage; - const idMaterial *shader; - const shaderStage_t *pStage; - const float *regs; - float color[4]; - const srfTriangles_t *tri; - - tri = surf->geo; - shader = surf->material; - - if ( !shader->HasAmbient() ) { - return; - } - - if ( shader->IsPortalSky() ) { - return; - } - - // change the matrix if needed - if ( surf->space != backEnd.currentSpace ) { - qglLoadMatrixf( surf->space->modelViewMatrix ); - backEnd.currentSpace = surf->space; - RB_SetProgramEnvironmentSpace(); - } - - // change the scissor if needed - if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( surf->scissorRect ) ) { - backEnd.currentScissor = surf->scissorRect; - qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, - backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, - backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, - backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); - } - - // some deforms may disable themselves by setting numIndexes = 0 - if ( !tri->numIndexes ) { - return; - } - - if ( !tri->ambientCache ) { - common->Printf( "RB_T_RenderShaderPasses: !tri->ambientCache\n" ); - return; - } - - // check whether we're drawing a soft particle surface #3878 - const bool soft_particle = ( surf->dsFlags & DSF_SOFT_PARTICLE ) != 0; - - // get the expressions for conditionals / color / texcoords - regs = surf->shaderRegisters; - - // set face culling appropriately - GL_Cull( shader->GetCullType() ); - - // set polygon offset if necessary - if ( shader->TestMaterialFlag(MF_POLYGONOFFSET) ) { - qglEnable( GL_POLYGON_OFFSET_FILL ); - qglPolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); - } - - if ( surf->space->weaponDepthHack ) { - RB_EnterWeaponDepthHack(); - } - - if ( surf->space->modelDepthHack != 0.0f && !soft_particle ) // #3878 soft particles don't want modelDepthHack, which is - { // an older way to slightly "soften" particles - RB_EnterModelDepthHack( surf->space->modelDepthHack ); - } - - idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache ); - qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); - qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), reinterpret_cast(&ac->st) ); - - for ( stage = 0; stage < shader->GetNumStages() ; stage++ ) { - pStage = shader->GetStage(stage); - - // check the enable condition - if ( regs[ pStage->conditionRegister ] == 0 ) { - continue; - } - - // skip the stages involved in lighting - if ( pStage->lighting != SL_AMBIENT ) { - continue; - } - - // skip if the stage is ( GL_ZERO, GL_ONE ), which is used for some alpha masks - if ( ( pStage->drawStateBits & (GLS_SRCBLEND_BITS|GLS_DSTBLEND_BITS) ) == ( GLS_SRCBLEND_ZERO | GLS_DSTBLEND_ONE ) ) { - continue; - } - - // determine the blend mode (used by soft particles #3878) - const int src_blend = pStage->drawStateBits & GLS_SRCBLEND_BITS; - - // see if we are a new-style stage - newShaderStage_t *newStage = pStage->newStage; - if ( newStage ) { - //-------------------------- - // - // new style stages - // - //-------------------------- - - // completely skip the stage if we don't have the capability - if ( tr.backEndRenderer != BE_ARB2 ) { - continue; - } - if ( r_skipNewAmbient.GetBool() ) { - continue; - } - qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), (void *)&ac->color ); - qglVertexAttribPointerARB( 9, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() ); - qglVertexAttribPointerARB( 10, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() ); - qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); - - qglEnableClientState( GL_COLOR_ARRAY ); - qglEnableVertexAttribArrayARB( 9 ); - qglEnableVertexAttribArrayARB( 10 ); - qglEnableClientState( GL_NORMAL_ARRAY ); - - GL_State( pStage->drawStateBits ); - - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, newStage->vertexProgram ); - qglEnable( GL_VERTEX_PROGRAM_ARB ); - - // megaTextures bind a lot of images and set a lot of parameters - if ( newStage->megaTexture ) { - newStage->megaTexture->SetMappingForSurface( tri ); - idVec3 localViewer; - R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.viewDef->renderView.vieworg, localViewer ); - newStage->megaTexture->BindForViewOrigin( localViewer ); - } - - for ( int i = 0 ; i < newStage->numVertexParms ; i++ ) { - float parm[4]; - parm[0] = regs[ newStage->vertexParms[i][0] ]; - parm[1] = regs[ newStage->vertexParms[i][1] ]; - parm[2] = regs[ newStage->vertexParms[i][2] ]; - parm[3] = regs[ newStage->vertexParms[i][3] ]; - qglProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, i, parm ); - } - - for ( int i = 0 ; i < newStage->numFragmentProgramImages ; i++ ) { - if ( newStage->fragmentProgramImages[i] ) { - GL_SelectTexture( i ); - newStage->fragmentProgramImages[i]->Bind(); - } - } - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, newStage->fragmentProgram ); - qglEnable( GL_FRAGMENT_PROGRAM_ARB ); - - // draw it - RB_DrawElementsWithCounters( tri ); - - for ( int i = 1 ; i < newStage->numFragmentProgramImages ; i++ ) { - if ( newStage->fragmentProgramImages[i] ) { - GL_SelectTexture( i ); - globalImages->BindNull(); - } - } - if ( newStage->megaTexture ) { - newStage->megaTexture->Unbind(); - } - - GL_SelectTexture( 0 ); - - qglDisable( GL_VERTEX_PROGRAM_ARB ); - qglDisable( GL_FRAGMENT_PROGRAM_ARB ); - // Fixme: Hack to get around an apparent bug in ATI drivers. Should remove as soon as it gets fixed. - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, 0 ); // FIXME: ... - - qglDisableClientState( GL_COLOR_ARRAY ); - qglDisableVertexAttribArrayARB( 9 ); - qglDisableVertexAttribArrayARB( 10 ); - qglDisableClientState( GL_NORMAL_ARRAY ); - continue; - } - else if ( soft_particle - && surf->particle_radius > 0.0f - && ( src_blend == GLS_SRCBLEND_ONE || src_blend == GLS_SRCBLEND_SRC_ALPHA ) - && tr.backEndRenderer == BE_ARB2 - && !r_skipNewAmbient.GetBool() ) - { - // SteveL #3878. Particles are automatically softened by the engine, unless they have shader programs of - // their own (i.e. are "newstages" handled above). This section comes after the newstage part so that if a - // designer has specified their own shader programs, those will be used instead of the soft particle program. - if ( pStage->vertexColor == SVC_IGNORE ) - { - // Ignoring vertexColor is not recommended for particles. The particle system uses vertexColor for fading. - // However, there are existing particle effects that don't use it, in which case we default to using the - // rgb color modulation specified in the material like the "old stages" do below. - color[0] = regs[pStage->color.registers[0]]; - color[1] = regs[pStage->color.registers[1]]; - color[2] = regs[pStage->color.registers[2]]; - color[3] = regs[pStage->color.registers[3]]; - qglColor4fv( color ); - } - else - { - // A properly set-up particle shader - qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), (void *)&ac->color ); - qglEnableClientState( GL_COLOR_ARRAY ); - } + int stage; + const idMaterial *shader; + const shaderStage_t *pStage; + const float *regs; + float color[4]; + const srfTriangles_t *tri; + + tri = surf->geo; + shader = surf->material; + + if ( !shader->HasAmbient() ) { + return; + } + + if ( shader->IsPortalSky() ) { + return; + } + + // change the matrix if needed + if ( surf->space != backEnd.currentSpace ) { + qglLoadMatrixf( surf->space->modelViewMatrix ); + backEnd.currentSpace = surf->space; + RB_SetProgramEnvironmentSpace(); + } + + // change the scissor if needed + if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( surf->scissorRect ) ) { + backEnd.currentScissor = surf->scissorRect; + qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, + backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, + backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, + backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); + } + + // some deforms may disable themselves by setting numIndexes = 0 + if ( !tri->numIndexes ) { + return; + } + + if ( !tri->ambientCache ) { + common->Printf( "RB_T_RenderShaderPasses: !tri->ambientCache\n" ); + return; + } + + // check whether we're drawing a soft particle surface #3878 + const bool soft_particle = ( surf->dsFlags & DSF_SOFT_PARTICLE ) != 0; + + // get the expressions for conditionals / color / texcoords + regs = surf->shaderRegisters; + + // set face culling appropriately + GL_Cull( shader->GetCullType() ); + + // set polygon offset if necessary + if ( shader->TestMaterialFlag( MF_POLYGONOFFSET ) ) { + qglEnable( GL_POLYGON_OFFSET_FILL ); + qglPolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); + } + + if ( surf->space->weaponDepthHack ) { + RB_EnterWeaponDepthHack(); + } + + if ( surf->space->modelDepthHack != 0.0f && !soft_particle ) { // #3878 soft particles don't want modelDepthHack, which is + // an older way to slightly "soften" particles + RB_EnterModelDepthHack( surf->space->modelDepthHack ); + } + idDrawVert *ac = ( idDrawVert * )vertexCache.Position( tri->ambientCache ); + qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); + qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), reinterpret_cast( &ac->st ) ); + + for ( stage = 0; stage < shader->GetNumStages() ; stage++ ) { + pStage = shader->GetStage( stage ); + + // check the enable condition + if ( regs[ pStage->conditionRegister ] == 0 ) { + continue; + } + + // skip the stages involved in lighting + if ( pStage->lighting != SL_AMBIENT ) { + continue; + } + + // skip if the stage is ( GL_ZERO, GL_ONE ), which is used for some alpha masks + if ( ( pStage->drawStateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) == ( GLS_SRCBLEND_ZERO | GLS_DSTBLEND_ONE ) ) { + continue; + } + + // determine the blend mode (used by soft particles #3878) + const int src_blend = pStage->drawStateBits & GLS_SRCBLEND_BITS; + + // see if we are a new-style stage + newShaderStage_t *newStage = pStage->newStage; + if ( newStage ) { + //-------------------------- + // + // new style stages + // + //-------------------------- + + // completely skip the stage if we don't have the capability + if ( tr.backEndRenderer != BE_ARB2 ) { + continue; + } + + if ( r_skipNewAmbient.GetBool() ) { + continue; + } + qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), ( void * )&ac->color ); + qglVertexAttribPointerARB( 9, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() ); + qglVertexAttribPointerARB( 10, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() ); + qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); + + qglEnableClientState( GL_COLOR_ARRAY ); + qglEnableVertexAttribArrayARB( 9 ); + qglEnableVertexAttribArrayARB( 10 ); + qglEnableClientState( GL_NORMAL_ARRAY ); + + GL_State( pStage->drawStateBits ); + + qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, newStage->vertexProgram ); + qglEnable( GL_VERTEX_PROGRAM_ARB ); + + // megaTextures bind a lot of images and set a lot of parameters + if ( newStage->megaTexture ) { + newStage->megaTexture->SetMappingForSurface( tri ); + idVec3 localViewer; + R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.viewDef->renderView.vieworg, localViewer ); + newStage->megaTexture->BindForViewOrigin( localViewer ); + } + + for ( int i = 0 ; i < newStage->numVertexParms ; i++ ) { + float parm[4]; + parm[0] = regs[ newStage->vertexParms[i][0] ]; + parm[1] = regs[ newStage->vertexParms[i][1] ]; + parm[2] = regs[ newStage->vertexParms[i][2] ]; + parm[3] = regs[ newStage->vertexParms[i][3] ]; + qglProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, i, parm ); + } + + for ( int i = 0 ; i < newStage->numFragmentProgramImages ; i++ ) { + if ( newStage->fragmentProgramImages[i] ) { + GL_SelectTexture( i ); + newStage->fragmentProgramImages[i]->Bind(); + } + } + qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, newStage->fragmentProgram ); + qglEnable( GL_FRAGMENT_PROGRAM_ARB ); + + // draw it + RB_DrawElementsWithCounters( tri ); + + for ( int i = 1 ; i < newStage->numFragmentProgramImages ; i++ ) { + if ( newStage->fragmentProgramImages[i] ) { + GL_SelectTexture( i ); + globalImages->BindNull(); + } + } + + if ( newStage->megaTexture ) { + newStage->megaTexture->Unbind(); + } + GL_SelectTexture( 0 ); + + qglDisable( GL_VERTEX_PROGRAM_ARB ); + qglDisable( GL_FRAGMENT_PROGRAM_ARB ); + + // Fixme: Hack to get around an apparent bug in ATI drivers. Should remove as soon as it gets fixed. + qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, 0 ); // FIXME: ... + + qglDisableClientState( GL_COLOR_ARRAY ); + qglDisableVertexAttribArrayARB( 9 ); + qglDisableVertexAttribArrayARB( 10 ); + qglDisableClientState( GL_NORMAL_ARRAY ); + continue; + } else if ( soft_particle && + ( surf->particle_radius > 0.0f ) && + ( src_blend == GLS_SRCBLEND_ONE || src_blend == GLS_SRCBLEND_SRC_ALPHA ) && + ( tr.backEndRenderer == BE_ARB2 ) && + !r_skipNewAmbient.GetBool() ) { + // SteveL #3878. Particles are automatically softened by the engine, unless they have shader programs of + // their own (i.e. are "newstages" handled above). This section comes after the newstage part so that if a + // designer has specified their own shader programs, those will be used instead of the soft particle program. + if ( pStage->vertexColor == SVC_IGNORE ) { + // Ignoring vertexColor is not recommended for particles. The particle system uses vertexColor for fading. + // However, there are existing particle effects that don't use it, in which case we default to using the + // rgb color modulation specified in the material like the "old stages" do below. + color[0] = regs[pStage->color.registers[0]]; + color[1] = regs[pStage->color.registers[1]]; + color[2] = regs[pStage->color.registers[2]]; + color[3] = regs[pStage->color.registers[3]]; + qglColor4fv( color ); + } else { + // A properly set-up particle shader + qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), ( void * )&ac->color ); + qglEnableClientState( GL_COLOR_ARRAY ); + } #if 0 // debug stuff: render particles opaque so debug colors written in the shader are properly visible - int dsbits = pStage->drawStateBits | GLS_DEPTHFUNC_ALWAYS; - dsbits &= ~(GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS); - //dsbits |= GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO; both values are 0, so this would be a noop - GL_State( dsbits ); + int dsbits = pStage->drawStateBits | GLS_DEPTHFUNC_ALWAYS; + dsbits &= ~( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ); + //dsbits |= GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO; both values are 0, so this would be a noop + GL_State( dsbits ); #endif - GL_State( pStage->drawStateBits | GLS_DEPTHFUNC_ALWAYS ); // Disable depth clipping. The fragment program will - // handle it to allow overdraw. + GL_State( pStage->drawStateBits | GLS_DEPTHFUNC_ALWAYS ); // Disable depth clipping. The fragment program will + // handle it to allow overdraw. - qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_SOFT_PARTICLE ); - qglEnable( GL_VERTEX_PROGRAM_ARB ); + qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_SOFT_PARTICLE ); + qglEnable( GL_VERTEX_PROGRAM_ARB ); - // Bind image and _currentDepth - GL_SelectTexture( 0 ); - pStage->texture.image->Bind(); - GL_SelectTexture( 1 ); - globalImages->currentDepthImage->Bind(); + // Bind image and _currentDepth + GL_SelectTexture( 0 ); + pStage->texture.image->Bind(); + GL_SelectTexture( 1 ); + globalImages->currentDepthImage->Bind(); - qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_SOFT_PARTICLE ); - qglEnable( GL_FRAGMENT_PROGRAM_ARB ); + qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_SOFT_PARTICLE ); + qglEnable( GL_FRAGMENT_PROGRAM_ARB ); #if 0 // debug stuff - // Set up parameters for fragment program - const char* srcblendstr = "???"; - if ( src_blend >= 0 && src_blend <= 9 ) { - const char* blendModes[] = { - "ONE", - "ZERO", - "!! INVALID !!", - "DST_COLOR", - "ONE_MINUS_DST_COLOR", - "SRC_ALPHA", - "ONE_MINUS_SRC_ALPHA", - "DST_ALPHA", - "ONE_MINUS_DST_ALPHA", - "ALPHA_SATURATE" - }; - srcblendstr = blendModes[src_blend]; - } - - - int dst_blend = pStage->drawStateBits & GLS_DSTBLEND_BITS; - const char* dstblend = "???"; - switch ( dst_blend ) { + // Set up parameters for fragment program + const char *srcblendstr = "???"; + if ( src_blend >= 0 && src_blend <= 9 ) { + const char *blendModes[] = { + "ONE", + "ZERO", + "!! INVALID !!", + "DST_COLOR", + "ONE_MINUS_DST_COLOR", + "SRC_ALPHA", + "ONE_MINUS_SRC_ALPHA", + "DST_ALPHA", + "ONE_MINUS_DST_ALPHA", + "ALPHA_SATURATE" + }; + srcblendstr = blendModes[src_blend]; + } + int dst_blend = pStage->drawStateBits & GLS_DSTBLEND_BITS; + const char *dstblend = "???"; + + switch ( dst_blend ) { #define MY_CASE(X) case GLS_DSTBLEND_ ##X : dstblend = #X; break; - MY_CASE(ZERO) - MY_CASE(ONE) - MY_CASE(SRC_COLOR) - MY_CASE(ONE_MINUS_SRC_COLOR) - MY_CASE(SRC_ALPHA) - MY_CASE(ONE_MINUS_SRC_ALPHA) - MY_CASE(DST_ALPHA) - MY_CASE(ONE_MINUS_DST_ALPHA) + MY_CASE( ZERO ) + MY_CASE( ONE ) + MY_CASE( SRC_COLOR ) + MY_CASE( ONE_MINUS_SRC_COLOR ) + MY_CASE( SRC_ALPHA ) + MY_CASE( ONE_MINUS_SRC_ALPHA ) + MY_CASE( DST_ALPHA ) + MY_CASE( ONE_MINUS_DST_ALPHA ) #undef MY_CASE - } - - printf("XX mat: %s, src_blend = %s dest_blend = %s radius = %g\n", shader->GetName(), srcblendstr, dstblend, surf->particle_radius); + } + printf( "XX mat: %s, src_blend = %s dest_blend = %s radius = %g\n", shader->GetName(), srcblendstr, dstblend, surf->particle_radius ); #endif - // DG: some particle materials (at least the muzzle flash in dentonmod) set the - // texture matrix (with scroll, translate, scale, centerScale, shear or rotate). - // Support that like in R_SetDrawInteraction() (the soft particle shader only - // uses one texture, so I set the diffuse matrix for it) - idVec4 texMatrix[2]; - if ( pStage->texture.hasMatrix ) { - texMatrix[0][0] = regs[pStage->texture.matrix[0][0]]; - texMatrix[0][1] = regs[pStage->texture.matrix[0][1]]; - texMatrix[0][2] = 0; - texMatrix[0][3] = regs[pStage->texture.matrix[0][2]]; - - texMatrix[1][0] = regs[pStage->texture.matrix[1][0]]; - texMatrix[1][1] = regs[pStage->texture.matrix[1][1]]; - texMatrix[1][2] = 0; - texMatrix[1][3] = regs[pStage->texture.matrix[1][2]]; - - // we attempt to keep scrolls from generating incredibly large texture values, but - // center rotations and center scales can still generate offsets that need to be > 1 - if ( texMatrix[0][3] < -40 || texMatrix[0][3] > 40 ) { - texMatrix[0][3] -= (int)texMatrix[0][3]; - } - if ( texMatrix[1][3] < -40 || texMatrix[1][3] > 40 ) { - texMatrix[1][3] -= (int)texMatrix[1][3]; - } - } else { - texMatrix[0].Set( 1, 0, 0, 0 ); - texMatrix[1].Set( 0, 1, 0, 0 ); - } - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_S, texMatrix[0].ToFloatPtr() ); - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_T, texMatrix[1].ToFloatPtr() ); - - // program.env[23] is the particle radius, given as { radius, 1/(faderange), 1/radius } - float fadeRange = 1.0f; - // fadeRange is the particle diameter for alpha blends (like smoke), but the particle radius for additive - // blends (light glares), because additive effects work differently. Fog is half as apparent when a wall - // is in the middle of it. Light glares lose no visibility when they have something to reflect off. See - // The Dark Mod issue #3878 for diagram - if ( src_blend == GLS_SRCBLEND_SRC_ALPHA ) // an alpha blend material - { - fadeRange = surf->particle_radius * 2.0f; - } - else if ( src_blend == GLS_SRCBLEND_ONE ) // an additive (blend add) material - { - fadeRange = surf->particle_radius; - } - - float parm[4] = { - surf->particle_radius, - 1.0f / ( fadeRange ), - 1.0f / surf->particle_radius, - 0.0f - }; - qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_PARTICLE_RADIUS, parm ); - - // program.env[24] is the color channel mask. It gets added to the fade multiplier, so adding 1 - // to a channel will make sure it doesn't get faded at all. Particles with additive blend - // need their RGB channels modifying to blend them out. Particles with an alpha blend need - // their alpha channel modifying. - if ( src_blend == GLS_SRCBLEND_SRC_ALPHA ) // an alpha blend material - { - parm[0] = parm[1] = parm[2] = 1.0f; // Leave the rgb channels at full strength when fading - parm[3] = 0.0f; // but fade the alpha channel - } - else if ( src_blend == GLS_SRCBLEND_ONE ) // an additive (blend add) material - { - parm[0] = parm[1] = parm[2] = 0.0f; // Fade the rgb channels but - parm[3] = 1.0f; // leave the alpha channel at full strength - } - qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_PARTICLE_COLCHAN_MASK, parm ); - - // draw it - RB_DrawElementsWithCounters( tri ); - - // Clean up GL state - GL_SelectTexture( 1 ); - globalImages->BindNull(); - GL_SelectTexture( 0 ); - globalImages->BindNull(); - - qglDisable( GL_VERTEX_PROGRAM_ARB ); - qglDisable( GL_FRAGMENT_PROGRAM_ARB ); - - if ( pStage->vertexColor != SVC_IGNORE ) { - qglDisableClientState( GL_COLOR_ARRAY ); - } - continue; - } - - //-------------------------- - // - // old style stages - // - //-------------------------- - - // set the color - color[0] = regs[ pStage->color.registers[0] ]; - color[1] = regs[ pStage->color.registers[1] ]; - color[2] = regs[ pStage->color.registers[2] ]; - color[3] = regs[ pStage->color.registers[3] ]; - - // skip the entire stage if an add would be black - if ( ( pStage->drawStateBits & (GLS_SRCBLEND_BITS|GLS_DSTBLEND_BITS) ) == ( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ) - && color[0] <= 0 && color[1] <= 0 && color[2] <= 0 ) { - continue; - } - - // skip the entire stage if a blend would be completely transparent - if ( ( pStage->drawStateBits & (GLS_SRCBLEND_BITS|GLS_DSTBLEND_BITS) ) == ( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) - && color[3] <= 0 ) { - continue; - } - - // select the vertex color source - if ( pStage->vertexColor == SVC_IGNORE ) { - qglColor4fv( color ); - } else { - qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), (void *)&ac->color ); - qglEnableClientState( GL_COLOR_ARRAY ); - - if ( pStage->vertexColor == SVC_INVERSE_MODULATE ) { - GL_TexEnv( GL_COMBINE_ARB ); - qglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE ); - qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE ); - qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB ); - qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR ); - qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_ONE_MINUS_SRC_COLOR ); - qglTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1 ); - } - - // for vertex color and modulated color, we need to enable a second - // texture stage - if ( color[0] != 1 || color[1] != 1 || color[2] != 1 || color[3] != 1 ) { - GL_SelectTexture( 1 ); - - globalImages->whiteImage->Bind(); - GL_TexEnv( GL_COMBINE_ARB ); - - qglTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color ); - - qglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE ); - qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB ); - qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT_ARB ); - qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR ); - qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR ); - qglTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1 ); - - qglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE ); - qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB ); - qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_CONSTANT_ARB ); - qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA ); - qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA ); - qglTexEnvi( GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1 ); - - GL_SelectTexture( 0 ); - } - } - - // bind the texture - RB_BindVariableStageImage( &pStage->texture, regs ); - - // set the state - GL_State( pStage->drawStateBits ); - - RB_PrepareStageTexturing( pStage, surf, ac ); - - // draw it - RB_DrawElementsWithCounters( tri ); - - RB_FinishStageTexturing( pStage, surf, ac ); - - if ( pStage->vertexColor != SVC_IGNORE ) { - qglDisableClientState( GL_COLOR_ARRAY ); - - GL_SelectTexture( 1 ); - GL_TexEnv( GL_MODULATE ); - globalImages->BindNull(); - GL_SelectTexture( 0 ); - GL_TexEnv( GL_MODULATE ); - } - } - - // reset polygon offset - if ( shader->TestMaterialFlag(MF_POLYGONOFFSET) ) { - qglDisable( GL_POLYGON_OFFSET_FILL ); - } - if ( surf->space->weaponDepthHack || ( !soft_particle && surf->space->modelDepthHack != 0.0f ) ) // #3878 soft particles - { - RB_LeaveDepthHack(); - } + // DG: some particle materials (at least the muzzle flash in dentonmod) set the + // texture matrix (with scroll, translate, scale, centerScale, shear or rotate). + // Support that like in R_SetDrawInteraction() (the soft particle shader only + // uses one texture, so I set the diffuse matrix for it) + idVec4 texMatrix[2]; + if ( pStage->texture.hasMatrix ) { + texMatrix[0][0] = regs[pStage->texture.matrix[0][0]]; + texMatrix[0][1] = regs[pStage->texture.matrix[0][1]]; + texMatrix[0][2] = 0; + texMatrix[0][3] = regs[pStage->texture.matrix[0][2]]; + + texMatrix[1][0] = regs[pStage->texture.matrix[1][0]]; + texMatrix[1][1] = regs[pStage->texture.matrix[1][1]]; + texMatrix[1][2] = 0; + texMatrix[1][3] = regs[pStage->texture.matrix[1][2]]; + + // we attempt to keep scrolls from generating incredibly large texture values, but + // center rotations and center scales can still generate offsets that need to be > 1 + if ( texMatrix[0][3] < -40 || texMatrix[0][3] > 40 ) { + texMatrix[0][3] -= ( int )texMatrix[0][3]; + } + + if ( texMatrix[1][3] < -40 || texMatrix[1][3] > 40 ) { + texMatrix[1][3] -= ( int )texMatrix[1][3]; + } + } else { + texMatrix[0].Set( 1, 0, 0, 0 ); + texMatrix[1].Set( 0, 1, 0, 0 ); + } + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_S, texMatrix[0].ToFloatPtr() ); + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_T, texMatrix[1].ToFloatPtr() ); + + // program.env[23] is the particle radius, given as { radius, 1/(faderange), 1/radius } + float fadeRange = 1.0f; + + // fadeRange is the particle diameter for alpha blends (like smoke), but the particle radius for additive + // blends (light glares), because additive effects work differently. Fog is half as apparent when a wall + // is in the middle of it. Light glares lose no visibility when they have something to reflect off. See + // The Dark Mod issue #3878 for diagram + if ( src_blend == GLS_SRCBLEND_SRC_ALPHA ) { // an alpha blend material + fadeRange = surf->particle_radius * 2.0f; + } else if ( src_blend == GLS_SRCBLEND_ONE ) { // an additive (blend add) material + fadeRange = surf->particle_radius; + } + + float parm[4] = { + surf->particle_radius, + 1.0f / ( fadeRange ), + 1.0f / surf->particle_radius, + 0.0f + }; + qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_PARTICLE_RADIUS, parm ); + + // program.env[24] is the color channel mask. It gets added to the fade multiplier, so adding 1 + // to a channel will make sure it doesn't get faded at all. Particles with additive blend + // need their RGB channels modifying to blend them out. Particles with an alpha blend need + // their alpha channel modifying. + if ( src_blend == GLS_SRCBLEND_SRC_ALPHA ) { // an alpha blend material + parm[0] = parm[1] = parm[2] = 1.0f; // Leave the rgb channels at full strength when fading + parm[3] = 0.0f; // but fade the alpha channel + } else if ( src_blend == GLS_SRCBLEND_ONE ) { // an additive (blend add) material + parm[0] = parm[1] = parm[2] = 0.0f; // Fade the rgb channels but + parm[3] = 1.0f; // leave the alpha channel at full strength + } + qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_PARTICLE_COLCHAN_MASK, parm ); + + // draw it + RB_DrawElementsWithCounters( tri ); + + // Clean up GL state + GL_SelectTexture( 1 ); + globalImages->BindNull(); + GL_SelectTexture( 0 ); + globalImages->BindNull(); + + qglDisable( GL_VERTEX_PROGRAM_ARB ); + qglDisable( GL_FRAGMENT_PROGRAM_ARB ); + + if ( pStage->vertexColor != SVC_IGNORE ) { + qglDisableClientState( GL_COLOR_ARRAY ); + } + continue; + } + + //-------------------------- + // + // old style stages + // + //-------------------------- + + // set the color + color[0] = regs[ pStage->color.registers[0] ]; + color[1] = regs[ pStage->color.registers[1] ]; + color[2] = regs[ pStage->color.registers[2] ]; + color[3] = regs[ pStage->color.registers[3] ]; + + // skip the entire stage if an add would be black + if ( ( pStage->drawStateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) == ( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ) && color[0] <= 0 && color[1] <= 0 && color[2] <= 0 ) { + continue; + } + + // skip the entire stage if a blend would be completely transparent + if ( ( pStage->drawStateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) == ( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) && color[3] <= 0 ) { + continue; + } + + // select the vertex color source + if ( pStage->vertexColor == SVC_IGNORE ) { + qglColor4fv( color ); + } else { + qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), ( void * )&ac->color ); + qglEnableClientState( GL_COLOR_ARRAY ); + + if ( pStage->vertexColor == SVC_INVERSE_MODULATE ) { + GL_TexEnv( GL_COMBINE_ARB ); + qglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE ); + qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE ); + qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB ); + qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR ); + qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_ONE_MINUS_SRC_COLOR ); + qglTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1 ); + } + + // for vertex color and modulated color, we need to enable a second + // texture stage + if ( color[0] != 1 || color[1] != 1 || color[2] != 1 || color[3] != 1 ) { + GL_SelectTexture( 1 ); + + globalImages->whiteImage->Bind(); + GL_TexEnv( GL_COMBINE_ARB ); + + qglTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color ); + + qglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE ); + qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB ); + qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT_ARB ); + qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR ); + qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR ); + qglTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1 ); + + qglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE ); + qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB ); + qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_CONSTANT_ARB ); + qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA ); + qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA ); + qglTexEnvi( GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1 ); + + GL_SelectTexture( 0 ); + } + } + + // bind the texture + RB_BindVariableStageImage( &pStage->texture, regs ); + + // set the state + GL_State( pStage->drawStateBits ); + + RB_PrepareStageTexturing( pStage, surf, ac ); + + // draw it + RB_DrawElementsWithCounters( tri ); + + RB_FinishStageTexturing( pStage, surf, ac ); + + if ( pStage->vertexColor != SVC_IGNORE ) { + qglDisableClientState( GL_COLOR_ARRAY ); + + GL_SelectTexture( 1 ); + GL_TexEnv( GL_MODULATE ); + globalImages->BindNull(); + GL_SelectTexture( 0 ); + GL_TexEnv( GL_MODULATE ); + } + } + + // reset polygon offset + if ( shader->TestMaterialFlag( MF_POLYGONOFFSET ) ) { + qglDisable( GL_POLYGON_OFFSET_FILL ); + } + + if ( surf->space->weaponDepthHack || ( !soft_particle && surf->space->modelDepthHack != 0.0f ) ) { // #3878 soft particles + RB_LeaveDepthHack(); + } } /* @@ -1209,72 +1195,67 @@ Draw non-light dependent passes ===================== */ int RB_STD_DrawShaderPasses( drawSurf_t **drawSurfs, int numDrawSurfs ) { - int i; - - // only obey skipAmbient if we are rendering a view - if ( backEnd.viewDef->viewEntitys && r_skipAmbient.GetBool() ) { - return numDrawSurfs; - } - - bool isPostProcess = false; - - // if we are about to draw the first surface that needs - // the rendering in a texture, copy it over - if ( drawSurfs[0]->material->GetSort() >= SS_POST_PROCESS ) { - if ( r_skipPostProcess.GetBool() ) { - return 0; - } - isPostProcess = true; - - // only dump if in a 3d view - if ( backEnd.viewDef->viewEntitys && tr.backEndRenderer == BE_ARB2 ) { - globalImages->currentRenderImage->CopyFramebuffer( backEnd.viewDef->viewport.x1, - backEnd.viewDef->viewport.y1, backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1, - backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1, true ); - } - backEnd.currentRenderCopied = true; - } - - GL_SelectTexture( 1 ); - globalImages->BindNull(); - - GL_SelectTexture( 0 ); - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - - RB_SetProgramEnvironment( isPostProcess ); - - // we don't use RB_RenderDrawSurfListWithFunction() - // because we want to defer the matrix load because many - // surfaces won't draw any ambient passes - backEnd.currentSpace = NULL; - for (i = 0 ; i < numDrawSurfs ; i++ ) { - if ( drawSurfs[i]->material->SuppressInSubview() ) { - continue; - } - - if ( backEnd.viewDef->isXraySubview && drawSurfs[i]->space->entityDef ) { - if ( drawSurfs[i]->space->entityDef->parms.xrayIndex != 2 ) { - continue; - } - } - - // we need to draw the post process shaders after we have drawn the fog lights - if ( drawSurfs[i]->material->GetSort() >= SS_POST_PROCESS - && !backEnd.currentRenderCopied ) { - break; - } - - RB_STD_T_RenderShaderPasses( drawSurfs[i] ); - } - - GL_Cull( CT_FRONT_SIDED ); - qglColor3f( 1, 1, 1 ); - - return i; + int i; + + // only obey skipAmbient if we are rendering a view + if ( backEnd.viewDef->viewEntitys && r_skipAmbient.GetBool() ) { + return numDrawSurfs; + } + bool isPostProcess = false; + + // if we are about to draw the first surface that needs + // the rendering in a texture, copy it over + if ( drawSurfs[0]->material->GetSort() >= SS_POST_PROCESS ) { + if ( r_skipPostProcess.GetBool() ) { + return 0; + } + isPostProcess = true; + + // only dump if in a 3d view + if ( backEnd.viewDef->viewEntitys && tr.backEndRenderer == BE_ARB2 ) { + globalImages->currentRenderImage->CopyFramebuffer( backEnd.viewDef->viewport.x1, + backEnd.viewDef->viewport.y1, + backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1, + backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1, true ); + } + backEnd.currentRenderCopied = true; + } + GL_SelectTexture( 1 ); + globalImages->BindNull(); + + GL_SelectTexture( 0 ); + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + + RB_SetProgramEnvironment( isPostProcess ); + + // we don't use RB_RenderDrawSurfListWithFunction() + // because we want to defer the matrix load because many + // surfaces won't draw any ambient passes + backEnd.currentSpace = NULL; + + for ( i = 0 ; i < numDrawSurfs ; i++ ) { + if ( drawSurfs[i]->material->SuppressInSubview() ) { + continue; + } + + if ( backEnd.viewDef->isXraySubview && drawSurfs[i]->space->entityDef ) { + if ( drawSurfs[i]->space->entityDef->parms.xrayIndex != 2 ) { + continue; + } + } + + // we need to draw the post process shaders after we have drawn the fog lights + if ( drawSurfs[i]->material->GetSort() >= SS_POST_PROCESS && !backEnd.currentRenderCopied ) { + break; + } + RB_STD_T_RenderShaderPasses( drawSurfs[i] ); + } + GL_Cull( CT_FRONT_SIDED ); + qglColor3f( 1, 1, 1 ); + + return i; } - - /* ============================================================================== @@ -1291,180 +1272,173 @@ the shadow volumes face INSIDE ===================== */ static void RB_T_Shadow( const drawSurf_t *surf ) { - const srfTriangles_t *tri; - - // set the light position if we are using a vertex program to project the rear surfaces - if ( tr.backEndRendererHasVertexPrograms && r_useShadowVertexProgram.GetBool() - && surf->space != backEnd.currentSpace ) { - idVec4 localLight; - - R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.vLight->globalLightOrigin, localLight.ToVec3() ); - localLight.w = 0.0f; - qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_ORIGIN, localLight.ToFloatPtr() ); - } - - tri = surf->geo; - - if ( !tri->shadowCache ) { - return; - } - - qglVertexPointer( 4, GL_FLOAT, sizeof( shadowCache_t ), vertexCache.Position(tri->shadowCache) ); - - // we always draw the sil planes, but we may not need to draw the front or rear caps - int numIndexes; - bool external = false; - - if ( !r_useExternalShadows.GetInteger() ) { - numIndexes = tri->numIndexes; - } else if ( r_useExternalShadows.GetInteger() == 2 ) { // force to no caps for testing - numIndexes = tri->numShadowIndexesNoCaps; - } else if ( !(surf->dsFlags & DSF_VIEW_INSIDE_SHADOW) ) { - // if we aren't inside the shadow projection, no caps are ever needed needed - numIndexes = tri->numShadowIndexesNoCaps; - external = true; - } else if ( !backEnd.vLight->viewInsideLight && !(surf->geo->shadowCapPlaneBits & SHADOW_CAP_INFINITE) ) { - // if we are inside the shadow projection, but outside the light, and drawing - // a non-infinite shadow, we can skip some caps - if ( backEnd.vLight->viewSeesShadowPlaneBits & surf->geo->shadowCapPlaneBits ) { - // we can see through a rear cap, so we need to draw it, but we can skip the - // caps on the actual surface - numIndexes = tri->numShadowIndexesNoFrontCaps; - } else { - // we don't need to draw any caps - numIndexes = tri->numShadowIndexesNoCaps; - } - external = true; - } else { - // must draw everything - numIndexes = tri->numIndexes; - } - - // set depth bounds - if( glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool() ) { - qglDepthBoundsEXT( surf->scissorRect.zmin, surf->scissorRect.zmax ); - } - - // debug visualization - if ( r_showShadows.GetInteger() ) { - if ( r_showShadows.GetInteger() == 3 ) { - if ( external ) { - qglColor3f( 0.1/backEnd.overBright, 1/backEnd.overBright, 0.1/backEnd.overBright ); - } else { - // these are the surfaces that require the reverse - qglColor3f( 1/backEnd.overBright, 0.1/backEnd.overBright, 0.1/backEnd.overBright ); - } - } else { - // draw different color for turboshadows - if ( surf->geo->shadowCapPlaneBits & SHADOW_CAP_INFINITE ) { - if ( numIndexes == tri->numIndexes ) { - qglColor3f( 1/backEnd.overBright, 0.1/backEnd.overBright, 0.1/backEnd.overBright ); - } else { - qglColor3f( 1/backEnd.overBright, 0.4/backEnd.overBright, 0.1/backEnd.overBright ); - } - } else { - if ( numIndexes == tri->numIndexes ) { - qglColor3f( 0.1/backEnd.overBright, 1/backEnd.overBright, 0.1/backEnd.overBright ); - } else if ( numIndexes == tri->numShadowIndexesNoFrontCaps ) { - qglColor3f( 0.1/backEnd.overBright, 1/backEnd.overBright, 0.6/backEnd.overBright ); - } else { - qglColor3f( 0.6/backEnd.overBright, 1/backEnd.overBright, 0.1/backEnd.overBright ); - } - } - } - - qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); - qglDisable( GL_STENCIL_TEST ); - GL_Cull( CT_TWO_SIDED ); - RB_DrawShadowElementsWithCounters( tri, numIndexes ); - GL_Cull( CT_FRONT_SIDED ); - qglEnable( GL_STENCIL_TEST ); - - return; - } - - // DG: that bloody patent on depth-fail stencil shadows has finally expired on 2019-10-13, - // so use them (see https://patents.google.com/patent/US6384822B1/en for expiration status) - bool useStencilOpSeperate = r_useStencilOpSeparate.GetBool() && qglStencilOpSeparate != NULL; - if( !r_useCarmacksReverse.GetBool() ) { - if( useStencilOpSeperate ) { - // not using z-fail, but using qglStencilOpSeparate() - GLenum firstFace = backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK; - GLenum secondFace = backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT; - GL_Cull( CT_TWO_SIDED ); - if ( !external ) { - qglStencilOpSeparate( firstFace, GL_KEEP, tr.stencilDecr, tr.stencilDecr ); - qglStencilOpSeparate( secondFace, GL_KEEP, tr.stencilIncr, tr.stencilIncr ); - RB_DrawShadowElementsWithCounters( tri, numIndexes ); - } - - qglStencilOpSeparate( firstFace, GL_KEEP, GL_KEEP, tr.stencilIncr ); - qglStencilOpSeparate( secondFace, GL_KEEP, GL_KEEP, tr.stencilDecr ); - - RB_DrawShadowElementsWithCounters( tri, numIndexes ); - - } else { // DG: this is the original code: - // patent-free work around - if ( !external ) { - // "preload" the stencil buffer with the number of volumes - // that get clipped by the near or far clip plane - qglStencilOp( GL_KEEP, tr.stencilDecr, tr.stencilDecr ); - GL_Cull( CT_FRONT_SIDED ); - RB_DrawShadowElementsWithCounters( tri, numIndexes ); - qglStencilOp( GL_KEEP, tr.stencilIncr, tr.stencilIncr ); - GL_Cull( CT_BACK_SIDED ); - RB_DrawShadowElementsWithCounters( tri, numIndexes ); - } - - // traditional depth-pass stencil shadows - qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilIncr ); - GL_Cull( CT_FRONT_SIDED ); - RB_DrawShadowElementsWithCounters( tri, numIndexes ); - - qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilDecr ); - GL_Cull( CT_BACK_SIDED ); - RB_DrawShadowElementsWithCounters( tri, numIndexes ); - } - } else { // use the formerly patented "Carmack's Reverse" Z-Fail code - if( useStencilOpSeperate ) { - // Z-Fail with glStencilOpSeparate() which will reduce draw calls - GLenum firstFace = backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK; - GLenum secondFace = backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT; - if ( !external ) { // z-fail - qglStencilOpSeparate( firstFace, GL_KEEP, tr.stencilDecr, GL_KEEP ); - qglStencilOpSeparate( secondFace, GL_KEEP, tr.stencilIncr, GL_KEEP ); - } else { // depth-pass - qglStencilOpSeparate( firstFace, GL_KEEP, GL_KEEP, tr.stencilIncr ); - qglStencilOpSeparate( secondFace, GL_KEEP, GL_KEEP, tr.stencilDecr ); - } - GL_Cull( CT_TWO_SIDED ); - RB_DrawShadowElementsWithCounters( tri, numIndexes ); - - } else { // Z-Fail without glStencilOpSeparate() - - // LEITH: the (formerly patented) "Carmack's Reverse" code - - // depth-fail/Z-Fail stencil shadows - if ( !external ) { - qglStencilOp( GL_KEEP, tr.stencilDecr, GL_KEEP ); - GL_Cull( CT_FRONT_SIDED ); - RB_DrawShadowElementsWithCounters( tri, numIndexes ); - qglStencilOp( GL_KEEP, tr.stencilIncr, GL_KEEP ); - GL_Cull( CT_BACK_SIDED ); - RB_DrawShadowElementsWithCounters( tri, numIndexes ); - } - // traditional depth-pass stencil shadows - else { - qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilIncr ); - GL_Cull( CT_FRONT_SIDED ); - RB_DrawShadowElementsWithCounters( tri, numIndexes ); - - qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilDecr ); - GL_Cull( CT_BACK_SIDED ); - RB_DrawShadowElementsWithCounters( tri, numIndexes ); - } - } - } + const srfTriangles_t *tri = surf->geo; + + // check this before setting the program parameter to save on some unnecessary state changes + if ( !tri->shadowCache ) { + return; + } + + // set depth bounds testing for the whole shadow + const DepthBoundsTest depthBoundsTest( backEnd.vLight->scissorRect ); + + // set the light position if we are using a vertex program to project the rear surfaces + if ( r_useShadowVertexProgram.GetBool() && surf->space != backEnd.currentSpace ) { + idVec4 localLight; + R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.vLight->globalLightOrigin, localLight.ToVec3() ); + localLight.w = 0.0f; + + // get the stencilshadow program location + qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_ORIGIN, localLight.ToFloatPtr() ); + } + qglVertexPointer( 4, GL_FLOAT, sizeof( shadowCache_t ), vertexCache.Position( tri->shadowCache ) ); + + // we always draw the sil planes, but we may not need to draw the front or rear caps + int numIndexes; + bool external = false; + + if ( !r_useExternalShadows.GetInteger() ) { + numIndexes = tri->numIndexes; + } else if ( r_useExternalShadows.GetInteger() == 2 ) { + // force to no caps for testing + numIndexes = tri->numShadowIndexesNoCaps; + external = true; // this is also external. + } else if ( !( surf->dsFlags & DSF_VIEW_INSIDE_SHADOW ) ) { + // if we aren't inside the shadow projection, no caps are ever needed needed + numIndexes = tri->numShadowIndexesNoCaps; + external = true; + } else if ( !backEnd.vLight->viewInsideLight && !( surf->geo->shadowCapPlaneBits & SHADOW_CAP_INFINITE ) ) { + // if we are inside the shadow projection, but outside the light, and drawing + // a non-infinite shadow, we can skip some caps + if ( backEnd.vLight->viewSeesShadowPlaneBits & surf->geo->shadowCapPlaneBits ) { + // we can see through a rear cap, so we need to draw it, but we can skip the + // caps on the actual surface + numIndexes = tri->numShadowIndexesNoFrontCaps; + } else { + // we don't need to draw any caps + numIndexes = tri->numShadowIndexesNoCaps; + } + external = true; + } else { + // must draw everything + numIndexes = tri->numIndexes; + } + + // debug visualization + if ( r_showShadows.GetInteger() ) { + if ( r_showShadows.GetInteger() == 3 ) { + if ( external ) { + qglColor3f( 0.1 / backEnd.overBright, 1 / backEnd.overBright, 0.1 / backEnd.overBright ); + } else { + // these are the surfaces that require the reverse + qglColor3f( 1 / backEnd.overBright, 0.1 / backEnd.overBright, 0.1 / backEnd.overBright ); + } + } else { + // draw different color for turboshadows + if ( surf->geo->shadowCapPlaneBits & SHADOW_CAP_INFINITE ) { + if ( numIndexes == tri->numIndexes ) { + qglColor3f( 1 / backEnd.overBright, 0.1 / backEnd.overBright, 0.1 / backEnd.overBright ); + } else { + qglColor3f( 1 / backEnd.overBright, 0.4 / backEnd.overBright, 0.1 / backEnd.overBright ); + } + } else { + if ( numIndexes == tri->numIndexes ) { + qglColor3f( 0.1 / backEnd.overBright, 1 / backEnd.overBright, 0.1 / backEnd.overBright ); + } else if ( numIndexes == tri->numShadowIndexesNoFrontCaps ) { + qglColor3f( 0.1 / backEnd.overBright, 1 / backEnd.overBright, 0.6 / backEnd.overBright ); + } else { + qglColor3f( 0.6 / backEnd.overBright, 1 / backEnd.overBright, 0.1 / backEnd.overBright ); + } + } + } + qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); + qglDisable( GL_STENCIL_TEST ); + GL_Cull( CT_TWO_SIDED ); + RB_DrawShadowElementsWithCounters( tri, numIndexes ); + GL_Cull( CT_FRONT_SIDED ); + qglEnable( GL_STENCIL_TEST ); + + return; + } + + // DG: that bloody patent on depth-fail stencil shadows has finally expired on 2019-10-13, + // so use them (see https://patents.google.com/patent/US6384822B1/en for expiration status) + bool useStencilOpSeperate = r_useStencilOpSeparate.GetBool() && qglStencilOpSeparate != NULL; + if ( !r_useCarmacksReverse.GetBool() ) { + if ( useStencilOpSeperate ) { + // not using z-fail, but using qglStencilOpSeparate() + GLenum firstFace = backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK; + GLenum secondFace = backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT; + GL_Cull( CT_TWO_SIDED ); + if ( !external ) { + qglStencilOpSeparate( firstFace, GL_KEEP, tr.stencilDecr, tr.stencilDecr ); + qglStencilOpSeparate( secondFace, GL_KEEP, tr.stencilIncr, tr.stencilIncr ); + RB_DrawShadowElementsWithCounters( tri, numIndexes ); + } + qglStencilOpSeparate( firstFace, GL_KEEP, GL_KEEP, tr.stencilIncr ); + qglStencilOpSeparate( secondFace, GL_KEEP, GL_KEEP, tr.stencilDecr ); + + RB_DrawShadowElementsWithCounters( tri, numIndexes ); + } else { // DG: this is the original code: + // patent-free work around + if ( !external ) { + // "preload" the stencil buffer with the number of volumes + // that get clipped by the near or far clip plane + qglStencilOp( GL_KEEP, tr.stencilDecr, tr.stencilDecr ); + GL_Cull( CT_FRONT_SIDED ); + RB_DrawShadowElementsWithCounters( tri, numIndexes ); + qglStencilOp( GL_KEEP, tr.stencilIncr, tr.stencilIncr ); + GL_Cull( CT_BACK_SIDED ); + RB_DrawShadowElementsWithCounters( tri, numIndexes ); + } + + // traditional depth-pass stencil shadows + qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilIncr ); + GL_Cull( CT_FRONT_SIDED ); + RB_DrawShadowElementsWithCounters( tri, numIndexes ); + + qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilDecr ); + GL_Cull( CT_BACK_SIDED ); + RB_DrawShadowElementsWithCounters( tri, numIndexes ); + } + } else { + // use the formerly patented "Carmack's Reverse" Z-Fail code + if ( useStencilOpSeperate ) { + // Z-Fail with glStencilOpSeparate() which will reduce draw calls + GLenum firstFace = backEnd.viewDef->isMirror ? GL_FRONT : GL_BACK; + GLenum secondFace = backEnd.viewDef->isMirror ? GL_BACK : GL_FRONT; + + if ( !external ) { // z-fail + qglStencilOpSeparate( firstFace, GL_KEEP, tr.stencilDecr, GL_KEEP ); + qglStencilOpSeparate( secondFace, GL_KEEP, tr.stencilIncr, GL_KEEP ); + } else { // depth-pass + qglStencilOpSeparate( firstFace, GL_KEEP, GL_KEEP, tr.stencilIncr ); + qglStencilOpSeparate( secondFace, GL_KEEP, GL_KEEP, tr.stencilDecr ); + } + GL_Cull( CT_TWO_SIDED ); + RB_DrawShadowElementsWithCounters( tri, numIndexes ); + } else { + // Z-Fail without glStencilOpSeparate() + // LEITH: the (formerly patented) "Carmack's Reverse" code + // depth-fail/Z-Fail stencil shadows + if ( !external ) { + qglStencilOp( GL_KEEP, tr.stencilDecr, GL_KEEP ); + GL_Cull( CT_FRONT_SIDED ); + RB_DrawShadowElementsWithCounters( tri, numIndexes ); + qglStencilOp( GL_KEEP, tr.stencilIncr, GL_KEEP ); + GL_Cull( CT_BACK_SIDED ); + RB_DrawShadowElementsWithCounters( tri, numIndexes ); + } else { // traditional depth-pass stencil shadows + qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilIncr ); + GL_Cull( CT_FRONT_SIDED ); + RB_DrawShadowElementsWithCounters( tri, numIndexes ); + + qglStencilOp( GL_KEEP, GL_KEEP, tr.stencilDecr ); + GL_Cull( CT_BACK_SIDED ); + RB_DrawShadowElementsWithCounters( tri, numIndexes ); + } + } + } } /* @@ -1476,62 +1450,49 @@ been set to 128 on any surfaces that might receive shadows ===================== */ void RB_StencilShadowPass( const drawSurf_t *drawSurfs ) { - if ( !r_shadows.GetBool() ) { - return; - } - - if ( !drawSurfs ) { - return; - } - - globalImages->BindNull(); - qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - - // for visualizing the shadows - if ( r_showShadows.GetInteger() ) { - if ( r_showShadows.GetInteger() == 2 ) { - // draw filled in - GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_LESS ); - } else { - // draw as lines, filling the depth buffer - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS ); - } - } else { - // don't write to the color buffer, just the stencil buffer - GL_State( GLS_DEPTHMASK | GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHFUNC_LESS ); - } - - if ( r_shadowPolygonFactor.GetFloat() || r_shadowPolygonOffset.GetFloat() ) { - qglPolygonOffset( r_shadowPolygonFactor.GetFloat(), -r_shadowPolygonOffset.GetFloat() ); - qglEnable( GL_POLYGON_OFFSET_FILL ); - } - - qglStencilFunc( GL_ALWAYS, 1, 255 ); - - if ( glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool() ) { - qglEnable( GL_DEPTH_BOUNDS_TEST_EXT ); - } - - RB_RenderDrawSurfChainWithFunction( drawSurfs, RB_T_Shadow ); - - GL_Cull( CT_FRONT_SIDED ); - - if ( r_shadowPolygonFactor.GetFloat() || r_shadowPolygonOffset.GetFloat() ) { - qglDisable( GL_POLYGON_OFFSET_FILL ); - } - - if ( glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool() ) { - qglDisable( GL_DEPTH_BOUNDS_TEST_EXT ); - } - - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - - qglStencilFunc( GL_GEQUAL, 128, 255 ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); + if ( !r_shadows.GetBool() ) { + return; + } + + if ( !drawSurfs ) { + return; + } + globalImages->BindNull(); + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + + // for visualizing the shadows + if ( r_showShadows.GetInteger() ) { + if ( r_showShadows.GetInteger() == 2 ) { + // draw filled in + GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_LESS ); + } else { + // draw as lines, filling the depth buffer + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS ); + } + } else { + // don't write to the color buffer, just the stencil buffer + GL_State( GLS_DEPTHMASK | GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHFUNC_LESS ); + } + + if ( r_shadowPolygonFactor.GetFloat() || r_shadowPolygonOffset.GetFloat() ) { + qglPolygonOffset( r_shadowPolygonFactor.GetFloat(), -r_shadowPolygonOffset.GetFloat() ); + qglEnable( GL_POLYGON_OFFSET_FILL ); + } + qglStencilFunc( GL_ALWAYS, 1, 255 ); + + RB_RenderDrawSurfChainWithFunction( drawSurfs, RB_T_Shadow ); + + GL_Cull( CT_FRONT_SIDED ); + + if ( r_shadowPolygonFactor.GetFloat() || r_shadowPolygonOffset.GetFloat() ) { + qglDisable( GL_POLYGON_OFFSET_FILL ); + } + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + + qglStencilFunc( GL_GEQUAL, 128, 255 ); + qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); } - - /* ============================================================================================= @@ -1547,40 +1508,37 @@ RB_T_BlendLight ===================== */ static void RB_T_BlendLight( const drawSurf_t *surf ) { - const srfTriangles_t *tri; - - tri = surf->geo; - - if ( backEnd.currentSpace != surf->space ) { - idPlane lightProject[4]; - int i; - - for ( i = 0 ; i < 4 ; i++ ) { - R_GlobalPlaneToLocal( surf->space->modelMatrix, backEnd.vLight->lightProject[i], lightProject[i] ); - } - - GL_SelectTexture( 0 ); - qglTexGenfv( GL_S, GL_OBJECT_PLANE, lightProject[0].ToFloatPtr() ); - qglTexGenfv( GL_T, GL_OBJECT_PLANE, lightProject[1].ToFloatPtr() ); - qglTexGenfv( GL_Q, GL_OBJECT_PLANE, lightProject[2].ToFloatPtr() ); - - GL_SelectTexture( 1 ); - qglTexGenfv( GL_S, GL_OBJECT_PLANE, lightProject[3].ToFloatPtr() ); - } - - // this gets used for both blend lights and shadow draws - if ( tri->ambientCache ) { - idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache ); - qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); - } else if ( tri->shadowCache ) { - shadowCache_t *sc = (shadowCache_t *)vertexCache.Position( tri->shadowCache ); - qglVertexPointer( 3, GL_FLOAT, sizeof( shadowCache_t ), sc->xyz.ToFloatPtr() ); - } - - RB_DrawElementsWithCounters( tri ); + const srfTriangles_t *tri; + + tri = surf->geo; + + if ( backEnd.currentSpace != surf->space ) { + idPlane lightProject[4]; + int i; + + for ( i = 0 ; i < 4 ; i++ ) { + R_GlobalPlaneToLocal( surf->space->modelMatrix, backEnd.vLight->lightProject[i], lightProject[i] ); + } + GL_SelectTexture( 0 ); + qglTexGenfv( GL_S, GL_OBJECT_PLANE, lightProject[0].ToFloatPtr() ); + qglTexGenfv( GL_T, GL_OBJECT_PLANE, lightProject[1].ToFloatPtr() ); + qglTexGenfv( GL_Q, GL_OBJECT_PLANE, lightProject[2].ToFloatPtr() ); + + GL_SelectTexture( 1 ); + qglTexGenfv( GL_S, GL_OBJECT_PLANE, lightProject[3].ToFloatPtr() ); + } + + // this gets used for both blend lights and shadow draws + if ( tri->ambientCache ) { + idDrawVert *ac = ( idDrawVert * )vertexCache.Position( tri->ambientCache ); + qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); + } else if ( tri->shadowCache ) { + shadowCache_t *sc = ( shadowCache_t * )vertexCache.Position( tri->shadowCache ); + qglVertexPointer( 3, GL_FLOAT, sizeof( shadowCache_t ), sc->xyz.ToFloatPtr() ); + } + RB_DrawElementsWithCounters( tri ); } - /* ===================== RB_BlendLight @@ -1590,83 +1548,81 @@ mode to the framebuffer, instead of interacting with the surface texture ===================== */ static void RB_BlendLight( const drawSurf_t *drawSurfs, const drawSurf_t *drawSurfs2 ) { - const idMaterial *lightShader; - const shaderStage_t *stage; - int i; - const float *regs; - - if ( !drawSurfs ) { - return; - } - if ( r_skipBlendLights.GetBool() ) { - return; - } - - lightShader = backEnd.vLight->lightShader; - regs = backEnd.vLight->shaderRegisters; - - // texture 1 will get the falloff texture - GL_SelectTexture( 1 ); - qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - qglEnable( GL_TEXTURE_GEN_S ); - qglTexCoord2f( 0, 0.5 ); - backEnd.vLight->falloffImage->Bind(); - - // texture 0 will get the projected texture - GL_SelectTexture( 0 ); - qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - qglEnable( GL_TEXTURE_GEN_S ); - qglEnable( GL_TEXTURE_GEN_T ); - qglEnable( GL_TEXTURE_GEN_Q ); - - for ( i = 0 ; i < lightShader->GetNumStages() ; i++ ) { - stage = lightShader->GetStage(i); - - if ( !regs[ stage->conditionRegister ] ) { - continue; - } - - GL_State( GLS_DEPTHMASK | stage->drawStateBits | GLS_DEPTHFUNC_EQUAL ); - - GL_SelectTexture( 0 ); - stage->texture.image->Bind(); - - if ( stage->texture.hasMatrix ) { - RB_LoadShaderTextureMatrix( regs, &stage->texture ); - } - - // get the modulate values from the light, including alpha, unlike normal lights - backEnd.lightColor[0] = regs[ stage->color.registers[0] ]; - backEnd.lightColor[1] = regs[ stage->color.registers[1] ]; - backEnd.lightColor[2] = regs[ stage->color.registers[2] ]; - backEnd.lightColor[3] = regs[ stage->color.registers[3] ]; - qglColor4fv( backEnd.lightColor ); - - RB_RenderDrawSurfChainWithFunction( drawSurfs, RB_T_BlendLight ); - RB_RenderDrawSurfChainWithFunction( drawSurfs2, RB_T_BlendLight ); - - if ( stage->texture.hasMatrix ) { - GL_SelectTexture( 0 ); - qglMatrixMode( GL_TEXTURE ); - qglLoadIdentity(); - qglMatrixMode( GL_MODELVIEW ); - } - } - - GL_SelectTexture( 1 ); - qglDisable( GL_TEXTURE_GEN_S ); - globalImages->BindNull(); - - GL_SelectTexture( 0 ); - qglDisable( GL_TEXTURE_GEN_S ); - qglDisable( GL_TEXTURE_GEN_T ); - qglDisable( GL_TEXTURE_GEN_Q ); + const idMaterial *lightShader; + const shaderStage_t *stage; + int i; + const float *regs; + + if ( !drawSurfs ) { + return; + } + + if ( r_skipBlendLights.GetBool() ) { + return; + } + lightShader = backEnd.vLight->lightShader; + regs = backEnd.vLight->shaderRegisters; + + // texture 1 will get the falloff texture + GL_SelectTexture( 1 ); + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + qglEnable( GL_TEXTURE_GEN_S ); + qglTexCoord2f( 0, 0.5 ); + backEnd.vLight->falloffImage->Bind(); + + // texture 0 will get the projected texture + GL_SelectTexture( 0 ); + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + qglEnable( GL_TEXTURE_GEN_S ); + qglEnable( GL_TEXTURE_GEN_T ); + qglEnable( GL_TEXTURE_GEN_Q ); + + for ( i = 0 ; i < lightShader->GetNumStages() ; i++ ) { + stage = lightShader->GetStage( i ); + + if ( !regs[ stage->conditionRegister ] ) { + continue; + } + GL_State( GLS_DEPTHMASK | stage->drawStateBits | GLS_DEPTHFUNC_EQUAL ); + + GL_SelectTexture( 0 ); + stage->texture.image->Bind(); + + if ( stage->texture.hasMatrix ) { + RB_LoadShaderTextureMatrix( regs, &stage->texture ); + } + + // get the modulate values from the light, including alpha, unlike normal lights + backEnd.lightColor[0] = regs[ stage->color.registers[0] ]; + backEnd.lightColor[1] = regs[ stage->color.registers[1] ]; + backEnd.lightColor[2] = regs[ stage->color.registers[2] ]; + backEnd.lightColor[3] = regs[ stage->color.registers[3] ]; + qglColor4fv( backEnd.lightColor ); + + RB_RenderDrawSurfChainWithFunction( drawSurfs, RB_T_BlendLight ); + RB_RenderDrawSurfChainWithFunction( drawSurfs2, RB_T_BlendLight ); + + if ( stage->texture.hasMatrix ) { + GL_SelectTexture( 0 ); + qglMatrixMode( GL_TEXTURE ); + qglLoadIdentity(); + qglMatrixMode( GL_MODELVIEW ); + } + } + GL_SelectTexture( 1 ); + qglDisable( GL_TEXTURE_GEN_S ); + globalImages->BindNull(); + + GL_SelectTexture( 0 ); + qglDisable( GL_TEXTURE_GEN_S ); + qglDisable( GL_TEXTURE_GEN_T ); + qglDisable( GL_TEXTURE_GEN_Q ); } //======================================================================== -static idPlane fogPlanes[4]; +static idPlane fogPlanes[4]; /* ===================== @@ -1675,149 +1631,144 @@ RB_T_BasicFog ===================== */ static void RB_T_BasicFog( const drawSurf_t *surf ) { - if ( backEnd.currentSpace != surf->space ) { - idPlane local; - - GL_SelectTexture( 0 ); + if ( backEnd.currentSpace != surf->space ) { + idPlane local; - R_GlobalPlaneToLocal( surf->space->modelMatrix, fogPlanes[0], local ); - local[3] += 0.5; - qglTexGenfv( GL_S, GL_OBJECT_PLANE, local.ToFloatPtr() ); + GL_SelectTexture( 0 ); -// R_GlobalPlaneToLocal( surf->space->modelMatrix, fogPlanes[1], local ); -// local[3] += 0.5; -local[0] = local[1] = local[2] = 0; local[3] = 0.5; - qglTexGenfv( GL_T, GL_OBJECT_PLANE, local.ToFloatPtr() ); + R_GlobalPlaneToLocal( surf->space->modelMatrix, fogPlanes[0], local ); + local[3] += 0.5; + qglTexGenfv( GL_S, GL_OBJECT_PLANE, local.ToFloatPtr() ); - GL_SelectTexture( 1 ); + // R_GlobalPlaneToLocal( surf->space->modelMatrix, fogPlanes[1], local ); + // local[3] += 0.5; + local[0] = local[1] = local[2] = 0; + local[3] = 0.5; + qglTexGenfv( GL_T, GL_OBJECT_PLANE, local.ToFloatPtr() ); - // GL_S is constant per viewer - R_GlobalPlaneToLocal( surf->space->modelMatrix, fogPlanes[2], local ); - local[3] += FOG_ENTER; - qglTexGenfv( GL_T, GL_OBJECT_PLANE, local.ToFloatPtr() ); + GL_SelectTexture( 1 ); - R_GlobalPlaneToLocal( surf->space->modelMatrix, fogPlanes[3], local ); - qglTexGenfv( GL_S, GL_OBJECT_PLANE, local.ToFloatPtr() ); - } + // GL_S is constant per viewer + R_GlobalPlaneToLocal( surf->space->modelMatrix, fogPlanes[2], local ); + local[3] += FOG_ENTER; + qglTexGenfv( GL_T, GL_OBJECT_PLANE, local.ToFloatPtr() ); - RB_T_RenderTriangleSurface( surf ); + R_GlobalPlaneToLocal( surf->space->modelMatrix, fogPlanes[3], local ); + qglTexGenfv( GL_S, GL_OBJECT_PLANE, local.ToFloatPtr() ); + } + RB_T_RenderTriangleSurface( surf ); } - - /* ================== RB_FogPass ================== */ static void RB_FogPass( const drawSurf_t *drawSurfs, const drawSurf_t *drawSurfs2 ) { - const srfTriangles_t*frustumTris; - drawSurf_t ds; - const idMaterial *lightShader; - const shaderStage_t *stage; - const float *regs; - - // create a surface for the light frustom triangles, which are oriented drawn side out - frustumTris = backEnd.vLight->frustumTris; - - // if we ran out of vertex cache memory, skip it - if ( !frustumTris->ambientCache ) { - return; - } - memset( &ds, 0, sizeof( ds ) ); - ds.space = &backEnd.viewDef->worldSpace; - ds.geo = frustumTris; - ds.scissorRect = backEnd.viewDef->scissor; - - // find the current color and density of the fog - lightShader = backEnd.vLight->lightShader; - regs = backEnd.vLight->shaderRegisters; - // assume fog shaders have only a single stage - stage = lightShader->GetStage(0); - - backEnd.lightColor[0] = regs[ stage->color.registers[0] ]; - backEnd.lightColor[1] = regs[ stage->color.registers[1] ]; - backEnd.lightColor[2] = regs[ stage->color.registers[2] ]; - backEnd.lightColor[3] = regs[ stage->color.registers[3] ]; - - qglColor3fv( backEnd.lightColor ); - - // calculate the falloff planes - float a; - - // if they left the default value on, set a fog distance of 500 - if ( backEnd.lightColor[3] <= 1.0 ) { - a = -0.5f / DEFAULT_FOG_DISTANCE; - } else { - // otherwise, distance = alpha color - a = -0.5f / backEnd.lightColor[3]; - } - - GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); - - // texture 0 is the falloff image - GL_SelectTexture( 0 ); - globalImages->fogImage->Bind(); - //GL_Bind( tr.whiteImage ); - qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - qglEnable( GL_TEXTURE_GEN_S ); - qglEnable( GL_TEXTURE_GEN_T ); - qglTexCoord2f( 0.5f, 0.5f ); // make sure Q is set - - fogPlanes[0][0] = a * backEnd.viewDef->worldSpace.modelViewMatrix[2]; - fogPlanes[0][1] = a * backEnd.viewDef->worldSpace.modelViewMatrix[6]; - fogPlanes[0][2] = a * backEnd.viewDef->worldSpace.modelViewMatrix[10]; - fogPlanes[0][3] = a * backEnd.viewDef->worldSpace.modelViewMatrix[14]; - - fogPlanes[1][0] = a * backEnd.viewDef->worldSpace.modelViewMatrix[0]; - fogPlanes[1][1] = a * backEnd.viewDef->worldSpace.modelViewMatrix[4]; - fogPlanes[1][2] = a * backEnd.viewDef->worldSpace.modelViewMatrix[8]; - fogPlanes[1][3] = a * backEnd.viewDef->worldSpace.modelViewMatrix[12]; - - - // texture 1 is the entering plane fade correction - GL_SelectTexture( 1 ); - globalImages->fogEnterImage->Bind(); - qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); - qglEnable( GL_TEXTURE_GEN_S ); - qglEnable( GL_TEXTURE_GEN_T ); - - // T will get a texgen for the fade plane, which is always the "top" plane on unrotated lights - fogPlanes[2][0] = 0.001f * backEnd.vLight->fogPlane[0]; - fogPlanes[2][1] = 0.001f * backEnd.vLight->fogPlane[1]; - fogPlanes[2][2] = 0.001f * backEnd.vLight->fogPlane[2]; - fogPlanes[2][3] = 0.001f * backEnd.vLight->fogPlane[3]; - - // S is based on the view origin - float s = backEnd.viewDef->renderView.vieworg * fogPlanes[2].Normal() + fogPlanes[2][3]; - - fogPlanes[3][0] = 0; - fogPlanes[3][1] = 0; - fogPlanes[3][2] = 0; - fogPlanes[3][3] = FOG_ENTER + s; - - qglTexCoord2f( FOG_ENTER + s, FOG_ENTER ); - - - // draw it - RB_RenderDrawSurfChainWithFunction( drawSurfs, RB_T_BasicFog ); - RB_RenderDrawSurfChainWithFunction( drawSurfs2, RB_T_BasicFog ); - - // the light frustum bounding planes aren't in the depth buffer, so use depthfunc_less instead - // of depthfunc_equal - GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_LESS ); - GL_Cull( CT_BACK_SIDED ); - RB_RenderDrawSurfChainWithFunction( &ds, RB_T_BasicFog ); - GL_Cull( CT_FRONT_SIDED ); - - GL_SelectTexture( 1 ); - qglDisable( GL_TEXTURE_GEN_S ); - qglDisable( GL_TEXTURE_GEN_T ); - globalImages->BindNull(); - - GL_SelectTexture( 0 ); - qglDisable( GL_TEXTURE_GEN_S ); - qglDisable( GL_TEXTURE_GEN_T ); + const srfTriangles_t *frustumTris; + drawSurf_t ds; + const idMaterial *lightShader; + const shaderStage_t *stage; + const float *regs; + + // create a surface for the light frustom triangles, which are oriented drawn side out + frustumTris = backEnd.vLight->frustumTris; + + // if we ran out of vertex cache memory, skip it + if ( !frustumTris->ambientCache ) { + return; + } + memset( &ds, 0, sizeof( ds ) ); + ds.space = &backEnd.viewDef->worldSpace; + ds.geo = frustumTris; + ds.scissorRect = backEnd.viewDef->scissor; + + // find the current color and density of the fog + lightShader = backEnd.vLight->lightShader; + regs = backEnd.vLight->shaderRegisters; + // assume fog shaders have only a single stage + stage = lightShader->GetStage( 0 ); + + backEnd.lightColor[0] = regs[ stage->color.registers[0] ]; + backEnd.lightColor[1] = regs[ stage->color.registers[1] ]; + backEnd.lightColor[2] = regs[ stage->color.registers[2] ]; + backEnd.lightColor[3] = regs[ stage->color.registers[3] ]; + + qglColor3fv( backEnd.lightColor ); + + // calculate the falloff planes + float a; + + // if they left the default value on, set a fog distance of 500 + if ( backEnd.lightColor[3] <= 1.0 ) { + a = -0.5f / DEFAULT_FOG_DISTANCE; + } else { + // otherwise, distance = alpha color + a = -0.5f / backEnd.lightColor[3]; + } + GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); + + // texture 0 is the falloff image + GL_SelectTexture( 0 ); + globalImages->fogImage->Bind(); + //GL_Bind( tr.whiteImage ); + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + qglEnable( GL_TEXTURE_GEN_S ); + qglEnable( GL_TEXTURE_GEN_T ); + qglTexCoord2f( 0.5f, 0.5f ); // make sure Q is set + + fogPlanes[0][0] = a * backEnd.viewDef->worldSpace.modelViewMatrix[2]; + fogPlanes[0][1] = a * backEnd.viewDef->worldSpace.modelViewMatrix[6]; + fogPlanes[0][2] = a * backEnd.viewDef->worldSpace.modelViewMatrix[10]; + fogPlanes[0][3] = a * backEnd.viewDef->worldSpace.modelViewMatrix[14]; + + fogPlanes[1][0] = a * backEnd.viewDef->worldSpace.modelViewMatrix[0]; + fogPlanes[1][1] = a * backEnd.viewDef->worldSpace.modelViewMatrix[4]; + fogPlanes[1][2] = a * backEnd.viewDef->worldSpace.modelViewMatrix[8]; + fogPlanes[1][3] = a * backEnd.viewDef->worldSpace.modelViewMatrix[12]; + + // texture 1 is the entering plane fade correction + GL_SelectTexture( 1 ); + globalImages->fogEnterImage->Bind(); + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); + qglEnable( GL_TEXTURE_GEN_S ); + qglEnable( GL_TEXTURE_GEN_T ); + + // T will get a texgen for the fade plane, which is always the "top" plane on unrotated lights + fogPlanes[2][0] = 0.001f * backEnd.vLight->fogPlane[0]; + fogPlanes[2][1] = 0.001f * backEnd.vLight->fogPlane[1]; + fogPlanes[2][2] = 0.001f * backEnd.vLight->fogPlane[2]; + fogPlanes[2][3] = 0.001f * backEnd.vLight->fogPlane[3]; + + // S is based on the view origin + float s = backEnd.viewDef->renderView.vieworg * fogPlanes[2].Normal() + fogPlanes[2][3]; + + fogPlanes[3][0] = 0; + fogPlanes[3][1] = 0; + fogPlanes[3][2] = 0; + fogPlanes[3][3] = FOG_ENTER + s; + + qglTexCoord2f( FOG_ENTER + s, FOG_ENTER ); + + // draw it + RB_RenderDrawSurfChainWithFunction( drawSurfs, RB_T_BasicFog ); + RB_RenderDrawSurfChainWithFunction( drawSurfs2, RB_T_BasicFog ); + + // the light frustum bounding planes aren't in the depth buffer, so use depthfunc_less instead + // of depthfunc_equal + GL_State( GLS_DEPTHMASK | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_LESS ); + GL_Cull( CT_BACK_SIDED ); + RB_RenderDrawSurfChainWithFunction( &ds, RB_T_BasicFog ); + GL_Cull( CT_FRONT_SIDED ); + + GL_SelectTexture( 1 ); + qglDisable( GL_TEXTURE_GEN_S ); + qglDisable( GL_TEXTURE_GEN_T ); + globalImages->BindNull(); + + GL_SelectTexture( 0 ); + qglDisable( GL_TEXTURE_GEN_S ); + qglDisable( GL_TEXTURE_GEN_T ); } @@ -1827,57 +1778,54 @@ RB_STD_FogAllLights ================== */ void RB_STD_FogAllLights( void ) { - viewLight_t *vLight; - - if ( r_skipFogLights.GetBool() || r_showOverDraw.GetInteger() != 0 - || backEnd.viewDef->isXraySubview /* dont fog in xray mode*/ - ) { - return; - } + viewLight_t *vLight; - qglDisable( GL_STENCIL_TEST ); + /* dont fog in xray mode*/ + if ( r_skipFogLights.GetBool() || r_showOverDraw.GetInteger() != 0 || backEnd.viewDef->isXraySubview ) { + return; + } + qglDisable( GL_STENCIL_TEST ); - for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) { - backEnd.vLight = vLight; + for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) { + backEnd.vLight = vLight; - if ( !vLight->lightShader->IsFogLight() && !vLight->lightShader->IsBlendLight() ) { - continue; - } + if ( !vLight->lightShader->IsFogLight() && !vLight->lightShader->IsBlendLight() ) { + continue; + } #if 0 // _D3XP disabled that - if ( r_ignore.GetInteger() ) { - // we use the stencil buffer to guarantee that no pixels will be - // double fogged, which happens in some areas that are thousands of - // units from the origin - backEnd.currentScissor = vLight->scissorRect; - if ( r_useScissor.GetBool() ) { - qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, - backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, - backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, - backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); - } - qglClear( GL_STENCIL_BUFFER_BIT ); - - qglEnable( GL_STENCIL_TEST ); - - // only pass on the cleared stencil values - qglStencilFunc( GL_EQUAL, 128, 255 ); - - // when we pass the stencil test and depth test and are going to draw, - // increment the stencil buffer so we don't ever draw on that pixel again - qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); - } + if ( r_ignore.GetInteger() ) { + // we use the stencil buffer to guarantee that no pixels will be + // double fogged, which happens in some areas that are thousands of + // units from the origin + backEnd.currentScissor = vLight->scissorRect; + if ( r_useScissor.GetBool() ) { + qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, + backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, + backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, + backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); + } + qglClear( GL_STENCIL_BUFFER_BIT ); + + qglEnable( GL_STENCIL_TEST ); + + // only pass on the cleared stencil values + qglStencilFunc( GL_EQUAL, 128, 255 ); + + // when we pass the stencil test and depth test and are going to draw, + // increment the stencil buffer so we don't ever draw on that pixel again + qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); + } #endif - if ( vLight->lightShader->IsFogLight() ) { - RB_FogPass( vLight->globalInteractions, vLight->localInteractions ); - } else if ( vLight->lightShader->IsBlendLight() ) { - RB_BlendLight( vLight->globalInteractions, vLight->localInteractions ); - } - qglDisable( GL_STENCIL_TEST ); - } - - qglEnable( GL_STENCIL_TEST ); + if ( vLight->lightShader->IsFogLight() ) { + RB_FogPass( vLight->globalInteractions, vLight->localInteractions ); + } else if ( vLight->lightShader->IsBlendLight() ) { + RB_BlendLight( vLight->globalInteractions, vLight->localInteractions ); + } + qglDisable( GL_STENCIL_TEST ); + } + qglEnable( GL_STENCIL_TEST ); } //========================================================================================= @@ -1891,61 +1839,61 @@ a floating point value ================== */ void RB_STD_LightScale( void ) { - float v, f; - - if ( backEnd.overBright == 1.0f ) { - return; - } - - if ( r_skipLightScale.GetBool() ) { - return; - } - - // the scissor may be smaller than the viewport for subviews - if ( r_useScissor.GetBool() ) { - qglScissor( backEnd.viewDef->viewport.x1 + backEnd.viewDef->scissor.x1, - backEnd.viewDef->viewport.y1 + backEnd.viewDef->scissor.y1, - backEnd.viewDef->scissor.x2 - backEnd.viewDef->scissor.x1 + 1, - backEnd.viewDef->scissor.y2 - backEnd.viewDef->scissor.y1 + 1 ); - backEnd.currentScissor = backEnd.viewDef->scissor; - } - - // full screen blends - qglLoadIdentity(); - qglMatrixMode( GL_PROJECTION ); - qglPushMatrix(); - qglLoadIdentity(); - qglOrtho( 0, 1, 0, 1, -1, 1 ); - - GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_SRC_COLOR ); - GL_Cull( CT_TWO_SIDED ); // so mirror views also get it - globalImages->BindNull(); - qglDisable( GL_DEPTH_TEST ); - qglDisable( GL_STENCIL_TEST ); - - v = 1; - while ( idMath::Fabs( v - backEnd.overBright ) > 0.01 ) { // a little extra slop - f = backEnd.overBright / v; - f /= 2; - if ( f > 1 ) { - f = 1; - } - qglColor3f( f, f, f ); - v = v * f * 2; - - qglBegin( GL_QUADS ); - qglVertex2f( 0,0 ); - qglVertex2f( 0,1 ); - qglVertex2f( 1,1 ); - qglVertex2f( 1,0 ); - qglEnd(); - } - - - qglPopMatrix(); - qglEnable( GL_DEPTH_TEST ); - qglMatrixMode( GL_MODELVIEW ); - GL_Cull( CT_FRONT_SIDED ); + float v, f; + + if ( backEnd.overBright == 1.0f ) { + return; + } + + if ( r_skipLightScale.GetBool() ) { + return; + } + + // the scissor may be smaller than the viewport for subviews + if ( r_useScissor.GetBool() ) { + qglScissor( backEnd.viewDef->viewport.x1 + backEnd.viewDef->scissor.x1, + backEnd.viewDef->viewport.y1 + backEnd.viewDef->scissor.y1, + backEnd.viewDef->scissor.x2 - backEnd.viewDef->scissor.x1 + 1, + backEnd.viewDef->scissor.y2 - backEnd.viewDef->scissor.y1 + 1 ); + backEnd.currentScissor = backEnd.viewDef->scissor; + } + + // full screen blends + qglLoadIdentity(); + qglMatrixMode( GL_PROJECTION ); + qglPushMatrix(); + qglLoadIdentity(); + qglOrtho( 0, 1, 0, 1, -1, 1 ); + + GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_SRC_COLOR ); + GL_Cull( CT_TWO_SIDED ); // so mirror views also get it + globalImages->BindNull(); + qglDisable( GL_DEPTH_TEST ); + qglDisable( GL_STENCIL_TEST ); + + v = 1; + + while ( idMath::Fabs( v - backEnd.overBright ) > 0.01 ) { // a little extra slop + f = backEnd.overBright / v; + f /= 2; + + if ( f > 1 ) { + f = 1; + } + qglColor3f( f, f, f ); + v = v * f * 2; + + qglBegin( GL_QUADS ); + qglVertex2f( 0, 0 ); + qglVertex2f( 0, 1 ); + qglVertex2f( 1, 1 ); + qglVertex2f( 1, 0 ); + qglEnd(); + } + qglPopMatrix(); + qglEnable( GL_DEPTH_TEST ); + qglMatrixMode( GL_MODELVIEW ); + GL_Cull( CT_FRONT_SIDED ); } //========================================================================================= @@ -1956,49 +1904,47 @@ RB_STD_DrawView ============= */ -void RB_STD_DrawView( void ) { - drawSurf_t **drawSurfs; - int numDrawSurfs; - - backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL; - - drawSurfs = (drawSurf_t **)&backEnd.viewDef->drawSurfs[0]; - numDrawSurfs = backEnd.viewDef->numDrawSurfs; +void RB_STD_DrawView( void ) { + drawSurf_t **drawSurfs; + int numDrawSurfs; - // clear the z buffer, set the projection matrix, etc - RB_BeginDrawingView(); + backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL; - // decide how much overbrighting we are going to do - RB_DetermineLightScale(); + drawSurfs = ( drawSurf_t ** )&backEnd.viewDef->drawSurfs[0]; + numDrawSurfs = backEnd.viewDef->numDrawSurfs; - // fill the depth buffer and clear color buffer to black except on - // subviews - RB_STD_FillDepthBuffer( drawSurfs, numDrawSurfs ); + // clear the z buffer, set the projection matrix, etc + RB_BeginDrawingView(); - // main light renderer - switch( tr.backEndRenderer ) { - case BE_ARB2: - RB_ARB2_DrawInteractions(); - break; - } + // decide how much overbrighting we are going to do + RB_DetermineLightScale(); - // disable stencil shadow test - qglStencilFunc( GL_ALWAYS, 128, 255 ); + // fill the depth buffer and clear color buffer to black except on + // subviews + RB_STD_FillDepthBuffer( drawSurfs, numDrawSurfs ); - // uplight the entire screen to crutch up not having better blending range - RB_STD_LightScale(); + // main light renderer (redundant we only support ARB2) + switch ( tr.backEndRenderer ) { + case BE_ARB2: + RB_ARB2_DrawInteractions(); + break; + } - // now draw any non-light dependent shading passes - int processed = RB_STD_DrawShaderPasses( drawSurfs, numDrawSurfs ); + // disable stencil shadow test + qglStencilFunc( GL_ALWAYS, 128, 255 ); - // fob and blend lights - RB_STD_FogAllLights(); + // uplight the entire screen to crutch up not having better blending range + RB_STD_LightScale(); - // now draw any post-processing effects using _currentRender - if ( processed < numDrawSurfs ) { - RB_STD_DrawShaderPasses( drawSurfs+processed, numDrawSurfs-processed ); - } + // now draw any non-light dependent shading passes + int processed = RB_STD_DrawShaderPasses( drawSurfs, numDrawSurfs ); - RB_RenderDebugTools( drawSurfs, numDrawSurfs ); + // fob and blend lights + RB_STD_FogAllLights(); + // now draw any post-processing effects using _currentRender + if ( processed < numDrawSurfs ) { + RB_STD_DrawShaderPasses( drawSurfs + processed, numDrawSurfs - processed ); + } + RB_RenderDebugTools( drawSurfs, numDrawSurfs ); } diff --git a/neo/renderer/qgl.h b/neo/renderer/qgl.h index abce7a8ea..7f42d68bf 100644 --- a/neo/renderer/qgl.h +++ b/neo/renderer/qgl.h @@ -42,6 +42,8 @@ If you have questions concerning this license or the applicable additional terms #endif #endif +#define GL_GLEXT_PROTOTYPES + #ifdef D3_SDL3 #include #else // SDL1.2 or SDL2 @@ -77,6 +79,60 @@ extern void ( APIENTRY * qglMultiTexCoord2fvARB )( GLenum texture, GLfloat *st ) extern void ( APIENTRY * qglActiveTextureARB )( GLenum texture ); extern void ( APIENTRY * qglClientActiveTextureARB )( GLenum texture ); +// ARB_MapBufferRange +extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC qglFlushMappedBufferRange; +extern PFNGLMAPBUFFERRANGEPROC qglMapBufferRange; + +// ARB_shading_language_100 +extern PFNGLUNIFORM1FPROC qglUniform1f; +extern PFNGLUNIFORM1FVPROC qglUniform1fv; +extern PFNGLUNIFORM1IPROC qglUniform1i; +extern PFNGLUNIFORM1IVPROC qglUniform1iv; +extern PFNGLUNIFORM2FPROC qglUniform2f; +extern PFNGLUNIFORM2FVPROC qglUniform2fv; +extern PFNGLUNIFORM2IPROC qglUniform2i; +extern PFNGLUNIFORM2IVPROC qglUniform2iv; +extern PFNGLUNIFORM3FPROC qglUniform3f; +extern PFNGLUNIFORM3FVPROC qglUniform3fv; +extern PFNGLUNIFORM3IPROC qglUniform3i; +extern PFNGLUNIFORM3IVPROC qglUniform3iv; +extern PFNGLUNIFORM4FPROC qglUniform4f; +extern PFNGLUNIFORM4FVPROC qglUniform4fv; +extern PFNGLUNIFORM4IPROC qglUniform4i; +extern PFNGLUNIFORM4IVPROC qglUniform4iv; +extern PFNGLUNIFORMMATRIX2FVPROC qglUniformMatrix2fv; +extern PFNGLUNIFORMMATRIX3FVPROC qglUniformMatrix3fv; +extern PFNGLUNIFORMMATRIX4FVPROC qglUniformMatrix4fv; +extern PFNGLUNIFORMMATRIX2X3FVPROC qglUniformMatrix2x3fv; +extern PFNGLUNIFORMMATRIX2X4FVPROC qglUniformMatrix2x4fv; +extern PFNGLUNIFORMMATRIX3X2FVPROC qglUniformMatrix3x2fv; +extern PFNGLUNIFORMMATRIX3X4FVPROC qglUniformMatrix3x4fv; +extern PFNGLUNIFORMMATRIX4X2FVPROC qglUniformMatrix4x2fv; +extern PFNGLUNIFORMMATRIX4X3FVPROC qglUniformMatrix4x3fv; + +extern PFNGLISPROGRAMPROC qglIsProgram; +extern PFNGLCREATEPROGRAMPROC qglCreateProgram; +extern PFNGLVALIDATEPROGRAMPROC qglValidateProgram; +extern PFNGLLINKPROGRAMPROC qglLinkProgram; + +extern PFNGLISSHADERPROC qglIsShader; +extern PFNGLSHADERSOURCEPROC qglShaderSource; +extern PFNGLCREATESHADERPROC qglCreateShader; +extern PFNGLATTACHSHADERPROC qglAttachShader; +extern PFNGLBINDATTRIBLOCATIONPROC qglBindAttribLocation; +extern PFNGLCOMPILESHADERPROC qglCompileShader; +extern PFNGLDETACHSHADERPROC qglDetachShader; +extern PFNGLDELETESHADERPROC qglDeleteShader; + +extern PFNGLGETPROGRAMINFOLOGPROC qglGetProgramInfoLog; +extern PFNGLGETPROGRAMIVPROC qglGetProgramiv; +extern PFNGLGETSHADERINFOLOGPROC qglGetShaderInfoLog; +extern PFNGLGETSHADERSOURCEPROC qglGetShaderSource; +extern PFNGLGETSHADERIVPROC qglGetShaderiv; +extern PFNGLGETUNIFORMLOCATIONPROC qglGetUniformLocation; +extern PFNGLGETUNIFORMFVPROC qglGetUniformfv; +extern PFNGLGETUNIFORMIVPROC qglGetUniformiv; + // ARB_vertex_buffer_object extern PFNGLBINDBUFFERARBPROC qglBindBufferARB; extern PFNGLDELETEBUFFERSARBPROC qglDeleteBuffersARB; diff --git a/neo/renderer/qgl_proc.h b/neo/renderer/qgl_proc.h index af0146d0f..49662dfa3 100644 --- a/neo/renderer/qgl_proc.h +++ b/neo/renderer/qgl_proc.h @@ -90,6 +90,7 @@ QGLPROC(glCopyTexSubImage1D, void, (GLenum target, GLint level, GLint xoffset, G QGLPROC(glCopyTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)) QGLPROC(glCullFace, void, (GLenum mode)) QGLPROC(glDeleteLists, void, (GLuint list, GLsizei range)) +QGLPROC(glDeleteProgram, void, (GLuint program)) QGLPROC(glDeleteTextures, void, (GLsizei n, const GLuint *textures)) QGLPROC(glDepthFunc, void, (GLenum func)) QGLPROC(glDepthMask, void, (GLboolean flag)) @@ -341,6 +342,7 @@ QGLPROC(glTexSubImage1D, void, (GLenum target, GLint level, GLint xoffset, GLsiz QGLPROC(glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)) QGLPROC(glTranslated, void, (GLdouble x, GLdouble y, GLdouble z)) QGLPROC(glTranslatef, void, (GLfloat x, GLfloat y, GLfloat z)) +QGLPROC(glUseProgram, void,(GLuint program)) QGLPROC(glVertex2d, void, (GLdouble x, GLdouble y)) QGLPROC(glVertex2dv, void, (const GLdouble *v)) QGLPROC(glVertex2f, void, (GLfloat x, GLfloat y)) diff --git a/neo/renderer/tr_backend.cpp b/neo/renderer/tr_backend.cpp index cf1c57143..f2b1b591b 100644 --- a/neo/renderer/tr_backend.cpp +++ b/neo/renderer/tr_backend.cpp @@ -44,10 +44,10 @@ may touch, including the editor. ====================== */ void RB_SetDefaultGLState( void ) { - int i; + int tmu; qglClearDepth( 1.0f ); - qglColor4f (1,1,1,1); + qglColor4f( 1, 1, 1, 1 ); // the vertex array is always enabled qglEnableClientState( GL_VERTEX_ARRAY ); @@ -70,7 +70,7 @@ void RB_SetDefaultGLState( void ) { qglDisable( GL_LINE_STIPPLE ); qglDisable( GL_STENCIL_TEST ); - qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); qglDepthMask( GL_TRUE ); qglDepthFunc( GL_ALWAYS ); @@ -81,8 +81,8 @@ void RB_SetDefaultGLState( void ) { qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); } - for ( i = glConfig.maxTextureUnits - 1 ; i >= 0 ; i-- ) { - GL_SelectTexture( i ); + for ( tmu = glConfig.maxTextureUnits - 1 ; tmu >= 0 ; tmu-- ) { + GL_SelectTexture( tmu ); // object linear texgen is our default qglTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); @@ -92,22 +92,19 @@ void RB_SetDefaultGLState( void ) { GL_TexEnv( GL_MODULATE ); qglDisable( GL_TEXTURE_2D ); + if ( glConfig.texture3DAvailable ) { qglDisable( GL_TEXTURE_3D ); } + if ( glConfig.cubeMapAvailable ) { qglDisable( GL_TEXTURE_CUBE_MAP_EXT ); } } } - - - //============================================================================= - - /* ==================== GL_SelectTexture @@ -118,18 +115,16 @@ void GL_SelectTexture( int unit ) { return; } - if ( unit < 0 || (unit >= glConfig.maxTextureUnits && unit >= glConfig.maxTextureImageUnits) ) { + if ( unit < 0 || ( unit >= glConfig.maxTextureUnits && unit >= glConfig.maxTextureImageUnits ) ) { common->Warning( "GL_SelectTexture: unit = %i", unit ); return; } - qglActiveTextureARB( GL_TEXTURE0_ARB + unit ); qglClientActiveTextureARB( GL_TEXTURE0_ARB + unit ); backEnd.glState.currenttmu = unit; } - /* ==================== GL_Cull @@ -164,7 +159,6 @@ void GL_Cull( int cullType ) { } } } - backEnd.glState.faceCulling = cullType; } @@ -177,10 +171,10 @@ void GL_TexEnv( int env ) { tmu_t *tmu; tmu = &backEnd.glState.tmu[backEnd.glState.currenttmu]; + if ( env == tmu->texEnv ) { return; } - tmu->texEnv = env; switch ( env ) { @@ -226,6 +220,7 @@ void GL_State( int stateBits ) { backEnd.glState.forceGlState = false; } else { diff = stateBits ^ backEnd.glState.glStateBits; + if ( !diff ) { return; } @@ -244,7 +239,6 @@ void GL_State( int stateBits ) { } } - // // check blend bits // @@ -315,7 +309,6 @@ void GL_State( int stateBits ) { common->Error( "GL_State: invalid dst blend state bits\n" ); break; } - qglBlendFunc( srcFactor, dstFactor ); } @@ -333,8 +326,8 @@ void GL_State( int stateBits ) { // // check colormask // - if ( diff & (GLS_REDMASK|GLS_GREENMASK|GLS_BLUEMASK|GLS_ALPHAMASK) ) { - GLboolean r, g, b, a; + if ( diff & ( GLS_REDMASK | GLS_GREENMASK | GLS_BLUEMASK | GLS_ALPHAMASK ) ) { + GLboolean r, g, b, a; r = ( stateBits & GLS_REDMASK ) ? 0 : 1; g = ( stateBits & GLS_GREENMASK ) ? 0 : 1; b = ( stateBits & GLS_BLUEMASK ) ? 0 : 1; @@ -378,12 +371,32 @@ void GL_State( int stateBits ) { break; } } - backEnd.glState.glStateBits = stateBits; } +/* +============================================================================ + +DEPTH BOUNDS TESTING +============================================================================ +*/ + +DepthBoundsTest::DepthBoundsTest( const idScreenRect &scissorRect ) { + if ( !glConfig.depthBoundsTestAvailable || !r_useDepthBoundsTest.GetBool() ) { + return; + } + assert( scissorRect.zmin <= scissorRect.zmax ); + qglEnable( GL_DEPTH_BOUNDS_TEST_EXT ); + qglDepthBoundsEXT( scissorRect.zmin, scissorRect.zmax ); +} +DepthBoundsTest::~DepthBoundsTest() { + if ( !glConfig.depthBoundsTestAvailable || !r_useDepthBoundsTest.GetBool() ) { + return; + } + qglDisable( GL_DEPTH_BOUNDS_TEST_EXT ); +} /* ============================================================================ @@ -403,6 +416,7 @@ This is not used by the normal game paths, just by some tools void RB_SetGL2D( void ) { // set 2D virtual screen size qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); + if ( r_useScissor.GetBool() ) { qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); } @@ -413,8 +427,8 @@ void RB_SetGL2D( void ) { qglLoadIdentity(); GL_State( GLS_DEPTHFUNC_ALWAYS | - GLS_SRCBLEND_SRC_ALPHA | - GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); + GLS_SRCBLEND_SRC_ALPHA | + GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); GL_Cull( CT_TWO_SIDED ); @@ -422,20 +436,16 @@ void RB_SetGL2D( void ) { qglDisable( GL_STENCIL_TEST ); } - - /* ============= RB_SetBuffer - ============= */ static void RB_SetBuffer( const void *data ) { const setBufferCommand_t *cmd; // see which draw buffer we want to render the frame to - - cmd = (const setBufferCommand_t *)data; + cmd = ( const setBufferCommand_t * )data; backEnd.frameCount = cmd->frameCount; @@ -488,7 +498,6 @@ void RB_ShowImages( void ) { if ( image->texnum == idImage::TEXTURE_NOT_LOADED && image->partialImage == NULL ) { continue; } - w = glConfig.vidWidth / 20; h = glConfig.vidHeight / 15; x = i % 20 * w; @@ -499,9 +508,8 @@ void RB_ShowImages( void ) { w *= image->uploadWidth / 512.0f; h *= image->uploadHeight / 512.0f; } - image->Bind(); - qglBegin (GL_QUADS); + qglBegin( GL_QUADS ); qglTexCoord2f( 0, 0 ); qglVertex2f( x, y ); qglTexCoord2f( 1, 0 ); @@ -512,18 +520,15 @@ void RB_ShowImages( void ) { qglVertex2f( x, y + h ); qglEnd(); } - qglFinish(); end = Sys_Milliseconds(); common->Printf( "%i msec to draw all images\n", end - start ); } - /* ============= RB_SwapBuffers - ============= */ const void RB_SwapBuffers( const void *data ) { @@ -531,34 +536,38 @@ const void RB_SwapBuffers( const void *data ) { if ( r_showImages.GetInteger() != 0 ) { RB_ShowImages(); } - D3::ImGuiHooks::EndFrame(); int fillAlpha = r_fillWindowAlphaChan.GetInteger(); - if ( fillAlpha == 1 || (fillAlpha == -1 && glConfig.shouldFillWindowAlpha) ) - { + + if ( fillAlpha == 1 || ( fillAlpha == -1 && glConfig.shouldFillWindowAlpha ) ) { // make sure the whole alpha chan of the (default) framebuffer is opaque. // at least Wayland needs this, see also the big comment in GLimp_Init() - bool blendEnabled = qglIsEnabled( GL_BLEND ); - if ( !blendEnabled ) - qglEnable( GL_BLEND ); - - // TODO: GL_DEPTH_TEST ? (should be disabled, if it needs changing at all) + if ( !blendEnabled ) { + qglEnable( GL_BLEND ); + } bool scissorEnabled = qglIsEnabled( GL_SCISSOR_TEST ); - if( scissorEnabled ) - qglDisable( GL_SCISSOR_TEST ); + if ( scissorEnabled ) { + qglDisable( GL_SCISSOR_TEST ); + } bool tex2Denabled = qglIsEnabled( GL_TEXTURE_2D ); - if( tex2Denabled ) + + if ( tex2Denabled ) { qglDisable( GL_TEXTURE_2D ); + } + bool depthTestEnabled = qglIsEnabled( GL_DEPTH_BOUNDS_TEST_EXT ); + // possibly reduntdant the RAII depthbounds test auto disables anyway + if ( depthTestEnabled ) { + qglDisable( GL_DEPTH_BOUNDS_TEST_EXT ); + } qglDisable( GL_VERTEX_PROGRAM_ARB ); qglDisable( GL_FRAGMENT_PROGRAM_ARB ); qglBlendEquation( GL_FUNC_ADD ); - qglBlendFunc( GL_ONE, GL_ONE ); // setup transform matrices so we can easily/reliably draw a fullscreen quad @@ -572,17 +581,18 @@ const void RB_SwapBuffers( const void *data ) { qglOrtho( 0, 1, 0, 1, -1, 1 ); // draw screen-sized quad with color (0.0, 0.0, 0.0, 1.0) - const float x=0, y=0, w=1, h=1; + const float x = 0, y = 0, w = 1, h = 1; qglColor4f( 0.0f, 0.0f, 0.0f, 1.0f ); + // debug values: //const float x = 0.1, y = 0.1, w = 0.8, h = 0.8; //qglColor4f( 0.0f, 0.0f, 0.5f, 1.0f ); qglBegin( GL_QUADS ); - qglVertex2f( x, y ); // ( 0,0 ); - qglVertex2f( x, y+h ); // ( 0,1 ); - qglVertex2f( x+w, y+h ); // ( 1,1 ); - qglVertex2f( x+w, y ); // ( 1,0 ); + qglVertex2f( x, y ); // ( 0,0 ); + qglVertex2f( x, y + h ); // ( 0,1 ); + qglVertex2f( x + w, y + h ); // ( 1,1 ); + qglVertex2f( x + w, y ); // ( 1,0 ); qglEnd(); // restore previous transform matrix states @@ -592,12 +602,18 @@ const void RB_SwapBuffers( const void *data ) { // restore default or previous states qglBlendEquation( GL_FUNC_ADD ); - if ( !blendEnabled ) + + if ( !blendEnabled ) { qglDisable( GL_BLEND ); - if( tex2Denabled ) + } + + if ( tex2Denabled ) { qglEnable( GL_TEXTURE_2D ); - if( scissorEnabled ) + } + + if ( scissorEnabled ) { qglEnable( GL_SCISSOR_TEST ); + } } // force a gl sync if requested @@ -621,13 +637,13 @@ Copy part of the current framebuffer to an image const void RB_CopyRender( const void *data ) { const copyRenderCommand_t *cmd; - cmd = (const copyRenderCommand_t *)data; + cmd = ( const copyRenderCommand_t * )data; if ( r_skipCopyTexture.GetBool() ) { return; } - if (cmd->image) { + if ( cmd->image ) { cmd->image->CopyFramebuffer( cmd->x, cmd->y, cmd->imageWidth, cmd->imageHeight, false ); } } @@ -640,7 +656,7 @@ This function will be called syncronously if running without smp extensions, or asyncronously by another thread. ==================== */ -int backEndStartTime, backEndFinishTime; +int backEndStartTime, backEndFinishTime; void RB_ExecuteBackEndCommands( const emptyCommand_t *cmds ) { // r_debugRenderToTexture int c_draw3d = 0, c_draw2d = 0, c_setBuffers = 0, c_swapBuffers = 0, c_copyRenders = 0; @@ -648,7 +664,6 @@ void RB_ExecuteBackEndCommands( const emptyCommand_t *cmds ) { if ( cmds->commandId == RC_NOP && !cmds->next ) { return; } - backEndStartTime = Sys_Milliseconds(); // needed for editor rendering @@ -657,16 +672,15 @@ void RB_ExecuteBackEndCommands( const emptyCommand_t *cmds ) { // upload any image loads that have completed globalImages->CompleteBackgroundImageLoads(); - for ( ; cmds ; cmds = (const emptyCommand_t *)cmds->next ) { + for ( ; cmds ; cmds = ( const emptyCommand_t * )cmds->next ) { switch ( cmds->commandId ) { case RC_NOP: break; case RC_DRAW_VIEW: RB_DrawView( cmds ); - if ( ((const drawSurfsCommand_t *)cmds)->viewDef->viewEntitys ) { + if ( ( ( const drawSurfsCommand_t * )cmds )->viewDef->viewEntitys ) { c_draw3d++; - } - else { + } else { c_draw2d++; } break; diff --git a/neo/renderer/tr_deform.cpp b/neo/renderer/tr_deform.cpp index 7d50a6156..4c892968a 100644 --- a/neo/renderer/tr_deform.cpp +++ b/neo/renderer/tr_deform.cpp @@ -29,7 +29,6 @@ If you have questions concerning this license or the applicable additional terms #include "sys/platform.h" #include "idlib/containers/BinSearch.h" #include "renderer/VertexCache.h" - #include "renderer/tr_local.h" @@ -85,15 +84,17 @@ static void R_AutospriteDeform( drawSurf_t *surf ) { tri = surf->geo; + // lots of mods use this function and not allways honoring + // restrictions, so turn the warning into a debug warning. if ( tri->numVerts & 3 ) { - common->Warning( "R_AutospriteDeform: shader had odd vertex count" ); + common->DWarning( "R_AutospriteDeform: shader had odd vertex count" ); return; } + if ( tri->numIndexes != ( tri->numVerts >> 2 ) * 6 ) { - common->Warning( "R_AutospriteDeform: autosprite had odd index count" ); + common->DWarning( "R_AutospriteDeform: autosprite had odd index count" ); return; } - R_GlobalVectorToLocal( surf->space->modelMatrix, tr.viewDef->renderView.viewaxis[1], leftDir ); R_GlobalVectorToLocal( surf->space->modelMatrix, tr.viewDef->renderView.viewaxis[2], upDir ); @@ -145,7 +146,6 @@ static void R_AutospriteDeform( drawSurf_t *surf ) { newTri->indexes[6*(i>>2)+4] = i+2; newTri->indexes[6*(i>>2)+5] = i+3; } - R_FinishDeform( surf, newTri, ac ); } @@ -165,20 +165,21 @@ static void R_TubeDeform( drawSurf_t *surf ) { int i, j; int indexes; const srfTriangles_t *tri; -static int edgeVerts[6][2] = { - { 0, 1 }, - { 1, 2 }, - { 2, 0 }, - { 3, 4 }, - { 4, 5 }, - { 5, 3 } -}; + static int edgeVerts[6][2] = { + { 0, 1 }, + { 1, 2 }, + { 2, 0 }, + { 3, 4 }, + { 4, 5 }, + { 5, 3 } + }; tri = surf->geo; if ( tri->numVerts & 3 ) { common->Error( "R_AutospriteDeform: shader had odd vertex count" ); } + if ( tri->numIndexes != ( tri->numVerts >> 2 ) * 6 ) { common->Error( "R_AutospriteDeform: autosprite had odd index count" ); } @@ -273,7 +274,6 @@ static int edgeVerts[6][2] = { } } } - R_FinishDeform( surf, newTri, ac ); } @@ -286,7 +286,6 @@ R_WindingFromTriangles #define MAX_TRI_WINDING_INDEXES 16 int R_WindingFromTriangles( const srfTriangles_t *tri, glIndex_t indexes[MAX_TRI_WINDING_INDEXES] ) { int i, j, k, l; - indexes[0] = tri->indexes[0]; int numIndexes = 1; int numTris = tri->numIndexes / 3; @@ -312,6 +311,7 @@ int R_WindingFromTriangles( const srfTriangles_t *tri, glIndex_t indexes[MAX_TRI break; } } + if ( k != numIndexes ) { continue; } @@ -322,6 +322,7 @@ int R_WindingFromTriangles( const srfTriangles_t *tri, glIndex_t indexes[MAX_TRI if ( k == i ) { continue; } + for ( l = 0 ; l < 3 ; l++ ) { int a, b; @@ -330,6 +331,7 @@ int R_WindingFromTriangles( const srfTriangles_t *tri, glIndex_t indexes[MAX_TRI continue; } b = tri->indexes[k*3+(l+1)%3]; + if ( b != indexes[numIndexes-1] ) { continue; } @@ -337,10 +339,12 @@ int R_WindingFromTriangles( const srfTriangles_t *tri, glIndex_t indexes[MAX_TRI // this is an interior edge break; } + if ( l != 3 ) { break; } } + if ( k != numTris ) { continue; } @@ -350,10 +354,12 @@ int R_WindingFromTriangles( const srfTriangles_t *tri, glIndex_t indexes[MAX_TRI numIndexes++; break; } + if ( j != 3 ) { break; } } + if ( numIndexes == tri->numVerts ) { break; } @@ -365,148 +371,8 @@ int R_WindingFromTriangles( const srfTriangles_t *tri, glIndex_t indexes[MAX_TRI /* ===================== R_FlareDeform - ===================== */ -/* -static void R_FlareDeform( drawSurf_t *surf ) { - const srfTriangles_t *tri; - srfTriangles_t *newTri; - idPlane plane; - float dot; - idVec3 localViewer; - int j; - - tri = surf->geo; - - if ( tri->numVerts != 4 || tri->numIndexes != 6 ) { - //FIXME: temp hack for flares on tripleted models - common->Warning( "R_FlareDeform: not a single quad" ); - return; - } - - // this srfTriangles_t and all its indexes and caches are in frame - // memory, and will be automatically disposed of - newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ) ); - newTri->numVerts = 4; - newTri->numIndexes = 2*3; - newTri->indexes = (glIndex_t *)R_FrameAlloc( newTri->numIndexes * sizeof( newTri->indexes[0] ) ); - - idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) ); - - // find the plane - plane.FromPoints( tri->verts[tri->indexes[0]].xyz, tri->verts[tri->indexes[1]].xyz, tri->verts[tri->indexes[2]].xyz ); - - // if viewer is behind the plane, draw nothing - R_GlobalPointToLocal( surf->space->modelMatrix, tr.viewDef->renderView.vieworg, localViewer ); - float distFromPlane = localViewer * plane.Normal() + plane[3]; - if ( distFromPlane <= 0 ) { - newTri->numIndexes = 0; - surf->geo = newTri; - return; - } - - idVec3 center; - center = tri->verts[0].xyz; - for ( j = 1 ; j < tri->numVerts ; j++ ) { - center += tri->verts[j].xyz; - } - center *= 1.0/tri->numVerts; - - idVec3 dir = localViewer - center; - dir.Normalize(); - - dot = dir * plane.Normal(); - - // set vertex colors based on plane angle - int color = (int)(dot * 8 * 256); - if ( color > 255 ) { - color = 255; - } - for ( j = 0 ; j < newTri->numVerts ; j++ ) { - ac[j].color[0] = - ac[j].color[1] = - ac[j].color[2] = color; - ac[j].color[3] = 255; - } - - float spread = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ] * r_flareSize.GetFloat(); - idVec3 edgeDir[4][3]; - glIndex_t indexes[MAX_TRI_WINDING_INDEXES]; - int numIndexes = R_WindingFromTriangles( tri, indexes ); - - surf->material = declManager->FindMaterial( "textures/smf/anamorphicFlare" ); - - // only deal with quads - if ( numIndexes != 4 ) { - return; - } - - // compute centroid - idVec3 centroid, toeye, forward, up, left; - centroid.Set( 0, 0, 0 ); - for ( int i = 0; i < 4; i++ ) { - centroid += tri->verts[ indexes[i] ].xyz; - } - centroid /= 4; - - // compute basis vectors - up.Set( 0, 0, 1 ); - - toeye = centroid - localViewer; - toeye.Normalize(); - left = toeye.Cross( up ); - up = left.Cross( toeye ); - - left = left * 40 * 6; - up = up * 40; - - // compute flares - struct flare_t { - float angle; - float length; - }; - - static flare_t flares[] = { - { 0, 100 }, - { 90, 100 } - }; - - for ( int i = 0; i < 4; i++ ) { - memset( ac + i, 0, sizeof( ac[i] ) ); - } - - ac[0].xyz = centroid - left; - ac[0].st[0] = 0; ac[0].st[1] = 0; - - ac[1].xyz = centroid + up; - ac[1].st[0] = 1; ac[1].st[1] = 0; - - ac[2].xyz = centroid + left; - ac[2].st[0] = 1; ac[2].st[1] = 1; - - ac[3].xyz = centroid - up; - ac[3].st[0] = 0; ac[3].st[1] = 1; - - // setup colors - for ( j = 0 ; j < newTri->numVerts ; j++ ) { - ac[j].color[0] = - ac[j].color[1] = - ac[j].color[2] = 255; - ac[j].color[3] = 255; - } - - // setup indexes - static glIndex_t triIndexes[2*3] = { - 0,1,2, 0,2,3 - }; - - memcpy( newTri->indexes, triIndexes, sizeof( triIndexes ) ); - - R_FinishDeform( surf, newTri, ac ); -} -*/ - static void R_FlareDeform( drawSurf_t *surf ) { const srfTriangles_t *tri; srfTriangles_t *newTri; @@ -540,15 +406,15 @@ static void R_FlareDeform( drawSurf_t *surf ) { // if viewer is behind the plane, draw nothing R_GlobalPointToLocal( surf->space->modelMatrix, tr.viewDef->renderView.vieworg, localViewer ); + float distFromPlane = localViewer * plane.Normal() + plane[3]; if ( distFromPlane <= 0 ) { newTri->numIndexes = 0; surf->geo = newTri; return; } + idVec3 center = tri->verts[0].xyz; - idVec3 center; - center = tri->verts[0].xyz; for ( j = 1 ; j < tri->numVerts ; j++ ) { center += tri->verts[j].xyz; } @@ -556,7 +422,6 @@ static void R_FlareDeform( drawSurf_t *surf ) { idVec3 dir = localViewer - center; dir.Normalize(); - dot = dir * plane.Normal(); // set vertex colors based on plane angle @@ -564,24 +429,24 @@ static void R_FlareDeform( drawSurf_t *surf ) { if ( color > 255 ) { color = 255; } + for ( j = 0 ; j < newTri->numVerts ; j++ ) { ac[j].color[0] = ac[j].color[1] = ac[j].color[2] = color; ac[j].color[3] = 255; } - - float spread = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ] * r_flareSize.GetFloat(); - idVec3 edgeDir[4][3]; - glIndex_t indexes[MAX_TRI_WINDING_INDEXES]; - int numIndexes = R_WindingFromTriangles( tri, indexes ); - + float spread = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ] * r_flareSize.GetFloat(); + idVec3 edgeDir[4][3]; + glIndex_t indexes[MAX_TRI_WINDING_INDEXES]; + int numIndexes = R_WindingFromTriangles( tri, indexes ); // only deal with quads if ( numIndexes != 4 ) { return; } int i; + // calculate vector directions for ( i = 0 ; i < 4 ; i++ ) { ac[i].xyz = tri->verts[ indexes[i] ].xyz; @@ -661,16 +526,12 @@ static void R_FlareDeform( drawSurf_t *surf ) { for ( i = 4 ; i < 16 ; i++ ) { idVec3 dir = ac[i].xyz - localViewer; float len = dir.Normalize(); - float ang = dir * plane.Normal(); - -// ac[i].xyz -= dir * spread * 2; float newLen = -( distFromPlane / ang ); if ( newLen > 0 && newLen < len ) { ac[i].xyz = localViewer + dir * newLen; } - ac[i].st[0] = 0; ac[i].st[1] = 0.5; } @@ -693,8 +554,6 @@ static void R_FlareDeform( drawSurf_t *surf ) { R_FinishDeform( surf, newTri, ac ); } - - /* ===================== R_ExpandDeform @@ -703,9 +562,9 @@ Expands the surface along it's normals by a shader amount ===================== */ static void R_ExpandDeform( drawSurf_t *surf ) { - int i; + int i; const srfTriangles_t *tri; - srfTriangles_t *newTri; + srfTriangles_t *newTri; tri = surf->geo; @@ -717,13 +576,11 @@ static void R_ExpandDeform( drawSurf_t *surf ) { newTri->indexes = tri->indexes; idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) ); - float dist = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ]; for ( i = 0 ; i < tri->numVerts ; i++ ) { ac[i] = *(idDrawVert *)&tri->verts[i]; ac[i].xyz = tri->verts[i].xyz + tri->verts[i].normal * dist; } - R_FinishDeform( surf, newTri, ac ); } @@ -749,13 +606,11 @@ static void R_MoveDeform( drawSurf_t *surf ) { newTri->indexes = tri->indexes; idDrawVert *ac = (idDrawVert *)_alloca16( newTri->numVerts * sizeof( idDrawVert ) ); - float dist = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ]; for ( i = 0 ; i < tri->numVerts ; i++ ) { ac[i] = *(idDrawVert *)&tri->verts[i]; ac[i].xyz[0] += dist; } - R_FinishDeform( surf, newTri, ac ); } @@ -801,7 +656,6 @@ static void R_TurbulentDeform( drawSurf_t *surf ) { ac[i].st[0] += range * table->TableLookup( f ); ac[i].st[1] += range * table->TableLookup( f + tOfs ); } - R_FinishDeform( surf, newTri, ac ); } @@ -849,15 +703,16 @@ static void AddTriangleToIsland_r( const srfTriangles_t *tri, int triangleNum, b if ( usedList[i] ) { continue; } - if ( tri->indexes[i*3+0] == a - || tri->indexes[i*3+1] == a - || tri->indexes[i*3+2] == a - || tri->indexes[i*3+0] == b - || tri->indexes[i*3+1] == b - || tri->indexes[i*3+2] == b - || tri->indexes[i*3+0] == c - || tri->indexes[i*3+1] == c - || tri->indexes[i*3+2] == c ) { + + if ( tri->indexes[i*3+0] == a || + tri->indexes[i*3+1] == a || + tri->indexes[i*3+2] == a || + tri->indexes[i*3+0] == b || + tri->indexes[i*3+1] == b || + tri->indexes[i*3+2] == b || + tri->indexes[i*3+0] == c || + tri->indexes[i*3+1] == c || + tri->indexes[i*3+2] == c ) { AddTriangleToIsland_r( tri, i, usedList, island ); } } @@ -872,12 +727,12 @@ pointing out the eye, and another single triangle in front of the eye for the fo ===================== */ static void R_EyeballDeform( drawSurf_t *surf ) { - int i, j, k; + int i, j, k; const srfTriangles_t *tri; - srfTriangles_t *newTri; - eyeIsland_t islands[MAX_EYEBALL_ISLANDS]; - int numIslands; - bool triUsed[MAX_EYEBALL_ISLANDS*MAX_EYEBALL_TRIS]; + srfTriangles_t *newTri; + eyeIsland_t islands[MAX_EYEBALL_ISLANDS]; + int numIslands; + bool triUsed[MAX_EYEBALL_ISLANDS*MAX_EYEBALL_TRIS]; tri = surf->geo; @@ -892,12 +747,14 @@ static void R_EyeballDeform( drawSurf_t *surf ) { for ( numIslands = 0 ; numIslands < MAX_EYEBALL_ISLANDS ; numIslands++ ) { islands[numIslands].numTris = 0; islands[numIslands].bounds.Clear(); + for ( i = 0 ; i < numTri ; i++ ) { if ( !triUsed[i] ) { AddTriangleToIsland_r( tri, i, triUsed, &islands[numIslands] ); break; } } + if ( i == numTri ) { break; } @@ -943,8 +800,10 @@ static void R_EyeballDeform( drawSurf_t *surf ) { for ( j = 0 ; j < numIslands ; j++ ) { idVec3 dir = islands[j].mid - island->mid; + dist[j] = dir.Length(); sortOrder[j] = j; + for ( k = j-1 ; k >= 0 ; k-- ) { if ( dist[k] > dist[k+1] ) { int temp = sortOrder[k]; @@ -956,10 +815,8 @@ static void R_EyeballDeform( drawSurf_t *surf ) { } } } - originIsland = sortOrder[1]; origin = islands[originIsland].mid; - focus = islands[sortOrder[2]].mid; // determine the projection directions based on the origin island triangle @@ -979,7 +836,6 @@ static void R_EyeballDeform( drawSurf_t *surf ) { idVec3 texVec[2]; texVec[0].Cross( v1, v2 ); - texVec[1].Cross( texVec[0], dir ); for ( j = 0 ; j < 2 ; j++ ) { @@ -988,7 +844,6 @@ static void R_EyeballDeform( drawSurf_t *surf ) { } // emit these triangles, generating the projected texcoords - for ( j = 0 ; j < islands[i].numTris ; j++ ) { for ( k = 0 ; k < 3 ; k++ ) { int index = islands[i].tris[j] * 3; @@ -1005,7 +860,6 @@ static void R_EyeballDeform( drawSurf_t *surf ) { } } } - R_FinishDeform( surf, newTri, ac ); } @@ -1039,17 +893,18 @@ static void R_ParticleDeform( drawSurf_t *surf, bool useArea ) { // // calculate the area of all the triangles // - int numSourceTris = surf->geo->numIndexes / 3; - float totalArea = 0; - float *sourceTriAreas = NULL; + int numSourceTris = surf->geo->numIndexes / 3; + float totalArea = 0; + float *sourceTriAreas = NULL; const srfTriangles_t *srcTri = surf->geo; if ( useArea ) { + int triNum = 0; + sourceTriAreas = (float *)_alloca( sizeof( *sourceTriAreas ) * numSourceTris ); - int triNum = 0; - for ( int i = 0 ; i < srcTri->numIndexes ; i += 3, triNum++ ) { - float area; - area = idWinding::TriangleArea( srcTri->verts[srcTri->indexes[i]].xyz, srcTri->verts[srcTri->indexes[i+1]].xyz, srcTri->verts[srcTri->indexes[i+2]].xyz ); + + for ( int i = 0; i < srcTri->numIndexes ; i += 3, triNum++ ) { + float area = idWinding::TriangleArea( srcTri->verts[srcTri->indexes[i]].xyz, srcTri->verts[srcTri->indexes[i+1]].xyz, srcTri->verts[srcTri->indexes[i+2]].xyz ); sourceTriAreas[triNum] = totalArea; totalArea += area; } @@ -1073,18 +928,19 @@ static void R_ParticleDeform( drawSurf_t *surf, bool useArea ) { if ( !stage->material ) { continue; } + if ( !stage->cycleMsec ) { continue; } + if ( stage->hidden ) { // just for gui particle editor use continue; } // we interpret stage->totalParticles as "particles per map square area" // so the systems look the same on different size surfaces - int totalParticles = ( useArea ) ? stage->totalParticles * totalArea / 4096.0 : ( stage->totalParticles ); - - int count = totalParticles * stage->NumQuadsPerParticle(); + int totalParticles = ( useArea ) ? stage->totalParticles * totalArea / 4096.0 : ( stage->totalParticles ); + int count = totalParticles * stage->NumQuadsPerParticle(); // allocate a srfTriangles in temp memory that can hold all the particles srfTriangles_t *tri; @@ -1118,13 +974,14 @@ static void R_ParticleDeform( drawSurf_t *surf, bool useArea ) { // calculate local age for this index int bunchOffset = stage->particleLife * 1000 * stage->spawnBunching * index / totalParticles; - int particleAge = stageAge - bunchOffset; int particleCycle = particleAge / stage->cycleMsec; + if ( particleCycle < 0 ) { // before the particleSystem spawned continue; } + if ( stage->cycles && particleCycle >= stage->cycles ) { // cycled systems will only run cycle times continue; @@ -1135,7 +992,6 @@ static void R_ParticleDeform( drawSurf_t *surf, bool useArea ) { } else { g.random = steppingRandom2; } - int inCycleTime = particleAge - particleCycle * stage->cycleMsec; if ( renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] && @@ -1146,10 +1002,12 @@ static void R_ParticleDeform( drawSurf_t *surf, bool useArea ) { // supress particles before or after the age clamp g.frac = (float)inCycleTime / ( stage->particleLife * 1000 ); + if ( g.frac < 0 ) { // yet to be spawned continue; } + if ( g.frac > 1.0 ) { // this particle is in the deadTime band continue; @@ -1158,7 +1016,6 @@ static void R_ParticleDeform( drawSurf_t *surf, bool useArea ) { //--------------- // locate the particle origin and axis somewhere on the surface //--------------- - int pointTri = currentTri; if ( useArea ) { @@ -1201,6 +1058,7 @@ static void R_ParticleDeform( drawSurf_t *surf, bool useArea ) { if ( tri->numVerts > 0 ) { // build the index list int indexes = 0; + for ( int i = 0 ; i < tri->numVerts ; i += 4 ) { tri->indexes[indexes+0] = i; tri->indexes[indexes+1] = i+2; @@ -1212,6 +1070,7 @@ static void R_ParticleDeform( drawSurf_t *surf, bool useArea ) { } tri->numIndexes = indexes; tri->ambientCache = vertexCache.AllocFrameTemp( tri->verts, tri->numVerts * sizeof( idDrawVert ) ); + if ( tri->ambientCache ) { // add the drawsurf R_AddDrawSurf( tri, surf->space, renderEntity, stage->material, surf->scissorRect ); @@ -1236,6 +1095,7 @@ void R_DeformDrawSurf( drawSurf_t *drawSurf ) { if ( r_skipDeforms.GetBool() ) { return; } + switch ( drawSurf->material->Deform() ) { case DFRM_NONE: return; diff --git a/neo/renderer/tr_guisurf.cpp b/neo/renderer/tr_guisurf.cpp index a90cbde1d..90e4f9f78 100644 --- a/neo/renderer/tr_guisurf.cpp +++ b/neo/renderer/tr_guisurf.cpp @@ -49,75 +49,75 @@ the axis will give a 0.0 to 1.0 range in S and T when inside the gui surface ================ */ void R_SurfaceToTextureAxis( const srfTriangles_t *tri, idVec3 &origin, idVec3 axis[3] ) { - float area, inva; - float d0[5], d1[5]; - idDrawVert *a, *b, *c; - float bounds[2][2]; - float boundsOrg[2]; - int i, j; - float v; - - // find the bounds of the texture - bounds[0][0] = bounds[0][1] = 999999; - bounds[1][0] = bounds[1][1] = -999999; - for ( i = 0 ; i < tri->numVerts ; i++ ) { - for ( j = 0 ; j < 2 ; j++ ) { - v = tri->verts[i].st[j]; - if ( v < bounds[0][j] ) { - bounds[0][j] = v; - } - if ( v > bounds[1][j] ) { - bounds[1][j] = v; - } - } - } - - // use the floor of the midpoint as the origin of the - // surface, which will prevent a slight misalignment - // from throwing it an entire cycle off - boundsOrg[0] = floor( ( bounds[0][0] + bounds[1][0] ) * 0.5 ); - boundsOrg[1] = floor( ( bounds[0][1] + bounds[1][1] ) * 0.5 ); - - - // determine the world S and T vectors from the first drawSurf triangle - a = tri->verts + tri->indexes[0]; - b = tri->verts + tri->indexes[1]; - c = tri->verts + tri->indexes[2]; - - VectorSubtract( b->xyz, a->xyz, d0 ); - d0[3] = b->st[0] - a->st[0]; - d0[4] = b->st[1] - a->st[1]; - VectorSubtract( c->xyz, a->xyz, d1 ); - d1[3] = c->st[0] - a->st[0]; - d1[4] = c->st[1] - a->st[1]; - - area = d0[3] * d1[4] - d0[4] * d1[3]; - if ( area == 0.0 ) { - origin.Zero(); - axis[0].Zero(); - axis[1].Zero(); - axis[2].Zero(); - return; // degenerate - } - inva = 1.0 / area; - - axis[0][0] = (d0[0] * d1[4] - d0[4] * d1[0]) * inva; - axis[0][1] = (d0[1] * d1[4] - d0[4] * d1[1]) * inva; - axis[0][2] = (d0[2] * d1[4] - d0[4] * d1[2]) * inva; - - axis[1][0] = (d0[3] * d1[0] - d0[0] * d1[3]) * inva; - axis[1][1] = (d0[3] * d1[1] - d0[1] * d1[3]) * inva; - axis[1][2] = (d0[3] * d1[2] - d0[2] * d1[3]) * inva; - - idPlane plane; - plane.FromPoints( a->xyz, b->xyz, c->xyz ); - axis[2][0] = plane[0]; - axis[2][1] = plane[1]; - axis[2][2] = plane[2]; - - // take point 0 and project the vectors to the texture origin - VectorMA( a->xyz, boundsOrg[0] - a->st[0], axis[0], origin ); - VectorMA( origin, boundsOrg[1] - a->st[1], axis[1], origin ); + float area, inva; + float d0[5], d1[5]; + idDrawVert *a, *b, *c; + float bounds[2][2]; + float boundsOrg[2]; + int i, j; + float v; + + // find the bounds of the texture + bounds[0][0] = bounds[0][1] = 999999; + bounds[1][0] = bounds[1][1] = -999999; + for ( i = 0 ; i < tri->numVerts ; i++ ) { + for ( j = 0 ; j < 2 ; j++ ) { + v = tri->verts[i].st[j]; + if ( v < bounds[0][j] ) { + bounds[0][j] = v; + } + if ( v > bounds[1][j] ) { + bounds[1][j] = v; + } + } + } + + // use the floor of the midpoint as the origin of the + // surface, which will prevent a slight misalignment + // from throwing it an entire cycle off + boundsOrg[0] = floor( ( bounds[0][0] + bounds[1][0] ) * 0.5 ); + boundsOrg[1] = floor( ( bounds[0][1] + bounds[1][1] ) * 0.5 ); + + + // determine the world S and T vectors from the first drawSurf triangle + a = tri->verts + tri->indexes[0]; + b = tri->verts + tri->indexes[1]; + c = tri->verts + tri->indexes[2]; + + VectorSubtract( b->xyz, a->xyz, d0 ); + d0[3] = b->st[0] - a->st[0]; + d0[4] = b->st[1] - a->st[1]; + VectorSubtract( c->xyz, a->xyz, d1 ); + d1[3] = c->st[0] - a->st[0]; + d1[4] = c->st[1] - a->st[1]; + + area = d0[3] * d1[4] - d0[4] * d1[3]; + if ( area == 0.0 ) { + origin.Zero(); + axis[0].Zero(); + axis[1].Zero(); + axis[2].Zero(); + return; // degenerate + } + inva = 1.0 / area; + + axis[0][0] = (d0[0] * d1[4] - d0[4] * d1[0]) * inva; + axis[0][1] = (d0[1] * d1[4] - d0[4] * d1[1]) * inva; + axis[0][2] = (d0[2] * d1[4] - d0[4] * d1[2]) * inva; + + axis[1][0] = (d0[3] * d1[0] - d0[0] * d1[3]) * inva; + axis[1][1] = (d0[3] * d1[1] - d0[1] * d1[3]) * inva; + axis[1][2] = (d0[3] * d1[2] - d0[2] * d1[3]) * inva; + + idPlane plane; + plane.FromPoints( a->xyz, b->xyz, c->xyz ); + axis[2][0] = plane[0]; + axis[2][1] = plane[1]; + axis[2][2] = plane[2]; + + // take point 0 and project the vectors to the texture origin + VectorMA( a->xyz, boundsOrg[0] - a->st[0], axis[0], origin ); + VectorMA( origin, boundsOrg[1] - a->st[1], axis[1], origin ); } /* @@ -129,58 +129,58 @@ call the GUI generator to create quads for it. ================= */ void R_RenderGuiSurf( idUserInterface *gui, drawSurf_t *drawSurf ) { - idVec3 origin, axis[3]; + idVec3 origin, axis[3]; - // for testing the performance hit - if ( r_skipGuiShaders.GetInteger() == 1 ) { - return; - } + // for testing the performance hit + if ( r_skipGuiShaders.GetInteger() == 1 ) { + return; + } - // don't allow an infinite recursion loop - if ( tr.guiRecursionLevel == 4 ) { - return; - } + // don't allow an infinite recursion loop + if ( tr.guiRecursionLevel == 4 ) { + return; + } - tr.pc.c_guiSurfs++; + tr.pc.c_guiSurfs++; - // create the new matrix to draw on this surface - R_SurfaceToTextureAxis( drawSurf->geo, origin, axis ); + // create the new matrix to draw on this surface + R_SurfaceToTextureAxis( drawSurf->geo, origin, axis ); - float guiModelMatrix[16]; - float modelMatrix[16]; + float guiModelMatrix[16]; + float modelMatrix[16]; - guiModelMatrix[0] = axis[0][0] / 640.0; - guiModelMatrix[4] = axis[1][0] / 480.0; - guiModelMatrix[8] = axis[2][0]; - guiModelMatrix[12] = origin[0]; + guiModelMatrix[0] = axis[0][0] / 640.0; + guiModelMatrix[4] = axis[1][0] / 480.0; + guiModelMatrix[8] = axis[2][0]; + guiModelMatrix[12] = origin[0]; - guiModelMatrix[1] = axis[0][1] / 640.0; - guiModelMatrix[5] = axis[1][1] / 480.0; - guiModelMatrix[9] = axis[2][1]; - guiModelMatrix[13] = origin[1]; + guiModelMatrix[1] = axis[0][1] / 640.0; + guiModelMatrix[5] = axis[1][1] / 480.0; + guiModelMatrix[9] = axis[2][1]; + guiModelMatrix[13] = origin[1]; - guiModelMatrix[2] = axis[0][2] / 640.0; - guiModelMatrix[6] = axis[1][2] / 480.0; - guiModelMatrix[10] = axis[2][2]; - guiModelMatrix[14] = origin[2]; + guiModelMatrix[2] = axis[0][2] / 640.0; + guiModelMatrix[6] = axis[1][2] / 480.0; + guiModelMatrix[10] = axis[2][2]; + guiModelMatrix[14] = origin[2]; - guiModelMatrix[3] = 0; - guiModelMatrix[7] = 0; - guiModelMatrix[11] = 0; - guiModelMatrix[15] = 1; + guiModelMatrix[3] = 0; + guiModelMatrix[7] = 0; + guiModelMatrix[11] = 0; + guiModelMatrix[15] = 1; - myGlMultMatrix( guiModelMatrix, drawSurf->space->modelMatrix, - modelMatrix ); + R_MatrixMultiply( guiModelMatrix, drawSurf->space->modelMatrix, + modelMatrix ); - tr.guiRecursionLevel++; + tr.guiRecursionLevel++; - // call the gui, which will call the 2D drawing functions - tr.guiModel->Clear(); - gui->Redraw( tr.viewDef->renderView.time ); - tr.guiModel->EmitToCurrentView( modelMatrix, drawSurf->space->weaponDepthHack ); - tr.guiModel->Clear(); + // call the gui, which will call the 2D drawing functions + tr.guiModel->Clear(); + gui->Redraw( tr.viewDef->renderView.time ); + tr.guiModel->EmitToCurrentView( modelMatrix, drawSurf->space->weaponDepthHack ); + tr.guiModel->Clear(); - tr.guiRecursionLevel--; + tr.guiRecursionLevel--; } @@ -198,17 +198,17 @@ Should we also reload the map models? ================ */ void R_ReloadGuis_f( const idCmdArgs &args ) { - bool all; + bool all; - if ( !idStr::Icmp( args.Argv(1), "all" ) ) { - all = true; - common->Printf( "Reloading all gui files...\n" ); - } else { - all = false; - common->Printf( "Checking for changed gui files...\n" ); - } + if ( !idStr::Icmp( args.Argv(1), "all" ) ) { + all = true; + common->Printf( "Reloading all gui files...\n" ); + } else { + all = false; + common->Printf( "Checking for changed gui files...\n" ); + } - uiManager->Reload( all ); + uiManager->Reload( all ); } /* @@ -218,5 +218,5 @@ R_ListGuis_f ================ */ void R_ListGuis_f( const idCmdArgs &args ) { - uiManager->ListGuis(); + uiManager->ListGuis(); } diff --git a/neo/renderer/tr_light.cpp b/neo/renderer/tr_light.cpp index 6b2db540c..ee0200528 100644 --- a/neo/renderer/tr_light.cpp +++ b/neo/renderer/tr_light.cpp @@ -59,12 +59,13 @@ bool R_CreateAmbientCache( srfTriangles_t *tri, bool needsLighting ) { if ( tri->ambientCache ) { return true; } + // we are going to use it for drawing, so make sure we have the tangents and normals if ( needsLighting && !tri->tangentsCalculated ) { R_DeriveTangents( tri ); } - vertexCache.Alloc( tri->verts, tri->numVerts * sizeof( tri->verts[0] ), &tri->ambientCache ); + if ( !tri->ambientCache ) { return false; } @@ -79,7 +80,7 @@ Returns false if the cache couldn't be allocated, in which case the surface shou ================== */ bool R_CreateLightingCache( const idRenderEntityLocal *ent, const idRenderLightLocal *light, srfTriangles_t *tri ) { - idVec3 localLightOrigin; + idVec3 localLightOrigin; // fogs and blends don't need light vectors if ( light->lightShader->IsFogLight() || light->lightShader->IsBlendLight() ) { @@ -90,26 +91,26 @@ bool R_CreateLightingCache( const idRenderEntityLocal *ent, const idRenderLightL if ( tr.backEndRendererHasVertexPrograms ) { return true; } - R_GlobalPointToLocal( ent->modelMatrix, light->globalLightOrigin, localLightOrigin ); - int size = tri->ambientSurface->numVerts * sizeof( lightingCache_t ); - lightingCache_t *cache = (lightingCache_t *)_alloca16( size ); + int size = tri->ambientSurface->numVerts * sizeof( lightingCache_t ); + lightingCache_t *cache = ( lightingCache_t * )_alloca16( size ); #if 1 SIMDProcessor->CreateTextureSpaceLightVectors( &cache[0].localLightVector, localLightOrigin, - tri->ambientSurface->verts, tri->ambientSurface->numVerts, tri->indexes, tri->numIndexes ); + tri->ambientSurface->verts, tri->ambientSurface->numVerts, tri->indexes, tri->numIndexes ); #else - bool *used = (bool *)_alloca16( tri->ambientSurface->numVerts * sizeof( used[0] ) ); + bool *used = ( bool * )_alloca16( tri->ambientSurface->numVerts * sizeof( used[0] ) ); memset( used, 0, tri->ambientSurface->numVerts * sizeof( used[0] ) ); // because the interaction may be a very small subset of the full surface, // it makes sense to only deal with the verts used for ( int j = 0; j < tri->numIndexes; j++ ) { int i = tri->indexes[j]; + if ( used[i] ) { continue; } @@ -130,6 +131,7 @@ bool R_CreateLightingCache( const idRenderEntityLocal *ent, const idRenderLightL #endif vertexCache.Alloc( cache, size, &tri->lightingCache ); + if ( !tri->lightingCache ) { return false; } @@ -147,7 +149,6 @@ void R_CreatePrivateShadowCache( srfTriangles_t *tri ) { if ( !tri->shadowVertexes ) { return; } - vertexCache.Alloc( tri->shadowVertexes, tri->numVerts * sizeof( *tri->shadowVertexes ), &tri->shadowCache ); } @@ -163,10 +164,7 @@ void R_CreateVertexProgramShadowCache( srfTriangles_t *tri ) { if ( tri->verts == NULL ) { return; } - - // DG: use Mem_MallocA() instead of _alloca16() to avoid stack overflows with big models - bool tempOnStack; - shadowCache_t *temp = (shadowCache_t *)Mem_MallocA( tri->numVerts * 2 * sizeof( shadowCache_t ), tempOnStack ); + shadowCache_t *temp = ( shadowCache_t * )_alloca16( tri->numVerts * 2 * sizeof( shadowCache_t ) ); #if 1 @@ -178,20 +176,19 @@ void R_CreateVertexProgramShadowCache( srfTriangles_t *tri ) { const idDrawVert *verts = tri->verts; for ( int i = 0; i < numVerts; i++ ) { const float *v = verts[i].xyz.ToFloatPtr(); - temp[i*2+0].xyz[0] = v[0]; - temp[i*2+1].xyz[0] = v[0]; - temp[i*2+0].xyz[1] = v[1]; - temp[i*2+1].xyz[1] = v[1]; - temp[i*2+0].xyz[2] = v[2]; - temp[i*2+1].xyz[2] = v[2]; - temp[i*2+0].xyz[3] = 1.0f; // on the model surface - temp[i*2+1].xyz[3] = 0.0f; // will be projected to infinity + temp[i * 2 + 0].xyz[0] = v[0]; + temp[i * 2 + 1].xyz[0] = v[0]; + temp[i * 2 + 0].xyz[1] = v[1]; + temp[i * 2 + 1].xyz[1] = v[1]; + temp[i * 2 + 0].xyz[2] = v[2]; + temp[i * 2 + 1].xyz[2] = v[2]; + temp[i * 2 + 0].xyz[3] = 1.0f; // on the model surface + temp[i * 2 + 1].xyz[3] = 0.0f; // will be projected to infinity } #endif vertexCache.Alloc( temp, tri->numVerts * 2 * sizeof( shadowCache_t ), &tri->shadowCache ); - Mem_FreeA( temp, tempOnStack ); } /* @@ -200,22 +197,20 @@ R_SkyboxTexGen ================== */ void R_SkyboxTexGen( drawSurf_t *surf, const idVec3 &viewOrg ) { - int i; - idVec3 localViewOrigin; + int i; + idVec3 localViewOrigin; R_GlobalPointToLocal( surf->space->modelMatrix, viewOrg, localViewOrigin ); int numVerts = surf->geo->numVerts; int size = numVerts * sizeof( idVec3 ); - idVec3 *texCoords = (idVec3 *) _alloca16( size ); - + idVec3 *texCoords = ( idVec3 * ) _alloca16( size ); const idDrawVert *verts = surf->geo->verts; for ( i = 0; i < numVerts; i++ ) { texCoords[i][0] = verts[i].xyz[0] - localViewOrigin[0]; texCoords[i][1] = verts[i].xyz[1] - localViewOrigin[1]; texCoords[i][2] = verts[i].xyz[2] - localViewOrigin[2]; } - surf->dynamicTexCoords = vertexCache.AllocFrameTemp( texCoords, size ); } @@ -225,27 +220,27 @@ R_WobbleskyTexGen ================== */ void R_WobbleskyTexGen( drawSurf_t *surf, const idVec3 &viewOrg ) { - int i; - idVec3 localViewOrigin; + int i; + idVec3 localViewOrigin; const int *parms = surf->material->GetTexGenRegisters(); - float wobbleDegrees = surf->shaderRegisters[ parms[0] ]; - float wobbleSpeed = surf->shaderRegisters[ parms[1] ]; - float rotateSpeed = surf->shaderRegisters[ parms[2] ]; + float wobbleDegrees = surf->shaderRegisters[ parms[0] ]; + float wobbleSpeed = surf->shaderRegisters[ parms[1] ]; + float rotateSpeed = surf->shaderRegisters[ parms[2] ]; wobbleDegrees = wobbleDegrees * idMath::PI / 180; wobbleSpeed = wobbleSpeed * 2 * idMath::PI / 60; rotateSpeed = rotateSpeed * 2 * idMath::PI / 60; // very ad-hoc "wobble" transform - float transform[16]; - float a = tr.viewDef->floatTime * wobbleSpeed; - float s = sin( a ) * sin( wobbleDegrees ); - float c = cos( a ) * sin( wobbleDegrees ); - float z = cos( wobbleDegrees ); + float transform[16]; + float a = tr.viewDef->floatTime * wobbleSpeed; + float s = sin( a ) * sin( wobbleDegrees ); + float c = cos( a ) * sin( wobbleDegrees ); + float z = cos( wobbleDegrees ); - idVec3 axis[3]; + idVec3 axis[3]; axis[2][0] = c; axis[2][1] = s; @@ -285,8 +280,7 @@ void R_WobbleskyTexGen( drawSurf_t *surf, const idVec3 &viewOrg ) { int numVerts = surf->geo->numVerts; int size = numVerts * sizeof( idVec3 ); - idVec3 *texCoords = (idVec3 *) _alloca16( size ); - + idVec3 *texCoords = ( idVec3 * ) _alloca16( size ); const idDrawVert *verts = surf->geo->verts; for ( i = 0; i < numVerts; i++ ) { idVec3 v; @@ -297,7 +291,6 @@ void R_WobbleskyTexGen( drawSurf_t *surf, const idVec3 &viewOrg ) { R_LocalPointToGlobal( transform, v, texCoords[i] ); } - surf->dynamicTexCoords = vertexCache.AllocFrameTemp( texCoords, size ); } @@ -310,8 +303,8 @@ Calculates the specular coordinates for cards without vertex programs. */ static void R_SpecularTexGen( drawSurf_t *surf, const idVec3 &globalLightOrigin, const idVec3 &viewOrg ) { const srfTriangles_t *tri; - idVec3 localLightOrigin; - idVec3 localViewOrigin; + idVec3 localLightOrigin; + idVec3 localViewOrigin; R_GlobalPointToLocal( surf->space->modelMatrix, globalLightOrigin, localLightOrigin ); R_GlobalPointToLocal( surf->space->modelMatrix, viewOrg, localViewOrigin ); @@ -319,23 +312,24 @@ static void R_SpecularTexGen( drawSurf_t *surf, const idVec3 &globalLightOrigin, tri = surf->geo; // FIXME: change to 3 component? - int size = tri->numVerts * sizeof( idVec4 ); - idVec4 *texCoords = (idVec4 *) _alloca16( size ); + int size = tri->numVerts * sizeof( idVec4 ); + idVec4 *texCoords = ( idVec4 * ) _alloca16( size ); #if 1 SIMDProcessor->CreateSpecularTextureCoords( texCoords, localLightOrigin, localViewOrigin, - tri->verts, tri->numVerts, tri->indexes, tri->numIndexes ); + tri->verts, tri->numVerts, tri->indexes, tri->numIndexes ); #else - bool *used = (bool *)_alloca16( tri->numVerts * sizeof( used[0] ) ); + bool *used = ( bool * )_alloca16( tri->numVerts * sizeof( used[0] ) ); memset( used, 0, tri->numVerts * sizeof( used[0] ) ); // because the interaction may be a very small subset of the full surface, // it makes sense to only deal with the verts used for ( int j = 0; j < tri->numIndexes; j++ ) { int i = tri->indexes[j]; + if ( used[i] ) { continue; } @@ -385,7 +379,7 @@ This does not instantiate dynamic models for the entity yet. ============= */ viewEntity_t *R_SetEntityDefViewEntity( idRenderEntityLocal *def ) { - viewEntity_t *vModel; + viewEntity_t *vModel; if ( def->viewCount == tr.viewCount ) { return def->viewEntity; @@ -393,7 +387,7 @@ viewEntity_t *R_SetEntityDefViewEntity( idRenderEntityLocal *def ) { def->viewCount = tr.viewCount; // set the model and modelview matricies - vModel = (viewEntity_t *)R_ClearedFrameAlloc( sizeof( *vModel ) ); + vModel = ( viewEntity_t * )R_ClearedFrameAlloc( sizeof( *vModel ) ); vModel->entityDef = def; // the scissorRect will be expanded as the model bounds is accepted into visible portal chains @@ -407,12 +401,11 @@ viewEntity_t *R_SetEntityDefViewEntity( idRenderEntityLocal *def ) { // we may not have a viewDef if we are just creating shadows at entity creation time if ( tr.viewDef ) { - myGlMultMatrix( vModel->modelMatrix, tr.viewDef->worldSpace.modelViewMatrix, vModel->modelViewMatrix ); + R_MatrixMultiply( vModel->modelMatrix, tr.viewDef->worldSpace.modelViewMatrix, vModel->modelViewMatrix ); vModel->next = tr.viewDef->viewEntitys; tr.viewDef->viewEntitys = vModel; } - def->viewEntity = vModel; return vModel; @@ -426,16 +419,16 @@ R_TestPointInViewLight static const float INSIDE_LIGHT_FRUSTUM_SLOP = 32; // this needs to be greater than the dist from origin to corner of near clip plane static bool R_TestPointInViewLight( const idVec3 &org, const idRenderLightLocal *light ) { - int i; - idVec3 local; + int i; + idVec3 local; for ( i = 0 ; i < 6 ; i++ ) { float d = light->frustum[i].Distance( org ); + if ( d > INSIDE_LIGHT_FRUSTUM_SLOP ) { return false; } } - return true; } @@ -449,6 +442,7 @@ Assumes positive sides face outward static bool R_PointInFrustum( idVec3 &p, idPlane *planes, int numPlanes ) { for ( int i = 0 ; i < numPlanes ; i++ ) { float d = planes[i].Distance( p ); + if ( d > 0 ) { return false; } @@ -473,7 +467,7 @@ viewLight_t *R_SetLightDefViewLight( idRenderLightLocal *light ) { light->viewCount = tr.viewCount; // add to the view light chain - vLight = (viewLight_t *)R_ClearedFrameAlloc( sizeof( *vLight ) ); + vLight = ( viewLight_t * )R_ClearedFrameAlloc( sizeof( *vLight ) ); vLight->lightDef = light; // the scissorRect will be expanded as the light bounds is accepted into visible portal chains @@ -481,12 +475,15 @@ viewLight_t *R_SetLightDefViewLight( idRenderLightLocal *light ) { // calculate the shadow cap optimization states vLight->viewInsideLight = R_TestPointInViewLight( tr.viewDef->renderView.vieworg, light ); + if ( !vLight->viewInsideLight ) { vLight->viewSeesShadowPlaneBits = 0; + for ( int i = 0 ; i < light->numShadowFrustums ; i++ ) { float d = light->shadowFrustums[i].planes[5].Distance( tr.viewDef->renderView.vieworg ); + if ( d < INSIDE_LIGHT_FRUSTUM_SLOP ) { - vLight->viewSeesShadowPlaneBits|= 1 << i; + vLight->viewSeesShadowPlaneBits |= 1 << i; } } } else { @@ -507,7 +504,7 @@ viewLight_t *R_SetLightDefViewLight( idRenderLightLocal *light ) { vLight->frustumTris = light->frustumTris; vLight->falloffImage = light->falloffImage; vLight->lightShader = light->lightShader; - vLight->shaderRegisters = NULL; // allocated and evaluated in R_AddLightSurfaces + vLight->shaderRegisters = NULL; // allocated and evaluated in R_AddLightSurfaces // link the view light vLight->next = tr.viewDef->viewLights; @@ -548,11 +545,11 @@ Both shadow and light surfaces have been generated. Either or both surfaces may ================= */ void idRenderWorldLocal::CreateLightDefInteractions( idRenderLightLocal *ldef ) { - areaReference_t *eref; - areaReference_t *lref; - idRenderEntityLocal *edef; - portalArea_t *area; - idInteraction *inter; + areaReference_t *eref; + areaReference_t *lref; + idRenderEntityLocal *edef; + portalArea_t *area; + idInteraction *inter; for ( lref = ldef->references ; lref ; lref = lref->ownerNext ) { area = lref->area; @@ -571,11 +568,13 @@ void idRenderWorldLocal::CreateLightDefInteractions( idRenderLightLocal *ldef ) if ( !ldef->lightShader->LightCastsShadows() ) { continue; } + // if we are suppressing its shadow in this view, skip if ( !r_skipSuppress.GetBool() ) { if ( edef->parms.suppressShadowInViewID && edef->parms.suppressShadowInViewID == tr.viewDef->renderView.viewID ) { continue; } + if ( edef->parms.suppressShadowInLightID && edef->parms.suppressShadowInLightID == ldef->parms.lightId ) { continue; } @@ -594,7 +593,9 @@ void idRenderWorldLocal::CreateLightDefInteractions( idRenderLightLocal *ldef ) // allocating these tables may take several megs on big maps, but it saves 3% to 5% of // the CPU time. The table is updated at interaction::AllocAndLink() and interaction::UnlinkAndFree() int index = ldef->index * this->interactionTableWidth + edef->index; + inter = this->interactionTable[ index ]; + if ( inter ) { // if this entity wasn't in view already, the scissor rect will be empty, // so it will only be used for shadow casting @@ -633,8 +634,8 @@ void idRenderWorldLocal::CreateLightDefInteractions( idRenderLightLocal *ldef ) // do a check of the entity reference bounds against the light frustum, // trying to avoid creating a viewEntity if it hasn't been already - float modelMatrix[16]; - float *m; + float modelMatrix[16]; + float *m; if ( edef->viewCount == tr.viewCount ) { m = edef->viewEntity->modelMatrix; @@ -665,14 +666,13 @@ R_LinkLightSurf ================= */ void R_LinkLightSurf( const drawSurf_t **link, const srfTriangles_t *tri, const viewEntity_t *space, - const idRenderLightLocal *light, const idMaterial *shader, const idScreenRect &scissor, bool viewInsideShadow ) { - drawSurf_t *drawSurf; + const idRenderLightLocal *light, const idMaterial *shader, const idScreenRect &scissor, bool viewInsideShadow ) { + drawSurf_t *drawSurf; if ( !space ) { space = &tr.viewDef->worldSpace; } - - drawSurf = (drawSurf_t *)R_FrameAlloc( sizeof( *drawSurf ) ); + drawSurf = ( drawSurf_t * )R_FrameAlloc( sizeof( *drawSurf ) ); drawSurf->geo = tri; drawSurf->space = space; @@ -696,7 +696,7 @@ void R_LinkLightSurf( const drawSurf_t **link, const srfTriangles_t *tri, const drawSurf->shaderRegisters = constRegs; } else { // FIXME: share with the ambient surface? - float *regs = (float *)R_FrameAlloc( shader->GetNumRegisters() * sizeof( float ) ); + float *regs = ( float * )R_FrameAlloc( shader->GetNumRegisters() * sizeof( float ) ); drawSurf->shaderRegisters = regs; shader->EvaluateRegisters( regs, space->entityDef->parms.shaderParms, tr.viewDef, space->entityDef->parms.referenceSound ); } @@ -744,7 +744,6 @@ idScreenRect R_ClippedLightScissorRectangle( viewLight_t *vLight ) { if ( light->frustum[i].Distance( tr.viewDef->renderView.vieworg ) >= 0 ) { continue; } - w = *ow; // now check the winding against each of the frustum planes @@ -756,15 +755,14 @@ idScreenRect R_ClippedLightScissorRectangle( viewLight_t *vLight ) { // project these points to the screen and add to bounds for ( j = 0; j < w.GetNumPoints(); j++ ) { - idPlane eye, clip; - idVec3 ndc; + idPlane eye, clip; + idVec3 ndc; R_TransformModelToClip( w[j].ToVec3(), tr.viewDef->worldSpace.modelViewMatrix, tr.viewDef->projectionMatrix, eye, clip ); if ( clip[3] <= 0.01f ) { clip[3] = 0.01f; } - R_TransformClipToDevice( clip, tr.viewDef, ndc ); float windowX = 0.5f * ( 1.0f + ndc[0] ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 ); @@ -775,12 +773,12 @@ idScreenRect R_ClippedLightScissorRectangle( viewLight_t *vLight ) { } else if ( windowX < tr.viewDef->scissor.x1 ) { windowX = tr.viewDef->scissor.x1; } + if ( windowY > tr.viewDef->scissor.y2 ) { windowY = tr.viewDef->scissor.y2; } else if ( windowY < tr.viewDef->scissor.y1 ) { windowY = tr.viewDef->scissor.y1; } - r.AddPoint( windowX, windowY ); } } @@ -799,13 +797,13 @@ The light screen bounds will be used to crop the scissor rect during stencil clears and interaction drawing ================== */ -int c_clippedLight, c_unclippedLight; +int c_clippedLight, c_unclippedLight; -idScreenRect R_CalcLightScissorRectangle( viewLight_t *vLight ) { - idScreenRect r; - srfTriangles_t *tri; - idPlane eye, clip; - idVec3 ndc; +idScreenRect R_CalcLightScissorRectangle( viewLight_t *vLight ) { + idScreenRect r; + srfTriangles_t *tri; + idPlane eye, clip; + idVec3 ndc; if ( vLight->lightDef->parms.pointLight ) { idBounds bounds; @@ -817,17 +815,18 @@ idScreenRect R_CalcLightScissorRectangle( viewLight_t *vLight ) { if ( r_useClippedLightScissors.GetInteger() == 2 ) { return R_ClippedLightScissorRectangle( vLight ); } - r.Clear(); tri = vLight->lightDef->frustumTris; + for ( int i = 0 ; i < tri->numVerts ; i++ ) { R_TransformModelToClip( tri->verts[i].xyz, tr.viewDef->worldSpace.modelViewMatrix, - tr.viewDef->projectionMatrix, eye, clip ); + tr.viewDef->projectionMatrix, eye, clip ); // if it is near clipped, clip the winding polygons to the view frustum if ( clip[3] <= 1 ) { c_clippedLight++; + if ( r_useClippedLightScissors.GetInteger() ) { return R_ClippedLightScissorRectangle( vLight ); } else { @@ -837,23 +836,21 @@ idScreenRect R_CalcLightScissorRectangle( viewLight_t *vLight ) { return r; } } - R_TransformClipToDevice( clip, tr.viewDef, ndc ); float windowX = 0.5f * ( 1.0f + ndc[0] ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 ); float windowY = 0.5f * ( 1.0f + ndc[1] ) * ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 ); - if ( windowX > tr.viewDef->scissor.x2 ) { windowX = tr.viewDef->scissor.x2; } else if ( windowX < tr.viewDef->scissor.x1 ) { windowX = tr.viewDef->scissor.x1; } + if ( windowY > tr.viewDef->scissor.y2 ) { windowY = tr.viewDef->scissor.y2; } else if ( windowY < tr.viewDef->scissor.y1 ) { windowY = tr.viewDef->scissor.y1; } - r.AddPoint( windowX, windowY ); } @@ -884,31 +881,33 @@ and the viewEntitys due to game movement ================= */ void R_AddLightSurfaces( void ) { - viewLight_t *vLight; + viewLight_t *vLight; idRenderLightLocal *light; - viewLight_t **ptr; + viewLight_t **ptr; // go through each visible light, possibly removing some from the list ptr = &tr.viewDef->viewLights; + while ( *ptr ) { vLight = *ptr; light = vLight->lightDef; - const idMaterial *lightShader = light->lightShader; + const idMaterial *lightShader = light->lightShader; if ( !lightShader ) { common->Error( "R_AddLightSurfaces: NULL lightShader" ); } // see if we are suppressing the light in this view if ( !r_skipSuppress.GetBool() ) { - if ( light->parms.suppressLightInViewID - && light->parms.suppressLightInViewID == tr.viewDef->renderView.viewID ) { + if ( light->parms.suppressLightInViewID && + light->parms.suppressLightInViewID == tr.viewDef->renderView.viewID ) { *ptr = vLight->next; light->viewCount = -1; continue; } - if ( light->parms.allowLightInViewID - && light->parms.allowLightInViewID != tr.viewDef->renderView.viewID ) { + + if ( light->parms.allowLightInViewID && + light->parms.allowLightInViewID != tr.viewDef->renderView.viewID ) { *ptr = vLight->next; light->viewCount = -1; continue; @@ -916,7 +915,7 @@ void R_AddLightSurfaces( void ) { } // evaluate the light shader registers - float *lightRegs =(float *)R_FrameAlloc( lightShader->GetNumRegisters() * sizeof( float ) ); + float *lightRegs = ( float * )R_FrameAlloc( lightShader->GetNumRegisters() * sizeof( float ) ); vLight->shaderRegisters = lightRegs; lightShader->EvaluateRegisters( lightRegs, light->parms.shaderParms, tr.viewDef, light->parms.referenceSound ); @@ -925,38 +924,39 @@ void R_AddLightSurfaces( void ) { if ( !lightShader->IsFogLight() && !lightShader->IsBlendLight() ) { int lightStageNum; for ( lightStageNum = 0 ; lightStageNum < lightShader->GetNumStages() ; lightStageNum++ ) { - const shaderStage_t *lightStage = lightShader->GetStage( lightStageNum ); + const shaderStage_t *lightStage = lightShader->GetStage( lightStageNum ); // ignore stages that fail the condition if ( !lightRegs[ lightStage->conditionRegister ] ) { continue; } - const int *registers = lightStage->color.registers; // snap tiny values to zero to avoid lights showing up with the wrong color if ( lightRegs[ registers[0] ] < 0.001f ) { lightRegs[ registers[0] ] = 0.0f; } + if ( lightRegs[ registers[1] ] < 0.001f ) { lightRegs[ registers[1] ] = 0.0f; } + if ( lightRegs[ registers[2] ] < 0.001f ) { lightRegs[ registers[2] ] = 0.0f; } - // FIXME: when using the following values the light shows up bright red when using nvidia drivers/hardware - // this seems to have been fixed ? + // FIXME: when using the following values the light shows up bright red when using nvidia drivers/hardware + // this seems to have been fixed ? //lightRegs[ registers[0] ] = 1.5143074e-005f; //lightRegs[ registers[1] ] = 1.5483369e-005f; //lightRegs[ registers[2] ] = 1.7014690e-005f; - if ( lightRegs[ registers[0] ] > 0.0f || - lightRegs[ registers[1] ] > 0.0f || - lightRegs[ registers[2] ] > 0.0f ) { + lightRegs[ registers[1] ] > 0.0f || + lightRegs[ registers[2] ] > 0.0f ) { break; } } + if ( lightStageNum == lightShader->GetNumStages() ) { // we went through all the stages and didn't find one that adds anything // remove the light from the viewLights list, and change its frame marker @@ -972,6 +972,7 @@ void R_AddLightSurfaces( void ) { // calculate the screen area covered by the light frustum // which will be used to crop the stencil cull idScreenRect scissorRect = R_CalcLightScissorRectangle( vLight ); + // intersect with the portal crossing scissor rectangle vLight->scissorRect.Intersect( scissorRect ); @@ -996,7 +997,7 @@ void R_AddLightSurfaces( void ) { // a random offset every time if ( r_lightSourceRadius.GetFloat() != 0.0f ) { for ( int i = 0 ; i < 3 ; i++ ) { - light->globalLightOrigin[i] += r_lightSourceRadius.GetFloat() * ( -1 + 2 * (rand()&0xfff)/(float)0xfff ); + light->globalLightOrigin[i] += r_lightSourceRadius.GetFloat() * ( -1 + 2 * ( rand() & 0xfff ) / ( float )0xfff ); } } @@ -1015,6 +1016,7 @@ void R_AddLightSurfaces( void ) { continue; } } + // touch the surface so it won't get purged vertexCache.Touch( light->frustumTris->ambientCache ); } @@ -1025,8 +1027,8 @@ void R_AddLightSurfaces( void ) { if ( !light->parms.prelightModel->NumSurfaces() ) { common->Error( "no surfs in prelight model '%s'", light->parms.prelightModel->Name() ); } + srfTriangles_t *tri = light->parms.prelightModel->Surface( 0 )->geometry; - srfTriangles_t *tri = light->parms.prelightModel->Surface( 0 )->geometry; if ( !tri->shadowVertexes ) { common->Error( "R_AddLightSurfaces: prelight model '%s' without shadowVertexes", light->parms.prelightModel->Name() ); } @@ -1041,6 +1043,7 @@ void R_AddLightSurfaces( void ) { // if we have been purged, re-upload the shadowVertexes if ( !tri->shadowCache ) { R_CreatePrivateShadowCache( tri ); + if ( !tri->shadowCache ) { continue; } @@ -1052,10 +1055,10 @@ void R_AddLightSurfaces( void ) { if ( !tri->indexCache && r_useIndexBuffers.GetBool() ) { vertexCache.Alloc( tri->indexes, tri->numIndexes * sizeof( tri->indexes[0] ), &tri->indexCache, true ); } + if ( tri->indexCache ) { vertexCache.Touch( tri->indexCache ); } - R_LinkLightSurf( &vLight->globalShadows, tri, NULL, light, NULL, vLight->scissorRect, true /* FIXME? */ ); } } @@ -1069,16 +1072,16 @@ R_IssueEntityDefCallback ================== */ bool R_IssueEntityDefCallback( idRenderEntityLocal *def ) { - bool update; - idBounds oldBounds; + bool update; + idBounds oldBounds; const bool checkBounds = r_checkBounds.GetBool(); if ( checkBounds ) { oldBounds = def->referenceBounds; } - - def->archived = false; // will need to be written to the demo file + def->archived = false; // will need to be written to the demo file tr.pc.c_entityDefCallbacks++; + if ( tr.viewDef ) { update = def->parms.callback( &def->parms, &tr.viewDef->renderView ); } else { @@ -1091,16 +1094,15 @@ bool R_IssueEntityDefCallback( idRenderEntityLocal *def ) { } if ( checkBounds ) { - if ( oldBounds[0][0] > def->referenceBounds[0][0] + CHECK_BOUNDS_EPSILON || - oldBounds[0][1] > def->referenceBounds[0][1] + CHECK_BOUNDS_EPSILON || - oldBounds[0][2] > def->referenceBounds[0][2] + CHECK_BOUNDS_EPSILON || - oldBounds[1][0] < def->referenceBounds[1][0] - CHECK_BOUNDS_EPSILON || - oldBounds[1][1] < def->referenceBounds[1][1] - CHECK_BOUNDS_EPSILON || - oldBounds[1][2] < def->referenceBounds[1][2] - CHECK_BOUNDS_EPSILON ) { + if ( oldBounds[0][0] > def->referenceBounds[0][0] + CHECK_BOUNDS_EPSILON || + oldBounds[0][1] > def->referenceBounds[0][1] + CHECK_BOUNDS_EPSILON || + oldBounds[0][2] > def->referenceBounds[0][2] + CHECK_BOUNDS_EPSILON || + oldBounds[1][0] < def->referenceBounds[1][0] - CHECK_BOUNDS_EPSILON || + oldBounds[1][1] < def->referenceBounds[1][1] - CHECK_BOUNDS_EPSILON || + oldBounds[1][2] < def->referenceBounds[1][2] - CHECK_BOUNDS_EPSILON ) { common->Printf( "entity %i callback extended reference bounds\n", def->index ); } } - return update; } @@ -1123,7 +1125,6 @@ idRenderModel *R_EntityDefDynamicModel( idRenderEntityLocal *def ) { } else { callbackUpdate = false; } - idRenderModel *model = def->parms.hModel; if ( !model ) { @@ -1158,17 +1159,17 @@ idRenderModel *R_EntityDefDynamicModel( idRenderEntityLocal *def ) { if ( r_checkBounds.GetBool() ) { idBounds b = def->cachedDynamicModel->Bounds(); - if ( b[0][0] < def->referenceBounds[0][0] - CHECK_BOUNDS_EPSILON || - b[0][1] < def->referenceBounds[0][1] - CHECK_BOUNDS_EPSILON || - b[0][2] < def->referenceBounds[0][2] - CHECK_BOUNDS_EPSILON || - b[1][0] > def->referenceBounds[1][0] + CHECK_BOUNDS_EPSILON || - b[1][1] > def->referenceBounds[1][1] + CHECK_BOUNDS_EPSILON || - b[1][2] > def->referenceBounds[1][2] + CHECK_BOUNDS_EPSILON ) { + + if ( b[0][0] < def->referenceBounds[0][0] - CHECK_BOUNDS_EPSILON || + b[0][1] < def->referenceBounds[0][1] - CHECK_BOUNDS_EPSILON || + b[0][2] < def->referenceBounds[0][2] - CHECK_BOUNDS_EPSILON || + b[1][0] > def->referenceBounds[1][0] + CHECK_BOUNDS_EPSILON || + b[1][1] > def->referenceBounds[1][1] + CHECK_BOUNDS_EPSILON || + b[1][2] > def->referenceBounds[1][2] + CHECK_BOUNDS_EPSILON ) { common->Printf( "entity %i dynamic model exceeded reference bounds\n", def->index ); } } } - def->dynamicModel = def->cachedDynamicModel; def->dynamicModelFrameCount = tr.frameCount; } @@ -1184,7 +1185,6 @@ idRenderModel *R_EntityDefDynamicModel( idRenderEntityLocal *def ) { // FIXME: if any of the surfaces have deforms, create a frame-temporary model with references to the // undeformed surfaces. This would allow deforms to be light interacting. - return def->dynamicModel; } @@ -1194,27 +1194,23 @@ R_AddDrawSurf ================= */ void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const renderEntity_t *renderEntity, - const idMaterial *shader, const idScreenRect &scissor, const float soft_particle_radius ) -{ - drawSurf_t *drawSurf; - const float *shaderParms; - static float refRegs[MAX_EXPRESSION_REGISTERS]; // don't put on stack, or VC++ will do a page touch - float generatedShaderParms[MAX_ENTITY_SHADER_PARMS]; - - drawSurf = (drawSurf_t *)R_FrameAlloc( sizeof( *drawSurf ) ); + const idMaterial *shader, const idScreenRect &scissor, const float soft_particle_radius ) { + drawSurf_t *drawSurf; + const float *shaderParms; + static float refRegs[MAX_EXPRESSION_REGISTERS]; // don't put on stack, or VC++ will do a page touch + float generatedShaderParms[MAX_ENTITY_SHADER_PARMS]; + + drawSurf = ( drawSurf_t * )R_FrameAlloc( sizeof( *drawSurf ) ); drawSurf->geo = tri; drawSurf->space = space; drawSurf->material = shader; drawSurf->scissorRect = scissor; drawSurf->sort = shader->GetSort() + tr.sortOffset; - if ( soft_particle_radius != -1.0f ) // #3878 - { + if ( soft_particle_radius != -1.0f ) { // #3878 drawSurf->dsFlags = DSF_SOFT_PARTICLE; drawSurf->particle_radius = soft_particle_radius; - } - else - { + } else { drawSurf->dsFlags = 0; drawSurf->particle_radius = 0.0f; } @@ -1225,8 +1221,8 @@ void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const // if it doesn't fit, resize the list if ( tr.viewDef->numDrawSurfs == tr.viewDef->maxDrawSurfs ) { - drawSurf_t **old = tr.viewDef->drawSurfs; - int count; + drawSurf_t **old = tr.viewDef->drawSurfs; + int count; if ( tr.viewDef->maxDrawSurfs == 0 ) { tr.viewDef->maxDrawSurfs = INITIAL_DRAWSURFS; @@ -1235,20 +1231,22 @@ void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const count = tr.viewDef->maxDrawSurfs * sizeof( tr.viewDef->drawSurfs[0] ); tr.viewDef->maxDrawSurfs *= 2; } - tr.viewDef->drawSurfs = (drawSurf_t **)R_FrameAlloc( tr.viewDef->maxDrawSurfs * sizeof( tr.viewDef->drawSurfs[0] ) ); - if(count > 0) + tr.viewDef->drawSurfs = ( drawSurf_t ** )R_FrameAlloc( tr.viewDef->maxDrawSurfs * sizeof( tr.viewDef->drawSurfs[0] ) ); + + if ( count > 0 ) { memcpy( tr.viewDef->drawSurfs, old, count ); + } } tr.viewDef->drawSurfs[tr.viewDef->numDrawSurfs] = drawSurf; tr.viewDef->numDrawSurfs++; // process the shader expressions for conditionals / color / texcoords - const float *constRegs = shader->ConstantRegisters(); + const float *constRegs = shader->ConstantRegisters(); if ( constRegs ) { // shader only uses constant values drawSurf->shaderRegisters = constRegs; } else { - float *regs = (float *)R_FrameAlloc( shader->GetNumRegisters() * sizeof( float ) ); + float *regs = ( float * )R_FrameAlloc( shader->GetNumRegisters() * sizeof( float ) ); drawSurf->shaderRegisters = regs; // a reference shader will take the calculated stage color value from another shader @@ -1260,7 +1258,7 @@ void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const const shaderStage_t *pStage; renderEntity->referenceShader->EvaluateRegisters( refRegs, renderEntity->shaderParms, tr.viewDef, renderEntity->referenceSound ); - pStage = renderEntity->referenceShader->GetStage(0); + pStage = renderEntity->referenceShader->GetStage( 0 ); memcpy( generatedShaderParms, renderEntity->shaderParms, sizeof( generatedShaderParms ) ); generatedShaderParms[0] = refRegs[ pStage->color.registers[0] ]; @@ -1272,9 +1270,8 @@ void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const // evaluate with the entityDef's shader parms shaderParms = renderEntity->shaderParms; } - float oldFloatTime = 0.0f; - int oldTime = 0; + int oldTime = 0; if ( space->entityDef && space->entityDef->parms.timeGroup ) { oldFloatTime = tr.viewDef->floatTime; @@ -1283,7 +1280,6 @@ void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const tr.viewDef->floatTime = game->GetTimeGroupTime( space->entityDef->parms.timeGroup ) * 0.001; tr.viewDef->renderView.time = game->GetTimeGroupTime( space->entityDef->parms.timeGroup ); } - shader->EvaluateRegisters( regs, shaderParms, tr.viewDef, renderEntity->referenceSound ); if ( space->entityDef && space->entityDef->parms.timeGroup ) { @@ -1296,17 +1292,17 @@ void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const R_DeformDrawSurf( drawSurf ); // skybox surfaces need a dynamic texgen - switch( shader->Texgen() ) { - case TG_SKYBOX_CUBE: - R_SkyboxTexGen( drawSurf, tr.viewDef->renderView.vieworg ); - break; - case TG_WOBBLESKY_CUBE: - R_WobbleskyTexGen( drawSurf, tr.viewDef->renderView.vieworg ); - break; + switch ( shader->Texgen() ) { + case TG_SKYBOX_CUBE: + R_SkyboxTexGen( drawSurf, tr.viewDef->renderView.vieworg ); + break; + case TG_WOBBLESKY_CUBE: + R_WobbleskyTexGen( drawSurf, tr.viewDef->renderView.vieworg ); + break; } // check for gui surfaces - idUserInterface *gui = NULL; + idUserInterface *gui = NULL; if ( !space->entityDef ) { gui = shader->GlobalGui(); @@ -1315,6 +1311,7 @@ void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const if ( guiNum >= 0 && guiNum < MAX_RENDERENTITY_GUI ) { gui = renderEntity->gui[ guiNum ]; } + if ( gui == NULL ) { gui = shader->GlobalGui(); } @@ -1335,10 +1332,9 @@ void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const if ( !R_PreciseCullSurface( drawSurf, ndcBounds ) ) { // did we ever use this to forward an entity color to a gui that didn't set color? -// memcpy( tr.guiShaderParms, shaderParms, sizeof( tr.guiShaderParms ) ); + // memcpy( tr.guiShaderParms, shaderParms, sizeof( tr.guiShaderParms ) ); R_RenderGuiSurf( gui, drawSurf ); } - tr.viewDef->floatTime = oldFloatTime; tr.viewDef->renderView.time = oldTime; } @@ -1358,11 +1354,11 @@ each viewEntity that has a non-empty scissorRect =============== */ static void R_AddAmbientDrawsurfs( viewEntity_t *vEntity ) { - int i, total; - idRenderEntityLocal *def; - srfTriangles_t *tri; - idRenderModel *model; - const idMaterial *shader; + int i, total; + idRenderEntityLocal *def; + srfTriangles_t *tri; + idRenderModel *model; + const idMaterial *shader; def = vEntity->entityDef; @@ -1374,18 +1370,20 @@ static void R_AddAmbientDrawsurfs( viewEntity_t *vEntity ) { // add all the surfaces total = model->NumSurfaces(); + for ( i = 0 ; i < total ; i++ ) { - const modelSurface_t *surf = model->Surface( i ); + const modelSurface_t *surf = model->Surface( i ); // for debugging, only show a single surface at a time if ( r_singleSurface.GetInteger() >= 0 && i != r_singleSurface.GetInteger() ) { continue; } - tri = surf->geometry; + if ( !tri ) { continue; } + if ( !tri->numIndexes ) { continue; } @@ -1397,6 +1395,7 @@ static void R_AddAmbientDrawsurfs( viewEntity_t *vEntity ) { if ( !shader ) { continue; } + if ( !shader->IsDrawn() ) { continue; } @@ -1406,17 +1405,19 @@ static void R_AddAmbientDrawsurfs( viewEntity_t *vEntity ) { int j, k; for ( j = 0 ; j < tri->numVerts ; j++ ) { for ( k = 0 ; k < 3 ; k++ ) { - if ( tri->verts[j].xyz[k] > tri->bounds[1][k] + CHECK_BOUNDS_EPSILON - || tri->verts[j].xyz[k] < tri->bounds[0][k] - CHECK_BOUNDS_EPSILON ) { + if ( tri->verts[j].xyz[k] > tri->bounds[1][k] + CHECK_BOUNDS_EPSILON || + tri->verts[j].xyz[k] < tri->bounds[0][k] - CHECK_BOUNDS_EPSILON ) { common->Printf( "bad tri->bounds on %s:%s\n", def->parms.hModel->Name(), shader->GetName() ); break; } - if ( tri->verts[j].xyz[k] > def->referenceBounds[1][k] + CHECK_BOUNDS_EPSILON - || tri->verts[j].xyz[k] < def->referenceBounds[0][k] - CHECK_BOUNDS_EPSILON ) { + + if ( tri->verts[j].xyz[k] > def->referenceBounds[1][k] + CHECK_BOUNDS_EPSILON || + tri->verts[j].xyz[k] < def->referenceBounds[0][k] - CHECK_BOUNDS_EPSILON ) { common->Printf( "bad referenceBounds on %s:%s\n", def->parms.hModel->Name(), shader->GetName() ); break; } } + if ( k != 3 ) { break; } @@ -1432,25 +1433,26 @@ static void R_AddAmbientDrawsurfs( viewEntity_t *vEntity ) { // don't add anything if the vertex cache was too full to give us an ambient cache return; } + // touch it so it won't get purged vertexCache.Touch( tri->ambientCache ); if ( r_useIndexBuffers.GetBool() && !tri->indexCache ) { vertexCache.Alloc( tri->indexes, tri->numIndexes * sizeof( tri->indexes[0] ), &tri->indexCache, true ); } + if ( tri->indexCache ) { vertexCache.Touch( tri->indexCache ); } // Soft Particles -- SteveL #3878 - float particle_radius = -1.0f; // Default = disallow softening, but allow modelDepthHack if specified in the decl. - if ( r_useSoftParticles.GetBool() && r_enableDepthCapture.GetInteger() != 0 - && !shader->ReceivesLighting() // don't soften surfaces that are meant to be solid - && tr.viewDef->renderView.viewID >= 0 ) // Skip during "invisible" rendering passes (e.g. lightgem) - { - const idRenderModelPrt* prt = dynamic_cast( def->parms.hModel ); // yuck. - if ( prt ) - { + float particle_radius = -1.0f; // Default = disallow softening, but allow modelDepthHack if specified in the decl. + if ( r_useSoftParticles.GetBool() && + r_enableDepthCapture.GetInteger() != 0 && + !shader->ReceivesLighting() && // don't soften surfaces that are meant to be solid + tr.viewDef->renderView.viewID >= 0 ) { // Skip during "invisible" rendering passes (e.g. lightgem) + const idRenderModelPrt *prt = dynamic_cast( def->parms.hModel ); // yuck. + if ( prt ) { particle_radius = prt->SofteningRadius( surf->id ); } } @@ -1496,13 +1498,13 @@ two or more lights. =================== */ void R_AddModelSurfaces( void ) { - viewEntity_t *vEntity; - idInteraction *inter, *next; - idRenderModel *model; + viewEntity_t *vEntity; + idInteraction *inter, *next; + idRenderModel *model; // clear the ambient surface list tr.viewDef->numDrawSurfs = 0; - tr.viewDef->maxDrawSurfs = 0; // will be set to INITIAL_DRAWSURFS on R_AddDrawSurf + tr.viewDef->maxDrawSurfs = 0; // will be set to INITIAL_DRAWSURFS on R_AddDrawSurf // go through each entity that is either visible to the view, or to // any light that intersects the view (for shadows) @@ -1511,6 +1513,7 @@ void R_AddModelSurfaces( void ) { if ( r_useEntityScissors.GetBool() ) { // calculate the screen area covered by the entity idScreenRect scissorRect = R_CalcEntityScissorRectangle( vEntity ); + // intersect with the portal crossing scissor rectangle vEntity->scissorRect.Intersect( scissorRect ); @@ -1518,9 +1521,8 @@ void R_AddModelSurfaces( void ) { R_ShowColoredScreenRect( vEntity->scissorRect, vEntity->entityDef->index ); } } - float oldFloatTime = 0.0f; - int oldTime = 0; + int oldTime = 0; game->SelectTimeGroup( vEntity->entityDef->parms.timeGroup ); @@ -1546,17 +1548,17 @@ void R_AddModelSurfaces( void ) { continue; } - // Don't let particle entities re-instantiate their dynamic model during non-visible + // Don't let particle entities re-instantiate their dynamic model during non-visible // views (in TDM, the light gem render) -- SteveL #3970 - if ( tr.viewDef->renderView.viewID < 0 - && dynamic_cast( vEntity->entityDef->parms.hModel ) != NULL ) // yuck. - { + if ( tr.viewDef->renderView.viewID < 0 && dynamic_cast( vEntity->entityDef->parms.hModel ) != NULL ) { + // yuck. continue; } // add the ambient surface if it has a visible rectangle if ( !vEntity->scissorRect.IsEmpty() ) { model = R_EntityDefDynamicModel( vEntity->entityDef ); + if ( model == NULL || model->NumSurfaces() <= 0 ) { if ( vEntity->entityDef->parms.timeGroup ) { tr.viewDef->floatTime = oldFloatTime; @@ -1564,7 +1566,6 @@ void R_AddModelSurfaces( void ) { } continue; } - R_AddAmbientDrawsurfs( vEntity ); tr.pc.c_visibleViewEntities++; } else { @@ -1578,6 +1579,7 @@ void R_AddModelSurfaces( void ) { if ( vEntity->entityDef->parms.xrayIndex == 2 ) { for ( inter = vEntity->entityDef->firstInteraction; inter != NULL && !inter->IsEmpty(); inter = next ) { next = inter->entityNext; + if ( inter->lightDef->viewCount != tr.viewCount ) { continue; } @@ -1604,7 +1606,6 @@ void R_AddModelSurfaces( void ) { tr.viewDef->floatTime = oldFloatTime; tr.viewDef->renderView.time = oldTime; } - } } @@ -1614,7 +1615,7 @@ R_RemoveUnecessaryViewLights ===================== */ void R_RemoveUnecessaryViewLights( void ) { - viewLight_t *vLight; + viewLight_t *vLight; // go through each visible light for ( vLight = tr.viewDef->viewLights ; vLight ; vLight = vLight->next ) { @@ -1632,33 +1633,33 @@ void R_RemoveUnecessaryViewLights( void ) { // This doesn't seem to actually help, perhaps because the surface scissor // rects aren't actually the surface, but only the portal clippings. for ( vLight = tr.viewDef->viewLights ; vLight ; vLight = vLight->next ) { - const drawSurf_t *surf; - idScreenRect surfRect; + const drawSurf_t *surf; + idScreenRect surfRect; if ( !vLight->lightShader->LightCastsShadows() ) { continue; } - surfRect.Clear(); for ( surf = vLight->globalInteractions ; surf ; surf = surf->nextOnLight ) { surfRect.Union( surf->scissorRect ); } + for ( surf = vLight->localShadows ; surf ; surf = surf->nextOnLight ) { - const_cast(surf)->scissorRect.Intersect( surfRect ); + const_cast( surf )->scissorRect.Intersect( surfRect ); } for ( surf = vLight->localInteractions ; surf ; surf = surf->nextOnLight ) { surfRect.Union( surf->scissorRect ); } + for ( surf = vLight->globalShadows ; surf ; surf = surf->nextOnLight ) { - const_cast(surf)->scissorRect.Intersect( surfRect ); + const_cast( surf )->scissorRect.Intersect( surfRect ); } for ( surf = vLight->translucentInteractions ; surf ; surf = surf->nextOnLight ) { surfRect.Union( surf->scissorRect ); } - vLight->scissorRect.Intersect( surfRect ); } } diff --git a/neo/renderer/tr_local.h b/neo/renderer/tr_local.h index 51ae91d4d..2b8ffe528 100644 --- a/neo/renderer/tr_local.h +++ b/neo/renderer/tr_local.h @@ -1,1688 +1,1805 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __TR_LOCAL_H__ -#define __TR_LOCAL_H__ - -class idScreenRect; // yay for include recursion - -#include "renderer/Image.h" -#include "renderer/Interaction.h" -#include "renderer/MegaTexture.h" -#include "renderer/ModelDecal.h" -#include "renderer/ModelOverlay.h" -#include "renderer/RenderSystem.h" -#include "renderer/RenderWorld.h" - -class idRenderWorldLocal; - -// everything that is needed by the backend needs -// to be double buffered to allow it to run in -// parallel on a dual cpu machine -const int SMP_FRAMES = 1; - -const int FALLOFF_TEXTURE_SIZE = 64; - -const float DEFAULT_FOG_DISTANCE = 500.0f; - -const int FOG_ENTER_SIZE = 64; -const float FOG_ENTER = (FOG_ENTER_SIZE+1.0f)/(FOG_ENTER_SIZE*2); -// picky to get the bilerp correct at terminator - - -// idScreenRect gets carried around with each drawSurf, so it makes sense -// to keep it compact, instead of just using the idBounds class -class idScreenRect { -public: - short x1, y1, x2, y2; // inclusive pixel bounds inside viewport - float zmin, zmax; // for depth bounds test - - void Clear(); // clear to backwards values - void AddPoint( float x, float y ); // adds a point - void Expand(); // expand by one pixel each way to fix roundoffs - void Intersect( const idScreenRect &rect ); - void Union( const idScreenRect &rect ); - bool Equals( const idScreenRect &rect ) const; - bool IsEmpty() const; -}; - -idScreenRect R_ScreenRectFromViewFrustumBounds( const idBounds &bounds ); -void R_ShowColoredScreenRect( const idScreenRect &rect, int colorIndex ); - -typedef enum { - DC_BAD, - DC_RENDERVIEW, - DC_UPDATE_ENTITYDEF, - DC_DELETE_ENTITYDEF, - DC_UPDATE_LIGHTDEF, - DC_DELETE_LIGHTDEF, - DC_LOADMAP, - DC_CROP_RENDER, - DC_UNCROP_RENDER, - DC_CAPTURE_RENDER, - DC_END_FRAME, - DC_DEFINE_MODEL, - DC_SET_PORTAL_STATE, - DC_UPDATE_SOUNDOCCLUSION, - DC_GUI_MODEL -} demoCommand_t; - -/* -============================================================================== - -SURFACES - -============================================================================== -*/ - -// drawSurf_t structures command the back end to render surfaces -// a given srfTriangles_t may be used with multiple viewEntity_t, -// as when viewed in a subview or multiple viewport render, or -// with multiple shaders when skinned, or, possibly with multiple -// lights, although currently each lighting interaction creates -// unique srfTriangles_t - -// drawSurf_t are always allocated and freed every frame, they are never cached -static const int DSF_VIEW_INSIDE_SHADOW = 1; -static const int DSF_SOFT_PARTICLE = 2; // #3878 - soft particles - -typedef struct drawSurf_s { - const srfTriangles_t *geo; - const struct viewEntity_s *space; - const idMaterial *material; // may be NULL for shadow volumes - float sort; // material->sort, modified by gui / entity sort offsets - const float *shaderRegisters; // evaluated and adjusted for referenceShaders - const struct drawSurf_s *nextOnLight; // viewLight chains - idScreenRect scissorRect; // for scissor clipping, local inside renderView viewport - int dsFlags; // DSF_VIEW_INSIDE_SHADOW, etc - struct vertCache_s *dynamicTexCoords; // float * in vertex cache memory - // specular directions for non vertex program cards, skybox texcoords, etc - float particle_radius; // The radius of individual quads for soft particles #3878 -} drawSurf_t; - - -typedef struct { - int numPlanes; // this is always 6 for now - idPlane planes[6]; - // positive sides facing inward - // plane 5 is always the plane the projection is going to, the - // other planes are just clip planes - // all planes are in global coordinates - - bool makeClippedPlanes; - // a projected light with a single frustum needs to make sil planes - // from triangles that clip against side planes, but a point light - // that has adjacent frustums doesn't need to -} shadowFrustum_t; - - -// areas have references to hold all the lights and entities in them -typedef struct areaReference_s { - struct areaReference_s *areaNext; // chain in the area - struct areaReference_s *areaPrev; - struct areaReference_s *ownerNext; // chain on either the entityDef or lightDef - idRenderEntityLocal * entity; // only one of entity / light will be non-NULL - idRenderLightLocal * light; // only one of entity / light will be non-NULL - struct portalArea_s * area; // so owners can find all the areas they are in -} areaReference_t; - - -// idRenderLight should become the new public interface replacing the qhandle_t to light defs in the idRenderWorld interface -class idRenderLight { -public: - virtual ~idRenderLight() {} - - virtual void FreeRenderLight() = 0; - virtual void UpdateRenderLight( const renderLight_t *re, bool forceUpdate = false ) = 0; - virtual void GetRenderLight( renderLight_t *re ) = 0; - virtual void ForceUpdate() = 0; - virtual int GetIndex() = 0; -}; - - -// idRenderEntity should become the new public interface replacing the qhandle_t to entity defs in the idRenderWorld interface -class idRenderEntity { -public: - virtual ~idRenderEntity() {} - - virtual void FreeRenderEntity() = 0; - virtual void UpdateRenderEntity( const renderEntity_t *re, bool forceUpdate = false ) = 0; - virtual void GetRenderEntity( renderEntity_t *re ) = 0; - virtual void ForceUpdate() = 0; - virtual int GetIndex() = 0; - - // overlays are extra polygons that deform with animating models for blood and damage marks - virtual void ProjectOverlay( const idPlane localTextureAxis[2], const idMaterial *material ) = 0; - virtual void RemoveDecals() = 0; -}; - - -class idRenderLightLocal : public idRenderLight { -public: - idRenderLightLocal(); - - virtual void FreeRenderLight(); - virtual void UpdateRenderLight( const renderLight_t *re, bool forceUpdate = false ); - virtual void GetRenderLight( renderLight_t *re ); - virtual void ForceUpdate(); - virtual int GetIndex(); - - renderLight_t parms; // specification - - bool lightHasMoved; // the light has changed its position since it was - // first added, so the prelight model is not valid - - float modelMatrix[16]; // this is just a rearrangement of parms.axis and parms.origin - - idRenderWorldLocal * world; - int index; // in world lightdefs - - int areaNum; // if not -1, we may be able to cull all the light's - // interactions if !viewDef->connectedAreas[areaNum] - - int lastModifiedFrameNum; // to determine if it is constantly changing, - // and should go in the dynamic frame memory, or kept - // in the cached memory - bool archived; // for demo writing - - - // derived information - idPlane lightProject[4]; - - const idMaterial * lightShader; // guaranteed to be valid, even if parms.shader isn't - idImage * falloffImage; - - idVec3 globalLightOrigin; // accounting for lightCenter and parallel - - - idPlane frustum[6]; // in global space, positive side facing out, last two are front/back - idWinding * frustumWindings[6]; // used for culling - srfTriangles_t * frustumTris; // triangulated frustumWindings[] - - int numShadowFrustums; // one for projected lights, usually six for point lights - shadowFrustum_t shadowFrustums[6]; - - int viewCount; // if == tr.viewCount, the light is on the viewDef->viewLights list - struct viewLight_s * viewLight; - - areaReference_t * references; // each area the light is present in will have a lightRef - idInteraction * firstInteraction; // doubly linked list - idInteraction * lastInteraction; - - struct doublePortal_s * foggedPortals; -}; - - -class idRenderEntityLocal : public idRenderEntity { -public: - idRenderEntityLocal(); - - virtual void FreeRenderEntity(); - virtual void UpdateRenderEntity( const renderEntity_t *re, bool forceUpdate = false ); - virtual void GetRenderEntity( renderEntity_t *re ); - virtual void ForceUpdate(); - virtual int GetIndex(); - - // overlays are extra polygons that deform with animating models for blood and damage marks - virtual void ProjectOverlay( const idPlane localTextureAxis[2], const idMaterial *material ); - virtual void RemoveDecals(); - - renderEntity_t parms; - - float modelMatrix[16]; // this is just a rearrangement of parms.axis and parms.origin - - idRenderWorldLocal * world; - int index; // in world entityDefs - - int lastModifiedFrameNum; // to determine if it is constantly changing, - // and should go in the dynamic frame memory, or kept - // in the cached memory - bool archived; // for demo writing - - idRenderModel * dynamicModel; // if parms.model->IsDynamicModel(), this is the generated data - int dynamicModelFrameCount; // continuously animating dynamic models will recreate - // dynamicModel if this doesn't == tr.viewCount - idRenderModel * cachedDynamicModel; - - idBounds referenceBounds; // the local bounds used to place entityRefs, either from parms or a model - - // a viewEntity_t is created whenever a idRenderEntityLocal is considered for inclusion - // in a given view, even if it turns out to not be visible - int viewCount; // if tr.viewCount == viewCount, viewEntity is valid, - // but the entity may still be off screen - struct viewEntity_s * viewEntity; // in frame temporary memory - - int visibleCount; - // if tr.viewCount == visibleCount, at least one ambient - // surface has actually been added by R_AddAmbientDrawsurfs - // note that an entity could still be in the view frustum and not be visible due - // to portal passing - - idRenderModelDecal * decals; // chain of decals that have been projected on this model - idRenderModelOverlay * overlay; // blood overlays on animated models - - areaReference_t * entityRefs; // chain of all references - idInteraction * firstInteraction; // doubly linked list - idInteraction * lastInteraction; - - bool needsPortalSky; -}; - - -// viewLights are allocated on the frame temporary stack memory -// a viewLight contains everything that the back end needs out of an idRenderLightLocal, -// which the front end may be modifying simultaniously if running in SMP mode. -// a viewLight may exist even without any surfaces, and may be relevent for fogging, -// but should never exist if its volume does not intersect the view frustum -typedef struct viewLight_s { - struct viewLight_s * next; - - // back end should NOT reference the lightDef, because it can change when running SMP - idRenderLightLocal * lightDef; - - // for scissor clipping, local inside renderView viewport - // scissorRect.Empty() is true if the viewEntity_t was never actually - // seen through any portals - idScreenRect scissorRect; - - // if the view isn't inside the light, we can use the non-reversed - // shadow drawing, avoiding the draws of the front and rear caps - bool viewInsideLight; - - // true if globalLightOrigin is inside the view frustum, even if it may - // be obscured by geometry. This allows us to skip shadows from non-visible objects - bool viewSeesGlobalLightOrigin; - - // if !viewInsideLight, the corresponding bit for each of the shadowFrustum - // projection planes that the view is on the negative side of will be set, - // allowing us to skip drawing the projected caps of shadows if we can't see the face - int viewSeesShadowPlaneBits; - - idVec3 globalLightOrigin; // global light origin used by backend - idPlane lightProject[4]; // light project used by backend - idPlane fogPlane; // fog plane for backend fog volume rendering - const srfTriangles_t * frustumTris; // light frustum for backend fog volume rendering - const idMaterial * lightShader; // light shader used by backend - const float * shaderRegisters; // shader registers used by backend - idImage * falloffImage; // falloff image used by backend - - const struct drawSurf_s *globalShadows; // shadow everything - const struct drawSurf_s *localInteractions; // don't get local shadows - const struct drawSurf_s *localShadows; // don't shadow local Surfaces - const struct drawSurf_s *globalInteractions; // get shadows from everything - const struct drawSurf_s *translucentInteractions; // get shadows from everything -} viewLight_t; - - -// a viewEntity is created whenever a idRenderEntityLocal is considered for inclusion -// in the current view, but it may still turn out to be culled. -// viewEntity are allocated on the frame temporary stack memory -// a viewEntity contains everything that the back end needs out of a idRenderEntityLocal, -// which the front end may be modifying simultaniously if running in SMP mode. -// A single entityDef can generate multiple viewEntity_t in a single frame, as when seen in a mirror -typedef struct viewEntity_s { - struct viewEntity_s *next; - - // back end should NOT reference the entityDef, because it can change when running SMP - idRenderEntityLocal *entityDef; - - // for scissor clipping, local inside renderView viewport - // scissorRect.Empty() is true if the viewEntity_t was never actually - // seen through any portals, but was created for shadow casting. - // a viewEntity can have a non-empty scissorRect, meaning that an area - // that it is in is visible, and still not be visible. - idScreenRect scissorRect; - - bool weaponDepthHack; - float modelDepthHack; - - float modelMatrix[16]; // local coords to global coords - float modelViewMatrix[16]; // local coords to eye coords -} viewEntity_t; - - -const int MAX_CLIP_PLANES = 1; // we may expand this to six for some subview issues - -// viewDefs are allocated on the frame temporary stack memory -typedef struct viewDef_s { - // specified in the call to DrawScene() - renderView_t renderView; - - float projectionMatrix[16]; - viewEntity_t worldSpace; - - idRenderWorldLocal *renderWorld; - - float floatTime; - - idVec3 initialViewAreaOrigin; - // Used to find the portalArea that view flooding will take place from. - // for a normal view, the initialViewOrigin will be renderView.viewOrg, - // but a mirror may put the projection origin outside - // of any valid area, or in an unconnected area of the map, so the view - // area must be based on a point just off the surface of the mirror / subview. - // It may be possible to get a failed portal pass if the plane of the - // mirror intersects a portal, and the initialViewAreaOrigin is on - // a different side than the renderView.viewOrg is. - - bool isSubview; // true if this view is not the main view - bool isMirror; // the portal is a mirror, invert the face culling - bool isXraySubview; - - bool isEditor; - - int numClipPlanes; // mirrors will often use a single clip plane - idPlane clipPlanes[MAX_CLIP_PLANES]; // in world space, the positive side - // of the plane is the visible side - idScreenRect viewport; // in real pixels and proper Y flip - - idScreenRect scissor; - // for scissor clipping, local inside renderView viewport - // subviews may only be rendering part of the main view - // these are real physical pixel values, possibly scaled and offset from the - // renderView x/y/width/height - - struct viewDef_s * superView; // never go into an infinite subview loop - struct drawSurf_s * subviewSurface; - - // drawSurfs are the visible surfaces of the viewEntities, sorted - // by the material sort parameter - drawSurf_t ** drawSurfs; // we don't use an idList for this, because - int numDrawSurfs; // it is allocated in frame temporary memory - int maxDrawSurfs; // may be resized - - struct viewLight_s *viewLights; // chain of all viewLights effecting view - struct viewEntity_s *viewEntitys; // chain of all viewEntities effecting view, including off screen ones casting shadows - // we use viewEntities as a check to see if a given view consists solely - // of 2D rendering, which we can optimize in certain ways. A 2D view will - // not have any viewEntities - - idPlane frustum[5]; // positive sides face outward, [4] is the front clip plane - idFrustum viewFrustum; - - int areaNum; // -1 = not in a valid area - - bool * connectedAreas; - // An array in frame temporary memory that lists if an area can be reached without - // crossing a closed door. This is used to avoid drawing interactions - // when the light is behind a closed door. - -} viewDef_t; - - -// complex light / surface interactions are broken up into multiple passes of a -// simple interaction shader -typedef struct { - const drawSurf_t * surf; - - idImage * lightImage; - idImage * lightFalloffImage; - idImage * bumpImage; - idImage * diffuseImage; - idImage * specularImage; - - idVec4 diffuseColor; // may have a light color baked into it, will be < tr.backEndRendererMaxLight - idVec4 specularColor; // may have a light color baked into it, will be < tr.backEndRendererMaxLight - stageVertexColor_t vertexColor; // applies to both diffuse and specular - - int ambientLight; // use tr.ambientNormalMap instead of normalization cube map - // (not a bool just to avoid an uninitialized memory check of the pad region by valgrind) - - // these are loaded into the vertex program - idVec4 localLightOrigin; - idVec4 localViewOrigin; - idVec4 lightProjection[4]; // in local coordinates, possibly with a texture matrix baked in - idVec4 bumpMatrix[2]; - idVec4 diffuseMatrix[2]; - idVec4 specularMatrix[2]; -} drawInteraction_t; - - -/* -============================================================= - -RENDERER BACK END COMMAND QUEUE - -TR_CMDS - -============================================================= -*/ - -typedef enum { - RC_NOP, - RC_DRAW_VIEW, - RC_SET_BUFFER, - RC_COPY_RENDER, - RC_SWAP_BUFFERS // can't just assume swap at end of list because - // of forced list submission before syncs -} renderCommand_t; - -typedef struct { - renderCommand_t commandId, *next; -} emptyCommand_t; - -typedef struct { - renderCommand_t commandId, *next; - GLenum buffer; - int frameCount; -} setBufferCommand_t; - -typedef struct { - renderCommand_t commandId, *next; - viewDef_t *viewDef; -} drawSurfsCommand_t; - -typedef struct { - renderCommand_t commandId, *next; - int x, y, imageWidth, imageHeight; - idImage *image; - int cubeFace; // when copying to a cubeMap -} copyRenderCommand_t; - - -//======================================================================= - -// this is the inital allocation for max number of drawsurfs -// in a given view, but it will automatically grow if needed -const int INITIAL_DRAWSURFS = 0x4000; - -// a request for frame memory will never fail -// (until malloc fails), but it may force the -// allocation of a new memory block that will -// be discontinuous with the existing memory -typedef struct frameMemoryBlock_s { - struct frameMemoryBlock_s *next; - int size; - int used; - int poop; // so that base is 16 byte aligned - byte base[4]; // dynamically allocated as [size] -} frameMemoryBlock_t; - -// all of the information needed by the back end must be -// contained in a frameData_t. This entire structure is -// duplicated so the front and back end can run in parallel -// on an SMP machine (OBSOLETE: this capability has been removed) -typedef struct { - // one or more blocks of memory for all frame - // temporary allocations - frameMemoryBlock_t *memory; - - // alloc will point somewhere into the memory chain - frameMemoryBlock_t *alloc; - - srfTriangles_t * firstDeferredFreeTriSurf; - srfTriangles_t * lastDeferredFreeTriSurf; - - int memoryHighwater; // max used on any frame - - // the currently building command list - // commands can be inserted at the front if needed, as for required - // dynamically generated textures - emptyCommand_t *cmdHead, *cmdTail; // may be of other command type based on commandId -} frameData_t; - -extern frameData_t *frameData; - -//======================================================================= - -void R_ClearCommandChain( void ); -void R_AddDrawViewCmd( viewDef_t *parms ); - -void R_ReloadGuis_f( const idCmdArgs &args ); -void R_ListGuis_f( const idCmdArgs &args ); - -void *R_GetCommandBuffer( int bytes ); - -// this allows a global override of all materials -bool R_GlobalShaderOverride( const idMaterial **shader ); - -// this does various checks before calling the idDeclSkin -const idMaterial *R_RemapShaderBySkin( const idMaterial *shader, const idDeclSkin *customSkin, const idMaterial *customShader ); - - -//==================================================== - - -/* -** performanceCounters_t -*/ -typedef struct { - int c_sphere_cull_in, c_sphere_cull_clip, c_sphere_cull_out; - int c_box_cull_in, c_box_cull_out; - int c_createInteractions; // number of calls to idInteraction::CreateInteraction - int c_createLightTris; - int c_createShadowVolumes; - int c_generateMd5; - int c_entityDefCallbacks; - int c_alloc, c_free; // counts for R_StaticAllc/R_StaticFree - int c_visibleViewEntities; - int c_shadowViewEntities; - int c_viewLights; - int c_numViews; // number of total views rendered - int c_deformedSurfaces; // idMD5Mesh::GenerateSurface - int c_deformedVerts; // idMD5Mesh::GenerateSurface - int c_deformedIndexes; // idMD5Mesh::GenerateSurface - int c_tangentIndexes; // R_DeriveTangents() - int c_entityUpdates, c_lightUpdates, c_entityReferences, c_lightReferences; - int c_guiSurfs; - int frontEndMsec; // sum of time in all RE_RenderScene's in a frame -} performanceCounters_t; - - -typedef struct { - int current2DMap; - int current3DMap; - int currentCubeMap; - int texEnv; - textureType_t textureType; -} tmu_t; - -const int MAX_MULTITEXTURE_UNITS = 8; -typedef struct { - tmu_t tmu[MAX_MULTITEXTURE_UNITS]; - int currenttmu; - - int faceCulling; - int glStateBits; - bool forceGlState; // the next GL_State will ignore glStateBits and set everything -} glstate_t; - - -typedef struct { - int c_surfaces; - int c_shaders; - int c_vertexes; - int c_indexes; // one set per pass - int c_totalIndexes; // counting all passes - - int c_drawElements; - int c_drawIndexes; - int c_drawVertexes; - int c_drawRefIndexes; - int c_drawRefVertexes; - - int c_shadowElements; - int c_shadowIndexes; - int c_shadowVertexes; - - int c_vboIndexes; - float c_overDraw; - - float maxLightValue; // for light scale - int msec; // total msec for backend run -} backEndCounters_t; - -// all state modified by the back end is separated -// from the front end state -typedef struct { - int frameCount; // used to track all images used in a frame - const viewDef_t * viewDef; - backEndCounters_t pc; - - const viewEntity_t *currentSpace; // for detecting when a matrix must change - idScreenRect currentScissor; - // for scissor clipping, local inside renderView viewport - - viewLight_t * vLight; - int depthFunc; // GLS_DEPTHFUNC_EQUAL, or GLS_DEPTHFUNC_LESS for translucent - float lightTextureMatrix[16]; // only if lightStage->texture.hasMatrix - float lightColor[4]; // evaluation of current light's color stage - - float lightScale; // Every light color calaculation will be multiplied by this, - // which will guarantee that the result is < tr.backEndRendererMaxLight - // A card with high dynamic range will have this set to 1.0 - float overBright; // The amount that all light interactions must be multiplied by - // with post processing to get the desired total light level. - // A high dynamic range card will have this set to 1.0. - - bool currentRenderCopied; // true if any material has already referenced _currentRender - - // our OpenGL state deltas - glstate_t glState; - - int c_copyFrameBuffer; -} backEndState_t; - - -const int MAX_GUI_SURFACES = 1024; // default size of the drawSurfs list for guis, will - // be automatically expanded as needed - -typedef enum { - BE_ARB2, - BE_BAD -} backEndName_t; - -typedef struct { - int x, y, width, height; // these are in physical, OpenGL Y-at-bottom pixels -} renderCrop_t; -static const int MAX_RENDER_CROPS = 8; - -/* -** Most renderer globals are defined here. -** backend functions should never modify any of these fields, -** but may read fields that aren't dynamically modified -** by the frontend. -*/ -class idRenderSystemLocal : public idRenderSystem { -public: - // external functions - virtual void Init( void ); - virtual void Shutdown( void ); - virtual void InitOpenGL( void ); - virtual void ShutdownOpenGL( void ); - virtual bool IsOpenGLRunning( void ) const; - virtual bool IsFullScreen( void ) const; - virtual int GetScreenWidth( void ) const; - virtual int GetScreenHeight( void ) const; - virtual idRenderWorld * AllocRenderWorld( void ); - virtual void FreeRenderWorld( idRenderWorld *rw ); - virtual void BeginLevelLoad( void ); - virtual void EndLevelLoad( void ); - virtual bool RegisterFont( const char *fontName, fontInfoEx_t &font ); - virtual void SetColor( const idVec4 &rgba ); - virtual void SetColor4( float r, float g, float b, float a ); - virtual void DrawStretchPic ( const idDrawVert *verts, const glIndex_t *indexes, int vertCount, int indexCount, const idMaterial *material, - bool clip = true, float x = 0.0f, float y = 0.0f, float w = 640.0f, float h = 0.0f ); - virtual void DrawStretchPic ( float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial *material ); - - virtual void DrawStretchTri ( idVec2 p1, idVec2 p2, idVec2 p3, idVec2 t1, idVec2 t2, idVec2 t3, const idMaterial *material ); - virtual void GlobalToNormalizedDeviceCoordinates( const idVec3 &global, idVec3 &ndc ); - virtual void GetGLSettings( int& width, int& height ); - virtual void PrintMemInfo( MemInfo_t *mi ); - - virtual void DrawSmallChar( int x, int y, int ch, const idMaterial *material ); - virtual void DrawSmallStringExt( int x, int y, const char *string, const idVec4 &setColor, bool forceColor, const idMaterial *material ); - virtual void DrawBigChar( int x, int y, int ch, const idMaterial *material ); - virtual void DrawBigStringExt( int x, int y, const char *string, const idVec4 &setColor, bool forceColor, const idMaterial *material ); - virtual void WriteDemoPics(); - virtual void DrawDemoPics(); - virtual void BeginFrame( int windowWidth, int windowHeight ); - virtual void EndFrame( int *frontEndMsec, int *backEndMsec ); - virtual void TakeScreenshot( int width, int height, const char *fileName, int downSample, renderView_t *ref ); - virtual void CropRenderSize( int width, int height, bool makePowerOfTwo = false, bool forceDimensions = false ); - virtual void CaptureRenderToImage( const char *imageName ); - virtual void CaptureRenderToFile( const char *fileName, bool fixAlpha ); - virtual void UnCrop(); - virtual bool UploadImage( const char *imageName, const byte *data, int width, int height ); - -public: - // internal functions - idRenderSystemLocal( void ); - ~idRenderSystemLocal( void ); - - void Clear( void ); - void SetBackEndRenderer(); // sets tr.backEndRenderer based on cvars - void RenderViewToViewport( const renderView_t *renderView, idScreenRect *viewport ); - -public: - // renderer globals - bool registered; // cleared at shutdown, set at InitOpenGL - - bool takingScreenshot; - - int frameCount; // incremented every frame - int viewCount; // incremented every view (twice a scene if subviewed) - // and every R_MarkFragments call - - int staticAllocCount; // running total of bytes allocated - - float frameShaderTime; // shader time for all non-world 2D rendering - - int viewportOffset[2]; // for doing larger-than-window tiled renderings - int tiledViewport[2]; - - // determines which back end to use, and if vertex programs are in use - backEndName_t backEndRenderer; - bool backEndRendererHasVertexPrograms; - float backEndRendererMaxLight; // 1.0 for standard, unlimited for floats - // determines how much overbrighting needs - // to be done post-process - - idVec4 ambientLightVector; // used for "ambient bump mapping" - - float sortOffset; // for determinist sorting of equal sort materials - - idListworlds; - - idRenderWorldLocal * primaryWorld; - renderView_t primaryRenderView; - viewDef_t * primaryView; - // many console commands need to know which world they should operate on - - const idMaterial * defaultMaterial; - idImage * testImage; - idCinematic * testVideo; - float testVideoStartTime; - - idImage * ambientCubeImage; // hack for testing dependent ambient lighting - - viewDef_t * viewDef; - - performanceCounters_t pc; // performance counters - - drawSurfsCommand_t lockSurfacesCmd; // use this when r_lockSurfaces = 1 - //renderView_t lockSurfacesRenderView; - viewDef_t lockSurfacesViewDef; // of locked position/view - viewDef_t lockSurfacesRealViewDef; // of actual player position - - viewEntity_t identitySpace; // can use if we don't know viewDef->worldSpace is valid - int stencilIncr, stencilDecr; // GL_INCR / INCR_WRAP_EXT, GL_DECR / GL_DECR_EXT - - renderCrop_t renderCrops[MAX_RENDER_CROPS]; - int currentRenderCrop; - - // GUI drawing variables for surface creation - int guiRecursionLevel; // to prevent infinite overruns - class idGuiModel * guiModel; - class idGuiModel * demoGuiModel; - - // DG: remember the original glConfig.vidWidth/Height values that get overwritten in BeginFrame() - // so they can be reset in EndFrame() (Editors tend to mess up the viewport by using BeginFrame()) - int origWidth; - int origHeight; -}; - -extern backEndState_t backEnd; -extern idRenderSystemLocal tr; -extern glconfig_t glConfig; // outside of TR since it shouldn't be cleared during ref re-init - - -// -// cvars -// -extern idCVar r_mode; // video mode number -extern idCVar r_displayRefresh; // optional display refresh rate option for vid mode -extern idCVar r_fullscreen; // 0 = windowed, 1 = full screen -extern idCVar r_fullscreenDesktop; // 0: 'real' fullscreen mode 1: keep resolution 'desktop' fullscreen mode -extern idCVar r_multiSamples; // number of antialiasing samples -extern idCVar r_windowResizable; // DG: allow resizing and maximizing the window - -extern idCVar r_ignore; // used for random debugging without defining new vars -extern idCVar r_ignore2; // used for random debugging without defining new vars -extern idCVar r_znear; // near Z clip plane - -extern idCVar r_finish; // force a call to glFinish() every frame -extern idCVar r_frontBuffer; // draw to front buffer for debugging -extern idCVar r_swapInterval; // changes the GL swap interval -extern idCVar r_offsetFactor; // polygon offset parameter -extern idCVar r_offsetUnits; // polygon offset parameter -extern idCVar r_singleTriangle; // only draw a single triangle per primitive -extern idCVar r_clear; // force screen clear every frame -extern idCVar r_shadows; // enable shadows -extern idCVar r_subviewOnly; // 1 = don't render main view, allowing subviews to be debugged -extern idCVar r_lightScale; // all light intensities are multiplied by this, which is normally 2 -extern idCVar r_flareSize; // scale the flare deforms from the material def - -extern idCVar r_gamma; // changes gamma tables -extern idCVar r_brightness; // changes gamma tables -extern idCVar r_gammaInShader; // set gamma+brightness in shader instead of modifying system gamma tables - -extern idCVar r_renderer; // arb2, etc - -extern idCVar r_checkBounds; // compare all surface bounds with precalculated ones - -extern idCVar r_useLightPortalFlow; // 1 = do a more precise area reference determination -extern idCVar r_useShadowSurfaceScissor;// 1 = scissor shadows by the scissor rect of the interaction surfaces -extern idCVar r_useConstantMaterials; // 1 = use pre-calculated material registers if possible -extern idCVar r_useInteractionTable; // create a full entityDefs * lightDefs table to make finding interactions faster -extern idCVar r_useNodeCommonChildren; // stop pushing reference bounds early when possible -extern idCVar r_useSilRemap; // 1 = consider verts with the same XYZ, but different ST the same for shadows -extern idCVar r_useCulling; // 0 = none, 1 = sphere, 2 = sphere + box -extern idCVar r_useLightCulling; // 0 = none, 1 = box, 2 = exact clip of polyhedron faces -extern idCVar r_useLightScissors; // 1 = use custom scissor rectangle for each light -extern idCVar r_useClippedLightScissors;// 0 = full screen when near clipped, 1 = exact when near clipped, 2 = exact always -extern idCVar r_useEntityCulling; // 0 = none, 1 = box -extern idCVar r_useEntityScissors; // 1 = use custom scissor rectangle for each entity -extern idCVar r_useInteractionCulling; // 1 = cull interactions -extern idCVar r_useInteractionScissors; // 1 = use a custom scissor rectangle for each interaction -extern idCVar r_useFrustumFarDistance; // if != 0 force the view frustum far distance to this distance -extern idCVar r_useShadowCulling; // try to cull shadows from partially visible lights -extern idCVar r_usePreciseTriangleInteractions; // 1 = do winding clipping to determine if each ambiguous tri should be lit -extern idCVar r_useTurboShadow; // 1 = use the infinite projection with W technique for dynamic shadows -extern idCVar r_useExternalShadows; // 1 = skip drawing caps when outside the light volume -extern idCVar r_useOptimizedShadows; // 1 = use the dmap generated static shadow volumes -extern idCVar r_useShadowVertexProgram; // 1 = do the shadow projection in the vertex program on capable cards -extern idCVar r_useShadowProjectedCull; // 1 = discard triangles outside light volume before shadowing -extern idCVar r_useDeferredTangents; // 1 = don't always calc tangents after deform -extern idCVar r_useCachedDynamicModels; // 1 = cache snapshots of dynamic models -extern idCVar r_useTwoSidedStencil; // 1 = do stencil shadows in one pass with different ops on each side -extern idCVar r_useInfiniteFarZ; // 1 = use the no-far-clip-plane trick -extern idCVar r_useScissor; // 1 = scissor clip as portals and lights are processed -extern idCVar r_usePortals; // 1 = use portals to perform area culling, otherwise draw everything -extern idCVar r_useStateCaching; // avoid redundant state changes in GL_*() calls -extern idCVar r_useCombinerDisplayLists;// if 1, put all nvidia register combiner programming in display lists -extern idCVar r_useVertexBuffers; // if 0, don't use ARB_vertex_buffer_object for vertexes -extern idCVar r_useIndexBuffers; // if 0, don't use ARB_vertex_buffer_object for indexes -extern idCVar r_useEntityCallbacks; // if 0, issue the callback immediately at update time, rather than defering -extern idCVar r_lightAllBackFaces; // light all the back faces, even when they would be shadowed -extern idCVar r_useDepthBoundsTest; // use depth bounds test to reduce shadow fill - -extern idCVar r_skipPostProcess; // skip all post-process renderings -extern idCVar r_skipSuppress; // ignore the per-view suppressions -extern idCVar r_skipInteractions; // skip all light/surface interaction drawing -extern idCVar r_skipFrontEnd; // bypasses all front end work, but 2D gui rendering still draws -extern idCVar r_skipBackEnd; // don't draw anything -extern idCVar r_skipCopyTexture; // do all rendering, but don't actually copyTexSubImage2D -extern idCVar r_skipRender; // skip 3D rendering, but pass 2D -extern idCVar r_skipRenderContext; // NULL the rendering context during backend 3D rendering -extern idCVar r_skipTranslucent; // skip the translucent interaction rendering -extern idCVar r_skipAmbient; // bypasses all non-interaction drawing -extern idCVar r_skipNewAmbient; // bypasses all vertex/fragment program ambients -extern idCVar r_skipBlendLights; // skip all blend lights -extern idCVar r_skipFogLights; // skip all fog lights -extern idCVar r_skipSubviews; // 1 = don't render any mirrors / cameras / etc -extern idCVar r_skipGuiShaders; // 1 = don't render any gui elements on surfaces -extern idCVar r_skipParticles; // 1 = don't render any particles -extern idCVar r_skipUpdates; // 1 = don't accept any entity or light updates, making everything static -extern idCVar r_skipDeforms; // leave all deform materials in their original state -extern idCVar r_skipDynamicTextures; // don't dynamically create textures -extern idCVar r_skipLightScale; // don't do any post-interaction light scaling, makes things dim on low-dynamic range cards -extern idCVar r_skipBump; // uses a flat surface instead of the bump map -extern idCVar r_skipSpecular; // use black for specular -extern idCVar r_skipDiffuse; // use black for diffuse -extern idCVar r_skipOverlays; // skip overlay surfaces -extern idCVar r_skipROQ; - -extern idCVar r_ignoreGLErrors; - -extern idCVar r_forceLoadImages; // draw all images to screen after registration -extern idCVar r_demonstrateBug; // used during development to show IHV's their problems -extern idCVar r_screenFraction; // for testing fill rate, the resolution of the entire screen can be changed - -extern idCVar r_showUnsmoothedTangents; // highlight geometry rendered with unsmoothed tangents -extern idCVar r_showSilhouette; // highlight edges that are casting shadow planes -extern idCVar r_showVertexColor; // draws all triangles with the solid vertex color -extern idCVar r_showUpdates; // report entity and light updates and ref counts -extern idCVar r_showDemo; // report reads and writes to the demo file -extern idCVar r_showDynamic; // report stats on dynamic surface generation -extern idCVar r_showLightScale; // report the scale factor applied to drawing for overbrights -extern idCVar r_showIntensity; // draw the screen colors based on intensity, red = 0, green = 128, blue = 255 -extern idCVar r_showDefs; // report the number of modeDefs and lightDefs in view -extern idCVar r_showTrace; // show the intersection of an eye trace with the world -extern idCVar r_showSmp; // show which end (front or back) is blocking -extern idCVar r_showDepth; // display the contents of the depth buffer and the depth range -extern idCVar r_showImages; // draw all images to screen instead of rendering -extern idCVar r_showTris; // enables wireframe rendering of the world -extern idCVar r_showSurfaceInfo; // show surface material name under crosshair -extern idCVar r_showNormals; // draws wireframe normals -extern idCVar r_showEdges; // draw the sil edges -extern idCVar r_showViewEntitys; // displays the bounding boxes of all view models and optionally the index -extern idCVar r_showTexturePolarity; // shade triangles by texture area polarity -extern idCVar r_showTangentSpace; // shade triangles by tangent space -extern idCVar r_showDominantTri; // draw lines from vertexes to center of dominant triangles -extern idCVar r_showTextureVectors; // draw each triangles texture (tangent) vectors -extern idCVar r_showLights; // 1 = print light info, 2 = also draw volumes -extern idCVar r_showLightCount; // colors surfaces based on light count -extern idCVar r_showShadows; // visualize the stencil shadow volumes -extern idCVar r_showShadowCount; // colors screen based on shadow volume depth complexity -extern idCVar r_showLightScissors; // show light scissor rectangles -extern idCVar r_showEntityScissors; // show entity scissor rectangles -extern idCVar r_showInteractionFrustums;// show a frustum for each interaction -extern idCVar r_showInteractionScissors;// show screen rectangle which contains the interaction frustum -extern idCVar r_showMemory; // print frame memory utilization -extern idCVar r_showCull; // report sphere and box culling stats -extern idCVar r_showInteractions; // report interaction generation activity -extern idCVar r_showSurfaces; // report surface/light/shadow counts -extern idCVar r_showPrimitives; // report vertex/index/draw counts -extern idCVar r_showPortals; // draw portal outlines in color based on passed / not passed -extern idCVar r_showAlloc; // report alloc/free counts -extern idCVar r_showSkel; // draw the skeleton when model animates -extern idCVar r_showOverDraw; // show overdraw -extern idCVar r_jointNameScale; // size of joint names when r_showskel is set to 1 -extern idCVar r_jointNameOffset; // offset of joint names when r_showskel is set to 1 - -extern idCVar r_testGamma; // draw a grid pattern to test gamma levels -extern idCVar r_testStepGamma; // draw a grid pattern to test gamma levels -extern idCVar r_testGammaBias; // draw a grid pattern to test gamma levels - -extern idCVar r_testARBProgram; // experiment with vertex/fragment programs - -extern idCVar r_singleLight; // suppress all but one light -extern idCVar r_singleEntity; // suppress all but one entity -extern idCVar r_singleArea; // only draw the portal area the view is actually in -extern idCVar r_singleSurface; // suppress all but one surface on each entity -extern idCVar r_shadowPolygonOffset; // bias value added to depth test for stencil shadow drawing -extern idCVar r_shadowPolygonFactor; // scale value for stencil shadow drawing - -extern idCVar r_jitter; // randomly subpixel jitter the projection matrix -extern idCVar r_lightSourceRadius; // for soft-shadow sampling -extern idCVar r_lockSurfaces; -extern idCVar r_orderIndexes; // perform index reorganization to optimize vertex use - -extern idCVar r_debugLineDepthTest; // perform depth test on debug lines -extern idCVar r_debugLineWidth; // width of debug lines -extern idCVar r_debugArrowStep; // step size of arrow cone line rotation in degrees -extern idCVar r_debugPolygonFilled; - -extern idCVar r_materialOverride; // override all materials - -extern idCVar r_debugRenderToTexture; - -extern idCVar r_glDebugContext; // DG: use debug context to call logging callbacks on GL errors -extern idCVar r_enableDepthCapture; // DG: disable capturing depth buffer, used for soft particles -extern idCVar r_useSoftParticles; - -/* -==================================================================== - -GL wrapper/helper functions - -==================================================================== -*/ - -void GL_SelectTexture( int unit ); -void GL_CheckErrors( void ); -void GL_ClearStateDelta( void ); -void GL_State( int stateVector ); -void GL_TexEnv( int env ); -void GL_Cull( int cullType ); - -const int GLS_SRCBLEND_ZERO = 0x00000001; -const int GLS_SRCBLEND_ONE = 0x0; -const int GLS_SRCBLEND_DST_COLOR = 0x00000003; -const int GLS_SRCBLEND_ONE_MINUS_DST_COLOR = 0x00000004; -const int GLS_SRCBLEND_SRC_ALPHA = 0x00000005; -const int GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA = 0x00000006; -const int GLS_SRCBLEND_DST_ALPHA = 0x00000007; -const int GLS_SRCBLEND_ONE_MINUS_DST_ALPHA = 0x00000008; -const int GLS_SRCBLEND_ALPHA_SATURATE = 0x00000009; -const int GLS_SRCBLEND_BITS = 0x0000000f; - -const int GLS_DSTBLEND_ZERO = 0x0; -const int GLS_DSTBLEND_ONE = 0x00000020; -const int GLS_DSTBLEND_SRC_COLOR = 0x00000030; -const int GLS_DSTBLEND_ONE_MINUS_SRC_COLOR = 0x00000040; -const int GLS_DSTBLEND_SRC_ALPHA = 0x00000050; -const int GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA = 0x00000060; -const int GLS_DSTBLEND_DST_ALPHA = 0x00000070; -const int GLS_DSTBLEND_ONE_MINUS_DST_ALPHA = 0x00000080; -const int GLS_DSTBLEND_BITS = 0x000000f0; - - -// these masks are the inverse, meaning when set the glColorMask value will be 0, -// preventing that channel from being written -const int GLS_DEPTHMASK = 0x00000100; -const int GLS_REDMASK = 0x00000200; -const int GLS_GREENMASK = 0x00000400; -const int GLS_BLUEMASK = 0x00000800; -const int GLS_ALPHAMASK = 0x00001000; -const int GLS_COLORMASK = (GLS_REDMASK|GLS_GREENMASK|GLS_BLUEMASK); - -const int GLS_POLYMODE_LINE = 0x00002000; - -const int GLS_DEPTHFUNC_ALWAYS = 0x00010000; -const int GLS_DEPTHFUNC_EQUAL = 0x00020000; -const int GLS_DEPTHFUNC_LESS = 0x0; - -const int GLS_ATEST_EQ_255 = 0x10000000; -const int GLS_ATEST_LT_128 = 0x20000000; -const int GLS_ATEST_GE_128 = 0x40000000; -const int GLS_ATEST_BITS = 0x70000000; - -const int GLS_DEFAULT = GLS_DEPTHFUNC_ALWAYS; - -void R_Init( void ); -void R_InitOpenGL( void ); - -void R_DoneFreeType( void ); - -void R_SetColorMappings( void ); - -void R_ScreenShot_f( const idCmdArgs &args ); -void R_StencilShot( void ); - -bool R_CheckExtension( const char *name ); - - -/* -==================================================================== - -IMPLEMENTATION SPECIFIC FUNCTIONS - -==================================================================== -*/ - -typedef struct { - int width; - int height; - bool fullScreen; - bool fullScreenDesktop; - bool stereo; - int displayHz; // TODO: SDL3 uses float - int multiSamples; -} glimpParms_t; - -bool GLimp_Init( glimpParms_t parms ); -// If the desired mode can't be set satisfactorily, false will be returned. -// The renderer will then reset the glimpParms to "safe mode" of 640x480 -// fullscreen and try again. If that also fails, the error will be fatal. - -bool GLimp_SetScreenParms( glimpParms_t parms ); -// will set up gl up with the new parms - -void GLimp_Shutdown( void ); -// Destroys the rendering context, closes the window, resets the resolution, -// and resets the gamma ramps. - -void GLimp_SwapBuffers( void ); -// Calls the system specific swapbuffers routine, and may also perform -// other system specific cvar checks that happen every frame. -// This will not be called if 'r_drawBuffer GL_FRONT' - -void GLimp_SetGamma( unsigned short red[256], - unsigned short green[256], - unsigned short blue[256] ); -// Sets the hardware gamma ramps for gamma and brightness adjustment. -// These are now taken as 16 bit values, so we can take full advantage -// of dacs with >8 bits of precision - -void GLimp_ResetGamma(); -// resets the gamma to what it was at startup - -// Returns false if the system only has a single processor - -void GLimp_ActivateContext( void ); -void GLimp_DeactivateContext( void ); -// These are used for managing SMP handoffs of the OpenGL context -// between threads, and as a performance tunining aid. Setting -// 'r_skipRenderContext 1' will call GLimp_DeactivateContext() before -// the 3D rendering code, and GLimp_ActivateContext() afterwards. On -// most OpenGL implementations, this will result in all OpenGL calls -// being immediate returns, which lets us guage how much time is -// being spent inside OpenGL. - -const int GRAB_GRABMOUSE = (1 << 0); -const int GRAB_HIDECURSOR = (1 << 1); -const int GRAB_RELATIVEMOUSE = (1 << 2); -const int GRAB_ENABLETEXTINPUT = (1 << 3); // only used with SDL3, where textinput must be explicitly activated - -void GLimp_GrabInput(int flags); - -bool GLimp_SetSwapInterval( int swapInterval ); -bool GLimp_SetWindowResizable( bool enableResizable ); -void GLimp_UpdateWindowSize(); - -glimpParms_t GLimp_GetCurState(); - -/* -==================================================================== - -MAIN - -==================================================================== -*/ - -void R_RenderView( viewDef_t *parms ); - -// performs radius cull first, then corner cull -bool R_CullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ); -bool R_RadiusCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ); -bool R_CornerCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ); - -void R_AxisToModelMatrix( const idMat3 &axis, const idVec3 &origin, float modelMatrix[16] ); - -// note that many of these assume a normalized matrix, and will not work with scaled axis -void R_GlobalPointToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ); -void R_GlobalVectorToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ); -void R_GlobalPlaneToLocal( const float modelMatrix[16], const idPlane &in, idPlane &out ); -void R_PointTimesMatrix( const float modelMatrix[16], const idVec4 &in, idVec4 &out ); -void R_LocalPointToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ); -void R_LocalVectorToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ); -void R_LocalPlaneToGlobal( const float modelMatrix[16], const idPlane &in, idPlane &out ); -void R_TransformEyeZToWin( float src_z, const float *projectionMatrix, float &dst_z ); - -void R_GlobalToNormalizedDeviceCoordinates( const idVec3 &global, idVec3 &ndc ); - -void R_TransformModelToClip( const idVec3 &src, const float *modelMatrix, const float *projectionMatrix, idPlane &eye, idPlane &dst ); - -void R_TransformClipToDevice( const idPlane &clip, const viewDef_t *view, idVec3 &normalized ); - -void R_TransposeGLMatrix( const float in[16], float out[16] ); - -void R_SetViewMatrix( viewDef_t *viewDef ); - -void myGlMultMatrix( const float *a, const float *b, float *out ); - -/* -============================================================ - -LIGHT - -============================================================ -*/ - -void R_ListRenderLightDefs_f( const idCmdArgs &args ); -void R_ListRenderEntityDefs_f( const idCmdArgs &args ); - -bool R_IssueEntityDefCallback( idRenderEntityLocal *def ); -idRenderModel *R_EntityDefDynamicModel( idRenderEntityLocal *def ); - -viewEntity_t *R_SetEntityDefViewEntity( idRenderEntityLocal *def ); -viewLight_t *R_SetLightDefViewLight( idRenderLightLocal *def ); - -void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const renderEntity_t *renderEntity, - const idMaterial *shader, const idScreenRect &scissor, const float soft_particle_radius = -1.0f ); // soft particles in #3878 - -void R_LinkLightSurf( const drawSurf_t **link, const srfTriangles_t *tri, const viewEntity_t *space, - const idRenderLightLocal *light, const idMaterial *shader, const idScreenRect &scissor, bool viewInsideShadow ); - -bool R_CreateAmbientCache( srfTriangles_t *tri, bool needsLighting ); -bool R_CreateLightingCache( const idRenderEntityLocal *ent, const idRenderLightLocal *light, srfTriangles_t *tri ); -void R_CreatePrivateShadowCache( srfTriangles_t *tri ); -void R_CreateVertexProgramShadowCache( srfTriangles_t *tri ); - -/* -============================================================ - -LIGHTRUN - -============================================================ -*/ - -void R_RegenerateWorld_f( const idCmdArgs &args ); - -void R_ModulateLights_f( const idCmdArgs &args ); - -void R_SetLightProject( idPlane lightProject[4], const idVec3 origin, const idVec3 targetPoint, - const idVec3 rightVector, const idVec3 upVector, const idVec3 start, const idVec3 stop ); - -void R_AddLightSurfaces( void ); -void R_AddModelSurfaces( void ); -void R_RemoveUnecessaryViewLights( void ); - -void R_FreeDerivedData( void ); -void R_ReCreateWorldReferences( void ); - -void R_CreateEntityRefs( idRenderEntityLocal *def ); -void R_CreateLightRefs( idRenderLightLocal *light ); - -void R_DeriveLightData( idRenderLightLocal *light ); -void R_FreeLightDefDerivedData( idRenderLightLocal *light ); -void R_CheckForEntityDefsUsingModel( idRenderModel *model ); - -void R_ClearEntityDefDynamicModel( idRenderEntityLocal *def ); -void R_FreeEntityDefDerivedData( idRenderEntityLocal *def, bool keepDecals, bool keepCachedDynamicModel ); -void R_FreeEntityDefCachedDynamicModel( idRenderEntityLocal *def ); -void R_FreeEntityDefDecals( idRenderEntityLocal *def ); -void R_FreeEntityDefOverlay( idRenderEntityLocal *def ); -void R_FreeEntityDefFadedDecals( idRenderEntityLocal *def, int time ); - -void R_CreateLightDefFogPortals( idRenderLightLocal *ldef ); - -/* -============================================================ - -POLYTOPE - -============================================================ -*/ - -srfTriangles_t *R_PolytopeSurface( int numPlanes, const idPlane *planes, idWinding **windings ); - -/* -============================================================ - -RENDER - -============================================================ -*/ - -void RB_EnterWeaponDepthHack(); -void RB_EnterModelDepthHack( float depth ); -void RB_LeaveDepthHack(); -void RB_DrawElementsImmediate( const srfTriangles_t *tri ); -void RB_RenderTriangleSurface( const srfTriangles_t *tri ); -void RB_T_RenderTriangleSurface( const drawSurf_t *surf ); -void RB_RenderDrawSurfListWithFunction( drawSurf_t **drawSurfs, int numDrawSurfs, - void (*triFunc_)( const drawSurf_t *) ); -void RB_RenderDrawSurfChainWithFunction( const drawSurf_t *drawSurfs, - void (*triFunc_)( const drawSurf_t *) ); -void RB_DrawShaderPasses( drawSurf_t **drawSurfs, int numDrawSurfs ); -void RB_LoadShaderTextureMatrix( const float *shaderRegisters, const textureStage_t *texture ); -void RB_GetShaderTextureMatrix( const float *shaderRegisters, const textureStage_t *texture, float matrix[16] ); -void RB_CreateSingleDrawInteractions( const drawSurf_t *surf, void (*DrawInteraction)(const drawInteraction_t *) ); - -const shaderStage_t *RB_SetLightTexture( const idRenderLightLocal *light ); - -void RB_DrawView( const void *data ); - -void RB_DetermineLightScale( void ); -void RB_STD_LightScale( void ); -void RB_BeginDrawingView (void); - -/* -============================================================ - -DRAW_STANDARD - -============================================================ -*/ - -void RB_DrawElementsWithCounters( const srfTriangles_t *tri ); -void RB_DrawShadowElementsWithCounters( const srfTriangles_t *tri, int numIndexes ); -void RB_STD_FillDepthBuffer( drawSurf_t **drawSurfs, int numDrawSurfs ); -void RB_BindVariableStageImage( const textureStage_t *texture, const float *shaderRegisters ); -void RB_BindStageTexture( const float *shaderRegisters, const textureStage_t *texture, const drawSurf_t *surf ); -void RB_FinishStageTexture( const textureStage_t *texture, const drawSurf_t *surf ); -void RB_StencilShadowPass( const drawSurf_t *drawSurfs ); -void RB_STD_DrawView( void ); -void RB_STD_FogAllLights( void ); -void RB_BakeTextureMatrixIntoTexgen( idPlane lightProject[3], const float textureMatrix[16] ); - -/* -============================================================ - -DRAW_* - -============================================================ -*/ - -void R_ARB2_Init( void ); -void RB_ARB2_DrawInteractions( void ); -void R_ReloadARBPrograms_f( const idCmdArgs &args ); -int R_FindARBProgram( GLenum target, const char *program ); - -typedef enum { - PROG_INVALID, - VPROG_INTERACTION, - VPROG_ENVIRONMENT, - VPROG_BUMPY_ENVIRONMENT, - VPROG_STENCIL_SHADOW, - VPROG_TEST, - FPROG_INTERACTION, - FPROG_ENVIRONMENT, - FPROG_BUMPY_ENVIRONMENT, - FPROG_TEST, - VPROG_AMBIENT, - FPROG_AMBIENT, - VPROG_GLASSWARP, - FPROG_GLASSWARP, - // SteveL #3878: soft particles - VPROG_SOFT_PARTICLE, - FPROG_SOFT_PARTICLE, - // - PROG_USER -} program_t; - -/* - - All vertex programs use the same constant register layout: - -c[4] localLightOrigin -c[5] localViewOrigin -c[6] lightProjection S -c[7] lightProjection T -c[8] lightProjection Q -c[9] lightFalloff S -c[10] bumpMatrix S -c[11] bumpMatrix T -c[12] diffuseMatrix S -c[13] diffuseMatrix T -c[14] specularMatrix S -c[15] specularMatrix T - - -c[20] light falloff tq constant - -// texture 0 was cube map -// texture 1 will be the per-surface bump map -// texture 2 will be the light falloff texture -// texture 3 will be the light projection texture -// texture 4 is the per-surface diffuse map -// texture 5 is the per-surface specular map -// texture 6 is the specular half angle cube map - -*/ - -typedef enum { - PP_LIGHT_ORIGIN = 4, - PP_VIEW_ORIGIN, - PP_LIGHT_PROJECT_S, - PP_LIGHT_PROJECT_T, - PP_LIGHT_PROJECT_Q, - PP_LIGHT_FALLOFF_S, - PP_BUMP_MATRIX_S, - PP_BUMP_MATRIX_T, - PP_DIFFUSE_MATRIX_S, - PP_DIFFUSE_MATRIX_T, - PP_SPECULAR_MATRIX_S, - PP_SPECULAR_MATRIX_T, - PP_COLOR_MODULATE, - PP_COLOR_ADD, // 17 - - PP_LIGHT_FALLOFF_TQ = 20, // only for NV programs - DG: unused - PP_GAMMA_BRIGHTNESS = 21, // DG: for gamma in shader: { r_brightness, r_brightness, r_brightness, 1/r_gamma } - // DG: for soft particles from TDM: reciprocal of _currentDepth size. - // Lets us convert a screen position to a texcoord in _currentDepth - PP_CURDEPTH_RECIPR = 22, - // DG: for soft particles from TDM: particle radius, given as { radius, 1/(fadeRange), 1/radius } - // fadeRange is the particle diameter for alpha blends (like smoke), but the particle radius for additive - // blends (light glares), because additive effects work differently. Fog is half as apparent when a wall - // is in the middle of it. Light glares lose no visibility when they have something to reflect off. - PP_PARTICLE_RADIUS = 23, - // DG: for soft particles from TDM: color channel mask. - // Particles with additive blend need their RGB channels modifying to blend them out - // Particles with an alpha blend need their alpha channel modifying. - PP_PARTICLE_COLCHAN_MASK = 24, -} programParameter_t; - - -/* -============================================================ - -TR_STENCILSHADOWS - -"facing" should have one more element than tri->numIndexes / 3, which should be set to 1 - -============================================================ -*/ - -void R_MakeShadowFrustums( idRenderLightLocal *def ); - -typedef enum { - SG_DYNAMIC, // use infinite projections - SG_STATIC, // clip to bounds - SG_OFFLINE // perform very time consuming optimizations -} shadowGen_t; - -srfTriangles_t *R_CreateShadowVolume( const idRenderEntityLocal *ent, - const srfTriangles_t *tri, const idRenderLightLocal *light, - shadowGen_t optimize, srfCullInfo_t &cullInfo ); - -/* -============================================================ - -TR_TURBOSHADOW - -Fast, non-clipped overshoot shadow volumes - -"facing" should have one more element than tri->numIndexes / 3, which should be set to 1 -calling this function may modify "facing" based on culling - -============================================================ -*/ - -srfTriangles_t *R_CreateVertexProgramTurboShadowVolume( const idRenderEntityLocal *ent, - const srfTriangles_t *tri, const idRenderLightLocal *light, - srfCullInfo_t &cullInfo ); - -srfTriangles_t *R_CreateTurboShadowVolume( const idRenderEntityLocal *ent, - const srfTriangles_t *tri, const idRenderLightLocal *light, - srfCullInfo_t &cullInfo ); - -/* -============================================================ - -util/shadowopt3 - -dmap time optimization of shadow volumes, called from R_CreateShadowVolume - -============================================================ -*/ - - -typedef struct { - idVec3 *verts; // includes both front and back projections, caller should free - int numVerts; - glIndex_t *indexes; // caller should free - - // indexes must be sorted frontCap, rearCap, silPlanes so the caps can be removed - // when the viewer is in a position that they don't need to see them - int numFrontCapIndexes; - int numRearCapIndexes; - int numSilPlaneIndexes; - int totalIndexes; -} optimizedShadow_t; - -optimizedShadow_t SuperOptimizeOccluders( idVec4 *verts, glIndex_t *indexes, int numIndexes, - idPlane projectionPlane, idVec3 projectionOrigin ); - -void CleanupOptimizedShadowTris( srfTriangles_t *tri ); - -/* -============================================================ - -TRISURF - -============================================================ -*/ - -#define USE_TRI_DATA_ALLOCATOR - -void R_InitTriSurfData( void ); -void R_ShutdownTriSurfData( void ); -void R_PurgeTriSurfData( frameData_t *frame ); -void R_ShowTriSurfMemory_f( const idCmdArgs &args ); - -srfTriangles_t * R_AllocStaticTriSurf( void ); -srfTriangles_t * R_CopyStaticTriSurf( const srfTriangles_t *tri ); -void R_AllocStaticTriSurfVerts( srfTriangles_t *tri, int numVerts ); -void R_AllocStaticTriSurfIndexes( srfTriangles_t *tri, int numIndexes ); -void R_AllocStaticTriSurfShadowVerts( srfTriangles_t *tri, int numVerts ); -void R_AllocStaticTriSurfPlanes( srfTriangles_t *tri, int numIndexes ); -void R_ResizeStaticTriSurfVerts( srfTriangles_t *tri, int numVerts ); -void R_ResizeStaticTriSurfIndexes( srfTriangles_t *tri, int numIndexes ); -void R_ResizeStaticTriSurfShadowVerts( srfTriangles_t *tri, int numVerts ); -void R_ReferenceStaticTriSurfVerts( srfTriangles_t *tri, const srfTriangles_t *reference ); -void R_ReferenceStaticTriSurfIndexes( srfTriangles_t *tri, const srfTriangles_t *reference ); -void R_FreeStaticTriSurfSilIndexes( srfTriangles_t *tri ); -void R_FreeStaticTriSurf( srfTriangles_t *tri ); -void R_FreeStaticTriSurfVertexCaches( srfTriangles_t *tri ); -void R_ReallyFreeStaticTriSurf( srfTriangles_t *tri ); -void R_FreeDeferredTriSurfs( frameData_t *frame ); -int R_TriSurfMemory( const srfTriangles_t *tri ); - -void R_BoundTriSurf( srfTriangles_t *tri ); -void R_RemoveDuplicatedTriangles( srfTriangles_t *tri ); -void R_CreateSilIndexes( srfTriangles_t *tri ); -void R_RemoveDegenerateTriangles( srfTriangles_t *tri ); -void R_RemoveUnusedVerts( srfTriangles_t *tri ); -void R_RangeCheckIndexes( const srfTriangles_t *tri ); -void R_CreateVertexNormals( srfTriangles_t *tri ); // also called by dmap -void R_DeriveFacePlanes( srfTriangles_t *tri ); // also called by renderbump -void R_CleanupTriangles( srfTriangles_t *tri, bool createNormals, bool identifySilEdges, bool useUnsmoothedTangents ); -void R_ReverseTriangles( srfTriangles_t *tri ); - -// Only deals with vertexes and indexes, not silhouettes, planes, etc. -// Does NOT perform a cleanup triangles, so there may be duplicated verts in the result. -srfTriangles_t * R_MergeSurfaceList( const srfTriangles_t **surfaces, int numSurfaces ); -srfTriangles_t * R_MergeTriangles( const srfTriangles_t *tri1, const srfTriangles_t *tri2 ); - -// if the deformed verts have significant enough texture coordinate changes to reverse the texture -// polarity of a triangle, the tangents will be incorrect -void R_DeriveTangents( srfTriangles_t *tri, bool allocFacePlanes = true ); - -// deformable meshes precalculate as much as possible from a base frame, then generate -// complete srfTriangles_t from just a new set of vertexes -typedef struct deformInfo_s { - int numSourceVerts; - - // numOutputVerts may be smaller if the input had duplicated or degenerate triangles - // it will often be larger if the input had mirrored texture seams that needed - // to be busted for proper tangent spaces - int numOutputVerts; - - int numMirroredVerts; - int * mirroredVerts; - - int numIndexes; - glIndex_t * indexes; - - glIndex_t * silIndexes; - - int numDupVerts; - int * dupVerts; - - int numSilEdges; - silEdge_t * silEdges; - - dominantTri_t * dominantTris; -} deformInfo_t; - - -deformInfo_t * R_BuildDeformInfo( int numVerts, const idDrawVert *verts, int numIndexes, const int *indexes, bool useUnsmoothedTangents ); -void R_FreeDeformInfo( deformInfo_t *deformInfo ); -int R_DeformInfoMemoryUsed( deformInfo_t *deformInfo ); - -/* -============================================================ - -SUBVIEW - -============================================================ -*/ - -bool R_PreciseCullSurface( const drawSurf_t *drawSurf, idBounds &ndcBounds ); -bool R_GenerateSubViews( void ); - -/* -============================================================ - -SCENE GENERATION - -============================================================ -*/ - -void R_InitFrameData( void ); -void R_ShutdownFrameData( void ); -int R_CountFrameData( void ); -void R_ToggleSmpFrame( void ); -void *R_FrameAlloc( int bytes ); -void *R_ClearedFrameAlloc( int bytes ); -void R_FrameFree( void *data ); - -void *R_StaticAlloc( int bytes ); // just malloc with error checking -void *R_ClearedStaticAlloc( int bytes ); // with memset -void R_StaticFree( void *data ); - - -/* -============================================================= - -RENDERER DEBUG TOOLS - -============================================================= -*/ - -float RB_DrawTextLength( const char *text, float scale, int len ); -void RB_AddDebugText( const char *text, const idVec3 &origin, float scale, const idVec4 &color, const idMat3 &viewAxis, const int align, const int lifetime, const bool depthTest ); -void RB_ClearDebugText( int time ); -void RB_AddDebugLine( const idVec4 &color, const idVec3 &start, const idVec3 &end, const int lifeTime, const bool depthTest ); -void RB_ClearDebugLines( int time ); -void RB_AddDebugPolygon( const idVec4 &color, const idWinding &winding, const int lifeTime, const bool depthTest ); -void RB_ClearDebugPolygons( int time ); -void RB_DrawBounds( const idBounds &bounds ); -void RB_ShowLights( drawSurf_t **drawSurfs, int numDrawSurfs ); -void RB_ShowLightCount( drawSurf_t **drawSurfs, int numDrawSurfs ); -void RB_PolygonClear( void ); -void RB_ScanStencilBuffer( void ); -void RB_ShowDestinationAlpha( void ); -void RB_ShowOverdraw( void ); -void RB_RenderDebugTools( drawSurf_t **drawSurfs, int numDrawSurfs ); -void RB_ShutdownDebugTools( void ); - -/* -============================================================= - -TR_BACKEND - -============================================================= -*/ - -void RB_SetDefaultGLState( void ); -void RB_SetGL2D( void ); - -void RB_ShowImages( void ); - -void RB_ExecuteBackEndCommands( const emptyCommand_t *cmds ); - - -/* -============================================================= - -TR_GUISURF - -============================================================= -*/ - -void R_SurfaceToTextureAxis( const srfTriangles_t *tri, idVec3 &origin, idVec3 axis[3] ); -void R_RenderGuiSurf( idUserInterface *gui, drawSurf_t *drawSurf ); - -/* -============================================================= - -TR_ORDERINDEXES - -============================================================= -*/ - -void R_OrderIndexes( int numIndexes, glIndex_t *indexes ); - -/* -============================================================= - -TR_DEFORM - -============================================================= -*/ - -void R_DeformDrawSurf( drawSurf_t *drawSurf ); - -/* -============================================================= - -TR_TRACE - -============================================================= -*/ - -typedef struct { - float fraction; - // only valid if fraction < 1.0 - idVec3 point; - idVec3 normal; - int indexes[3]; -} localTrace_t; - -localTrace_t R_LocalTrace( const idVec3 &start, const idVec3 &end, const float radius, const srfTriangles_t *tri ); -void RB_ShowTrace( drawSurf_t **drawSurfs, int numDrawSurfs ); - -/* -============================================================= - -TR_SHADOWBOUNDS - -============================================================= -*/ -idScreenRect R_CalcIntersectionScissor( const idRenderLightLocal * lightDef, - const idRenderEntityLocal * entityDef, - const viewDef_t * viewDef ); - -//============================================= - -#endif /* !__TR_LOCAL_H__ */ +/* +=========================================================================== + +Doom 3 GPL Source Code +Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. + +This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). + +Doom 3 Source Code is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Doom 3 Source Code is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Doom 3 Source Code. If not, see . + +In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ + +#ifndef __TR_LOCAL_H__ +#define __TR_LOCAL_H__ + +class idScreenRect; // yay for include recursion + +#include "renderer/Image.h" +#include "renderer/Interaction.h" +#include "renderer/MegaTexture.h" +#include "renderer/ModelDecal.h" +#include "renderer/ModelOverlay.h" +#include "renderer/RenderSystem.h" +#include "renderer/RenderWorld.h" + +class idRenderWorldLocal; + +// everything that is needed by the backend needs +// to be double buffered to allow it to run in +// parallel on a dual cpu machine +const int SMP_FRAMES = 1; + +const int FALLOFF_TEXTURE_SIZE = 64; + +const float DEFAULT_FOG_DISTANCE = 500.0f; + +const int FOG_ENTER_SIZE = 64; +const float FOG_ENTER = ( FOG_ENTER_SIZE + 1.0f ) / ( FOG_ENTER_SIZE * 2 ); +// picky to get the bilerp correct at terminator + + +// idScreenRect gets carried around with each drawSurf, so it makes sense +// to keep it compact, instead of just using the idBounds class +class idScreenRect { +public: + short x1, y1, x2, y2; // inclusive pixel bounds inside viewport + float zmin, zmax; // for depth bounds test + + void Clear(); // clear to backwards values + void AddPoint( float x, float y ); // adds a point + void Expand(); // expand by one pixel each way to fix roundoffs + void Intersect( const idScreenRect &rect ); + void Union( const idScreenRect &rect ); + bool Equals( const idScreenRect &rect ) const; + bool IsEmpty() const; +}; + +idScreenRect R_ScreenRectFromViewFrustumBounds( const idBounds &bounds ); +void R_ShowColoredScreenRect( const idScreenRect &rect, int colorIndex ); + +typedef enum { + DC_BAD, + DC_RENDERVIEW, + DC_UPDATE_ENTITYDEF, + DC_DELETE_ENTITYDEF, + DC_UPDATE_LIGHTDEF, + DC_DELETE_LIGHTDEF, + DC_LOADMAP, + DC_CROP_RENDER, + DC_UNCROP_RENDER, + DC_CAPTURE_RENDER, + DC_END_FRAME, + DC_DEFINE_MODEL, + DC_SET_PORTAL_STATE, + DC_UPDATE_SOUNDOCCLUSION, + DC_GUI_MODEL +} demoCommand_t; + +/* +============================================================================== + +SURFACES + +============================================================================== +*/ + +// drawSurf_t structures command the back end to render surfaces +// a given srfTriangles_t may be used with multiple viewEntity_t, +// as when viewed in a subview or multiple viewport render, or +// with multiple shaders when skinned, or, possibly with multiple +// lights, although currently each lighting interaction creates +// unique srfTriangles_t + +// drawSurf_t are always allocated and freed every frame, they are never cached +static const int DSF_VIEW_INSIDE_SHADOW = 1; +static const int DSF_SOFT_PARTICLE = 2; // #3878 - soft particles + +typedef struct drawSurf_s { + const srfTriangles_t *geo; + const struct viewEntity_s *space; + const idMaterial *material; // may be NULL for shadow volumes + float sort; // material->sort, modified by gui / entity sort offsets + const float *shaderRegisters; // evaluated and adjusted for referenceShaders + const struct drawSurf_s *nextOnLight; // viewLight chains + idScreenRect scissorRect; // for scissor clipping, local inside renderView viewport + int dsFlags; // DSF_VIEW_INSIDE_SHADOW, etc + struct vertCache_s *dynamicTexCoords; // float * in vertex cache memory + // specular directions for non vertex program cards, skybox texcoords, etc + float particle_radius; // The radius of individual quads for soft particles #3878 +} drawSurf_t; + + +typedef struct { + int numPlanes; // this is always 6 for now + idPlane planes[6]; + // positive sides facing inward + // plane 5 is always the plane the projection is going to, the + // other planes are just clip planes + // all planes are in global coordinates + + bool makeClippedPlanes; + // a projected light with a single frustum needs to make sil planes + // from triangles that clip against side planes, but a point light + // that has adjacent frustums doesn't need to +} shadowFrustum_t; + + +// areas have references to hold all the lights and entities in them +typedef struct areaReference_s { + struct areaReference_s *areaNext; // chain in the area + struct areaReference_s *areaPrev; + struct areaReference_s *ownerNext; // chain on either the entityDef or lightDef + idRenderEntityLocal *entity; // only one of entity / light will be non-NULL + idRenderLightLocal *light; // only one of entity / light will be non-NULL + struct portalArea_s *area; // so owners can find all the areas they are in +} areaReference_t; + + +// idRenderLight should become the new public interface replacing the qhandle_t to light defs in the idRenderWorld interface +class idRenderLight { +public: + virtual ~idRenderLight() {} + + virtual void FreeRenderLight() = 0; + virtual void UpdateRenderLight( const renderLight_t *re, bool forceUpdate = false ) = 0; + virtual void GetRenderLight( renderLight_t *re ) = 0; + virtual void ForceUpdate() = 0; + virtual int GetIndex() = 0; +}; + + +// idRenderEntity should become the new public interface replacing the qhandle_t to entity defs in the idRenderWorld interface +class idRenderEntity { +public: + virtual ~idRenderEntity() {} + + virtual void FreeRenderEntity() = 0; + virtual void UpdateRenderEntity( const renderEntity_t *re, bool forceUpdate = false ) = 0; + virtual void GetRenderEntity( renderEntity_t *re ) = 0; + virtual void ForceUpdate() = 0; + virtual int GetIndex() = 0; + + // overlays are extra polygons that deform with animating models for blood and damage marks + virtual void ProjectOverlay( const idPlane localTextureAxis[2], const idMaterial *material ) = 0; + virtual void RemoveDecals() = 0; +}; + + +class idRenderLightLocal : public idRenderLight { +public: + idRenderLightLocal(); + + virtual void FreeRenderLight(); + virtual void UpdateRenderLight( const renderLight_t *re, bool forceUpdate = false ); + virtual void GetRenderLight( renderLight_t *re ); + virtual void ForceUpdate(); + virtual int GetIndex(); + + renderLight_t parms; // specification + + bool lightHasMoved; // the light has changed its position since it was + // first added, so the prelight model is not valid + + float modelMatrix[16]; // this is just a rearrangement of parms.axis and parms.origin + + idRenderWorldLocal *world; + int index; // in world lightdefs + + int areaNum; // if not -1, we may be able to cull all the light's + // interactions if !viewDef->connectedAreas[areaNum] + + int lastModifiedFrameNum; // to determine if it is constantly changing, + // and should go in the dynamic frame memory, or kept + // in the cached memory + bool archived; // for demo writing + + + // derived information + idPlane lightProject[4]; + + const idMaterial *lightShader; // guaranteed to be valid, even if parms.shader isn't + idImage *falloffImage; + + idVec3 globalLightOrigin; // accounting for lightCenter and parallel + + + idPlane frustum[6]; // in global space, positive side facing out, last two are front/back + idWinding *frustumWindings[6]; // used for culling + srfTriangles_t *frustumTris; // triangulated frustumWindings[] + + int numShadowFrustums; // one for projected lights, usually six for point lights + shadowFrustum_t shadowFrustums[6]; + + int viewCount; // if == tr.viewCount, the light is on the viewDef->viewLights list + struct viewLight_s *viewLight; + + areaReference_t *references; // each area the light is present in will have a lightRef + idInteraction *firstInteraction; // doubly linked list + idInteraction *lastInteraction; + + struct doublePortal_s *foggedPortals; +}; + + +class idRenderEntityLocal : public idRenderEntity { +public: + idRenderEntityLocal(); + + virtual void FreeRenderEntity(); + virtual void UpdateRenderEntity( const renderEntity_t *re, bool forceUpdate = false ); + virtual void GetRenderEntity( renderEntity_t *re ); + virtual void ForceUpdate(); + virtual int GetIndex(); + + // overlays are extra polygons that deform with animating models for blood and damage marks + virtual void ProjectOverlay( const idPlane localTextureAxis[2], const idMaterial *material ); + virtual void RemoveDecals(); + + renderEntity_t parms; + + float modelMatrix[16]; // this is just a rearrangement of parms.axis and parms.origin + + idRenderWorldLocal *world; + int index; // in world entityDefs + + int lastModifiedFrameNum; // to determine if it is constantly changing, + // and should go in the dynamic frame memory, or kept + // in the cached memory + bool archived; // for demo writing + + idRenderModel *dynamicModel; // if parms.model->IsDynamicModel(), this is the generated data + int dynamicModelFrameCount; // continuously animating dynamic models will recreate + // dynamicModel if this doesn't == tr.viewCount + idRenderModel *cachedDynamicModel; + + idBounds referenceBounds; // the local bounds used to place entityRefs, either from parms or a model + + // a viewEntity_t is created whenever a idRenderEntityLocal is considered for inclusion + // in a given view, even if it turns out to not be visible + int viewCount; // if tr.viewCount == viewCount, viewEntity is valid, + // but the entity may still be off screen + struct viewEntity_s *viewEntity; // in frame temporary memory + + int visibleCount; + // if tr.viewCount == visibleCount, at least one ambient + // surface has actually been added by R_AddAmbientDrawsurfs + // note that an entity could still be in the view frustum and not be visible due + // to portal passing + + idRenderModelDecal *decals; // chain of decals that have been projected on this model + idRenderModelOverlay *overlay; // blood overlays on animated models + + areaReference_t *entityRefs; // chain of all references + idInteraction *firstInteraction; // doubly linked list + idInteraction *lastInteraction; + + bool needsPortalSky; +}; + + +// viewLights are allocated on the frame temporary stack memory +// a viewLight contains everything that the back end needs out of an idRenderLightLocal, +// which the front end may be modifying simultaniously if running in SMP mode. +// a viewLight may exist even without any surfaces, and may be relevent for fogging, +// but should never exist if its volume does not intersect the view frustum +typedef struct viewLight_s { + struct viewLight_s *next; + + // back end should NOT reference the lightDef, because it can change when running SMP + idRenderLightLocal *lightDef; + + // for scissor clipping, local inside renderView viewport + // scissorRect.Empty() is true if the viewEntity_t was never actually + // seen through any portals + idScreenRect scissorRect; + + // if the view isn't inside the light, we can use the non-reversed + // shadow drawing, avoiding the draws of the front and rear caps + bool viewInsideLight; + + // true if globalLightOrigin is inside the view frustum, even if it may + // be obscured by geometry. This allows us to skip shadows from non-visible objects + bool viewSeesGlobalLightOrigin; + + // if !viewInsideLight, the corresponding bit for each of the shadowFrustum + // projection planes that the view is on the negative side of will be set, + // allowing us to skip drawing the projected caps of shadows if we can't see the face + int viewSeesShadowPlaneBits; + + idVec3 globalLightOrigin; // global light origin used by backend + idPlane lightProject[4]; // light project used by backend + idPlane fogPlane; // fog plane for backend fog volume rendering + const srfTriangles_t *frustumTris; // light frustum for backend fog volume rendering + const idMaterial *lightShader; // light shader used by backend + const float *shaderRegisters; // shader registers used by backend + idImage *falloffImage; // falloff image used by backend + + const struct drawSurf_s *globalShadows; // shadow everything + const struct drawSurf_s *localInteractions; // don't get local shadows + const struct drawSurf_s *localShadows; // don't shadow local Surfaces + const struct drawSurf_s *globalInteractions; // get shadows from everything + const struct drawSurf_s *translucentInteractions; // get shadows from everything +} viewLight_t; + + +// a viewEntity is created whenever a idRenderEntityLocal is considered for inclusion +// in the current view, but it may still turn out to be culled. +// viewEntity are allocated on the frame temporary stack memory +// a viewEntity contains everything that the back end needs out of a idRenderEntityLocal, +// which the front end may be modifying simultaniously if running in SMP mode. +// A single entityDef can generate multiple viewEntity_t in a single frame, as when seen in a mirror +typedef struct viewEntity_s { + struct viewEntity_s *next; + + // back end should NOT reference the entityDef, because it can change when running SMP + idRenderEntityLocal *entityDef; + + // for scissor clipping, local inside renderView viewport + // scissorRect.Empty() is true if the viewEntity_t was never actually + // seen through any portals, but was created for shadow casting. + // a viewEntity can have a non-empty scissorRect, meaning that an area + // that it is in is visible, and still not be visible. + idScreenRect scissorRect; + + bool weaponDepthHack; + float modelDepthHack; + + float modelMatrix[16]; // local coords to global coords + float modelViewMatrix[16]; // local coords to eye coords +} viewEntity_t; + + +const int MAX_CLIP_PLANES = 1; // we may expand this to six for some subview issues + +// viewDefs are allocated on the frame temporary stack memory +typedef struct viewDef_s { + // specified in the call to DrawScene() + renderView_t renderView; + + float projectionMatrix[16]; + viewEntity_t worldSpace; + + idRenderWorldLocal *renderWorld; + + float floatTime; + + idVec3 initialViewAreaOrigin; + // Used to find the portalArea that view flooding will take place from. + // for a normal view, the initialViewOrigin will be renderView.viewOrg, + // but a mirror may put the projection origin outside + // of any valid area, or in an unconnected area of the map, so the view + // area must be based on a point just off the surface of the mirror / subview. + // It may be possible to get a failed portal pass if the plane of the + // mirror intersects a portal, and the initialViewAreaOrigin is on + // a different side than the renderView.viewOrg is. + + bool isSubview; // true if this view is not the main view + bool isMirror; // the portal is a mirror, invert the face culling + bool isXraySubview; + + bool isEditor; + + int numClipPlanes; // mirrors will often use a single clip plane + idPlane clipPlanes[MAX_CLIP_PLANES]; // in world space, the positive side + // of the plane is the visible side + idScreenRect viewport; // in real pixels and proper Y flip + + idScreenRect scissor; + // for scissor clipping, local inside renderView viewport + // subviews may only be rendering part of the main view + // these are real physical pixel values, possibly scaled and offset from the + // renderView x/y/width/height + + struct viewDef_s *superView; // never go into an infinite subview loop + struct drawSurf_s *subviewSurface; + + // drawSurfs are the visible surfaces of the viewEntities, sorted + // by the material sort parameter + drawSurf_t **drawSurfs; // we don't use an idList for this, because + int numDrawSurfs; // it is allocated in frame temporary memory + int maxDrawSurfs; // may be resized + + struct viewLight_s *viewLights; // chain of all viewLights effecting view + struct viewEntity_s *viewEntitys; // chain of all viewEntities effecting view, including off screen ones casting shadows + // we use viewEntities as a check to see if a given view consists solely + // of 2D rendering, which we can optimize in certain ways. A 2D view will + // not have any viewEntities + + idPlane frustum[5]; // positive sides face outward, [4] is the front clip plane + idFrustum viewFrustum; + + int areaNum; // -1 = not in a valid area + + bool *connectedAreas; + // An array in frame temporary memory that lists if an area can be reached without + // crossing a closed door. This is used to avoid drawing interactions + // when the light is behind a closed door. + +} viewDef_t; + + +// complex light / surface interactions are broken up into multiple passes of a +// simple interaction shader +typedef struct { + const drawSurf_t *surf; + + idImage *lightImage; + idImage *lightFalloffImage; + idImage *bumpImage; + idImage *diffuseImage; + idImage *specularImage; + + idVec4 diffuseColor; // may have a light color baked into it, will be < tr.backEndRendererMaxLight + idVec4 specularColor; // may have a light color baked into it, will be < tr.backEndRendererMaxLight + stageVertexColor_t vertexColor; // applies to both diffuse and specular + + int ambientLight; // use tr.ambientNormalMap instead of normalization cube map + // (not a bool just to avoid an uninitialized memory check of the pad region by valgrind) + + // these are loaded into the vertex program + idVec4 localLightOrigin; + idVec4 localViewOrigin; + idVec4 lightProjection[4]; // in local coordinates, possibly with a texture matrix baked in + idVec4 bumpMatrix[2]; + idVec4 diffuseMatrix[2]; + idVec4 specularMatrix[2]; +} drawInteraction_t; + + +/* +============================================================= + +RENDERER BACK END COMMAND QUEUE + +TR_CMDS + +============================================================= +*/ + +typedef enum { + RC_NOP, + RC_DRAW_VIEW, + RC_SET_BUFFER, + RC_COPY_RENDER, + RC_SWAP_BUFFERS // can't just assume swap at end of list because + // of forced list submission before syncs +} renderCommand_t; + +typedef struct { + renderCommand_t commandId, *next; +} emptyCommand_t; + +typedef struct { + renderCommand_t commandId, *next; + GLenum buffer; + int frameCount; +} setBufferCommand_t; + +typedef struct { + renderCommand_t commandId, *next; + viewDef_t *viewDef; +} drawSurfsCommand_t; + +typedef struct { + renderCommand_t commandId, *next; + int x, y, imageWidth, imageHeight; + idImage *image; + int cubeFace; // when copying to a cubeMap +} copyRenderCommand_t; + + +//======================================================================= + +// this is the inital allocation for max number of drawsurfs +// in a given view, but it will automatically grow if needed +const int INITIAL_DRAWSURFS = 0x4000; + +// a request for frame memory will never fail +// (until malloc fails), but it may force the +// allocation of a new memory block that will +// be discontinuous with the existing memory +typedef struct frameMemoryBlock_s { + struct frameMemoryBlock_s *next; + int size; + int used; + int poop; // so that base is 16 byte aligned + byte base[4]; // dynamically allocated as [size] +} frameMemoryBlock_t; + +// all of the information needed by the back end must be +// contained in a frameData_t. This entire structure is +// duplicated so the front and back end can run in parallel +// on an SMP machine (OBSOLETE: this capability has been removed) +typedef struct { + // one or more blocks of memory for all frame + // temporary allocations + frameMemoryBlock_t *memory; + + // alloc will point somewhere into the memory chain + frameMemoryBlock_t *alloc; + + srfTriangles_t *firstDeferredFreeTriSurf; + srfTriangles_t *lastDeferredFreeTriSurf; + + int memoryHighwater; // max used on any frame + + // the currently building command list + // commands can be inserted at the front if needed, as for required + // dynamically generated textures + emptyCommand_t *cmdHead, *cmdTail; // may be of other command type based on commandId +} frameData_t; + +extern frameData_t *frameData; + +//======================================================================= + +void R_ClearCommandChain( void ); +void R_AddDrawViewCmd( viewDef_t *parms ); + +void R_ReloadGuis_f( const idCmdArgs &args ); +void R_ListGuis_f( const idCmdArgs &args ); + +void *R_GetCommandBuffer( int bytes ); + +// this allows a global override of all materials +bool R_GlobalShaderOverride( const idMaterial **shader ); + +// this does various checks before calling the idDeclSkin +const idMaterial *R_RemapShaderBySkin( const idMaterial *shader, const idDeclSkin *customSkin, const idMaterial *customShader ); + + +//==================================================== + + +/* +** performanceCounters_t +*/ +typedef struct { + int c_sphere_cull_in, c_sphere_cull_clip, c_sphere_cull_out; + int c_box_cull_in, c_box_cull_out; + int c_createInteractions; // number of calls to idInteraction::CreateInteraction + int c_createLightTris; + int c_createShadowVolumes; + int c_generateMd5; + int c_entityDefCallbacks; + int c_alloc, c_free; // counts for R_StaticAllc/R_StaticFree + int c_visibleViewEntities; + int c_shadowViewEntities; + int c_viewLights; + int c_numViews; // number of total views rendered + int c_deformedSurfaces; // idMD5Mesh::GenerateSurface + int c_deformedVerts; // idMD5Mesh::GenerateSurface + int c_deformedIndexes; // idMD5Mesh::GenerateSurface + int c_tangentIndexes; // R_DeriveTangents() + int c_entityUpdates, c_lightUpdates, c_entityReferences, c_lightReferences; + int c_guiSurfs; + int frontEndMsec; // sum of time in all RE_RenderScene's in a frame +} performanceCounters_t; + + +typedef struct { + int current2DMap; + int current3DMap; + int currentCubeMap; + int texEnv; + textureType_t textureType; +} tmu_t; + +const int MAX_MULTITEXTURE_UNITS = 8; +typedef struct { + tmu_t tmu[MAX_MULTITEXTURE_UNITS]; + int currenttmu; + + int faceCulling; + int glStateBits; + bool forceGlState; // the next GL_State will ignore glStateBits and set everything +} glstate_t; + + +typedef struct { + int c_surfaces; + int c_shaders; + int c_vertexes; + int c_indexes; // one set per pass + int c_totalIndexes; // counting all passes + + int c_drawElements; + int c_drawIndexes; + int c_drawVertexes; + int c_drawRefIndexes; + int c_drawRefVertexes; + + int c_shadowElements; + int c_shadowIndexes; + int c_shadowVertexes; + + int c_vboIndexes; + float c_overDraw; + + float maxLightValue; // for light scale + int msec; // total msec for backend run +} backEndCounters_t; + +// all state modified by the back end is separated +// from the front end state +typedef struct { + int frameCount; // used to track all images used in a frame + const viewDef_t *viewDef; + backEndCounters_t pc; + + const viewEntity_t *currentSpace; // for detecting when a matrix must change + idScreenRect currentScissor; + // for scissor clipping, local inside renderView viewport + + viewLight_t *vLight; + int depthFunc; // GLS_DEPTHFUNC_EQUAL, or GLS_DEPTHFUNC_LESS for translucent + float lightTextureMatrix[16]; // only if lightStage->texture.hasMatrix + float lightColor[4]; // evaluation of current light's color stage + + float lightScale; // Every light color calaculation will be multiplied by this, + // which will guarantee that the result is < tr.backEndRendererMaxLight + // A card with high dynamic range will have this set to 1.0 + float overBright; // The amount that all light interactions must be multiplied by + // with post processing to get the desired total light level. + // A high dynamic range card will have this set to 1.0. + + bool currentRenderCopied; // true if any material has already referenced _currentRender + + // our OpenGL state deltas + glstate_t glState; + + int c_copyFrameBuffer; +} backEndState_t; + + +const int MAX_GUI_SURFACES = 1024; // default size of the drawSurfs list for guis, will +// be automatically expanded as needed + +typedef enum { + BE_ARB2, + BE_BAD +} backEndName_t; + +typedef struct { + int x, y, width, height; // these are in physical, OpenGL Y-at-bottom pixels +} renderCrop_t; +static const int MAX_RENDER_CROPS = 8; + +/* +** Most renderer globals are defined here. +** backend functions should never modify any of these fields, +** but may read fields that aren't dynamically modified +** by the frontend. +*/ +class idRenderSystemLocal : public idRenderSystem { +public: + // external functions + virtual void Init( void ); + virtual void Shutdown( void ); + virtual void InitOpenGL( void ); + virtual void ShutdownOpenGL( void ); + virtual bool IsOpenGLRunning( void ) const; + virtual bool IsFullScreen( void ) const; + virtual int GetScreenWidth( void ) const; + virtual int GetScreenHeight( void ) const; + virtual idRenderWorld *AllocRenderWorld( void ); + virtual void FreeRenderWorld( idRenderWorld *rw ); + virtual void BeginLevelLoad( void ); + virtual void EndLevelLoad( void ); + virtual bool RegisterFont( const char *fontName, fontInfoEx_t &font ); + virtual void SetColor( const idVec4 &rgba ); + virtual void SetColor4( float r, float g, float b, float a ); + virtual void DrawStretchPic( const idDrawVert *verts, const glIndex_t *indexes, int vertCount, int indexCount, const idMaterial *material, + bool clip = true, float x = 0.0f, float y = 0.0f, float w = 640.0f, float h = 0.0f ); + virtual void DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial *material ); + + virtual void DrawStretchTri( idVec2 p1, idVec2 p2, idVec2 p3, idVec2 t1, idVec2 t2, idVec2 t3, const idMaterial *material ); + virtual void GlobalToNormalizedDeviceCoordinates( const idVec3 &global, idVec3 &ndc ); + virtual void GetGLSettings( int &width, int &height ); + virtual void PrintMemInfo( MemInfo_t *mi ); + + virtual void DrawSmallChar( int x, int y, int ch, const idMaterial *material ); + virtual void DrawSmallStringExt( int x, int y, const char *string, const idVec4 &setColor, bool forceColor, const idMaterial *material ); + virtual void DrawBigChar( int x, int y, int ch, const idMaterial *material ); + virtual void DrawBigStringExt( int x, int y, const char *string, const idVec4 &setColor, bool forceColor, const idMaterial *material ); + virtual void WriteDemoPics(); + virtual void DrawDemoPics(); + virtual void BeginFrame( int windowWidth, int windowHeight ); + virtual void EndFrame( int *frontEndMsec, int *backEndMsec ); + virtual void TakeScreenshot( int width, int height, const char *fileName, int downSample, renderView_t *ref ); + virtual void CropRenderSize( int width, int height, bool makePowerOfTwo = false, bool forceDimensions = false ); + virtual void CaptureRenderToImage( const char *imageName ); + virtual void CaptureRenderToFile( const char *fileName, bool fixAlpha ); + virtual void UnCrop(); + virtual bool UploadImage( const char *imageName, const byte *data, int width, int height ); + +public: + // internal functions + idRenderSystemLocal( void ); + ~idRenderSystemLocal( void ); + + void Clear( void ); + void SetBackEndRenderer(); // sets tr.backEndRenderer based on cvars + void RenderViewToViewport( const renderView_t *renderView, idScreenRect *viewport ); + +public: + // renderer globals + bool registered; // cleared at shutdown, set at InitOpenGL + + bool takingScreenshot; + + int frameCount; // incremented every frame + int viewCount; // incremented every view (twice a scene if subviewed) + // and every R_MarkFragments call + + int staticAllocCount; // running total of bytes allocated + + float frameShaderTime; // shader time for all non-world 2D rendering + + int viewportOffset[2]; // for doing larger-than-window tiled renderings + int tiledViewport[2]; + + // determines which back end to use, and if vertex programs are in use + backEndName_t backEndRenderer; + bool backEndRendererHasVertexPrograms; + float backEndRendererMaxLight; // 1.0 for standard, unlimited for floats + // determines how much overbrighting needs + // to be done post-process + + idVec4 ambientLightVector; // used for "ambient bump mapping" + + float sortOffset; // for determinist sorting of equal sort materials + + idListworlds; + + idRenderWorldLocal *primaryWorld; + renderView_t primaryRenderView; + viewDef_t *primaryView; + // many console commands need to know which world they should operate on + + const idMaterial *defaultMaterial; + idImage *testImage; + idCinematic *testVideo; + float testVideoStartTime; + + idImage *ambientCubeImage; // hack for testing dependent ambient lighting + + viewDef_t *viewDef; + + performanceCounters_t pc; // performance counters + + drawSurfsCommand_t lockSurfacesCmd; // use this when r_lockSurfaces = 1 + //renderView_t lockSurfacesRenderView; + viewDef_t lockSurfacesViewDef; // of locked position/view + viewDef_t lockSurfacesRealViewDef; // of actual player position + + viewEntity_t identitySpace; // can use if we don't know viewDef->worldSpace is valid + int stencilIncr, stencilDecr; // GL_INCR / INCR_WRAP_EXT, GL_DECR / GL_DECR_EXT + + renderCrop_t renderCrops[MAX_RENDER_CROPS]; + int currentRenderCrop; + + // GUI drawing variables for surface creation + int guiRecursionLevel; // to prevent infinite overruns + class idGuiModel *guiModel; + class idGuiModel *demoGuiModel; + + // DG: remember the original glConfig.vidWidth/Height values that get overwritten in BeginFrame() + // so they can be reset in EndFrame() (Editors tend to mess up the viewport by using BeginFrame()) + int origWidth; + int origHeight; +}; + +extern backEndState_t backEnd; +extern idRenderSystemLocal tr; +extern glconfig_t glConfig; // outside of TR since it shouldn't be cleared during ref re-init + + +// +// cvars +// +extern idCVar r_mode; // video mode number +extern idCVar r_displayRefresh; // optional display refresh rate option for vid mode +extern idCVar r_fullscreen; // 0 = windowed, 1 = full screen +extern idCVar r_fullscreenDesktop; // 0: 'real' fullscreen mode 1: keep resolution 'desktop' fullscreen mode +extern idCVar r_multiSamples; // number of antialiasing samples +extern idCVar r_windowResizable; // DG: allow resizing and maximizing the window + +extern idCVar r_ignore; // used for random debugging without defining new vars +extern idCVar r_ignore2; // used for random debugging without defining new vars +extern idCVar r_znear; // near Z clip plane + +extern idCVar r_finish; // force a call to glFinish() every frame +extern idCVar r_frontBuffer; // draw to front buffer for debugging +extern idCVar r_swapInterval; // changes the GL swap interval +extern idCVar r_offsetFactor; // polygon offset parameter +extern idCVar r_offsetUnits; // polygon offset parameter +extern idCVar r_singleTriangle; // only draw a single triangle per primitive +extern idCVar r_clear; // force screen clear every frame +extern idCVar r_shadows; // enable shadows +extern idCVar r_subviewOnly; // 1 = don't render main view, allowing subviews to be debugged +extern idCVar r_lightScale; // all light intensities are multiplied by this, which is normally 2 +extern idCVar r_flareSize; // scale the flare deforms from the material def + +extern idCVar r_gamma; // changes gamma tables +extern idCVar r_brightness; // changes gamma tables +extern idCVar r_gammaInShader; // set gamma+brightness in shader instead of modifying system gamma tables + +extern idCVar r_renderer; // arb2, etc + +extern idCVar r_checkBounds; // compare all surface bounds with precalculated ones + +extern idCVar r_useLightPortalFlow; // 1 = do a more precise area reference determination +extern idCVar r_useShadowSurfaceScissor;// 1 = scissor shadows by the scissor rect of the interaction surfaces +extern idCVar r_useConstantMaterials; // 1 = use pre-calculated material registers if possible +extern idCVar r_useInteractionTable; // create a full entityDefs * lightDefs table to make finding interactions faster +extern idCVar r_useNodeCommonChildren; // stop pushing reference bounds early when possible +extern idCVar r_useSilRemap; // 1 = consider verts with the same XYZ, but different ST the same for shadows +extern idCVar r_useCulling; // 0 = none, 1 = sphere, 2 = sphere + box +extern idCVar r_useLightCulling; // 0 = none, 1 = box, 2 = exact clip of polyhedron faces +extern idCVar r_useLightScissors; // 1 = use custom scissor rectangle for each light +extern idCVar r_useClippedLightScissors;// 0 = full screen when near clipped, 1 = exact when near clipped, 2 = exact always +extern idCVar r_useEntityCulling; // 0 = none, 1 = box +extern idCVar r_useEntityScissors; // 1 = use custom scissor rectangle for each entity +extern idCVar r_useInteractionCulling; // 1 = cull interactions +extern idCVar r_useInteractionScissors; // 1 = use a custom scissor rectangle for each interaction +extern idCVar r_useFrustumFarDistance; // if != 0 force the view frustum far distance to this distance +extern idCVar r_useShadowCulling; // try to cull shadows from partially visible lights +extern idCVar r_usePreciseTriangleInteractions; // 1 = do winding clipping to determine if each ambiguous tri should be lit +extern idCVar r_useTurboShadow; // 1 = use the infinite projection with W technique for dynamic shadows +extern idCVar r_useExternalShadows; // 1 = skip drawing caps when outside the light volume +extern idCVar r_useOptimizedShadows; // 1 = use the dmap generated static shadow volumes +extern idCVar r_useShadowVertexProgram; // 1 = do the shadow projection in the vertex program on capable cards +extern idCVar r_useShadowProjectedCull; // 1 = discard triangles outside light volume before shadowing +extern idCVar r_useDeferredTangents; // 1 = don't always calc tangents after deform +extern idCVar r_useCachedDynamicModels; // 1 = cache snapshots of dynamic models +extern idCVar r_useTwoSidedStencil; // 1 = do stencil shadows in one pass with different ops on each side +extern idCVar r_useInfiniteFarZ; // 1 = use the no-far-clip-plane trick +extern idCVar r_useScissor; // 1 = scissor clip as portals and lights are processed +extern idCVar r_usePortals; // 1 = use portals to perform area culling, otherwise draw everything +extern idCVar r_useStateCaching; // avoid redundant state changes in GL_*() calls +extern idCVar r_useCombinerDisplayLists;// if 1, put all nvidia register combiner programming in display lists +extern idCVar r_useVertexBuffers; // if 0, don't use ARB_vertex_buffer_object for vertexes +extern idCVar r_useIndexBuffers; // if 0, don't use ARB_vertex_buffer_object for indexes +extern idCVar r_useEntityCallbacks; // if 0, issue the callback immediately at update time, rather than defering +extern idCVar r_lightAllBackFaces; // light all the back faces, even when they would be shadowed +extern idCVar r_useDepthBoundsTest; // use depth bounds test to reduce shadow fill +extern idCVar r_useGLSL; // use GLSL backend for interaction passes + +extern idCVar r_skipPostProcess; // skip all post-process renderings +extern idCVar r_skipSuppress; // ignore the per-view suppressions +extern idCVar r_skipInteractions; // skip all light/surface interaction drawing +extern idCVar r_skipFrontEnd; // bypasses all front end work, but 2D gui rendering still draws +extern idCVar r_skipBackEnd; // don't draw anything +extern idCVar r_skipCopyTexture; // do all rendering, but don't actually copyTexSubImage2D +extern idCVar r_skipRender; // skip 3D rendering, but pass 2D +extern idCVar r_skipRenderContext; // NULL the rendering context during backend 3D rendering +extern idCVar r_skipTranslucent; // skip the translucent interaction rendering +extern idCVar r_skipAmbient; // bypasses all non-interaction drawing +extern idCVar r_skipNewAmbient; // bypasses all vertex/fragment program ambients +extern idCVar r_skipBlendLights; // skip all blend lights +extern idCVar r_skipFogLights; // skip all fog lights +extern idCVar r_skipSubviews; // 1 = don't render any mirrors / cameras / etc +extern idCVar r_skipGuiShaders; // 1 = don't render any gui elements on surfaces +extern idCVar r_skipParticles; // 1 = don't render any particles +extern idCVar r_skipUpdates; // 1 = don't accept any entity or light updates, making everything static +extern idCVar r_skipDeforms; // leave all deform materials in their original state +extern idCVar r_skipDynamicTextures; // don't dynamically create textures +extern idCVar r_skipLightScale; // don't do any post-interaction light scaling, makes things dim on low-dynamic range cards +extern idCVar r_skipBump; // uses a flat surface instead of the bump map +extern idCVar r_skipSpecular; // use black for specular +extern idCVar r_skipDiffuse; // use black for diffuse +extern idCVar r_skipOverlays; // skip overlay surfaces +extern idCVar r_skipROQ; + +extern idCVar r_ignoreGLErrors; + +extern idCVar r_forceLoadImages; // draw all images to screen after registration +extern idCVar r_demonstrateBug; // used during development to show IHV's their problems +extern idCVar r_screenFraction; // for testing fill rate, the resolution of the entire screen can be changed + +extern idCVar r_showUnsmoothedTangents; // highlight geometry rendered with unsmoothed tangents +extern idCVar r_showSilhouette; // highlight edges that are casting shadow planes +extern idCVar r_showVertexColor; // draws all triangles with the solid vertex color +extern idCVar r_showUpdates; // report entity and light updates and ref counts +extern idCVar r_showDemo; // report reads and writes to the demo file +extern idCVar r_showDynamic; // report stats on dynamic surface generation +extern idCVar r_showLightScale; // report the scale factor applied to drawing for overbrights +extern idCVar r_showIntensity; // draw the screen colors based on intensity, red = 0, green = 128, blue = 255 +extern idCVar r_showDefs; // report the number of modeDefs and lightDefs in view +extern idCVar r_showTrace; // show the intersection of an eye trace with the world +extern idCVar r_showSmp; // show which end (front or back) is blocking +extern idCVar r_showDepth; // display the contents of the depth buffer and the depth range +extern idCVar r_showImages; // draw all images to screen instead of rendering +extern idCVar r_showTris; // enables wireframe rendering of the world +extern idCVar r_showSurfaceInfo; // show surface material name under crosshair +extern idCVar r_showNormals; // draws wireframe normals +extern idCVar r_showEdges; // draw the sil edges +extern idCVar r_showViewEntitys; // displays the bounding boxes of all view models and optionally the index +extern idCVar r_showTexturePolarity; // shade triangles by texture area polarity +extern idCVar r_showTangentSpace; // shade triangles by tangent space +extern idCVar r_showDominantTri; // draw lines from vertexes to center of dominant triangles +extern idCVar r_showTextureVectors; // draw each triangles texture (tangent) vectors +extern idCVar r_showLights; // 1 = print light info, 2 = also draw volumes +extern idCVar r_showLightCount; // colors surfaces based on light count +extern idCVar r_showShadows; // visualize the stencil shadow volumes +extern idCVar r_showShadowCount; // colors screen based on shadow volume depth complexity +extern idCVar r_showLightScissors; // show light scissor rectangles +extern idCVar r_showEntityScissors; // show entity scissor rectangles +extern idCVar r_showInteractionFrustums;// show a frustum for each interaction +extern idCVar r_showInteractionScissors;// show screen rectangle which contains the interaction frustum +extern idCVar r_showMemory; // print frame memory utilization +extern idCVar r_showCull; // report sphere and box culling stats +extern idCVar r_showInteractions; // report interaction generation activity +extern idCVar r_showSurfaces; // report surface/light/shadow counts +extern idCVar r_showPrimitives; // report vertex/index/draw counts +extern idCVar r_showPortals; // draw portal outlines in color based on passed / not passed +extern idCVar r_showAlloc; // report alloc/free counts +extern idCVar r_showSkel; // draw the skeleton when model animates +extern idCVar r_showOverDraw; // show overdraw +extern idCVar r_jointNameScale; // size of joint names when r_showskel is set to 1 +extern idCVar r_jointNameOffset; // offset of joint names when r_showskel is set to 1 + +extern idCVar r_testGamma; // draw a grid pattern to test gamma levels +extern idCVar r_testStepGamma; // draw a grid pattern to test gamma levels +extern idCVar r_testGammaBias; // draw a grid pattern to test gamma levels + +extern idCVar r_testARBProgram; // experiment with vertex/fragment programs + +extern idCVar r_singleLight; // suppress all but one light +extern idCVar r_singleEntity; // suppress all but one entity +extern idCVar r_singleArea; // only draw the portal area the view is actually in +extern idCVar r_singleSurface; // suppress all but one surface on each entity +extern idCVar r_shadowPolygonOffset; // bias value added to depth test for stencil shadow drawing +extern idCVar r_shadowPolygonFactor; // scale value for stencil shadow drawing + +extern idCVar r_jitter; // randomly subpixel jitter the projection matrix +extern idCVar r_lightSourceRadius; // for soft-shadow sampling +extern idCVar r_lockSurfaces; +extern idCVar r_orderIndexes; // perform index reorganization to optimize vertex use + +extern idCVar r_debugLineDepthTest; // perform depth test on debug lines +extern idCVar r_debugLineWidth; // width of debug lines +extern idCVar r_debugArrowStep; // step size of arrow cone line rotation in degrees +extern idCVar r_debugPolygonFilled; + +extern idCVar r_materialOverride; // override all materials + +extern idCVar r_debugRenderToTexture; + +extern idCVar r_glDebugContext; // DG: use debug context to call logging callbacks on GL errors +extern idCVar r_enableDepthCapture; // DG: disable capturing depth buffer, used for soft particles +extern idCVar r_useSoftParticles; + +/* +==================================================================== + +GL wrapper/helper functions + +==================================================================== +*/ + +void GL_SelectTexture( int unit ); +void GL_CheckErrors( void ); +void GL_ClearStateDelta( void ); +void GL_State( int stateVector ); +void GL_TexEnv( int env ); +void GL_Cull( int cullType ); + +const int GLS_SRCBLEND_ZERO = 0x00000001; +const int GLS_SRCBLEND_ONE = 0x0; +const int GLS_SRCBLEND_DST_COLOR = 0x00000003; +const int GLS_SRCBLEND_ONE_MINUS_DST_COLOR = 0x00000004; +const int GLS_SRCBLEND_SRC_ALPHA = 0x00000005; +const int GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA = 0x00000006; +const int GLS_SRCBLEND_DST_ALPHA = 0x00000007; +const int GLS_SRCBLEND_ONE_MINUS_DST_ALPHA = 0x00000008; +const int GLS_SRCBLEND_ALPHA_SATURATE = 0x00000009; +const int GLS_SRCBLEND_BITS = 0x0000000f; + +const int GLS_DSTBLEND_ZERO = 0x0; +const int GLS_DSTBLEND_ONE = 0x00000020; +const int GLS_DSTBLEND_SRC_COLOR = 0x00000030; +const int GLS_DSTBLEND_ONE_MINUS_SRC_COLOR = 0x00000040; +const int GLS_DSTBLEND_SRC_ALPHA = 0x00000050; +const int GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA = 0x00000060; +const int GLS_DSTBLEND_DST_ALPHA = 0x00000070; +const int GLS_DSTBLEND_ONE_MINUS_DST_ALPHA = 0x00000080; +const int GLS_DSTBLEND_BITS = 0x000000f0; + + +// these masks are the inverse, meaning when set the glColorMask value will be 0, +// preventing that channel from being written +const int GLS_DEPTHMASK = 0x00000100; +const int GLS_REDMASK = 0x00000200; +const int GLS_GREENMASK = 0x00000400; +const int GLS_BLUEMASK = 0x00000800; +const int GLS_ALPHAMASK = 0x00001000; +const int GLS_COLORMASK = ( GLS_REDMASK | GLS_GREENMASK | GLS_BLUEMASK ); + +const int GLS_POLYMODE_LINE = 0x00002000; + +const int GLS_DEPTHFUNC_ALWAYS = 0x00010000; +const int GLS_DEPTHFUNC_EQUAL = 0x00020000; +const int GLS_DEPTHFUNC_LESS = 0x0; + +const int GLS_ATEST_EQ_255 = 0x10000000; +const int GLS_ATEST_LT_128 = 0x20000000; +const int GLS_ATEST_GE_128 = 0x40000000; +const int GLS_ATEST_BITS = 0x70000000; + +const int GLS_DEFAULT = GLS_DEPTHFUNC_ALWAYS; + +void R_Init( void ); +void R_InitOpenGL( void ); + +void R_DoneFreeType( void ); + +void R_SetColorMappings( void ); + +void R_ScreenShot_f( const idCmdArgs &args ); +void R_StencilShot( void ); + +bool R_CheckExtension( const char *name ); + + +/* +==================================================================== + +IMPLEMENTATION SPECIFIC FUNCTIONS + +==================================================================== +*/ + +typedef struct { + int width; + int height; + bool fullScreen; + bool fullScreenDesktop; + bool stereo; + int displayHz; // TODO: SDL3 uses float + int multiSamples; +} glimpParms_t; + +bool GLimp_Init( glimpParms_t parms ); +// If the desired mode can't be set satisfactorily, false will be returned. +// The renderer will then reset the glimpParms to "safe mode" of 640x480 +// fullscreen and try again. If that also fails, the error will be fatal. + +bool GLimp_SetScreenParms( glimpParms_t parms ); +// will set up gl up with the new parms + +void GLimp_Shutdown( void ); +// Destroys the rendering context, closes the window, resets the resolution, +// and resets the gamma ramps. + +void GLimp_SwapBuffers( void ); +// Calls the system specific swapbuffers routine, and may also perform +// other system specific cvar checks that happen every frame. +// This will not be called if 'r_drawBuffer GL_FRONT' + +void GLimp_SetGamma( unsigned short red[256], + unsigned short green[256], + unsigned short blue[256] ); +// Sets the hardware gamma ramps for gamma and brightness adjustment. +// These are now taken as 16 bit values, so we can take full advantage +// of dacs with >8 bits of precision + +void GLimp_ResetGamma(); +// resets the gamma to what it was at startup + +// Returns false if the system only has a single processor + +void GLimp_ActivateContext( void ); +void GLimp_DeactivateContext( void ); +// These are used for managing SMP handoffs of the OpenGL context +// between threads, and as a performance tunining aid. Setting +// 'r_skipRenderContext 1' will call GLimp_DeactivateContext() before +// the 3D rendering code, and GLimp_ActivateContext() afterwards. On +// most OpenGL implementations, this will result in all OpenGL calls +// being immediate returns, which lets us guage how much time is +// being spent inside OpenGL. + +const int GRAB_GRABMOUSE = ( 1 << 0 ); +const int GRAB_HIDECURSOR = ( 1 << 1 ); +const int GRAB_RELATIVEMOUSE = ( 1 << 2 ); +const int GRAB_ENABLETEXTINPUT = ( 1 << 3 ); // only used with SDL3, where textinput must be explicitly activated + +void GLimp_GrabInput( int flags ); + +bool GLimp_SetSwapInterval( int swapInterval ); +bool GLimp_SetWindowResizable( bool enableResizable ); +void GLimp_UpdateWindowSize(); + +glimpParms_t GLimp_GetCurState(); + +/* +==================================================================== + +MAIN + +==================================================================== +*/ + +void R_RenderView( viewDef_t *parms ); + +// performs radius cull first, then corner cull +bool R_CullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ); +bool R_RadiusCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ); +bool R_CornerCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ); + +void R_AxisToModelMatrix( const idMat3 &axis, const idVec3 &origin, float modelMatrix[16] ); + +// note that many of these assume a normalized matrix, and will not work with scaled axis +void R_GlobalPointToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ); +void R_GlobalVectorToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ); +void R_GlobalPlaneToLocal( const float modelMatrix[16], const idPlane &in, idPlane &out ); +void R_PointTimesMatrix( const float modelMatrix[16], const idVec4 &in, idVec4 &out ); +void R_LocalPointToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ); +void R_LocalVectorToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ); +void R_LocalPlaneToGlobal( const float modelMatrix[16], const idPlane &in, idPlane &out ); +void R_TransformEyeZToWin( float src_z, const float *projectionMatrix, float &dst_z ); + +void R_GlobalToNormalizedDeviceCoordinates( const idVec3 &global, idVec3 &ndc ); + +void R_TransformModelToClip( const idVec3 &src, const float *modelMatrix, const float *projectionMatrix, idPlane &eye, idPlane &dst ); + +void R_TransformClipToDevice( const idPlane &clip, const viewDef_t *view, idVec3 &normalized ); + +void R_TransposeGLMatrix( const float in[16], float out[16] ); + +void R_SetViewMatrix( viewDef_t *viewDef ); + +void R_MatrixMultiply( const float *a, const float *b, float *out ); + +/* +============================================================ + +LIGHT + +============================================================ +*/ + +void R_ListRenderLightDefs_f( const idCmdArgs &args ); +void R_ListRenderEntityDefs_f( const idCmdArgs &args ); + +bool R_IssueEntityDefCallback( idRenderEntityLocal *def ); +idRenderModel *R_EntityDefDynamicModel( idRenderEntityLocal *def ); + +viewEntity_t *R_SetEntityDefViewEntity( idRenderEntityLocal *def ); +viewLight_t *R_SetLightDefViewLight( idRenderLightLocal *def ); + +void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const renderEntity_t *renderEntity, + const idMaterial *shader, const idScreenRect &scissor, const float soft_particle_radius = -1.0f ); // soft particles in #3878 + +void R_LinkLightSurf( const drawSurf_t **link, const srfTriangles_t *tri, const viewEntity_t *space, + const idRenderLightLocal *light, const idMaterial *shader, const idScreenRect &scissor, bool viewInsideShadow ); + +bool R_CreateAmbientCache( srfTriangles_t *tri, bool needsLighting ); +bool R_CreateLightingCache( const idRenderEntityLocal *ent, const idRenderLightLocal *light, srfTriangles_t *tri ); +void R_CreatePrivateShadowCache( srfTriangles_t *tri ); +void R_CreateVertexProgramShadowCache( srfTriangles_t *tri ); + +/* +============================================================ + +LIGHTRUN + +============================================================ +*/ + +void R_RegenerateWorld_f( const idCmdArgs &args ); + +void R_ModulateLights_f( const idCmdArgs &args ); + +void R_SetLightProject( idPlane lightProject[4], const idVec3 origin, const idVec3 targetPoint, + const idVec3 rightVector, const idVec3 upVector, const idVec3 start, const idVec3 stop ); + +void R_AddLightSurfaces( void ); +void R_AddModelSurfaces( void ); +void R_RemoveUnecessaryViewLights( void ); + +void R_FreeDerivedData( void ); +void R_ReCreateWorldReferences( void ); + +void R_CreateEntityRefs( idRenderEntityLocal *def ); +void R_CreateLightRefs( idRenderLightLocal *light ); + +void R_DeriveLightData( idRenderLightLocal *light ); +void R_FreeLightDefDerivedData( idRenderLightLocal *light ); +void R_CheckForEntityDefsUsingModel( idRenderModel *model ); + +void R_ClearEntityDefDynamicModel( idRenderEntityLocal *def ); +void R_FreeEntityDefDerivedData( idRenderEntityLocal *def, bool keepDecals, bool keepCachedDynamicModel ); +void R_FreeEntityDefDecals( idRenderEntityLocal *def ); +void R_FreeEntityDefOverlay( idRenderEntityLocal *def ); +void R_FreeEntityDefFadedDecals( idRenderEntityLocal *def, int time ); + +void R_CreateLightDefFogPortals( idRenderLightLocal *ldef ); + +/* +============================================================ + +POLYTOPE + +============================================================ +*/ + +srfTriangles_t *R_PolytopeSurface( int numPlanes, const idPlane *planes, idWinding **windings ); + +/* +============================================================ + +RENDER + +============================================================ +*/ + +void RB_EnterWeaponDepthHack(); +void RB_EnterModelDepthHack( float depth ); +void RB_LeaveDepthHack(); +void RB_DrawElementsImmediate( const srfTriangles_t *tri ); +void RB_RenderTriangleSurface( const srfTriangles_t *tri ); +void RB_T_RenderTriangleSurface( const drawSurf_t *surf ); +void RB_RenderDrawSurfListWithFunction( drawSurf_t **drawSurfs, int numDrawSurfs, + void ( *triFunc_ )( const drawSurf_t * ) ); +void RB_RenderDrawSurfChainWithFunction( const drawSurf_t *drawSurfs, + void ( *triFunc_ )( const drawSurf_t * ) ); +void RB_LoadShaderTextureMatrix( const float *shaderRegisters, const textureStage_t *texture ); +void RB_GetShaderTextureMatrix( const float *shaderRegisters, const textureStage_t *texture, float matrix[16] ); +void RB_CreateSingleDrawInteractions( const drawSurf_t *surf, void ( *DrawInteraction )( const drawInteraction_t * ) ); + +void RB_DrawView( const void *data ); +void RB_SetProgramEnvironment( bool isPostProcess ); // so RB_STD_FillDepthBuffer() can use it +void RB_DetermineLightScale( void ); +void RB_STD_LightScale( void ); +void RB_BeginDrawingView( void ); + +/* +============================================================ + +DRAW_STANDARD + +============================================================ +*/ + +void RB_DrawElementsWithCounters( const srfTriangles_t *tri ); +void RB_DrawShadowElementsWithCounters( const srfTriangles_t *tri, int numIndexes ); +void RB_STD_FillDepthBuffer( drawSurf_t **drawSurfs, int numDrawSurfs ); +void RB_BindVariableStageImage( const textureStage_t *texture, const float *shaderRegisters ); +void RB_StencilShadowPass( const drawSurf_t *drawSurfs ); +void RB_STD_DrawView( void ); +void RB_STD_FogAllLights( void ); +void RB_BakeTextureMatrixIntoTexgen( idPlane lightProject[3], const float textureMatrix[16] ); + +/* +=========================================================================== + +DEFAULT GLSL *SHADER + +Be Extremely vary of formatting here (breaks the shaders)... +=========================================================================== +*/ + +// TODO: add gamma / brightness shader +#define GLSL_VERSION_ATTRIBS "#version 130\n" + +#define GLSL_INPUT_ATTRIBS \ + "in vec4 attrTexCoords;\n" \ + "in vec3 attrTangents0;\n" \ + "in vec3 attrTangents1;\n" \ + "in vec3 attrNormal;\n" \ + "mat3x3 u_lightMatrix = mat3x3 (attrTangents0, attrTangents1, attrNormal);\n\n" + +#define GLSL_UNIFORMS \ + "uniform vec4 u_light_origin;\n" \ + "uniform vec4 u_view_origin;\n" \ + "uniform vec4 u_color_modulate;\n" \ + "uniform vec4 u_color_add;\n" \ + "uniform mat2x4 u_diffMatrix;\n" \ + "uniform mat2x4 u_bumpMatrix;\n" \ + "uniform mat2x4 u_specMatrix;\n" \ + "uniform mat4x4 u_projMatrix;\n" \ + "uniform mat4x4 u_fallMatrix;\n" \ + "uniform sampler2D bumpImage;\n" \ + "uniform sampler2D lightFalloffImage;\n" \ + "uniform sampler2D lightProjectImage;\n" \ + "uniform sampler2D diffuseImage;\n" \ + "uniform sampler2D specularImage;\n" \ + "uniform vec4 u_constant_diffuse;\n" \ + "uniform vec4 u_constant_specular;\n\n" + +#define GLSL_VARYINGS \ + "varying vec2 diffCoords;\n" \ + "varying vec2 bumpCoords;\n" \ + "varying vec2 specCoords;\n" \ + "varying vec4 projCoords;\n" \ + "varying vec4 fallCoords;\n" \ + "varying vec3 lightDir;\n" \ + "varying vec3 halfAngle;\n" \ + "varying vec4 Color;\n" + +// these are our GLSL interaction shaders +#define interaction_vs \ + GLSL_VERSION_ATTRIBS \ + GLSL_INPUT_ATTRIBS \ + GLSL_UNIFORMS \ + GLSL_VARYINGS \ + "void main ()\n" \ + "{\n" \ + " // we must use ftransform as Doom 3 needs invariant position\n" \ + " gl_Position = ftransform ();\n" \ + "\n" \ + " diffCoords = attrTexCoords * u_diffMatrix;\n" \ + " bumpCoords = attrTexCoords * u_bumpMatrix;\n" \ + " specCoords = attrTexCoords * u_specMatrix;\n" \ + "\n" \ + " projCoords = gl_Vertex * u_projMatrix;\n" \ + " fallCoords = gl_Vertex * u_fallMatrix;\n" \ + "\n" \ + " Color = (gl_Color * u_color_modulate) + u_color_add;\n" \ + "\n" \ + " vec3 OffsetViewOrigin = (u_view_origin - gl_Vertex).xyz;\n" \ + " vec3 OffsetLightOrigin = (u_light_origin - gl_Vertex).xyz;\n" \ + "\n" \ + " lightDir = OffsetLightOrigin * u_lightMatrix;\n" \ + " halfAngle = (normalize (OffsetViewOrigin) + normalize (OffsetLightOrigin)) * u_lightMatrix;\n" \ + "}\n\n" + +#define interaction_fs \ + GLSL_VERSION_ATTRIBS \ + GLSL_UNIFORMS \ + GLSL_VARYINGS \ + "void main ()\n" \ + "{\n" \ + " vec3 normalMap = texture2D (bumpImage, bumpCoords).agb * 2.0 - 1.0;\n" \ + " vec4 lightMap = texture2DProj (lightProjectImage, projCoords);\n" \ + "\n" \ + " lightMap *= dot (normalize (lightDir), normalMap);\n" \ + " lightMap *= texture2DProj (lightFalloffImage, fallCoords);\n" \ + " lightMap *= Color;\n" \ + "\n" \ + " vec4 diffuseMap = texture2D (diffuseImage, diffCoords) * u_constant_diffuse;\n" \ + " float specularComponent = clamp ((dot (normalize (halfAngle), normalMap) - 0.75) * 4.0, 0.0, 1.0);\n" \ + "\n" \ + " vec4 specularResult = u_constant_specular * (specularComponent * specularComponent);\n" \ + " vec4 specularMap = texture2D (specularImage, specCoords) * 2.0;\n" \ + "\n" \ + " gl_FragColor = (diffuseMap + (specularResult * specularMap)) * lightMap;\n" \ + "}\n\n" + +/* 32 bit hexadecimal 0, BFG had this set to a negative value which is illegal on unsigned */ +static const GLuint INVALID_PROGRAM = 0x00000000; + +static GLuint u_light_origin = INVALID_PROGRAM; +static GLuint u_view_origin = INVALID_PROGRAM; + +static GLuint u_color_modulate = INVALID_PROGRAM; +static GLuint u_color_add = INVALID_PROGRAM; + +static GLuint u_constant_diffuse = INVALID_PROGRAM; +static GLuint u_constant_specular = INVALID_PROGRAM; + +static GLuint u_diffMatrix = INVALID_PROGRAM; +static GLuint u_bumpMatrix = INVALID_PROGRAM; +static GLuint u_specMatrix = INVALID_PROGRAM; + +static GLuint u_projMatrix = INVALID_PROGRAM; +static GLuint u_fallMatrix = INVALID_PROGRAM; + +static GLuint rb_glsl_interaction_program = INVALID_PROGRAM; + +/* +============================================================ + +DRAW_* + +============================================================ +*/ + +void R_ARB2_Init( void ); +void RB_ARB2_DrawInteractions( void ); +void R_ReloadARBPrograms_f( const idCmdArgs &args ); +int R_FindARBProgram( GLenum target, const char *program ); + +typedef enum { + PROG_INVALID, + VPROG_INTERACTION, + VPROG_ENVIRONMENT, + VPROG_BUMPY_ENVIRONMENT, + VPROG_STENCIL_SHADOW, + VPROG_TEST, + FPROG_INTERACTION, + FPROG_ENVIRONMENT, + FPROG_BUMPY_ENVIRONMENT, + FPROG_TEST, + VPROG_AMBIENT, + FPROG_AMBIENT, + VPROG_GLASSWARP, + FPROG_GLASSWARP, + // SteveL #3878: soft particles + VPROG_SOFT_PARTICLE, + FPROG_SOFT_PARTICLE, + PROG_USER +} program_t; + +/* + + All vertex programs use the same constant register layout: + +c[4] localLightOrigin +c[5] localViewOrigin +c[6] lightProjection S +c[7] lightProjection T +c[8] lightProjection Q +c[9] lightFalloff S +c[10] bumpMatrix S +c[11] bumpMatrix T +c[12] diffuseMatrix S +c[13] diffuseMatrix T +c[14] specularMatrix S +c[15] specularMatrix T + + +c[20] light falloff tq constant + +// texture 0 was cube map +// texture 1 will be the per-surface bump map +// texture 2 will be the light falloff texture +// texture 3 will be the light projection texture +// texture 4 is the per-surface diffuse map +// texture 5 is the per-surface specular map +// texture 6 is the specular half angle cube map + +*/ + +typedef enum { + PP_LIGHT_ORIGIN = 4, + PP_VIEW_ORIGIN, + PP_LIGHT_PROJECT_S, + PP_LIGHT_PROJECT_T, + PP_LIGHT_PROJECT_Q, + PP_LIGHT_FALLOFF_S, + PP_BUMP_MATRIX_S, + PP_BUMP_MATRIX_T, + PP_DIFFUSE_MATRIX_S, + PP_DIFFUSE_MATRIX_T, + PP_SPECULAR_MATRIX_S, + PP_SPECULAR_MATRIX_T, + PP_COLOR_MODULATE, + PP_COLOR_ADD, // 17 + + PP_LIGHT_FALLOFF_TQ = 20, // only for NV programs - DG: unused + PP_GAMMA_BRIGHTNESS = 21, // DG: for gamma in shader: { r_brightness, r_brightness, r_brightness, 1/r_gamma } + // DG: for soft particles from TDM: reciprocal of _currentDepth size. + // Lets us convert a screen position to a texcoord in _currentDepth + PP_CURDEPTH_RECIPR = 22, + // DG: for soft particles from TDM: particle radius, given as { radius, 1/(fadeRange), 1/radius } + // fadeRange is the particle diameter for alpha blends (like smoke), but the particle radius for additive + // blends (light glares), because additive effects work differently. Fog is half as apparent when a wall + // is in the middle of it. Light glares lose no visibility when they have something to reflect off. + PP_PARTICLE_RADIUS = 23, + // DG: for soft particles from TDM: color channel mask. + // Particles with additive blend need their RGB channels modifying to blend them out + // Particles with an alpha blend need their alpha channel modifying. + PP_PARTICLE_COLCHAN_MASK = 24, +} programParameter_t; + + +/* +============================================================ + +TR_STENCILSHADOWS + +"facing" should have one more element than tri->numIndexes / 3, which should be set to 1 + +============================================================ +*/ + +void R_MakeShadowFrustums( idRenderLightLocal *def ); + +typedef enum { + SG_DYNAMIC, // use infinite projections + SG_STATIC, // clip to bounds + SG_OFFLINE // perform very time consuming optimizations +} shadowGen_t; + +srfTriangles_t *R_CreateShadowVolume( const idRenderEntityLocal *ent, + const srfTriangles_t *tri, const idRenderLightLocal *light, + shadowGen_t optimize, srfCullInfo_t &cullInfo ); + +/* +============================================================ + +TR_TURBOSHADOW + +Fast, non-clipped overshoot shadow volumes + +"facing" should have one more element than tri->numIndexes / 3, which should be set to 1 +calling this function may modify "facing" based on culling + +============================================================ +*/ + +srfTriangles_t *R_CreateVertexProgramTurboShadowVolume( const idRenderEntityLocal *ent, + const srfTriangles_t *tri, const idRenderLightLocal *light, + srfCullInfo_t &cullInfo ); + +srfTriangles_t *R_CreateTurboShadowVolume( const idRenderEntityLocal *ent, + const srfTriangles_t *tri, const idRenderLightLocal *light, + srfCullInfo_t &cullInfo ); + +/* +============================================================ + +util/shadowopt3 + +dmap time optimization of shadow volumes, called from R_CreateShadowVolume + +============================================================ +*/ + + +typedef struct { + idVec3 *verts; // includes both front and back projections, caller should free + int numVerts; + glIndex_t *indexes; // caller should free + + // indexes must be sorted frontCap, rearCap, silPlanes so the caps can be removed + // when the viewer is in a position that they don't need to see them + int numFrontCapIndexes; + int numRearCapIndexes; + int numSilPlaneIndexes; + int totalIndexes; +} optimizedShadow_t; + +optimizedShadow_t SuperOptimizeOccluders( idVec4 *verts, glIndex_t *indexes, int numIndexes, + idPlane projectionPlane, idVec3 projectionOrigin ); + +void CleanupOptimizedShadowTris( srfTriangles_t *tri ); + +/* +============================================================ + +TRISURF + +============================================================ +*/ + +#define USE_TRI_DATA_ALLOCATOR + +void R_InitTriSurfData( void ); +void R_ShutdownTriSurfData( void ); +void R_PurgeTriSurfData( frameData_t *frame ); +void R_ShowTriSurfMemory_f( const idCmdArgs &args ); + +srfTriangles_t *R_AllocStaticTriSurf( void ); +srfTriangles_t *R_CopyStaticTriSurf( const srfTriangles_t *tri ); +void R_AllocStaticTriSurfVerts( srfTriangles_t *tri, int numVerts ); +void R_AllocStaticTriSurfIndexes( srfTriangles_t *tri, int numIndexes ); +void R_AllocStaticTriSurfShadowVerts( srfTriangles_t *tri, int numVerts ); +void R_AllocStaticTriSurfPlanes( srfTriangles_t *tri, int numIndexes ); +void R_ResizeStaticTriSurfVerts( srfTriangles_t *tri, int numVerts ); +void R_ResizeStaticTriSurfIndexes( srfTriangles_t *tri, int numIndexes ); +void R_ResizeStaticTriSurfShadowVerts( srfTriangles_t *tri, int numVerts ); +void R_ReferenceStaticTriSurfVerts( srfTriangles_t *tri, const srfTriangles_t *reference ); +void R_ReferenceStaticTriSurfIndexes( srfTriangles_t *tri, const srfTriangles_t *reference ); +void R_FreeStaticTriSurfSilIndexes( srfTriangles_t *tri ); +void R_FreeStaticTriSurf( srfTriangles_t *tri ); +void R_FreeStaticTriSurfVertexCaches( srfTriangles_t *tri ); +void R_ReallyFreeStaticTriSurf( srfTriangles_t *tri ); +void R_FreeDeferredTriSurfs( frameData_t *frame ); +int R_TriSurfMemory( const srfTriangles_t *tri ); + +void R_BoundTriSurf( srfTriangles_t *tri ); +void R_RemoveDuplicatedTriangles( srfTriangles_t *tri ); +void R_CreateSilIndexes( srfTriangles_t *tri ); +void R_RemoveDegenerateTriangles( srfTriangles_t *tri ); +void R_RemoveUnusedVerts( srfTriangles_t *tri ); +void R_RangeCheckIndexes( const srfTriangles_t *tri ); +void R_CreateVertexNormals( srfTriangles_t *tri ); // also called by dmap +void R_DeriveFacePlanes( srfTriangles_t *tri ); // also called by renderbump +void R_CleanupTriangles( srfTriangles_t *tri, bool createNormals, bool identifySilEdges, bool useUnsmoothedTangents ); +void R_ReverseTriangles( srfTriangles_t *tri ); + +// Only deals with vertexes and indexes, not silhouettes, planes, etc. +// Does NOT perform a cleanup triangles, so there may be duplicated verts in the result. +srfTriangles_t *R_MergeSurfaceList( const srfTriangles_t **surfaces, int numSurfaces ); +srfTriangles_t *R_MergeTriangles( const srfTriangles_t *tri1, const srfTriangles_t *tri2 ); + +// if the deformed verts have significant enough texture coordinate changes to reverse the texture +// polarity of a triangle, the tangents will be incorrect +void R_DeriveTangents( srfTriangles_t *tri, bool allocFacePlanes = true ); + +// deformable meshes precalculate as much as possible from a base frame, then generate +// complete srfTriangles_t from just a new set of vertexes +typedef struct deformInfo_s { + int numSourceVerts; + + // numOutputVerts may be smaller if the input had duplicated or degenerate triangles + // it will often be larger if the input had mirrored texture seams that needed + // to be busted for proper tangent spaces + int numOutputVerts; + + int numMirroredVerts; + int *mirroredVerts; + + int numIndexes; + glIndex_t *indexes; + + glIndex_t *silIndexes; + + int numDupVerts; + int *dupVerts; + + int numSilEdges; + silEdge_t *silEdges; + + dominantTri_t *dominantTris; +} deformInfo_t; + + +deformInfo_t *R_BuildDeformInfo( int numVerts, const idDrawVert *verts, int numIndexes, const int *indexes, bool useUnsmoothedTangents ); +void R_FreeDeformInfo( deformInfo_t *deformInfo ); +int R_DeformInfoMemoryUsed( deformInfo_t *deformInfo ); + +/* +============================================================ + +SUBVIEW + +============================================================ +*/ + +bool R_PreciseCullSurface( const drawSurf_t *drawSurf, idBounds &ndcBounds ); +bool R_GenerateSubViews( void ); + +/* +============================================================ + +SCENE GENERATION + +============================================================ +*/ + +void R_InitFrameData( void ); +void R_ShutdownFrameData( void ); +int R_CountFrameData( void ); +void R_ToggleSmpFrame( void ); +void *R_FrameAlloc( int bytes ); +void *R_ClearedFrameAlloc( int bytes ); +void R_FrameFree( void *data ); + +void *R_StaticAlloc( int bytes ); // just malloc with error checking +void *R_ClearedStaticAlloc( int bytes ); // with memset +void R_StaticFree( void *data ); + + +/* +============================================================= + +RENDERER DEBUG TOOLS + +============================================================= +*/ + +float RB_DrawTextLength( const char *text, float scale, int len ); +void RB_AddDebugText( const char *text, const idVec3 &origin, float scale, const idVec4 &color, const idMat3 &viewAxis, const int align, const int lifetime, const bool depthTest ); +void RB_ClearDebugText( int time ); +void RB_AddDebugLine( const idVec4 &color, const idVec3 &start, const idVec3 &end, const int lifeTime, const bool depthTest ); +void RB_ClearDebugLines( int time ); +void RB_AddDebugPolygon( const idVec4 &color, const idWinding &winding, const int lifeTime, const bool depthTest ); +void RB_ClearDebugPolygons( int time ); +void RB_DrawBounds( const idBounds &bounds ); +void RB_ShowLights( drawSurf_t **drawSurfs, int numDrawSurfs ); +void RB_ShowLightCount( drawSurf_t **drawSurfs, int numDrawSurfs ); +void RB_PolygonClear( void ); +void RB_ScanStencilBuffer( void ); +void RB_ShowDestinationAlpha( void ); +void RB_ShowOverdraw( void ); +void RB_RenderDebugTools( drawSurf_t **drawSurfs, int numDrawSurfs ); +void RB_ShutdownDebugTools( void ); + +/* +============================================================= + +TR_BACKEND + +============================================================= +*/ + +// RAII-style wrapper for glDepthBoundsEXT +class DepthBoundsTest { +public: + DepthBoundsTest( const idScreenRect &scissorRect ); + ~DepthBoundsTest(); +}; + +void RB_SetDefaultGLState( void ); +void RB_SetGL2D( void ); + +void RB_ShowImages( void ); + +void RB_ExecuteBackEndCommands( const emptyCommand_t *cmds ); + +/* +============================================================= + +TR_GUISURF + +============================================================= +*/ + +void R_SurfaceToTextureAxis( const srfTriangles_t *tri, idVec3 &origin, idVec3 axis[3] ); +void R_RenderGuiSurf( idUserInterface *gui, drawSurf_t *drawSurf ); + +/* +============================================================= + +TR_ORDERINDEXES + +============================================================= +*/ + +void R_OrderIndexes( int numIndexes, glIndex_t *indexes ); + +/* +============================================================= + +TR_DEFORM + +============================================================= +*/ + +void R_DeformDrawSurf( drawSurf_t *drawSurf ); + +/* +============================================================= + +TR_TRACE + +============================================================= +*/ + +typedef struct { + float fraction; + // only valid if fraction < 1.0 + idVec3 point; + idVec3 normal; + int indexes[3]; +} localTrace_t; + +localTrace_t R_LocalTrace( const idVec3 &start, const idVec3 &end, const float radius, const srfTriangles_t *tri ); +void RB_ShowTrace( drawSurf_t **drawSurfs, int numDrawSurfs ); + +/* +============================================================= + +TR_SHADOWBOUNDS + +============================================================= +*/ +idScreenRect R_CalcIntersectionScissor( const idRenderLightLocal *lightDef, + const idRenderEntityLocal *entityDef, + const viewDef_t *viewDef ); + +//============================================= + +#endif /* !__TR_LOCAL_H__ */ diff --git a/neo/renderer/tr_main.cpp b/neo/renderer/tr_main.cpp index 3fb5c02b4..18726c8aa 100644 --- a/neo/renderer/tr_main.cpp +++ b/neo/renderer/tr_main.cpp @@ -26,17 +26,22 @@ If you have questions concerning this license or the applicable additional terms =========================================================================== */ +// atleast ppc seems to have totally different intrinsics #if defined(__ppc__) && defined(__APPLE__) #include #endif -#if defined(__GNUC__) && defined(__SSE2__) + +#if defined(__GNUC__) && defined(__SSE__) +#include +#endif + +#if defined(_MSC_VER) #include #endif #include "sys/platform.h" #include "framework/Session.h" #include "renderer/RenderWorld_local.h" - #include "renderer/tr_local.h" //==================================================================== @@ -47,9 +52,10 @@ idScreenRect::Clear ====================== */ void idScreenRect::Clear() { - x1 = y1 = 32000; - x2 = y2 = -32000; - zmin = 0.0f; zmax = 1.0f; + x1 = y1 = 32000; + x2 = y2 = -32000; + zmin = 0.0f; + zmax = 1.0f; } /* @@ -58,21 +64,24 @@ idScreenRect::AddPoint ====================== */ void idScreenRect::AddPoint( float x, float y ) { - int ix = idMath::FtoiFast( x ); - int iy = idMath::FtoiFast( y ); - - if ( ix < x1 ) { - x1 = ix; - } - if ( ix > x2 ) { - x2 = ix; - } - if ( iy < y1 ) { - y1 = iy; - } - if ( iy > y2 ) { - y2 = iy; - } + int ix = idMath::FtoiFast( x ); + int iy = idMath::FtoiFast( y ); + + if ( ix < x1 ) { + x1 = ix; + } + + if ( ix > x2 ) { + x2 = ix; + } + + if ( iy < y1 ) { + y1 = iy; + } + + if ( iy > y2 ) { + y2 = iy; + } } /* @@ -81,10 +90,10 @@ idScreenRect::Expand ====================== */ void idScreenRect::Expand() { - x1--; - y1--; - x2++; - y2++; + x1--; + y1--; + x2++; + y2++; } /* @@ -93,18 +102,21 @@ idScreenRect::Intersect ====================== */ void idScreenRect::Intersect( const idScreenRect &rect ) { - if ( rect.x1 > x1 ) { - x1 = rect.x1; - } - if ( rect.x2 < x2 ) { - x2 = rect.x2; - } - if ( rect.y1 > y1 ) { - y1 = rect.y1; - } - if ( rect.y2 < y2 ) { - y2 = rect.y2; - } + if ( rect.x1 > x1 ) { + x1 = rect.x1; + } + + if ( rect.x2 < x2 ) { + x2 = rect.x2; + } + + if ( rect.y1 > y1 ) { + y1 = rect.y1; + } + + if ( rect.y2 < y2 ) { + y2 = rect.y2; + } } /* @@ -113,18 +125,21 @@ idScreenRect::Union ====================== */ void idScreenRect::Union( const idScreenRect &rect ) { - if ( rect.x1 < x1 ) { - x1 = rect.x1; - } - if ( rect.x2 > x2 ) { - x2 = rect.x2; - } - if ( rect.y1 < y1 ) { - y1 = rect.y1; - } - if ( rect.y2 > y2 ) { - y2 = rect.y2; - } + if ( rect.x1 < x1 ) { + x1 = rect.x1; + } + + if ( rect.x2 > x2 ) { + x2 = rect.x2; + } + + if ( rect.y1 < y1 ) { + y1 = rect.y1; + } + + if ( rect.y2 > y2 ) { + y2 = rect.y2; + } } /* @@ -133,7 +148,7 @@ idScreenRect::Equals ====================== */ bool idScreenRect::Equals( const idScreenRect &rect ) const { - return ( x1 == rect.x1 && x2 == rect.x2 && y1 == rect.y1 && y2 == rect.y2 ); + return ( x1 == rect.x1 && x2 == rect.x2 && y1 == rect.y1 && y2 == rect.y2 ); } /* @@ -142,7 +157,7 @@ idScreenRect::IsEmpty ====================== */ bool idScreenRect::IsEmpty() const { - return ( x1 > x2 || y1 > y2 ); + return ( x1 > x2 || y1 > y2 ); } /* @@ -151,19 +166,18 @@ R_ScreenRectFromViewFrustumBounds ====================== */ idScreenRect R_ScreenRectFromViewFrustumBounds( const idBounds &bounds ) { - idScreenRect screenRect; - - screenRect.x1 = idMath::FtoiFast( 0.5f * ( 1.0f - bounds[1].y ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 ) ); - screenRect.x2 = idMath::FtoiFast( 0.5f * ( 1.0f - bounds[0].y ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 ) ); - screenRect.y1 = idMath::FtoiFast( 0.5f * ( 1.0f + bounds[0].z ) * ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 ) ); - screenRect.y2 = idMath::FtoiFast( 0.5f * ( 1.0f + bounds[1].z ) * ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 ) ); - - if ( r_useDepthBoundsTest.GetInteger() ) { - R_TransformEyeZToWin( -bounds[0].x, tr.viewDef->projectionMatrix, screenRect.zmin ); - R_TransformEyeZToWin( -bounds[1].x, tr.viewDef->projectionMatrix, screenRect.zmax ); - } - - return screenRect; + idScreenRect screenRect; + + screenRect.x1 = idMath::FtoiFast( 0.5f * ( 1.0f - bounds[1].y ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 ) ); + screenRect.x2 = idMath::FtoiFast( 0.5f * ( 1.0f - bounds[0].y ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 ) ); + screenRect.y1 = idMath::FtoiFast( 0.5f * ( 1.0f + bounds[0].z ) * ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 ) ); + screenRect.y2 = idMath::FtoiFast( 0.5f * ( 1.0f + bounds[1].z ) * ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 ) ); + + if ( r_useDepthBoundsTest.GetInteger() ) { + R_TransformEyeZToWin( -bounds[0].x, tr.viewDef->projectionMatrix, screenRect.zmin ); + R_TransformEyeZToWin( -bounds[1].x, tr.viewDef->projectionMatrix, screenRect.zmax ); + } + return screenRect; } /* @@ -172,10 +186,10 @@ R_ShowColoredScreenRect ====================== */ void R_ShowColoredScreenRect( const idScreenRect &rect, int colorIndex ) { - if ( !rect.IsEmpty() ) { - static idVec4 colors[] = { colorRed, colorGreen, colorBlue, colorYellow, colorMagenta, colorCyan, colorWhite, colorPurple }; - tr.viewDef->renderWorld->DebugScreenRect( colors[colorIndex & 7], rect, tr.viewDef ); - } + if ( !rect.IsEmpty() ) { + static idVec4 colors[] = { colorRed, colorGreen, colorBlue, colorYellow, colorMagenta, colorCyan, colorWhite, colorPurple }; + tr.viewDef->renderWorld->DebugScreenRect( colors[colorIndex & 7], rect, tr.viewDef ); + } } /* @@ -184,32 +198,31 @@ R_ToggleSmpFrame ==================== */ void R_ToggleSmpFrame( void ) { - R_FreeDeferredTriSurfs( frameData ); - - // clear frame-temporary data - frameData_t *frame; - frameMemoryBlock_t *block; + R_FreeDeferredTriSurfs( frameData ); - // update the highwater mark - R_CountFrameData(); + // clear frame-temporary data + frameData_t *frame; + frameMemoryBlock_t *block; - frame = frameData; + // update the highwater mark + R_CountFrameData(); - // reset the memory allocation to the first block - frame->alloc = frame->memory; + frame = frameData; - // clear all the blocks - for ( block = frame->memory ; block ; block = block->next ) { - block->used = 0; - } + // reset the memory allocation to the first block + frame->alloc = frame->memory; - R_ClearCommandChain(); + // clear all the blocks + for ( block = frame->memory ; block ; block = block->next ) { + block->used = 0; + } + R_ClearCommandChain(); } //===================================================== -#define MEMORY_BLOCK_SIZE 0x100000 +#define MEMORY_BLOCK_SIZE 0x100000 /* ===================== @@ -217,24 +230,24 @@ R_ShutdownFrameData ===================== */ void R_ShutdownFrameData( void ) { - frameData_t *frame; - frameMemoryBlock_t *block; - - // free any current data - frame = frameData; - if ( !frame ) { - return; - } - - R_FreeDeferredTriSurfs( frame ); - - frameMemoryBlock_t *nextBlock; - for ( block = frame->memory ; block ; block = nextBlock ) { - nextBlock = block->next; - Mem_Free( block ); - } - Mem_Free( frame ); - frameData = NULL; + frameData_t *frame; + frameMemoryBlock_t *block; + + // free any current data + frame = frameData; + + if ( !frame ) { + return; + } + R_FreeDeferredTriSurfs( frame ); + + frameMemoryBlock_t *nextBlock; + for ( block = frame->memory ; block ; block = nextBlock ) { + nextBlock = block->next; + Mem_Free( block ); + } + Mem_Free( frame ); + frameData = NULL; } /* @@ -243,26 +256,27 @@ R_InitFrameData ===================== */ void R_InitFrameData( void ) { - int size; - frameData_t *frame; - frameMemoryBlock_t *block; - - R_ShutdownFrameData(); - - frameData = (frameData_t *)Mem_ClearedAlloc( sizeof( *frameData )); - frame = frameData; - size = MEMORY_BLOCK_SIZE; - block = (frameMemoryBlock_t *)Mem_Alloc( size + sizeof( *block ) ); - if ( !block ) { - common->FatalError( "R_InitFrameData: Mem_Alloc() failed" ); - } - block->size = size; - block->used = 0; - block->next = NULL; - frame->memory = block; - frame->memoryHighwater = 0; - - R_ToggleSmpFrame(); + int size; + frameData_t *frame; + frameMemoryBlock_t *block; + + R_ShutdownFrameData(); + + frameData = ( frameData_t * )Mem_ClearedAlloc( sizeof( *frameData ) ); + frame = frameData; + size = MEMORY_BLOCK_SIZE; + block = ( frameMemoryBlock_t * )Mem_Alloc( size + sizeof( *block ) ); + + if ( !block ) { + common->FatalError( "R_InitFrameData: Mem_Alloc() failed" ); + } + block->size = size; + block->used = 0; + block->next = NULL; + frame->memory = block; + frame->memoryHighwater = 0; + + R_ToggleSmpFrame(); } /* @@ -271,25 +285,26 @@ R_CountFrameData ================ */ int R_CountFrameData( void ) { - frameData_t *frame; - frameMemoryBlock_t *block; - int count; - - count = 0; - frame = frameData; - for ( block = frame->memory ; block ; block=block->next ) { - count += block->used; - if ( block == frame->alloc ) { - break; - } - } - - // note if this is a new highwater mark - if ( count > frame->memoryHighwater ) { - frame->memoryHighwater = count; - } - - return count; + frameData_t *frame; + frameMemoryBlock_t *block; + int count; + + count = 0; + frame = frameData; + + for ( block = frame->memory ; block ; block = block->next ) { + count += block->used; + + if ( block == frame->alloc ) { + break; + } + } + + // note if this is a new highwater mark + if ( count > frame->memoryHighwater ) { + frame->memoryHighwater = count; + } + return count; } /* @@ -298,19 +313,19 @@ R_StaticAlloc ================= */ void *R_StaticAlloc( int bytes ) { - void *buf; + void *buf; - tr.pc.c_alloc++; + tr.pc.c_alloc++; - tr.staticAllocCount += bytes; + tr.staticAllocCount += bytes; - buf = Mem_Alloc( bytes ); + buf = Mem_Alloc( bytes ); - // don't exit on failure on zero length allocations since the old code didn't - if ( !buf && ( bytes != 0 ) ) { - common->FatalError( "R_StaticAlloc failed on %i bytes", bytes ); - } - return buf; + // don't exit on failure on zero length allocations since the old code didn't + if ( !buf && ( bytes != 0 ) ) { + common->FatalError( "R_StaticAlloc failed on %i bytes", bytes ); + } + return buf; } /* @@ -319,11 +334,11 @@ R_ClearedStaticAlloc ================= */ void *R_ClearedStaticAlloc( int bytes ) { - void *buf; + void *buf; - buf = R_StaticAlloc( bytes ); - SIMDProcessor->Memset( buf, 0, bytes ); - return buf; + buf = R_StaticAlloc( bytes ); + SIMDProcessor->Memset( buf, 0, bytes ); + return buf; } /* @@ -332,8 +347,8 @@ R_StaticFree ================= */ void R_StaticFree( void *data ) { - tr.pc.c_free++; - Mem_Free( data ); + tr.pc.c_free++; + Mem_Free( data ); } /* @@ -362,50 +377,50 @@ Should part of this be inlined in a macro? ================ */ void *R_FrameAlloc( int bytes ) { - frameData_t *frame; - frameMemoryBlock_t *block; - void *buf; - - bytes = (bytes+16)&~15; - // see if it can be satisfied in the current block - frame = frameData; - block = frame->alloc; - - if ( block->size - block->used >= bytes ) { - buf = block->base + block->used; - block->used += bytes; - return buf; - } - - // advance to the next memory block if available - block = block->next; - // create a new block if we are at the end of - // the chain - if ( !block ) { - int size; - - size = MEMORY_BLOCK_SIZE; - block = (frameMemoryBlock_t *)Mem_Alloc( size + sizeof( *block ) ); - if ( !block ) { - common->FatalError( "R_FrameAlloc: Mem_Alloc() failed" ); - } - block->size = size; - block->used = 0; - block->next = NULL; - frame->alloc->next = block; - } - - // we could fix this if we needed to... - if ( bytes > block->size ) { - common->FatalError( "R_FrameAlloc of %i exceeded MEMORY_BLOCK_SIZE", - bytes ); - } - - frame->alloc = block; - - block->used = bytes; - - return block->base; + frameData_t *frame; + frameMemoryBlock_t *block; + void *buf; + + bytes = ( bytes + 16 ) & ~15; + + // see if it can be satisfied in the current block + frame = frameData; + block = frame->alloc; + + if ( block->size - block->used >= bytes ) { + buf = block->base + block->used; + block->used += bytes; + return buf; + } + + // advance to the next memory block if available + block = block->next; + + // create a new block if we are at the end of + // the chain + if ( !block ) { + int size; + + size = MEMORY_BLOCK_SIZE; + block = ( frameMemoryBlock_t * )Mem_Alloc( size + sizeof( *block ) ); + + if ( !block ) { + common->FatalError( "R_FrameAlloc: Mem_Alloc() failed" ); + } + block->size = size; + block->used = 0; + block->next = NULL; + frame->alloc->next = block; + } + + // we could fix this if we needed to... + if ( bytes > block->size ) { + common->FatalError( "R_FrameAlloc of %i exceeded MEMORY_BLOCK_SIZE", bytes ); + } + frame->alloc = block; + block->used = bytes; + + return block->base; } /* @@ -414,11 +429,9 @@ R_ClearedFrameAlloc ================== */ void *R_ClearedFrameAlloc( int bytes ) { - void *r; - - r = R_FrameAlloc( bytes ); - SIMDProcessor->Memset( r, 0, bytes ); - return r; + void *r = R_FrameAlloc( bytes ); + SIMDProcessor->Memset( r, 0, bytes ); + return r; } @@ -437,142 +450,124 @@ to both alloc and free. void R_FrameFree( void *data ) { } - - //========================================================================== void R_AxisToModelMatrix( const idMat3 &axis, const idVec3 &origin, float modelMatrix[16] ) { - modelMatrix[0] = axis[0][0]; - modelMatrix[4] = axis[1][0]; - modelMatrix[8] = axis[2][0]; - modelMatrix[12] = origin[0]; - - modelMatrix[1] = axis[0][1]; - modelMatrix[5] = axis[1][1]; - modelMatrix[9] = axis[2][1]; - modelMatrix[13] = origin[1]; - - modelMatrix[2] = axis[0][2]; - modelMatrix[6] = axis[1][2]; - modelMatrix[10] = axis[2][2]; - modelMatrix[14] = origin[2]; - - modelMatrix[3] = 0; - modelMatrix[7] = 0; - modelMatrix[11] = 0; - modelMatrix[15] = 1; + modelMatrix[0] = axis[0][0]; + modelMatrix[4] = axis[1][0]; + modelMatrix[8] = axis[2][0]; + modelMatrix[12] = origin[0]; + + modelMatrix[1] = axis[0][1]; + modelMatrix[5] = axis[1][1]; + modelMatrix[9] = axis[2][1]; + modelMatrix[13] = origin[1]; + + modelMatrix[2] = axis[0][2]; + modelMatrix[6] = axis[1][2]; + modelMatrix[10] = axis[2][2]; + modelMatrix[14] = origin[2]; + + modelMatrix[3] = 0; + modelMatrix[7] = 0; + modelMatrix[11] = 0; + modelMatrix[15] = 1; } - -// FIXME: these assume no skewing or scaling transforms - +// FIXME: these assume no skewing or scaling transforms (disabled SSE intrinsics on MAC ppc) void R_LocalPointToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) { -#if defined(__GNUC__) && defined(__SSE2__) - __m128 m0, m1, m2, m3; - __m128 in0, in1, in2; - float i0,i1,i2; - i0 = in[0]; - i1 = in[1]; - i2 = in[2]; - - m0 = _mm_loadu_ps(&modelMatrix[0]); - m1 = _mm_loadu_ps(&modelMatrix[4]); - m2 = _mm_loadu_ps(&modelMatrix[8]); - m3 = _mm_loadu_ps(&modelMatrix[12]); - - in0 = _mm_load1_ps(&i0); - in1 = _mm_load1_ps(&i1); - in2 = _mm_load1_ps(&i2); - - m0 = _mm_mul_ps(m0, in0); - m1 = _mm_mul_ps(m1, in1); - m2 = _mm_mul_ps(m2, in2); - - m0 = _mm_add_ps(m0, m1); - m0 = _mm_add_ps(m0, m2); - m0 = _mm_add_ps(m0, m3); - - _mm_store_ss(&out[0], m0); - m1 = (__m128) _mm_shuffle_epi32((__m128i)m0, 0x55); - _mm_store_ss(&out[1], m1); - m2 = _mm_movehl_ps(m2, m0); - _mm_store_ss(&out[2], m2); +#if !( defined(__ppc__) || defined(MACOS_X) || defined(__APPLE__) ) + int cpuid = idLib::sys->GetProcessorId(); + + // a more general approach here, bonus also supports SSE instead of minimum SSE2 + if ( cpuid & CPUID_SSE ) { + __m128 row0 = _mm_loadu_ps( &modelMatrix[0] ); + __m128 row1 = _mm_loadu_ps( &modelMatrix[4] ); + __m128 row2 = _mm_loadu_ps( &modelMatrix[8] ); + __m128 row3 = _mm_loadu_ps( &modelMatrix[12] ); + __m128 xxxx = _mm_set1_ps( in.x ); + __m128 yyyy = _mm_set1_ps( in.y ); + __m128 zzzz = _mm_set1_ps( in.z ); + __m128 res = _mm_add_ps( _mm_add_ps( _mm_mul_ps( row0, xxxx ), + _mm_mul_ps( row1, yyyy ) ), + _mm_add_ps( _mm_mul_ps( row2, zzzz ), row3 ) ); + // unaligned float x 3 store + _mm_storel_pi( ( __m64 * )&out[0], res ); + _mm_store_ss( &out[2], _mm_movehl_ps( res, res ) ); + } else { + // fall back to non SSE + out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4] + in[2] * modelMatrix[8] + modelMatrix[12]; + out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5] + in[2] * modelMatrix[9] + modelMatrix[13]; + out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6] + in[2] * modelMatrix[10] + modelMatrix[14]; + } #else - out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4] - + in[2] * modelMatrix[8] + modelMatrix[12]; - out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5] - + in[2] * modelMatrix[9] + modelMatrix[13]; - out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6] - + in[2] * modelMatrix[10] + modelMatrix[14]; + // fall back to non SSE on mac + out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4] + in[2] * modelMatrix[8] + modelMatrix[12]; + out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5] + in[2] * modelMatrix[9] + modelMatrix[13]; + out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6] + in[2] * modelMatrix[10] + modelMatrix[14]; #endif } void R_PointTimesMatrix( const float modelMatrix[16], const idVec4 &in, idVec4 &out ) { - out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4] - + in[2] * modelMatrix[8] + modelMatrix[12]; - out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5] - + in[2] * modelMatrix[9] + modelMatrix[13]; - out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6] - + in[2] * modelMatrix[10] + modelMatrix[14]; - out[3] = in[0] * modelMatrix[3] + in[1] * modelMatrix[7] - + in[2] * modelMatrix[11] + modelMatrix[15]; + out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4] + in[2] * modelMatrix[8] + modelMatrix[12]; + out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5] + in[2] * modelMatrix[9] + modelMatrix[13]; + out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6] + in[2] * modelMatrix[10] + modelMatrix[14]; + out[3] = in[0] * modelMatrix[3] + in[1] * modelMatrix[7] + in[2] * modelMatrix[11] + modelMatrix[15]; } void R_GlobalPointToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) { - idVec3 temp; + idVec3 temp; - VectorSubtract( in, &modelMatrix[12], temp ); + VectorSubtract( in, &modelMatrix[12], temp ); - out[0] = DotProduct( temp, &modelMatrix[0] ); - out[1] = DotProduct( temp, &modelMatrix[4] ); - out[2] = DotProduct( temp, &modelMatrix[8] ); + out[0] = DotProduct( temp, &modelMatrix[0] ); + out[1] = DotProduct( temp, &modelMatrix[4] ); + out[2] = DotProduct( temp, &modelMatrix[8] ); } void R_LocalVectorToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) { - out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4] - + in[2] * modelMatrix[8]; - out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5] - + in[2] * modelMatrix[9]; - out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6] - + in[2] * modelMatrix[10]; + out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4] + in[2] * modelMatrix[8]; + out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5] + in[2] * modelMatrix[9]; + out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6] + in[2] * modelMatrix[10]; } void R_GlobalVectorToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) { - out[0] = DotProduct( in, &modelMatrix[0] ); - out[1] = DotProduct( in, &modelMatrix[4] ); - out[2] = DotProduct( in, &modelMatrix[8] ); + out[0] = DotProduct( in, &modelMatrix[0] ); + out[1] = DotProduct( in, &modelMatrix[4] ); + out[2] = DotProduct( in, &modelMatrix[8] ); } void R_GlobalPlaneToLocal( const float modelMatrix[16], const idPlane &in, idPlane &out ) { - out[0] = DotProduct( in, &modelMatrix[0] ); - out[1] = DotProduct( in, &modelMatrix[4] ); - out[2] = DotProduct( in, &modelMatrix[8] ); - out[3] = in[3] + modelMatrix[12] * in[0] + modelMatrix[13] * in[1] + modelMatrix[14] * in[2]; + out[0] = DotProduct( in, &modelMatrix[0] ); + out[1] = DotProduct( in, &modelMatrix[4] ); + out[2] = DotProduct( in, &modelMatrix[8] ); + + out[3] = in[3] + modelMatrix[12] * in[0] + modelMatrix[13] * in[1] + modelMatrix[14] * in[2]; } void R_LocalPlaneToGlobal( const float modelMatrix[16], const idPlane &in, idPlane &out ) { - float offset; + float offset; - R_LocalVectorToGlobal( modelMatrix, in.Normal(), out.Normal() ); + R_LocalVectorToGlobal( modelMatrix, in.Normal(), out.Normal() ); - offset = modelMatrix[12] * out[0] + modelMatrix[13] * out[1] + modelMatrix[14] * out[2]; - out[3] = in[3] - offset; + offset = modelMatrix[12] * out[0] + modelMatrix[13] * out[1] + modelMatrix[14] * out[2]; + out[3] = in[3] - offset; } // transform Z in eye coordinates to window coordinates void R_TransformEyeZToWin( float src_z, const float *projectionMatrix, float &dst_z ) { - float clip_z, clip_w; - - // projection - clip_z = src_z * projectionMatrix[ 2 + 2 * 4 ] + projectionMatrix[ 2 + 3 * 4 ]; - clip_w = src_z * projectionMatrix[ 3 + 2 * 4 ] + projectionMatrix[ 3 + 3 * 4 ]; - - if ( clip_w <= 0.0f ) { - dst_z = 0.0f; // clamp to near plane - } else { - dst_z = clip_z / clip_w; - dst_z = dst_z * 0.5f + 0.5f; // convert to window coords - } + float clip_z, clip_w; + + // projection + clip_z = src_z * projectionMatrix[ 2 + 2 * 4 ] + projectionMatrix[ 2 + 3 * 4 ]; + clip_w = src_z * projectionMatrix[ 3 + 2 * 4 ] + projectionMatrix[ 3 + 3 * 4 ]; + + if ( clip_w <= 0.0f ) { + dst_z = 0.0f; // clamp to near plane + } else { + dst_z = clip_z / clip_w; + dst_z = dst_z * 0.5f + 0.5f; // convert to window coords + } } /* @@ -584,32 +579,32 @@ Returns true if the box is outside the given global frustum, (positive sides are ================= */ bool R_RadiusCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) { - int i; - float d; - idVec3 worldOrigin; - float worldRadius; - const idPlane *frust; + int i; + float d; + idVec3 worldOrigin; + float worldRadius; + const idPlane *frust; - if ( r_useCulling.GetInteger() == 0 ) { - return false; - } + if ( r_useCulling.GetInteger() == 0 ) { + return false; + } - // transform the surface bounds into world space - idVec3 localOrigin = ( bounds[0] + bounds[1] ) * 0.5; + // transform the surface bounds into world space + idVec3 localOrigin = ( bounds[0] + bounds[1] ) * 0.5; - R_LocalPointToGlobal( modelMatrix, localOrigin, worldOrigin ); + R_LocalPointToGlobal( modelMatrix, localOrigin, worldOrigin ); - worldRadius = (bounds[0] - localOrigin).Length(); // FIXME: won't be correct for scaled objects + worldRadius = ( bounds[0] - localOrigin ).Length(); // FIXME: won't be correct for scaled objects - for ( i = 0 ; i < numPlanes ; i++ ) { - frust = planes + i; - d = frust->Distance( worldOrigin ); - if ( d > worldRadius ) { - return true; // culled - } - } + for ( i = 0 ; i < numPlanes ; i++ ) { + frust = planes + i; + d = frust->Distance( worldOrigin ); - return false; // no culled + if ( d > worldRadius ) { + return true; // culled + } + } + return false; // no culled } /* @@ -622,45 +617,47 @@ Returns true if the box is outside the given global frustum, (positive sides are ================= */ bool R_CornerCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) { - int i, j; - idVec3 transformed[8]; - float dists[8]; - idVec3 v; - const idPlane *frust; - - // we can disable box culling for experimental timing purposes - if ( r_useCulling.GetInteger() < 2 ) { - return false; - } - - // transform into world space - for ( i = 0 ; i < 8 ; i++ ) { - v[0] = bounds[i&1][0]; - v[1] = bounds[(i>>1)&1][1]; - v[2] = bounds[(i>>2)&1][2]; - - R_LocalPointToGlobal( modelMatrix, v, transformed[i] ); - } - - // check against frustum planes - for ( i = 0 ; i < numPlanes ; i++ ) { - frust = planes + i; - for ( j = 0 ; j < 8 ; j++ ) { - dists[j] = frust->Distance( transformed[j] ); - if ( dists[j] < 0 ) { - break; - } - } - if ( j == 8 ) { - // all points were behind one of the planes - tr.pc.c_box_cull_out++; - return true; - } - } - - tr.pc.c_box_cull_in++; - - return false; // not culled + int i, j; + idVec3 transformed[8]; + float dists[8]; + idVec3 v; + const idPlane *frust; + + // we can disable box culling for experimental timing purposes + if ( r_useCulling.GetInteger() < 2 ) { + return false; + } + + // transform into world space + for ( i = 0 ; i < 8 ; i++ ) { + v[0] = bounds[i & 1][0]; + v[1] = bounds[( i >> 1 ) & 1][1]; + v[2] = bounds[( i >> 2 ) & 1][2]; + + R_LocalPointToGlobal( modelMatrix, v, transformed[i] ); + } + + // check against frustum planes + for ( i = 0 ; i < numPlanes ; i++ ) { + frust = planes + i; + + for ( j = 0 ; j < 8 ; j++ ) { + dists[j] = frust->Distance( transformed[j] ); + + if ( dists[j] < 0 ) { + break; + } + } + + if ( j == 8 ) { + // all points were behind one of the planes + tr.pc.c_box_cull_out++; + return true; + } + } + tr.pc.c_box_cull_in++; + + return false; // not culled } /* @@ -672,10 +669,10 @@ Returns true if the box is outside the given global frustum, (positive sides are ================= */ bool R_CullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) { - if ( R_RadiusCullLocalBox( bounds, modelMatrix, numPlanes, planes ) ) { - return true; - } - return R_CornerCullLocalBox( bounds, modelMatrix, numPlanes, planes ); + if ( R_RadiusCullLocalBox( bounds, modelMatrix, numPlanes, planes ) ) { + return true; + } + return R_CornerCullLocalBox( bounds, modelMatrix, numPlanes, planes ); } /* @@ -684,23 +681,23 @@ R_TransformModelToClip ========================== */ void R_TransformModelToClip( const idVec3 &src, const float *modelMatrix, const float *projectionMatrix, idPlane &eye, idPlane &dst ) { - int i; - - for ( i = 0 ; i < 4 ; i++ ) { - eye[i] = - src[0] * modelMatrix[ i + 0 * 4 ] + - src[1] * modelMatrix[ i + 1 * 4 ] + - src[2] * modelMatrix[ i + 2 * 4 ] + - 1 * modelMatrix[ i + 3 * 4 ]; - } - - for ( i = 0 ; i < 4 ; i++ ) { - dst[i] = - eye[0] * projectionMatrix[ i + 0 * 4 ] + - eye[1] * projectionMatrix[ i + 1 * 4 ] + - eye[2] * projectionMatrix[ i + 2 * 4 ] + - eye[3] * projectionMatrix[ i + 3 * 4 ]; - } + int i; + + for ( i = 0 ; i < 4 ; i++ ) { + eye[i] = + src[0] * modelMatrix[ i + 0 * 4 ] + + src[1] * modelMatrix[ i + 1 * 4 ] + + src[2] * modelMatrix[ i + 2 * 4 ] + + 1 * modelMatrix[ i + 3 * 4 ]; + } + + for ( i = 0 ; i < 4 ; i++ ) { + dst[i] = + eye[0] * projectionMatrix[ i + 0 * 4 ] + + eye[1] * projectionMatrix[ i + 1 * 4 ] + + eye[2] * projectionMatrix[ i + 2 * 4 ] + + eye[3] * projectionMatrix[ i + 3 * 4 ]; + } } /* @@ -711,53 +708,47 @@ R_GlobalToNormalizedDeviceCoordinates ========================== */ void R_GlobalToNormalizedDeviceCoordinates( const idVec3 &global, idVec3 &ndc ) { - int i; - idPlane view; - idPlane clip; - - // _D3XP added work on primaryView when no viewDef - if ( !tr.viewDef ) { - - for ( i = 0 ; i < 4 ; i ++ ) { - view[i] = - global[0] * tr.primaryView->worldSpace.modelViewMatrix[ i + 0 * 4 ] + - global[1] * tr.primaryView->worldSpace.modelViewMatrix[ i + 1 * 4 ] + - global[2] * tr.primaryView->worldSpace.modelViewMatrix[ i + 2 * 4 ] + - tr.primaryView->worldSpace.modelViewMatrix[ i + 3 * 4 ]; - } - - for ( i = 0 ; i < 4 ; i ++ ) { - clip[i] = - view[0] * tr.primaryView->projectionMatrix[ i + 0 * 4 ] + - view[1] * tr.primaryView->projectionMatrix[ i + 1 * 4 ] + - view[2] * tr.primaryView->projectionMatrix[ i + 2 * 4 ] + - view[3] * tr.primaryView->projectionMatrix[ i + 3 * 4 ]; - } - - } else { - - for ( i = 0 ; i < 4 ; i ++ ) { - view[i] = - global[0] * tr.viewDef->worldSpace.modelViewMatrix[ i + 0 * 4 ] + - global[1] * tr.viewDef->worldSpace.modelViewMatrix[ i + 1 * 4 ] + - global[2] * tr.viewDef->worldSpace.modelViewMatrix[ i + 2 * 4 ] + - tr.viewDef->worldSpace.modelViewMatrix[ i + 3 * 4 ]; - } - - - for ( i = 0 ; i < 4 ; i ++ ) { - clip[i] = - view[0] * tr.viewDef->projectionMatrix[ i + 0 * 4 ] + - view[1] * tr.viewDef->projectionMatrix[ i + 1 * 4 ] + - view[2] * tr.viewDef->projectionMatrix[ i + 2 * 4 ] + - view[3] * tr.viewDef->projectionMatrix[ i + 3 * 4 ]; - } - - } - - ndc[0] = clip[0] / clip[3]; - ndc[1] = clip[1] / clip[3]; - ndc[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] ); + int i; + idPlane view; + idPlane clip; + + // _D3XP added work on primaryView when no viewDef + if ( !tr.viewDef ) { + for ( i = 0 ; i < 4 ; i ++ ) { + view[i] = + global[0] * tr.primaryView->worldSpace.modelViewMatrix[ i + 0 * 4 ] + + global[1] * tr.primaryView->worldSpace.modelViewMatrix[ i + 1 * 4 ] + + global[2] * tr.primaryView->worldSpace.modelViewMatrix[ i + 2 * 4 ] + + tr.primaryView->worldSpace.modelViewMatrix[ i + 3 * 4 ]; + } + + for ( i = 0 ; i < 4 ; i ++ ) { + clip[i] = + view[0] * tr.primaryView->projectionMatrix[ i + 0 * 4 ] + + view[1] * tr.primaryView->projectionMatrix[ i + 1 * 4 ] + + view[2] * tr.primaryView->projectionMatrix[ i + 2 * 4 ] + + view[3] * tr.primaryView->projectionMatrix[ i + 3 * 4 ]; + } + } else { + for ( i = 0 ; i < 4 ; i ++ ) { + view[i] = + global[0] * tr.viewDef->worldSpace.modelViewMatrix[ i + 0 * 4 ] + + global[1] * tr.viewDef->worldSpace.modelViewMatrix[ i + 1 * 4 ] + + global[2] * tr.viewDef->worldSpace.modelViewMatrix[ i + 2 * 4 ] + + tr.viewDef->worldSpace.modelViewMatrix[ i + 3 * 4 ]; + } + + for ( i = 0 ; i < 4 ; i ++ ) { + clip[i] = + view[0] * tr.viewDef->projectionMatrix[ i + 0 * 4 ] + + view[1] * tr.viewDef->projectionMatrix[ i + 1 * 4 ] + + view[2] * tr.viewDef->projectionMatrix[ i + 2 * 4 ] + + view[3] * tr.viewDef->projectionMatrix[ i + 3 * 4 ]; + } + } + ndc[0] = clip[0] / clip[3]; + ndc[1] = clip[1] / clip[3]; + ndc[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] ); } /* @@ -768,47 +759,77 @@ Clip to normalized device coordinates ========================== */ void R_TransformClipToDevice( const idPlane &clip, const viewDef_t *view, idVec3 &normalized ) { - normalized[0] = clip[0] / clip[3]; - normalized[1] = clip[1] / clip[3]; - normalized[2] = clip[2] / clip[3]; + normalized[0] = clip[0] / clip[3]; + normalized[1] = clip[1] / clip[3]; + normalized[2] = clip[2] / clip[3]; } - /* ========================== -myGlMultMatrix +R_MatrixMultiply + +Changed name to be more in line with RBDoom (disabled SSE intrinsics on MAC ppc) ========================== */ -void myGlMultMatrix( const float a[16], const float b[16], float out[16] ) { -#if 0 - int i, j; - - for ( i = 0 ; i < 4 ; i++ ) { - for ( j = 0 ; j < 4 ; j++ ) { - out[ i * 4 + j ] = - a [ i * 4 + 0 ] * b [ 0 * 4 + j ] - + a [ i * 4 + 1 ] * b [ 1 * 4 + j ] - + a [ i * 4 + 2 ] * b [ 2 * 4 + j ] - + a [ i * 4 + 3 ] * b [ 3 * 4 + j ]; - } - } +void R_MatrixMultiply( const float a[16], const float b[16], float out[16] ) { +#if !( defined(__ppc__) || defined(MACOS_X) || defined(__APPLE__) ) + int cpuid = idLib::sys->GetProcessorId(); + + /* fast path use sse */ + if ( cpuid & CPUID_SSE ) { + __m128 B0x = _mm_loadu_ps( &b[0] ); + __m128 B1x = _mm_loadu_ps( &b[4] ); + __m128 B2x = _mm_loadu_ps( &b[8] ); + __m128 B3x = _mm_loadu_ps( &b[12] ); + + for ( int i = 0; i < 4; i++ ) { + __m128 Ai0 = _mm_set1_ps( a[4 * i + 0] ); + __m128 Ai1 = _mm_set1_ps( a[4 * i + 1] ); + __m128 Ai2 = _mm_set1_ps( a[4 * i + 2] ); + __m128 Ai3 = _mm_set1_ps( a[4 * i + 3] ); + __m128 Rix = _mm_add_ps( _mm_add_ps( _mm_mul_ps( Ai0, B0x ), + _mm_mul_ps( Ai1, B1x ) ), + _mm_add_ps( _mm_mul_ps( Ai2, B2x ), + _mm_mul_ps( Ai3, B3x ) ) ); + _mm_storeu_ps( &out[4 * i], Rix ); + } + } else { + /* fallback to non SSE matrix */ + out[0 * 4 + 0] = a[0 * 4 + 0] * b[0 * 4 + 0] + a[0 * 4 + 1] * b[1 * 4 + 0] + a[0 * 4 + 2] * b[2 * 4 + 0] + a[0 * 4 + 3] * b[3 * 4 + 0]; + out[0 * 4 + 1] = a[0 * 4 + 0] * b[0 * 4 + 1] + a[0 * 4 + 1] * b[1 * 4 + 1] + a[0 * 4 + 2] * b[2 * 4 + 1] + a[0 * 4 + 3] * b[3 * 4 + 1]; + out[0 * 4 + 2] = a[0 * 4 + 0] * b[0 * 4 + 2] + a[0 * 4 + 1] * b[1 * 4 + 2] + a[0 * 4 + 2] * b[2 * 4 + 2] + a[0 * 4 + 3] * b[3 * 4 + 2]; + out[0 * 4 + 3] = a[0 * 4 + 0] * b[0 * 4 + 3] + a[0 * 4 + 1] * b[1 * 4 + 3] + a[0 * 4 + 2] * b[2 * 4 + 3] + a[0 * 4 + 3] * b[3 * 4 + 3]; + out[1 * 4 + 0] = a[1 * 4 + 0] * b[0 * 4 + 0] + a[1 * 4 + 1] * b[1 * 4 + 0] + a[1 * 4 + 2] * b[2 * 4 + 0] + a[1 * 4 + 3] * b[3 * 4 + 0]; + out[1 * 4 + 1] = a[1 * 4 + 0] * b[0 * 4 + 1] + a[1 * 4 + 1] * b[1 * 4 + 1] + a[1 * 4 + 2] * b[2 * 4 + 1] + a[1 * 4 + 3] * b[3 * 4 + 1]; + out[1 * 4 + 2] = a[1 * 4 + 0] * b[0 * 4 + 2] + a[1 * 4 + 1] * b[1 * 4 + 2] + a[1 * 4 + 2] * b[2 * 4 + 2] + a[1 * 4 + 3] * b[3 * 4 + 2]; + out[1 * 4 + 3] = a[1 * 4 + 0] * b[0 * 4 + 3] + a[1 * 4 + 1] * b[1 * 4 + 3] + a[1 * 4 + 2] * b[2 * 4 + 3] + a[1 * 4 + 3] * b[3 * 4 + 3]; + out[2 * 4 + 0] = a[2 * 4 + 0] * b[0 * 4 + 0] + a[2 * 4 + 1] * b[1 * 4 + 0] + a[2 * 4 + 2] * b[2 * 4 + 0] + a[2 * 4 + 3] * b[3 * 4 + 0]; + out[2 * 4 + 1] = a[2 * 4 + 0] * b[0 * 4 + 1] + a[2 * 4 + 1] * b[1 * 4 + 1] + a[2 * 4 + 2] * b[2 * 4 + 1] + a[2 * 4 + 3] * b[3 * 4 + 1]; + out[2 * 4 + 2] = a[2 * 4 + 0] * b[0 * 4 + 2] + a[2 * 4 + 1] * b[1 * 4 + 2] + a[2 * 4 + 2] * b[2 * 4 + 2] + a[2 * 4 + 3] * b[3 * 4 + 2]; + out[2 * 4 + 3] = a[2 * 4 + 0] * b[0 * 4 + 3] + a[2 * 4 + 1] * b[1 * 4 + 3] + a[2 * 4 + 2] * b[2 * 4 + 3] + a[2 * 4 + 3] * b[3 * 4 + 3]; + out[3 * 4 + 0] = a[3 * 4 + 0] * b[0 * 4 + 0] + a[3 * 4 + 1] * b[1 * 4 + 0] + a[3 * 4 + 2] * b[2 * 4 + 0] + a[3 * 4 + 3] * b[3 * 4 + 0]; + out[3 * 4 + 1] = a[3 * 4 + 0] * b[0 * 4 + 1] + a[3 * 4 + 1] * b[1 * 4 + 1] + a[3 * 4 + 2] * b[2 * 4 + 1] + a[3 * 4 + 3] * b[3 * 4 + 1]; + out[3 * 4 + 2] = a[3 * 4 + 0] * b[0 * 4 + 2] + a[3 * 4 + 1] * b[1 * 4 + 2] + a[3 * 4 + 2] * b[2 * 4 + 2] + a[3 * 4 + 3] * b[3 * 4 + 2]; + out[3 * 4 + 3] = a[3 * 4 + 0] * b[0 * 4 + 3] + a[3 * 4 + 1] * b[1 * 4 + 3] + a[3 * 4 + 2] * b[2 * 4 + 3] + a[3 * 4 + 3] * b[3 * 4 + 3]; + } #else - out[0*4+0] = a[0*4+0]*b[0*4+0] + a[0*4+1]*b[1*4+0] + a[0*4+2]*b[2*4+0] + a[0*4+3]*b[3*4+0]; - out[0*4+1] = a[0*4+0]*b[0*4+1] + a[0*4+1]*b[1*4+1] + a[0*4+2]*b[2*4+1] + a[0*4+3]*b[3*4+1]; - out[0*4+2] = a[0*4+0]*b[0*4+2] + a[0*4+1]*b[1*4+2] + a[0*4+2]*b[2*4+2] + a[0*4+3]*b[3*4+2]; - out[0*4+3] = a[0*4+0]*b[0*4+3] + a[0*4+1]*b[1*4+3] + a[0*4+2]*b[2*4+3] + a[0*4+3]*b[3*4+3]; - out[1*4+0] = a[1*4+0]*b[0*4+0] + a[1*4+1]*b[1*4+0] + a[1*4+2]*b[2*4+0] + a[1*4+3]*b[3*4+0]; - out[1*4+1] = a[1*4+0]*b[0*4+1] + a[1*4+1]*b[1*4+1] + a[1*4+2]*b[2*4+1] + a[1*4+3]*b[3*4+1]; - out[1*4+2] = a[1*4+0]*b[0*4+2] + a[1*4+1]*b[1*4+2] + a[1*4+2]*b[2*4+2] + a[1*4+3]*b[3*4+2]; - out[1*4+3] = a[1*4+0]*b[0*4+3] + a[1*4+1]*b[1*4+3] + a[1*4+2]*b[2*4+3] + a[1*4+3]*b[3*4+3]; - out[2*4+0] = a[2*4+0]*b[0*4+0] + a[2*4+1]*b[1*4+0] + a[2*4+2]*b[2*4+0] + a[2*4+3]*b[3*4+0]; - out[2*4+1] = a[2*4+0]*b[0*4+1] + a[2*4+1]*b[1*4+1] + a[2*4+2]*b[2*4+1] + a[2*4+3]*b[3*4+1]; - out[2*4+2] = a[2*4+0]*b[0*4+2] + a[2*4+1]*b[1*4+2] + a[2*4+2]*b[2*4+2] + a[2*4+3]*b[3*4+2]; - out[2*4+3] = a[2*4+0]*b[0*4+3] + a[2*4+1]*b[1*4+3] + a[2*4+2]*b[2*4+3] + a[2*4+3]*b[3*4+3]; - out[3*4+0] = a[3*4+0]*b[0*4+0] + a[3*4+1]*b[1*4+0] + a[3*4+2]*b[2*4+0] + a[3*4+3]*b[3*4+0]; - out[3*4+1] = a[3*4+0]*b[0*4+1] + a[3*4+1]*b[1*4+1] + a[3*4+2]*b[2*4+1] + a[3*4+3]*b[3*4+1]; - out[3*4+2] = a[3*4+0]*b[0*4+2] + a[3*4+1]*b[1*4+2] + a[3*4+2]*b[2*4+2] + a[3*4+3]*b[3*4+2]; - out[3*4+3] = a[3*4+0]*b[0*4+3] + a[3*4+1]*b[1*4+3] + a[3*4+2]*b[2*4+3] + a[3*4+3]*b[3*4+3]; + /* fallback to non SSE matrix on mac */ + out[0 * 4 + 0] = a[0 * 4 + 0] * b[0 * 4 + 0] + a[0 * 4 + 1] * b[1 * 4 + 0] + a[0 * 4 + 2] * b[2 * 4 + 0] + a[0 * 4 + 3] * b[3 * 4 + 0]; + out[0 * 4 + 1] = a[0 * 4 + 0] * b[0 * 4 + 1] + a[0 * 4 + 1] * b[1 * 4 + 1] + a[0 * 4 + 2] * b[2 * 4 + 1] + a[0 * 4 + 3] * b[3 * 4 + 1]; + out[0 * 4 + 2] = a[0 * 4 + 0] * b[0 * 4 + 2] + a[0 * 4 + 1] * b[1 * 4 + 2] + a[0 * 4 + 2] * b[2 * 4 + 2] + a[0 * 4 + 3] * b[3 * 4 + 2]; + out[0 * 4 + 3] = a[0 * 4 + 0] * b[0 * 4 + 3] + a[0 * 4 + 1] * b[1 * 4 + 3] + a[0 * 4 + 2] * b[2 * 4 + 3] + a[0 * 4 + 3] * b[3 * 4 + 3]; + out[1 * 4 + 0] = a[1 * 4 + 0] * b[0 * 4 + 0] + a[1 * 4 + 1] * b[1 * 4 + 0] + a[1 * 4 + 2] * b[2 * 4 + 0] + a[1 * 4 + 3] * b[3 * 4 + 0]; + out[1 * 4 + 1] = a[1 * 4 + 0] * b[0 * 4 + 1] + a[1 * 4 + 1] * b[1 * 4 + 1] + a[1 * 4 + 2] * b[2 * 4 + 1] + a[1 * 4 + 3] * b[3 * 4 + 1]; + out[1 * 4 + 2] = a[1 * 4 + 0] * b[0 * 4 + 2] + a[1 * 4 + 1] * b[1 * 4 + 2] + a[1 * 4 + 2] * b[2 * 4 + 2] + a[1 * 4 + 3] * b[3 * 4 + 2]; + out[1 * 4 + 3] = a[1 * 4 + 0] * b[0 * 4 + 3] + a[1 * 4 + 1] * b[1 * 4 + 3] + a[1 * 4 + 2] * b[2 * 4 + 3] + a[1 * 4 + 3] * b[3 * 4 + 3]; + out[2 * 4 + 0] = a[2 * 4 + 0] * b[0 * 4 + 0] + a[2 * 4 + 1] * b[1 * 4 + 0] + a[2 * 4 + 2] * b[2 * 4 + 0] + a[2 * 4 + 3] * b[3 * 4 + 0]; + out[2 * 4 + 1] = a[2 * 4 + 0] * b[0 * 4 + 1] + a[2 * 4 + 1] * b[1 * 4 + 1] + a[2 * 4 + 2] * b[2 * 4 + 1] + a[2 * 4 + 3] * b[3 * 4 + 1]; + out[2 * 4 + 2] = a[2 * 4 + 0] * b[0 * 4 + 2] + a[2 * 4 + 1] * b[1 * 4 + 2] + a[2 * 4 + 2] * b[2 * 4 + 2] + a[2 * 4 + 3] * b[3 * 4 + 2]; + out[2 * 4 + 3] = a[2 * 4 + 0] * b[0 * 4 + 3] + a[2 * 4 + 1] * b[1 * 4 + 3] + a[2 * 4 + 2] * b[2 * 4 + 3] + a[2 * 4 + 3] * b[3 * 4 + 3]; + out[3 * 4 + 0] = a[3 * 4 + 0] * b[0 * 4 + 0] + a[3 * 4 + 1] * b[1 * 4 + 0] + a[3 * 4 + 2] * b[2 * 4 + 0] + a[3 * 4 + 3] * b[3 * 4 + 0]; + out[3 * 4 + 1] = a[3 * 4 + 0] * b[0 * 4 + 1] + a[3 * 4 + 1] * b[1 * 4 + 1] + a[3 * 4 + 2] * b[2 * 4 + 1] + a[3 * 4 + 3] * b[3 * 4 + 1]; + out[3 * 4 + 2] = a[3 * 4 + 0] * b[0 * 4 + 2] + a[3 * 4 + 1] * b[1 * 4 + 2] + a[3 * 4 + 2] * b[2 * 4 + 2] + a[3 * 4 + 3] * b[3 * 4 + 2]; + out[3 * 4 + 3] = a[3 * 4 + 0] * b[0 * 4 + 3] + a[3 * 4 + 1] * b[1 * 4 + 3] + a[3 * 4 + 2] * b[2 * 4 + 3] + a[3 * 4 + 3] * b[3 * 4 + 3]; #endif } @@ -818,13 +839,13 @@ R_TransposeGLMatrix ================ */ void R_TransposeGLMatrix( const float in[16], float out[16] ) { - int i, j; + int i, j; - for ( i = 0 ; i < 4 ; i++ ) { - for ( j = 0 ; j < 4 ; j++ ) { - out[i*4+j] = in[j*4+i]; - } - } + for ( i = 0 ; i < 4 ; i++ ) { + for ( j = 0 ; j < 4 ; j++ ) { + out[i * 4 + j] = in[j * 4 + i]; + } + } } /* @@ -835,53 +856,53 @@ Sets up the world to view matrix for a given viewParm ================= */ void R_SetViewMatrix( viewDef_t *viewDef ) { - idVec3 origin; - viewEntity_t *world; - float viewerMatrix[16]; - static float s_flipMatrix[16] = { - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 - }; - - world = &viewDef->worldSpace; - - memset( world, 0, sizeof(*world) ); - - // the model matrix is an identity - world->modelMatrix[0*4+0] = 1; - world->modelMatrix[1*4+1] = 1; - world->modelMatrix[2*4+2] = 1; - - // transform by the camera placement - origin = viewDef->renderView.vieworg; - - viewerMatrix[0] = viewDef->renderView.viewaxis[0][0]; - viewerMatrix[4] = viewDef->renderView.viewaxis[0][1]; - viewerMatrix[8] = viewDef->renderView.viewaxis[0][2]; - viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8]; - - viewerMatrix[1] = viewDef->renderView.viewaxis[1][0]; - viewerMatrix[5] = viewDef->renderView.viewaxis[1][1]; - viewerMatrix[9] = viewDef->renderView.viewaxis[1][2]; - viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9]; - - viewerMatrix[2] = viewDef->renderView.viewaxis[2][0]; - viewerMatrix[6] = viewDef->renderView.viewaxis[2][1]; - viewerMatrix[10] = viewDef->renderView.viewaxis[2][2]; - viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10]; - - viewerMatrix[3] = 0; - viewerMatrix[7] = 0; - viewerMatrix[11] = 0; - viewerMatrix[15] = 1; - - // convert from our coordinate system (looking down X) - // to OpenGL's coordinate system (looking down -Z) - myGlMultMatrix( viewerMatrix, s_flipMatrix, world->modelViewMatrix ); + idVec3 origin; + viewEntity_t *world; + float viewerMatrix[16]; + static float s_flipMatrix[16] = { + // convert from our coordinate system (looking down X) + // to OpenGL's coordinate system (looking down -Z) + 0, 0, -1, 0, + -1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 0, 1 + }; + + world = &viewDef->worldSpace; + + memset( world, 0, sizeof( *world ) ); + + // the model matrix is an identity + world->modelMatrix[0 * 4 + 0] = 1; + world->modelMatrix[1 * 4 + 1] = 1; + world->modelMatrix[2 * 4 + 2] = 1; + + // transform by the camera placement + origin = viewDef->renderView.vieworg; + + viewerMatrix[0] = viewDef->renderView.viewaxis[0][0]; + viewerMatrix[4] = viewDef->renderView.viewaxis[0][1]; + viewerMatrix[8] = viewDef->renderView.viewaxis[0][2]; + viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8]; + + viewerMatrix[1] = viewDef->renderView.viewaxis[1][0]; + viewerMatrix[5] = viewDef->renderView.viewaxis[1][1]; + viewerMatrix[9] = viewDef->renderView.viewaxis[1][2]; + viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9]; + + viewerMatrix[2] = viewDef->renderView.viewaxis[2][0]; + viewerMatrix[6] = viewDef->renderView.viewaxis[2][1]; + viewerMatrix[10] = viewDef->renderView.viewaxis[2][2]; + viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10]; + + viewerMatrix[3] = 0; + viewerMatrix[7] = 0; + viewerMatrix[11] = 0; + viewerMatrix[15] = 1; + + // convert from our coordinate system (looking down X) + // to OpenGL's coordinate system (looking down -Z) + R_MatrixMultiply( viewerMatrix, s_flipMatrix, world->modelViewMatrix ); } /* @@ -891,69 +912,69 @@ R_SetupProjection This uses the "infinite far z" trick =============== */ -void R_SetupProjection( viewDef_t * viewDef ) { - float xmin, xmax, ymin, ymax; - float width, height; - float zNear; - float jitterx, jittery; - static idRandom random; - - // random jittering is usefull when multiple - // frames are going to be blended together - // for motion blurred anti-aliasing - if ( r_jitter.GetBool() ) { - jitterx = random.RandomFloat(); - jittery = random.RandomFloat(); - } else { - jitterx = jittery = 0; - } - - // - // set up projection matrix - // - zNear = r_znear.GetFloat(); - if ( viewDef->renderView.cramZNear ) { - zNear *= 0.25; - } - - ymax = zNear * tan( viewDef->renderView.fov_y * idMath::PI / 360.0f ); - ymin = -ymax; - - xmax = zNear * tan( viewDef->renderView.fov_x * idMath::PI / 360.0f ); - xmin = -xmax; - - width = xmax - xmin; - height = ymax - ymin; - - jitterx = jitterx * width / ( viewDef->viewport.x2 - viewDef->viewport.x1 + 1 ); - xmin += jitterx; - xmax += jitterx; - jittery = jittery * height / ( viewDef->viewport.y2 - viewDef->viewport.y1 + 1 ); - ymin += jittery; - ymax += jittery; - - viewDef->projectionMatrix[0] = 2 * zNear / width; - viewDef->projectionMatrix[4] = 0; - viewDef->projectionMatrix[8] = ( xmax + xmin ) / width; // normally 0 - viewDef->projectionMatrix[12] = 0; - - viewDef->projectionMatrix[1] = 0; - viewDef->projectionMatrix[5] = 2 * zNear / height; - viewDef->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0 - viewDef->projectionMatrix[13] = 0; - - // this is the far-plane-at-infinity formulation, and - // crunches the Z range slightly so w=0 vertexes do not - // rasterize right at the wraparound point - viewDef->projectionMatrix[2] = 0; - viewDef->projectionMatrix[6] = 0; - viewDef->projectionMatrix[10] = -0.999f; - viewDef->projectionMatrix[14] = -2.0f * zNear; - - viewDef->projectionMatrix[3] = 0; - viewDef->projectionMatrix[7] = 0; - viewDef->projectionMatrix[11] = -1; - viewDef->projectionMatrix[15] = 0; +void R_SetupProjection( viewDef_t *viewDef ) { + float xmin, xmax, ymin, ymax; + float width, height; + float zNear; + float jitterx, jittery; + static idRandom random; + + // random jittering is usefull when multiple + // frames are going to be blended together + // for motion blurred anti-aliasing + if ( r_jitter.GetBool() ) { + jitterx = random.RandomFloat(); + jittery = random.RandomFloat(); + } else { + jitterx = jittery = 0; + } + + // + // set up projection matrix + // + zNear = r_znear.GetFloat(); + + if ( viewDef->renderView.cramZNear ) { + zNear *= 0.25; + } + ymax = zNear * tan( viewDef->renderView.fov_y * idMath::PI / 360.0f ); + ymin = -ymax; + + xmax = zNear * tan( viewDef->renderView.fov_x * idMath::PI / 360.0f ); + xmin = -xmax; + + width = xmax - xmin; + height = ymax - ymin; + + jitterx = jitterx * width / ( viewDef->viewport.x2 - viewDef->viewport.x1 + 1 ); + xmin += jitterx; + xmax += jitterx; + jittery = jittery * height / ( viewDef->viewport.y2 - viewDef->viewport.y1 + 1 ); + ymin += jittery; + ymax += jittery; + + viewDef->projectionMatrix[0] = 2 * zNear / width; + viewDef->projectionMatrix[4] = 0; + viewDef->projectionMatrix[8] = ( xmax + xmin ) / width; // normally 0 + viewDef->projectionMatrix[12] = 0; + + viewDef->projectionMatrix[1] = 0; + viewDef->projectionMatrix[5] = 2 * zNear / height; + viewDef->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0 + viewDef->projectionMatrix[13] = 0; + + // this is the far-plane-at-infinity formulation, and + // crunches the Z range slightly so w=0 vertexes do not + // rasterize right at the wraparound point + viewDef->projectionMatrix[2] = 0; + viewDef->projectionMatrix[6] = 0; + viewDef->projectionMatrix[10] = -0.999f; + viewDef->projectionMatrix[14] = -2.0f * zNear; + + viewDef->projectionMatrix[3] = 0; + viewDef->projectionMatrix[7] = 0; + viewDef->projectionMatrix[11] = -1; + viewDef->projectionMatrix[15] = 0; } /* @@ -965,47 +986,47 @@ FIXME: derive from modelview matrix times projection matrix ================= */ //static -void R_SetupViewFrustum( viewDef_t* viewDef ) { - int i; - float xs, xc; - float ang; +void R_SetupViewFrustum( viewDef_t *viewDef ) { + int i; + float xs, xc; + float ang; - ang = DEG2RAD( viewDef->renderView.fov_x ) * 0.5f; - idMath::SinCos( ang, xs, xc ); + ang = DEG2RAD( viewDef->renderView.fov_x ) * 0.5f; + idMath::SinCos( ang, xs, xc ); - viewDef->frustum[0] = xs * viewDef->renderView.viewaxis[0] + xc * viewDef->renderView.viewaxis[1]; - viewDef->frustum[1] = xs * viewDef->renderView.viewaxis[0] - xc * viewDef->renderView.viewaxis[1]; + viewDef->frustum[0] = xs * viewDef->renderView.viewaxis[0] + xc * viewDef->renderView.viewaxis[1]; + viewDef->frustum[1] = xs * viewDef->renderView.viewaxis[0] - xc * viewDef->renderView.viewaxis[1]; - ang = DEG2RAD( viewDef->renderView.fov_y ) * 0.5f; - idMath::SinCos( ang, xs, xc ); + ang = DEG2RAD( viewDef->renderView.fov_y ) * 0.5f; + idMath::SinCos( ang, xs, xc ); - viewDef->frustum[2] = xs * viewDef->renderView.viewaxis[0] + xc * viewDef->renderView.viewaxis[2]; - viewDef->frustum[3] = xs * viewDef->renderView.viewaxis[0] - xc * viewDef->renderView.viewaxis[2]; + viewDef->frustum[2] = xs * viewDef->renderView.viewaxis[0] + xc * viewDef->renderView.viewaxis[2]; + viewDef->frustum[3] = xs * viewDef->renderView.viewaxis[0] - xc * viewDef->renderView.viewaxis[2]; - // plane four is the front clipping plane - viewDef->frustum[4] = /* vec3_origin - */ viewDef->renderView.viewaxis[0]; + // plane four is the front clipping plane + viewDef->frustum[4] = /* vec3_origin - */ viewDef->renderView.viewaxis[0]; - for ( i = 0; i < 5; i++ ) { - // flip direction so positive side faces out (FIXME: globally unify this) - viewDef->frustum[i] = -viewDef->frustum[i].Normal(); - viewDef->frustum[i][3] = -( viewDef->renderView.vieworg * viewDef->frustum[i].Normal() ); - } + for ( i = 0; i < 5; i++ ) { + // flip direction so positive side faces out (FIXME: globally unify this) + viewDef->frustum[i] = -viewDef->frustum[i].Normal(); + viewDef->frustum[i][3] = -( viewDef->renderView.vieworg * viewDef->frustum[i].Normal() ); + } - // eventually, plane five will be the rear clipping plane for fog + // eventually, plane five will be the rear clipping plane for fog + float dNear, dFar, dLeft, dUp; - float dNear, dFar, dLeft, dUp; + dNear = r_znear.GetFloat(); - dNear = r_znear.GetFloat(); - if ( viewDef->renderView.cramZNear ) { - dNear *= 0.25f; - } + if ( viewDef->renderView.cramZNear ) { + dNear *= 0.25f; + } + dFar = MAX_WORLD_SIZE; + dLeft = dFar * tan( DEG2RAD( viewDef->renderView.fov_x * 0.5f ) ); + dUp = dFar * tan( DEG2RAD( viewDef->renderView.fov_y * 0.5f ) ); - dFar = MAX_WORLD_SIZE; - dLeft = dFar * tan( DEG2RAD( viewDef->renderView.fov_x * 0.5f ) ); - dUp = dFar * tan( DEG2RAD( viewDef->renderView.fov_y * 0.5f ) ); - viewDef->viewFrustum.SetOrigin( viewDef->renderView.vieworg ); - viewDef->viewFrustum.SetAxis( viewDef->renderView.viewaxis ); - viewDef->viewFrustum.SetSize( dNear, dFar, dLeft, dUp ); + viewDef->viewFrustum.SetOrigin( viewDef->renderView.vieworg ); + viewDef->viewFrustum.SetAxis( viewDef->renderView.viewaxis ); + viewDef->viewFrustum.SetSize( dNear, dFar, dLeft, dUp ); } /* @@ -1014,21 +1035,23 @@ R_ConstrainViewFrustum =================== */ static void R_ConstrainViewFrustum( void ) { - idBounds bounds; - - // constrain the view frustum to the total bounds of all visible lights and visible entities - bounds.Clear(); - for ( viewLight_t *vLight = tr.viewDef->viewLights; vLight; vLight = vLight->next ) { - bounds.AddBounds( vLight->lightDef->frustumTris->bounds ); - } - for ( viewEntity_t *vEntity = tr.viewDef->viewEntitys; vEntity; vEntity = vEntity->next ) { - bounds.AddBounds( vEntity->entityDef->referenceBounds ); - } - tr.viewDef->viewFrustum.ConstrainToBounds( bounds ); - - if ( r_useFrustumFarDistance.GetFloat() > 0.0f ) { - tr.viewDef->viewFrustum.MoveFarDistance( r_useFrustumFarDistance.GetFloat() ); - } + idBounds bounds; + + // constrain the view frustum to the total bounds of all visible lights and visible entities + bounds.Clear(); + + for ( viewLight_t *vLight = tr.viewDef->viewLights; vLight; vLight = vLight->next ) { + bounds.AddBounds( vLight->lightDef->frustumTris->bounds ); + } + + for ( viewEntity_t *vEntity = tr.viewDef->viewEntitys; vEntity; vEntity = vEntity->next ) { + bounds.AddBounds( vEntity->entityDef->referenceBounds ); + } + tr.viewDef->viewFrustum.ConstrainToBounds( bounds ); + + if ( r_useFrustumFarDistance.GetFloat() > 0.0f ) { + tr.viewDef->viewFrustum.MoveFarDistance( r_useFrustumFarDistance.GetFloat() ); + } } /* @@ -1047,20 +1070,20 @@ R_QsortSurfaces ======================= */ static int R_QsortSurfaces( const void *a, const void *b ) { - const drawSurf_t *ea, *eb; - - ea = *(drawSurf_t **)a; - eb = *(drawSurf_t **)b; - - if ( ea->sort < eb->sort ) { - return -1; - } - if ( ea->sort > eb->sort ) { - return 1; - } - return 0; -} + const drawSurf_t *ea, *eb; + ea = *( drawSurf_t ** )a; + eb = *( drawSurf_t ** )b; + + if ( ea->sort < eb->sort ) { + return -1; + } + + if ( ea->sort > eb->sort ) { + return 1; + } + return 0; +} /* ================= @@ -1068,20 +1091,12 @@ R_SortDrawSurfs ================= */ static void R_SortDrawSurfs( void ) { - // sort the drawsurfs by sort type, then orientation, then shader - qsort( tr.viewDef->drawSurfs, tr.viewDef->numDrawSurfs, sizeof( tr.viewDef->drawSurfs[0] ), - R_QsortSurfaces ); + // sort the drawsurfs by sort type, then orientation, then shader + qsort( tr.viewDef->drawSurfs, tr.viewDef->numDrawSurfs, sizeof( tr.viewDef->drawSurfs[0] ), R_QsortSurfaces ); } - - -//======================================================================== - - //============================================================================== - - /* ================ R_RenderView @@ -1093,71 +1108,70 @@ Parms will typically be allocated with R_FrameAlloc ================ */ void R_RenderView( viewDef_t *parms ) { - viewDef_t *oldView; - - if ( parms->renderView.width <= 0 || parms->renderView.height <= 0 ) { - return; - } + viewDef_t *oldView; - tr.viewCount++; + if ( parms->renderView.width <= 0 || parms->renderView.height <= 0 ) { + return; + } + tr.viewCount++; - // save view in case we are a subview - oldView = tr.viewDef; + // save view in case we are a subview + oldView = tr.viewDef; - tr.viewDef = parms; + tr.viewDef = parms; - tr.sortOffset = 0; + tr.sortOffset = 0; - // set the matrix for world space to eye space - R_SetViewMatrix( tr.viewDef ); + // set the matrix for world space to eye space + R_SetViewMatrix( tr.viewDef ); - // the four sides of the view frustum are needed - // for culling and portal visibility - R_SetupViewFrustum( tr.viewDef ); + // the four sides of the view frustum are needed + // for culling and portal visibility + R_SetupViewFrustum( tr.viewDef ); - // we need to set the projection matrix before doing - // portal-to-screen scissor box calculations - R_SetupProjection( tr.viewDef ); + // we need to set the projection matrix before doing + // portal-to-screen scissor box calculations + R_SetupProjection( tr.viewDef ); - // identify all the visible portalAreas, and the entityDefs and - // lightDefs that are in them and pass culling. - static_cast(parms->renderWorld)->FindViewLightsAndEntities(); + // identify all the visible portalAreas, and the entityDefs and + // lightDefs that are in them and pass culling. + static_cast( parms->renderWorld )->FindViewLightsAndEntities(); - // constrain the view frustum to the view lights and entities - R_ConstrainViewFrustum(); + // constrain the view frustum to the view lights and entities + R_ConstrainViewFrustum(); - // make sure that interactions exist for all light / entity combinations - // that are visible - // add any pre-generated light shadows, and calculate the light shader values - R_AddLightSurfaces(); + // make sure that interactions exist for all light / entity combinations + // that are visible + // add any pre-generated light shadows, and calculate the light shader values + R_AddLightSurfaces(); - // adds ambient surfaces and create any necessary interaction surfaces to add to the light - // lists - R_AddModelSurfaces(); + // adds ambient surfaces and create any necessary interaction surfaces to add to the light + // lists + R_AddModelSurfaces(); - // any viewLight that didn't have visible surfaces can have it's shadows removed - R_RemoveUnecessaryViewLights(); + // any viewLight that didn't have visible surfaces can have it's shadows removed + R_RemoveUnecessaryViewLights(); - // sort all the ambient surfaces for translucency ordering - R_SortDrawSurfs(); + // sort all the ambient surfaces for translucency ordering + R_SortDrawSurfs(); - // generate any subviews (mirrors, cameras, etc) before adding this view - if ( R_GenerateSubViews() ) { - // if we are debugging subviews, allow the skipping of the - // main view draw - if ( r_subviewOnly.GetBool() ) { - return; - } - } + // generate any subviews (mirrors, cameras, etc) before adding this view + if ( R_GenerateSubViews() ) { + // if we are debugging subviews, allow the skipping of the + // main view draw + if ( r_subviewOnly.GetBool() ) { + return; + } + } - // write everything needed to the demo file - if ( session->writeDemo ) { - static_cast(parms->renderWorld)->WriteVisibleDefs( tr.viewDef ); - } + // write everything needed to the demo file + if ( session->writeDemo ) { + static_cast( parms->renderWorld )->WriteVisibleDefs( tr.viewDef ); + } - // add the rendering commands for this viewDef - R_AddDrawViewCmd( parms ); + // add the rendering commands for this viewDef + R_AddDrawViewCmd( parms ); - // restore view in case we are a subview - tr.viewDef = oldView; + // restore view in case we are a subview + tr.viewDef = oldView; } diff --git a/neo/renderer/tr_render.cpp b/neo/renderer/tr_render.cpp index 2b7e10fce..2ea2c36a1 100644 --- a/neo/renderer/tr_render.cpp +++ b/neo/renderer/tr_render.cpp @@ -49,25 +49,25 @@ This should never happen if the vertex cache is operating properly. */ void RB_DrawElementsImmediate( const srfTriangles_t *tri ) { - backEnd.pc.c_drawElements++; - backEnd.pc.c_drawIndexes += tri->numIndexes; - backEnd.pc.c_drawVertexes += tri->numVerts; - - if ( tri->ambientSurface != NULL ) { - if ( tri->indexes == tri->ambientSurface->indexes ) { - backEnd.pc.c_drawRefIndexes += tri->numIndexes; - } - if ( tri->verts == tri->ambientSurface->verts ) { - backEnd.pc.c_drawRefVertexes += tri->numVerts; - } - } - - qglBegin( GL_TRIANGLES ); - for ( int i = 0 ; i < tri->numIndexes ; i++ ) { - qglTexCoord2fv( tri->verts[ tri->indexes[i] ].st.ToFloatPtr() ); - qglVertex3fv( tri->verts[ tri->indexes[i] ].xyz.ToFloatPtr() ); - } - qglEnd(); + backEnd.pc.c_drawElements++; + backEnd.pc.c_drawIndexes += tri->numIndexes; + backEnd.pc.c_drawVertexes += tri->numVerts; + + if ( tri->ambientSurface != NULL ) { + if ( tri->indexes == tri->ambientSurface->indexes ) { + backEnd.pc.c_drawRefIndexes += tri->numIndexes; + } + if ( tri->verts == tri->ambientSurface->verts ) { + backEnd.pc.c_drawRefVertexes += tri->numVerts; + } + } + qglBegin( GL_TRIANGLES ); + + for ( int i = 0 ; i < tri->numIndexes ; i++ ) { + qglTexCoord2fv( tri->verts[ tri->indexes[i] ].st.ToFloatPtr() ); + qglVertex3fv( tri->verts[ tri->indexes[i] ].xyz.ToFloatPtr() ); + } + qglEnd(); } @@ -78,34 +78,36 @@ RB_DrawElementsWithCounters */ void RB_DrawElementsWithCounters( const srfTriangles_t *tri ) { - backEnd.pc.c_drawElements++; - backEnd.pc.c_drawIndexes += tri->numIndexes; - backEnd.pc.c_drawVertexes += tri->numVerts; - - if ( tri->ambientSurface != NULL ) { - if ( tri->indexes == tri->ambientSurface->indexes ) { - backEnd.pc.c_drawRefIndexes += tri->numIndexes; - } - if ( tri->verts == tri->ambientSurface->verts ) { - backEnd.pc.c_drawRefVertexes += tri->numVerts; - } - } - - if ( tri->indexCache && r_useIndexBuffers.GetBool() ) { - qglDrawElements( GL_TRIANGLES, - r_singleTriangle.GetBool() ? 3 : tri->numIndexes, - GL_INDEX_TYPE, - (int *)vertexCache.Position( tri->indexCache ) ); - backEnd.pc.c_vboIndexes += tri->numIndexes; - } else { - if ( r_useIndexBuffers.GetBool() ) { - vertexCache.UnbindIndex(); - } - qglDrawElements( GL_TRIANGLES, - r_singleTriangle.GetBool() ? 3 : tri->numIndexes, - GL_INDEX_TYPE, - tri->indexes ); - } + backEnd.pc.c_drawElements++; + backEnd.pc.c_drawIndexes += tri->numIndexes; + backEnd.pc.c_drawVertexes += tri->numVerts; + + if ( tri->ambientSurface != NULL ) { + if ( tri->indexes == tri->ambientSurface->indexes ) { + backEnd.pc.c_drawRefIndexes += tri->numIndexes; + } + + if ( tri->verts == tri->ambientSurface->verts ) { + backEnd.pc.c_drawRefVertexes += tri->numVerts; + } + } + + if ( tri->indexCache && r_useIndexBuffers.GetBool() ) { + // cast to wrong type int * but needs const GLvoid * the type however is const void * so just remove the cast + qglDrawElements( GL_TRIANGLES, + r_singleTriangle.GetBool() ? 3 : tri->numIndexes, + GL_INDEX_TYPE, + vertexCache.Position( tri->indexCache ) ); + backEnd.pc.c_vboIndexes += tri->numIndexes; + } else { + if ( r_useIndexBuffers.GetBool() ) { + vertexCache.UnbindIndex( GL_ELEMENT_ARRAY_BUFFER ); + } + qglDrawElements( GL_TRIANGLES, + r_singleTriangle.GetBool() ? 3 : tri->numIndexes, + GL_INDEX_TYPE, + tri->indexes ); + } } /* @@ -116,28 +118,27 @@ May not use all the indexes in the surface if caps are skipped ================ */ void RB_DrawShadowElementsWithCounters( const srfTriangles_t *tri, int numIndexes ) { - backEnd.pc.c_shadowElements++; - backEnd.pc.c_shadowIndexes += numIndexes; - backEnd.pc.c_shadowVertexes += tri->numVerts; - - if ( tri->indexCache && r_useIndexBuffers.GetBool() ) { - qglDrawElements( GL_TRIANGLES, - r_singleTriangle.GetBool() ? 3 : numIndexes, - GL_INDEX_TYPE, - (int *)vertexCache.Position( tri->indexCache ) ); - backEnd.pc.c_vboIndexes += numIndexes; - } else { - if ( r_useIndexBuffers.GetBool() ) { - vertexCache.UnbindIndex(); - } - qglDrawElements( GL_TRIANGLES, - r_singleTriangle.GetBool() ? 3 : numIndexes, - GL_INDEX_TYPE, - tri->indexes ); - } + backEnd.pc.c_shadowElements++; + backEnd.pc.c_shadowIndexes += numIndexes; + backEnd.pc.c_shadowVertexes += tri->numVerts; + + if ( tri->indexCache && r_useIndexBuffers.GetBool() ) { + qglDrawElements( GL_TRIANGLES, + r_singleTriangle.GetBool() ? 3 : numIndexes, + GL_INDEX_TYPE, + (int *)vertexCache.Position( tri->indexCache ) ); + backEnd.pc.c_vboIndexes += numIndexes; + } else { + if ( r_useIndexBuffers.GetBool() ) { + vertexCache.UnbindIndex( GL_ELEMENT_ARRAY_BUFFER ); + } + qglDrawElements( GL_TRIANGLES, + r_singleTriangle.GetBool() ? 3 : numIndexes, + GL_INDEX_TYPE, + tri->indexes ); + } } - /* =============== RB_RenderTriangleSurface @@ -146,17 +147,16 @@ Sets texcoord and vertex pointers =============== */ void RB_RenderTriangleSurface( const srfTriangles_t *tri ) { - if ( !tri->ambientCache ) { - RB_DrawElementsImmediate( tri ); - return; - } - + if ( !tri->ambientCache ) { + RB_DrawElementsImmediate( tri ); + return; + } + idDrawVert *ac = ( idDrawVert * )vertexCache.Position( tri->ambientCache ); - idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache ); - qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); - qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), ac->st.ToFloatPtr() ); + qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); + qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), ac->st.ToFloatPtr() ); - RB_DrawElementsWithCounters( tri ); + RB_DrawElementsWithCounters( tri ); } /* @@ -166,7 +166,7 @@ RB_T_RenderTriangleSurface =============== */ void RB_T_RenderTriangleSurface( const drawSurf_t *surf ) { - RB_RenderTriangleSurface( surf->geo ); + RB_RenderTriangleSurface( surf->geo ); } /* @@ -175,17 +175,17 @@ RB_EnterWeaponDepthHack =============== */ void RB_EnterWeaponDepthHack() { - qglDepthRange( 0, 0.5 ); + qglDepthRange( 0, 0.5 ); - float matrix[16]; + float matrix[16]; - memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) ); + memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) ); - matrix[14] *= 0.25; + matrix[14] *= 0.25; - qglMatrixMode(GL_PROJECTION); - qglLoadMatrixf( matrix ); - qglMatrixMode(GL_MODELVIEW); + qglMatrixMode(GL_PROJECTION); + qglLoadMatrixf( matrix ); + qglMatrixMode(GL_MODELVIEW); } /* @@ -194,17 +194,17 @@ RB_EnterModelDepthHack =============== */ void RB_EnterModelDepthHack( float depth ) { - qglDepthRange( 0.0f, 1.0f ); + qglDepthRange( 0.0f, 1.0f ); - float matrix[16]; + float matrix[16]; - memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) ); + memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) ); - matrix[14] -= depth; + matrix[14] -= depth; - qglMatrixMode(GL_PROJECTION); - qglLoadMatrixf( matrix ); - qglMatrixMode(GL_MODELVIEW); + qglMatrixMode(GL_PROJECTION); + qglLoadMatrixf( matrix ); + qglMatrixMode(GL_MODELVIEW); } /* @@ -213,11 +213,11 @@ RB_LeaveDepthHack =============== */ void RB_LeaveDepthHack() { - qglDepthRange( 0, 1 ); + qglDepthRange( 0, 1 ); - qglMatrixMode(GL_PROJECTION); - qglLoadMatrixf( backEnd.viewDef->projectionMatrix ); - qglMatrixMode(GL_MODELVIEW); + qglMatrixMode(GL_PROJECTION); + qglLoadMatrixf( backEnd.viewDef->projectionMatrix ); + qglMatrixMode(GL_MODELVIEW); } /* @@ -231,46 +231,46 @@ be updated after the triangle function completes. ==================== */ void RB_RenderDrawSurfListWithFunction( drawSurf_t **drawSurfs, int numDrawSurfs, - void (*triFunc_)( const drawSurf_t *) ) { - int i; - const drawSurf_t *drawSurf; - - backEnd.currentSpace = NULL; - - for (i = 0 ; i < numDrawSurfs ; i++ ) { - drawSurf = drawSurfs[i]; - - // change the matrix if needed - if ( drawSurf->space != backEnd.currentSpace ) { - qglLoadMatrixf( drawSurf->space->modelViewMatrix ); - } - - if ( drawSurf->space->weaponDepthHack ) { - RB_EnterWeaponDepthHack(); - } - - if ( drawSurf->space->modelDepthHack != 0.0f ) { - RB_EnterModelDepthHack( drawSurf->space->modelDepthHack ); - } - - // change the scissor if needed - if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( drawSurf->scissorRect ) ) { - backEnd.currentScissor = drawSurf->scissorRect; - qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, - backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, - backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, - backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); - } - - // render it - triFunc_( drawSurf ); - - if ( drawSurf->space->weaponDepthHack || drawSurf->space->modelDepthHack != 0.0f ) { - RB_LeaveDepthHack(); - } - - backEnd.currentSpace = drawSurf->space; - } + void (*triFunc_)( const drawSurf_t *) ) { + int i; + const drawSurf_t *drawSurf; + + backEnd.currentSpace = NULL; + + for (i = 0 ; i < numDrawSurfs ; i++ ) { + drawSurf = drawSurfs[i]; + + // change the matrix if needed + if ( drawSurf->space != backEnd.currentSpace ) { + qglLoadMatrixf( drawSurf->space->modelViewMatrix ); + } + + if ( drawSurf->space->weaponDepthHack ) { + RB_EnterWeaponDepthHack(); + } + + if ( drawSurf->space->modelDepthHack != 0.0f ) { + RB_EnterModelDepthHack( drawSurf->space->modelDepthHack ); + } + + // change the scissor if needed + if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( drawSurf->scissorRect ) ) { + backEnd.currentScissor = drawSurf->scissorRect; + + qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, + backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, + backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, + backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); + } + + // render it + triFunc_( drawSurf ); + + if ( drawSurf->space->weaponDepthHack || drawSurf->space->modelDepthHack != 0.0f ) { + RB_LeaveDepthHack(); + } + backEnd.currentSpace = drawSurf->space; + } } /* @@ -279,43 +279,43 @@ RB_RenderDrawSurfChainWithFunction ====================== */ void RB_RenderDrawSurfChainWithFunction( const drawSurf_t *drawSurfs, - void (*triFunc_)( const drawSurf_t *) ) { - const drawSurf_t *drawSurf; - - backEnd.currentSpace = NULL; - - for ( drawSurf = drawSurfs ; drawSurf ; drawSurf = drawSurf->nextOnLight ) { - // change the matrix if needed - if ( drawSurf->space != backEnd.currentSpace ) { - qglLoadMatrixf( drawSurf->space->modelViewMatrix ); - } - - if ( drawSurf->space->weaponDepthHack ) { - RB_EnterWeaponDepthHack(); - } - - if ( drawSurf->space->modelDepthHack ) { - RB_EnterModelDepthHack( drawSurf->space->modelDepthHack ); - } - - // change the scissor if needed - if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( drawSurf->scissorRect ) ) { - backEnd.currentScissor = drawSurf->scissorRect; - qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, - backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, - backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, - backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); - } - - // render it - triFunc_( drawSurf ); - - if ( drawSurf->space->weaponDepthHack || drawSurf->space->modelDepthHack != 0.0f ) { - RB_LeaveDepthHack(); - } - - backEnd.currentSpace = drawSurf->space; - } + void ( *triFunc_ )( const drawSurf_t *) ) { + const drawSurf_t *drawSurf; + + backEnd.currentSpace = NULL; + + for ( drawSurf = drawSurfs ; drawSurf ; drawSurf = drawSurf->nextOnLight ) { + // change the matrix if needed + if ( drawSurf->space != backEnd.currentSpace ) { + qglLoadMatrixf( drawSurf->space->modelViewMatrix ); + } + + if ( drawSurf->space->weaponDepthHack ) { + RB_EnterWeaponDepthHack(); + } + + if ( drawSurf->space->modelDepthHack ) { + RB_EnterModelDepthHack( drawSurf->space->modelDepthHack ); + } + + // change the scissor if needed + if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( drawSurf->scissorRect ) ) { + backEnd.currentScissor = drawSurf->scissorRect; + + qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, + backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, + backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, + backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); + } + + // render it + triFunc_( drawSurf ); + + if ( drawSurf->space->weaponDepthHack || drawSurf->space->modelDepthHack != 0.0f ) { + RB_LeaveDepthHack(); + } + backEnd.currentSpace = drawSurf->space; + } } /* @@ -324,35 +324,34 @@ RB_GetShaderTextureMatrix ====================== */ void RB_GetShaderTextureMatrix( const float *shaderRegisters, - const textureStage_t *texture, float matrix[16] ) { - matrix[0] = shaderRegisters[ texture->matrix[0][0] ]; - matrix[4] = shaderRegisters[ texture->matrix[0][1] ]; - matrix[8] = 0; - matrix[12] = shaderRegisters[ texture->matrix[0][2] ]; - - // we attempt to keep scrolls from generating incredibly large texture values, but - // center rotations and center scales can still generate offsets that need to be > 1 - if ( matrix[12] < -40 || matrix[12] > 40 ) { - matrix[12] -= (int)matrix[12]; - } - - matrix[1] = shaderRegisters[ texture->matrix[1][0] ]; - matrix[5] = shaderRegisters[ texture->matrix[1][1] ]; - matrix[9] = 0; - matrix[13] = shaderRegisters[ texture->matrix[1][2] ]; - if ( matrix[13] < -40 || matrix[13] > 40 ) { - matrix[13] -= (int)matrix[13]; - } - - matrix[2] = 0; - matrix[6] = 0; - matrix[10] = 1; - matrix[14] = 0; - - matrix[3] = 0; - matrix[7] = 0; - matrix[11] = 0; - matrix[15] = 1; + const textureStage_t *texture, float matrix[16] ) { + matrix[0] = shaderRegisters[ texture->matrix[0][0] ]; + matrix[4] = shaderRegisters[ texture->matrix[0][1] ]; + matrix[8] = 0; + matrix[12] = shaderRegisters[ texture->matrix[0][2] ]; + + // we attempt to keep scrolls from generating incredibly large texture values, but + // center rotations and center scales can still generate offsets that need to be > 1 + if ( matrix[12] < -40 || matrix[12] > 40 ) { + matrix[12] -= (int)matrix[12]; + } + matrix[1] = shaderRegisters[ texture->matrix[1][0] ]; + matrix[5] = shaderRegisters[ texture->matrix[1][1] ]; + matrix[9] = 0; + matrix[13] = shaderRegisters[ texture->matrix[1][2] ]; + + if ( matrix[13] < -40 || matrix[13] > 40 ) { + matrix[13] -= (int)matrix[13]; + } + matrix[2] = 0; + matrix[6] = 0; + matrix[10] = 1; + matrix[14] = 0; + + matrix[3] = 0; + matrix[7] = 0; + matrix[11] = 0; + matrix[15] = 1; } /* @@ -361,12 +360,13 @@ RB_LoadShaderTextureMatrix ====================== */ void RB_LoadShaderTextureMatrix( const float *shaderRegisters, const textureStage_t *texture ) { - float matrix[16]; + float matrix[16]; + + RB_GetShaderTextureMatrix( shaderRegisters, texture, matrix ); - RB_GetShaderTextureMatrix( shaderRegisters, texture, matrix ); - qglMatrixMode( GL_TEXTURE ); - qglLoadMatrixf( matrix ); - qglMatrixMode( GL_MODELVIEW ); + qglMatrixMode( GL_TEXTURE ); + qglLoadMatrixf( matrix ); + qglMatrixMode( GL_MODELVIEW ); } /* @@ -377,111 +377,34 @@ Handles generating a cinematic frame if needed ====================== */ void RB_BindVariableStageImage( const textureStage_t *texture, const float *shaderRegisters ) { - if ( texture->cinematic ) { - cinData_t cin; - - if ( r_skipDynamicTextures.GetBool() ) { - globalImages->defaultImage->Bind(); - return; - } - - // offset time by shaderParm[7] (FIXME: make the time offset a parameter of the shader?) - // We make no attempt to optimize for multiple identical cinematics being in view, or - // for cinematics going at a lower framerate than the renderer. - cin = texture->cinematic->ImageForTime( (int)(1000 * ( backEnd.viewDef->floatTime + backEnd.viewDef->renderView.shaderParms[11] ) ) ); - - if ( cin.image ) { - globalImages->cinematicImage->UploadScratch( cin.image, cin.imageWidth, cin.imageHeight ); - } else { - globalImages->blackImage->Bind(); - } - } else { - //FIXME: see why image is invalid - if (texture->image) { - texture->image->Bind(); - } - } -} - -/* -====================== -RB_BindStageTexture -====================== -*/ -void RB_BindStageTexture( const float *shaderRegisters, const textureStage_t *texture, const drawSurf_t *surf ) { - // image - RB_BindVariableStageImage( texture, shaderRegisters ); - - // texgens - if ( texture->texgen == TG_DIFFUSE_CUBE ) { - qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->normal.ToFloatPtr() ); - } - if ( texture->texgen == TG_SKYBOX_CUBE || texture->texgen == TG_WOBBLESKY_CUBE ) { - qglTexCoordPointer( 3, GL_FLOAT, 0, vertexCache.Position( surf->dynamicTexCoords ) ); - } - if ( texture->texgen == TG_REFLECT_CUBE ) { - qglEnable( GL_TEXTURE_GEN_S ); - qglEnable( GL_TEXTURE_GEN_T ); - qglEnable( GL_TEXTURE_GEN_R ); - qglTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT ); - qglTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT ); - qglTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT ); - qglEnableClientState( GL_NORMAL_ARRAY ); - qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->normal.ToFloatPtr() ); - - qglMatrixMode( GL_TEXTURE ); - float mat[16]; - - R_TransposeGLMatrix( backEnd.viewDef->worldSpace.modelViewMatrix, mat ); - - qglLoadMatrixf( mat ); - qglMatrixMode( GL_MODELVIEW ); - } - - // matrix - if ( texture->hasMatrix ) { - RB_LoadShaderTextureMatrix( shaderRegisters, texture ); - } + if ( texture->cinematic ) { + cinData_t cin; + + if ( r_skipDynamicTextures.GetBool() ) { + globalImages->defaultImage->Bind(); + return; + } + + // offset time by shaderParm[7] (FIXME: make the time offset a parameter of the shader?) + // We make no attempt to optimize for multiple identical cinematics being in view, or + // for cinematics going at a lower framerate than the renderer. + cin = texture->cinematic->ImageForTime( (int)(1000 * ( backEnd.viewDef->floatTime + backEnd.viewDef->renderView.shaderParms[11] ) ) ); + + if ( cin.image ) { + globalImages->cinematicImage->UploadScratch( cin.image, cin.imageWidth, cin.imageHeight ); + } else { + globalImages->blackImage->Bind(); + } + } else { + //FIXME: see why image is invalid + if ( texture->image ) { + texture->image->Bind(); + } + } } -/* -====================== -RB_FinishStageTexture -====================== -*/ -void RB_FinishStageTexture( const textureStage_t *texture, const drawSurf_t *surf ) { - if ( texture->texgen == TG_DIFFUSE_CUBE || texture->texgen == TG_SKYBOX_CUBE - || texture->texgen == TG_WOBBLESKY_CUBE ) { - qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), - (void *)&(((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->st) ); - } - - if ( texture->texgen == TG_REFLECT_CUBE ) { - qglDisable( GL_TEXTURE_GEN_S ); - qglDisable( GL_TEXTURE_GEN_T ); - qglDisable( GL_TEXTURE_GEN_R ); - qglTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); - qglTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); - qglTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); - qglDisableClientState( GL_NORMAL_ARRAY ); - - qglMatrixMode( GL_TEXTURE ); - qglLoadIdentity(); - qglMatrixMode( GL_MODELVIEW ); - } - - if ( texture->hasMatrix ) { - qglMatrixMode( GL_TEXTURE ); - qglLoadIdentity(); - qglMatrixMode( GL_MODELVIEW ); - } -} - - - //============================================================================================= - /* ================= RB_DetermineLightScale @@ -499,49 +422,52 @@ overbright past 1.0 ================= */ void RB_DetermineLightScale( void ) { - viewLight_t *vLight; - const idMaterial *shader; - float max; - int i, j, numStages; - const shaderStage_t *stage; - - // the light scale will be based on the largest color component of any surface - // that will be drawn. - // should we consider separating rgb scales? - - // if there are no lights, this will remain at 1.0, so GUI-only - // rendering will not lose any bits of precision - max = 1.0; - - for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) { - // lights with no surfaces or shaderparms may still be present - // for debug display - if ( !vLight->localInteractions && !vLight->globalInteractions - && !vLight->translucentInteractions ) { - continue; - } - - shader = vLight->lightShader; - numStages = shader->GetNumStages(); - for ( i = 0 ; i < numStages ; i++ ) { - stage = shader->GetStage( i ); - for ( j = 0 ; j < 3 ; j++ ) { - float v = r_lightScale.GetFloat() * vLight->shaderRegisters[ stage->color.registers[j] ]; - if ( v > max ) { - max = v; - } - } - } - } - - backEnd.pc.maxLightValue = max; - if ( max <= tr.backEndRendererMaxLight ) { - backEnd.lightScale = r_lightScale.GetFloat(); - backEnd.overBright = 1.0; - } else { - backEnd.lightScale = r_lightScale.GetFloat() * tr.backEndRendererMaxLight / max; - backEnd.overBright = max / tr.backEndRendererMaxLight; - } + viewLight_t *vLight; + const idMaterial *shader; + float max; + int i, j, numStages; + const shaderStage_t *stage; + + // the light scale will be based on the largest color component of any surface + // that will be drawn. + // should we consider separating rgb scales? + + // if there are no lights, this will remain at 1.0, so GUI-only + // rendering will not lose any bits of precision + max = 1.0f; + + for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) { + // lights with no surfaces or shaderparms may still be present + // for debug display + if ( !vLight->localInteractions && + !vLight->globalInteractions && + !vLight->translucentInteractions ) { + continue; + } + shader = vLight->lightShader; + numStages = shader->GetNumStages(); + + for ( i = 0 ; i < numStages ; i++ ) { + stage = shader->GetStage( i ); + + for ( j = 0 ; j < 3 ; j++ ) { + float v = r_lightScale.GetFloat() * vLight->shaderRegisters[ stage->color.registers[j] ]; + + if ( v > max ) { + max = v; + } + } + } + } + backEnd.pc.maxLightValue = max; + + if ( max <= tr.backEndRendererMaxLight ) { + backEnd.lightScale = r_lightScale.GetFloat(); + backEnd.overBright = 1.0; + } else { + backEnd.lightScale = r_lightScale.GetFloat() * tr.backEndRendererMaxLight / max; + backEnd.overBright = max / tr.backEndRendererMaxLight; + } } @@ -553,47 +479,46 @@ Any mirrored or portaled views have already been drawn, so prepare to actually render the visible surfaces for this view ================= */ -void RB_BeginDrawingView (void) { - - const viewDef_t* viewDef = backEnd.viewDef; - - // set the modelview matrix for the viewer - qglMatrixMode(GL_PROJECTION); - qglLoadMatrixf( viewDef->projectionMatrix ); - qglMatrixMode(GL_MODELVIEW); - - // set the window clipping - qglViewport( tr.viewportOffset[0] + viewDef->viewport.x1, - tr.viewportOffset[1] + viewDef->viewport.y1, - viewDef->viewport.x2 + 1 - viewDef->viewport.x1, - viewDef->viewport.y2 + 1 - viewDef->viewport.y1 ); - - // the scissor may be smaller than the viewport for subviews - qglScissor( tr.viewportOffset[0] + viewDef->viewport.x1 + viewDef->scissor.x1, - tr.viewportOffset[1] + viewDef->viewport.y1 + viewDef->scissor.y1, - viewDef->scissor.x2 + 1 - viewDef->scissor.x1, - viewDef->scissor.y2 + 1 - viewDef->scissor.y1 ); - backEnd.currentScissor = viewDef->scissor; - - // ensures that depth writes are enabled for the depth clear - GL_State( GLS_DEFAULT ); - - // we don't have to clear the depth / stencil buffer for 2D rendering - if ( backEnd.viewDef->viewEntitys ) { - qglStencilMask( 0xff ); - // some cards may have 7 bit stencil buffers, so don't assume this - // should be 128 - qglClearStencil( 1<<(glConfig.stencilBits-1) ); - qglClear( GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); - qglEnable( GL_DEPTH_TEST ); - } else { - qglDisable( GL_DEPTH_TEST ); - qglDisable( GL_STENCIL_TEST ); - } - - backEnd.glState.faceCulling = -1; // force face culling to set next time - GL_Cull( CT_FRONT_SIDED ); - +void RB_BeginDrawingView ( void ) { + const viewDef_t* viewDef = backEnd.viewDef; + + // set the modelview matrix for the viewer + qglMatrixMode(GL_PROJECTION); + qglLoadMatrixf( viewDef->projectionMatrix ); + qglMatrixMode(GL_MODELVIEW); + + // set the window clipping + qglViewport( tr.viewportOffset[0] + viewDef->viewport.x1, + tr.viewportOffset[1] + viewDef->viewport.y1, + viewDef->viewport.x2 + 1 - viewDef->viewport.x1, + viewDef->viewport.y2 + 1 - viewDef->viewport.y1 ); + + // the scissor may be smaller than the viewport for subviews + qglScissor( tr.viewportOffset[0] + viewDef->viewport.x1 + viewDef->scissor.x1, + tr.viewportOffset[1] + viewDef->viewport.y1 + viewDef->scissor.y1, + viewDef->scissor.x2 + 1 - viewDef->scissor.x1, + viewDef->scissor.y2 + 1 - viewDef->scissor.y1 ); + + backEnd.currentScissor = viewDef->scissor; + + // ensures that depth writes are enabled for the depth clear + GL_State( GLS_DEFAULT ); + + // we don't have to clear the depth / stencil buffer for 2D rendering + if ( backEnd.viewDef->viewEntitys ) { + qglStencilMask( 0xff ); + // some cards may have 7 bit stencil buffers, so don't assume this + // should be 128 + qglClearStencil( 1<<(glConfig.stencilBits-1) ); + qglClear( GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); + qglEnable( GL_DEPTH_TEST ); + } else { + qglDisable( GL_DEPTH_TEST ); + qglDisable( GL_STENCIL_TEST ); + } + backEnd.glState.faceCulling = -1; // force face culling to set next time + + GL_Cull( CT_FRONT_SIDED ); } /* @@ -602,52 +527,55 @@ R_SetDrawInteractions ================== */ void R_SetDrawInteraction( const shaderStage_t *surfaceStage, const float *surfaceRegs, - idImage **image, idVec4 matrix[2], float color[4] ) { - *image = surfaceStage->texture.image; - if ( surfaceStage->texture.hasMatrix ) { - matrix[0][0] = surfaceRegs[surfaceStage->texture.matrix[0][0]]; - matrix[0][1] = surfaceRegs[surfaceStage->texture.matrix[0][1]]; - matrix[0][2] = 0; - matrix[0][3] = surfaceRegs[surfaceStage->texture.matrix[0][2]]; - - matrix[1][0] = surfaceRegs[surfaceStage->texture.matrix[1][0]]; - matrix[1][1] = surfaceRegs[surfaceStage->texture.matrix[1][1]]; - matrix[1][2] = 0; - matrix[1][3] = surfaceRegs[surfaceStage->texture.matrix[1][2]]; - - // we attempt to keep scrolls from generating incredibly large texture values, but - // center rotations and center scales can still generate offsets that need to be > 1 - if ( matrix[0][3] < -40 || matrix[0][3] > 40 ) { - matrix[0][3] -= (int)matrix[0][3]; - } - if ( matrix[1][3] < -40 || matrix[1][3] > 40 ) { - matrix[1][3] -= (int)matrix[1][3]; - } - } else { - matrix[0][0] = 1; - matrix[0][1] = 0; - matrix[0][2] = 0; - matrix[0][3] = 0; - - matrix[1][0] = 0; - matrix[1][1] = 1; - matrix[1][2] = 0; - matrix[1][3] = 0; - } - - if ( color ) { - for ( int i = 0 ; i < 4 ; i++ ) { - color[i] = surfaceRegs[surfaceStage->color.registers[i]]; - // clamp here, so card with greater range don't look different. - // we could perform overbrighting like we do for lights, but - // it doesn't currently look worth it. - if ( color[i] < 0 ) { - color[i] = 0; - } else if ( color[i] > 1.0 ) { - color[i] = 1.0; - } - } - } + idImage **image, idVec4 matrix[2], float color[4] ) { + *image = surfaceStage->texture.image; + + if ( surfaceStage->texture.hasMatrix ) { + matrix[0][0] = surfaceRegs[surfaceStage->texture.matrix[0][0]]; + matrix[0][1] = surfaceRegs[surfaceStage->texture.matrix[0][1]]; + matrix[0][2] = 0; + matrix[0][3] = surfaceRegs[surfaceStage->texture.matrix[0][2]]; + + matrix[1][0] = surfaceRegs[surfaceStage->texture.matrix[1][0]]; + matrix[1][1] = surfaceRegs[surfaceStage->texture.matrix[1][1]]; + matrix[1][2] = 0; + matrix[1][3] = surfaceRegs[surfaceStage->texture.matrix[1][2]]; + + // we attempt to keep scrolls from generating incredibly large texture values, but + // center rotations and center scales can still generate offsets that need to be > 1 + if ( matrix[0][3] < -40 || matrix[0][3] > 40 ) { + matrix[0][3] -= (int)matrix[0][3]; + } + + if ( matrix[1][3] < -40 || matrix[1][3] > 40 ) { + matrix[1][3] -= (int)matrix[1][3]; + } + } else { + matrix[0][0] = 1; + matrix[0][1] = 0; + matrix[0][2] = 0; + matrix[0][3] = 0; + + matrix[1][0] = 0; + matrix[1][1] = 1; + matrix[1][2] = 0; + matrix[1][3] = 0; + } + + if ( color ) { + for ( int i = 0 ; i < 4 ; i++ ) { + color[i] = surfaceRegs[surfaceStage->color.registers[i]]; + + // clamp here, so card with greater range don't look different. + // we could perform overbrighting like we do for lights, but + // it doesn't currently look worth it. + if ( color[i] < 0 ) { + color[i] = 0; + } else if ( color[i] > 1.0 ) { + color[i] = 1.0; + } + } + } } /* @@ -656,30 +584,33 @@ RB_SubmittInteraction ================= */ static void RB_SubmittInteraction( drawInteraction_t *din, void (*DrawInteraction)(const drawInteraction_t *) ) { - if ( !din->bumpImage ) { - return; - } - - if ( !din->diffuseImage || r_skipDiffuse.GetBool() ) { - din->diffuseImage = globalImages->blackImage; - } - if ( !din->specularImage || r_skipSpecular.GetBool() || din->ambientLight ) { - din->specularImage = globalImages->blackImage; - } - if ( !din->bumpImage || r_skipBump.GetBool() ) { - din->bumpImage = globalImages->flatNormalMap; - } - - // if we wouldn't draw anything, don't call the Draw function - if ( - ( ( din->diffuseColor[0] > 0 || - din->diffuseColor[1] > 0 || - din->diffuseColor[2] > 0 ) && din->diffuseImage != globalImages->blackImage ) - || ( ( din->specularColor[0] > 0 || - din->specularColor[1] > 0 || - din->specularColor[2] > 0 ) && din->specularImage != globalImages->blackImage ) ) { - DrawInteraction( din ); - } + if ( !din->bumpImage ) { + return; + } + + if ( !din->diffuseImage || r_skipDiffuse.GetBool() ) { + din->diffuseImage = globalImages->blackImage; + } + + if ( !din->specularImage || r_skipSpecular.GetBool() || din->ambientLight ) { + din->specularImage = globalImages->blackImage; + } + + if ( !din->bumpImage || r_skipBump.GetBool() ) { + din->bumpImage = globalImages->flatNormalMap; + } + + // if we wouldn't draw anything, don't call the Draw function + if ( ( ( din->diffuseColor[0] > 0 || + din->diffuseColor[1] > 0 || + din->diffuseColor[2] > 0 ) && + din->diffuseImage != globalImages->blackImage ) || + ( ( din->specularColor[0] > 0 || + din->specularColor[1] > 0 || + din->specularColor[2] > 0 ) && + din->specularImage != globalImages->blackImage ) ) { + DrawInteraction( din ); + } } /* @@ -691,158 +622,159 @@ interaction into primitive interactions ============= */ void RB_CreateSingleDrawInteractions( const drawSurf_t *surf, void (*DrawInteraction)(const drawInteraction_t *) ) { - const idMaterial *surfaceShader = surf->material; - const float *surfaceRegs = surf->shaderRegisters; - const viewLight_t *vLight = backEnd.vLight; - const idMaterial *lightShader = vLight->lightShader; - const float *lightRegs = vLight->shaderRegisters; - drawInteraction_t inter; - inter.diffuseMatrix[0].Zero(); - inter.diffuseMatrix[1].Zero(); - inter.specularMatrix[0].Zero(); - inter.specularMatrix[1].Zero(); - - if ( r_skipInteractions.GetBool() || !surf->geo || !surf->geo->ambientCache ) { - return; - } - - // change the matrix and light projection vectors if needed - if ( surf->space != backEnd.currentSpace ) { - backEnd.currentSpace = surf->space; - qglLoadMatrixf( surf->space->modelViewMatrix ); - } - - // change the scissor if needed - if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( surf->scissorRect ) ) { - backEnd.currentScissor = surf->scissorRect; - qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, - backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, - backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, - backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); - } - - // hack depth range if needed - if ( surf->space->weaponDepthHack ) { - RB_EnterWeaponDepthHack(); - } - - if ( surf->space->modelDepthHack ) { - RB_EnterModelDepthHack( surf->space->modelDepthHack ); - } - - inter.surf = surf; - inter.lightFalloffImage = vLight->falloffImage; - - R_GlobalPointToLocal( surf->space->modelMatrix, vLight->globalLightOrigin, inter.localLightOrigin.ToVec3() ); - R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.viewDef->renderView.vieworg, inter.localViewOrigin.ToVec3() ); - inter.localLightOrigin[3] = 0; - inter.localViewOrigin[3] = 1; - inter.ambientLight = lightShader->IsAmbientLight(); - - // the base projections may be modified by texture matrix on light stages - idPlane lightProject[4]; - for ( int i = 0 ; i < 4 ; i++ ) { - R_GlobalPlaneToLocal( surf->space->modelMatrix, backEnd.vLight->lightProject[i], lightProject[i] ); - } - - for ( int lightStageNum = 0 ; lightStageNum < lightShader->GetNumStages() ; lightStageNum++ ) { - const shaderStage_t *lightStage = lightShader->GetStage( lightStageNum ); - - // ignore stages that fail the condition - if ( !lightRegs[ lightStage->conditionRegister ] ) { - continue; - } - - inter.lightImage = lightStage->texture.image; - - memcpy( inter.lightProjection, lightProject, sizeof( inter.lightProjection ) ); - // now multiply the texgen by the light texture matrix - if ( lightStage->texture.hasMatrix ) { - RB_GetShaderTextureMatrix( lightRegs, &lightStage->texture, backEnd.lightTextureMatrix ); - RB_BakeTextureMatrixIntoTexgen( reinterpret_cast(inter.lightProjection), backEnd.lightTextureMatrix ); - } - - inter.bumpImage = NULL; - inter.specularImage = NULL; - inter.diffuseImage = NULL; - inter.diffuseColor[0] = inter.diffuseColor[1] = inter.diffuseColor[2] = inter.diffuseColor[3] = 0; - inter.specularColor[0] = inter.specularColor[1] = inter.specularColor[2] = inter.specularColor[3] = 0; - - float lightColor[4]; - - // backEnd.lightScale is calculated so that lightColor[] will never exceed - // tr.backEndRendererMaxLight - lightColor[0] = backEnd.lightScale * lightRegs[ lightStage->color.registers[0] ]; - lightColor[1] = backEnd.lightScale * lightRegs[ lightStage->color.registers[1] ]; - lightColor[2] = backEnd.lightScale * lightRegs[ lightStage->color.registers[2] ]; - lightColor[3] = lightRegs[ lightStage->color.registers[3] ]; - - // go through the individual stages - for ( int surfaceStageNum = 0 ; surfaceStageNum < surfaceShader->GetNumStages() ; surfaceStageNum++ ) { - const shaderStage_t *surfaceStage = surfaceShader->GetStage( surfaceStageNum ); - - switch( surfaceStage->lighting ) { - case SL_AMBIENT: { - // ignore ambient stages while drawing interactions - break; - } - case SL_BUMP: { - // ignore stage that fails the condition - if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) { - break; - } - // draw any previous interaction - RB_SubmittInteraction( &inter, DrawInteraction ); - inter.diffuseImage = NULL; - inter.specularImage = NULL; - R_SetDrawInteraction( surfaceStage, surfaceRegs, &inter.bumpImage, inter.bumpMatrix, NULL ); - break; - } - case SL_DIFFUSE: { - // ignore stage that fails the condition - if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) { - break; - } - if ( inter.diffuseImage ) { - RB_SubmittInteraction( &inter, DrawInteraction ); - } - R_SetDrawInteraction( surfaceStage, surfaceRegs, &inter.diffuseImage, - inter.diffuseMatrix, inter.diffuseColor.ToFloatPtr() ); - inter.diffuseColor[0] *= lightColor[0]; - inter.diffuseColor[1] *= lightColor[1]; - inter.diffuseColor[2] *= lightColor[2]; - inter.diffuseColor[3] *= lightColor[3]; - inter.vertexColor = surfaceStage->vertexColor; - break; - } - case SL_SPECULAR: { - // ignore stage that fails the condition - if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) { - break; - } - if ( inter.specularImage ) { - RB_SubmittInteraction( &inter, DrawInteraction ); - } - R_SetDrawInteraction( surfaceStage, surfaceRegs, &inter.specularImage, - inter.specularMatrix, inter.specularColor.ToFloatPtr() ); - inter.specularColor[0] *= lightColor[0]; - inter.specularColor[1] *= lightColor[1]; - inter.specularColor[2] *= lightColor[2]; - inter.specularColor[3] *= lightColor[3]; - inter.vertexColor = surfaceStage->vertexColor; - break; - } - } - } - - // draw the final interaction - RB_SubmittInteraction( &inter, DrawInteraction ); - } - - // unhack depth range if needed - if ( surf->space->weaponDepthHack || surf->space->modelDepthHack != 0.0f ) { - RB_LeaveDepthHack(); - } + const idMaterial *surfaceShader = surf->material; + const float *surfaceRegs = surf->shaderRegisters; + const viewLight_t *vLight = backEnd.vLight; + const idMaterial *lightShader = vLight->lightShader; + const float *lightRegs = vLight->shaderRegisters; + drawInteraction_t inter; + + inter.diffuseMatrix[0].Zero(); + inter.diffuseMatrix[1].Zero(); + inter.specularMatrix[0].Zero(); + inter.specularMatrix[1].Zero(); + + if ( r_skipInteractions.GetBool() || !surf->geo || !surf->geo->ambientCache ) { + return; + } + + // change the matrix and light projection vectors if needed + if ( surf->space != backEnd.currentSpace ) { + backEnd.currentSpace = surf->space; + + qglLoadMatrixf( surf->space->modelViewMatrix ); + } + + // change the scissor if needed + if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( surf->scissorRect ) ) { + backEnd.currentScissor = surf->scissorRect; + + qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, + backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, + backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, + backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); + } + + // hack depth range if needed + if ( surf->space->weaponDepthHack ) { + RB_EnterWeaponDepthHack(); + } + + if ( surf->space->modelDepthHack ) { + RB_EnterModelDepthHack( surf->space->modelDepthHack ); + } + inter.surf = surf; + inter.lightFalloffImage = vLight->falloffImage; + + R_GlobalPointToLocal( surf->space->modelMatrix, vLight->globalLightOrigin, inter.localLightOrigin.ToVec3() ); + R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.viewDef->renderView.vieworg, inter.localViewOrigin.ToVec3() ); + inter.localLightOrigin[3] = 0; + inter.localViewOrigin[3] = 1; + inter.ambientLight = lightShader->IsAmbientLight(); + + // the base projections may be modified by texture matrix on light stages + idPlane lightProject[4]; + for ( int i = 0 ; i < 4 ; i++ ) { + R_GlobalPlaneToLocal( surf->space->modelMatrix, backEnd.vLight->lightProject[i], lightProject[i] ); + } + + for ( int lightStageNum = 0 ; lightStageNum < lightShader->GetNumStages() ; lightStageNum++ ) { + const shaderStage_t *lightStage = lightShader->GetStage( lightStageNum ); + + // ignore stages that fail the condition + if ( !lightRegs[ lightStage->conditionRegister ] ) { + continue; + } + inter.lightImage = lightStage->texture.image; + + memcpy( inter.lightProjection, lightProject, sizeof( inter.lightProjection ) ); + + // now multiply the texgen by the light texture matrix + if ( lightStage->texture.hasMatrix ) { + RB_GetShaderTextureMatrix( lightRegs, &lightStage->texture, backEnd.lightTextureMatrix ); + RB_BakeTextureMatrixIntoTexgen( reinterpret_cast( inter.lightProjection ), backEnd.lightTextureMatrix ); + } + inter.bumpImage = NULL; + inter.specularImage = NULL; + inter.diffuseImage = NULL; + inter.diffuseColor[0] = inter.diffuseColor[1] = inter.diffuseColor[2] = inter.diffuseColor[3] = 0; + inter.specularColor[0] = inter.specularColor[1] = inter.specularColor[2] = inter.specularColor[3] = 0; + + float lightColor[4]; + + // backEnd.lightScale is calculated so that lightColor[] will never exceed + // tr.backEndRendererMaxLight + lightColor[0] = backEnd.lightScale * lightRegs[ lightStage->color.registers[0] ]; + lightColor[1] = backEnd.lightScale * lightRegs[ lightStage->color.registers[1] ]; + lightColor[2] = backEnd.lightScale * lightRegs[ lightStage->color.registers[2] ]; + lightColor[3] = lightRegs[ lightStage->color.registers[3] ]; + + // go through the individual stages + for ( int surfaceStageNum = 0 ; surfaceStageNum < surfaceShader->GetNumStages() ; surfaceStageNum++ ) { + const shaderStage_t *surfaceStage = surfaceShader->GetStage( surfaceStageNum ); + + switch( surfaceStage->lighting ) { + case SL_AMBIENT: { + // ignore ambient stages while drawing interactions + break; + } + case SL_BUMP: { + // ignore stage that fails the condition + if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) { + break; + } + // draw any previous interaction + RB_SubmittInteraction( &inter, DrawInteraction ); + inter.diffuseImage = NULL; + inter.specularImage = NULL; + R_SetDrawInteraction( surfaceStage, surfaceRegs, &inter.bumpImage, inter.bumpMatrix, NULL ); + break; + } + case SL_DIFFUSE: { + // ignore stage that fails the condition + if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) { + break; + } + if ( inter.diffuseImage ) { + RB_SubmittInteraction( &inter, DrawInteraction ); + } + R_SetDrawInteraction( surfaceStage, surfaceRegs, &inter.diffuseImage, + inter.diffuseMatrix, inter.diffuseColor.ToFloatPtr() ); + inter.diffuseColor[0] *= lightColor[0]; + inter.diffuseColor[1] *= lightColor[1]; + inter.diffuseColor[2] *= lightColor[2]; + inter.diffuseColor[3] *= lightColor[3]; + inter.vertexColor = surfaceStage->vertexColor; + break; + } + case SL_SPECULAR: { + // ignore stage that fails the condition + if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) { + break; + } + if ( inter.specularImage ) { + RB_SubmittInteraction( &inter, DrawInteraction ); + } + R_SetDrawInteraction( surfaceStage, surfaceRegs, &inter.specularImage, + inter.specularMatrix, inter.specularColor.ToFloatPtr() ); + inter.specularColor[0] *= lightColor[0]; + inter.specularColor[1] *= lightColor[1]; + inter.specularColor[2] *= lightColor[2]; + inter.specularColor[3] *= lightColor[3]; + inter.vertexColor = surfaceStage->vertexColor; + break; + } + } + } + + // draw the final interaction + RB_SubmittInteraction( &inter, DrawInteraction ); + } + + // unhack depth range if needed + if ( surf->space->weaponDepthHack || surf->space->modelDepthHack != 0.0f ) { + RB_LeaveDepthHack(); + } } /* @@ -851,69 +783,65 @@ RB_DrawView ============= */ void RB_DrawView( const void *data ) { - const drawSurfsCommand_t *cmd; - - cmd = (const drawSurfsCommand_t *)data; - - // with r_lockSurfaces enabled, we set the locked render view - // for the primary viewDef for all the "what should be drawn" calculations. - // now it must be reverted to the real render view so the scene gets rendered - // from the actual current players point of view - if(r_lockSurfaces.GetBool() && tr.primaryView == cmd->viewDef) { - viewDef_t* parms = cmd->viewDef; - const viewDef_t origParms = *parms; - - *parms = tr.lockSurfacesRealViewDef; // actual current player/camera position - parms->renderWorld = origParms.renderWorld; - parms->floatTime = origParms.floatTime; - parms->drawSurfs = origParms.drawSurfs; - parms->numDrawSurfs = origParms.numDrawSurfs; - parms->maxDrawSurfs = origParms.maxDrawSurfs; - parms->viewLights = origParms.viewLights; - parms->viewEntitys = origParms.viewEntitys; - parms->connectedAreas = origParms.connectedAreas; - - for( viewEntity_t* vModel = parms->viewEntitys ; vModel ; vModel = vModel->next ) { - myGlMultMatrix( vModel->modelMatrix, - parms->worldSpace.modelViewMatrix, - vModel->modelViewMatrix ); - } - } - - backEnd.viewDef = cmd->viewDef; - - // we will need to do a new copyTexSubImage of the screen - // when a SS_POST_PROCESS material is used - backEnd.currentRenderCopied = false; - - // if there aren't any drawsurfs, do nothing - if ( !backEnd.viewDef->numDrawSurfs ) { - return; - } - - // skip render bypasses everything that has models, assuming - // them to be 3D views, but leaves 2D rendering visible - if ( r_skipRender.GetBool() && backEnd.viewDef->viewEntitys ) { - return; - } - - // skip render context sets the gl context to NULL, - // which should factor out the API cost, under the assumption - // that all gl calls just return if the context isn't valid - if ( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) { - GLimp_DeactivateContext(); - } - - backEnd.pc.c_surfaces += backEnd.viewDef->numDrawSurfs; - - RB_ShowOverdraw(); - - // render the scene, jumping to the hardware specific interaction renderers - RB_STD_DrawView(); - - // restore the context for 2D drawing if we were stubbing it out - if ( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) { - GLimp_ActivateContext(); - RB_SetDefaultGLState(); - } + const drawSurfsCommand_t *cmd; + + cmd = (const drawSurfsCommand_t *)data; + + // with r_lockSurfaces enabled, we set the locked render view + // for the primary viewDef for all the "what should be drawn" calculations. + // now it must be reverted to the real render view so the scene gets rendered + // from the actual current players point of view + if(r_lockSurfaces.GetBool() && tr.primaryView == cmd->viewDef) { + viewDef_t* parms = cmd->viewDef; + const viewDef_t origParms = *parms; + + *parms = tr.lockSurfacesRealViewDef; // actual current player/camera position + parms->renderWorld = origParms.renderWorld; + parms->floatTime = origParms.floatTime; + parms->drawSurfs = origParms.drawSurfs; + parms->numDrawSurfs = origParms.numDrawSurfs; + parms->maxDrawSurfs = origParms.maxDrawSurfs; + parms->viewLights = origParms.viewLights; + parms->viewEntitys = origParms.viewEntitys; + parms->connectedAreas = origParms.connectedAreas; + + for( viewEntity_t* vModel = parms->viewEntitys ; vModel ; vModel = vModel->next ) { + R_MatrixMultiply( vModel->modelMatrix, parms->worldSpace.modelViewMatrix, vModel->modelViewMatrix ); + } + } + backEnd.viewDef = cmd->viewDef; + + // we will need to do a new copyTexSubImage of the screen + // when a SS_POST_PROCESS material is used + backEnd.currentRenderCopied = false; + + // if there aren't any drawsurfs, do nothing + if ( !backEnd.viewDef->numDrawSurfs ) { + return; + } + + // skip render bypasses everything that has models, assuming + // them to be 3D views, but leaves 2D rendering visible + if ( r_skipRender.GetBool() && backEnd.viewDef->viewEntitys ) { + return; + } + + // skip render context sets the gl context to NULL, + // which should factor out the API cost, under the assumption + // that all gl calls just return if the context isn't valid + if ( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) { + GLimp_DeactivateContext(); + } + backEnd.pc.c_surfaces += backEnd.viewDef->numDrawSurfs; + + RB_ShowOverdraw(); + + // render the scene, jumping to the hardware specific interaction renderers + RB_STD_DrawView(); + + // restore the context for 2D drawing if we were stubbing it out + if ( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) { + GLimp_ActivateContext(); + RB_SetDefaultGLState(); + } } diff --git a/neo/renderer/tr_rendertools.cpp b/neo/renderer/tr_rendertools.cpp index d54b434c1..e9d169fbc 100644 --- a/neo/renderer/tr_rendertools.cpp +++ b/neo/renderer/tr_rendertools.cpp @@ -89,7 +89,6 @@ void RB_DrawBounds( const idBounds &bounds ) { if ( bounds.IsCleared() ) { return; } - qglBegin( GL_LINE_LOOP ); qglVertex3f( bounds[0][0], bounds[0][1], bounds[0][2] ); qglVertex3f( bounds[0][0], bounds[1][1], bounds[0][2] ); @@ -118,7 +117,6 @@ void RB_DrawBounds( const idBounds &bounds ) { qglEnd(); } - /* ================ RB_SimpleSurfaceSetup @@ -135,9 +133,9 @@ void RB_SimpleSurfaceSetup( const drawSurf_t *drawSurf ) { if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( drawSurf->scissorRect ) ) { backEnd.currentScissor = drawSurf->scissorRect; qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, - backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, - backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, - backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); + backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, + backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, + backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); } } @@ -152,9 +150,9 @@ void RB_SimpleWorldSetup( void ) { backEnd.currentScissor = backEnd.viewDef->scissor; qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, - backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, - backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, - backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); + backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, + backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, + backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); } /* @@ -169,7 +167,7 @@ stenciling will matter. */ void RB_PolygonClear( void ) { qglPushMatrix(); - qglPushAttrib( GL_ALL_ATTRIB_BITS ); + qglPushAttrib( GL_ALL_ATTRIB_BITS ); qglLoadIdentity(); qglDisable( GL_TEXTURE_2D ); qglDisable( GL_DEPTH_TEST ); @@ -210,17 +208,17 @@ void RB_ScanStencilBuffer( void ) { memset( counts, 0, sizeof( counts ) ); - stencilReadback = (byte *)R_StaticAlloc( glConfig.vidWidth * glConfig.vidHeight ); + stencilReadback = ( byte * )R_StaticAlloc( glConfig.vidWidth * glConfig.vidHeight ); qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback ); for ( i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++ ) { counts[ stencilReadback[i] ]++; } - R_StaticFree( stencilReadback ); // print some stats (not supposed to do from back end in SMP...) common->Printf( "stencil values:\n" ); + for ( i = 0 ; i < 255 ; i++ ) { if ( counts[i] ) { common->Printf( "%i: %i\n", i, counts[i] ); @@ -241,19 +239,18 @@ void RB_CountStencilBuffer( void ) { int i; byte *stencilReadback; - - stencilReadback = (byte *)R_StaticAlloc( glConfig.vidWidth * glConfig.vidHeight ); + stencilReadback = ( byte * )R_StaticAlloc( glConfig.vidWidth * glConfig.vidHeight ); qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback ); count = 0; + for ( i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++ ) { count += stencilReadback[i]; } - R_StaticFree( stencilReadback ); // print some stats (not supposed to do from back end in SMP...) - common->Printf( "overdraw: %5.1f\n", (float)count/(glConfig.vidWidth * glConfig.vidHeight) ); + common->Printf( "overdraw: %5.1f\n", ( float )count / ( glConfig.vidWidth * glConfig.vidHeight ) ); } /* @@ -268,14 +265,14 @@ stencil buffer. Stencil of 0 = black, 1 = red, 2 = green, static void R_ColorByStencilBuffer( void ) { int i; static float colors[8][3] = { - {0,0,0}, - {1,0,0}, - {0,1,0}, - {0,0,1}, - {0,1,1}, - {1,0,1}, - {1,1,0}, - {1,1,1}, + {0, 0, 0}, + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + {0, 1, 1}, + {1, 0, 1}, + {1, 1, 0}, + {1, 1, 1}, }; // clear color buffer to white (>6 passes) @@ -285,12 +282,12 @@ static void R_ColorByStencilBuffer( void ) { // now draw color for each stencil value qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); + for ( i = 0 ; i < 6 ; i++ ) { qglColor3fv( colors[i] ); qglStencilFunc( GL_EQUAL, i, 255 ); RB_PolygonClear(); } - qglStencilFunc( GL_ALWAYS, 0, 255 ); } @@ -302,26 +299,26 @@ RB_ShowOverdraw ================== */ void RB_ShowOverdraw( void ) { - const idMaterial * material; + const idMaterial *material; int i; drawSurf_t * * drawSurfs; - const drawSurf_t * surf; + const drawSurf_t *surf; int numDrawSurfs; - viewLight_t * vLight; + viewLight_t *vLight; if ( r_showOverDraw.GetInteger() == 0 ) { return; } - material = declManager->FindMaterial( "textures/common/overdrawtest", false ); + if ( material == NULL ) { return; } - drawSurfs = backEnd.viewDef->drawSurfs; numDrawSurfs = backEnd.viewDef->numDrawSurfs; int interactions = 0; + for ( vLight = backEnd.viewDef->viewLights; vLight; vLight = vLight->next ) { for ( surf = vLight->localInteractions; surf; surf = surf->nextOnLight ) { interactions++; @@ -330,43 +327,44 @@ void RB_ShowOverdraw( void ) { interactions++; } } - - drawSurf_t **newDrawSurfs = (drawSurf_t **)R_FrameAlloc( numDrawSurfs + interactions * sizeof( newDrawSurfs[0] ) ); + drawSurf_t **newDrawSurfs = ( drawSurf_t ** )R_FrameAlloc( numDrawSurfs + interactions * sizeof( newDrawSurfs[0] ) ); for ( i = 0; i < numDrawSurfs; i++ ) { surf = drawSurfs[i]; + if ( surf->material ) { - const_cast(surf)->material = material; + const_cast( surf )->material = material; } - newDrawSurfs[i] = const_cast(surf); + newDrawSurfs[i] = const_cast( surf ); } for ( vLight = backEnd.viewDef->viewLights; vLight; vLight = vLight->next ) { for ( surf = vLight->localInteractions; surf; surf = surf->nextOnLight ) { - const_cast(surf)->material = material; - newDrawSurfs[i++] = const_cast(surf); + const_cast( surf )->material = material; + newDrawSurfs[i++] = const_cast( surf ); } + for ( surf = vLight->globalInteractions; surf; surf = surf->nextOnLight ) { - const_cast(surf)->material = material; - newDrawSurfs[i++] = const_cast(surf); + const_cast( surf )->material = material; + newDrawSurfs[i++] = const_cast( surf ); } vLight->localInteractions = NULL; vLight->globalInteractions = NULL; } - switch( r_showOverDraw.GetInteger() ) { - case 1: // geometry overdraw - const_cast(backEnd.viewDef)->drawSurfs = newDrawSurfs; - const_cast(backEnd.viewDef)->numDrawSurfs = numDrawSurfs; - break; - case 2: // light interaction overdraw - const_cast(backEnd.viewDef)->drawSurfs = &newDrawSurfs[numDrawSurfs]; - const_cast(backEnd.viewDef)->numDrawSurfs = interactions; - break; - case 3: // geometry + light interaction overdraw - const_cast(backEnd.viewDef)->drawSurfs = newDrawSurfs; - const_cast(backEnd.viewDef)->numDrawSurfs += interactions; - break; + switch ( r_showOverDraw.GetInteger() ) { + case 1: // geometry overdraw + const_cast( backEnd.viewDef )->drawSurfs = newDrawSurfs; + const_cast( backEnd.viewDef )->numDrawSurfs = numDrawSurfs; + break; + case 2: // light interaction overdraw + const_cast( backEnd.viewDef )->drawSurfs = &newDrawSurfs[numDrawSurfs]; + const_cast( backEnd.viewDef )->numDrawSurfs = interactions; + break; + case 3: // geometry + light interaction overdraw + const_cast( backEnd.viewDef )->drawSurfs = newDrawSurfs; + const_cast( backEnd.viewDef )->numDrawSurfs += interactions; + break; } } @@ -386,27 +384,29 @@ void RB_ShowIntensity( void ) { if ( !r_showIntensity.GetBool() ) { return; } - - colorReadback = (byte *)R_StaticAlloc( glConfig.vidWidth * glConfig.vidHeight * 4 ); + colorReadback = ( byte * )R_StaticAlloc( glConfig.vidWidth * glConfig.vidHeight * 4 ); qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGBA, GL_UNSIGNED_BYTE, colorReadback ); c = glConfig.vidWidth * glConfig.vidHeight * 4; - for ( i = 0; i < c ; i+=4 ) { + for ( i = 0; i < c ; i += 4 ) { j = colorReadback[i]; - if ( colorReadback[i+1] > j ) { - j = colorReadback[i+1]; + + if ( colorReadback[i + 1] > j ) { + j = colorReadback[i + 1]; } - if ( colorReadback[i+2] > j ) { - j = colorReadback[i+2]; + + if ( colorReadback[i + 2] > j ) { + j = colorReadback[i + 2]; } + if ( j < 128 ) { - colorReadback[i+0] = 2*(128-j); - colorReadback[i+1] = 2*j; - colorReadback[i+2] = 0; + colorReadback[i + 0] = 2 * ( 128 - j ); + colorReadback[i + 1] = 2 * j; + colorReadback[i + 2] = 0; } else { - colorReadback[i+0] = 0; - colorReadback[i+1] = 2*(255-j); - colorReadback[i+2] = 2*(j-128); + colorReadback[i + 0] = 0; + colorReadback[i + 1] = 2 * ( 255 - j ); + colorReadback[i + 2] = 2 * ( j - 128 ); } } @@ -423,12 +423,11 @@ void RB_ShowIntensity( void ) { globalImages->BindNull(); qglMatrixMode( GL_MODELVIEW ); - qglDrawPixels( glConfig.vidWidth, glConfig.vidHeight, GL_RGBA , GL_UNSIGNED_BYTE, colorReadback ); + qglDrawPixels( glConfig.vidWidth, glConfig.vidHeight, GL_RGBA, GL_UNSIGNED_BYTE, colorReadback ); R_StaticFree( colorReadback ); } - /* =================== RB_ShowDepthBuffer @@ -437,11 +436,9 @@ Draw the depth buffer as colors =================== */ void RB_ShowDepthBuffer( void ) { - if ( !r_showDepth.GetBool() ) { return; } - qglPushMatrix(); qglLoadIdentity(); qglMatrixMode( GL_PROJECTION ); @@ -453,71 +450,68 @@ void RB_ShowDepthBuffer( void ) { GL_State( GLS_DEPTHFUNC_ALWAYS ); qglColor3f( 1, 1, 1 ); - bool haveDepthCapture = r_enableDepthCapture.GetInteger() == 1 - || (r_enableDepthCapture.GetInteger() == -1 && r_useSoftParticles.GetBool()); + bool haveDepthCapture = r_enableDepthCapture.GetInteger() == 1 || ( r_enableDepthCapture.GetInteger() == -1 && r_useSoftParticles.GetBool() ); if ( haveDepthCapture ) { //GL_SelectTexture( 0 ); //qglEnable(GL_TEXTURE_2D); globalImages->currentDepthImage->Bind(); - const float x=0, y=0, w=1, h=1; + const float x = 0, y = 0, w = 1, h = 1; // debug values: //const float x = 0.1, y = 0.1, w = 0.8, h = 0.8; //qglColor4f( 0.0f, 0.0f, 0.5f, 1.0f ); - const float tx=0, ty=0; + const float tx = 0, ty = 0; // the actual texturesize of currentDepthImage is the next bigger power of two (POT), // so the normalized width/height of the part of it we actually wanna show is the following - const float tw = float(glConfig.vidWidth) / float(globalImages->currentDepthImage->uploadWidth); - const float th = float(glConfig.vidHeight) / float(globalImages->currentDepthImage->uploadHeight); + const float tw = float( glConfig.vidWidth ) / float( globalImages->currentDepthImage->uploadWidth ); + const float th = float( glConfig.vidHeight ) / float( globalImages->currentDepthImage->uploadHeight ); qglBegin( GL_QUADS ); - qglTexCoord2f(tx, ty); - qglVertex2f( x, y ); // ( 0,0 ); + qglTexCoord2f( tx, ty ); + qglVertex2f( x, y ); // ( 0,0 ); - qglTexCoord2f(tx, ty+th); - qglVertex2f( x, y+h ); // ( 0,1 ); + qglTexCoord2f( tx, ty + th ); + qglVertex2f( x, y + h ); // ( 0,1 ); - qglTexCoord2f(tx+tw, ty+th); - qglVertex2f( x+w, y+h ); // ( 1,1 ); + qglTexCoord2f( tx + tw, ty + th ); + qglVertex2f( x + w, y + h ); // ( 1,1 ); - qglTexCoord2f(tx+tw, ty); - qglVertex2f( x+w, y ); // ( 1,0 ); + qglTexCoord2f( tx + tw, ty ); + qglVertex2f( x + w, y ); // ( 1,0 ); qglEnd(); // TODO: probably a shader transforming this to something viewable - qglPopMatrix(); qglMatrixMode( GL_MODELVIEW ); qglPopMatrix(); - } else { qglPopMatrix(); qglMatrixMode( GL_MODELVIEW ); qglPopMatrix(); globalImages->BindNull(); - void* depthReadback = R_StaticAlloc( glConfig.vidWidth * glConfig.vidHeight*4 ); - memset( depthReadback, 0, glConfig.vidWidth * glConfig.vidHeight*4 ); + void *depthReadback = R_StaticAlloc( glConfig.vidWidth * glConfig.vidHeight * 4 ); + memset( depthReadback, 0, glConfig.vidWidth * glConfig.vidHeight * 4 ); - qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_DEPTH_COMPONENT , GL_FLOAT, depthReadback ); + qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_DEPTH_COMPONENT, GL_FLOAT, depthReadback ); #if 0 // the following looks better, but is different from the !r_skipDepthCapture.GetBool() case above - // (which draws the captured depth buffer unaltered, unless we add a shader) - for ( int i = 0, n=glConfig.vidWidth * glConfig.vidHeight; i < n ; i++ ) { - float& px = ((float *)depthReadback)[i]; + // (which draws the captured depth buffer unaltered, unless we add a shader) + for ( int i = 0, n = glConfig.vidWidth * glConfig.vidHeight; i < n ; i++ ) { + float &px = ( ( float * )depthReadback )[i]; float d = px; // the following calculation is based on how the TDM soft particle shader translates the depth value to doom units // 0.9995 is practically infinite distance, clamping to 0.9994 clamps to max 30k doom units, // which is more than enough (and prevents a potential division by 0 below) - d = (d < 0.9994f) ? d : 0.9994f; + d = ( d < 0.9994f ) ? d : 0.9994f; d = d - 0.9995f; // d is now negative, between -0.0001 and -0.9995 d = 1.0f / d; // d *= -3.0f; // this would translate d to distance in doom units, doing it together with the next step - d *= (-3.0f / 3000.0f); // now 3000 units is 1.0, i.e. completely white (=> more details for closer distances) + d *= ( -3.0f / 3000.0f ); // now 3000 units is 1.0, i.e. completely white (=> more details for closer distances) px = d; } #endif @@ -542,13 +536,11 @@ void RB_ShowLightCount( void ) { if ( !r_showLightCount.GetBool() ) { return; } - GL_State( GLS_DEPTHFUNC_EQUAL ); RB_SimpleWorldSetup(); qglClearStencil( 0 ); qglClear( GL_STENCIL_BUFFER_BIT ); - qglEnable( GL_STENCIL_TEST ); // optionally count everything through walls @@ -557,20 +549,18 @@ void RB_ShowLightCount( void ) { } else { qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); } - qglStencilFunc( GL_ALWAYS, 1, 255 ); globalImages->defaultImage->Bind(); for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) { for ( i = 0 ; i < 2 ; i++ ) { - for ( surf = i ? vLight->localInteractions: vLight->globalInteractions; surf; surf = (drawSurf_t *)surf->nextOnLight ) { + for ( surf = i ? vLight->localInteractions : vLight->globalInteractions; surf; surf = ( drawSurf_t * )surf->nextOnLight ) { RB_SimpleSurfaceSetup( surf ); if ( !surf->geo->ambientCache ) { continue; } - - const idDrawVert *ac = (idDrawVert *)vertexCache.Position( surf->geo->ambientCache ); + const idDrawVert *ac = ( idDrawVert * )vertexCache.Position( surf->geo->ambientCache ); qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), &ac->xyz ); RB_DrawElementsWithCounters( surf->geo ); } @@ -618,9 +608,7 @@ void RB_ShowSilhouette( void ) { GL_Cull( CT_TWO_SIDED ); qglDisable( GL_DEPTH_TEST ); - RB_RenderDrawSurfListWithFunction( backEnd.viewDef->drawSurfs, backEnd.viewDef->numDrawSurfs, - RB_T_RenderTriangleSurface ); - + RB_RenderDrawSurfListWithFunction( backEnd.viewDef->drawSurfs, backEnd.viewDef->numDrawSurfs, RB_T_RenderTriangleSurface ); // // now blend in edges that cast silhouettes @@ -631,8 +619,7 @@ void RB_ShowSilhouette( void ) { for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) { for ( i = 0 ; i < 2 ; i++ ) { - for ( surf = i ? vLight->localShadows : vLight->globalShadows - ; surf ; surf = (drawSurf_t *)surf->nextOnLight ) { + for ( surf = i ? vLight->localShadows : vLight->globalShadows ; surf ; surf = ( drawSurf_t * )surf->nextOnLight ) { RB_SimpleSurfaceSetup( surf ); const srfTriangles_t *tri = surf->geo; @@ -640,31 +627,29 @@ void RB_ShowSilhouette( void ) { qglVertexPointer( 3, GL_FLOAT, sizeof( shadowCache_t ), vertexCache.Position( tri->shadowCache ) ); qglBegin( GL_LINES ); - for ( int j = 0 ; j < tri->numIndexes ; j+=3 ) { - int i1 = tri->indexes[j+0]; - int i2 = tri->indexes[j+1]; - int i3 = tri->indexes[j+2]; + for ( int j = 0 ; j < tri->numIndexes ; j += 3 ) { + int i1 = tri->indexes[j + 0]; + int i2 = tri->indexes[j + 1]; + int i3 = tri->indexes[j + 2]; - if ( (i1 & 1) + (i2 & 1) + (i3 & 1) == 1 ) { - if ( (i1 & 1) + (i2 & 1) == 0 ) { + if ( ( i1 & 1 ) + ( i2 & 1 ) + ( i3 & 1 ) == 1 ) { + if ( ( i1 & 1 ) + ( i2 & 1 ) == 0 ) { qglArrayElement( i1 ); qglArrayElement( i2 ); - } else if ( (i1 & 1 ) + (i3 & 1) == 0 ) { + } else if ( ( i1 & 1 ) + ( i3 & 1 ) == 0 ) { qglArrayElement( i1 ); qglArrayElement( i3 ); } } } qglEnd(); - } } } - qglEnable( GL_DEPTH_TEST ); GL_State( GLS_DEFAULT ); - qglColor3f( 1,1,1 ); + qglColor3f( 1, 1, 1 ); GL_Cull( CT_FRONT_SIDED ); } @@ -686,7 +671,6 @@ static void RB_ShowShadowCount( void ) { if ( !r_showShadowCount.GetBool() ) { return; } - GL_State( GLS_DEFAULT ); qglClearStencil( 0 ); @@ -695,7 +679,6 @@ static void RB_ShowShadowCount( void ) { qglEnable( GL_STENCIL_TEST ); qglStencilOp( GL_KEEP, GL_INCR, GL_INCR ); - qglStencilFunc( GL_ALWAYS, 1, 255 ); globalImages->defaultImage->Bind(); @@ -705,10 +688,11 @@ static void RB_ShowShadowCount( void ) { for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) { for ( i = 0 ; i < 2 ; i++ ) { - for ( surf = i ? vLight->localShadows : vLight->globalShadows - ; surf ; surf = (drawSurf_t *)surf->nextOnLight ) { + for ( surf = i ? vLight->localShadows : vLight->globalShadows ; surf ; surf = ( drawSurf_t * )surf->nextOnLight ) { RB_SimpleSurfaceSetup( surf ); + const srfTriangles_t *tri = surf->geo; + if ( !tri->shadowCache ) { continue; } @@ -719,14 +703,14 @@ static void RB_ShowShadowCount( void ) { continue; } } + if ( r_showShadowCount.GetInteger() == 4 ) { // only show static shadows if ( tri->numShadowIndexesNoCaps == tri->numIndexes ) { continue; } } - - shadowCache_t *cache = (shadowCache_t *)vertexCache.Position( tri->shadowCache ); + shadowCache_t *cache = ( shadowCache_t * )vertexCache.Position( tri->shadowCache ); qglVertexPointer( 4, GL_FLOAT, sizeof( *cache ), &cache->xyz ); RB_DrawElementsWithCounters( tri ); } @@ -747,11 +731,9 @@ static void RB_ShowShadowCount( void ) { if ( r_showShadowCount.GetInteger() >= 2 ) { RB_CountStencilBuffer(); } - GL_Cull( CT_FRONT_SIDED ); } - /* =============== RB_T_RenderTriangleSurfaceAsLines @@ -764,13 +746,13 @@ void RB_T_RenderTriangleSurfaceAsLines( const drawSurf_t *surf ) { if ( !tri->verts ) { return; } - qglBegin( GL_LINES ); - for ( int i = 0 ; i < tri->numIndexes ; i+= 3 ) { + + for ( int i = 0 ; i < tri->numIndexes ; i += 3 ) { for ( int j = 0 ; j < 3 ; j++ ) { int k = ( j + 1 ) % 3; - qglVertex3fv( tri->verts[ tri->silIndexes[i+j] ].xyz.ToFloatPtr() ); - qglVertex3fv( tri->verts[ tri->silIndexes[i+k] ].xyz.ToFloatPtr() ); + qglVertex3fv( tri->verts[ tri->silIndexes[i + j] ].xyz.ToFloatPtr() ); + qglVertex3fv( tri->verts[ tri->silIndexes[i + k] ].xyz.ToFloatPtr() ); } } qglEnd(); @@ -790,7 +772,6 @@ static void RB_ShowTris( drawSurf_t **drawSurfs, int numDrawSurfs ) { if ( !r_showTris.GetInteger() ) { return; } - qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); globalImages->BindNull(); qglDisable( GL_TEXTURE_2D ); @@ -798,7 +779,6 @@ static void RB_ShowTris( drawSurf_t **drawSurfs, int numDrawSurfs ) { qglColor3f( 1, 1, 1 ); - GL_State( GLS_POLYMODE_LINE ); switch ( r_showTris.GetInteger() ) { @@ -816,7 +796,6 @@ static void RB_ShowTris( drawSurf_t **drawSurfs, int numDrawSurfs ) { qglDisable( GL_DEPTH_TEST ); break; } - RB_RenderDrawSurfListWithFunction( drawSurfs, numDrawSurfs, RB_T_RenderTriangleSurface ); qglEnable( GL_DEPTH_TEST ); @@ -827,7 +806,6 @@ static void RB_ShowTris( drawSurf_t **drawSurfs, int numDrawSurfs ) { GL_Cull( CT_FRONT_SIDED ); } - /* ===================== RB_ShowSurfaceInfo @@ -846,10 +824,10 @@ static void RB_ShowSurfaceInfo( drawSurf_t **drawSurfs, int numDrawSurfs ) { // start far enough away that we don't hit the player model start = tr.primaryView->renderView.vieworg + tr.primaryView->renderView.viewaxis[0] * 16; end = start + tr.primaryView->renderView.viewaxis[0] * 1000.0f; + if ( !tr.primaryWorld->Trace( mt, start, end, 0.0f, false ) ) { return; } - qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); globalImages->BindNull(); qglDisable( GL_TEXTURE_2D ); @@ -868,9 +846,9 @@ static void RB_ShowSurfaceInfo( drawSurf_t **drawSurfs, int numDrawSurfs ) { R_AxisToModelMatrix( mt.entity->axis, mt.entity->origin, matrix ); tr.primaryWorld->DrawText( mt.entity->hModel->Name(), mt.point + tr.primaryView->renderView.viewaxis[2] * 12, - 0.35f, colorRed, tr.primaryView->renderView.viewaxis ); + 0.35f, colorRed, tr.primaryView->renderView.viewaxis ); tr.primaryWorld->DrawText( mt.material->GetName(), mt.point, - 0.35f, colorBlue, tr.primaryView->renderView.viewaxis ); + 0.35f, colorBlue, tr.primaryView->renderView.viewaxis ); qglEnable( GL_DEPTH_TEST ); qglDisable( GL_POLYGON_OFFSET_LINE ); @@ -892,15 +870,16 @@ static void RB_ShowViewEntitys( viewEntity_t *vModels ) { if ( !r_showViewEntitys.GetBool() ) { return; } + if ( r_showViewEntitys.GetInteger() == 2 ) { common->Printf( "view entities: " ); + for ( ; vModels ; vModels = vModels->next ) { common->Printf( "%i ", vModels->entityDef->index ); } common->Printf( "\n" ); return; } - qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); globalImages->BindNull(); qglDisable( GL_TEXTURE_2D ); @@ -908,14 +887,13 @@ static void RB_ShowViewEntitys( viewEntity_t *vModels ) { qglColor3f( 1, 1, 1 ); - GL_State( GLS_POLYMODE_LINE ); GL_Cull( CT_TWO_SIDED ); qglDisable( GL_DEPTH_TEST ); qglDisable( GL_SCISSOR_TEST ); - for ( ; vModels ; vModels = vModels->next ) { + for ( /**/; vModels ; vModels = vModels->next ) { idBounds b; qglLoadMatrixf( vModels->modelViewMatrix ); @@ -928,18 +906,17 @@ static void RB_ShowViewEntitys( viewEntity_t *vModels ) { qglColor3f( 1, 1, 0 ); RB_DrawBounds( vModels->entityDef->referenceBounds ); - // draw the model bounds in white qglColor3f( 1, 1, 1 ); idRenderModel *model = R_EntityDefDynamicModel( vModels->entityDef ); + if ( !model ) { continue; // particles won't instantiate without a current view } b = model->Bounds( &vModels->entityDef->parms ); RB_DrawBounds( b ); } - qglEnable( GL_DEPTH_TEST ); qglDisable( GL_POLYGON_OFFSET_LINE ); @@ -978,22 +955,23 @@ static void RB_ShowTexturePolarity( drawSurf_t **drawSurfs, int numDrawSurfs ) { if ( !tri->verts ) { continue; } - RB_SimpleSurfaceSetup( drawSurf ); qglBegin( GL_TRIANGLES ); - for ( j = 0 ; j < tri->numIndexes ; j+=3 ) { + + for ( j = 0 ; j < tri->numIndexes ; j += 3 ) { idDrawVert *a, *b, *c; float d0[5], d1[5]; float area; a = tri->verts + tri->indexes[j]; - b = tri->verts + tri->indexes[j+1]; - c = tri->verts + tri->indexes[j+2]; + b = tri->verts + tri->indexes[j + 1]; + c = tri->verts + tri->indexes[j + 2]; // VectorSubtract( b->xyz, a->xyz, d0 ); d0[3] = b->st[0] - a->st[0]; d0[4] = b->st[1] - a->st[1]; + // VectorSubtract( c->xyz, a->xyz, d1 ); d1[3] = c->st[0] - a->st[0]; d1[4] = c->st[1] - a->st[1]; @@ -1013,11 +991,9 @@ static void RB_ShowTexturePolarity( drawSurf_t **drawSurfs, int numDrawSurfs ) { } qglEnd(); } - GL_State( GLS_DEFAULT ); } - /* ===================== RB_ShowUnsmoothedTangents @@ -1047,17 +1023,18 @@ static void RB_ShowUnsmoothedTangents( drawSurf_t **drawSurfs, int numDrawSurfs if ( !drawSurf->material->UseUnsmoothedTangents() ) { continue; } - RB_SimpleSurfaceSetup( drawSurf ); tri = drawSurf->geo; + qglBegin( GL_TRIANGLES ); - for ( j = 0 ; j < tri->numIndexes ; j+=3 ) { + + for ( j = 0 ; j < tri->numIndexes ; j += 3 ) { idDrawVert *a, *b, *c; a = tri->verts + tri->indexes[j]; - b = tri->verts + tri->indexes[j+1]; - c = tri->verts + tri->indexes[j+2]; + b = tri->verts + tri->indexes[j + 1]; + c = tri->verts + tri->indexes[j + 2]; qglVertex3fv( a->xyz.ToFloatPtr() ); qglVertex3fv( b->xyz.ToFloatPtr() ); @@ -1065,7 +1042,6 @@ static void RB_ShowUnsmoothedTangents( drawSurf_t **drawSurfs, int numDrawSurfs } qglEnd(); } - GL_State( GLS_DEFAULT ); } @@ -1100,10 +1076,12 @@ static void RB_ShowTangentSpace( drawSurf_t **drawSurfs, int numDrawSurfs ) { RB_SimpleSurfaceSetup( drawSurf ); tri = drawSurf->geo; + if ( !tri->verts ) { continue; } qglBegin( GL_TRIANGLES ); + for ( j = 0 ; j < tri->numIndexes ; j++ ) { const idDrawVert *v; @@ -1111,19 +1089,18 @@ static void RB_ShowTangentSpace( drawSurf_t **drawSurfs, int numDrawSurfs ) { if ( r_showTangentSpace.GetInteger() == 1 ) { qglColor4f( 0.5 + 0.5 * v->tangents[0][0], 0.5 + 0.5 * v->tangents[0][1], - 0.5 + 0.5 * v->tangents[0][2], 0.5 ); + 0.5 + 0.5 * v->tangents[0][2], 0.5 ); } else if ( r_showTangentSpace.GetInteger() == 2 ) { qglColor4f( 0.5 + 0.5 * v->tangents[1][0], 0.5 + 0.5 * v->tangents[1][1], - 0.5 + 0.5 * v->tangents[1][2], 0.5 ); + 0.5 + 0.5 * v->tangents[1][2], 0.5 ); } else { qglColor4f( 0.5 + 0.5 * v->normal[0], 0.5 + 0.5 * v->normal[1], - 0.5 + 0.5 * v->normal[2], 0.5 ); + 0.5 + 0.5 * v->normal[2], 0.5 ); } qglVertex3fv( v->xyz.ToFloatPtr() ); } qglEnd(); } - GL_State( GLS_DEFAULT ); } @@ -1154,10 +1131,12 @@ static void RB_ShowVertexColor( drawSurf_t **drawSurfs, int numDrawSurfs ) { RB_SimpleSurfaceSetup( drawSurf ); tri = drawSurf->geo; + if ( !tri->verts ) { continue; } qglBegin( GL_TRIANGLES ); + for ( j = 0 ; j < tri->numIndexes ; j++ ) { const idDrawVert *v; @@ -1167,7 +1146,6 @@ static void RB_ShowVertexColor( drawSurf_t **drawSurfs, int numDrawSurfs ) { } qglEnd(); } - GL_State( GLS_DEFAULT ); } @@ -1191,19 +1169,19 @@ static void RB_ShowNormals( drawSurf_t **drawSurfs, int numDrawSurfs ) { if ( r_showNormals.GetFloat() == 0.0f ) { return; } - GL_State( GLS_POLYMODE_LINE ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); globalImages->BindNull(); qglDisable( GL_STENCIL_TEST ); + if ( !r_debugLineDepthTest.GetBool() ) { qglDisable( GL_DEPTH_TEST ); } else { qglEnable( GL_DEPTH_TEST ); } - size = r_showNormals.GetFloat(); + if ( size < 0.0f ) { size = -size; showNumbers = true; @@ -1217,11 +1195,12 @@ static void RB_ShowNormals( drawSurf_t **drawSurfs, int numDrawSurfs ) { RB_SimpleSurfaceSetup( drawSurf ); tri = drawSurf->geo; + if ( !tri->verts ) { continue; } - qglBegin( GL_LINES ); + for ( j = 0 ; j < tri->numVerts ; j++ ) { qglColor3f( 0, 0, 1 ); qglVertex3fv( tri->verts[j].xyz.ToFloatPtr() ); @@ -1243,9 +1222,12 @@ static void RB_ShowNormals( drawSurf_t **drawSurfs, int numDrawSurfs ) { if ( showNumbers ) { RB_SimpleWorldSetup(); + for ( i = 0 ; i < numDrawSurfs ; i++ ) { drawSurf = drawSurfs[i]; + tri = drawSurf->geo; + if ( !tri->verts ) { continue; } @@ -1261,11 +1243,9 @@ static void RB_ShowNormals( drawSurf_t **drawSurfs, int numDrawSurfs ) { } } } - qglEnable( GL_STENCIL_TEST ); } - /* ===================== RB_ShowNormals @@ -1283,7 +1263,6 @@ static void RB_AltShowNormals( drawSurf_t **drawSurfs, int numDrawSurfs ) { if ( r_showNormals.GetFloat() == 0.0f ) { return; } - GL_State( GLS_DEFAULT ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); @@ -1302,9 +1281,9 @@ static void RB_AltShowNormals( drawSurf_t **drawSurfs, int numDrawSurfs ) { const idDrawVert *v[3]; idVec3 mid; - v[0] = &tri->verts[tri->indexes[j+0]]; - v[1] = &tri->verts[tri->indexes[j+1]]; - v[2] = &tri->verts[tri->indexes[j+2]]; + v[0] = &tri->verts[tri->indexes[j + 0]]; + v[1] = &tri->verts[tri->indexes[j + 1]]; + v[2] = &tri->verts[tri->indexes[j + 2]]; // make the midpoint slightly above the triangle mid = ( v[0]->xyz + v[1]->xyz + v[2]->xyz ) * ( 1.0f / 3.0f ); @@ -1337,7 +1316,6 @@ static void RB_AltShowNormals( drawSurf_t **drawSurfs, int numDrawSurfs ) { } qglEnd(); } - qglEnable( GL_DEPTH_TEST ); qglEnable( GL_STENCIL_TEST ); } @@ -1360,8 +1338,8 @@ static void RB_ShowTextureVectors( drawSurf_t **drawSurfs, int numDrawSurfs ) { if ( r_showTextureVectors.GetFloat() == 0.0f ) { return; } - GL_State( GLS_DEPTHFUNC_LESS ); + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); globalImages->BindNull(); @@ -1374,6 +1352,7 @@ static void RB_ShowTextureVectors( drawSurf_t **drawSurfs, int numDrawSurfs ) { if ( !tri->verts ) { continue; } + if ( !tri->facePlanes ) { continue; } @@ -1382,7 +1361,7 @@ static void RB_ShowTextureVectors( drawSurf_t **drawSurfs, int numDrawSurfs ) { // draw non-shared edges in yellow qglBegin( GL_LINES ); - for ( j = 0 ; j < tri->numIndexes ; j+= 3 ) { + for ( j = 0 ; j < tri->numIndexes ; j += 3 ) { const idDrawVert *a, *b, *c; float area, inva; idVec3 temp; @@ -1390,9 +1369,9 @@ static void RB_ShowTextureVectors( drawSurf_t **drawSurfs, int numDrawSurfs ) { idVec3 mid; idVec3 tangents[2]; - a = &tri->verts[tri->indexes[j+0]]; - b = &tri->verts[tri->indexes[j+1]]; - c = &tri->verts[tri->indexes[j+2]]; + a = &tri->verts[tri->indexes[j + 0]]; + b = &tri->verts[tri->indexes[j + 1]]; + c = &tri->verts[tri->indexes[j + 2]]; // make the midpoint slightly above the triangle mid = ( a->xyz + b->xyz + c->xyz ) * ( 1.0f / 3.0f ); @@ -1402,25 +1381,27 @@ static void RB_ShowTextureVectors( drawSurf_t **drawSurfs, int numDrawSurfs ) { VectorSubtract( b->xyz, a->xyz, d0 ); d0[3] = b->st[0] - a->st[0]; d0[4] = b->st[1] - a->st[1]; + VectorSubtract( c->xyz, a->xyz, d1 ); d1[3] = c->st[0] - a->st[0]; d1[4] = c->st[1] - a->st[1]; area = d0[3] * d1[4] - d0[4] * d1[3]; + if ( area == 0 ) { continue; } inva = 1.0 / area; - temp[0] = (d0[0] * d1[4] - d0[4] * d1[0]) * inva; - temp[1] = (d0[1] * d1[4] - d0[4] * d1[1]) * inva; - temp[2] = (d0[2] * d1[4] - d0[4] * d1[2]) * inva; + temp[0] = ( d0[0] * d1[4] - d0[4] * d1[0] ) * inva; + temp[1] = ( d0[1] * d1[4] - d0[4] * d1[1] ) * inva; + temp[2] = ( d0[2] * d1[4] - d0[4] * d1[2] ) * inva; temp.Normalize(); tangents[0] = temp; - temp[0] = (d0[3] * d1[0] - d0[0] * d1[3]) * inva; - temp[1] = (d0[3] * d1[1] - d0[1] * d1[3]) * inva; - temp[2] = (d0[3] * d1[2] - d0[2] * d1[3]) * inva; + temp[0] = ( d0[3] * d1[0] - d0[0] * d1[3] ) * inva; + temp[1] = ( d0[3] * d1[1] - d0[1] * d1[3] ) * inva; + temp[2] = ( d0[3] * d1[2] - d0[2] * d1[3] ) * inva; temp.Normalize(); tangents[1] = temp; @@ -1436,7 +1417,6 @@ static void RB_ShowTextureVectors( drawSurf_t **drawSurfs, int numDrawSurfs ) { qglVertex3fv( mid.ToFloatPtr() ); qglVertex3fv( tangents[1].ToFloatPtr() ); } - qglEnd(); } } @@ -1456,7 +1436,6 @@ static void RB_ShowDominantTris( drawSurf_t **drawSurfs, int numDrawSurfs ) { if ( !r_showDominantTri.GetBool() ) { return; } - GL_State( GLS_DEPTHFUNC_LESS ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); @@ -1473,6 +1452,7 @@ static void RB_ShowDominantTris( drawSurf_t **drawSurfs, int numDrawSurfs ) { if ( !tri->verts ) { continue; } + if ( !tri->dominantTris ) { continue; } @@ -1486,7 +1466,6 @@ static void RB_ShowDominantTris( drawSurf_t **drawSurfs, int numDrawSurfs ) { idVec3 mid; // find the midpoint of the dominant tri - a = &tri->verts[j]; b = &tri->verts[tri->dominantTris[j].v2]; c = &tri->verts[tri->dominantTris[j].v3]; @@ -1496,7 +1475,6 @@ static void RB_ShowDominantTris( drawSurf_t **drawSurfs, int numDrawSurfs ) { qglVertex3fv( mid.ToFloatPtr() ); qglVertex3fv( a->xyz.ToFloatPtr() ); } - qglEnd(); } qglDisable( GL_POLYGON_OFFSET_LINE ); @@ -1519,8 +1497,8 @@ static void RB_ShowEdges( drawSurf_t **drawSurfs, int numDrawSurfs ) { if ( !r_showEdges.GetBool() ) { return; } - GL_State( GLS_DEFAULT ); + qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); globalImages->BindNull(); @@ -1531,29 +1509,29 @@ static void RB_ShowEdges( drawSurf_t **drawSurfs, int numDrawSurfs ) { tri = drawSurf->geo; - idDrawVert *ac = (idDrawVert *)tri->verts; + idDrawVert *ac = ( idDrawVert * )tri->verts; + if ( !ac ) { continue; } - RB_SimpleSurfaceSetup( drawSurf ); // draw non-shared edges in yellow qglColor3f( 1, 1, 0 ); qglBegin( GL_LINES ); - for ( j = 0 ; j < tri->numIndexes ; j+= 3 ) { + for ( j = 0 ; j < tri->numIndexes ; j += 3 ) { for ( k = 0 ; k < 3 ; k++ ) { int l, i1, i2; l = ( k == 2 ) ? 0 : k + 1; - i1 = tri->indexes[j+k]; - i2 = tri->indexes[j+l]; + i1 = tri->indexes[j + k]; + i2 = tri->indexes[j + l]; // if these are used backwards, the edge is shared for ( m = 0 ; m < tri->numIndexes ; m += 3 ) { for ( n = 0 ; n < 3 ; n++ ) { o = ( n == 2 ) ? 0 : n + 1; - if ( tri->indexes[m+n] == i2 && tri->indexes[m+o] == i1 ) { + if ( tri->indexes[m + n] == i2 && tri->indexes[m + o] == i1 ) { break; } } @@ -1570,7 +1548,6 @@ static void RB_ShowEdges( drawSurf_t **drawSurfs, int numDrawSurfs ) { } } - qglEnd(); // draw dangling sil edges in red @@ -1585,19 +1562,18 @@ static void RB_ShowEdges( drawSurf_t **drawSurfs, int numDrawSurfs ) { qglColor3f( 1, 0, 0 ); qglBegin( GL_LINES ); + for ( j = 0 ; j < tri->numSilEdges ; j++ ) { edge = tri->silEdges + j; if ( edge->p1 != danglePlane && edge->p2 != danglePlane ) { continue; } - qglVertex3fv( ac[ edge->v1 ].xyz.ToFloatPtr() ); qglVertex3fv( ac[ edge->v2 ].xyz.ToFloatPtr() ); } qglEnd(); } - qglEnable( GL_DEPTH_TEST ); } @@ -1628,14 +1604,13 @@ void RB_ShowLights( void ) { globalImages->BindNull(); qglDisable( GL_STENCIL_TEST ); - GL_Cull( CT_TWO_SIDED ); qglDisable( GL_DEPTH_TEST ); - common->Printf( "volumes: " ); // FIXME: not in back end! count = 0; + for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) { light = vLight->lightDef; count++; @@ -1652,15 +1627,13 @@ void RB_ShowLights( void ) { // non-hidden lines if ( r_showLights.GetInteger() >= 3 ) { - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK ); + GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK ); qglDisable( GL_DEPTH_TEST ); qglColor3f( 1, 1, 1 ); RB_RenderTriangleSurface( tri ); } + int index = backEnd.viewDef->renderWorld->lightDefs.FindIndex( vLight->lightDef ); - int index; - - index = backEnd.viewDef->renderWorld->lightDefs.FindIndex( vLight->lightDef ); if ( vLight->viewInsideLight ) { // view is in this volume common->Printf( "[%i] ", index ); @@ -1668,7 +1641,6 @@ void RB_ShowLights( void ) { common->Printf( "%i ", index ); } } - qglEnable( GL_DEPTH_TEST ); qglDisable( GL_POLYGON_OFFSET_LINE ); @@ -1699,7 +1671,7 @@ void RB_ShowPortals( void ) { GL_State( GLS_DEFAULT ); - ((idRenderWorldLocal *)backEnd.viewDef->renderWorld)->ShowPortals(); + ( ( idRenderWorldLocal * )backEnd.viewDef->renderWorld )->ShowPortals(); qglEnable( GL_DEPTH_TEST ); } @@ -1729,6 +1701,7 @@ void RB_ClearDebugText( int time ) { // copy any text that still needs to be drawn num = 0; text = rb_debugText; + for ( i = 0 ; i < rb_numDebugText; i++, text++ ) { if ( text->lifeTime > time ) { if ( num != i ) { @@ -1774,7 +1747,7 @@ float RB_DrawTextLength( const char *text, float scale, int len ) { if ( text && *text ) { if ( !len ) { - len = strlen(text); + len = strlen( text ); } for ( i = 0; i < len; i++ ) { charIndex = text[i] - 32; @@ -1785,13 +1758,13 @@ float RB_DrawTextLength( const char *text, float scale, int len ) { spacing = simplex[charIndex][1]; index = 2; - while( index - 2 < num ) { - if ( simplex[charIndex][index] < 0) { + while ( index - 2 < num ) { + if ( simplex[charIndex][index] < 0 ) { index++; continue; } index += 2; - if ( simplex[charIndex][index] < 0) { + if ( simplex[charIndex][index] < 0 ) { index++; continue; } @@ -1824,20 +1797,22 @@ static void RB_DrawText( const char *text, const idVec3 &origin, float scale, co } else { line = 0; } - org.Zero(); len = strlen( text ); + for ( i = 0; i < len; i++ ) { if ( i == 0 || text[i] == '\n' ) { org = origin - viewAxis[2] * ( line * 36.0f * scale ); + if ( align != 0 ) { - for ( j = 1; i+j <= len; j++ ) { - if ( i+j == len || text[i+j] == '\n' ) { - textLen = RB_DrawTextLength( text+i, scale, j ); + for ( j = 1; i + j <= len; j++ ) { + if ( i + j == len || text[i + j] == '\n' ) { + textLen = RB_DrawTextLength( text + i, scale, j ); break; } } + if ( align == 2 ) { // right org += viewAxis[1] * textLen; @@ -1848,8 +1823,8 @@ static void RB_DrawText( const char *text, const idVec3 &origin, float scale, co } line++; } - charIndex = text[i] - 32; + if ( charIndex < 0 || charIndex > NUM_SIMPLEX_CHARS ) { continue; } @@ -1857,25 +1832,24 @@ static void RB_DrawText( const char *text, const idVec3 &origin, float scale, co spacing = simplex[charIndex][1]; index = 2; - while( index - 2 < num ) { - if ( simplex[charIndex][index] < 0) { + while ( index - 2 < num ) { + if ( simplex[charIndex][index] < 0 ) { index++; continue; } - p1 = org + scale * simplex[charIndex][index] * -viewAxis[1] + scale * simplex[charIndex][index+1] * viewAxis[2]; + p1 = org + scale * simplex[charIndex][index] * -viewAxis[1] + scale * simplex[charIndex][index + 1] * viewAxis[2]; index += 2; - if ( simplex[charIndex][index] < 0) { + if ( simplex[charIndex][index] < 0 ) { index++; continue; } - p2 = org + scale * simplex[charIndex][index] * -viewAxis[1] + scale * simplex[charIndex][index+1] * viewAxis[2]; + p2 = org + scale * simplex[charIndex][index] * -viewAxis[1] + scale * simplex[charIndex][index + 1] * viewAxis[2]; qglVertex3fv( p1.ToFloatPtr() ); qglVertex3fv( p2.ToFloatPtr() ); } org -= viewAxis[1] * ( spacing * scale ); } - qglEnd(); } } @@ -1913,8 +1887,8 @@ void RB_ShowDebugText( void ) { if ( !r_debugLineDepthTest.GetBool() ) { qglDisable( GL_DEPTH_TEST ); } - text = rb_debugText; + for ( i = 0 ; i < rb_numDebugText; i++, text++ ) { if ( !text->depthTest ) { RB_DrawText( text->text, text->origin, text->scale, text->color, text->viewAxis, text->align ); @@ -1924,14 +1898,13 @@ void RB_ShowDebugText( void ) { if ( !r_debugLineDepthTest.GetBool() ) { qglEnable( GL_DEPTH_TEST ); } - text = rb_debugText; + for ( i = 0 ; i < rb_numDebugText; i++, text++ ) { if ( text->depthTest ) { RB_DrawText( text->text, text->origin, text->scale, text->color, text->viewAxis, text->align ); } } - qglLineWidth( 1 ); GL_State( GLS_DEFAULT ); } @@ -1956,6 +1929,7 @@ void RB_ClearDebugLines( int time ) { // copy any lines that still need to be drawn num = 0; line = rb_debugLines; + for ( i = 0 ; i < rb_numDebugLines; i++, line++ ) { if ( line->lifeTime > time ) { if ( num != i ) { @@ -2005,6 +1979,7 @@ void RB_ShowDebugLines( void ) { globalImages->BindNull(); width = r_debugLineWidth.GetInteger(); + if ( width < 1 ) { width = 1; } else if ( width > 10 ) { @@ -2018,10 +1993,10 @@ void RB_ShowDebugLines( void ) { if ( !r_debugLineDepthTest.GetBool() ) { qglDisable( GL_DEPTH_TEST ); } - qglBegin( GL_LINES ); line = rb_debugLines; + for ( i = 0 ; i < rb_numDebugLines; i++, line++ ) { if ( !line->depthTest ) { qglColor3fv( line->rgb.ToFloatPtr() ); @@ -2034,10 +2009,10 @@ void RB_ShowDebugLines( void ) { if ( !r_debugLineDepthTest.GetBool() ) { qglEnable( GL_DEPTH_TEST ); } - qglBegin( GL_LINES ); line = rb_debugLines; + for ( i = 0 ; i < rb_numDebugLines; i++, line++ ) { if ( line->depthTest ) { qglColor4fv( line->rgb.ToFloatPtr() ); @@ -2045,7 +2020,6 @@ void RB_ShowDebugLines( void ) { qglVertex3fv( line->end.ToFloatPtr() ); } } - qglEnd(); qglLineWidth( 1 ); @@ -2073,6 +2047,7 @@ void RB_ClearDebugPolygons( int time ) { num = 0; poly = rb_debugPolygons; + for ( i = 0 ; i < rb_numDebugPolygons; i++, poly++ ) { if ( poly->lifeTime > time ) { if ( num != i ) { @@ -2133,23 +2108,18 @@ void RB_ShowDebugPolygons( void ) { qglPolygonOffset( -1, -2 ); qglEnable( GL_POLYGON_OFFSET_LINE ); } - poly = rb_debugPolygons; - for ( i = 0 ; i < rb_numDebugPolygons; i++, poly++ ) { -// if ( !poly->depthTest ) { - qglColor4fv( poly->rgb.ToFloatPtr() ); + for ( i = 0 ; i < rb_numDebugPolygons; i++, poly++ ) { + qglColor4fv( poly->rgb.ToFloatPtr() ); - qglBegin( GL_POLYGON ); + qglBegin( GL_POLYGON ); - for ( j = 0; j < poly->winding.GetNumPoints(); j++) { - qglVertex3fv( poly->winding[j].ToFloatPtr() ); - } - - qglEnd(); -// } + for ( j = 0; j < poly->winding.GetNumPoints(); j++ ) { + qglVertex3fv( poly->winding[j].ToFloatPtr() ); + } + qglEnd(); } - GL_State( GLS_DEFAULT ); if ( r_debugPolygonFilled.GetBool() ) { @@ -2157,8 +2127,8 @@ void RB_ShowDebugPolygons( void ) { } else { qglDisable( GL_POLYGON_OFFSET_LINE ); } - qglDepthRange( 0, 1 ); + GL_State( GLS_DEFAULT ); } @@ -2181,37 +2151,40 @@ void RB_TestGamma( void ) { if ( r_testGamma.GetInteger() <= 0 ) { return; } - v = r_testGamma.GetInteger(); + if ( v <= 1 || v >= 196 ) { v = 128; } - memset( image, 0, sizeof( image ) ); for ( mask = 0 ; mask < 8 ; mask++ ) { y = mask * BAR_HEIGHT; + for ( c = 0 ; c < 4 ; c++ ) { v = c * 64 + 32; + // solid color - for ( i = 0 ; i < BAR_HEIGHT/2 ; i++ ) { - for ( j = 0 ; j < G_WIDTH/4 ; j++ ) { + for ( i = 0 ; i < BAR_HEIGHT / 2 ; i++ ) { + for ( j = 0 ; j < G_WIDTH / 4 ; j++ ) { for ( comp = 0 ; comp < 3 ; comp++ ) { if ( mask & ( 1 << comp ) ) { - image[y+i][c*G_WIDTH/4+j][comp] = v; + image[y + i][c * G_WIDTH / 4 + j][comp] = v; } } } + // dithered color - for ( j = 0 ; j < G_WIDTH/4 ; j++ ) { + for ( j = 0 ; j < G_WIDTH / 4 ; j++ ) { if ( ( i ^ j ) & 1 ) { dither = c * 64; } else { dither = c * 64 + 63; } + for ( comp = 0 ; comp < 3 ; comp++ ) { if ( mask & ( 1 << comp ) ) { - image[y+BAR_HEIGHT/2+i][c*G_WIDTH/4+j][comp] = dither; + image[y + BAR_HEIGHT / 2 + i][c * G_WIDTH / 4 + j][comp] = dither; } } } @@ -2221,25 +2194,27 @@ void RB_TestGamma( void ) { // draw geometrically increasing steps in the bottom row y = 0 * BAR_HEIGHT; + float scale = 1; + for ( c = 0 ; c < 4 ; c++ ) { - v = (int)(64 * scale); + v = ( int )( 64 * scale ); + if ( v < 0 ) { v = 0; } else if ( v > 255 ) { v = 255; } - scale = scale * 1.5; + scale = scale * 1.5f; + for ( i = 0 ; i < BAR_HEIGHT ; i++ ) { - for ( j = 0 ; j < G_WIDTH/4 ; j++ ) { - image[y+i][c*G_WIDTH/4+j][0] = v; - image[y+i][c*G_WIDTH/4+j][1] = v; - image[y+i][c*G_WIDTH/4+j][2] = v; + for ( j = 0 ; j < G_WIDTH / 4 ; j++ ) { + image[y + i][c * G_WIDTH / 4 + j][0] = v; + image[y + i][c * G_WIDTH / 4 + j][1] = v; + image[y + i][c * G_WIDTH / 4 + j][2] = v; } } } - - qglLoadIdentity(); qglMatrixMode( GL_PROJECTION ); @@ -2256,7 +2231,6 @@ void RB_TestGamma( void ) { qglMatrixMode( GL_MODELVIEW ); } - /* ================== RB_TestGammaBias @@ -2268,29 +2242,31 @@ static void RB_TestGammaBias( void ) { if ( r_testGammaBias.GetInteger() <= 0 ) { return; } - int y = 0; - for ( int bias = -40 ; bias < 40 ; bias+=10, y += BAR_HEIGHT ) { + + for ( int bias = -40 ; bias < 40 ; bias += 10, y += BAR_HEIGHT ) { float scale = 1; + for ( int c = 0 ; c < 4 ; c++ ) { - int v = (int)(64 * scale + bias); + int v = ( int )( 64 * scale + bias ); + scale = scale * 1.5; + if ( v < 0 ) { v = 0; } else if ( v > 255 ) { v = 255; } + for ( int i = 0 ; i < BAR_HEIGHT ; i++ ) { - for ( int j = 0 ; j < G_WIDTH/4 ; j++ ) { - image[y+i][c*G_WIDTH/4+j][0] = v; - image[y+i][c*G_WIDTH/4+j][1] = v; - image[y+i][c*G_WIDTH/4+j][2] = v; + for ( int j = 0 ; j < G_WIDTH / 4 ; j++ ) { + image[y + i][c * G_WIDTH / 4 + j][0] = v; + image[y + i][c * G_WIDTH / 4 + j][1] = v; + image[y + i][c * G_WIDTH / 4 + j][2] = v; } } } } - - qglLoadIdentity(); qglMatrixMode( GL_PROJECTION ); GL_State( GLS_DEPTHFUNC_ALWAYS ); @@ -2319,14 +2295,14 @@ void RB_TestImage( void ) { float w, h; image = tr.testImage; + if ( !image ) { return; } if ( tr.testVideo ) { - cinData_t cin; + cinData_t cin = tr.testVideo->ImageForTime( ( int )( 1000 * ( backEnd.viewDef->floatTime - tr.testVideoStartTime ) ) ); - cin = tr.testVideo->ImageForTime( (int)(1000 * ( backEnd.viewDef->floatTime - tr.testVideoStartTime ) ) ); if ( cin.image ) { image->UploadScratch( cin.image, cin.imageWidth, cin.imageHeight ); } else { @@ -2341,9 +2317,8 @@ void RB_TestImage( void ) { w = 0.25 * image->uploadWidth / max; h = 0.25 * image->uploadHeight / max; - w *= (float)glConfig.vidHeight / glConfig.vidWidth; + w *= ( float )glConfig.vidHeight / glConfig.vidWidth; } - qglLoadIdentity(); qglMatrixMode( GL_PROJECTION ); @@ -2360,10 +2335,10 @@ void RB_TestImage( void ) { qglVertex2f( 0.5 - w, 0 ); qglTexCoord2f( 0, 0 ); - qglVertex2f( 0.5 - w, h*2 ); + qglVertex2f( 0.5 - w, h * 2 ); qglTexCoord2f( 1, 0 ); - qglVertex2f( 0.5 + w, h*2 ); + qglVertex2f( 0.5 + w, h * 2 ); qglTexCoord2f( 1, 1 ); qglVertex2f( 0.5 + w, 0 ); @@ -2384,14 +2359,12 @@ void RB_RenderDebugTools( drawSurf_t **drawSurfs, int numDrawSurfs ) { if ( !backEnd.viewDef->viewEntitys ) { return; } - GL_State( GLS_DEFAULT ); backEnd.currentScissor = backEnd.viewDef->scissor; qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, - backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, - backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, - backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); - + backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1, + backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1, + backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 ); RB_ShowLightCount(); RB_ShowShadowCount(); @@ -2407,9 +2380,11 @@ void RB_RenderDebugTools( drawSurf_t **drawSurfs, int numDrawSurfs ) { RB_ShowLights(); RB_ShowTextureVectors( drawSurfs, numDrawSurfs ); RB_ShowDominantTris( drawSurfs, numDrawSurfs ); + if ( r_testGamma.GetInteger() > 0 ) { // test here so stack check isn't so damn slow on debug builds RB_TestGamma(); } + if ( r_testGammaBias.GetInteger() > 0 ) { RB_TestGammaBias(); } diff --git a/neo/renderer/tr_shadowbounds.cpp b/neo/renderer/tr_shadowbounds.cpp index 8a6ce296d..70ac76be8 100644 --- a/neo/renderer/tr_shadowbounds.cpp +++ b/neo/renderer/tr_shadowbounds.cpp @@ -582,9 +582,10 @@ idScreenRect R_CalcIntersectionScissor( const idRenderLightLocal * lightDef, if ( r_useInteractionScissors.GetInteger() == -2 ) { draw_segments( viewDef, out_segs, colorGreen ); } - idBounds outbounds; + outbounds.Clear(); + for( unsigned int i = 0; i < out_segs.size(); i++ ) { idVec4 v; @@ -593,7 +594,6 @@ idScreenRect R_CalcIntersectionScissor( const idRenderLightLocal * lightDef, if( v.w <= 0.0f ) { return lightDef->viewLight->scissorRect; } - idVec3 rv(v.x, v.y, v.z); rv /= v.w; @@ -604,16 +604,18 @@ idScreenRect R_CalcIntersectionScissor( const idRenderLightLocal * lightDef, if ( outbounds[0].x < -1.0f ) { outbounds[0].x = -1.0f; } + if ( outbounds[1].x > 1.0f ) { outbounds[1].x = 1.0f; } + if ( outbounds[0].y < -1.0f ) { outbounds[0].y = -1.0f; } + if ( outbounds[1].y > 1.0f ) { outbounds[1].y = 1.0f; } - float w2 = ( viewDef->viewport.x2 - viewDef->viewport.x1 + 1 ) / 2.0f; float x = viewDef->viewport.x1; float h2 = ( viewDef->viewport.y2 - viewDef->viewport.y1 + 1 ) / 2.0f; @@ -632,6 +634,5 @@ idScreenRect R_CalcIntersectionScissor( const idRenderLightLocal * lightDef, if ( r_useInteractionScissors.GetInteger() == -2 && !rect.IsEmpty() ) { viewDef->renderWorld->DebugScreenRect( colorYellow, rect, viewDef ); } - return rect; } diff --git a/neo/renderer/tr_stencilshadow.cpp b/neo/renderer/tr_stencilshadow.cpp index 9b4278f7a..44f8c909a 100644 --- a/neo/renderer/tr_stencilshadow.cpp +++ b/neo/renderer/tr_stencilshadow.cpp @@ -27,7 +27,6 @@ If you have questions concerning this license or the applicable additional terms */ #include "sys/platform.h" - #include "renderer/tr_local.h" // tr_stencilShadow.c -- creaton of stencil shadow volumes @@ -94,10 +93,10 @@ If you have questions concerning this license or the applicable additional terms // the positive side of the frustum is inside d = tri->verts[i].xyz * frustum[j].Normal() + frustum[j][3]; if ( d < LIGHT_CLIP_EPSILON ) { - pointCull[i] |= ( 1 << j ); + pointCull[i] |= ( 1 << j ); } if ( d > -LIGHT_CLIP_EPSILON ) { - pointCull[i] |= ( 1 << (6+j) ); + pointCull[i] |= ( 1 << (6+j) ); } If a low order bit is set, the point is on or outside the plane @@ -105,113 +104,56 @@ If a high order bit is set, the point is on or inside the plane If a low order bit is clear, the point is inside the plane (definately positive) If a high order bit is clear, the point is outside the plane (definately negative) - */ -#define TRIANGLE_CULLED(p1,p2,p3) ( pointCull[p1] & pointCull[p2] & pointCull[p3] & 0x3f ) - -//#define TRIANGLE_CLIPPED(p1,p2,p3) ( ( pointCull[p1] | pointCull[p2] | pointCull[p3] ) & 0xfc0 ) -#define TRIANGLE_CLIPPED(p1,p2,p3) ( ( ( pointCull[p1] & pointCull[p2] & pointCull[p3] ) & 0xfc0 ) != 0xfc0 ) +#define TRIANGLE_CULLED( p1, p2, p3 ) ( pointCull[p1] & pointCull[p2] & pointCull[p3] & 0x3f ) +#define TRIANGLE_CLIPPED( p1, p2, p3 ) ( ( ( pointCull[p1] & pointCull[p2] & pointCull[p3] ) & 0xfc0 ) != 0xfc0 ) // an edge that is on the plane is NOT culled -#define EDGE_CULLED(p1,p2) ( ( pointCull[p1] ^ 0xfc0 ) & ( pointCull[p2] ^ 0xfc0 ) & 0xfc0 ) - -#define EDGE_CLIPPED(p1,p2) ( ( pointCull[p1] & pointCull[p2] & 0xfc0 ) != 0xfc0 ) +#define EDGE_CULLED( p1, p2 ) ( ( pointCull[p1] ^ 0xfc0 ) & ( pointCull[p2] ^ 0xfc0 ) & 0xfc0 ) +#define EDGE_CLIPPED( p1, p2 ) ( ( pointCull[p1] & pointCull[p2] & 0xfc0 ) != 0xfc0 ) // a point that is on the plane is NOT culled -//#define POINT_CULLED(p1) ( ( pointCull[p1] ^ 0xfc0 ) & 0xfc0 ) -#define POINT_CULLED(p1) ( ( pointCull[p1] & 0xfc0 ) != 0xfc0 ) - -//#define LIGHT_CLIP_EPSILON 0.001f -#define LIGHT_CLIP_EPSILON 0.1f - -#define MAX_CLIP_SIL_EDGES 2048 -static int numClipSilEdges; -static int clipSilEdges[MAX_CLIP_SIL_EDGES][2]; - -// facing will be 0 if forward facing, 1 if backwards facing -// grabbed with alloca -static byte *globalFacing; - -// faceCastsShadow will be 1 if the face is in the projection -// and facing the apropriate direction -static byte *faceCastsShadow; - -static int *remap; - -#define MAX_SHADOW_INDEXES 0x18000 -#define MAX_SHADOW_VERTS 0x18000 -static int numShadowIndexes; -static glIndex_t shadowIndexes[MAX_SHADOW_INDEXES]; -static int numShadowVerts; -static idVec4 shadowVerts[MAX_SHADOW_VERTS]; -static bool overflowed; - -idPlane pointLightFrustums[6][6] = { - { - idPlane( 1,0,0,0 ), - idPlane( 1,1,0,0 ), - idPlane( 1,-1,0,0 ), - idPlane( 1,0,1,0 ), - idPlane( 1,0,-1,0 ), - idPlane( -1,0,0,0 ), - }, - { - idPlane( -1,0,0,0 ), - idPlane( -1,1,0,0 ), - idPlane( -1,-1,0,0 ), - idPlane( -1,0,1,0 ), - idPlane( -1,0,-1,0 ), - idPlane( 1,0,0,0 ), - }, - - { - idPlane( 0,1,0,0 ), - idPlane( 0,1,1,0 ), - idPlane( 0,1,-1,0 ), - idPlane( 1,1,0,0 ), - idPlane( -1,1,0,0 ), - idPlane( 0,-1,0,0 ), - }, - { - idPlane( 0,-1,0,0 ), - idPlane( 0,-1,1,0 ), - idPlane( 0,-1,-1,0 ), - idPlane( 1,-1,0,0 ), - idPlane( -1,-1,0,0 ), - idPlane( 0,1,0,0 ), - }, - - { - idPlane( 0,0,1,0 ), - idPlane( 1,0,1,0 ), - idPlane( -1,0,1,0 ), - idPlane( 0,1,1,0 ), - idPlane( 0,-1,1,0 ), - idPlane( 0,0,-1,0 ), - }, - { - idPlane( 0,0,-1,0 ), - idPlane( 1,0,-1,0 ), - idPlane( -1,0,-1,0 ), - idPlane( 0,1,-1,0 ), - idPlane( 0,-1,-1,0 ), - idPlane( 0,0,1,0 ), - }, -}; - -int c_caps, c_sils; - -static bool callOptimizer; // call the preprocessor optimizer after clipping occluders +#define POINT_CULLED( p1 ) ( ( pointCull[p1] & 0xfc0 ) != 0xfc0 ) + +int c_caps, c_sils; typedef struct { - int frontCapStart; - int rearCapStart; - int silStart; - int end; + int frontCapStart; + int rearCapStart; + int silStart; + int end; } indexRef_t; -static indexRef_t indexRef[6]; -static int indexFrustumNumber; // which shadow generating side of a light the indexRef is for + +#define MAX_CLIP_SIL_EDGES 2048 +#define MAX_SHADOW_INDEXES 0x18000 +#define MAX_SHADOW_VERTS 0x18000 + +// Consolidated all static variables into a struct +// to pass as a state during shadow calculation +typedef struct { + int numClipSilEdges; + int clipSilEdges[MAX_CLIP_SIL_EDGES][2]; + + // facing will be 0 if forward facing, 1 if backwards facing + // grabbed with alloca + byte *globalFacing; + + // faceCastsShadow will be 1 if the face is in the projection + // and facing the apropriate direction + byte *faceCastsShadow; + + int *remap; + + int numShadowIndexes; + glIndex_t shadowIndexes[MAX_SHADOW_INDEXES]; + int numShadowVerts; + idVec4 shadowVerts[MAX_SHADOW_VERTS]; + bool overflowed; + bool callOptimizer; // call the preprocessor optimizer after clipping occluders + indexRef_t indexRef[6]; + int indexFrustumNumber; // which shadow generating side of a light the indexRef is for +} stencilRef_t; /* =============== @@ -229,22 +171,22 @@ If surfaces are ever guaranteed to not have to edge match with other surfaces, we could just compare indexes. =============== */ -static bool PointsOrdered( const idVec3 &a, const idVec3 &b ) { - float i, j; +static inline bool PointsOrdered( const idVec3 &a, const idVec3 &b ) { + float i, j; - // vectors that wind up getting an equal hash value will - // potentially cause a misorder, which can show as a couple - // crack pixels in a shadow + // vectors that wind up getting an equal hash value will + // potentially cause a misorder, which can show as a couple + // crack pixels in a shadow - // scale by some odd numbers so -8, 8, 8 will not be equal - // to 8, -8, 8 + // scale by some odd numbers so -8, 8, 8 will not be equal + // to 8, -8, 8 - // in the very rare case that these might be equal, all that would - // happen is an oportunity for a tiny rasterization shadow crack - i = a[0] + a[1]*127 + a[2]*1023; - j = b[0] + b[1]*127 + b[2]*1023; + // in the very rare case that these might be equal, all that would + // happen is an oportunity for a tiny rasterization shadow crack + i = a[0] + a[1] * 127 + a[2] * 1023; + j = b[0] + b[1] * 127 + b[2] * 1023; - return (bool)(i < j); + return ( bool )( i < j ); } /* @@ -254,37 +196,37 @@ R_LightProjectionMatrix ==================== */ void R_LightProjectionMatrix( const idVec3 &origin, const idPlane &rearPlane, idVec4 mat[4] ) { - idVec4 lv; - float lg; - - // calculate the homogenious light vector - lv.x = origin.x; - lv.y = origin.y; - lv.z = origin.z; - lv.w = 1; - - lg = rearPlane.ToVec4() * lv; - - // outer product - mat[0][0] = lg -rearPlane[0] * lv[0]; - mat[0][1] = -rearPlane[1] * lv[0]; - mat[0][2] = -rearPlane[2] * lv[0]; - mat[0][3] = -rearPlane[3] * lv[0]; - - mat[1][0] = -rearPlane[0] * lv[1]; - mat[1][1] = lg -rearPlane[1] * lv[1]; - mat[1][2] = -rearPlane[2] * lv[1]; - mat[1][3] = -rearPlane[3] * lv[1]; - - mat[2][0] = -rearPlane[0] * lv[2]; - mat[2][1] = -rearPlane[1] * lv[2]; - mat[2][2] = lg -rearPlane[2] * lv[2]; - mat[2][3] = -rearPlane[3] * lv[2]; - - mat[3][0] = -rearPlane[0] * lv[3]; - mat[3][1] = -rearPlane[1] * lv[3]; - mat[3][2] = -rearPlane[2] * lv[3]; - mat[3][3] = lg -rearPlane[3] * lv[3]; + idVec4 lv; + float lg; + + // calculate the homogenious light vector + lv.x = origin.x; + lv.y = origin.y; + lv.z = origin.z; + lv.w = 1; + + lg = rearPlane.ToVec4() * lv; + + // outer product + mat[0][0] = lg - rearPlane[0] * lv[0]; + mat[0][1] = -rearPlane[1] * lv[0]; + mat[0][2] = -rearPlane[2] * lv[0]; + mat[0][3] = -rearPlane[3] * lv[0]; + + mat[1][0] = -rearPlane[0] * lv[1]; + mat[1][1] = lg - rearPlane[1] * lv[1]; + mat[1][2] = -rearPlane[2] * lv[1]; + mat[1][3] = -rearPlane[3] * lv[1]; + + mat[2][0] = -rearPlane[0] * lv[2]; + mat[2][1] = -rearPlane[1] * lv[2]; + mat[2][2] = lg - rearPlane[2] * lv[2]; + mat[2][3] = -rearPlane[3] * lv[2]; + + mat[3][0] = -rearPlane[0] * lv[3]; + mat[3][1] = -rearPlane[1] * lv[3]; + mat[3][2] = -rearPlane[2] * lv[3]; + mat[3][3] = lg - rearPlane[3] * lv[3]; } /* @@ -295,60 +237,44 @@ make a projected copy of the even verts into the odd spots that is on the far light clip plane =================== */ -static void R_ProjectPointsToFarPlane( const idRenderEntityLocal *ent, const idRenderLightLocal *light, - const idPlane &lightPlaneLocal, - int firstShadowVert, int numShadowVerts ) { - idVec3 lv; - idVec4 mat[4]; - int i; - idVec4 *in; - - R_GlobalPointToLocal( ent->modelMatrix, light->globalLightOrigin, lv ); - R_LightProjectionMatrix( lv, lightPlaneLocal, mat ); - -#if 1 - // make a projected copy of the even verts into the odd spots - in = &shadowVerts[firstShadowVert]; - for ( i = firstShadowVert ; i < numShadowVerts ; i+= 2, in += 2 ) { - float w, oow; - - in[0].w = 1; - - w = in->ToVec3() * mat[3].ToVec3() + mat[3][3]; - if ( w == 0 ) { - in[1] = in[0]; - continue; - } - - oow = 1.0 / w; - in[1].x = ( in->ToVec3() * mat[0].ToVec3() + mat[0][3] ) * oow; - in[1].y = ( in->ToVec3() * mat[1].ToVec3() + mat[1][3] ) * oow; - in[1].z = ( in->ToVec3() * mat[2].ToVec3() + mat[2][3] ) * oow; - in[1].w = 1; - } - -#else - // messing with W seems to cause some depth precision problems - - // make a projected copy of the even verts into the odd spots - in = &shadowVerts[firstShadowVert]; - for ( i = firstShadowVert ; i < numShadowVerts ; i+= 2, in += 2 ) { - in[0].w = 1; - in[1].x = *in * mat[0].ToVec3() + mat[0][3]; - in[1].y = *in * mat[1].ToVec3() + mat[1][3]; - in[1].z = *in * mat[2].ToVec3() + mat[2][3]; - in[1].w = *in * mat[3].ToVec3() + mat[3][3]; - } -#endif +static inline void R_ProjectPointsToFarPlane( stencilRef_t *st, const idRenderEntityLocal *ent, const idRenderLightLocal *light, + const idPlane &lightPlaneLocal, + int firstShadowVert, int numShadowVerts ) { + idVec3 lv; + idVec4 mat[4]; + int i; + idVec4 *in; + + R_GlobalPointToLocal( ent->modelMatrix, light->globalLightOrigin, lv ); + R_LightProjectionMatrix( lv, lightPlaneLocal, mat ); + + // make a projected copy of the even verts into the odd spots + in = &st->shadowVerts[firstShadowVert]; + + for ( i = firstShadowVert ; i < numShadowVerts ; i += 2, in += 2 ) { + float w, oow; + + in[0].w = 1; + + w = in->ToVec3() * mat[3].ToVec3() + mat[3][3]; + + if ( w == 0 ) { + in[1] = in[0]; + continue; + } + oow = 1.0 / w; + in[1].x = ( in->ToVec3() * mat[0].ToVec3() + mat[0][3] ) * oow; + in[1].y = ( in->ToVec3() * mat[1].ToVec3() + mat[1][3] ) * oow; + in[1].z = ( in->ToVec3() * mat[2].ToVec3() + mat[2][3] ) * oow; + in[1].w = 1; + } } - - -#define MAX_CLIPPED_POINTS 20 +#define MAX_CLIPPED_POINTS 20 typedef struct { - int numVerts; - idVec3 verts[MAX_CLIPPED_POINTS]; - int edgeFlags[MAX_CLIPPED_POINTS]; + int numVerts; + idVec3 verts[MAX_CLIPPED_POINTS]; + int edgeFlags[MAX_CLIPPED_POINTS]; } clipTri_t; /* @@ -363,87 +289,88 @@ I have some worries about edge flag cases when polygons are clipped multiple times near the epsilon. ============= */ -static int R_ChopWinding( clipTri_t clipTris[2], int inNum, const idPlane &plane ) { - clipTri_t *in, *out; - float dists[MAX_CLIPPED_POINTS]; - int sides[MAX_CLIPPED_POINTS]; - int counts[3]; - float dot; - int i, j; - idVec3 *p1, *p2; - idVec3 mid; - - in = &clipTris[inNum]; - out = &clipTris[inNum^1]; - counts[0] = counts[1] = counts[2] = 0; - - // determine sides for each point - for ( i = 0 ; i < in->numVerts ; i++ ) { - dot = plane.Distance( in->verts[i] ); - dists[i] = dot; - if ( dot < -LIGHT_CLIP_EPSILON ) { - sides[i] = SIDE_BACK; - } else if ( dot > LIGHT_CLIP_EPSILON ) { - sides[i] = SIDE_FRONT; - } else { - sides[i] = SIDE_ON; - } - counts[sides[i]]++; - } - - // if none in front, it is completely clipped away - if ( !counts[SIDE_FRONT] ) { - in->numVerts = 0; - return inNum; - } - if ( !counts[SIDE_BACK] ) { - return inNum; // inout stays the same - } - - // avoid wrapping checks by duplicating first value to end - sides[i] = sides[0]; - dists[i] = dists[0]; - in->verts[in->numVerts] = in->verts[0]; - in->edgeFlags[in->numVerts] = in->edgeFlags[0]; - - out->numVerts = 0; - for ( i = 0 ; i < in->numVerts ; i++ ) { - p1 = &in->verts[i]; - - if ( sides[i] != SIDE_BACK ) { - out->verts[out->numVerts] = *p1; - if ( sides[i] == SIDE_ON && sides[i+1] == SIDE_BACK ) { - out->edgeFlags[out->numVerts] = 1; - } else { - out->edgeFlags[out->numVerts] = in->edgeFlags[i]; - } - out->numVerts++; - } - - if ( (sides[i] == SIDE_FRONT && sides[i+1] == SIDE_BACK) - || (sides[i] == SIDE_BACK && sides[i+1] == SIDE_FRONT) ) { - // generate a split point - p2 = &in->verts[i+1]; - - dot = dists[i] / (dists[i]-dists[i+1]); - for ( j=0 ; j<3 ; j++ ) { - mid[j] = (*p1)[j] + dot*((*p2)[j]-(*p1)[j]); - } - - out->verts[out->numVerts] = mid; - - // set the edge flag - if ( sides[i+1] != SIDE_FRONT ) { - out->edgeFlags[out->numVerts] = 1; - } else { - out->edgeFlags[out->numVerts] = in->edgeFlags[i]; - } - - out->numVerts++; - } - } - - return inNum ^ 1; +static inline int R_ChopWinding( clipTri_t clipTris[2], int inNum, const idPlane &plane ) { + clipTri_t *in, *out; + float dists[MAX_CLIPPED_POINTS]; + int sides[MAX_CLIPPED_POINTS]; + int counts[3]; + float dot; + int i, j; + idVec3 *p1, *p2; + idVec3 mid; + + in = &clipTris[inNum]; + out = &clipTris[inNum ^ 1]; + counts[0] = counts[1] = counts[2] = 0; + + // determine sides for each point + for ( i = 0 ; i < in->numVerts ; i++ ) { + dot = plane.Distance( in->verts[i] ); + dists[i] = dot; + + if ( dot < -LIGHT_CLIP_EPSILON ) { + sides[i] = SIDE_BACK; + } else if ( dot > LIGHT_CLIP_EPSILON ) { + sides[i] = SIDE_FRONT; + } else { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + + // if none in front, it is completely clipped away + if ( !counts[SIDE_FRONT] ) { + in->numVerts = 0; + return inNum; + } + + if ( !counts[SIDE_BACK] ) { + return inNum; // inout stays the same + } + + // avoid wrapping checks by duplicating first value to end + sides[i] = sides[0]; + dists[i] = dists[0]; + in->verts[in->numVerts] = in->verts[0]; + in->edgeFlags[in->numVerts] = in->edgeFlags[0]; + out->numVerts = 0; + + for ( i = 0 ; i < in->numVerts ; i++ ) { + p1 = &in->verts[i]; + + if ( sides[i] != SIDE_BACK ) { + out->verts[out->numVerts] = *p1; + + if ( sides[i] == SIDE_ON && sides[i + 1] == SIDE_BACK ) { + out->edgeFlags[out->numVerts] = 1; + } else { + out->edgeFlags[out->numVerts] = in->edgeFlags[i]; + } + out->numVerts++; + } + + if ( ( sides[i] == SIDE_FRONT && sides[i + 1] == SIDE_BACK ) || + ( sides[i] == SIDE_BACK && sides[i + 1] == SIDE_FRONT ) ) { + // generate a split point + p2 = &in->verts[i + 1]; + + dot = dists[i] / ( dists[i] - dists[i + 1] ); + + for ( j = 0 ; j < 3 ; j++ ) { + mid[j] = ( *p1 )[j] + dot * ( ( *p2 )[j] - ( *p1 )[j] ); + } + out->verts[out->numVerts] = mid; + + // set the edge flag + if ( sides[i + 1] != SIDE_FRONT ) { + out->edgeFlags[out->numVerts] = 1; + } else { + out->edgeFlags[out->numVerts] = in->edgeFlags[i]; + } + out->numVerts++; + } + } + return inNum ^ 1; } /* @@ -453,74 +380,76 @@ R_ClipTriangleToLight Returns false if nothing is left after clipping =================== */ -static bool R_ClipTriangleToLight( const idVec3 &a, const idVec3 &b, const idVec3 &c, int planeBits, - const idPlane frustum[6] ) { - int i; - int base; - clipTri_t pingPong[2], *ct; - int p; - - pingPong[0].numVerts = 3; - pingPong[0].edgeFlags[0] = 0; - pingPong[0].edgeFlags[1] = 0; - pingPong[0].edgeFlags[2] = 0; - pingPong[0].verts[0] = a; - pingPong[0].verts[1] = b; - pingPong[0].verts[2] = c; - - p = 0; - for ( i = 0 ; i < 6 ; i++ ) { - if ( planeBits & ( 1 << i ) ) { - p = R_ChopWinding( pingPong, p, frustum[i] ); - if ( pingPong[p].numVerts < 1 ) { - return false; - } - } - } - ct = &pingPong[p]; - - // copy the clipped points out to shadowVerts - if ( numShadowVerts + ct->numVerts * 2 > MAX_SHADOW_VERTS ) { - overflowed = true; - return false; - } - - base = numShadowVerts; - for ( i = 0 ; i < ct->numVerts ; i++ ) { - shadowVerts[ base + i*2 ].ToVec3() = ct->verts[i]; - } - numShadowVerts += ct->numVerts * 2; - - if ( numShadowIndexes + 3 * ( ct->numVerts - 2 ) > MAX_SHADOW_INDEXES ) { - overflowed = true; - return false; - } - - for ( i = 2 ; i < ct->numVerts ; i++ ) { - shadowIndexes[numShadowIndexes++] = base + i * 2; - shadowIndexes[numShadowIndexes++] = base + ( i - 1 ) * 2; - shadowIndexes[numShadowIndexes++] = base; - } - - // any edges that were created by the clipping process will - // have a silhouette quad created for it, because it is one - // of the exterior bounds of the shadow volume - for ( i = 0 ; i < ct->numVerts ; i++ ) { - if ( ct->edgeFlags[i] ) { - if ( numClipSilEdges == MAX_CLIP_SIL_EDGES ) { - break; - } - clipSilEdges[ numClipSilEdges ][0] = base + i * 2; - if ( i == ct->numVerts - 1 ) { - clipSilEdges[ numClipSilEdges ][1] = base; - } else { - clipSilEdges[ numClipSilEdges ][1] = base + ( i + 1 ) * 2; - } - numClipSilEdges++; - } - } - - return true; +static inline bool R_ClipTriangleToLight( stencilRef_t *st, const idVec3 &a, const idVec3 &b, const idVec3 &c, int planeBits, + const idPlane frustum[6] ) { + int i; + int base; + clipTri_t pingPong[2], *ct; + int p; + + pingPong[0].numVerts = 3; + pingPong[0].edgeFlags[0] = 0; + pingPong[0].edgeFlags[1] = 0; + pingPong[0].edgeFlags[2] = 0; + pingPong[0].verts[0] = a; + pingPong[0].verts[1] = b; + pingPong[0].verts[2] = c; + + p = 0; + + for ( i = 0 ; i < 6 ; i++ ) { + if ( planeBits & ( 1 << i ) ) { + p = R_ChopWinding( pingPong, p, frustum[i] ); + + if ( pingPong[p].numVerts < 1 ) { + return false; + } + } + } + ct = &pingPong[p]; + + // copy the clipped points out to shadowVerts + if ( st->numShadowVerts + ct->numVerts * 2 > MAX_SHADOW_VERTS ) { + st->overflowed = true; + return false; + } + base = st->numShadowVerts; + + for ( i = 0 ; i < ct->numVerts ; i++ ) { + st->shadowVerts[ base + i * 2 ].ToVec3() = ct->verts[i]; + } + st->numShadowVerts += ct->numVerts * 2; + + if ( st->numShadowIndexes + 3 * ( ct->numVerts - 2 ) > MAX_SHADOW_INDEXES ) { + st->overflowed = true; + return false; + } + + for ( i = 2 ; i < ct->numVerts ; i++ ) { + st->shadowIndexes[st->numShadowIndexes++] = base + i * 2; + st->shadowIndexes[st->numShadowIndexes++] = base + ( i - 1 ) * 2; + st->shadowIndexes[st->numShadowIndexes++] = base; + } + + // any edges that were created by the clipping process will + // have a silhouette quad created for it, because it is one + // of the exterior bounds of the shadow volume + for ( i = 0 ; i < ct->numVerts ; i++ ) { + if ( ct->edgeFlags[i] ) { + if ( st->numClipSilEdges == MAX_CLIP_SIL_EDGES ) { + break; + } + st->clipSilEdges[ st->numClipSilEdges ][0] = base + i * 2; + + if ( i == ct->numVerts - 1 ) { + st->clipSilEdges[ st->numClipSilEdges ][1] = base; + } else { + st->clipSilEdges[ st->numClipSilEdges ][1] = base + ( i + 1 ) * 2; + } + st->numClipSilEdges++; + } + } + return true; } /* @@ -535,57 +464,54 @@ If one point is clearly clipped by the plane and the other point is on the plane, it will be completely removed. =================== */ -static bool R_ClipLineToLight( const idVec3 &a, const idVec3 &b, const idPlane frustum[6], - idVec3 &p1, idVec3 &p2 ) { - float *clip; - int j; - float d1, d2; - float f; - - p1 = a; - p2 = b; - - // clip it - for ( j = 0 ; j < 6 ; j++ ) { - d1 = frustum[j].Distance( p1 ); - d2 = frustum[j].Distance( p2 ); - - // if both on or in front, not clipped to this plane - if ( d1 > -LIGHT_CLIP_EPSILON && d2 > -LIGHT_CLIP_EPSILON ) { - continue; - } - - // if one is behind and the other isn't clearly in front, the edge is clipped off - if ( d1 <= -LIGHT_CLIP_EPSILON && d2 < LIGHT_CLIP_EPSILON ) { - return false; - } - if ( d2 <= -LIGHT_CLIP_EPSILON && d1 < LIGHT_CLIP_EPSILON ) { - return false; - } - - // clip it, keeping the negative side - if ( d1 < 0 ) { - clip = p1.ToFloatPtr(); - } else { - clip = p2.ToFloatPtr(); - } - +static inline bool R_ClipLineToLight( const idVec3 &a, const idVec3 &b, const idPlane frustum[6], idVec3 &p1, idVec3 &p2 ) { + float *clip; + int j; + float d1, d2; + float f; + + p1 = a; + p2 = b; + + // clip it + for ( j = 0 ; j < 6 ; j++ ) { + d1 = frustum[j].Distance( p1 ); + d2 = frustum[j].Distance( p2 ); + + // if both on or in front, not clipped to this plane + if ( d1 > -LIGHT_CLIP_EPSILON && d2 > -LIGHT_CLIP_EPSILON ) { + continue; + } + + // if one is behind and the other isn't clearly in front, the edge is clipped off + if ( d1 <= -LIGHT_CLIP_EPSILON && d2 < LIGHT_CLIP_EPSILON ) { + return false; + } + + if ( d2 <= -LIGHT_CLIP_EPSILON && d1 < LIGHT_CLIP_EPSILON ) { + return false; + } + + // clip it, keeping the negative side + if ( d1 < 0 ) { + clip = p1.ToFloatPtr(); + } else { + clip = p2.ToFloatPtr(); + } #if 0 - if ( idMath::Fabs(d1 - d2) < 0.001 ) { - d2 = d1 - 0.1; - } + if ( idMath::Fabs( d1 - d2 ) < 0.001 ) { + d2 = d1 - 0.1; + } #endif + f = d1 / ( d1 - d2 ); - f = d1 / ( d1 - d2 ); - clip[0] = p1[0] + f * ( p2[0] - p1[0] ); - clip[1] = p1[1] + f * ( p2[1] - p1[1] ); - clip[2] = p1[2] + f * ( p2[2] - p1[2] ); - } - - return true; // retain a fragment + clip[0] = p1[0] + f * ( p2[0] - p1[0] ); + clip[1] = p1[1] + f * ( p2[1] - p1[1] ); + clip[2] = p1[2] + f * ( p2[2] - p1[2] ); + } + return true; // retain a fragment } - /* ================== R_AddClipSilEdges @@ -596,38 +522,40 @@ the frustum. Only done for simple projected lights, not point lights. ================== */ -static void R_AddClipSilEdges( void ) { - int v1, v2; - int v1_back, v2_back; - int i; - - // don't allow it to overflow - if ( numShadowIndexes + numClipSilEdges * 6 > MAX_SHADOW_INDEXES ) { - overflowed = true; - return; - } - - for ( i = 0 ; i < numClipSilEdges ; i++ ) { - v1 = clipSilEdges[i][0]; - v2 = clipSilEdges[i][1]; - v1_back = v1 + 1; - v2_back = v2 + 1; - if ( PointsOrdered( shadowVerts[ v1 ].ToVec3(), shadowVerts[ v2 ].ToVec3() ) ) { - shadowIndexes[numShadowIndexes++] = v1; - shadowIndexes[numShadowIndexes++] = v2; - shadowIndexes[numShadowIndexes++] = v1_back; - shadowIndexes[numShadowIndexes++] = v2; - shadowIndexes[numShadowIndexes++] = v2_back; - shadowIndexes[numShadowIndexes++] = v1_back; - } else { - shadowIndexes[numShadowIndexes++] = v1; - shadowIndexes[numShadowIndexes++] = v2; - shadowIndexes[numShadowIndexes++] = v2_back; - shadowIndexes[numShadowIndexes++] = v1; - shadowIndexes[numShadowIndexes++] = v2_back; - shadowIndexes[numShadowIndexes++] = v1_back; - } - } +static inline void R_AddClipSilEdges( stencilRef_t *st ) { + int v1, v2; + int v1_back, v2_back; + int i; + + // don't allow it to overflow + if ( st->numShadowIndexes + st->numClipSilEdges * 6 > MAX_SHADOW_INDEXES ) { + st->overflowed = true; + return; + } + + for ( i = 0 ; i < st->numClipSilEdges ; i++ ) { + v1 = st->clipSilEdges[i][0]; + v2 = st->clipSilEdges[i][1]; + + v1_back = v1 + 1; + v2_back = v2 + 1; + + if ( PointsOrdered( st->shadowVerts[ v1 ].ToVec3(), st->shadowVerts[ v2 ].ToVec3() ) ) { + st->shadowIndexes[st->numShadowIndexes++] = v1; + st->shadowIndexes[st->numShadowIndexes++] = v2; + st->shadowIndexes[st->numShadowIndexes++] = v1_back; + st->shadowIndexes[st->numShadowIndexes++] = v2; + st->shadowIndexes[st->numShadowIndexes++] = v2_back; + st->shadowIndexes[st->numShadowIndexes++] = v1_back; + } else { + st->shadowIndexes[st->numShadowIndexes++] = v1; + st->shadowIndexes[st->numShadowIndexes++] = v2; + st->shadowIndexes[st->numShadowIndexes++] = v2_back; + st->shadowIndexes[st->numShadowIndexes++] = v1; + st->shadowIndexes[st->numShadowIndexes++] = v2_back; + st->shadowIndexes[st->numShadowIndexes++] = v1_back; + } + } } /* @@ -638,106 +566,108 @@ Add quads from the front points to the projected points for each silhouette edge in the light ================= */ -static void R_AddSilEdges( const srfTriangles_t *tri, unsigned short *pointCull, const idPlane frustum[6] ) { - int v1, v2; - int i; - silEdge_t *sil; - int numPlanes; - - numPlanes = tri->numIndexes / 3; - - // add sil edges for any true silhouette boundaries on the surface - for ( i = 0 ; i < tri->numSilEdges ; i++ ) { - sil = tri->silEdges + i; - if ( sil->p1 < 0 || sil->p1 > numPlanes || sil->p2 < 0 || sil->p2 > numPlanes ) { - common->Error( "Bad sil planes" ); - } - - // an edge will be a silhouette edge if the face on one side - // casts a shadow, but the face on the other side doesn't. - // "casts a shadow" means that it has some surface in the projection, - // not just that it has the correct facing direction - // This will cause edges that are exactly on the frustum plane - // to be considered sil edges if the face inside casts a shadow. - if ( !( faceCastsShadow[ sil->p1 ] ^ faceCastsShadow[ sil->p2 ] ) ) { - continue; - } - - // if the edge is completely off the negative side of - // a frustum plane, don't add it at all. This can still - // happen even if the face is visible and casting a shadow - // if it is partially clipped - if ( EDGE_CULLED( sil->v1, sil->v2 ) ) { - continue; - } - - // see if the edge needs to be clipped - if ( EDGE_CLIPPED( sil->v1, sil->v2 ) ) { - if ( numShadowVerts + 4 > MAX_SHADOW_VERTS ) { - overflowed = true; - return; - } - v1 = numShadowVerts; - v2 = v1 + 2; - if ( !R_ClipLineToLight( tri->verts[ sil->v1 ].xyz, tri->verts[ sil->v2 ].xyz, - frustum, shadowVerts[v1].ToVec3(), shadowVerts[v2].ToVec3() ) ) { - continue; // clipped away - } - - numShadowVerts += 4; - } else { - // use the entire edge - v1 = remap[ sil->v1 ]; - v2 = remap[ sil->v2 ]; - if ( v1 < 0 || v2 < 0 ) { - common->Error( "R_AddSilEdges: bad remap[]" ); - } - } - - // don't overflow - if ( numShadowIndexes + 6 > MAX_SHADOW_INDEXES ) { - overflowed = true; - return; - } - - // we need to choose the correct way of triangulating the silhouette quad - // consistantly between any two points, no matter which order they are specified. - // If this wasn't done, slight rasterization cracks would show in the shadow - // volume when two sil edges were exactly coincident - if ( faceCastsShadow[ sil->p2 ] ) { - if ( PointsOrdered( shadowVerts[ v1 ].ToVec3(), shadowVerts[ v2 ].ToVec3() ) ) { - shadowIndexes[numShadowIndexes++] = v1; - shadowIndexes[numShadowIndexes++] = v1+1; - shadowIndexes[numShadowIndexes++] = v2; - shadowIndexes[numShadowIndexes++] = v2; - shadowIndexes[numShadowIndexes++] = v1+1; - shadowIndexes[numShadowIndexes++] = v2+1; - } else { - shadowIndexes[numShadowIndexes++] = v1; - shadowIndexes[numShadowIndexes++] = v2+1; - shadowIndexes[numShadowIndexes++] = v2; - shadowIndexes[numShadowIndexes++] = v1; - shadowIndexes[numShadowIndexes++] = v1+1; - shadowIndexes[numShadowIndexes++] = v2+1; - } - } else { - if ( PointsOrdered( shadowVerts[ v1 ].ToVec3(), shadowVerts[ v2 ].ToVec3() ) ) { - shadowIndexes[numShadowIndexes++] = v1; - shadowIndexes[numShadowIndexes++] = v2; - shadowIndexes[numShadowIndexes++] = v1+1; - shadowIndexes[numShadowIndexes++] = v2; - shadowIndexes[numShadowIndexes++] = v2+1; - shadowIndexes[numShadowIndexes++] = v1+1; - } else { - shadowIndexes[numShadowIndexes++] = v1; - shadowIndexes[numShadowIndexes++] = v2; - shadowIndexes[numShadowIndexes++] = v2+1; - shadowIndexes[numShadowIndexes++] = v1; - shadowIndexes[numShadowIndexes++] = v2+1; - shadowIndexes[numShadowIndexes++] = v1+1; - } - } - } +static inline void R_AddSilEdges( stencilRef_t *st, const srfTriangles_t *tri, unsigned short *pointCull, const idPlane frustum[6] ) { + int v1, v2; + int i; + silEdge_t *sil; + int numPlanes; + + numPlanes = tri->numIndexes / 3; + + // add sil edges for any true silhouette boundaries on the surface + for ( i = 0 ; i < tri->numSilEdges ; i++ ) { + sil = tri->silEdges + i; + + if ( sil->p1 < 0 || sil->p1 > numPlanes || sil->p2 < 0 || sil->p2 > numPlanes ) { + common->Error( "Bad sil planes" ); + } + + // an edge will be a silhouette edge if the face on one side + // casts a shadow, but the face on the other side doesn't. + // "casts a shadow" means that it has some surface in the projection, + // not just that it has the correct facing direction + // This will cause edges that are exactly on the frustum plane + // to be considered sil edges if the face inside casts a shadow. + if ( !( st->faceCastsShadow[ sil->p1 ] ^ st->faceCastsShadow[ sil->p2 ] ) ) { + continue; + } + + // if the edge is completely off the negative side of + // a frustum plane, don't add it at all. This can still + // happen even if the face is visible and casting a shadow + // if it is partially clipped + if ( EDGE_CULLED( sil->v1, sil->v2 ) ) { + continue; + } + + // see if the edge needs to be clipped + if ( EDGE_CLIPPED( sil->v1, sil->v2 ) ) { + if ( st->numShadowVerts + 4 > MAX_SHADOW_VERTS ) { + st->overflowed = true; + return; + } + v1 = st->numShadowVerts; + v2 = v1 + 2; + + if ( !R_ClipLineToLight( tri->verts[ sil->v1 ].xyz, tri->verts[ sil->v2 ].xyz, + frustum, st->shadowVerts[v1].ToVec3(), st->shadowVerts[v2].ToVec3() ) ) { + continue; // clipped away + } + st->numShadowVerts += 4; + } else { + // use the entire edge + v1 = st->remap[ sil->v1 ]; + v2 = st->remap[ sil->v2 ]; + + if ( v1 < 0 || v2 < 0 ) { + common->Error( "R_AddSilEdges: bad remap[]" ); + } + } + + // don't overflow + if ( st->numShadowIndexes + 6 > MAX_SHADOW_INDEXES ) { + st->overflowed = true; + return; + } + + // we need to choose the correct way of triangulating the silhouette quad + // consistantly between any two points, no matter which order they are specified. + // If this wasn't done, slight rasterization cracks would show in the shadow + // volume when two sil edges were exactly coincident + if ( st->faceCastsShadow[ sil->p2 ] ) { + if ( PointsOrdered( st->shadowVerts[ v1 ].ToVec3(), st->shadowVerts[ v2 ].ToVec3() ) ) { + st->shadowIndexes[st->numShadowIndexes++] = v1; + st->shadowIndexes[st->numShadowIndexes++] = v1 + 1; + st->shadowIndexes[st->numShadowIndexes++] = v2; + st->shadowIndexes[st->numShadowIndexes++] = v2; + st->shadowIndexes[st->numShadowIndexes++] = v1 + 1; + st->shadowIndexes[st->numShadowIndexes++] = v2 + 1; + } else { + st->shadowIndexes[st->numShadowIndexes++] = v1; + st->shadowIndexes[st->numShadowIndexes++] = v2 + 1; + st->shadowIndexes[st->numShadowIndexes++] = v2; + st->shadowIndexes[st->numShadowIndexes++] = v1; + st->shadowIndexes[st->numShadowIndexes++] = v1 + 1; + st->shadowIndexes[st->numShadowIndexes++] = v2 + 1; + } + } else { + if ( PointsOrdered( st->shadowVerts[ v1 ].ToVec3(), st->shadowVerts[ v2 ].ToVec3() ) ) { + st->shadowIndexes[st->numShadowIndexes++] = v1; + st->shadowIndexes[st->numShadowIndexes++] = v2; + st->shadowIndexes[st->numShadowIndexes++] = v1 + 1; + st->shadowIndexes[st->numShadowIndexes++] = v2; + st->shadowIndexes[st->numShadowIndexes++] = v2 + 1; + st->shadowIndexes[st->numShadowIndexes++] = v1 + 1; + } else { + st->shadowIndexes[st->numShadowIndexes++] = v1; + st->shadowIndexes[st->numShadowIndexes++] = v2; + st->shadowIndexes[st->numShadowIndexes++] = v2 + 1; + st->shadowIndexes[st->numShadowIndexes++] = v1; + st->shadowIndexes[st->numShadowIndexes++] = v2 + 1; + st->shadowIndexes[st->numShadowIndexes++] = v1 + 1; + } + } + } } /* @@ -747,50 +677,30 @@ R_CalcPointCull Also inits the remap[] array to all -1 ================ */ -static void R_CalcPointCull( const srfTriangles_t *tri, const idPlane frustum[6], unsigned short *pointCull ) { - int i; - int frontBits; - float *planeSide; - byte *side1, *side2; - - SIMDProcessor->Memset( remap, -1, tri->numVerts * sizeof( remap[0] ) ); - - for ( frontBits = 0, i = 0; i < 6; i++ ) { - // get front bits for the whole surface - if ( tri->bounds.PlaneDistance( frustum[i] ) >= LIGHT_CLIP_EPSILON ) { - frontBits |= 1<<(i+6); - } - } - - // initialize point cull - for ( i = 0; i < tri->numVerts; i++ ) { - pointCull[i] = frontBits; - } - - // if the surface is not completely inside the light frustum - if ( frontBits == ( ( ( 1 << 6 ) - 1 ) ) << 6 ) { - return; - } - - planeSide = (float *) _alloca16( tri->numVerts * sizeof( float ) ); - side1 = (byte *) _alloca16( tri->numVerts * sizeof( byte ) ); - side2 = (byte *) _alloca16( tri->numVerts * sizeof( byte ) ); - SIMDProcessor->Memset( side1, 0, tri->numVerts * sizeof( byte ) ); - SIMDProcessor->Memset( side2, 0, tri->numVerts * sizeof( byte ) ); - - for ( i = 0; i < 6; i++ ) { - - if ( frontBits & (1<<(i+6)) ) { - continue; - } - - SIMDProcessor->Dot( planeSide, frustum[i], tri->verts, tri->numVerts ); - SIMDProcessor->CmpLT( side1, i, planeSide, LIGHT_CLIP_EPSILON, tri->numVerts ); - SIMDProcessor->CmpGT( side2, i, planeSide, -LIGHT_CLIP_EPSILON, tri->numVerts ); - } - for ( i = 0; i < tri->numVerts; i++ ) { - pointCull[i] |= side1[i] | (side2[i] << 6); - } +static inline void R_CalcPointCull( stencilRef_t *st, const srfTriangles_t *tri, const idPlane frustum[6], unsigned short *pointCull ) { + int i; + int frontBits; + + SIMDProcessor->Memset( st->remap, -1, tri->numVerts * sizeof( st->remap[0] ) ); + + for ( frontBits = 0, i = 0; i < 6; i++ ) { + // get front bits for the whole surface + if ( tri->bounds.PlaneDistance( frustum[i] ) >= LIGHT_CLIP_EPSILON ) { + frontBits |= 1 << ( i + 6 ); + } + } + + // if the surface is not completely inside the light frustum + if ( frontBits == ( ( ( 1 << 6 ) - 1 ) ) << 6 ) { + // initialize point cull + for ( i = 0; i < tri->numVerts; i++ ) { + pointCull[i] = frontBits; + } + return; + } + + // duzenko: we have a generic SSE and AVX* versions of this routine, neither of them using temp buffers + SIMDProcessor->CullByFrustum2( tri->verts, tri->numVerts, frustum, pointCull, LIGHT_CLIP_EPSILON ); } /* @@ -807,218 +717,222 @@ If the frustum is just part of a point light, clipped planes don't need to be added. ================= */ -static void R_CreateShadowVolumeInFrustum( const idRenderEntityLocal *ent, - const srfTriangles_t *tri, - const idRenderLightLocal *light, - const idVec3 lightOrigin, - const idPlane frustum[6], - const idPlane &farPlane, - bool makeClippedPlanes ) { - int i; - int numTris; - unsigned short *pointCull; - int numCapIndexes; - int firstShadowIndex; - int firstShadowVert; - int cullBits; - - pointCull = (unsigned short *)_alloca16( tri->numVerts * sizeof( pointCull[0] ) ); - - // test the vertexes for inside the light frustum, which will allow - // us to completely cull away some triangles from consideration. - R_CalcPointCull( tri, frustum, pointCull ); - - // this may not be the first frustum added to the volume - firstShadowIndex = numShadowIndexes; - firstShadowVert = numShadowVerts; - - // decide which triangles front shadow volumes, clipping as needed - numClipSilEdges = 0; - numTris = tri->numIndexes / 3; - for ( i = 0 ; i < numTris ; i++ ) { - int i1, i2, i3; - - faceCastsShadow[i] = 0; // until shown otherwise - - // if it isn't facing the right way, don't add it - // to the shadow volume - if ( globalFacing[i] ) { - continue; - } - - i1 = tri->silIndexes[ i*3 + 0 ]; - i2 = tri->silIndexes[ i*3 + 1 ]; - i3 = tri->silIndexes[ i*3 + 2 ]; - - // if all the verts are off one side of the frustum, - // don't add any of them - if ( TRIANGLE_CULLED( i1, i2, i3 ) ) { - continue; - } - - // make sure the verts that are not on the negative sides - // of the frustum are copied over. - // we need to get the original verts even from clipped triangles - // so the edges reference correctly, because an edge may be unclipped - // even when a triangle is clipped. - if ( numShadowVerts + 6 > MAX_SHADOW_VERTS ) { - overflowed = true; - return; - } - - if ( !POINT_CULLED(i1) && remap[i1] == -1 ) { - remap[i1] = numShadowVerts; - shadowVerts[ numShadowVerts ].ToVec3() = tri->verts[i1].xyz; - numShadowVerts+=2; - } - if ( !POINT_CULLED(i2) && remap[i2] == -1 ) { - remap[i2] = numShadowVerts; - shadowVerts[ numShadowVerts ].ToVec3() = tri->verts[i2].xyz; - numShadowVerts+=2; - } - if ( !POINT_CULLED(i3) && remap[i3] == -1 ) { - remap[i3] = numShadowVerts; - shadowVerts[ numShadowVerts ].ToVec3() = tri->verts[i3].xyz; - numShadowVerts+=2; - } - - // clip the triangle if any points are on the negative sides - if ( TRIANGLE_CLIPPED( i1, i2, i3 ) ) { - cullBits = ( ( pointCull[ i1 ] ^ 0xfc0 ) | ( pointCull[ i2 ] ^ 0xfc0 ) | ( pointCull[ i3 ] ^ 0xfc0 ) ) >> 6; - // this will also define clip edges that will become - // silhouette planes - if ( R_ClipTriangleToLight( tri->verts[i1].xyz, tri->verts[i2].xyz, - tri->verts[i3].xyz, cullBits, frustum ) ) { - faceCastsShadow[i] = 1; - } - } else { - // instead of overflowing or drawing a streamer shadow, don't draw a shadow at all - if ( numShadowIndexes + 3 > MAX_SHADOW_INDEXES ) { - overflowed = true; - return; - } - if ( remap[i1] == -1 || remap[i2] == -1 || remap[i3] == -1 ) { - common->Error( "R_CreateShadowVolumeInFrustum: bad remap[]" ); - } - shadowIndexes[numShadowIndexes++] = remap[i3]; - shadowIndexes[numShadowIndexes++] = remap[i2]; - shadowIndexes[numShadowIndexes++] = remap[i1]; - faceCastsShadow[i] = 1; - } - } - - // add indexes for the back caps, which will just be reversals of the - // front caps using the back vertexes - numCapIndexes = numShadowIndexes - firstShadowIndex; - - // if no faces have been defined for the shadow volume, - // there won't be anything at all - if ( numCapIndexes == 0 ) { - return; - } - - //--------------- off-line processing ------------------ - - // if we are running from dmap, perform the (very) expensive shadow optimizations - // to remove internal sil edges and optimize the caps - if ( callOptimizer ) { - optimizedShadow_t opt; - - // project all of the vertexes to the shadow plane, generating - // an equal number of back vertexes -// R_ProjectPointsToFarPlane( ent, light, farPlane, firstShadowVert, numShadowVerts ); - - opt = SuperOptimizeOccluders( shadowVerts, shadowIndexes + firstShadowIndex, numCapIndexes, farPlane, lightOrigin ); - - // pull off the non-optimized data - numShadowIndexes = firstShadowIndex; - numShadowVerts = firstShadowVert; - - // add the optimized data - if ( numShadowIndexes + opt.totalIndexes > MAX_SHADOW_INDEXES - || numShadowVerts + opt.numVerts > MAX_SHADOW_VERTS ) { - overflowed = true; - common->Printf( "WARNING: overflowed MAX_SHADOW tables, shadow discarded\n" ); - Mem_Free( opt.verts ); - Mem_Free( opt.indexes ); - return; - } - - for ( i = 0 ; i < opt.numVerts ; i++ ) { - shadowVerts[numShadowVerts+i][0] = opt.verts[i][0]; - shadowVerts[numShadowVerts+i][1] = opt.verts[i][1]; - shadowVerts[numShadowVerts+i][2] = opt.verts[i][2]; - shadowVerts[numShadowVerts+i][3] = 1; - } - for ( i = 0 ; i < opt.totalIndexes ; i++ ) { - int index = opt.indexes[i]; - if ( index < 0 || index > opt.numVerts ) { - common->Error( "optimized shadow index out of range" ); - } - shadowIndexes[numShadowIndexes+i] = index + numShadowVerts; - } - - numShadowVerts += opt.numVerts; - numShadowIndexes += opt.totalIndexes; - - // note the index distribution so we can sort all the caps after all the sils - indexRef[indexFrustumNumber].frontCapStart = firstShadowIndex; - indexRef[indexFrustumNumber].rearCapStart = firstShadowIndex+opt.numFrontCapIndexes; - indexRef[indexFrustumNumber].silStart = firstShadowIndex+opt.numFrontCapIndexes+opt.numRearCapIndexes; - indexRef[indexFrustumNumber].end = numShadowIndexes; - indexFrustumNumber++; - - Mem_Free( opt.verts ); - Mem_Free( opt.indexes ); - return; - } - - //--------------- real-time processing ------------------ - - // the dangling edge "face" is never considered to cast a shadow, - // so any face with dangling edges that casts a shadow will have - // it's dangling sil edge trigger a sil plane - faceCastsShadow[numTris] = 0; - - // instead of overflowing or drawing a streamer shadow, don't draw a shadow at all - // if we ran out of space - if ( numShadowIndexes + numCapIndexes > MAX_SHADOW_INDEXES ) { - overflowed = true; - return; - } - for ( i = 0 ; i < numCapIndexes ; i += 3 ) { - shadowIndexes[ numShadowIndexes + i + 0 ] = shadowIndexes[ firstShadowIndex + i + 2 ] + 1; - shadowIndexes[ numShadowIndexes + i + 1 ] = shadowIndexes[ firstShadowIndex + i + 1 ] + 1; - shadowIndexes[ numShadowIndexes + i + 2 ] = shadowIndexes[ firstShadowIndex + i + 0 ] + 1; - } - numShadowIndexes += numCapIndexes; - -c_caps += numCapIndexes * 2; - -int preSilIndexes = numShadowIndexes; - - // if any triangles were clipped, we will have a list of edges - // on the frustum which must now become sil edges - if ( makeClippedPlanes ) { - R_AddClipSilEdges(); - } - - // any edges that are a transition between a shadowing and - // non-shadowing triangle will cast a silhouette edge - R_AddSilEdges( tri, pointCull, frustum ); - -c_sils += numShadowIndexes - preSilIndexes; - - // project all of the vertexes to the shadow plane, generating - // an equal number of back vertexes - R_ProjectPointsToFarPlane( ent, light, farPlane, firstShadowVert, numShadowVerts ); - - // note the index distribution so we can sort all the caps after all the sils - indexRef[indexFrustumNumber].frontCapStart = firstShadowIndex; - indexRef[indexFrustumNumber].rearCapStart = firstShadowIndex+numCapIndexes; - indexRef[indexFrustumNumber].silStart = preSilIndexes; - indexRef[indexFrustumNumber].end = numShadowIndexes; - indexFrustumNumber++; +static inline void R_CreateShadowVolumeInFrustum( stencilRef_t *st, + const idRenderEntityLocal *ent, + const srfTriangles_t *tri, + const idRenderLightLocal *light, + const idVec3 lightOrigin, + const idPlane frustum[6], + const idPlane &farPlane, + bool makeClippedPlanes ) { + int i; + int numTris; + unsigned short *pointCull; + int numCapIndexes; + int firstShadowIndex; + int firstShadowVert; + int cullBits; + + pointCull = ( unsigned short * )_alloca16( tri->numVerts * sizeof( pointCull[0] ) ); + + // test the vertexes for inside the light frustum, which will allow + // us to completely cull away some triangles from consideration. + R_CalcPointCull( st, tri, frustum, pointCull ); + + // this may not be the first frustum added to the volume + firstShadowIndex = st->numShadowIndexes; + firstShadowVert = st->numShadowVerts; + + // decide which triangles front shadow volumes, clipping as needed + st->numClipSilEdges = 0; + numTris = tri->numIndexes / 3; + + for ( i = 0 ; i < numTris ; i++ ) { + int i1, i2, i3; + + st->faceCastsShadow[i] = 0; // until shown otherwise + + // if it isn't facing the right way, don't add it + // to the shadow volume + if ( st->globalFacing[i] ) { + continue; + } + i1 = tri->silIndexes[ i * 3 + 0 ]; + i2 = tri->silIndexes[ i * 3 + 1 ]; + i3 = tri->silIndexes[ i * 3 + 2 ]; + + // if all the verts are off one side of the frustum, + // don't add any of them + if ( TRIANGLE_CULLED( i1, i2, i3 ) ) { + continue; + } + + // make sure the verts that are not on the negative sides + // of the frustum are copied over. + // we need to get the original verts even from clipped triangles + // so the edges reference correctly, because an edge may be unclipped + // even when a triangle is clipped. + if ( st->numShadowVerts + 6 > MAX_SHADOW_VERTS ) { + st->overflowed = true; + return; + } + + if ( !POINT_CULLED( i1 ) && st->remap[i1] == -1 ) { + st->remap[i1] = st->numShadowVerts; + st->shadowVerts[st->numShadowVerts ].ToVec3() = tri->verts[i1].xyz; + st->numShadowVerts += 2; + } + + if ( !POINT_CULLED( i2 ) && st->remap[i2] == -1 ) { + st->remap[i2] = st->numShadowVerts; + st->shadowVerts[st->numShadowVerts ].ToVec3() = tri->verts[i2].xyz; + st->numShadowVerts += 2; + } + + if ( !POINT_CULLED( i3 ) && st->remap[i3] == -1 ) { + st->remap[i3] = st->numShadowVerts; + st->shadowVerts[st->numShadowVerts ].ToVec3() = tri->verts[i3].xyz; + st->numShadowVerts += 2; + } + + // clip the triangle if any points are on the negative sides + if ( TRIANGLE_CLIPPED( i1, i2, i3 ) ) { + cullBits = ( ( pointCull[ i1 ] ^ 0xfc0 ) | ( pointCull[ i2 ] ^ 0xfc0 ) | ( pointCull[ i3 ] ^ 0xfc0 ) ) >> 6; + + // this will also define clip edges that will become + // silhouette planes + if ( R_ClipTriangleToLight( st, tri->verts[i1].xyz, tri->verts[i2].xyz, + tri->verts[i3].xyz, cullBits, frustum ) ) { + st->faceCastsShadow[i] = 1; + } + } else { + // instead of overflowing or drawing a streamer shadow, don't draw a shadow at all + if ( st->numShadowIndexes + 3 > MAX_SHADOW_INDEXES ) { + st->overflowed = true; + return; + } + + if ( st->remap[i1] == -1 || st->remap[i2] == -1 || st->remap[i3] == -1 ) { + common->Error( "R_CreateShadowVolumeInFrustum: bad remap[]" ); + } + st->shadowIndexes[st->numShadowIndexes++] = st->remap[i3]; + st->shadowIndexes[st->numShadowIndexes++] = st->remap[i2]; + st->shadowIndexes[st->numShadowIndexes++] = st->remap[i1]; + st->faceCastsShadow[i] = 1; + } + } + + // add indexes for the back caps, which will just be reversals of the + // front caps using the back vertexes + numCapIndexes = st->numShadowIndexes - firstShadowIndex; + + // if no faces have been defined for the shadow volume, + // there won't be anything at all + if ( numCapIndexes == 0 ) { + return; + } + + //--------------- off-line processing ------------------ + + // if we are running from dmap, perform the (very) expensive shadow optimizations + // to remove internal sil edges and optimize the caps + if ( st->callOptimizer ) { + optimizedShadow_t opt; + + // project all of the vertexes to the shadow plane, generating + // an equal number of back vertexes + opt = SuperOptimizeOccluders( st->shadowVerts, st->shadowIndexes + firstShadowIndex, numCapIndexes, farPlane, lightOrigin ); + + // pull off the non-optimized data + st->numShadowIndexes = firstShadowIndex; + st->numShadowVerts = firstShadowVert; + + // add the optimized data + if ( st->numShadowIndexes + opt.totalIndexes > MAX_SHADOW_INDEXES || st->numShadowVerts + opt.numVerts > MAX_SHADOW_VERTS ) { + st->overflowed = true; + common->Printf( "WARNING: overflowed MAX_SHADOW tables, shadow discarded\n" ); + Mem_Free( opt.verts ); + Mem_Free( opt.indexes ); + return; + } + + for ( i = 0 ; i < opt.numVerts ; i++ ) { + st->shadowVerts[st->numShadowVerts + i][0] = opt.verts[i][0]; + st->shadowVerts[st->numShadowVerts + i][1] = opt.verts[i][1]; + st->shadowVerts[st->numShadowVerts + i][2] = opt.verts[i][2]; + st->shadowVerts[st->numShadowVerts + i][3] = 1; + } + + for ( i = 0 ; i < opt.totalIndexes ; i++ ) { + int index = opt.indexes[i]; + + if ( index < 0 || index > opt.numVerts ) { + common->Error( "optimized shadow index out of range" ); + } + st->shadowIndexes[st->numShadowIndexes + i] = index + st->numShadowVerts; + } + st->numShadowVerts += opt.numVerts; + st->numShadowIndexes += opt.totalIndexes; + + // note the index distribution so we can sort all the caps after all the sils + st->indexRef[st->indexFrustumNumber].frontCapStart = firstShadowIndex; + st->indexRef[st->indexFrustumNumber].rearCapStart = firstShadowIndex + opt.numFrontCapIndexes; + st->indexRef[st->indexFrustumNumber].silStart = firstShadowIndex + opt.numFrontCapIndexes + opt.numRearCapIndexes; + st->indexRef[st->indexFrustumNumber].end = st->numShadowIndexes; + st->indexFrustumNumber++; + + Mem_Free( opt.verts ); + Mem_Free( opt.indexes ); + return; + } + + //--------------- real-time processing ------------------ + + // the dangling edge "face" is never considered to cast a shadow, + // so any face with dangling edges that casts a shadow will have + // it's dangling sil edge trigger a sil plane + st->faceCastsShadow[numTris] = 0; + + // instead of overflowing or drawing a streamer shadow, don't draw a shadow at all + // if we ran out of space + if ( st->numShadowIndexes + numCapIndexes > MAX_SHADOW_INDEXES ) { + st->overflowed = true; + return; + } + + for ( i = 0 ; i < numCapIndexes ; i += 3 ) { + st->shadowIndexes[st->numShadowIndexes + i + 0 ] = st->shadowIndexes[ firstShadowIndex + i + 2 ] + 1; + st->shadowIndexes[st->numShadowIndexes + i + 1 ] = st->shadowIndexes[ firstShadowIndex + i + 1 ] + 1; + st->shadowIndexes[st->numShadowIndexes + i + 2 ] = st->shadowIndexes[ firstShadowIndex + i + 0 ] + 1; + } + st->numShadowIndexes += numCapIndexes; + + c_caps += numCapIndexes * 2; + + int preSilIndexes = st->numShadowIndexes; + + // if any triangles were clipped, we will have a list of edges + // on the frustum which must now become sil edges + if ( makeClippedPlanes ) { + R_AddClipSilEdges( st ); + } + + // any edges that are a transition between a shadowing and + // non-shadowing triangle will cast a silhouette edge + R_AddSilEdges( st, tri, pointCull, frustum ); + + c_sils += st->numShadowIndexes - preSilIndexes; + + // project all of the vertexes to the shadow plane, generating + // an equal number of back vertexes + R_ProjectPointsToFarPlane( st, ent, light, farPlane, firstShadowVert, st->numShadowVerts ); + + // note the index distribution so we can sort all the caps after all the sils + st->indexRef[st->indexFrustumNumber].frontCapStart = firstShadowIndex; + st->indexRef[st->indexFrustumNumber].rearCapStart = firstShadowIndex + numCapIndexes; + st->indexRef[st->indexFrustumNumber].silStart = preSilIndexes; + st->indexRef[st->indexFrustumNumber].end = st->numShadowIndexes; + st->indexFrustumNumber++; } /* @@ -1029,162 +943,127 @@ Called at definition derivation time =================== */ void R_MakeShadowFrustums( idRenderLightLocal *light ) { - int i, j; - - if ( light->parms.pointLight ) { -#if 0 - idVec3 adjustedRadius; - - // increase the light radius to cover any origin offsets. - // this will cause some shadows to extend out of the exact light - // volume, but is simpler than adjusting all the frustums - adjustedRadius[0] = light->parms.lightRadius[0] + idMath::Fabs( light->parms.lightCenter[0] ); - adjustedRadius[1] = light->parms.lightRadius[1] + idMath::Fabs( light->parms.lightCenter[1] ); - adjustedRadius[2] = light->parms.lightRadius[2] + idMath::Fabs( light->parms.lightCenter[2] ); - - light->numShadowFrustums = 0; - // a point light has to project against six planes - for ( i = 0 ; i < 6 ; i++ ) { - shadowFrustum_t *frust = &light->shadowFrustums[ light->numShadowFrustums ]; - - frust->numPlanes = 6; - frust->makeClippedPlanes = false; - for ( j = 0 ; j < 6 ; j++ ) { - idPlane &plane = frust->planes[j]; - plane[0] = pointLightFrustums[i][j][0] / adjustedRadius[0]; - plane[1] = pointLightFrustums[i][j][1] / adjustedRadius[1]; - plane[2] = pointLightFrustums[i][j][2] / adjustedRadius[2]; - plane.Normalize(); - plane[3] = -( plane.Normal() * light->globalLightOrigin ); - if ( j == 5 ) { - plane[3] += adjustedRadius[i>>1]; - } - } - - light->numShadowFrustums++; - } -#else - // exact projection,taking into account asymetric frustums when - // globalLightOrigin isn't centered - - static int faceCorners[6][4] = { - { 7, 5, 1, 3 }, // positive X side - { 4, 6, 2, 0 }, // negative X side - { 6, 7, 3, 2 }, // positive Y side - { 5, 4, 0, 1 }, // negative Y side - { 6, 4, 5, 7 }, // positive Z side - { 3, 1, 0, 2 } // negative Z side - }; - static int faceEdgeAdjacent[6][4] = { - { 4, 4, 2, 2 }, // positive X side - { 7, 7, 1, 1 }, // negative X side - { 5, 5, 0, 0 }, // positive Y side - { 6, 6, 3, 3 }, // negative Y side - { 0, 0, 3, 3 }, // positive Z side - { 5, 5, 6, 6 } // negative Z side - }; - - bool centerOutside = false; - - // if the light center of projection is outside the light bounds, - // we will need to build the planes a little differently - if ( fabs( light->parms.lightCenter[0] ) > light->parms.lightRadius[0] - || fabs( light->parms.lightCenter[1] ) > light->parms.lightRadius[1] - || fabs( light->parms.lightCenter[2] ) > light->parms.lightRadius[2] ) { - centerOutside = true; - } - - // make the corners - idVec3 corners[8]; - - for ( i = 0 ; i < 8 ; i++ ) { - idVec3 temp; - for ( j = 0 ; j < 3 ; j++ ) { - if ( i & ( 1 << j ) ) { - temp[j] = light->parms.lightRadius[j]; - } else { - temp[j] = -light->parms.lightRadius[j]; - } - } - - // transform to global space - corners[i] = light->parms.origin + light->parms.axis * temp; - } - - light->numShadowFrustums = 0; - for ( int side = 0 ; side < 6 ; side++ ) { - shadowFrustum_t *frust = &light->shadowFrustums[ light->numShadowFrustums ]; - idVec3 &p1 = corners[faceCorners[side][0]]; - idVec3 &p2 = corners[faceCorners[side][1]]; - idVec3 &p3 = corners[faceCorners[side][2]]; - idPlane backPlane; - - // plane will have positive side inward - backPlane.FromPoints( p1, p2, p3 ); - - // if center of projection is on the wrong side, skip - float d = backPlane.Distance( light->globalLightOrigin ); - if ( d < 0 ) { - continue; - } - - frust->numPlanes = 6; - frust->planes[5] = backPlane; - frust->planes[4] = backPlane; // we don't really need the extra plane - - // make planes with positive side facing inwards in light local coordinates - for ( int edge = 0 ; edge < 4 ; edge++ ) { - idVec3 &p1 = corners[faceCorners[side][edge]]; - idVec3 &p2 = corners[faceCorners[side][(edge+1)&3]]; - - // create a plane that goes through the center of projection - frust->planes[edge].FromPoints( p2, p1, light->globalLightOrigin ); - - // see if we should use an adjacent plane instead - if ( centerOutside ) { - idVec3 &p3 = corners[faceEdgeAdjacent[side][edge]]; - idPlane sidePlane; - - sidePlane.FromPoints( p2, p1, p3 ); - d = sidePlane.Distance( light->globalLightOrigin ); - if ( d < 0 ) { - // use this plane instead of the edged plane - frust->planes[edge] = sidePlane; - } - // we can't guarantee a neighbor, so add sill planes at edge - light->shadowFrustums[ light->numShadowFrustums ].makeClippedPlanes = true; - } - } - light->numShadowFrustums++; - } - -#endif - return; - } - - // projected light - - light->numShadowFrustums = 1; - shadowFrustum_t *frust = &light->shadowFrustums[ 0 ]; - - // flip and transform the frustum planes so the positive side faces - // inward in local coordinates - - // it is important to clip against even the near clip plane, because - // many projected lights that are faking area lights will have their - // origin behind solid surfaces. - for ( i = 0 ; i < 6 ; i++ ) { - idPlane &plane = frust->planes[i]; - - plane.SetNormal( -light->frustum[i].Normal() ); - plane.SetDist( -light->frustum[i].Dist() ); - } - - frust->numPlanes = 6; - - frust->makeClippedPlanes = true; - // projected lights don't have shared frustums, so any clipped edges - // right on the planes must have a sil plane created for them + int i, j; + + if ( light->parms.pointLight ) { + // exact projection,taking into account asymetric frustums when + // globalLightOrigin isn't centered + static int faceCorners[6][4] = { + { 7, 5, 1, 3 }, // positive X side + { 4, 6, 2, 0 }, // negative X side + { 6, 7, 3, 2 }, // positive Y side + { 5, 4, 0, 1 }, // negative Y side + { 6, 4, 5, 7 }, // positive Z side + { 3, 1, 0, 2 } // negative Z side + }; + + static int faceEdgeAdjacent[6][4] = { + { 4, 4, 2, 2 }, // positive X side + { 7, 7, 1, 1 }, // negative X side + { 5, 5, 0, 0 }, // positive Y side + { 6, 6, 3, 3 }, // negative Y side + { 0, 0, 3, 3 }, // positive Z side + { 5, 5, 6, 6 } // negative Z side + }; + + bool centerOutside = false; + + // if the light center of projection is outside the light bounds, + // we will need to build the planes a little differently + if ( fabs( light->parms.lightCenter[0] ) > light->parms.lightRadius[0] || + fabs( light->parms.lightCenter[1] ) > light->parms.lightRadius[1] || + fabs( light->parms.lightCenter[2] ) > light->parms.lightRadius[2] ) { + centerOutside = true; + } + + // make the corners + idVec3 corners[8]; + for ( i = 0 ; i < 8 ; i++ ) { + idVec3 temp; + + for ( j = 0 ; j < 3 ; j++ ) { + if ( i & ( 1 << j ) ) { + temp[j] = light->parms.lightRadius[j]; + } else { + temp[j] = -light->parms.lightRadius[j]; + } + } + + // transform to global space + corners[i] = light->parms.origin + light->parms.axis * temp; + } + light->numShadowFrustums = 0; + + for ( int side = 0 ; side < 6 ; side++ ) { + shadowFrustum_t *frust = &light->shadowFrustums[ light->numShadowFrustums ]; + idVec3 &p1 = corners[faceCorners[side][0]]; + idVec3 &p2 = corners[faceCorners[side][1]]; + idVec3 &p3 = corners[faceCorners[side][2]]; + idPlane backPlane; + + // plane will have positive side inward + backPlane.FromPoints( p1, p2, p3 ); + + // if center of projection is on the wrong side, skip + float d = backPlane.Distance( light->globalLightOrigin ); + if ( d < 0 ) { + continue; + } + frust->numPlanes = 6; + frust->planes[5] = backPlane; + frust->planes[4] = backPlane; // we don't really need the extra plane + + // make planes with positive side facing inwards in light local coordinates + for ( int edge = 0 ; edge < 4 ; edge++ ) { + idVec3 &p1 = corners[faceCorners[side][edge]]; + idVec3 &p2 = corners[faceCorners[side][( edge + 1 ) & 3]]; + + // create a plane that goes through the center of projection + frust->planes[edge].FromPoints( p2, p1, light->globalLightOrigin ); + + // see if we should use an adjacent plane instead + if ( centerOutside ) { + idVec3 &p3 = corners[faceEdgeAdjacent[side][edge]]; + idPlane sidePlane; + + sidePlane.FromPoints( p2, p1, p3 ); + d = sidePlane.Distance( light->globalLightOrigin ); + + if ( d < 0 ) { + // use this plane instead of the edged plane + frust->planes[edge] = sidePlane; + } + + // we can't guarantee a neighbor, so add sill planes at edge + light->shadowFrustums[ light->numShadowFrustums ].makeClippedPlanes = true; + } + } + light->numShadowFrustums++; + } + return; + } + + // projected light + light->numShadowFrustums = 1; + shadowFrustum_t *frust = &light->shadowFrustums[ 0 ]; + + // flip and transform the frustum planes so the positive side faces + // inward in local coordinates + + // it is important to clip against even the near clip plane, because + // many projected lights that are faking area lights will have their + // origin behind solid surfaces. + for ( i = 0 ; i < 6 ; i++ ) { + idPlane &plane = frust->planes[i]; + + plane.SetNormal( -light->frustum[i].Normal() ); + plane.SetDist( -light->frustum[i].Dist() ); + } + frust->numPlanes = 6; + frust->makeClippedPlanes = true; + + // projected lights don't have shared frustums, so any clipped edges + // right on the planes must have a sil plane created for them } /* @@ -1214,181 +1093,187 @@ generated by the triangle irregardless of if it actually was a sil edge. ================= */ srfTriangles_t *R_CreateShadowVolume( const idRenderEntityLocal *ent, - const srfTriangles_t *tri, const idRenderLightLocal *light, - shadowGen_t optimize, srfCullInfo_t &cullInfo ) { - int i, j; - idVec3 lightOrigin; - srfTriangles_t *newTri; - int capPlaneBits; - - if ( !r_shadows.GetBool() ) { - return NULL; - } - - if ( tri->numSilEdges == 0 || tri->numIndexes == 0 || tri->numVerts == 0 ) { - return NULL; - } - - if ( tri->numIndexes < 0 ) { - common->Error( "R_CreateShadowVolume: tri->numIndexes = %i", tri->numIndexes ); - } - - if ( tri->numVerts < 0 ) { - common->Error( "R_CreateShadowVolume: tri->numVerts = %i", tri->numVerts ); - } - - tr.pc.c_createShadowVolumes++; - - // use the fast infinite projection in dynamic situations, which - // trades somewhat more overdraw and no cap optimizations for - // a very simple generation process - if ( optimize == SG_DYNAMIC && r_useTurboShadow.GetBool() ) { - if ( tr.backEndRendererHasVertexPrograms && r_useShadowVertexProgram.GetBool() ) { - return R_CreateVertexProgramTurboShadowVolume( ent, tri, light, cullInfo ); - } else { - return R_CreateTurboShadowVolume( ent, tri, light, cullInfo ); - } - } - - R_CalcInteractionFacing( ent, tri, light, cullInfo ); - - int numFaces = tri->numIndexes / 3; - int allFront = 1; - for ( i = 0; i < numFaces && allFront; i++ ) { - allFront &= cullInfo.facing[i]; - } - if ( allFront ) { - // if no faces are the right direction, don't make a shadow at all - return NULL; - } - - // clear the shadow volume - numShadowIndexes = 0; - numShadowVerts = 0; - overflowed = false; - indexFrustumNumber = 0; - capPlaneBits = 0; - callOptimizer = (optimize == SG_OFFLINE); - - // the facing information will be the same for all six projections - // from a point light, as well as for any directed lights - globalFacing = cullInfo.facing; - faceCastsShadow = (byte *)_alloca16( tri->numIndexes / 3 + 1 ); // + 1 for fake dangling edge face - remap = (int *)_alloca16( tri->numVerts * sizeof( remap[0] ) ); - - R_GlobalPointToLocal( ent->modelMatrix, light->globalLightOrigin, lightOrigin ); - - // run through all the shadow frustums, which is one for a projected light, - // and usually six for a point light, but point lights with centers outside - // the box may have less - for ( int frustumNum = 0 ; frustumNum < light->numShadowFrustums ; frustumNum++ ) { - const shadowFrustum_t *frust = &light->shadowFrustums[frustumNum]; - ALIGN16( idPlane frustum[6] ); - - // transform the planes into entity space - // we could share and reverse some of the planes between frustums for a minor - // speed increase - - // the cull test is redundant for a single shadow frustum projected light, because - // the surface has already been checked against the main light frustums - - for ( j = 0 ; j < frust->numPlanes ; j++ ) { - R_GlobalPlaneToLocal( ent->modelMatrix, frust->planes[j], frustum[j] ); - - // try to cull the entire surface against this frustum - float d = tri->bounds.PlaneDistance( frustum[j] ); - if ( d < -LIGHT_CLIP_EPSILON ) { - break; - } - } - if ( j != frust->numPlanes ) { - continue; - } - // we need to check all the triangles - int oldFrustumNumber = indexFrustumNumber; - - R_CreateShadowVolumeInFrustum( ent, tri, light, lightOrigin, frustum, frustum[5], frust->makeClippedPlanes ); - - // if we couldn't make a complete shadow volume, it is better to - // not draw one at all, avoiding streamer problems - if ( overflowed ) { - return NULL; - } - - if ( indexFrustumNumber != oldFrustumNumber ) { - // note that we have caps projected against this frustum, - // which may allow us to skip drawing the caps if all projected - // planes face away from the viewer and the viewer is outside the light volume - capPlaneBits |= 1< MAX_SHADOW_VERTS || numShadowIndexes > MAX_SHADOW_INDEXES ) { - common->FatalError( "Shadow volume exceeded allocation" ); - } - - // allocate a new surface for the shadow volume - newTri = R_AllocStaticTriSurf(); - - // we might consider setting this, but it would only help for - // large lights that are partially off screen - newTri->bounds.Clear(); - - // copy off the verts and indexes - newTri->numVerts = numShadowVerts; - newTri->numIndexes = numShadowIndexes; - - // the shadow verts will go into a main memory buffer as well as a vertex - // cache buffer, so they can be copied back if they are purged - R_AllocStaticTriSurfShadowVerts( newTri, newTri->numVerts ); - SIMDProcessor->Memcpy( newTri->shadowVertexes, shadowVerts, newTri->numVerts * sizeof( newTri->shadowVertexes[0] ) ); - - R_AllocStaticTriSurfIndexes( newTri, newTri->numIndexes ); - - if ( 1 /* sortCapIndexes */ ) { - newTri->shadowCapPlaneBits = capPlaneBits; - - // copy the sil indexes first - newTri->numShadowIndexesNoCaps = 0; - for ( i = 0 ; i < indexFrustumNumber ; i++ ) { - int c = indexRef[i].end - indexRef[i].silStart; - SIMDProcessor->Memcpy( newTri->indexes+newTri->numShadowIndexesNoCaps, - shadowIndexes+indexRef[i].silStart, c * sizeof( newTri->indexes[0] ) ); - newTri->numShadowIndexesNoCaps += c; - } - // copy rear cap indexes next - newTri->numShadowIndexesNoFrontCaps = newTri->numShadowIndexesNoCaps; - for ( i = 0 ; i < indexFrustumNumber ; i++ ) { - int c = indexRef[i].silStart - indexRef[i].rearCapStart; - SIMDProcessor->Memcpy( newTri->indexes+newTri->numShadowIndexesNoFrontCaps, - shadowIndexes+indexRef[i].rearCapStart, c * sizeof( newTri->indexes[0] ) ); - newTri->numShadowIndexesNoFrontCaps += c; - } - // copy front cap indexes last - newTri->numIndexes = newTri->numShadowIndexesNoFrontCaps; - for ( i = 0 ; i < indexFrustumNumber ; i++ ) { - int c = indexRef[i].rearCapStart - indexRef[i].frontCapStart; - SIMDProcessor->Memcpy( newTri->indexes+newTri->numIndexes, - shadowIndexes+indexRef[i].frontCapStart, c * sizeof( newTri->indexes[0] ) ); - newTri->numIndexes += c; - } - - } else { - newTri->shadowCapPlaneBits = 63; // we don't have optimized index lists - SIMDProcessor->Memcpy( newTri->indexes, shadowIndexes, newTri->numIndexes * sizeof( newTri->indexes[0] ) ); - } - - if ( optimize == SG_OFFLINE ) { - CleanupOptimizedShadowTris( newTri ); - } - - return newTri; + const srfTriangles_t *tri, const idRenderLightLocal *light, + shadowGen_t optimize, srfCullInfo_t &cullInfo ) { + int i, j; + idVec3 lightOrigin; + srfTriangles_t *newTri; + int capPlaneBits; + + if ( !r_shadows.GetBool() ) { + return NULL; + } + + if ( tri->numSilEdges == 0 || tri->numIndexes == 0 || tri->numVerts == 0 ) { + return NULL; + } + + if ( tri->numIndexes < 0 ) { + common->Error( "R_CreateShadowVolume: tri->numIndexes = %i", tri->numIndexes ); + } + + if ( tri->numVerts < 0 ) { + common->Error( "R_CreateShadowVolume: tri->numVerts = %i", tri->numVerts ); + } + tr.pc.c_createShadowVolumes++; + + // use the fast infinite projection in dynamic situations, which + // trades somewhat more overdraw and no cap optimizations for + // a very simple generation process + if ( optimize == SG_DYNAMIC && r_useTurboShadow.GetBool() ) { + if ( tr.backEndRendererHasVertexPrograms && r_useShadowVertexProgram.GetBool() ) { + return R_CreateVertexProgramTurboShadowVolume( ent, tri, light, cullInfo ); + } else { + return R_CreateTurboShadowVolume( ent, tri, light, cullInfo ); + } + } + R_CalcInteractionFacing( ent, tri, light, cullInfo ); + + int numFaces = tri->numIndexes / 3; + int allFront = 1; + for ( i = 0; i < numFaces && allFront; i++ ) { + allFront &= cullInfo.facing[i]; + } + + if ( allFront ) { + // if no faces are the right direction, don't make a shadow at all + return NULL; + } + stencilRef_t *st = ( stencilRef_t * )_alloca( sizeof( stencilRef_t ) ); + assert( st != NULL ); + + // clear the shadow volume + st->numShadowIndexes = 0; + st->numShadowVerts = 0; + st->overflowed = false; + st->indexFrustumNumber = 0; + capPlaneBits = 0; + st->callOptimizer = ( optimize == SG_OFFLINE ); + + // the facing information will be the same for all six projections + // from a point light, as well as for any directed lights + st->globalFacing = cullInfo.facing; + st->faceCastsShadow = ( byte * )_alloca16( tri->numIndexes / 3 + 1 ); // + 1 for fake dangling edge face + st->remap = ( int * )_alloca16( tri->numVerts * sizeof( st->remap[0] ) ); + + R_GlobalPointToLocal( ent->modelMatrix, light->globalLightOrigin, lightOrigin ); + + // run through all the shadow frustums, which is one for a projected light, + // and usually six for a point light, but point lights with centers outside + // the box may have less + for ( int frustumNum = 0 ; frustumNum < light->numShadowFrustums ; frustumNum++ ) { + const shadowFrustum_t *frust = &light->shadowFrustums[frustumNum]; + ALIGN16( idPlane frustum[6] ); + + // transform the planes into entity space + // we could share and reverse some of the planes between frustums for a minor + // speed increase + + // the cull test is redundant for a single shadow frustum projected light, because + // the surface has already been checked against the main light frustums + for ( j = 0 ; j < frust->numPlanes ; j++ ) { + R_GlobalPlaneToLocal( ent->modelMatrix, frust->planes[j], frustum[j] ); + + // try to cull the entire surface against this frustum + float d = tri->bounds.PlaneDistance( frustum[j] ); + if ( d < -LIGHT_CLIP_EPSILON ) { + break; + } + } + + if ( j != frust->numPlanes ) { + continue; + } + + // we need to check all the triangles + int oldFrustumNumber = st->indexFrustumNumber; + + R_CreateShadowVolumeInFrustum( st, ent, tri, light, lightOrigin, frustum, frustum[5], frust->makeClippedPlanes ); + + // if we couldn't make a complete shadow volume, it is better to + // not draw one at all, avoiding streamer problems + if ( st->overflowed ) { + return NULL; + } + + if ( st->indexFrustumNumber != oldFrustumNumber ) { + // note that we have caps projected against this frustum, + // which may allow us to skip drawing the caps if all projected + // planes face away from the viewer and the viewer is outside the light volume + capPlaneBits |= ( 1 << frustumNum ); + } + } + + // if no faces have been defined for the shadow volume, + // there won't be anything at all + if ( st->numShadowIndexes == 0 ) { + return NULL; + } + + // this should have been prevented by the overflowed flag, so if it ever happens, + // it is a code error + if ( st->numShadowVerts > MAX_SHADOW_VERTS || st->numShadowIndexes > MAX_SHADOW_INDEXES ) { + common->FatalError( "Shadow volume exceeded allocation" ); + } + + // allocate a new surface for the shadow volume + newTri = R_AllocStaticTriSurf(); + + // we might consider setting this, but it would only help for + // large lights that are partially off screen + newTri->bounds.Clear(); + + // copy off the verts and indexes + newTri->numVerts = st->numShadowVerts; + newTri->numIndexes = st->numShadowIndexes; + + // the shadow verts will go into a main memory buffer as well as a vertex + // cache buffer, so they can be copied back if they are purged + R_AllocStaticTriSurfShadowVerts( newTri, newTri->numVerts ); + SIMDProcessor->Memcpy( newTri->shadowVertexes, st->shadowVerts, newTri->numVerts * sizeof( newTri->shadowVertexes[0] ) ); + + R_AllocStaticTriSurfIndexes( newTri, newTri->numIndexes ); + + if ( 1 /* sortCapIndexes */ ) { + newTri->shadowCapPlaneBits = capPlaneBits; + + // copy the sil indexes first + newTri->numShadowIndexesNoCaps = 0; + + for ( i = 0 ; i < st->indexFrustumNumber ; i++ ) { + int c = st->indexRef[i].end - st->indexRef[i].silStart; + SIMDProcessor->Memcpy( newTri->indexes + newTri->numShadowIndexesNoCaps, + st->shadowIndexes + st->indexRef[i].silStart, c * sizeof( newTri->indexes[0] ) ); + newTri->numShadowIndexesNoCaps += c; + } + + // copy rear cap indexes next + newTri->numShadowIndexesNoFrontCaps = newTri->numShadowIndexesNoCaps; + + for ( i = 0 ; i < st->indexFrustumNumber ; i++ ) { + int c = st->indexRef[i].silStart - st->indexRef[i].rearCapStart; + SIMDProcessor->Memcpy( newTri->indexes + newTri->numShadowIndexesNoFrontCaps, + st->shadowIndexes + st->indexRef[i].rearCapStart, c * sizeof( newTri->indexes[0] ) ); + newTri->numShadowIndexesNoFrontCaps += c; + } + + // copy front cap indexes last + newTri->numIndexes = newTri->numShadowIndexesNoFrontCaps; + + for ( i = 0 ; i < st->indexFrustumNumber ; i++ ) { + int c = st->indexRef[i].rearCapStart - st->indexRef[i].frontCapStart; + SIMDProcessor->Memcpy( newTri->indexes + newTri->numIndexes, + st->shadowIndexes + st->indexRef[i].frontCapStart, c * sizeof( newTri->indexes[0] ) ); + newTri->numIndexes += c; + } + } else { + newTri->shadowCapPlaneBits = 63; // we don't have optimized index lists + SIMDProcessor->Memcpy( newTri->indexes, st->shadowIndexes, + newTri->numIndexes * sizeof( newTri->indexes[0] ) ); + } + + if ( optimize == SG_OFFLINE ) { + CleanupOptimizedShadowTris( newTri ); + } + return newTri; } diff --git a/neo/renderer/tr_trisurf.cpp b/neo/renderer/tr_trisurf.cpp index 28726081a..2080c094e 100644 --- a/neo/renderer/tr_trisurf.cpp +++ b/neo/renderer/tr_trisurf.cpp @@ -790,9 +790,7 @@ R_CreateDupVerts void R_CreateDupVerts( srfTriangles_t *tri ) { int i; - // DG: use Mem_MallocA() instead of _alloca16() to avoid stack overflows with big models - bool remapOnStack; - int *remap = (int *)Mem_MallocA( tri->numVerts * sizeof( remap[0] ), remapOnStack ); + int *remap = (int *) _alloca16( tri->numVerts * sizeof( remap[0] ) ); // initialize vertex remap in case there are unused verts for ( i = 0; i < tri->numVerts; i++ ) { @@ -805,9 +803,7 @@ void R_CreateDupVerts( srfTriangles_t *tri ) { } // create duplicate vertex index based on the vertex remap - bool tempDupVertsOnStack; - int *tempDupVerts = (int *)Mem_MallocA( tri->numVerts * 2 * sizeof( tempDupVerts[0] ), tempDupVertsOnStack ); - + int * tempDupVerts = (int *) _alloca16( tri->numVerts * 2 * sizeof( tempDupVerts[0] ) ); tri->numDupVerts = 0; for ( i = 0; i < tri->numVerts; i++ ) { if ( remap[i] != i ) { @@ -823,9 +819,6 @@ void R_CreateDupVerts( srfTriangles_t *tri ) { } else { tri->dupVerts = NULL; } - - Mem_FreeA( remap, remapOnStack ); - Mem_FreeA( tempDupVerts, tempDupVertsOnStack ); } /* @@ -1286,10 +1279,7 @@ static void R_DuplicateMirroredVertexes( srfTriangles_t *tri ) { int totalVerts; int numMirror; - // DG: use Mem_MallocA() instead of _alloca16() to avoid stack overflows with big models - bool tvertsOnStack; - tverts = (tangentVert_t *)Mem_MallocA( tri->numVerts * sizeof( *tverts ), tvertsOnStack ); - + tverts = (tangentVert_t *)_alloca16( tri->numVerts * sizeof( *tverts ) ); memset( tverts, 0, tri->numVerts * sizeof( *tverts ) ); // determine texture polarity of each surface @@ -1319,7 +1309,6 @@ static void R_DuplicateMirroredVertexes( srfTriangles_t *tri ) { // now create the new list if ( totalVerts == tri->numVerts ) { tri->mirroredVerts = NULL; - Mem_FreeA( tverts, tvertsOnStack ); return; } @@ -1355,8 +1344,6 @@ static void R_DuplicateMirroredVertexes( srfTriangles_t *tri ) { } tri->numVerts = totalVerts; - - Mem_FreeA( tverts, tvertsOnStack ); } /* @@ -1399,10 +1386,14 @@ void R_DeriveTangentsWithoutNormals( srfTriangles_t *tri ) { faceTangents_t *ft; idDrawVert *vert; - // DG: use Mem_MallocA() instead of _alloca16() to avoid stack overflows with big models + // DG: windows only has a 1MB stack and it could happen that we try to allocate >1MB here + // (in lost mission mod, game/le_hell map), causing a stack overflow + // to prevent that, use heap allocation if it's >600KB size_t allocaSize = sizeof(faceTangents[0]) * tri->numIndexes/3; - bool faceTangentsOnStack; - faceTangents = (faceTangents_t *)Mem_MallocA( allocaSize, faceTangentsOnStack ); + if(allocaSize < 600000) + faceTangents = (faceTangents_t *)_alloca16( allocaSize ); + else + faceTangents = (faceTangents_t *)Mem_Alloc16( allocaSize ); R_DeriveFaceTangents( tri, faceTangents ); @@ -1460,7 +1451,8 @@ void R_DeriveTangentsWithoutNormals( srfTriangles_t *tri ) { tri->tangentsCalculated = true; - Mem_FreeA( faceTangents, faceTangentsOnStack ); + if(allocaSize >= 600000) + Mem_Free16( faceTangents ); } static ID_INLINE void VectorNormalizeFast2( const idVec3 &v, idVec3 &out) { @@ -1693,12 +1685,8 @@ void R_DeriveTangents( srfTriangles_t *tri, bool allocFacePlanes ) { #if 1 - // ok, this is also true if they're not on the stack but from tri->facePlanes - // (either way, Mem_FreeA() mustn't free() them) - bool planesOnStack = true; if ( !planes ) { - // DG: use Mem_MallocA() instead of _alloca16() to avoid stack overflows with big models - planes = (idPlane *)Mem_MallocA( ( tri->numIndexes / 3 ) * sizeof( planes[0] ), planesOnStack ); + planes = (idPlane *)_alloca16( ( tri->numIndexes / 3 ) * sizeof( planes[0] ) ); } SIMDProcessor->DeriveTangents( planes, tri->verts, tri->numVerts, tri->indexes, tri->numIndexes ); @@ -1858,8 +1846,6 @@ void R_DeriveTangents( srfTriangles_t *tri, bool allocFacePlanes ) { tri->tangentsCalculated = true; tri->facePlanesCalculated = true; - - Mem_FreeA( planes, planesOnStack ); } /* diff --git a/neo/sys/cpu.cpp b/neo/sys/cpu.cpp index 6d52e4c39..654347d0b 100644 --- a/neo/sys/cpu.cpp +++ b/neo/sys/cpu.cpp @@ -17,7 +17,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . +along with Doom 3 Source Code. If not, see . In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. @@ -28,10 +28,23 @@ If you have questions concerning this license or the applicable additional terms #include +// mingw-w64 changed __cpuid to the same type as msvc located in intrinsics.h so we cannot use this one +// atleast not on windows since SDL includes intrin.h before it so it gets overridden +#if defined(__unix__) || defined(MACOS_X) || defined(__APPLE__) || defined(__AROS__) +#include +#endif + #ifdef D3_SDL3 - #include +#include +#include #else // SDL1.2 or SDL2 - #include +#include +#include +#endif + +// hack add missing instructions to SDL1.2 +#if SDL_VERSION_ATLEAST(2, 0, 0) +#define SDL_SUPPORTS_ABOVE_SSE2 #endif // MSVC header intrin.h uses strcmp and errors out when not set @@ -39,160 +52,232 @@ If you have questions concerning this license or the applicable additional terms #include "sys/platform.h" #include "framework/Common.h" - #include "sys/sys_public.h" -#ifdef NO_CPUID -#undef NO_CPUID -#endif +// cpu registers +#define _REG_EAX 0 +#define _REG_EBX 1 +#define _REG_ECX 2 +#define _REG_EDX 3 -#if defined(__GNUC__) - #if !defined(__i386__) && !defined(__x86_64__) - #define NO_CPUID - #endif -#elif defined(_MSC_VER) - #if !defined(_M_IX86) - #define NO_CPUID - #endif -#else -#error unsupported compiler +/* +================ +CPUid +================ +*/ +static inline void CPUid( int func, unsigned regs[4] ) { +// guessing here but i reckon most unixes use the same function from cpuid.h +#if defined(__unix__) || defined(MACOS_X) || defined(__APPLE__) || defined(__AROS__) + __cpuid( func, regs[_REG_EAX], regs[_REG_EBX], regs[_REG_ECX], regs[_REG_EDX] ); +#else /* msvc / mingw / clang */ + int values[4] = { 0, 0, 0, 0 }; + + __cpuid( values, func ); + + regs[_REG_EAX] = static_cast( values[0] ); + regs[_REG_EBX] = static_cast( values[1] ); + regs[_REG_ECX] = static_cast( values[2] ); + regs[_REG_EDX] = static_cast( values[3] ); #endif - -#ifdef NO_CPUID -void Sys_FPU_SetDAZ(bool enable) { } -void Sys_FPU_SetFTZ(bool enable) { -} -#else - -#if defined(__GNUC__) -static inline void CPUid(int index, int *a, int *b, int *c, int *d) { -#if __x86_64__ -# define REG_b "rbx" -# define REG_S "rsi" -#elif __i386__ -# define REG_b "ebx" -# define REG_S "esi" -#endif - *a = *b = *c = *d = 0; - - __asm__ volatile - ( "mov %%" REG_b ", %%" REG_S "\n\t" - "cpuid\n\t" - "xchg %%" REG_b ", %%" REG_S - : "=a" (*a), "=S" (*b), - "=c" (*c), "=d" (*d) - : "0" (index)); -} -#elif defined(_MSC_VER) -#include -static inline void CPUid(int index, int *a, int *b, int *c, int *d) { - int info[4] = { }; - - // VS2005 and up - __cpuid(info, index); - - *a = info[0]; - *b = info[1]; - *c = info[2]; - *d = info[3]; +/* +================ +IsAMD +================ +*/ +static bool IsAMD( void ) { + char pstring[16]; + char processorString[13]; + + // get name of processor + CPUid( 0, ( unsigned int * )pstring ); + processorString[0] = pstring[4]; + processorString[1] = pstring[5]; + processorString[2] = pstring[6]; + processorString[3] = pstring[7]; + processorString[4] = pstring[12]; + processorString[5] = pstring[13]; + processorString[6] = pstring[14]; + processorString[7] = pstring[15]; + processorString[8] = pstring[8]; + processorString[9] = pstring[9]; + processorString[10] = pstring[10]; + processorString[11] = pstring[11]; + processorString[12] = 0; + + if ( strcmp( processorString, "AuthenticAMD" ) == 0 ) { + return true; + } + return false; } -#else -#error unsupported compiler -#endif - -#define c_SSE3 (1 << 0) -#define d_FXSAVE (1 << 24) -static inline bool HasDAZ() { - int a, b, c, d; +// SDL 1.2 only supports up to SSE2 so we Add our own. +#ifndef SDL_SUPPORTS_ABOVE_SSE2 - CPUid(0, &a, &b, &c, &d); - if (a < 1) - return false; +/* +================ +SDL_HasSSE3 +================ +*/ +static inline bool SDL_HasSSE3( void ) { + unsigned regs[4] = { 0, 0, 0, 0 }; - CPUid(1, &a, &b, &c, &d); + // get CPU feature bits + CPUid( 1, regs ); - return (d & d_FXSAVE) == d_FXSAVE; + // bit 9 of ECX denotes SSE3 existence + if ( regs[_REG_ECX] & ( 1 << 0 ) ) { + return true; + } + return false; } -static inline bool HasSSE3() { - int a, b, c, d; - - CPUid(0, &a, &b, &c, &d); - if (a < 1) - return false; +/* +================ +SDL_HasSSE41 +================ +*/ +static inline bool SDL_HasSSE41( void ) { + unsigned regs[4] = { 0, 0, 0, 0 }; - CPUid(1, &a, &b, &c, &d); + // get CPU feature bits + CPUid( 1, regs ); - return (c & c_SSE3) == c_SSE3; + // bit 19 of ECX denotes SSE4.1 existence + if ( regs[_REG_ECX] & ( 1 << 19 ) ) { + return true; + } + return false; } -#define MXCSR_DAZ (1 << 6) -#define MXCSR_FTZ (1 << 15) - -#ifdef _MSC_VER -#define STREFLOP_FSTCW(cw) do { short tmp; __asm { fstcw tmp }; (cw) = tmp; } while (0) -#define STREFLOP_FLDCW(cw) do { short tmp = (cw); __asm { fclex }; __asm { fldcw tmp }; } while (0) -#define STREFLOP_STMXCSR(cw) do { int tmp; __asm { stmxcsr tmp }; (cw) = tmp; } while (0) -#define STREFLOP_LDMXCSR(cw) do { int tmp = (cw); __asm { ldmxcsr tmp }; } while (0) -#else -#define STREFLOP_FSTCW(cw) do { asm volatile ("fstcw %0" : "=m" (cw) : ); } while (0) -#define STREFLOP_FLDCW(cw) do { asm volatile ("fclex \n fldcw %0" : : "m" (cw)); } while (0) -#define STREFLOP_STMXCSR(cw) do { asm volatile ("stmxcsr %0" : "=m" (cw) : ); } while (0) -#define STREFLOP_LDMXCSR(cw) do { asm volatile ("ldmxcsr %0" : : "m" (cw) ); } while (0) +/* +================ +SDL_HasAVX +================ +*/ +static inline bool SDL_HasAVX( void ) { + unsigned regs[4] = { 0, 0, 0, 0 }; + + // get CPU feature bits + CPUid( 1, regs ); + + //check if CPU supports AVX instructions + bool cpuAVXSupport = ( regs[_REG_ECX] & ( 1 << 28 ) ) != 0; + + //check if xsave/xrstor instructions are enabled by OS for context switches + bool osUsesXsaveXrstor = ( regs[_REG_ECX] & ( 1 << 27 ) ) != 0; + + if ( cpuAVXSupport && osUsesXsaveXrstor ) { +#if defined(_MSC_VER) + uint64_t xcrFeatureMask = _xgetbv( _XCR_XFEATURE_ENABLED_MASK ); +#elif defined (__GNUC__) && (defined(__i386__) || defined (__x86_64__)) + // stgatilov: GCC did not have proper _xgetbv intrinsic until GCC 9 + // inline assembly taken from: https://gist.github.com/hi2p-perim/7855506 + int index = 0; //_XCR_XFEATURE_ENABLED_MASK + unsigned int eax, edx; + __asm__ __volatile__( + "xgetbv;" + : "=a"( eax ), "=d"( edx ) + : "c"( index ) + ); + uint64_t xcrFeatureMask = ( ( unsigned long long )edx << 32 ) | eax; #endif + //check if OS is configured to save/restore YMM registers on context switches + if ( ( xcrFeatureMask & 0x6 ) == 0x6 ) { + return true; + } + } + return false; +} -static void EnableMXCSRFlag(int flag, bool enable, const char *name) { - int sse_mode; +/* +================ +SDL_HasAVX2 +================ +*/ +static inline bool SDL_HasAVX2( void ) { + unsigned regs[4] = { 0, 0, 0, 0 }; - STREFLOP_STMXCSR(sse_mode); + //check that cpuid instruction supports function 7 + CPUid( 0, regs ); - if (enable && (sse_mode & flag) == flag) { - common->Printf("%s mode is already enabled\n", name); - return; - } + if ( regs[0] < 7 ) { + return false; + } - if (!enable && (sse_mode & flag) == 0) { - common->Printf("%s mode is already disabled\n", name); - return; - } + // get CPU feature bits + CPUid( 7, regs ); - if (enable) { - common->Printf("enabling %s mode\n", name); - sse_mode |= flag; - } else { - common->Printf("disabling %s mode\n", name); - sse_mode &= ~flag; - } + // check if CPU supports AVX2 instructions + bool cpuAVX2Support = ( regs[_REG_EBX] & ( 1 << 5 ) ) != 0; - STREFLOP_LDMXCSR(sse_mode); + if ( cpuAVX2Support && HasAVX() ) { + return true; + } + return false; } +#endif /* SDL_HAS_ABOVE_SSE2_INSTRUCTIONS */ + /* ================ -Sys_FPU_SetDAZ +SDL_HasFMA3 ================ */ -void Sys_FPU_SetDAZ(bool enable) { - if (!HasDAZ()) { - common->Printf("this CPU doesn't support Denormals-Are-Zero\n"); - return; - } +static inline bool SDL_HasFMA3( void ) { + unsigned regs[4] = { 0, 0, 0, 0 }; + + // get CPU feature bits + CPUid( 1, regs ); - EnableMXCSRFlag(MXCSR_DAZ, enable, "Denormals-Are-Zero"); + // bit 12 of ECX denotes FMA3 support + bool cpuFMA3Support = ( regs[_REG_ECX] & ( 1 << 12 ) ) != 0; + + // stgatilov: ensure that AVX2 is enabled too + // (also checks for OS support of AVX registers) + if ( cpuFMA3Support && SDL_HasAVX2() ) { + return true; + } + return false; } +// bitmasks for Denormals are zero and Flush to zero +#define MXCSR_DAZ (1 << 6) +#define MXCSR_FTZ (1 << 15) + /* ================ -Sys_FPU_SetFTZ +SDL_HasDAZ ================ */ -void Sys_FPU_SetFTZ(bool enable) { - EnableMXCSRFlag(MXCSR_FTZ, enable, "Flush-To-Zero"); -} +static inline bool SDL_HasDAZ( void ) { + ALIGN16( unsigned char FXSaveArea[512] ); + unsigned char *FXArea = FXSaveArea; + unsigned regs[4] = { 0, 0, 0, 0 }; + + // get CPU feature bits + CPUid( 1, regs ); + + // bit 24 of EDX denotes support for FXSAVE (possibly deprecated) + if ( !( regs[_REG_EDX] & ( 1 << 24 ) ) ) { + return false; + } + memset( FXArea, 0, sizeof( FXSaveArea ) ); + +// inline assembly not supported by msvc on 64 bit +#if defined(_MSC_VER) && defined(_M_X64) || \ + defined(__GNUC__) && (defined(__i386__) || defined (__x86_64__)) + _fxsave( FXArea ); +#elif defined(_MSC_VER) && defined(_M_IX86) + __asm { + mov eax, FXArea + FXSAVE[eax] + } #endif + unsigned int dwMask = *( unsigned int * )&FXArea[28]; // Read the MXCSR Mask + return ( ( dwMask & MXCSR_DAZ ) == MXCSR_DAZ ); // Return if the DAZ bit is set +} /* ================ @@ -200,33 +285,157 @@ Sys_GetProcessorId ================ */ int Sys_GetProcessorId( void ) { - int flags = CPUID_GENERIC; + // unknown or unsupported cpu + int flags = CPUID_GENERIC; + + // check for an AMD cpu default to Intel if not found. + if ( IsAMD() ) { + flags = CPUID_AMD; + } else { + flags = CPUID_INTEL; + } + + // check for Multi Media Extensions + if ( SDL_HasMMX() ) { + flags |= CPUID_MMX; + } + +// SDL3 doesn't support detecting 3DNow, and current CPUs (even from AMD) don't support it either +#if !defined(D3_SDL3) + // check for 3DNow! (deprecated and removed in SDL3) + if ( SDL_Has3DNow() ) { + flags |= CPUID_3DNOW; + } +#endif - if (SDL_HasMMX()) - flags |= CPUID_MMX; + // check for Streaming SIMD Extensions + if ( SDL_HasSSE() ) { + flags |= CPUID_SSE; + } + + // check for Streaming SIMD Extensions 2 + if ( SDL_HasSSE2() ) { + flags |= CPUID_SSE2; + } + + // check for Streaming SIMD Extensions 3 aka Prescott's New Instructions + if ( SDL_HasSSE3() ) { + flags |= CPUID_SSE3; + } + + // check for Streaming SIMD Extensions 4.1 (unused atm) + if ( SDL_HasSSE41() ) { + flags |= CPUID_SSE41; + } + + // check for FMA3 (SDL2 does set the AVX2 flag without this but SDL1 does not even support AVX) + if ( SDL_HasFMA3() ) { + flags |= CPUID_FMA3; + } + + // check for AVX + if ( SDL_HasAVX() ) { + flags |= CPUID_AVX; + } + + // check for AVX2 + if ( SDL_HasAVX2() ) { + flags |= CPUID_AVX2; + } + + // check for Denormals-Are-Zero mode + if ( SDL_HasDAZ() ) { + flags |= CPUID_DAZ; + } + + // check for ALTIVEC (apple in my eye...) + if ( SDL_HasAltiVec() ) { + flags |= CPUID_ALTIVEC; + } + return flags; +} - // SDL3 doesn't support detecting 3DNow, and current CPUs (even from AMD) don't support it either -#ifndef D3_SDL3 - if (SDL_Has3DNow()) - flags |= CPUID_3DNOW; +// inline assembly not supported by msvc 64 bit +// so use the standard intel functions to get the value there. +// removed unused macros and added some that also work on 64 bit msvc +// btw the return values are unsigned not plain int. +#if defined(_MSC_VER) && defined(_M_IX86) +#define STREFLOP_STMXCSR( cw ) do { unsigned int tmp = 0; __asm { stmxcsr tmp }; ( cw ) = tmp; } while (0) +#define STREFLOP_LDMXCSR( cw ) do { unsigned int tmp = ( cw ); __asm { ldmxcsr tmp }; } while (0) +#elif defined(_MSC_VER) && defined(_M_X64) +#define STREFLOP_STMXCSR( cw ) do { unsigned int tmp = 0; tmp = _mm_getcsr(); ( cw ) = tmp; } while (0) +#define STREFLOP_LDMXCSR( cw ) do { unsigned int tmp = ( cw ); _mm_setcsr( tmp ); } while (0) +#else /* __GNUC__? */ +#define STREFLOP_STMXCSR( cw ) do { asm volatile ( "stmxcsr %0" : "=m" ( cw ) : ); } while (0) +#define STREFLOP_LDMXCSR( cw ) do { asm volatile ( "ldmxcsr %0" : : "m" ( cw ) ); } while (0) #endif - if (SDL_HasSSE()) - flags |= CPUID_SSE; - - if (SDL_HasSSE2()) - flags |= CPUID_SSE2; +/* +================ +EnableMXCSRFlag -#ifndef NO_CPUID - // there is no SDL_HasSSE3() in SDL 1.2 - if (HasSSE3()) - flags |= CPUID_SSE3; -#endif +Ignored anyway if the CPU does not support SSE +================ +*/ +static inline void EnableMXCSRFlag( unsigned int flag, bool enable, const char *name ) { + unsigned int sse_mode = 0; + + // stgatilov: note that MXCSR affects only SSE+ arithmetic + // old x87 FPU has its own control register, but we don't care about it =) + STREFLOP_STMXCSR( sse_mode ); + + // prevent resetting flag if allready enabled + if ( enable && ( sse_mode & flag ) == flag ) { + common->Printf( "%s mode is already enabled\n", name ); + return; + } + + // prevent resetting flag if allready disabled + if ( !enable && ( sse_mode & flag ) == 0 ) { + common->Printf( "%s mode is already disabled\n", name ); + return; + } + + if ( enable ) { + common->Printf( "enabling %s mode\n", name ); + sse_mode |= flag; + } else { + common->Printf( "disabling %s mode\n", name ); + sse_mode &= ~flag; + } + STREFLOP_LDMXCSR( sse_mode ); +} - if (SDL_HasAltiVec()) - flags |= CPUID_ALTIVEC; +/* +================ +Sys_FPU_SetDAZ +================ +*/ +void Sys_FPU_SetDAZ( bool enable ) { + int cpuid = Sys_GetProcessorId(); + + // extra safeguard simd.cpp does check for sse mode but not daz + if ( ( cpuid & CPUID_DAZ ) == 0 ) { + common->Printf( "this CPU doesn't support Denormals-Are-Zero\n" ); + return; + } + EnableMXCSRFlag( MXCSR_DAZ, enable, "Denormals-Are-Zero" ); +} - return flags; +/* +================ +Sys_FPU_SetFTZ +================ +*/ +void Sys_FPU_SetFTZ( bool enable ) { + int cpuid = Sys_GetProcessorId(); + + // extra safeguard simd.cpp does check for sse mode so probably overkill + if ( ( cpuid & CPUID_SSE ) == 0 ) { + common->Printf( "this CPU doesn't support Flush-To-Zero\n" ); + return; + } + EnableMXCSRFlag( MXCSR_FTZ, enable, "Flush-To-Zero" ); } /* @@ -236,6 +445,6 @@ Sys_FPU_SetPrecision */ void Sys_FPU_SetPrecision() { #if defined(_MSC_VER) && defined(_M_IX86) - _controlfp(_PC_64, _MCW_PC); + _controlfp( _PC_64, _MCW_PC ); #endif } diff --git a/neo/sys/events.cpp b/neo/sys/events.cpp index b50cd73d0..ad20784d5 100644 --- a/neo/sys/events.cpp +++ b/neo/sys/events.cpp @@ -27,7 +27,6 @@ If you have questions concerning this license or the applicable additional terms */ #include "sys/sys_sdl.h" - #include "sys/platform.h" #include "idlib/containers/List.h" #include "idlib/Heap.h" @@ -63,98 +62,98 @@ If you have questions concerning this license or the applicable additional terms // unholy hacks to make it work with SDL3 (and also SDL2 and partly SDL1.2) #if SDL_VERSION_ATLEAST(3, 0, 0) - // in SDL3 SDL_GetKeyFromScancode() got additional arguments that I don't care about - #define SDL_GetKeyFromScancode(SC) SDL_GetKeyFromScancode(SC, 0, true) - - #define SDLK_z SDLK_Z - - #define SDL_TEXTINPUT SDL_EVENT_TEXT_INPUT - #define SDL_KEYDOWN SDL_EVENT_KEY_DOWN - #define SDL_KEYUP SDL_EVENT_KEY_UP - - #define SDL_USEREVENT SDL_EVENT_USER - #define SDL_QUIT SDL_EVENT_QUIT - - #define SDL_MOUSEBUTTONDOWN SDL_EVENT_MOUSE_BUTTON_DOWN - #define SDL_MOUSEBUTTONUP SDL_EVENT_MOUSE_BUTTON_UP - #define SDL_MOUSEMOTION SDL_EVENT_MOUSE_MOTION - #define SDL_MOUSEWHEEL SDL_EVENT_MOUSE_WHEEL - - #define SDL_JoystickGUID SDL_GUID - #define SDL_JoystickGetGUID SDL_GetJoystickGUID - #define SDL_JoystickName SDL_GetJoystickName - #define SDL_JoystickGetGUIDString SDL_GUIDToString - - #define SDL_JOYDEVICEADDED SDL_EVENT_JOYSTICK_ADDED - #define SDL_JOYDEVICEREMOVED SDL_EVENT_JOYSTICK_REMOVED - - // game controllers have been renamed to gamepads and the - // corresponding SDL_Event members are now prefixed with g instead of c - #define cbutton gbutton - #define caxis gaxis - - #define SDL_GameController SDL_Gamepad - #define SDL_GameControllerAxis SDL_GamepadAxis - #define SDL_GameControllerButton SDL_GamepadButton - - #define SDL_GameControllerGetType SDL_GetGamepadType - #define SDL_GameControllerName SDL_GetGamepadName - #define SDL_GameControllerGetJoystick SDL_GetGamepadJoystick - #define SDL_GameControllerGetVendor SDL_GetGamepadVendor - #define SDL_GameControllerGetProduct SDL_GetGamepadProduct - #define SDL_GameControllerOpen SDL_OpenGamepad - - #define SDL_CONTROLLERAXISMOTION SDL_EVENT_GAMEPAD_AXIS_MOTION - #define SDL_CONTROLLERBUTTONDOWN SDL_EVENT_GAMEPAD_BUTTON_DOWN - #define SDL_CONTROLLERBUTTONUP SDL_EVENT_GAMEPAD_BUTTON_UP - - #define SDL_CONTROLLER_AXIS_LEFTX SDL_GAMEPAD_AXIS_LEFTX - #define SDL_CONTROLLER_AXIS_LEFTY SDL_GAMEPAD_AXIS_LEFTY - #define SDL_CONTROLLER_AXIS_MAX SDL_GAMEPAD_AXIS_MAX - #define SDL_CONTROLLER_AXIS_RIGHTX SDL_GAMEPAD_AXIS_RIGHTX - #define SDL_CONTROLLER_AXIS_RIGHTY SDL_GAMEPAD_AXIS_RIGHTY - #define SDL_CONTROLLER_AXIS_TRIGGERLEFT SDL_GAMEPAD_AXIS_LEFT_TRIGGER - #define SDL_CONTROLLER_AXIS_TRIGGERRIGHT SDL_GAMEPAD_AXIS_RIGHT_TRIGGER - #define SDL_CONTROLLER_BUTTON_A SDL_GAMEPAD_BUTTON_SOUTH - #define SDL_CONTROLLER_BUTTON_B SDL_GAMEPAD_BUTTON_EAST - #define SDL_CONTROLLER_BUTTON_X SDL_GAMEPAD_BUTTON_WEST - #define SDL_CONTROLLER_BUTTON_Y SDL_GAMEPAD_BUTTON_NORTH - #define SDL_CONTROLLER_BUTTON_BACK SDL_GAMEPAD_BUTTON_BACK - #define SDL_CONTROLLER_BUTTON_DPAD_DOWN SDL_GAMEPAD_BUTTON_DPAD_DOWN - #define SDL_CONTROLLER_BUTTON_DPAD_LEFT SDL_GAMEPAD_BUTTON_DPAD_LEFT - #define SDL_CONTROLLER_BUTTON_DPAD_RIGHT SDL_GAMEPAD_BUTTON_DPAD_RIGHT - #define SDL_CONTROLLER_BUTTON_DPAD_UP SDL_GAMEPAD_BUTTON_DPAD_UP - #define SDL_CONTROLLER_BUTTON_GUIDE SDL_GAMEPAD_BUTTON_GUIDE - #define SDL_CONTROLLER_BUTTON_INVALID SDL_GAMEPAD_BUTTON_INVALID - #define SDL_CONTROLLER_BUTTON_LEFTSHOULDER SDL_GAMEPAD_BUTTON_LEFT_SHOULDER - #define SDL_CONTROLLER_BUTTON_LEFTSTICK SDL_GAMEPAD_BUTTON_LEFT_STICK - #define SDL_CONTROLLER_BUTTON_MISC1 SDL_GAMEPAD_BUTTON_MISC1 - #define SDL_CONTROLLER_BUTTON_PADDLE1 SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1 - #define SDL_CONTROLLER_BUTTON_PADDLE2 SDL_GAMEPAD_BUTTON_LEFT_PADDLE1 - #define SDL_CONTROLLER_BUTTON_PADDLE3 SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2 - #define SDL_CONTROLLER_BUTTON_PADDLE4 SDL_GAMEPAD_BUTTON_LEFT_PADDLE2 - #define SDL_CONTROLLER_BUTTON_RIGHTSHOULDER SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER - #define SDL_CONTROLLER_BUTTON_RIGHTSTICK SDL_GAMEPAD_BUTTON_RIGHT_STICK - #define SDL_CONTROLLER_BUTTON_START SDL_GAMEPAD_BUTTON_START - #define SDL_CONTROLLER_BUTTON_TOUCHPAD SDL_GAMEPAD_BUTTON_TOUCHPAD - - #define SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT - #define SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR - #define SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT - #define SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO - #define SDL_CONTROLLER_TYPE_PS3 SDL_GAMEPAD_TYPE_PS3 - #define SDL_CONTROLLER_TYPE_PS4 SDL_GAMEPAD_TYPE_PS4 - #define SDL_CONTROLLER_TYPE_PS5 SDL_GAMEPAD_TYPE_PS5 - #define SDL_CONTROLLER_TYPE_UNKNOWN SDL_GAMEPAD_TYPE_STANDARD - #define SDL_CONTROLLER_TYPE_VIRTUAL SDL_GAMEPAD_TYPE_VIRTUAL - #define SDL_CONTROLLER_TYPE_XBOX360 SDL_GAMEPAD_TYPE_XBOX360 - #define SDL_CONTROLLER_TYPE_XBOXONE SDL_GAMEPAD_TYPE_XBOXONE - - #define IS_SDL_BTN_DOWN(EV) EV.down +// in SDL3 SDL_GetKeyFromScancode() got additional arguments that I don't care about +#define SDL_GetKeyFromScancode(SC) SDL_GetKeyFromScancode(SC, 0, true) + +#define SDLK_z SDLK_Z + +#define SDL_TEXTINPUT SDL_EVENT_TEXT_INPUT +#define SDL_KEYDOWN SDL_EVENT_KEY_DOWN +#define SDL_KEYUP SDL_EVENT_KEY_UP + +#define SDL_USEREVENT SDL_EVENT_USER +#define SDL_QUIT SDL_EVENT_QUIT + +#define SDL_MOUSEBUTTONDOWN SDL_EVENT_MOUSE_BUTTON_DOWN +#define SDL_MOUSEBUTTONUP SDL_EVENT_MOUSE_BUTTON_UP +#define SDL_MOUSEMOTION SDL_EVENT_MOUSE_MOTION +#define SDL_MOUSEWHEEL SDL_EVENT_MOUSE_WHEEL + +#define SDL_JoystickGUID SDL_GUID +#define SDL_JoystickGetGUID SDL_GetJoystickGUID +#define SDL_JoystickName SDL_GetJoystickName +#define SDL_JoystickGetGUIDString SDL_GUIDToString + +#define SDL_JOYDEVICEADDED SDL_EVENT_JOYSTICK_ADDED +#define SDL_JOYDEVICEREMOVED SDL_EVENT_JOYSTICK_REMOVED + +// game controllers have been renamed to gamepads and the +// corresponding SDL_Event members are now prefixed with g instead of c +#define cbutton gbutton +#define caxis gaxis + +#define SDL_GameController SDL_Gamepad +#define SDL_GameControllerAxis SDL_GamepadAxis +#define SDL_GameControllerButton SDL_GamepadButton + +#define SDL_GameControllerGetType SDL_GetGamepadType +#define SDL_GameControllerName SDL_GetGamepadName +#define SDL_GameControllerGetJoystick SDL_GetGamepadJoystick +#define SDL_GameControllerGetVendor SDL_GetGamepadVendor +#define SDL_GameControllerGetProduct SDL_GetGamepadProduct +#define SDL_GameControllerOpen SDL_OpenGamepad + +#define SDL_CONTROLLERAXISMOTION SDL_EVENT_GAMEPAD_AXIS_MOTION +#define SDL_CONTROLLERBUTTONDOWN SDL_EVENT_GAMEPAD_BUTTON_DOWN +#define SDL_CONTROLLERBUTTONUP SDL_EVENT_GAMEPAD_BUTTON_UP + +#define SDL_CONTROLLER_AXIS_LEFTX SDL_GAMEPAD_AXIS_LEFTX +#define SDL_CONTROLLER_AXIS_LEFTY SDL_GAMEPAD_AXIS_LEFTY +#define SDL_CONTROLLER_AXIS_MAX SDL_GAMEPAD_AXIS_MAX +#define SDL_CONTROLLER_AXIS_RIGHTX SDL_GAMEPAD_AXIS_RIGHTX +#define SDL_CONTROLLER_AXIS_RIGHTY SDL_GAMEPAD_AXIS_RIGHTY +#define SDL_CONTROLLER_AXIS_TRIGGERLEFT SDL_GAMEPAD_AXIS_LEFT_TRIGGER +#define SDL_CONTROLLER_AXIS_TRIGGERRIGHT SDL_GAMEPAD_AXIS_RIGHT_TRIGGER +#define SDL_CONTROLLER_BUTTON_A SDL_GAMEPAD_BUTTON_SOUTH +#define SDL_CONTROLLER_BUTTON_B SDL_GAMEPAD_BUTTON_EAST +#define SDL_CONTROLLER_BUTTON_X SDL_GAMEPAD_BUTTON_WEST +#define SDL_CONTROLLER_BUTTON_Y SDL_GAMEPAD_BUTTON_NORTH +#define SDL_CONTROLLER_BUTTON_BACK SDL_GAMEPAD_BUTTON_BACK +#define SDL_CONTROLLER_BUTTON_DPAD_DOWN SDL_GAMEPAD_BUTTON_DPAD_DOWN +#define SDL_CONTROLLER_BUTTON_DPAD_LEFT SDL_GAMEPAD_BUTTON_DPAD_LEFT +#define SDL_CONTROLLER_BUTTON_DPAD_RIGHT SDL_GAMEPAD_BUTTON_DPAD_RIGHT +#define SDL_CONTROLLER_BUTTON_DPAD_UP SDL_GAMEPAD_BUTTON_DPAD_UP +#define SDL_CONTROLLER_BUTTON_GUIDE SDL_GAMEPAD_BUTTON_GUIDE +#define SDL_CONTROLLER_BUTTON_INVALID SDL_GAMEPAD_BUTTON_INVALID +#define SDL_CONTROLLER_BUTTON_LEFTSHOULDER SDL_GAMEPAD_BUTTON_LEFT_SHOULDER +#define SDL_CONTROLLER_BUTTON_LEFTSTICK SDL_GAMEPAD_BUTTON_LEFT_STICK +#define SDL_CONTROLLER_BUTTON_MISC1 SDL_GAMEPAD_BUTTON_MISC1 +#define SDL_CONTROLLER_BUTTON_PADDLE1 SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1 +#define SDL_CONTROLLER_BUTTON_PADDLE2 SDL_GAMEPAD_BUTTON_LEFT_PADDLE1 +#define SDL_CONTROLLER_BUTTON_PADDLE3 SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2 +#define SDL_CONTROLLER_BUTTON_PADDLE4 SDL_GAMEPAD_BUTTON_LEFT_PADDLE2 +#define SDL_CONTROLLER_BUTTON_RIGHTSHOULDER SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER +#define SDL_CONTROLLER_BUTTON_RIGHTSTICK SDL_GAMEPAD_BUTTON_RIGHT_STICK +#define SDL_CONTROLLER_BUTTON_START SDL_GAMEPAD_BUTTON_START +#define SDL_CONTROLLER_BUTTON_TOUCHPAD SDL_GAMEPAD_BUTTON_TOUCHPAD + +#define SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT +#define SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR +#define SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT +#define SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO +#define SDL_CONTROLLER_TYPE_PS3 SDL_GAMEPAD_TYPE_PS3 +#define SDL_CONTROLLER_TYPE_PS4 SDL_GAMEPAD_TYPE_PS4 +#define SDL_CONTROLLER_TYPE_PS5 SDL_GAMEPAD_TYPE_PS5 +#define SDL_CONTROLLER_TYPE_UNKNOWN SDL_GAMEPAD_TYPE_STANDARD +#define SDL_CONTROLLER_TYPE_VIRTUAL SDL_GAMEPAD_TYPE_VIRTUAL +#define SDL_CONTROLLER_TYPE_XBOX360 SDL_GAMEPAD_TYPE_XBOX360 +#define SDL_CONTROLLER_TYPE_XBOXONE SDL_GAMEPAD_TYPE_XBOXONE + +#define IS_SDL_BTN_DOWN(EV) EV.down #else // SDL2 and SDL1.2 - #define IS_SDL_BTN_DOWN(EV) (EV.state == SDL_PRESSED) +#define IS_SDL_BTN_DOWN(EV) (EV.state == SDL_PRESSED) #endif // SDL_VERSION_ATLEAST(3, 0, 0) - unholy hacks @@ -169,17 +168,17 @@ const char *_in_kbdNames[] = { "english", "french", "german", "italian", "spanish", "turkish", "norwegian", "brazilian", NULL }; -static idCVar in_kbd("in_kbd", _in_kbdNames[0], CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT, "keyboard layout", _in_kbdNames, idCmdSystem::ArgCompletion_String<_in_kbdNames> ); +static idCVar in_kbd( "in_kbd", _in_kbdNames[0], CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT, "keyboard layout", _in_kbdNames, idCmdSystem::ArgCompletion_String<_in_kbdNames> ); // TODO: I'd really like to make in_ignoreConsoleKey default to 1, but I guess there would be too much confusion :-/ -static idCVar in_ignoreConsoleKey("in_ignoreConsoleKey", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT | CVAR_BOOL, - "Console only opens with Shift+Esc, not ` or ^ etc"); +static idCVar in_ignoreConsoleKey( "in_ignoreConsoleKey", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT | CVAR_BOOL, + "Console only opens with Shift+Esc, not ` or ^ etc" ); -static idCVar in_nograb("in_nograb", "0", CVAR_SYSTEM | CVAR_NOCHEAT, "prevents input grabbing"); -idCVar in_grabKeyboard("in_grabKeyboard", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT | CVAR_BOOL, - "if enabled, grabs all keyboard input if mouse is grabbed (so keyboard shortcuts from the OS like Alt-Tab or Windows Key won't work)"); +static idCVar in_nograb( "in_nograb", "0", CVAR_SYSTEM | CVAR_NOCHEAT, "prevents input grabbing" ); +idCVar in_grabKeyboard( "in_grabKeyboard", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT | CVAR_BOOL, + "if enabled, grabs all keyboard input if mouse is grabbed (so keyboard shortcuts from the OS like Alt-Tab or Windows Key won't work)" ); -idCVar joy_gamepadLayout("joy_gamepadLayout", "-1", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT | CVAR_INTEGER, - "Button layout of gamepad. -1: auto (needs SDL 2.0.12 or newer), 0: XBox-style, 1: Nintendo-style, 2: PS4/5-style, 3: PS2/3-style", idCmdSystem::ArgCompletion_Integer<-1, 3> ); +idCVar joy_gamepadLayout( "joy_gamepadLayout", "-1", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT | CVAR_INTEGER, + "Button layout of gamepad. -1: auto (needs SDL 2.0.12 or newer), 0: XBox-style, 1: Nintendo-style, 2: PS4/5-style, 3: PS2/3-style", idCmdSystem::ArgCompletion_Integer < -1, 3 > ); // set in handleMouseGrab(), used in Sys_GetEvent() to decide what kind of internal mouse event to generate static bool in_relativeMouseMode = true; @@ -187,20 +186,20 @@ static bool in_relativeMouseMode = true; static bool in_hasFocus = true; static enum D3_Gamepad_Type { - D3_GAMEPAD_XINPUT, // XBox/XInput standard, the default - D3_GAMEPAD_NINTENDO, // nintendo-like (A/B and X/Y are switched) - D3_GAMEPAD_PLAYSTATION, // PS-like (geometric symbols instead of A/B/X/Y) - D3_GAMEPAD_PLAYSTATION_OLD // PS2/PS3-like: the back button is called "select" instead of "share" + D3_GAMEPAD_XINPUT, // XBox/XInput standard, the default + D3_GAMEPAD_NINTENDO, // nintendo-like (A/B and X/Y are switched) + D3_GAMEPAD_PLAYSTATION, // PS-like (geometric symbols instead of A/B/X/Y) + D3_GAMEPAD_PLAYSTATION_OLD // PS2/PS3-like: the back button is called "select" instead of "share" } gamepadType = D3_GAMEPAD_XINPUT; struct kbd_poll_t { int key; bool state; - kbd_poll_t() : key(0), state(false) { + kbd_poll_t() : key( 0 ), state( false ) { } - kbd_poll_t(int k, bool s) { + kbd_poll_t( int k, bool s ) { key = k; state = s; } @@ -210,10 +209,9 @@ struct mouse_poll_t { int action; int value; - mouse_poll_t() : action(0), value(0) { - } + mouse_poll_t() : action( 0 ), value( 0 ) {} - mouse_poll_t(int a, int v) { + mouse_poll_t( int a, int v ) { action = a; value = v; } @@ -223,9 +221,9 @@ struct joystick_poll_t { int action; int value; - joystick_poll_t() : action(0), value(0) {} // TODO: or -1? + joystick_poll_t() : action( 0 ), value( 0 ) {} // TODO: or -1? - joystick_poll_t(int a, int v) { + joystick_poll_t( int a, int v ) { action = a; value = v; } @@ -242,81 +240,78 @@ static idList event_overflow; struct scancodename_t { int sdlScancode; - const char* name; + const char *name; }; // scancodenames[keynum - K_FIRST_SCANCODE] belongs to keynum static scancodename_t scancodemappings[] = { // NOTE: must be kept in sync with the K_SC_* section of keyNum_t in framework/KeyInput.h ! - #if SDL_VERSION_ATLEAST(2, 0, 0) - #define D3_SC_MAPPING(X) { SDL_SCANCODE_ ## X , "SC_" #X } +#define D3_SC_MAPPING(X) { SDL_SCANCODE_ ## X , "SC_" #X } #else // SDL1.2 doesn't have scancodes - #define D3_SC_MAPPING(X) { 0 , "SC_" #X } +#define D3_SC_MAPPING(X) { 0 , "SC_" #X } #endif - - D3_SC_MAPPING(A), // { SDL_SCANCODE_A, "SC_A" }, - D3_SC_MAPPING(B), - D3_SC_MAPPING(C), - D3_SC_MAPPING(D), - D3_SC_MAPPING(E), - D3_SC_MAPPING(F), - D3_SC_MAPPING(G), - D3_SC_MAPPING(H), - D3_SC_MAPPING(I), - D3_SC_MAPPING(J), - D3_SC_MAPPING(K), - D3_SC_MAPPING(L), - D3_SC_MAPPING(M), - D3_SC_MAPPING(N), - D3_SC_MAPPING(O), - D3_SC_MAPPING(P), - D3_SC_MAPPING(Q), - D3_SC_MAPPING(R), - D3_SC_MAPPING(S), - D3_SC_MAPPING(T), - D3_SC_MAPPING(U), - D3_SC_MAPPING(V), - D3_SC_MAPPING(W), - D3_SC_MAPPING(X), - D3_SC_MAPPING(Y), - D3_SC_MAPPING(Z), + D3_SC_MAPPING( A ), // { SDL_SCANCODE_A, "SC_A" }, + D3_SC_MAPPING( B ), + D3_SC_MAPPING( C ), + D3_SC_MAPPING( D ), + D3_SC_MAPPING( E ), + D3_SC_MAPPING( F ), + D3_SC_MAPPING( G ), + D3_SC_MAPPING( H ), + D3_SC_MAPPING( I ), + D3_SC_MAPPING( J ), + D3_SC_MAPPING( K ), + D3_SC_MAPPING( L ), + D3_SC_MAPPING( M ), + D3_SC_MAPPING( N ), + D3_SC_MAPPING( O ), + D3_SC_MAPPING( P ), + D3_SC_MAPPING( Q ), + D3_SC_MAPPING( R ), + D3_SC_MAPPING( S ), + D3_SC_MAPPING( T ), + D3_SC_MAPPING( U ), + D3_SC_MAPPING( V ), + D3_SC_MAPPING( W ), + D3_SC_MAPPING( X ), + D3_SC_MAPPING( Y ), + D3_SC_MAPPING( Z ), // leaving out SDL_SCANCODE_1 ... _0, we handle them separately already // also return, escape, backspace, tab, space, already handled as keycodes - D3_SC_MAPPING(MINUS), - D3_SC_MAPPING(EQUALS), - D3_SC_MAPPING(LEFTBRACKET), - D3_SC_MAPPING(RIGHTBRACKET), - D3_SC_MAPPING(BACKSLASH), - D3_SC_MAPPING(NONUSHASH), - D3_SC_MAPPING(SEMICOLON), - D3_SC_MAPPING(APOSTROPHE), - D3_SC_MAPPING(GRAVE), - D3_SC_MAPPING(COMMA), - D3_SC_MAPPING(PERIOD), - D3_SC_MAPPING(SLASH), + D3_SC_MAPPING( MINUS ), + D3_SC_MAPPING( EQUALS ), + D3_SC_MAPPING( LEFTBRACKET ), + D3_SC_MAPPING( RIGHTBRACKET ), + D3_SC_MAPPING( BACKSLASH ), + D3_SC_MAPPING( NONUSHASH ), + D3_SC_MAPPING( SEMICOLON ), + D3_SC_MAPPING( APOSTROPHE ), + D3_SC_MAPPING( GRAVE ), + D3_SC_MAPPING( COMMA ), + D3_SC_MAPPING( PERIOD ), + D3_SC_MAPPING( SLASH ), // leaving out lots of keys incl. from keypad, we already handle them as normal keys - D3_SC_MAPPING(NONUSBACKSLASH), - D3_SC_MAPPING(INTERNATIONAL1), /**< used on Asian keyboards, see footnotes in USB doc */ - D3_SC_MAPPING(INTERNATIONAL2), - D3_SC_MAPPING(INTERNATIONAL3), /**< Yen */ - D3_SC_MAPPING(INTERNATIONAL4), - D3_SC_MAPPING(INTERNATIONAL5), - D3_SC_MAPPING(INTERNATIONAL6), - D3_SC_MAPPING(INTERNATIONAL7), - D3_SC_MAPPING(INTERNATIONAL8), - D3_SC_MAPPING(INTERNATIONAL9), - D3_SC_MAPPING(THOUSANDSSEPARATOR), - D3_SC_MAPPING(DECIMALSEPARATOR), - D3_SC_MAPPING(CURRENCYUNIT), - D3_SC_MAPPING(CURRENCYSUBUNIT) - + D3_SC_MAPPING( NONUSBACKSLASH ), + D3_SC_MAPPING( INTERNATIONAL1 ), /**< used on Asian keyboards, see footnotes in USB doc */ + D3_SC_MAPPING( INTERNATIONAL2 ), + D3_SC_MAPPING( INTERNATIONAL3 ), /**< Yen */ + D3_SC_MAPPING( INTERNATIONAL4 ), + D3_SC_MAPPING( INTERNATIONAL5 ), + D3_SC_MAPPING( INTERNATIONAL6 ), + D3_SC_MAPPING( INTERNATIONAL7 ), + D3_SC_MAPPING( INTERNATIONAL8 ), + D3_SC_MAPPING( INTERNATIONAL9 ), + D3_SC_MAPPING( THOUSANDSSEPARATOR ), + D3_SC_MAPPING( DECIMALSEPARATOR ), + D3_SC_MAPPING( CURRENCYUNIT ), + D3_SC_MAPPING( CURRENCYSUBUNIT ) #undef D3_SC_MAPPING }; // for keynums between K_FIRST_SCANCODE and K_LAST_SCANCODE // returns e.g. "SC_A" for K_SC_A -const char* Sys_GetScancodeName( int key ) { +const char *Sys_GetScancodeName( int key ) { if ( key >= K_FIRST_SCANCODE && key <= K_LAST_SCANCODE ) { int scIdx = key - K_FIRST_SCANCODE; return scancodemappings[scIdx].name; @@ -325,10 +320,10 @@ const char* Sys_GetScancodeName( int key ) { } #if SDL_VERSION_ATLEAST(2, 0, 0) -static bool isAscii( const char* str_ ) { - const unsigned char* str = (const unsigned char*)str_; - while(*str != '\0') { - if(*str > 127) { +static bool isAscii( const char *str_ ) { + const unsigned char *str = ( const unsigned char * )str_; + while ( *str != '\0' ) { + if ( *str > 127 ) { return false; } ++str; @@ -338,168 +333,172 @@ static bool isAscii( const char* str_ ) { #endif // SDL2 // start button isn't bindable, but I want to use its name in the imgui-based menu -const char* D3_GetGamepadStartButtonName() { +const char *D3_GetGamepadStartButtonName() { int layout = joy_gamepadLayout.GetInteger(); + if ( layout == -1 ) { layout = gamepadType; } - switch( layout ) { - default: - common->Warning( "joy_gamepadLayout has invalid value %d !\n", joy_gamepadLayout.GetInteger() ); - // fall-through - case D3_GAMEPAD_PLAYSTATION_OLD: - case D3_GAMEPAD_XINPUT: - return "Pad Start"; - case D3_GAMEPAD_NINTENDO: - return "Pad (+)"; - - case D3_GAMEPAD_PLAYSTATION: - return "Pad Options"; + switch ( layout ) { + default: + common->Warning( "joy_gamepadLayout has invalid value %d !\n", joy_gamepadLayout.GetInteger() ); + // fall-through + case D3_GAMEPAD_PLAYSTATION_OLD: + case D3_GAMEPAD_XINPUT: + return "Pad Start"; + case D3_GAMEPAD_NINTENDO: + return "Pad (+)"; + + case D3_GAMEPAD_PLAYSTATION: + return "Pad Options"; } } -const char* Sys_GetLocalizedJoyKeyName( int key ) { +const char *Sys_GetLocalizedJoyKeyName( int key ) { // Note: trying to keep the returned names short, because the Doom3 binding window doesn't have much space for names.. #if SDL_VERSION_ATLEAST(2, 0, 0) // gamecontroller/gamepad not supported in SDL1 - if (key >= K_FIRST_JOY && key <= K_LAST_JOY) { + if ( key >= K_FIRST_JOY && key <= K_LAST_JOY ) { - if (key <= K_JOY_BTN_BACK) { + if ( key <= K_JOY_BTN_BACK ) { #if 0 //SDL_VERSION_ATLEAST(3, 0, 0) // TODO: or use the SDL2 code and just set joy_gamepadLayout automatically based on SDL_GetGamepadType() ? - SDL_GamepadButton gpbtn = (SDL_GamepadButton)(SDL_GAMEPAD_BUTTON_SOUTH + (key - K_JOY_BTN_SOUTH)); + SDL_GamepadButton gpbtn = ( SDL_GamepadButton )( SDL_GAMEPAD_BUTTON_SOUTH + ( key - K_JOY_BTN_SOUTH ) ); SDL_GamepadType sdlGamepadType = TODO; - SDL_GamepadButtonLabel label = SDL_GetGamepadButtonLabelForType(sdlGamepadType, gpbtn); - switch(label) { - case SDL_GAMEPAD_BUTTON_LABEL_A: - return "Pad A"; - case SDL_GAMEPAD_BUTTON_LABEL_B: - return "Pad B"; - case SDL_GAMEPAD_BUTTON_LABEL_X: - return "Pad X"; - case SDL_GAMEPAD_BUTTON_LABEL_Y: - return "Pad Y"; - case SDL_GAMEPAD_BUTTON_LABEL_CROSS: - return "Pad Cross"; - case SDL_GAMEPAD_BUTTON_LABEL_CIRCLE: - return "Pad Circle"; - case SDL_GAMEPAD_BUTTON_LABEL_SQUARE: - return "Pad Square"; - case SDL_GAMEPAD_BUTTON_LABEL_TRIANGLE: - return "Pad Triangle"; + SDL_GamepadButtonLabel label = SDL_GetGamepadButtonLabelForType( sdlGamepadType, gpbtn ); + switch ( label ) { + case SDL_GAMEPAD_BUTTON_LABEL_A: + return "Pad A"; + case SDL_GAMEPAD_BUTTON_LABEL_B: + return "Pad B"; + case SDL_GAMEPAD_BUTTON_LABEL_X: + return "Pad X"; + case SDL_GAMEPAD_BUTTON_LABEL_Y: + return "Pad Y"; + case SDL_GAMEPAD_BUTTON_LABEL_CROSS: + return "Pad Cross"; + case SDL_GAMEPAD_BUTTON_LABEL_CIRCLE: + return "Pad Circle"; + case SDL_GAMEPAD_BUTTON_LABEL_SQUARE: + return "Pad Square"; + case SDL_GAMEPAD_BUTTON_LABEL_TRIANGLE: + return "Pad Triangle"; } #else // SDL2 // South, East, West, North Back - static const char* xboxBtnNames[5] = { "Pad A", "Pad B", "Pad X", "Pad Y", "Pad Back" }; - static const char* nintendoBtnNames[5] = { "Pad B", "Pad A", "Pad Y", "Pad X", "Pad -" }; - static const char* psBtnNames[5] = { "Pad Cross", "Pad Circle", "Pad Square", "Pad Triangle", "Pad Share" }; + static const char *xboxBtnNames[5] = { "Pad A", "Pad B", "Pad X", "Pad Y", "Pad Back" }; + static const char *nintendoBtnNames[5] = { "Pad B", "Pad A", "Pad Y", "Pad X", "Pad -" }; + static const char *psBtnNames[5] = { "Pad Cross", "Pad Circle", "Pad Square", "Pad Triangle", "Pad Share" }; int layout = joy_gamepadLayout.GetInteger(); + if ( layout == -1 ) { layout = gamepadType; } - unsigned btnIdx = key - K_JOY_BTN_SOUTH; - assert(btnIdx < 5); - - switch( layout ) { - default: - common->Warning( "joy_gamepadLayout has invalid value %d !\n", joy_gamepadLayout.GetInteger() ); - // fall-through - case D3_GAMEPAD_XINPUT: - return xboxBtnNames[btnIdx]; - case D3_GAMEPAD_NINTENDO: - return nintendoBtnNames[btnIdx]; - case D3_GAMEPAD_PLAYSTATION_OLD: - if ( key == K_JOY_BTN_BACK ) - return "Pad Select"; - // the other button names are identical for PS2/3 and PS4/5 - // fall-through - case D3_GAMEPAD_PLAYSTATION: - return psBtnNames[btnIdx]; + + assert( btnIdx < 5 ); + + switch ( layout ) { + default: + common->Warning( "joy_gamepadLayout has invalid value %d !\n", joy_gamepadLayout.GetInteger() ); + // fall-through + case D3_GAMEPAD_XINPUT: + return xboxBtnNames[btnIdx]; + case D3_GAMEPAD_NINTENDO: + return nintendoBtnNames[btnIdx]; + case D3_GAMEPAD_PLAYSTATION_OLD: + if ( key == K_JOY_BTN_BACK ) { + return "Pad Select"; + } + // the other button names are identical for PS2/3 and PS4/5 + // fall-through + case D3_GAMEPAD_PLAYSTATION: + return psBtnNames[btnIdx]; } #endif // face button names for SDL2 } // the labels for the remaining keys are the same for SDL2 and SDL3 (and all controllers) - switch(key) { - case K_JOY_BTN_GUIDE: // can't be used in dhewm3, because it opens steam on some systems - case K_JOY_BTN_START: // can't be used for bindings, because it's hardcoded to generate Esc - return NULL; - - case K_JOY_BTN_LSTICK: - return "Pad LStick"; - case K_JOY_BTN_RSTICK: - return "Pad RStick"; - case K_JOY_BTN_LSHOULDER: - return "Pad LShoulder"; - case K_JOY_BTN_RSHOULDER: - return "Pad RShoulder"; - - case K_JOY_DPAD_UP: - return "DPad Up"; - case K_JOY_DPAD_DOWN: - return "DPad Down"; - case K_JOY_DPAD_LEFT: - return "DPad Left"; - case K_JOY_DPAD_RIGHT: - return "DPad Right"; - - case K_JOY_BTN_MISC1: - return "Pad Misc"; - case K_JOY_BTN_RPADDLE1: - return "Pad P1"; - case K_JOY_BTN_LPADDLE1: - return "Pad P3"; - case K_JOY_BTN_RPADDLE2: - return "Pad P2"; - case K_JOY_BTN_LPADDLE2: - return "Pad P4"; - - // Note: Would be nicer with "Pad " (or even "Gamepad ") at the beginning, - // but then it's too long for the keybinding window :-/ - case K_JOY_STICK1_UP: - return "Stick1 Up"; - case K_JOY_STICK1_DOWN: - return "Stick1 Down"; - case K_JOY_STICK1_LEFT: - return "Stick1 Left"; - case K_JOY_STICK1_RIGHT: - return "Stick1 Right"; - - case K_JOY_STICK2_UP: - return "Stick2 Up"; - case K_JOY_STICK2_DOWN: - return "Stick2 Down"; - case K_JOY_STICK2_LEFT: - return "Stick2 Left"; - case K_JOY_STICK2_RIGHT: - return "Stick2 Right"; - - case K_JOY_TRIGGER1: - return "Trigger 1"; - case K_JOY_TRIGGER2: - return "Trigger 2"; + switch ( key ) { + case K_JOY_BTN_GUIDE: // can't be used in dhewm3, because it opens steam on some systems + case K_JOY_BTN_START: // can't be used for bindings, because it's hardcoded to generate Esc + return NULL; + + case K_JOY_BTN_LSTICK: + return "Pad LStick"; + case K_JOY_BTN_RSTICK: + return "Pad RStick"; + case K_JOY_BTN_LSHOULDER: + return "Pad LShoulder"; + case K_JOY_BTN_RSHOULDER: + return "Pad RShoulder"; + + case K_JOY_DPAD_UP: + return "DPad Up"; + case K_JOY_DPAD_DOWN: + return "DPad Down"; + case K_JOY_DPAD_LEFT: + return "DPad Left"; + case K_JOY_DPAD_RIGHT: + return "DPad Right"; + + case K_JOY_BTN_MISC1: + return "Pad Misc"; + case K_JOY_BTN_RPADDLE1: + return "Pad P1"; + case K_JOY_BTN_LPADDLE1: + return "Pad P3"; + case K_JOY_BTN_RPADDLE2: + return "Pad P2"; + case K_JOY_BTN_LPADDLE2: + return "Pad P4"; + + // Note: Would be nicer with "Pad " (or even "Gamepad ") at the beginning, + // but then it's too long for the keybinding window :-/ + case K_JOY_STICK1_UP: + return "Stick1 Up"; + case K_JOY_STICK1_DOWN: + return "Stick1 Down"; + case K_JOY_STICK1_LEFT: + return "Stick1 Left"; + case K_JOY_STICK1_RIGHT: + return "Stick1 Right"; + + case K_JOY_STICK2_UP: + return "Stick2 Up"; + case K_JOY_STICK2_DOWN: + return "Stick2 Down"; + case K_JOY_STICK2_LEFT: + return "Stick2 Left"; + case K_JOY_STICK2_RIGHT: + return "Stick2 Right"; + + case K_JOY_TRIGGER1: + return "Trigger 1"; + case K_JOY_TRIGGER2: + return "Trigger 2"; - default: - assert(0 && "missing a case in Sys_GetLocalizedJoyKeyName()!"); + default: + assert( 0 && "missing a case in Sys_GetLocalizedJoyKeyName()!" ); } } #endif // SDL2+ return NULL; } -static const char* getLocalizedScancodeName( int key, bool useUtf8 ) -{ +static const char *getLocalizedScancodeName( int key, bool useUtf8 ) { if ( key >= K_FIRST_SCANCODE && key <= K_LAST_SCANCODE ) { int scIdx = key - K_FIRST_SCANCODE; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_Scancode sc = ( SDL_Scancode ) scancodemappings[scIdx].sdlScancode; SDL_Keycode k = SDL_GetKeyFromScancode( sc ); + if ( k >= 0xA1 && k <= 0xFF ) { static char shortStr[3] = {}; + if ( useUtf8 ) { // SDL_Keycodes are unicode chars (where applicable), // so at least for Latin-1 turn them directly into UTF-8 @@ -507,33 +506,34 @@ static const char* getLocalizedScancodeName( int key, bool useUtf8 ) // turn lowercase chars into their uppercase equivalents k -= 32; } - shortStr[0] = (unsigned char)( 0xC0 + (k >> 6) ); - shortStr[1] = (unsigned char)( 0x80 + (k & 0x3F) ); + shortStr[0] = ( unsigned char )( 0xC0 + ( k >> 6 ) ); + shortStr[1] = ( unsigned char )( 0x80 + ( k & 0x3F ) ); return shortStr; } else { // luckily, the "High-ASCII" (ISO-8559-1) chars supported by Doom3 // have the same values as the corresponding SDL_Keycodes. - shortStr[0] = (unsigned char)k; + shortStr[0] = ( unsigned char )k; shortStr[1] = 0; return shortStr; } } else if ( k != SDLK_UNKNOWN ) { const char *ret = SDL_GetKeyName( k ); if ( ret && *ret != '\0' ) { - if( useUtf8 ) { + if ( useUtf8 ) { return ret; } // the keyname from SDL2 is in UTF-8, which Doom3 can't print (except with ImGui), // so only return the name directly if it's ASCII, otherwise try to translate it // to ISO8859-1, and if that fails fall back to SC_* - if( isAscii( ret ) ) { + if ( isAscii( ret ) ) { return ret; } static char isoName[32]; + // try to convert name to ISO8859-1 (Doom3's supported "High ASCII") // TODO: pass '?' as invalidChar? - if ( D3_UTF8toISO8859_1( ret, isoName, sizeof(isoName) ) && isoName[0] != '\0' ) { + if ( D3_UTF8toISO8859_1( ret, isoName, sizeof( isoName ) ) && isoName[0] != '\0' ) { return isoName; } } @@ -550,19 +550,19 @@ static const char* getLocalizedScancodeName( int key, bool useUtf8 ) // to a "High-ASCII" char supported by Doom3. // Otherwise return same name as Sys_GetScancodeName() // !! Returned string is only valid until next call to this function !! -const char* Sys_GetLocalizedScancodeName( int key ) { +const char *Sys_GetLocalizedScancodeName( int key ) { return getLocalizedScancodeName( key, false ); } -const char* Sys_GetLocalizedScancodeNameUTF8( int key ) { +const char *Sys_GetLocalizedScancodeNameUTF8( int key ) { return getLocalizedScancodeName( key, true ); } // returns keyNum_t (K_SC_* constant) for given scancode name (like "SC_A") // only makes sense to call it if name starts with "SC_" (or "sc_") // returns -1 if not found -int Sys_GetKeynumForScancodeName( const char* name ) { - for( int scIdx = 0; scIdx < K_NUM_SCANCODES; ++scIdx ) { +int Sys_GetKeynumForScancodeName( const char *name ) { + for ( int scIdx = 0; scIdx < K_NUM_SCANCODES; ++scIdx ) { if ( idStr::Icmp( name, scancodemappings[scIdx].name ) == 0 ) { return scIdx + K_FIRST_SCANCODE; } @@ -573,7 +573,7 @@ int Sys_GetKeynumForScancodeName( const char* name ) { #if SDL_VERSION_ATLEAST(2, 0, 0) static int getKeynumForSDLscancode( SDL_Scancode scancode ) { int sc = scancode; - for ( int scIdx=0; scIdx < K_NUM_SCANCODES; ++scIdx ) { + for ( int scIdx = 0; scIdx < K_NUM_SCANCODES; ++scIdx ) { if ( scancodemappings[scIdx].sdlScancode == sc ) { return scIdx + K_FIRST_SCANCODE; } @@ -582,18 +582,19 @@ static int getKeynumForSDLscancode( SDL_Scancode scancode ) { } #endif -static byte mapkey(SDL_Keycode key) { - switch (key) { +static byte mapkey( SDL_Keycode key ) { + switch ( key ) { case SDLK_BACKSPACE: return K_BACKSPACE; case SDLK_PAUSE: return K_PAUSE; } - if (key <= SDLK_z) + if ( key <= SDLK_z ) { return key & 0xff; + } - switch (key) { + switch ( key ) { case SDLK_APPLICATION: return K_COMMAND; case SDLK_CAPSLOCK: @@ -746,7 +747,6 @@ static byte mapkey(SDL_Keycode key) { // FIXME: is this really right alt? (also mapping SDLK_RALT to K_RIGHT_ALT) return K_RIGHT_ALT; } - return 0; } @@ -765,9 +765,8 @@ enum { }; #endif // ! SDL_VERSION_ATLEAST(2, 0, 14) -static sys_jEvents mapjoybutton(SDL_GameControllerButton button) { - switch (button) - { +static sys_jEvents mapjoybutton( SDL_GameControllerButton button ) { + switch ( button ) { case SDL_CONTROLLER_BUTTON_A: return J_BTN_SOUTH; case SDL_CONTROLLER_BUTTON_B: @@ -812,15 +811,14 @@ static sys_jEvents mapjoybutton(SDL_GameControllerButton button) { case SDL_CONTROLLER_BUTTON_PADDLE4: return J_BTN_LPADDLE2; default: - common->Warning("unknown game controller button %u", button); + common->Warning( "unknown game controller button %u", button ); break; } return MAX_JOY_EVENT; } -static sys_jEvents mapjoyaxis(SDL_GameControllerAxis axis) { - switch (axis) - { +static sys_jEvents mapjoyaxis( SDL_GameControllerAxis axis ) { + switch ( axis ) { case SDL_CONTROLLER_AXIS_LEFTX: return J_AXIS_LEFT_X; case SDL_CONTROLLER_AXIS_LEFTY: @@ -834,7 +832,7 @@ static sys_jEvents mapjoyaxis(SDL_GameControllerAxis axis) { case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: return J_AXIS_RIGHT_TRIG; default: - common->Warning("unknown game controller axis %u", axis); + common->Warning( "unknown game controller axis %u", axis ); break; } return J_AXIS_MAX; @@ -858,47 +856,44 @@ enum { }; #endif // ! SDL_VERSION_ATLEAST(2, 24, 0) -static void setGamepadType( SDL_GameController* gc ) -{ +static void setGamepadType( SDL_GameController *gc ) { #if SDL_VERSION_ATLEAST(2, 0, 12) - const char* typestr = NULL; - switch( SDL_GameControllerGetType( gc ) ) { - default: // the other controller like luna, stadia, whatever, have a very similar layout - case SDL_CONTROLLER_TYPE_UNKNOWN: - case SDL_CONTROLLER_TYPE_XBOX360: - case SDL_CONTROLLER_TYPE_XBOXONE: - gamepadType = D3_GAMEPAD_XINPUT; - typestr = "XBox-like"; - break; + const char *typestr = NULL; + switch ( SDL_GameControllerGetType( gc ) ) { + default: // the other controller like luna, stadia, whatever, have a very similar layout + case SDL_CONTROLLER_TYPE_UNKNOWN: + case SDL_CONTROLLER_TYPE_XBOX360: + case SDL_CONTROLLER_TYPE_XBOXONE: + gamepadType = D3_GAMEPAD_XINPUT; + typestr = "XBox-like"; + break; - case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO: - case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT: - case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT: - case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR: - gamepadType = D3_GAMEPAD_NINTENDO; - typestr = "Nintendo-like"; - break; + case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO: + case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT: + case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT: + case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR: + gamepadType = D3_GAMEPAD_NINTENDO; + typestr = "Nintendo-like"; + break; - case SDL_CONTROLLER_TYPE_PS3: - gamepadType = D3_GAMEPAD_PLAYSTATION_OLD; - typestr = "Playstation2/3-like"; - break; - case SDL_CONTROLLER_TYPE_PS4: - case SDL_CONTROLLER_TYPE_PS5: - gamepadType = D3_GAMEPAD_PLAYSTATION; - typestr = "Playstation-like"; - break; + case SDL_CONTROLLER_TYPE_PS3: + gamepadType = D3_GAMEPAD_PLAYSTATION_OLD; + typestr = "Playstation2/3-like"; + break; + case SDL_CONTROLLER_TYPE_PS4: + case SDL_CONTROLLER_TYPE_PS5: + gamepadType = D3_GAMEPAD_PLAYSTATION; + typestr = "Playstation-like"; + break; } - common->Printf( "Detected Gamepad %s as type %s\n", SDL_GameControllerName( gc ), typestr ); - SDL_Joystick* joy = SDL_GameControllerGetJoystick( gc ); + SDL_Joystick *joy = SDL_GameControllerGetJoystick( gc ); SDL_JoystickGUID guid = SDL_JoystickGetGUID( joy ); char guidstr[34] = {}; - SDL_JoystickGetGUIDString( guid, guidstr, sizeof(guidstr) ); + SDL_JoystickGetGUIDString( guid, guidstr, sizeof( guidstr ) ); Uint16 vendor = SDL_GameControllerGetVendor( gc ); Uint16 product = SDL_GameControllerGetProduct( gc ); - const char* joyname = SDL_JoystickName( joy ); - + const char *joyname = SDL_JoystickName( joy ); common->Printf( " USB IDs: %.4hx:%.4hx Joystick Name: \"%s\" GUID: %s\n", vendor, product, joyname, guidstr ); #endif // SDL_VERSION_ATLEAST(2, 0, 12) @@ -906,22 +901,22 @@ static void setGamepadType( SDL_GameController* gc ) #endif // SDL2+ gamecontroller code -static void PushConsoleEvent(const char *s) { +static void PushConsoleEvent( const char *s ) { char *b; size_t len; - len = strlen(s) + 1; - b = (char *)Mem_Alloc(len); - strcpy(b, s); + len = strlen( s ) + 1; + b = ( char * )Mem_Alloc( len ); + strcpy( b, s ); SDL_Event event; event.type = SDL_USEREVENT; event.user.code = SE_CONSOLE; - event.user.data1 = (void *)len; + event.user.data1 = ( void * )len; event.user.data2 = b; - SDL_PushEvent(&event); + SDL_PushEvent( &event ); } /* @@ -930,21 +925,23 @@ Sys_InitInput ================= */ void Sys_InitInput() { - kbd_polls.SetGranularity(64); - mouse_polls.SetGranularity(64); + kbd_polls.SetGranularity( 64 ); + mouse_polls.SetGranularity( 64 ); - assert(sizeof(scancodemappings)/sizeof(scancodemappings[0]) == K_NUM_SCANCODES && "scancodemappings incomplete?"); + assert( sizeof( scancodemappings ) / sizeof( scancodemappings[0] ) == K_NUM_SCANCODES && "scancodemappings incomplete?" ); #if !SDL_VERSION_ATLEAST(2, 0, 0) - SDL_EnableUNICODE(1); - SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + SDL_EnableUNICODE( 1 ); + SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL ); #endif in_kbd.SetModified(); - Sys_GetConsoleKey(false); // initialize consoleKeymappingIdx from in_kbd + Sys_GetConsoleKey( false ); // initialize consoleKeymappingIdx from in_kbd + #if SDL_VERSION_ATLEAST(2, 0, 0) // NOTE: SDL3 doesn't support that hint/env var, but whatever, support the env var anyway - const char* grabKeyboardEnv = SDL_getenv("SDL_GRAB_KEYBOARD"); + const char *grabKeyboardEnv = SDL_getenv( "SDL_GRAB_KEYBOARD" ); + if ( grabKeyboardEnv ) { common->Printf( "The SDL_GRAB_KEYBOARD environment variable is set, setting the in_grabKeyboard CVar to the same value (%s)\n", grabKeyboardEnv ); in_grabKeyboard.SetString( grabKeyboardEnv ); @@ -955,34 +952,37 @@ void Sys_InitInput() { in_grabKeyboard.ClearModified(); #endif - joystick_polls.SetGranularity(64); - event_overflow.SetGranularity(64); + joystick_polls.SetGranularity( 64 ); + event_overflow.SetGranularity( 64 ); memset( buttonStates, 0, sizeof( buttonStates ) ); memset( joyAxis, 0, sizeof( joyAxis ) ); #if SDL_VERSION_ATLEAST(3, 0, 0) int numJoysticks = 0; - SDL_JoystickID* joysticks = SDL_GetJoysticks(&numJoysticks); - for( int i = 0; i < numJoysticks; ++i ) - { - SDL_GameController* gc = SDL_GameControllerOpen( joysticks[i] ); + + SDL_JoystickID *joysticks = SDL_GetJoysticks( &numJoysticks ); + + for ( int i = 0; i < numJoysticks; ++i ) { + SDL_GameController *gc = SDL_GameControllerOpen( joysticks[i] ); + if ( gc != NULL ) { setGamepadType( gc ); } } - SDL_free(joysticks); + SDL_free( joysticks ); #elif SDL_VERSION_ATLEAST(2, 0, 0) // use button positions instead of button labels, // Sys_GetLocalizedJoyKeyName() will do the translation // (I think this also was the default before 2.0.12?) - SDL_SetHint("SDL_GAMECONTROLLER_USE_BUTTON_LABELS", "0"); + SDL_SetHint( "SDL_GAMECONTROLLER_USE_BUTTON_LABELS", "0" ); const int NumJoysticks = SDL_NumJoysticks(); - for( int i = 0; i < NumJoysticks; ++i ) - { - SDL_GameController* gc = SDL_GameControllerOpen( i ); + + for ( int i = 0; i < NumJoysticks; ++i ) { + SDL_GameController *gc = SDL_GameControllerOpen( i ); + if ( gc != NULL ) { setGamepadType( gc ); } @@ -1015,14 +1015,14 @@ void Sys_InitScanTable() { struct ConsoleKeyMapping { - const char* langName; + const char *langName; unsigned char key; unsigned char keyShifted; }; static ConsoleKeyMapping consoleKeyMappings[] = { #if SDL_VERSION_ATLEAST(2, 0, 0) - { "auto", 0 , 0 }, // special case: set current keycode for SDL_SCANCODE_GRAVE (no shifted keycode, though) + { "auto", 0, 0 }, // special case: set current keycode for SDL_SCANCODE_GRAVE (no shifted keycode, though) #endif { "english", '`', '~' }, { "french", '<', '>' }, @@ -1036,26 +1036,28 @@ static ConsoleKeyMapping consoleKeyMappings[] = { static int consoleKeyMappingIdx = 0; static void initConsoleKeyMapping() { - const int numMappings = sizeof(consoleKeyMappings)/sizeof(consoleKeyMappings[0]); - + const int numMappings = sizeof( consoleKeyMappings ) / sizeof( consoleKeyMappings[0] ); idStr lang = in_kbd.GetString(); + consoleKeyMappingIdx = 0; #if SDL_VERSION_ATLEAST(2, 0, 0) consoleKeyMappings[0].key = 0; - if ( lang.Length() == 0 || lang.Icmp( "auto") == 0 ) { + if ( lang.Length() == 0 || lang.Icmp( "auto" ) == 0 ) { // auto-detection (SDL2-only) int keycode = SDL_GetKeyFromScancode( SDL_SCANCODE_GRAVE ); + if ( keycode > 0 && keycode <= 0xFF ) { // the SDL keycode and dhewm3 keycode should be identical for the mappings, // as it's ISO-8859-1 ("High ASCII") chars - for( int i=1; iPrintf( "Detected keyboard layout as \"%s\"\n", consoleKeyMappings[i].langName ); break; } } + if ( consoleKeyMappingIdx == 0 ) { // not found in known mappings consoleKeyMappings[0].key = keycode; } @@ -1063,14 +1065,15 @@ static void initConsoleKeyMapping() { } else #endif { - for( int i=1; iWarning( "in_kbd is set to \"%s\", but the actual keycode of the 'console key' is %c (%d), not %c (%d), so this might not work that well..\n", - lang.c_str(), (unsigned char)keycode, keycode, consoleKeyMappings[i].key, consoleKeyMappings[i].key ); + lang.c_str(), ( unsigned char )keycode, keycode, consoleKeyMappings[i].key, consoleKeyMappings[i].key ); } #endif break; @@ -1094,7 +1097,6 @@ unsigned char Sys_GetConsoleKey( bool shifted ) { initConsoleKeyMapping(); in_kbd.ClearModified(); } - return shifted ? consoleKeyMappings[consoleKeyMappingIdx].keyShifted : consoleKeyMappings[consoleKeyMappingIdx].key; } @@ -1103,7 +1105,7 @@ unsigned char Sys_GetConsoleKey( bool shifted ) { Sys_MapCharForKey =============== */ -unsigned char Sys_MapCharForKey(int key) { +unsigned char Sys_MapCharForKey( int key ) { return key & 0xff; } @@ -1115,10 +1117,10 @@ Note: Usually grabbing is handled in idCommonLocal::Frame() -> Sys_GenerateEvent common->Frame() won't be called for a while =============== */ -void Sys_GrabMouseCursor(bool grabIt) { - int flags = grabIt ? (GRAB_GRABMOUSE | GRAB_HIDECURSOR | GRAB_RELATIVEMOUSE) : 0; +void Sys_GrabMouseCursor( bool grabIt ) { + int flags = grabIt ? ( GRAB_GRABMOUSE | GRAB_HIDECURSOR | GRAB_RELATIVEMOUSE ) : 0; - GLimp_GrabInput(flags); + GLimp_GrabInput( flags ); } @@ -1137,9 +1139,9 @@ I hope this won't explode in my face :-p =============== */ bool D3_IN_interactiveIngameGuiActive = false; -void Sys_SetInteractiveIngameGuiActive( bool active, idUserInterface* ui ) -{ - static idList lastuis; +void Sys_SetInteractiveIngameGuiActive( bool active, idUserInterface *ui ) { + static idList lastuis; + if ( ui == NULL ) { // special case for clearing D3_IN_interactiveIngameGuiActive = false; @@ -1166,14 +1168,11 @@ void Sys_SetInteractiveIngameGuiActive( bool active, idUserInterface* ui ) // so D3_IN_interactiveIngameGuiActive remains true in that case // (the ingame UI is still in the list); the lastuis list is also needed // for the case of opening the PDA while an ingame GUI is focused - lastuis.RemoveIndex( idx ); } - D3_IN_interactiveIngameGuiActive = lastuis.Num() != 0; } - static void PushButton( int key, bool value ) { // So we don't keep sending the same SE_KEY message over and over again if ( buttonStates[key] != value ) { @@ -1181,7 +1180,7 @@ static void PushButton( int key, bool value ) { sysEvent_t res = { SE_KEY, key, value ? 1 : 0, 0, NULL }; // this is done to generate two events per controller axis event // one SE_JOYSTICK and one SE_KEY - event_overflow.Append(res); + event_overflow.Append( res ); } } @@ -1195,14 +1194,12 @@ sysEvent_t Sys_GetEvent() { sysEvent_t res = { }; int key; bool isDown = false; - static const sysEvent_t res_none = { SE_NONE, 0, 0, 0, NULL }; // process any overflow. - if (event_overflow.Num() > 0) - { + if ( event_overflow.Num() > 0 ) { res = event_overflow[0]; - event_overflow.RemoveIndex(0); + event_overflow.RemoveIndex( 0 ); return res; } @@ -1214,17 +1211,16 @@ sysEvent_t Sys_GetEvent() { static char s[128] = {0}; static size_t s_pos = 0; - if (s[0] != '\0') { + if ( s[0] != '\0' ) { res.evType = SE_CHAR; - res.evValue = (unsigned char)s[s_pos]; + res.evValue = ( unsigned char )s[s_pos]; ++s_pos; - if (!s[s_pos] || s_pos == sizeof(s)) { - memset(s, 0, sizeof(s)); + if ( !s[s_pos] || s_pos == sizeof( s ) ) { + memset( s, 0, sizeof( s ) ); s_pos = 0; } - return res; } #endif @@ -1234,101 +1230,103 @@ sysEvent_t Sys_GetEvent() { // It's 0 when not currently holding a char to generate an event static byte c = 0; - if (c) { + if ( c ) { res.evType = SE_CHAR; res.evValue = c; - c = 0; return res; } // loop until there is an event we care about (will return then) or no more events - while(SDL_PollEvent(&ev)) { - if(D3::ImGuiHooks::ProcessEvent(&ev)) { + while ( SDL_PollEvent( &ev ) ) { + if ( D3::ImGuiHooks::ProcessEvent( &ev ) ) { // ImGui has used the event, so it shouldn't also be handled by the game continue; } - switch (ev.type) { + switch ( ev.type ) { #if SDL_VERSION_ATLEAST(3, 0, 0) - case SDL_EVENT_WINDOW_FOCUS_GAINED: { - // unset modifier, in case alt-tab was used to leave window and ALT is still set - // as that can cause fullscreen-toggling when pressing enter... - SDL_Keymod currentmod = SDL_GetModState(); + case SDL_EVENT_WINDOW_FOCUS_GAINED: { + // unset modifier, in case alt-tab was used to leave window and ALT is still set + // as that can cause fullscreen-toggling when pressing enter... + SDL_Keymod currentmod = SDL_GetModState(); - int newmod = SDL_KMOD_NONE; - if (currentmod & SDL_KMOD_CAPS) // preserve capslock - newmod |= SDL_KMOD_CAPS; + int newmod = SDL_KMOD_NONE; - SDL_SetModState((SDL_Keymod)newmod); - } // new context because visual studio complains about newmod and currentmod not initialized because of the case SDL_WINDOWEVENT_FOCUS_LOST + if ( currentmod & SDL_KMOD_CAPS ) { // preserve capslock + newmod |= SDL_KMOD_CAPS; + } + SDL_SetModState( ( SDL_Keymod )newmod ); + } - in_hasFocus = true; + // new context because visual studio complains about newmod and currentmod not initialized because of the case SDL_WINDOWEVENT_FOCUS_LOST + in_hasFocus = true; - // start playing the game sound world again (when coming from editor) - session->SetPlayingSoundWorld(); - continue; // handle next event + // start playing the game sound world again (when coming from editor) + session->SetPlayingSoundWorld(); + continue; // handle next event - case SDL_EVENT_WINDOW_FOCUS_LOST: - in_hasFocus = false; - continue; // handle next event + case SDL_EVENT_WINDOW_FOCUS_LOST: + in_hasFocus = false; + continue; // handle next event - case SDL_EVENT_WINDOW_RESIZED: - case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: - GLimp_UpdateWindowSize(); - continue; // handle next event + case SDL_EVENT_WINDOW_RESIZED: + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: + GLimp_UpdateWindowSize(); + continue; // handle next event #elif SDL_VERSION_ATLEAST(2, 0, 0) case SDL_WINDOWEVENT: - switch (ev.window.event) { - case SDL_WINDOWEVENT_FOCUS_GAINED: { - // unset modifier, in case alt-tab was used to leave window and ALT is still set - // as that can cause fullscreen-toggling when pressing enter... - SDL_Keymod currentmod = SDL_GetModState(); - - int newmod = KMOD_NONE; - if (currentmod & KMOD_CAPS) // preserve capslock - newmod |= KMOD_CAPS; + switch ( ev.window.event ) { + case SDL_WINDOWEVENT_FOCUS_GAINED: { + // unset modifier, in case alt-tab was used to leave window and ALT is still set + // as that can cause fullscreen-toggling when pressing enter... + SDL_Keymod currentmod = SDL_GetModState(); - SDL_SetModState((SDL_Keymod)newmod); - } // new context because visual studio complains about newmod and currentmod not initialized because of the case SDL_WINDOWEVENT_FOCUS_LOST + int newmod = KMOD_NONE; - in_hasFocus = true; + if ( currentmod & KMOD_CAPS ) { // preserve capslock + newmod |= KMOD_CAPS; + } + SDL_SetModState( ( SDL_Keymod )newmod ); + } - // start playing the game sound world again (when coming from editor) - session->SetPlayingSoundWorld(); + // new context because visual studio complains about newmod and currentmod not initialized because of the case SDL_WINDOWEVENT_FOCUS_LOST + in_hasFocus = true; - break; - case SDL_WINDOWEVENT_FOCUS_LOST: - in_hasFocus = false; - break; - case SDL_WINDOWEVENT_SIZE_CHANGED: - GLimp_UpdateWindowSize(); - break; - } + // start playing the game sound world again (when coming from editor) + session->SetPlayingSoundWorld(); + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + in_hasFocus = false; + break; + case SDL_WINDOWEVENT_SIZE_CHANGED: + GLimp_UpdateWindowSize(); + break; + } continue; // handle next event #else - case SDL_ACTIVEEVENT: - { - if (ev.active.gain) { - in_hasFocus = true; + case SDL_ACTIVEEVENT: { + if ( ev.active.gain ) { + in_hasFocus = true; - // unset modifier, in case alt-tab was used to leave window and ALT is still set - // as that can cause fullscreen-toggling when pressing enter... - SDLMod currentmod = SDL_GetModState(); - int newmod = KMOD_NONE; - if (currentmod & KMOD_CAPS) // preserve capslock - newmod |= KMOD_CAPS; + // unset modifier, in case alt-tab was used to leave window and ALT is still set + // as that can cause fullscreen-toggling when pressing enter... + SDLMod currentmod = SDL_GetModState(); - SDL_SetModState((SDLMod)newmod); - } else { - in_hasFocus = false; + int newmod = KMOD_NONE; + + if ( currentmod & KMOD_CAPS ) { // preserve capslock + newmod |= KMOD_CAPS; } + SDL_SetModState( ( SDLMod )newmod ); + } else { + in_hasFocus = false; } - - continue; // handle next event + } + continue; // handle next event case SDL_VIDEOEXPOSE: continue; // handle next event @@ -1336,78 +1334,78 @@ sysEvent_t Sys_GetEvent() { case SDL_KEYDOWN: #if SDL_VERSION_ATLEAST(3, 0, 0) - if (ev.key.key == SDLK_RETURN && (ev.key.mod & SDL_KMOD_ALT) > 0) { + if ( ev.key.key == SDLK_RETURN && ( ev.key.mod & SDL_KMOD_ALT ) > 0 ) { #else - if (ev.key.keysym.sym == SDLK_RETURN && (ev.key.keysym.mod & KMOD_ALT) > 0) { + if ( ev.key.keysym.sym == SDLK_RETURN && ( ev.key.keysym.mod & KMOD_ALT ) > 0 ) { #endif - cvarSystem->SetCVarBool("r_fullscreen", !renderSystem->IsFullScreen()); - PushConsoleEvent("vid_restart partial"); + cvarSystem->SetCVarBool( "r_fullscreen", !renderSystem->IsFullScreen() ); + PushConsoleEvent( "vid_restart partial" ); return res_none; } - // fall through + // fall through case SDL_KEYUP: #if !SDL_VERSION_ATLEAST(2, 0, 0) // SDL1.2 - key = mapkey(ev.key.keysym.sym); - if (!key) { + key = mapkey( ev.key.keysym.sym ); + + if ( !key ) { if ( !in_ignoreConsoleKey.GetBool() ) { // check if its an unmapped console key - int c = Sys_GetConsoleKey( (ev.key.keysym.mod & KMOD_SHIFT) != 0 ); - if (ev.key.keysym.unicode == c) { + int c = Sys_GetConsoleKey( ( ev.key.keysym.mod & KMOD_SHIFT ) != 0 ); + + if ( ev.key.keysym.unicode == c ) { key = c; } } - if (!key) { - if (ev.type == SDL_KEYDOWN) + + if ( !key ) { + if ( ev.type == SDL_KEYDOWN ) { common->Warning( "unmapped SDL key %d (0x%x) - if possible use SDL2 for better keyboard support", ev.key.keysym.sym, ev.key.keysym.unicode ); + } continue; // handle next event } } #else // SDL2+ - { - #if SDL_VERSION_ATLEAST(3, 0, 0) - SDL_Scancode sc = ev.key.scancode; - SDL_Keycode keycode = ev.key.key; - #else // SDL2 - SDL_Scancode sc = ev.key.keysym.scancode; - SDL_Keycode keycode = ev.key.keysym.sym; - #endif - // workaround for AZERTY-keyboards, which don't have 1, 2, ..., 9, 0 in first row: - // always map those physical keys (scancodes) to those keycodes anyway - // see also https://bugzilla.libsdl.org/show_bug.cgi?id=3188 - if(sc == SDL_SCANCODE_0) - { - key = '0'; - } - else if(sc >= SDL_SCANCODE_1 && sc <= SDL_SCANCODE_9) - { - // note that the SDL_SCANCODEs are SDL_SCANCODE_1, _2, ..., _9, SDL_SCANCODE_0 - // while in ASCII it's '0', '1', ..., '9' => handle 0 and 1-9 separately - // (doom3 uses the ASCII values for those keys) - key = '1' + (sc - SDL_SCANCODE_1); - } - else { - key = mapkey(keycode); - } +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_Scancode sc = ev.key.scancode; + SDL_Keycode keycode = ev.key.key; +#else // SDL2 + SDL_Scancode sc = ev.key.keysym.scancode; + SDL_Keycode keycode = ev.key.keysym.sym; +#endif + // workaround for AZERTY-keyboards, which don't have 1, 2, ..., 9, 0 in first row: + // always map those physical keys (scancodes) to those keycodes anyway + // see also https://bugzilla.libsdl.org/show_bug.cgi?id=3188 + if ( sc == SDL_SCANCODE_0 ) { + key = '0'; + } else if ( sc >= SDL_SCANCODE_1 && sc <= SDL_SCANCODE_9 ) { + // note that the SDL_SCANCODEs are SDL_SCANCODE_1, _2, ..., _9, SDL_SCANCODE_0 + // while in ASCII it's '0', '1', ..., '9' => handle 0 and 1-9 separately + // (doom3 uses the ASCII values for those keys) + key = '1' + ( sc - SDL_SCANCODE_1 ); + } else { + key = mapkey( keycode ); + } - if ( !in_ignoreConsoleKey.GetBool() && sc == SDL_SCANCODE_GRAVE ) { - // that key between Esc, Tab and 1 is the console key - key = K_CONSOLE; - } + if ( !in_ignoreConsoleKey.GetBool() && sc == SDL_SCANCODE_GRAVE ) { + // that key between Esc, Tab and 1 is the console key + key = K_CONSOLE; + } - if ( !key ) { - // if the key couldn't be mapped so far, try to map the scancode to K_SC_* - key = getKeynumForSDLscancode(sc); - if(!key) { - if (ev.type == SDL_KEYDOWN) { - common->Warning("unmapped SDL key %d (scancode %d)", keycode, (int)sc); + if ( !key ) { + // if the key couldn't be mapped so far, try to map the scancode to K_SC_* + key = getKeynumForSDLscancode( sc ); + + if ( !key ) { + if ( ev.type == SDL_KEYDOWN ) { + common->Warning( "unmapped SDL key %d (scancode %d)", keycode, ( int )sc ); + } + continue; // handle next event } - continue; // handle next event } } - } #endif isDown = IS_SDL_BTN_DOWN( ev.key ); @@ -1418,39 +1416,41 @@ sysEvent_t Sys_GetEvent() { kbd_polls.Append( kbd_poll_t( key, isDown ) ); #if SDL_VERSION_ATLEAST(2, 0, 0) - if (key == K_BACKSPACE && isDown) + if ( key == K_BACKSPACE && isDown ) { c = key; + } #else - if (ev.key.state == SDL_PRESSED && (ev.key.keysym.unicode & 0xff00) == 0) + if ( ev.key.state == SDL_PRESSED && ( ev.key.keysym.unicode & 0xff00 ) == 0 ) { c = ev.key.keysym.unicode & 0xff; + } #endif // Note: c will be sent as SE_CHAR next time this function is called - return res; #if SDL_VERSION_ATLEAST(2, 0, 0) case SDL_TEXTINPUT: - if (ev.text.text[0]) { + if ( ev.text.text[0] ) { res.evType = SE_CHAR; - if ( isAscii(ev.text.text) ) { + if ( isAscii( ev.text.text ) ) { res.evValue = ev.text.text[0]; + if ( ev.text.text[1] != '\0' ) { - #if SDL_VERSION_ATLEAST(3, 0, 0) +#if SDL_VERSION_ATLEAST(3, 0, 0) // yes, it's ok if this is not 0-terminated, the code generating // events from s handles that - strncpy(s, ev.text.text, sizeof(s)); - #else // SDL2 + strncpy( s, ev.text.text, sizeof( s ) ); +#else // SDL2 memcpy( s, ev.text.text, SDL_TEXTINPUTEVENT_TEXT_SIZE ); s[SDL_TEXTINPUTEVENT_TEXT_SIZE] = '\0'; - #endif +#endif // pos 0 is returned, the rest of s is returned as SE_CHAR events // at the next times this function is called s_pos = 1; } return res; - } else if( D3_UTF8toISO8859_1( ev.text.text, s, sizeof(s) ) && s[0] != '\0' ) { - res.evValue = (unsigned char)s[0]; + } else if ( D3_UTF8toISO8859_1( ev.text.text, s, sizeof( s ) ) && s[0] != '\0' ) { + res.evValue = ( unsigned char )s[0]; if ( s[1] == '\0' ) { s_pos = 0; s[0] = '\0'; @@ -1462,7 +1462,6 @@ sysEvent_t Sys_GetEvent() { return res; } } - continue; // handle next event #endif @@ -1472,28 +1471,26 @@ sysEvent_t Sys_GetEvent() { res.evValue = ev.motion.xrel; res.evValue2 = ev.motion.yrel; - mouse_polls.Append(mouse_poll_t(M_DELTAX, ev.motion.xrel)); - mouse_polls.Append(mouse_poll_t(M_DELTAY, ev.motion.yrel)); + mouse_polls.Append( mouse_poll_t( M_DELTAX, ev.motion.xrel ) ); + mouse_polls.Append( mouse_poll_t( M_DELTAY, ev.motion.yrel ) ); } else { res.evType = SE_MOUSE_ABS; res.evValue = ev.motion.x; res.evValue2 = ev.motion.y; } - return res; #if SDL_VERSION_ATLEAST(2, 0, 0) case SDL_MOUSEWHEEL: res.evType = SE_KEY; - if (ev.wheel.y > 0) { + if ( ev.wheel.y > 0 ) { res.evValue = K_MWHEELUP; - mouse_polls.Append(mouse_poll_t(M_DELTAZ, 1)); - } else if (ev.wheel.y < 0) { + mouse_polls.Append( mouse_poll_t( M_DELTAZ, 1 ) ); + } else if ( ev.wheel.y < 0 ) { res.evValue = K_MWHEELDOWN; - mouse_polls.Append(mouse_poll_t(M_DELTAZ, -1)); + mouse_polls.Append( mouse_poll_t( M_DELTAZ, -1 ) ); } - res.evValue2 = 1; return res; @@ -1501,63 +1498,60 @@ sysEvent_t Sys_GetEvent() { case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: - isDown = IS_SDL_BTN_DOWN(ev.button); + isDown = IS_SDL_BTN_DOWN( ev.button ); res.evType = SE_KEY; - switch (ev.button.button) { + switch ( ev.button.button ) { case SDL_BUTTON_LEFT: res.evValue = K_MOUSE1; - mouse_polls.Append(mouse_poll_t(M_ACTION1, isDown)); + mouse_polls.Append( mouse_poll_t( M_ACTION1, isDown ) ); break; case SDL_BUTTON_MIDDLE: res.evValue = K_MOUSE3; - mouse_polls.Append(mouse_poll_t(M_ACTION3, isDown)); + mouse_polls.Append( mouse_poll_t( M_ACTION3, isDown ) ); break; case SDL_BUTTON_RIGHT: res.evValue = K_MOUSE2; - mouse_polls.Append(mouse_poll_t(M_ACTION2, isDown)); + mouse_polls.Append( mouse_poll_t( M_ACTION2, isDown ) ); break; #if !SDL_VERSION_ATLEAST(2, 0, 0) case SDL_BUTTON_WHEELUP: res.evValue = K_MWHEELUP; - if (ev.button.state == SDL_PRESSED) - mouse_polls.Append(mouse_poll_t(M_DELTAZ, 1)); + if ( ev.button.state == SDL_PRESSED ) { + mouse_polls.Append( mouse_poll_t( M_DELTAZ, 1 ) ); + } break; case SDL_BUTTON_WHEELDOWN: res.evValue = K_MWHEELDOWN; - if (ev.button.state == SDL_PRESSED) - mouse_polls.Append(mouse_poll_t(M_DELTAZ, -1)); + if ( ev.button.state == SDL_PRESSED ) { + mouse_polls.Append( mouse_poll_t( M_DELTAZ, -1 ) ); + } break; #endif default: #if SDL_VERSION_ATLEAST(2, 0, 0) // handle X1 button and above - if( ev.button.button < SDL_BUTTON_LEFT + 8 ) // doesn't support more than 8 mouse buttons - { + if ( ev.button.button < SDL_BUTTON_LEFT + 8 ) { // doesn't support more than 8 mouse buttons int buttonIndex = ev.button.button - SDL_BUTTON_LEFT; res.evValue = K_MOUSE1 + buttonIndex; mouse_polls.Append( mouse_poll_t( M_ACTION1 + buttonIndex, isDown ) ); - } - else + } else #endif - continue; // handle next event + continue; // handle next event } - res.evValue2 = isDown; return res; #if SDL_VERSION_ATLEAST(2, 0, 0) // gamecontroller/gamepad not supported in SDL1 case SDL_CONTROLLERBUTTONDOWN: - case SDL_CONTROLLERBUTTONUP: - { + case SDL_CONTROLLERBUTTONUP: { if ( !in_useGamepad.GetBool() ) { common->Warning( "Gamepad support is disabled! Set the in_useGamepad CVar to 1 to enable it!\n" ); continue; } - - isDown = IS_SDL_BTN_DOWN(ev.cbutton); + isDown = IS_SDL_BTN_DOWN( ev.cbutton ); res.evType = SE_KEY; res.evValue2 = isDown; @@ -1567,30 +1561,27 @@ sysEvent_t Sys_GetEvent() { if ( ev.cbutton.button == SDL_CONTROLLER_BUTTON_START ) { res.evValue = K_ESCAPE; return res; - } else if( (ev.cbutton.button == SDL_CONTROLLER_BUTTON_A || ev.cbutton.button == SDL_CONTROLLER_BUTTON_Y) - && D3_IN_interactiveIngameGuiActive && sessLocal.GetActiveMenu() == NULL ) - { + } else if ( ( ev.cbutton.button == SDL_CONTROLLER_BUTTON_A || ev.cbutton.button == SDL_CONTROLLER_BUTTON_Y ) + && D3_IN_interactiveIngameGuiActive && sessLocal.GetActiveMenu() == NULL ) { // ugly hack: currently an interactive ingame GUI (with a cursor) is active/focused // so pretend that the gamepads A (south) or Y (north, used by D3BFG to click ingame GUIs) button // is the left mouse button so it can be used for "clicking".. - mouse_polls.Append( mouse_poll_t(M_ACTION1, res.evValue2) ); + mouse_polls.Append( mouse_poll_t( M_ACTION1, res.evValue2 ) ); res.evValue = K_MOUSE1; return res; } + sys_jEvents jEvent = mapjoybutton( ( SDL_GameControllerButton )ev.cbutton.button ); - sys_jEvents jEvent = mapjoybutton( (SDL_GameControllerButton)ev.cbutton.button ); - joystick_polls.Append( joystick_poll_t(jEvent, isDown) ); + joystick_polls.Append( joystick_poll_t( jEvent, isDown ) ); if ( ( jEvent >= J_ACTION_FIRST ) && ( jEvent <= J_ACTION_MAX ) ) { res.evValue = K_FIRST_JOY + ( jEvent - J_ACTION_FIRST ); return res; } - continue; // try to get a decent event. } - case SDL_CONTROLLERAXISMOTION: - { + case SDL_CONTROLLERAXISMOTION: { const int range = 16384; if ( !in_useGamepad.GetBool() ) { @@ -1598,9 +1589,9 @@ sysEvent_t Sys_GetEvent() { // TODO: or print a message if value is big enough? continue; } + sys_jEvents jEvent = mapjoyaxis( ( SDL_GameControllerAxis )ev.caxis.axis ); - sys_jEvents jEvent = mapjoyaxis( (SDL_GameControllerAxis)ev.caxis.axis); - joystick_polls.Append(joystick_poll_t( jEvent, ev.caxis.value) ); + joystick_polls.Append( joystick_poll_t( jEvent, ev.caxis.value ) ); if ( jEvent == J_AXIS_LEFT_X ) { PushButton( K_JOY_STICK1_LEFT, ( ev.caxis.value < -range ) ); @@ -1619,26 +1610,26 @@ sysEvent_t Sys_GetEvent() { } else if ( jEvent == J_AXIS_RIGHT_TRIG ) { PushButton( K_JOY_TRIGGER2, ( ev.caxis.value > range ) ); } + if ( jEvent >= J_AXIS_MIN && jEvent <= J_AXIS_MAX ) { // NOTE: the stuff set here is only used to move the cursor in menus // ingame movement is done via joystick_polls int axis = jEvent - J_AXIS_MIN; float dz = joy_deadZone.GetFloat(); + float val = fabsf( ev.caxis.value * ( 1.0f / 32767.0f ) ); - float val = fabsf(ev.caxis.value * (1.0f / 32767.0f)); - if(val < dz) { + if ( val < dz ) { val = 0.0f; } else { // from deadzone .. 1 to 0 .. 1-deadzone val -= dz; // and then to 0..1 - val = val * (1.0f / (1.0f - dz)); + val = val * ( 1.0f / ( 1.0f - dz ) ); - if( ev.caxis.value < 0 ) { + if ( ev.caxis.value < 0 ) { val = -val; } } - joyAxis[axis] = val; } @@ -1648,9 +1639,8 @@ sysEvent_t Sys_GetEvent() { } break; - case SDL_JOYDEVICEADDED: - { - SDL_GameController* gc = SDL_GameControllerOpen( ev.jdevice.which ); + case SDL_JOYDEVICEADDED: { + SDL_GameController *gc = SDL_GameControllerOpen( ev.jdevice.which ); if ( gc != NULL ) { setGamepadType( gc ); } @@ -1665,18 +1655,18 @@ sysEvent_t Sys_GetEvent() { #endif // SDL2+ case SDL_QUIT: - PushConsoleEvent("quit"); + PushConsoleEvent( "quit" ); return res_none; case SDL_USEREVENT: - switch (ev.user.code) { + switch ( ev.user.code ) { case SE_CONSOLE: res.evType = SE_CONSOLE; - res.evPtrLength = (intptr_t)ev.user.data1; + res.evPtrLength = ( intptr_t )ev.user.data1; res.evPtr = ev.user.data2; return res; default: - common->Warning("unknown user event %u", ev.user.code); + common->Warning( "unknown user event %u", ev.user.code ); continue; // handle next event } default: @@ -1693,22 +1683,22 @@ sysEvent_t Sys_GetEvent() { static unsigned int lastMS = 0; static int joyAxisToSend = 0; unsigned int nowMS = Sys_Milliseconds(); + if ( nowMS - lastMS >= 16 ) { int val = joyAxis[joyAxisToSend] * 100; // float to percent res.evType = SE_JOYSTICK; res.evValue = joyAxisToSend; res.evValue2 = val; ++joyAxisToSend; - if(joyAxisToSend == MAX_JOYSTICK_AXIS) { + + if ( joyAxisToSend == MAX_JOYSTICK_AXIS ) { // we're done for this frame, so update lastMS and reset joyAxisToSend joyAxisToSend = 0; lastMS = nowMS; } return res; } - } - return res_none; } @@ -1720,17 +1710,16 @@ Sys_ClearEvents void Sys_ClearEvents() { SDL_Event ev; - while (SDL_PollEvent(&ev)) - ; + while ( SDL_PollEvent( &ev ) ); - kbd_polls.SetNum(0, false); - mouse_polls.SetNum(0, false); - joystick_polls.SetNum(0, false); + kbd_polls.SetNum( 0, false ); + mouse_polls.SetNum( 0, false ); + joystick_polls.SetNum( 0, false ); memset( buttonStates, 0, sizeof( buttonStates ) ); memset( joyAxis, 0, sizeof( joyAxis ) ); - event_overflow.SetNum(0, false); + event_overflow.SetNum( 0, false ); } static void handleMouseGrab() { @@ -1741,7 +1730,6 @@ static void handleMouseGrab() { bool grabMouse = false; bool relativeMouse = false; bool enableTextInput = false; - const bool imguiHasFocus = D3::ImGuiHooks::ShouldShowCursor(); // if com_editorActive, release everything, just like when we have no focus @@ -1766,7 +1754,6 @@ static void handleMouseGrab() { showCursor = false; grabMouse = relativeMouse = true; } - in_relativeMouseMode = relativeMouse; // if in_nograb is set, in_relativeMouseMode and relativeMouse can disagree @@ -1782,17 +1769,23 @@ static void handleMouseGrab() { // in theory, ImGui handles that itself, but currently GLimp_GrabInput() seems to override it enableTextInput = imguiHasFocus; } - int flags = 0; - if ( !showCursor ) + + if ( !showCursor ) { flags |= GRAB_HIDECURSOR; - if ( grabMouse ) + } + + if ( grabMouse ) { flags |= GRAB_GRABMOUSE; - if ( relativeMouse ) + } + + if ( relativeMouse ) { flags |= GRAB_RELATIVEMOUSE; - if ( enableTextInput ) - flags |= GRAB_ENABLETEXTINPUT; + } + if ( enableTextInput ) { + flags |= GRAB_ENABLETEXTINPUT; + } GLimp_GrabInput( flags ); } @@ -1807,8 +1800,9 @@ void Sys_GenerateEvents() { char *s = Sys_ConsoleInput(); - if (s) - PushConsoleEvent(s); + if ( s ) { + PushConsoleEvent( s ); + } // doesn't make sense on dedicated server and SDL3 handles this in GLimp_GrabInput() #if !defined(ID_DEDICATED) && ! SDL_VERSION_ATLEAST(3, 0, 0) @@ -1826,7 +1820,6 @@ void Sys_GenerateEvents() { in_grabKeyboard.ClearModified(); } #endif - SDL_PumpEvents(); } @@ -1844,10 +1837,10 @@ int Sys_PollKeyboardInputEvents() { Sys_ReturnKeyboardInputEvent ================ */ -int Sys_ReturnKeyboardInputEvent(const int n, int &key, bool &state) { - if (n >= kbd_polls.Num()) +int Sys_ReturnKeyboardInputEvent( const int n, int &key, bool &state ) { + if ( n >= kbd_polls.Num() ) { return 0; - + } key = kbd_polls[n].key; state = kbd_polls[n].state; return 1; @@ -1859,7 +1852,7 @@ Sys_EndKeyboardInputEvents ================ */ void Sys_EndKeyboardInputEvents() { - kbd_polls.SetNum(0, false); + kbd_polls.SetNum( 0, false ); } /* @@ -1876,10 +1869,10 @@ int Sys_PollMouseInputEvents() { Sys_ReturnMouseInputEvent ================ */ -int Sys_ReturnMouseInputEvent(const int n, int &action, int &value) { - if (n >= mouse_polls.Num()) +int Sys_ReturnMouseInputEvent( const int n, int &action, int &value ) { + if ( n >= mouse_polls.Num() ) { return 0; - + } action = mouse_polls[n].action; value = mouse_polls[n].value; return 1; @@ -1891,7 +1884,7 @@ Sys_EndMouseInputEvents ================ */ void Sys_EndMouseInputEvents() { - mouse_polls.SetNum(0, false); + mouse_polls.SetNum( 0, false ); } /* @@ -1901,27 +1894,28 @@ Joystick Input Methods */ void Sys_SetRumble( int device, int low, int hi ) { // TODO: support multiple controllers. - assert(device == 0); + assert( device == 0 ); + // TODO: support rumble maybe. - assert(0); + assert( 0 ); } int Sys_PollJoystickInputEvents( int deviceNum ) { // TODO: support multiple controllers. - assert(deviceNum == 0); + assert( deviceNum == 0 ); return joystick_polls.Num(); } int Sys_ReturnJoystickInputEvent( const int n, int &action, int &value ) { - if (n >= joystick_polls.Num()) + if ( n >= joystick_polls.Num() ) { return 0; - + } action = joystick_polls[n].action; value = joystick_polls[n].value; return 1; } void Sys_EndJoystickInputEvents() { - joystick_polls.SetNum(0, false); + joystick_polls.SetNum( 0, false ); } diff --git a/neo/sys/glimp.cpp b/neo/sys/glimp.cpp index e554d7a10..357f4c939 100644 --- a/neo/sys/glimp.cpp +++ b/neo/sys/glimp.cpp @@ -29,20 +29,18 @@ If you have questions concerning this license or the applicable additional terms #include "sys/sys_sdl.h" #if SDL_VERSION_ATLEAST(3, 0, 0) - // backwards-compat with SDL2 - #define SDL_WINDOW_ALLOW_HIGHDPI SDL_WINDOW_HIGH_PIXEL_DENSITY - #define SDL_GL_DeleteContext SDL_GL_DestroyContext - typedef SDL_WindowFlags My_SDL_WindowFlags; +// backwards-compat with SDL2 +#define SDL_WINDOW_ALLOW_HIGHDPI SDL_WINDOW_HIGH_PIXEL_DENSITY +#define SDL_GL_DeleteContext SDL_GL_DestroyContext +typedef SDL_WindowFlags My_SDL_WindowFlags; #else // SDL1.2 or SDL2 - // for compat with SDL3 - unfortunately SDL2 also has a SDL_WindowFlags type, but it's an enum - typedef Uint32 My_SDL_WindowFlags; +// for compat with SDL3 - unfortunately SDL2 also has a SDL_WindowFlags type, but it's an enum +typedef Uint32 My_SDL_WindowFlags; #endif #include "sys/platform.h" #include "framework/Licensee.h" - #include "renderer/tr_local.h" - #include "sys/sys_imgui.h" #if defined(_WIN32) && defined(ID_ALLOW_TOOLS) @@ -50,7 +48,7 @@ If you have questions concerning this license or the applicable additional terms // SDL3 doesn't have SDL_syswm.h #if ! SDL_VERSION_ATLEAST(3, 0, 0) - #include +#include #endif // from SDL_windowsopengl.h (internal SDL2 header) @@ -126,22 +124,20 @@ static SDL_Surface *window = NULL; extern idCVar in_grabKeyboard; -static void SetSDLIcon() -{ - #include "doom_icon.h" // contains the struct d3_icon +static void SetSDLIcon() { +#include "doom_icon.h" // contains the struct d3_icon - SDL_Surface* icon = SDL_CreateSurfaceFrom(d3_icon.width, d3_icon.height, - SDL_PIXELFORMAT_RGBA32, (void*)d3_icon.pixel_data, - d3_icon.bytes_per_pixel*d3_icon.width); + SDL_Surface *icon = SDL_CreateSurfaceFrom( d3_icon.width, d3_icon.height, + SDL_PIXELFORMAT_RGBA32, ( void * )d3_icon.pixel_data, + d3_icon.bytes_per_pixel * d3_icon.width ); - SDL_SetWindowIcon(window, icon); - SDL_DestroySurface(icon); + SDL_SetWindowIcon( window, icon ); + SDL_DestroySurface( icon ); } #else // SDL2 and SDL1.2 -static void SetSDLIcon() -{ +static void SetSDLIcon() { Uint32 rmask, gmask, bmask, amask; // ok, the following is pretty stupid.. SDL_CreateRGBSurfaceFrom() pretends to use a void* for the data, @@ -158,19 +154,19 @@ static void SetSDLIcon() amask = 0xff000000; #endif - #include "doom_icon.h" // contains the struct d3_icon +#include "doom_icon.h" // contains the struct d3_icon - SDL_Surface* icon = SDL_CreateRGBSurfaceFrom((void*)d3_icon.pixel_data, d3_icon.width, d3_icon.height, - d3_icon.bytes_per_pixel*8, d3_icon.bytes_per_pixel*d3_icon.width, - rmask, gmask, bmask, amask); + SDL_Surface *icon = SDL_CreateRGBSurfaceFrom( ( void * )d3_icon.pixel_data, d3_icon.width, d3_icon.height, + d3_icon.bytes_per_pixel * 8, d3_icon.bytes_per_pixel * d3_icon.width, + rmask, gmask, bmask, amask ); #if SDL_VERSION_ATLEAST(2, 0, 0) - SDL_SetWindowIcon(window, icon); + SDL_SetWindowIcon( window, icon ); #else - SDL_WM_SetIcon(icon, NULL); + SDL_WM_SetIcon( icon, NULL ); #endif - SDL_FreeSurface(icon); + SDL_FreeSurface( icon ); } #endif // SDL2 and SDL1.2 @@ -179,20 +175,19 @@ static void SetSDLIcon() GLimp_Init =================== */ -bool GLimp_Init(glimpParms_t parms) { - common->Printf("Initializing OpenGL subsystem\n"); +bool GLimp_Init( glimpParms_t parms ) { + common->Printf( "Initializing OpenGL subsystem\n" ); - assert(SDL_WasInit(SDL_INIT_VIDEO)); + assert( SDL_WasInit( SDL_INIT_VIDEO ) ); My_SDL_WindowFlags flags = SDL_WINDOW_OPENGL; - if (parms.fullScreen == 1) - { + if ( parms.fullScreen == 1 ) { #if SDL_VERSION_ATLEAST(3, 0, 0) // in SDL3 windows with SDL_WINDOW_FULLSCREEN set are fullscreen-desktop by default // and for exclusive fullscreen SDL_SetWindowFullscreenMode() must be called // after creating the window, so only set the flag if we want fullscreen-desktop mode - if(parms.fullScreen && parms.fullScreenDesktop) { + if ( parms.fullScreen && parms.fullScreenDesktop ) { flags |= SDL_WINDOW_FULLSCREEN; } #elif SDL_VERSION_ATLEAST(2, 0, 0) @@ -202,8 +197,8 @@ bool GLimp_Init(glimpParms_t parms) { #endif } - r_windowResizable.ClearModified(); + #if SDL_VERSION_ATLEAST(2, 0, 0) flags |= SDL_WINDOW_ALLOW_HIGHDPI; @@ -233,18 +228,18 @@ bool GLimp_Init(glimpParms_t parms) { * I don't enable this hack by default. If r_fillWindowAlphaChan == 1, it's enabled * when creating the window, though. */ - #ifdef SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY - SDL_SetHint(SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY, "1"); - #elif SDL_MAJOR_VERSION == 2 // little hack so this works if the SDL2 version used for building is older than runtime version - SDL_SetHint("SDL_VIDEO_EGL_ALLOW_TRANSPARENCY", "1"); - #endif +#ifdef SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY + SDL_SetHint( SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY, "1" ); +#elif SDL_MAJOR_VERSION == 2 // little hack so this works if the SDL2 version used for building is older than runtime version + SDL_SetHint( "SDL_VIDEO_EGL_ALLOW_TRANSPARENCY", "1" ); #endif +#endif int colorbits = 24; int depthbits = 24; int stencilbits = 8; - for (int i = 0; i < 16; i++) { + for ( int i = 0; i < 16; i++ ) { int multisamples = parms.multiSamples; @@ -252,278 +247,276 @@ bool GLimp_Init(glimpParms_t parms) { // 1 - minus colorbits // 2 - minus depthbits // 3 - minus stencil - if ((i % 4) == 0 && i) { + if ( ( i % 4 ) == 0 && i ) { // one pass, reduce - switch (i / 4) { + switch ( i / 4 ) { case 2 : - if (colorbits == 24) + if ( colorbits == 24 ) { colorbits = 16; + } break; case 1 : - if (depthbits == 24) + if ( depthbits == 24 ) { depthbits = 16; - else if (depthbits == 16) + } else if ( depthbits == 16 ) { depthbits = 8; + } case 3 : - if (stencilbits == 24) + if ( stencilbits == 24 ) { stencilbits = 16; - else if (stencilbits == 16) + } else if ( stencilbits == 16 ) { stencilbits = 8; + } } } - int tcolorbits = colorbits; int tdepthbits = depthbits; int tstencilbits = stencilbits; - if ((i % 4) == 3) { + if ( ( i % 4 ) == 3 ) { // reduce colorbits - if (tcolorbits == 24) + if ( tcolorbits == 24 ) { tcolorbits = 16; + } } - if ((i % 4) == 2) { + if ( ( i % 4 ) == 2 ) { // reduce depthbits - if (tdepthbits == 24) + if ( tdepthbits == 24 ) { tdepthbits = 16; - else if (tdepthbits == 16) + } else if ( tdepthbits == 16 ) { tdepthbits = 8; + } } - if ((i % 4) == 1) { + if ( ( i % 4 ) == 1 ) { // reduce stencilbits - if (tstencilbits == 24) + if ( tstencilbits == 24 ) { tstencilbits = 16; - else if (tstencilbits == 16) + } else if ( tstencilbits == 16 ) { tstencilbits = 8; - else + } else { tstencilbits = 0; + } } - int channelcolorbits = 4; - if (tcolorbits == 24) - channelcolorbits = 8; + if ( tcolorbits == 24 ) { + channelcolorbits = 8; + } int talphabits = channelcolorbits; try_again: + SDL_GL_SetAttribute( SDL_GL_RED_SIZE, channelcolorbits ); + SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, channelcolorbits ); + SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, channelcolorbits ); + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); + SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, tdepthbits ); + SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, tstencilbits ); - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, channelcolorbits); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, channelcolorbits); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, channelcolorbits); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, tdepthbits); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, tstencilbits); - - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, talphabits); + SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, talphabits ); - SDL_GL_SetAttribute(SDL_GL_STEREO, parms.stereo ? 1 : 0); + SDL_GL_SetAttribute( SDL_GL_STEREO, parms.stereo ? 1 : 0 ); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (multisamples > 1) ? 1 : 0); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, multisamples); + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, ( multisamples > 1 ) ? 1 : 0 ); + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, multisamples ); #if SDL_VERSION_ATLEAST(2, 0, 0) // SDL2 and SDL3 window creation if ( r_glDebugContext.GetBool() ) { common->Printf( "Requesting an OpenGL Debug Context (r_glDebugContext is enabled)\n" ); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG ); } if ( parms.fullScreen && parms.fullScreenDesktop ) { common->Printf( "Will create a pseudo-fullscreen window at the current desktop resolution\n" ); } else { - const char* windowMode = parms.fullScreen ? "fullscreen-" : ""; - common->Printf("Will create a %swindow with resolution %dx%d (r_mode = %d)\n", - windowMode, parms.width, parms.height, r_mode.GetInteger()); + const char *windowMode = parms.fullScreen ? "fullscreen-" : ""; + common->Printf( "Will create a %swindow with resolution %dx%d (r_mode = %d)\n", + windowMode, parms.width, parms.height, r_mode.GetInteger() ); } - Uint32 selectedDisplay = 0; - #if SDL_VERSION_ATLEAST(2, 0, 4) + +#if SDL_VERSION_ATLEAST(2, 0, 4) // try to put the window on the display the mousecursor currently is on { - #if SDL_VERSION_ATLEAST(3, 0, 0) +#if SDL_VERSION_ATLEAST(3, 0, 0) float x, y; int numDisplays = 0; - SDL_DisplayID* displayIDs = SDL_GetDisplays(&numDisplays); - #else // SDL2 + SDL_DisplayID *displayIDs = SDL_GetDisplays( &numDisplays ); +#else // SDL2 int numDisplays = SDL_GetNumVideoDisplays(); int x, y; - #endif - - SDL_GetGlobalMouseState(&x, &y); - - common->Printf("SDL detected %d displays: \n", numDisplays); +#endif + SDL_GetGlobalMouseState( &x, &y ); + common->Printf( "SDL detected %d displays: \n", numDisplays ); bool found = false; - for ( int j=0; jPrintf( " Display %d (ID %u) has the following modes:\n", j, displayId_x ); - for ( int dmIdx=0; dmIdx < numModes; ++dmIdx ) { - SDL_DisplayMode* mode = modes[dmIdx]; + for ( int dmIdx = 0; dmIdx < numModes; ++dmIdx ) { + SDL_DisplayMode *mode = modes[dmIdx]; common->Printf( " - %d x %d @ %g Hz, density %g \n", mode->w, mode->h, mode->refresh_rate, mode->pixel_density ); } SDL_free( modes ); - if ( SDL_GetDisplayBounds(displayId_x, &rect) ) { - common->Printf(" Currently: %dx%d at (%d, %d) to (%d, %d)\n", rect.w, rect.h, - rect.x, rect.y, rect.x+rect.w, rect.y+rect.h); - #else // SDL2 + if ( SDL_GetDisplayBounds( displayId_x, &rect ) ) { + common->Printf( " Currently: %dx%d at (%d, %d) to (%d, %d)\n", rect.w, rect.h, + rect.x, rect.y, rect.x + rect.w, rect.y + rect.h ); +#else // SDL2 int displayId_x = j; - if (SDL_GetDisplayBounds(displayId_x, &rect) == 0) { - common->Printf(" %d: %dx%d at (%d, %d) to (%d, %d)\n", j, rect.w, rect.h, - rect.x, rect.y, rect.x+rect.w, rect.y+rect.h); - #endif + if ( SDL_GetDisplayBounds( displayId_x, &rect ) == 0 ) { + common->Printf( " %d: %dx%d at (%d, %d) to (%d, %d)\n", j, rect.w, rect.h, + rect.x, rect.y, rect.x + rect.w, rect.y + rect.h ); +#endif if ( !found && x >= rect.x && x < rect.x + rect.w - && y >= rect.y && y < rect.y + rect.h ) - { + && y >= rect.y && y < rect.y + rect.h ) { selectedDisplay = j; found = true; } } } - #if SDL_VERSION_ATLEAST(3, 0, 0) - if(displayIDs != NULL) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + if ( displayIDs != NULL ) { SDL_DisplayID displayID = displayIDs[selectedDisplay]; - common->Printf("Will use display %u (%u) because mouse cursor is at (%g, %g).\n", - selectedDisplay, displayID, x, y); + common->Printf( "Will use display %u (%u) because mouse cursor is at (%g, %g).\n", selectedDisplay, displayID, x, y ); selectedDisplay = displayID; - SDL_free(displayIDs); + SDL_free( displayIDs ); } - #else // SDL2 - common->Printf("Will use display %u because mouse cursor is at (%d, %d).\n", - selectedDisplay, x, y); - #endif +#else // SDL2 + common->Printf( "Will use display %u because mouse cursor is at (%d, %d).\n", selectedDisplay, x, y ); +#endif } - #endif // SDL_VERSION_ATLEAST(2, 0, 4) +#endif // SDL_VERSION_ATLEAST(2, 0, 4) - #if SDL_VERSION_ATLEAST(3, 0, 0) +#if SDL_VERSION_ATLEAST(3, 0, 0) SDL_PropertiesID props = SDL_CreateProperties(); - SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, ENGINE_VERSION); - SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_UNDEFINED_DISPLAY(selectedDisplay)); - SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_UNDEFINED_DISPLAY(selectedDisplay)); - SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, parms.width); - SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, parms.height); - SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER, flags); + SDL_SetStringProperty( props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, ENGINE_VERSION ); + SDL_SetNumberProperty( props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_UNDEFINED_DISPLAY( selectedDisplay ) ); + SDL_SetNumberProperty( props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_UNDEFINED_DISPLAY( selectedDisplay ) ); + SDL_SetNumberProperty( props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, parms.width ); + SDL_SetNumberProperty( props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, parms.height ); + SDL_SetNumberProperty( props, SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER, flags ); // See above for the big comment about Wayland and alpha channels. // When using SDL3 I assume that people usually won't be affected by this bug, // because it's fixed in recent Mesa versions (and also works with the NVIDIA driver). // However, with `r_fillWindowAlphaChan 1` its usage can still be enforced // on Unix-like platforms (I don't think there's a point in this on Windows or Mac) - #if defined(__unix__) && !defined(__APPLE__) +#if defined(__unix__) && !defined(__APPLE__) if ( cvarSystem->GetCVarInteger( "r_fillWindowAlphaChan" ) == 1 ) { - SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_TRANSPARENT_BOOLEAN, true); + SDL_SetBooleanProperty( props, SDL_PROP_WINDOW_CREATE_TRANSPARENT_BOOLEAN, true ); } - #endif +#endif + window = SDL_CreateWindowWithProperties( props ); + + SDL_DestroyProperties( props ); - window = SDL_CreateWindowWithProperties(props); - SDL_DestroyProperties(props); - if (window == NULL) { - common->Warning("Couldn't set GL mode %d/%d/%d with %dx MSAA: %s", - channelcolorbits, tdepthbits, tstencilbits, parms.multiSamples, SDL_GetError()); + if ( window == NULL ) { + common->Warning( "Couldn't set GL mode %d/%d/%d with %dx MSAA: %s", + channelcolorbits, tdepthbits, tstencilbits, parms.multiSamples, SDL_GetError() ); // before trying to reduce color channel size or whatever, first try reducing MSAA, if possible - if (multisamples > 1) { - multisamples = (multisamples <= 2) ? 0 : (multisamples/2); + if ( multisamples > 1 ) { + multisamples = ( multisamples <= 2 ) ? 0 : ( multisamples / 2 ); // using goto because enhancing that logic which reduces attributes // based on i (so it'd first try reducing MSAA) would be too painful goto try_again; } - continue; } else { // creating the window succeeded, so adjust r_multiSamples to the value that was actually used parms.multiSamples = multisamples; - r_multiSamples.SetInteger(multisamples); + r_multiSamples.SetInteger( multisamples ); } // handle exclusive fullscreen mode (windowed mode and fullscreen // desktop were set when creating the window) // TODO: just call GLimp_SetScreenParms() ? - if (parms.fullScreen && !parms.fullScreenDesktop) { + if ( parms.fullScreen && !parms.fullScreenDesktop ) { SDL_DisplayID displayID = SDL_GetDisplayForWindow( window ); SDL_DisplayMode mode = {}; - if ( SDL_GetClosestFullscreenDisplayMode(displayID, parms.width, parms.height, - parms.displayHz, true, &mode) ) - { - if ( ! SDL_SetWindowFullscreenMode(window, &mode) ) { - common->Warning("Can't set window fullscreen mode: %s\n", SDL_GetError()); - SDL_DestroyWindow(window); + + if ( SDL_GetClosestFullscreenDisplayMode( displayID, parms.width, parms.height, parms.displayHz, true, &mode ) ) { + if ( ! SDL_SetWindowFullscreenMode( window, &mode ) ) { + common->Warning( "Can't set window fullscreen mode: %s\n", SDL_GetError() ); + SDL_DestroyWindow( window ); window = NULL; return false; // trying other color depth etc is unlikely to help with this issue } - if ( ! SDL_SetWindowFullscreen(window, true) ) { - common->Warning("Can't switch window to fullscreen mode: %s\n", SDL_GetError()); - SDL_DestroyWindow(window); + if ( ! SDL_SetWindowFullscreen( window, true ) ) { + common->Warning( "Can't switch window to fullscreen mode: %s\n", SDL_GetError() ); + SDL_DestroyWindow( window ); window = NULL; return false; // trying other color depth etc is unlikely to help with this issue } } else { - common->Warning("Can't get display mode: %s\n", SDL_GetError()); - SDL_DestroyWindow(window); + common->Warning( "Can't get display mode: %s\n", SDL_GetError() ); + SDL_DestroyWindow( window ); window = NULL; return false; // trying other color depth etc is unlikely to help with this issue } } - if ( ! SDL_SyncWindow(window) ) { - common->Warning("SDL_SyncWindow() failed: %s\n", SDL_GetError()); - SDL_DestroyWindow(window); + if ( ! SDL_SyncWindow( window ) ) { + common->Warning( "SDL_SyncWindow() failed: %s\n", SDL_GetError() ); + SDL_DestroyWindow( window ); window = NULL; return false; // trying other color depth etc is unlikely to help with this issue } - #else // SDL2 - window = SDL_CreateWindow(ENGINE_VERSION, - SDL_WINDOWPOS_UNDEFINED_DISPLAY(selectedDisplay), - SDL_WINDOWPOS_UNDEFINED_DISPLAY(selectedDisplay), - parms.width, parms.height, flags); +#else // SDL2 + window = SDL_CreateWindow( ENGINE_VERSION, + SDL_WINDOWPOS_UNDEFINED_DISPLAY( selectedDisplay ), + SDL_WINDOWPOS_UNDEFINED_DISPLAY( selectedDisplay ), + parms.width, parms.height, flags ); - if (!window) { - common->Warning("Couldn't set GL mode %d/%d/%d with %dx MSAA: %s", - channelcolorbits, tdepthbits, tstencilbits, parms.multiSamples, SDL_GetError()); + if ( !window ) { + common->Warning( "Couldn't set GL mode %d/%d/%d with %dx MSAA: %s", + channelcolorbits, tdepthbits, tstencilbits, parms.multiSamples, SDL_GetError() ); // before trying to reduce color channel size or whatever, first try reducing MSAA, if possible - if(multisamples > 1) { - multisamples = (multisamples <= 2) ? 0 : (multisamples/2); + if ( multisamples > 1 ) { + multisamples = ( multisamples <= 2 ) ? 0 : ( multisamples / 2 ); // using goto because enhancing that logic which reduces attributes // based on i (so it'd first try reducing MSAA) would be too painful goto try_again; } - continue; } else { // creating the window succeeded, so adjust r_multiSamples to the value that was actually used parms.multiSamples = multisamples; - r_multiSamples.SetInteger(multisamples); + r_multiSamples.SetInteger( multisamples ); } /* Check if we're really in the requested display mode. There is (or was) an SDL bug were SDL switched into the wrong mode without giving an error code. See the bug report for details: https://bugzilla.libsdl.org/show_bug.cgi?id=4700 */ - if ((flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) == SDL_WINDOW_FULLSCREEN) - { + if ( ( flags & ( SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP ) ) == SDL_WINDOW_FULLSCREEN ) { SDL_DisplayMode real_mode; - if (SDL_GetWindowDisplayMode(window, &real_mode) != 0) - { - SDL_DestroyWindow(window); + + if ( SDL_GetWindowDisplayMode( window, &real_mode ) != 0 ) { + SDL_DestroyWindow( window ); window = NULL; - common->Warning("Can't get display mode: %s\n", SDL_GetError()); + common->Warning( "Can't get display mode: %s\n", SDL_GetError() ); return false; // trying other color depth etc is unlikely to help with this issue } - if ((real_mode.w != parms.width) || (real_mode.h != parms.height)) - { - common->Warning("Current display mode isn't requested display mode\n"); - common->Warning("Likely SDL bug #4700, trying to work around it..\n"); - int dIdx = SDL_GetWindowDisplayIndex(window); - if(dIdx != selectedDisplay) { - common->Warning("Window's display index is %d, but we wanted %d!\n", dIdx, selectedDisplay); + + if ( ( real_mode.w != parms.width ) || ( real_mode.h != parms.height ) ) { + common->Warning( "Current display mode isn't requested display mode\n" ); + common->Warning( "Likely SDL bug #4700, trying to work around it..\n" ); + + int dIdx = SDL_GetWindowDisplayIndex( window ); + + if ( dIdx != selectedDisplay ) { + common->Warning( "Window's display index is %d, but we wanted %d!\n", dIdx, selectedDisplay ); } /* Mkay, try to hack around that. */ @@ -532,12 +525,11 @@ bool GLimp_Init(glimpParms_t parms) { wanted_mode.w = parms.width; wanted_mode.h = parms.height; - if (SDL_SetWindowDisplayMode(window, &wanted_mode) != 0) - { - SDL_DestroyWindow(window); + if ( SDL_SetWindowDisplayMode( window, &wanted_mode ) != 0 ) { + SDL_DestroyWindow( window ); window = NULL; - common->Warning("Can't force resolution to %ix%i: %s\n", parms.width, parms.height, SDL_GetError()); + common->Warning( "Can't force resolution to %ix%i: %s\n", parms.width, parms.height, SDL_GetError() ); return false; // trying other color depth etc is unlikely to help with this issue } @@ -546,34 +538,32 @@ bool GLimp_Init(glimpParms_t parms) { used on fullscreen windows. But at least in my test with SDL 2.0.9 the subsequent SDL_GetWindowDisplayMode() fails if I don't call it. */ - SDL_SetWindowSize(window, wanted_mode.w, wanted_mode.h); + SDL_SetWindowSize( window, wanted_mode.w, wanted_mode.h ); - if (SDL_GetWindowDisplayMode(window, &real_mode) != 0) - { - SDL_DestroyWindow(window); + if ( SDL_GetWindowDisplayMode( window, &real_mode ) != 0 ) { + SDL_DestroyWindow( window ); window = NULL; - common->Warning("Can't get display mode: %s\n", SDL_GetError()); + common->Warning( "Can't get display mode: %s\n", SDL_GetError() ); return false; // trying other color depth etc is unlikely to help with this issue } - if ((real_mode.w != parms.width) || (real_mode.h != parms.height)) - { - SDL_DestroyWindow(window); + if ( ( real_mode.w != parms.width ) || ( real_mode.h != parms.height ) ) { + SDL_DestroyWindow( window ); window = NULL; - common->Warning("Still in wrong display mode: %ix%i instead of %ix%i\n", - real_mode.w, real_mode.h, parms.width, parms.height); + common->Warning( "Still in wrong display mode: %ix%i instead of %ix%i\n", + real_mode.w, real_mode.h, parms.width, parms.height ); return false; // trying other color depth etc is unlikely to help with this issue } - common->Warning("Now we have the requested resolution (%d x %d)\n", parms.width, parms.height); + common->Warning( "Now we have the requested resolution (%d x %d)\n", parms.width, parms.height ); } } - #endif // SDL2 +#endif // SDL2 - context = SDL_GL_CreateContext(window); + context = SDL_GL_CreateContext( window ); GLimp_SetSwapInterval( r_swapInterval.GetInteger() ); r_swapInterval.ClearModified(); @@ -584,36 +574,38 @@ bool GLimp_Init(glimpParms_t parms) { SetSDLIcon(); // for SDL2 this must be done after creating the window // TODO: also check for fullscreen-desktop? - glConfig.isFullscreen = (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) != 0; - const char* fsStr = glConfig.isFullscreen ? "fullscreen " : ""; - if ( (int)glConfig.winWidth != glConfig.vidWidth ) { + glConfig.isFullscreen = ( SDL_GetWindowFlags( window ) & SDL_WINDOW_FULLSCREEN ) != 0; + + const char *fsStr = glConfig.isFullscreen ? "fullscreen " : ""; + + if ( ( int )glConfig.winWidth != glConfig.vidWidth ) { common->Printf( "Got a HighDPI %swindow with physical resolution %d x %d and virtual resolution %g x %g\n", - fsStr, glConfig.vidWidth, glConfig.vidHeight, glConfig.winWidth, glConfig.winHeight ); + fsStr, glConfig.vidWidth, glConfig.vidHeight, glConfig.winWidth, glConfig.winHeight ); } else { common->Printf( "Got a %swindow with resolution %g x %g\n", fsStr, glConfig.winWidth, glConfig.winHeight ); } #else // SDL1.2 window creation - SDL_WM_SetCaption(ENGINE_VERSION, ENGINE_VERSION); + SDL_WM_SetCaption( ENGINE_VERSION, ENGINE_VERSION ); SetSDLIcon(); // for SDL1.2 this must be done before creating the window - if (SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, r_swapInterval.GetInteger()) < 0) - common->Warning("SDL_GL_SWAP_CONTROL not supported"); + if ( SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, r_swapInterval.GetInteger() ) < 0 ) { + common->Warning( "SDL_GL_SWAP_CONTROL not supported" ); + } if ( r_glDebugContext.GetBool() ) { common->Warning( "r_glDebugContext is set, but not supported by SDL1.2!\n" ); } - r_swapInterval.ClearModified(); - window = SDL_SetVideoMode(parms.width, parms.height, colorbits, flags); - if (!window) { - common->DPrintf("Couldn't set GL mode %d/%d/%d: %s", - channelcolorbits, tdepthbits, tstencilbits, SDL_GetError()); + window = SDL_SetVideoMode( parms.width, parms.height, colorbits, flags ); + if ( !window ) { + common->DPrintf( "Couldn't set GL mode %d/%d/%d: %s", + channelcolorbits, tdepthbits, tstencilbits, SDL_GetError() ); // before trying to reduce color channel size or whatever, first try reducing MSAA, if possible - if(multisamples > 1) { - multisamples = (multisamples <= 2) ? 0 : (multisamples/2); + if ( multisamples > 1 ) { + multisamples = ( multisamples <= 2 ) ? 0 : ( multisamples / 2 ); // using goto because enhancing that logic which reduces attributes // based on i (so it'd first try reducing MSAA) would be too painful @@ -624,28 +616,26 @@ bool GLimp_Init(glimpParms_t parms) { } else { // creating the window succeeded, so adjust r_multiSamples to the value that was actually used parms.multiSamples = multisamples; - r_multiSamples.SetInteger(multisamples); + r_multiSamples.SetInteger( multisamples ); } - glConfig.vidWidth = window->w; glConfig.vidHeight = window->h; - glConfig.isFullscreen = (window->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN; + glConfig.isFullscreen = ( window->flags & SDL_FULLSCREEN ) == SDL_FULLSCREEN; #endif #if defined(_WIN32) && defined(ID_ALLOW_TOOLS) #if ! SDL_VERSION_ATLEAST(2, 0, 0) - #error "dhewm3 only supports the tools with SDL2, not SDL1!" +#error "dhewm3 only supports the tools with SDL2, not SDL1!" #endif // The tools are Win32 specific. If building the tools // then we know we are win32 and we have to include this // config to get the editors to work. - #if SDL_VERSION_ATLEAST(3, 0, 0) - HWND hwnd = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); - HDC hdc = (HDC)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HDC_POINTER, NULL); + HWND hwnd = ( HWND )SDL_GetPointerProperty( SDL_GetWindowProperties( window ), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL ); + HDC hdc = ( HDC )SDL_GetPointerProperty( SDL_GetWindowProperties( window ), SDL_PROP_WINDOW_WIN32_HDC_POINTER, NULL ); if ( hwnd && hdc ) { win32.hWnd = hwnd; win32.hDC = hdc; @@ -653,23 +643,23 @@ bool GLimp_Init(glimpParms_t parms) { // Get the HWND for later use. SDL_SysWMinfo sdlinfo; SDL_version sdlver; - SDL_VERSION(&sdlver); + SDL_VERSION( &sdlver ); + sdlinfo.version = sdlver; - if (SDL_GetWindowWMInfo(window, &sdlinfo) && sdlinfo.subsystem == SDL_SYSWM_WINDOWS) { + + if ( SDL_GetWindowWMInfo( window, &sdlinfo ) && sdlinfo.subsystem == SDL_SYSWM_WINDOWS ) { win32.hWnd = sdlinfo.info.win.window; win32.hDC = sdlinfo.info.win.hdc; #endif // NOTE: hInstance is set in main() win32.hGLRC = qwglGetCurrentContext(); - int pfIdx = GetPixelFormat(win32.hDC); + int pfIdx = GetPixelFormat( win32.hDC ); PIXELFORMATDESCRIPTOR src = {}; - if (DescribePixelFormat(win32.hDC, pfIdx, sizeof(PIXELFORMATDESCRIPTOR), &win32.pfd) == 0) - { - common->Warning("DescribePixelFormat() failed: %d!\n", GetLastError()); - PIXELFORMATDESCRIPTOR src = - { - sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd + if ( DescribePixelFormat( win32.hDC, pfIdx, sizeof( PIXELFORMATDESCRIPTOR ), &win32.pfd ) == 0 ) { + common->Warning( "DescribePixelFormat() failed: %d!\n", GetLastError() ); + PIXELFORMATDESCRIPTOR src = { + sizeof( PIXELFORMATDESCRIPTOR ), // size of this pfd 1, // version number PFD_DRAW_TO_WINDOW | // support window PFD_SUPPORT_OPENGL | // support OpenGL @@ -688,15 +678,14 @@ bool GLimp_Init(glimpParms_t parms) { 0, // reserved 0, 0, 0 // layer masks ignored }; - memcpy(&win32.pfd, &src, sizeof(PIXELFORMATDESCRIPTOR)); + memcpy( &win32.pfd, &src, sizeof( PIXELFORMATDESCRIPTOR ) ); } - win32.piAttribIList = NULL; - win32.wglGetPixelFormatAttribivARB = (BOOL(WINAPI*)(HDC,int,int,UINT,const int*,int*))SDL_GL_GetProcAddress("wglGetPixelFormatAttribivARB"); - win32.wglChoosePixelFormatARB = (BOOL(WINAPI*)(HDC,const int*,const FLOAT*,UINT,int*piFormats,UINT*))SDL_GL_GetProcAddress("wglChoosePixelFormatARB"); + win32.wglGetPixelFormatAttribivARB = ( BOOL( WINAPI * )( HDC, int, int, UINT, const int *, int * ) )SDL_GL_GetProcAddress( "wglGetPixelFormatAttribivARB" ); + win32.wglChoosePixelFormatARB = ( BOOL( WINAPI * )( HDC, const int *, const FLOAT *, UINT, int *piFormats, UINT * ) )SDL_GL_GetProcAddress( "wglChoosePixelFormatARB" ); - if(win32.wglGetPixelFormatAttribivARB != NULL && win32.wglChoosePixelFormatARB != NULL) { + if ( win32.wglGetPixelFormatAttribivARB != NULL && win32.wglChoosePixelFormatARB != NULL ) { const int queryAttributes[] = { // equivalents of all the SDL_GL_* attributes we set above (and ones set implicitly) WGL_DRAW_TO_WINDOW_ARB, @@ -714,71 +703,72 @@ bool GLimp_Init(glimpParms_t parms) { // WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB - not used WGL_ACCELERATION_ARB, }; - enum { NUM_ATTRIBUTES = sizeof(queryAttributes)/sizeof(queryAttributes[0]) }; + enum { NUM_ATTRIBUTES = sizeof( queryAttributes ) / sizeof( queryAttributes[0] ) }; int queryResults[NUM_ATTRIBUTES] = {}; - - win32.wglGetPixelFormatAttribivARB(win32.hDC, pfIdx, PFD_MAIN_PLANE, NUM_ATTRIBUTES, queryAttributes, queryResults); - - static int attribIList[2*NUM_ATTRIBUTES+2] = {}; // +2 for terminating 0, 0 pair - for(int i=0; iError("SDL_GetWindowWMInfo(), which is needed for Tools to work, failed!"); - } + common->Error( "SDL_GetWindowWMInfo(), which is needed for Tools to work, failed!" ); + } #endif // defined(_WIN32) && defined(ID_ALLOW_TOOLS) - common->Printf("Requested %d color bits per chan, %d alpha %d depth, %d stencil\n", - channelcolorbits, talphabits, tdepthbits, tstencilbits); + common->Printf( "Requested %d color bits per chan, %d alpha %d depth, %d stencil\n", + channelcolorbits, talphabits, tdepthbits, tstencilbits ); { int r, g, b, a, d, s; - SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &r); - SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &g); - SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &b); - SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &a); - SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &d); - SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &s); + SDL_GL_GetAttribute( SDL_GL_RED_SIZE, &r ); + SDL_GL_GetAttribute( SDL_GL_GREEN_SIZE, &g ); + SDL_GL_GetAttribute( SDL_GL_BLUE_SIZE, &b ); + SDL_GL_GetAttribute( SDL_GL_ALPHA_SIZE, &a ); + SDL_GL_GetAttribute( SDL_GL_DEPTH_SIZE, &d ); + SDL_GL_GetAttribute( SDL_GL_STENCIL_SIZE, &s ); - common->Printf("Got %d stencil bits, %d depth bits, color bits: r%d g%d b%d a%d\n", s, d, r, g, b, a); + common->Printf( "Got %d stencil bits, %d depth bits, color bits: r%d g%d b%d a%d\n", s, d, r, g, b, a ); - glConfig.colorBits = r+g+b; // a bit imprecise, but seems to be used only in GfxInfo_f() + glConfig.colorBits = r + g + b; // a bit imprecise, but seems to be used only in GfxInfo_f() glConfig.alphabits = a; glConfig.depthBits = d; glConfig.stencilBits = s; } - glConfig.displayFrequency = 0; // for r_fillWindowAlphaChan -1, see also the big comment above glConfig.shouldFillWindowAlpha = false; glConfig.isWayland = false; #if SDL_VERSION_ATLEAST(2, 0, 0) - const char* videoDriver = SDL_GetCurrentVideoDriver(); - if (idStr::Icmp(videoDriver, "wayland") == 0) { - #if SDL_MAJOR_VERSION == 2 // don't enable this hack by default with SDL3 + const char *videoDriver = SDL_GetCurrentVideoDriver(); + + if ( idStr::Icmp( videoDriver, "wayland" ) == 0 ) { +#if SDL_MAJOR_VERSION == 2 // don't enable this hack by default with SDL3 glConfig.shouldFillWindowAlpha = true; - #endif +#endif glConfig.isWayland = true; } #endif - glConfig.haveDebugContext = false; #if SDL_VERSION_ATLEAST(2, 0, 0) int cflags = 0; - #if SDL_VERSION_ATLEAST(3, 0, 0) +#if SDL_VERSION_ATLEAST(3, 0, 0) if ( SDL_GL_GetAttribute( SDL_GL_CONTEXT_FLAGS, &cflags ) ) { - #else // SDL2 +#else // SDL2 if ( SDL_GL_GetAttribute( SDL_GL_CONTEXT_FLAGS, &cflags ) == 0 ) { - #endif - glConfig.haveDebugContext = (cflags & SDL_GL_CONTEXT_DEBUG_FLAG) != 0; - if ( glConfig.haveDebugContext ) +#endif + glConfig.haveDebugContext = ( cflags & SDL_GL_CONTEXT_DEBUG_FLAG ) != 0; + + if ( glConfig.haveDebugContext ) { common->Printf( "Got a debug context!\n" ); - else if( r_glDebugContext.GetBool() ) { + } else if ( r_glDebugContext.GetBool() ) { common->Warning( "Requested a debug context, but didn't get one!\n" ); } } @@ -786,14 +776,14 @@ bool GLimp_Init(glimpParms_t parms) { break; } - if (!window) { - common->Warning("No usable GL mode found: %s", SDL_GetError()); + if ( !window ) { + common->Warning( "No usable GL mode found: %s", SDL_GetError() ); return false; } #if SDL_VERSION_ATLEAST(2, 0, 0) // SDL1.2 has no context, and is not supported by ImGui anyway - D3::ImGuiHooks::Init(window, context); + D3::ImGuiHooks::Init( window, context ); #endif return true; @@ -804,39 +794,37 @@ bool GLimp_Init(glimpParms_t parms) { GLimp_SetScreenParms =================== */ -bool GLimp_SetScreenParms(glimpParms_t parms) { +bool GLimp_SetScreenParms( glimpParms_t parms ) { #if SDL_VERSION_ATLEAST(2, 0, 0) glimpParms_t curState = GLimp_GetCurState(); - if( parms.multiSamples != -1 && parms.multiSamples != curState.multiSamples ) { + if ( parms.multiSamples != -1 && parms.multiSamples != curState.multiSamples ) { // if MSAA settings have changed, we really need a vid_restart return false; } - bool wantFullscreenDesktop = parms.fullScreen && parms.fullScreenDesktop; // TODO: parms.displayHz ? - if ( curState.fullScreenDesktop && wantFullscreenDesktop ) { return true; // nothing to do (resolution is not configurable in that mode) } if ( !parms.fullScreen ) { // we want windowed mode if ( curState.fullScreen && - #if SDL_VERSION_ATLEAST(3, 0, 0) - SDL_SetWindowFullscreen( window, 0 ) == false - #else - SDL_SetWindowFullscreen( window, 0 ) != 0 - #endif - ) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_SetWindowFullscreen( window, 0 ) == false +#else + SDL_SetWindowFullscreen( window, 0 ) != 0 +#endif + ) { common->Warning( "GLimp_SetScreenParms(): Couldn't switch to windowed mode, SDL error: %s\n", SDL_GetError() ); return false; } SDL_RestoreWindow( window ); // make sure we're not maximized, then setting the size wouldn't work SDL_SetWindowSize( window, parms.width, parms.height ); - #if SDL_VERSION_ATLEAST(3, 0, 0) +#if SDL_VERSION_ATLEAST(3, 0, 0) SDL_SyncWindow( window ); - #endif +#endif } else { // we want some kind of fullscreen mode // it's probably safest to first switch to windowed mode @@ -844,7 +832,7 @@ bool GLimp_SetScreenParms(glimpParms_t parms) { SDL_SetWindowFullscreen( window, 0 ); } - #if SDL_VERSION_ATLEAST(3, 0, 0) +#if SDL_VERSION_ATLEAST(3, 0, 0) if ( wantFullscreenDesktop ) { SDL_SetWindowFullscreenMode( window, NULL ); // setting it to NULL enables fullscreen desktop mode SDL_SetWindowFullscreen( window, true ); @@ -859,9 +847,7 @@ bool GLimp_SetScreenParms(glimpParms_t parms) { } else { // want real fullscreen SDL_DisplayID displayID = SDL_GetDisplayForWindow( window ); SDL_DisplayMode mode = {}; - if ( SDL_GetClosestFullscreenDisplayMode( displayID, parms.width, parms.height, - parms.displayHz, true, &mode ) ) - { + if ( SDL_GetClosestFullscreenDisplayMode( displayID, parms.width, parms.height, parms.displayHz, true, &mode ) ) { if ( ! SDL_SetWindowFullscreenMode( window, &mode ) ) { common->Warning( "Can't set window fullscreen mode: %s\n", SDL_GetError() ); //TODO: probably not SDL_DestroyWindow( window ); @@ -882,7 +868,6 @@ bool GLimp_SetScreenParms(glimpParms_t parms) { //window = NULL; return false; } - } else { if ( parms.displayHz != 0 ) { common->Warning( "Can't get display mode for %d x %d @ %dHz: %s\n", parms.width, @@ -897,7 +882,7 @@ bool GLimp_SetScreenParms(glimpParms_t parms) { } } - #else // SDL2 +#else // SDL2 if ( wantFullscreenDesktop ) { if ( SDL_SetWindowFullscreen( window, SDL_WINDOW_FULLSCREEN_DESKTOP ) != 0 ) { common->Warning( "GLimp_SetScreenParms(): Couldn't switch to fullscreen desktop mode, SDL error: %s\n", SDL_GetError() ); @@ -910,13 +895,10 @@ bool GLimp_SetScreenParms(glimpParms_t parms) { wanted_mode.h = parms.height; // TODO: refresh rate? parms.displayHz should probably try to get most similar mode before trying to set it? - - if ( SDL_SetWindowDisplayMode( window, &wanted_mode ) != 0 ) - { - common->Warning("GLimp_SetScreenParms(): Can't set fullscreen resolution to %ix%i: %s\n", wanted_mode.w, wanted_mode.h, SDL_GetError()); + if ( SDL_SetWindowDisplayMode( window, &wanted_mode ) != 0 ) { + common->Warning( "GLimp_SetScreenParms(): Can't set fullscreen resolution to %ix%i: %s\n", wanted_mode.w, wanted_mode.h, SDL_GetError() ); return false; } - SDL_SetWindowFullscreen( window, SDL_WINDOW_FULLSCREEN ); /* The SDL doku says, that SDL_SetWindowSize() shouldn't be @@ -926,24 +908,21 @@ bool GLimp_SetScreenParms(glimpParms_t parms) { SDL_SetWindowSize( window, wanted_mode.w, wanted_mode.h ); SDL_DisplayMode real_mode = {}; - if ( SDL_GetWindowDisplayMode( window, &real_mode ) != 0 ) - { + if ( SDL_GetWindowDisplayMode( window, &real_mode ) != 0 ) { common->Warning( "GLimp_SetScreenParms(): Can't get display mode: %s\n", SDL_GetError() ); return false; // trying other color depth etc is unlikely to help with this issue } - if ( (real_mode.w != wanted_mode.w) || (real_mode.h != wanted_mode.h) ) - { + if ( ( real_mode.w != wanted_mode.w ) || ( real_mode.h != wanted_mode.h ) ) { common->Warning( "GLimp_SetScreenParms(): Still in wrong display mode: %ix%i instead of %ix%i\n", real_mode.w, real_mode.h, wanted_mode.w, wanted_mode.h ); return false; } } - #endif // SDL2 +#endif // SDL2 } - - glConfig.isFullscreen = (SDL_GetWindowFlags( window ) & SDL_WINDOW_FULLSCREEN) != 0; + glConfig.isFullscreen = ( SDL_GetWindowFlags( window ) & SDL_WINDOW_FULLSCREEN ) != 0; return true; @@ -955,16 +934,15 @@ bool GLimp_SetScreenParms(glimpParms_t parms) { // sets a glimpParms_t based on the current true state (according to SDL) // Note: here, ret.fullScreenDesktop is only true if currently in fullscreen desktop mode // (and ret.fullScreen is true as well) -glimpParms_t GLimp_GetCurState() -{ +glimpParms_t GLimp_GetCurState() { glimpParms_t ret = {}; #if SDL_VERSION_ATLEAST(2, 0, 0) My_SDL_WindowFlags winFlags = SDL_GetWindowFlags( window ); - ret.fullScreen = (winFlags & SDL_WINDOW_FULLSCREEN) != 0; + ret.fullScreen = ( winFlags & SDL_WINDOW_FULLSCREEN ) != 0; int curMultiSamples = 0; - #if SDL_VERSION_ATLEAST(3, 0, 0) +#if SDL_VERSION_ATLEAST(3, 0, 0) if ( SDL_GL_GetAttribute( SDL_GL_MULTISAMPLEBUFFERS, &curMultiSamples ) && curMultiSamples > 0 ) { if ( ! SDL_GL_GetAttribute( SDL_GL_MULTISAMPLESAMPLES, &curMultiSamples ) ) { curMultiSamples = 0; // SDL_GL_GetAttribute() call failed, assume no MSAA @@ -973,9 +951,9 @@ glimpParms_t GLimp_GetCurState() curMultiSamples = 0; // SDL_GL_GetAttribute() call failed, assume no MSAA } - if (ret.fullScreen) { - const SDL_DisplayMode* fullscreenMode = SDL_GetWindowFullscreenMode( window ); - if (fullscreenMode != NULL) { + if ( ret.fullScreen ) { + const SDL_DisplayMode *fullscreenMode = SDL_GetWindowFullscreenMode( window ); + if ( fullscreenMode != NULL ) { ret.width = fullscreenMode->w; ret.height = fullscreenMode->h; ret.displayHz = fullscreenMode->refresh_rate; @@ -985,7 +963,7 @@ glimpParms_t GLimp_GetCurState() ret.fullScreenDesktop = true; } } - #else // SDL2 +#else // SDL2 if ( SDL_GL_GetAttribute( SDL_GL_MULTISAMPLEBUFFERS, &curMultiSamples ) == 0 && curMultiSamples > 0 ) { if ( SDL_GL_GetAttribute( SDL_GL_MULTISAMPLESAMPLES, &curMultiSamples ) != 0 ) { curMultiSamples = 0; // SDL_GL_GetAttribute() call failed, assume no MSAA @@ -993,8 +971,8 @@ glimpParms_t GLimp_GetCurState() } else { curMultiSamples = 0; // SDL_GL_GetAttribute() call failed, assume no MSAA } + ret.fullScreenDesktop = ( winFlags & SDL_WINDOW_FULLSCREEN_DESKTOP ) == SDL_WINDOW_FULLSCREEN_DESKTOP; - ret.fullScreenDesktop = (winFlags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP; if ( ret.fullScreen && !ret.fullScreenDesktop ) { // I think SDL_GetWindowDisplayMode() is only for "real" fullscreen? SDL_DisplayMode real_mode = {}; if ( SDL_GetWindowDisplayMode( window, &real_mode ) == 0 ) { @@ -1005,17 +983,15 @@ glimpParms_t GLimp_GetCurState() common->Warning( "GLimp_GetCurState(): Can't get display mode: %s\n", SDL_GetError() ); } } - #endif +#endif ret.multiSamples = curMultiSamples; if ( ret.width == 0 && ret.height == 0 ) { // windowed mode, fullscreen-desktop mode or SDL_GetWindowDisplayMode() failed SDL_GetWindowSize( window, &ret.width, &ret.height ); } - assert( ret.width == glConfig.winWidth && ret.height == glConfig.winHeight ); assert( ret.fullScreen == glConfig.isFullscreen ); - #else assert( 0 && "Don't use GLimp_GetCurState() with SDL1.2 !" ); #endif @@ -1029,19 +1005,17 @@ GLimp_Shutdown =================== */ void GLimp_Shutdown() { - D3::ImGuiHooks::Shutdown(); - - common->Printf("Shutting down OpenGL subsystem\n"); + common->Printf( "Shutting down OpenGL subsystem\n" ); #if SDL_VERSION_ATLEAST(2, 0, 0) - if (context) { - SDL_GL_DeleteContext(context); + if ( context ) { + SDL_GL_DeleteContext( context ); context = NULL; } - if (window) { - SDL_DestroyWindow(window); + if ( window ) { + SDL_DestroyWindow( window ); window = NULL; } #endif @@ -1054,7 +1028,7 @@ GLimp_SwapBuffers */ void GLimp_SwapBuffers() { #if SDL_VERSION_ATLEAST(2, 0, 0) - SDL_GL_SwapWindow(window); + SDL_GL_SwapWindow( window ); #else SDL_GL_SwapBuffers(); #endif @@ -1074,15 +1048,15 @@ static unsigned short gammaOrigBlue[256]; GLimp_SetGamma ================= */ -void GLimp_SetGamma(unsigned short red[256], unsigned short green[256], unsigned short blue[256]) { +void GLimp_SetGamma( unsigned short red[256], unsigned short green[256], unsigned short blue[256] ) { #if SDL_VERSION_ATLEAST(3, 0, 0) if ( ! r_gammaInShader.GetBool() ) { common->Warning( "This build of dhewm3 uses SDL3, which does not support hardware gamma." ); common->Warning( "If you want to adjust gamma or brightness, enable r_gammaInShader" ); } #else // SDL2 and SDL1.2 - if (!window) { - common->Warning("GLimp_SetGamma called without window"); + if ( !window ) { + common->Warning( "GLimp_SetGamma called without window" ); return; } @@ -1098,13 +1072,13 @@ void GLimp_SetGamma(unsigned short red[256], unsigned short green[256], unsigned } } - #if SDL_VERSION_ATLEAST(2, 0, 0) - if (SDL_SetWindowGammaRamp(window, red, green, blue)) + if ( SDL_SetWindowGammaRamp( window, red, green, blue ) ) { #else - if (SDL_SetGammaRamp(red, green, blue)) + if ( SDL_SetGammaRamp( red, green, blue ) ) { #endif - common->Warning("Couldn't set gamma ramp: %s", SDL_GetError()); + common->Warning( "Couldn't set gamma ramp: %s", SDL_GetError() ); + } #endif // SDL2 and SDL1.2 } @@ -1117,18 +1091,18 @@ Restore original system gamma setting */ void GLimp_ResetGamma() { #if ! SDL_VERSION_ATLEAST(3, 0, 0) // only for SDL2 and SDL1.2 - if( gammaOrigError ) { + if ( gammaOrigError ) { common->Warning( "Can't reset hardware gamma because getting the Gamma Ramp at startup failed!\n" ); common->Warning( "You might have to restart the game for gamma/brightness in shaders to work properly.\n" ); return; } - if( gammaOrigSet ) { - #if SDL_VERSION_ATLEAST(2, 0, 0) + if ( gammaOrigSet ) { +#if SDL_VERSION_ATLEAST(2, 0, 0) SDL_SetWindowGammaRamp( window, gammaOrigRed, gammaOrigGreen, gammaOrigBlue ); - #else +#else SDL_SetGammaRamp( gammaOrigRed, gammaOrigGreen, gammaOrigBlue ); - #endif +#endif } #endif // ! SDL_VERSION_ATLEAST(3, 0, 0) } @@ -1140,7 +1114,7 @@ GLimp_ActivateContext ================= */ void GLimp_ActivateContext() { - common->DPrintf("TODO: GLimp_ActivateContext\n"); + common->DPrintf( "TODO: GLimp_ActivateContext\n" ); } /* @@ -1149,7 +1123,7 @@ GLimp_DeactivateContext ================= */ void GLimp_DeactivateContext() { - common->DPrintf("TODO: GLimp_DeactivateContext\n"); + common->DPrintf( "TODO: GLimp_DeactivateContext\n" ); } /* @@ -1157,56 +1131,56 @@ void GLimp_DeactivateContext() { GLimp_ExtensionPointer =================== */ -GLExtension_t GLimp_ExtensionPointer(const char *name) { - assert(SDL_WasInit(SDL_INIT_VIDEO)); +GLExtension_t GLimp_ExtensionPointer( const char *name ) { + assert( SDL_WasInit( SDL_INIT_VIDEO ) ); - return (GLExtension_t)SDL_GL_GetProcAddress(name); + return ( GLExtension_t )SDL_GL_GetProcAddress( name ); } -void GLimp_GrabInput(int flags) { - if (!window) { - common->Warning("GLimp_GrabInput called without window"); +void GLimp_GrabInput( int flags ) { + if ( !window ) { + common->Warning( "GLimp_GrabInput called without window" ); return; } #if SDL_VERSION_ATLEAST(3, 0, 0) - if (flags & GRAB_HIDECURSOR) { + if ( flags & GRAB_HIDECURSOR ) { SDL_HideCursor(); } else { SDL_ShowCursor(); } - SDL_SetWindowRelativeMouseMode( window, (flags & GRAB_RELATIVEMOUSE) != 0 ); - if (flags & GRAB_GRABMOUSE) { + SDL_SetWindowRelativeMouseMode( window, ( flags & GRAB_RELATIVEMOUSE ) != 0 ); + + if ( flags & GRAB_GRABMOUSE ) { SDL_SetWindowMouseGrab( window, true ); SDL_SetWindowKeyboardGrab( window, in_grabKeyboard.GetBool() ); } else { SDL_SetWindowMouseGrab( window, false ); SDL_SetWindowKeyboardGrab( window, false ); } - if (flags & GRAB_ENABLETEXTINPUT) { + if ( flags & GRAB_ENABLETEXTINPUT ) { SDL_StartTextInput( window ); } else { SDL_StopTextInput( window ); } #elif SDL_VERSION_ATLEAST(2, 0, 0) - SDL_ShowCursor( (flags & GRAB_HIDECURSOR) ? SDL_DISABLE : SDL_ENABLE ); - SDL_SetRelativeMouseMode( (flags & GRAB_RELATIVEMOUSE) ? SDL_TRUE : SDL_FALSE ); - SDL_SetWindowGrab( window, (flags & GRAB_GRABMOUSE) ? SDL_TRUE : SDL_FALSE ); + SDL_ShowCursor( ( flags & GRAB_HIDECURSOR ) ? SDL_DISABLE : SDL_ENABLE ); + SDL_SetRelativeMouseMode( ( flags & GRAB_RELATIVEMOUSE ) ? SDL_TRUE : SDL_FALSE ); + SDL_SetWindowGrab( window, ( flags & GRAB_GRABMOUSE ) ? SDL_TRUE : SDL_FALSE ); #else - SDL_ShowCursor( (flags & GRAB_HIDECURSOR) ? SDL_DISABLE : SDL_ENABLE ); + SDL_ShowCursor( ( flags & GRAB_HIDECURSOR ) ? SDL_DISABLE : SDL_ENABLE ); // ignore GRAB_GRABMOUSE, SDL1.2 doesn't support grabbing without relative mode // so only grab if we want relative mode - SDL_WM_GrabInput( (flags & GRAB_RELATIVEMOUSE) ? SDL_GRAB_ON : SDL_GRAB_OFF ); + SDL_WM_GrabInput( ( flags & GRAB_RELATIVEMOUSE ) ? SDL_GRAB_ON : SDL_GRAB_OFF ); #endif } -bool GLimp_SetSwapInterval( int swapInterval ) -{ +bool GLimp_SetSwapInterval( int swapInterval ) { #if SDL_VERSION_ATLEAST(2, 0, 0) - #if SDL_VERSION_ATLEAST(3, 0, 0) +#if SDL_VERSION_ATLEAST(3, 0, 0) if ( ! SDL_GL_SetSwapInterval( swapInterval ) ) { - #elif SDL_VERSION_ATLEAST(2, 0, 0) +#elif SDL_VERSION_ATLEAST(2, 0, 0) if ( SDL_GL_SetSwapInterval( swapInterval ) < 0 ) { - #endif +#endif common->Warning( "SDL_GL_SetSwapInterval( %d ) not supported", swapInterval ); return false; } @@ -1217,13 +1191,12 @@ bool GLimp_SetSwapInterval( int swapInterval ) #endif } -bool GLimp_SetWindowResizable( bool enableResizable ) -{ +bool GLimp_SetWindowResizable( bool enableResizable ) { #if SDL_VERSION_ATLEAST(3, 0, 0) SDL_SetWindowResizable( window, enableResizable ); return true; #elif SDL_VERSION_ATLEAST(2, 0, 5) - SDL_SetWindowResizable( window, (SDL_bool)enableResizable ); + SDL_SetWindowResizable( window, ( SDL_bool )enableResizable ); return true; #else common->Warning( "dhewm3 must be built with SDL 2.0.5 or newer to change resizability of existing windows!" ); @@ -1231,22 +1204,22 @@ bool GLimp_SetWindowResizable( bool enableResizable ) #endif } -void GLimp_UpdateWindowSize() -{ +void GLimp_UpdateWindowSize() { #if SDL_VERSION_ATLEAST(2, 0, 0) My_SDL_WindowFlags winFlags = SDL_GetWindowFlags( window ); - #if SDL_VERSION_ATLEAST(3, 0, 0) +#if SDL_VERSION_ATLEAST(3, 0, 0) SDL_GetWindowSizeInPixels( window, &glConfig.vidWidth, &glConfig.vidHeight ); + const SDL_DisplayMode *fullscreenMode = SDL_GetWindowFullscreenMode( window ); - const SDL_DisplayMode* fullscreenMode = SDL_GetWindowFullscreenMode( window ); - if ( (winFlags & SDL_WINDOW_FULLSCREEN) != 0 && fullscreenMode != NULL) { + if ( ( winFlags & SDL_WINDOW_FULLSCREEN ) != 0 && fullscreenMode != NULL ) { glConfig.winWidth = fullscreenMode->w; glConfig.winHeight = fullscreenMode->h; } - #else // SDL2 +#else // SDL2 SDL_GL_GetDrawableSize( window, &glConfig.vidWidth, &glConfig.vidHeight ); - if ( (winFlags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN ) { + + if ( ( winFlags & SDL_WINDOW_FULLSCREEN_DESKTOP ) == SDL_WINDOW_FULLSCREEN ) { // real fullscreen mode => must use SDL_GetWindowDisplayMode() // TODO: well, theoretically SDL_GetWindowSize() should work for fullscreen mode as well, // but not in all SDL versions, I think? @@ -1254,18 +1227,19 @@ void GLimp_UpdateWindowSize() // returns the correct values and SDL_GetWindowDisplayMode() doesn't, when the fullscreen // resolution is lower than the desktop resolution.. it's kind of messy. SDL_DisplayMode dm = {}; + if ( SDL_GetWindowDisplayMode( window, &dm ) == 0 ) { glConfig.winWidth = dm.w; glConfig.winHeight = dm.h; - int ww=0, wh=0; + int ww = 0, wh = 0; SDL_GetWindowSize( window, &ww, &wh ); } else { common->Warning( "GLimp_UpdateWindowSize(): SDL_GetWindowDisplayMode() failed: %s\n", SDL_GetError() ); } } - #endif // SDL2 - else { - int ww=0, wh=0; +#endif // SDL2 + else { + int ww = 0, wh = 0; SDL_GetWindowSize( window, &ww, &wh ); glConfig.winWidth = ww; glConfig.winHeight = wh; diff --git a/neo/sys/platform.h b/neo/sys/platform.h index 567c83268..3d73e5afe 100644 --- a/neo/sys/platform.h +++ b/neo/sys/platform.h @@ -38,11 +38,9 @@ If you have questions concerning this license or the applicable additional terms // NOTE: By default Win32 uses a 1MB stack. Doom3 1.3.1 uses 4MB (probably set after compiling with EDITBIN /STACK // dhewm3 now uses a 8MB stack, set with a linker flag in CMakeLists.txt (/STACK:8388608 for MSVC, -Wl,--stack,8388608 for mingw) -// Linux has a 8MB stack by default, and so does macOS, at least for the main thread. -// Anyway, a 1MB limit for _alloca() should be safe even when using it multiple times -// in the same function or callstack. -// If there's a risk of bigger stack allocations, Mem_MallocA() should be used instead. -#define ID_MAX_ALLOCA_SIZE 1048576 // 1MB +// Linux has a 8MB stack by default, and so does macOS, at least for the main thread +// anyway, a 2MB limit alloca should be safe even when using it multiple times in the same function +#define ID_MAX_ALLOCA_SIZE 2097152 // 2MB /* =============================================================================== @@ -56,16 +54,16 @@ If you have questions concerning this license or the applicable additional terms #if defined(__AROS__) #define _alloca alloca -#define _alloca16( x ) ((void *)((((uintptr_t)alloca( (x)+15 )) + 15) & ~15)) +#define _alloca16( x ) ( ( void * )( ( ( ( uintptr_t )alloca( ( x ) + 15 ) ) + 15 ) & ~15 ) ) #ifdef GAME_DLL -#define ID_GAME_API __attribute__((visibility ("default"))) +#define ID_GAME_API __attribute__( ( visibility ( "default" ) ) ) #else #define ID_GAME_API #endif -#define ALIGN16( x ) x __attribute__ ((aligned (16))) -#define PACKED __attribute__((packed)) +#define ALIGN16( x ) x __attribute__ ( ( aligned ( 16 ) ) ) +#define PACKED __attribute__( ( packed ) ) #define PATHSEPERATOR_STR "/" #define PATHSEPERATOR_CHAR '/' @@ -84,13 +82,13 @@ If you have questions concerning this license or the applicable additional terms #if defined(WIN32) || defined(_WIN32) #ifdef __MINGW32__ - #undef _alloca // in mingw _alloca is a #define - // NOTE: Do *not* use __builtin_alloca_with_align(), unlike regular alloca it frees at end of block instead of end of function ! - #define _alloca16( x ) ( (void *) ( (assert((x) +// MSVC does not provide this C99 header +#include #endif #include #include @@ -275,7 +269,7 @@ typedef unsigned long ulong; typedef int qhandle_t; #ifndef NULL -#define NULL ((void *)0) +#define NULL ( ( void * ) 0 ) #endif #ifndef BIT diff --git a/neo/sys/proggyvector_font.h b/neo/sys/proggyvector_font.h new file mode 100644 index 000000000..98ecccaa0 --- /dev/null +++ b/neo/sys/proggyvector_font.h @@ -0,0 +1,4146 @@ +// File: 'ProggyVector-Dotted.ttf' (399600 bytes) +// Exported using binary_to_compressed_c.cpp +static const unsigned int ProggyVector_compressed_size = 198655; +static const unsigned int ProggyVector_compressed_data[198656/4] = +{ + 0x0000bc57, 0x00000000, 0xf0180600, 0x00000400, 0x00010037, 0x000c0000, 0x00030080, 0x54464640, 0xe779a24d, 0x18060057, 0x2c1582d4, 0x2f534f1c, + 0x4d438732, 0x010000a5, 0x360f8248, 0x616d6360, 0xaaaa8970, 0x0f000097, 0x060000cc, 0x7361671a, 0x82ffff70, 0x18062139, 0x00390f82, 0x796c6708, + 0x91ee6d66, 0x320000b4, 0x73050020, 0x61656898, 0x5f8b2264, 0x833b82be, 0x6836211f, 0x05231082, 0x82e30011, 0x8204204f, 0x24280813, 0x78746d68, + 0xb02a4915, 0xa8010000, 0x220e0000, 0x61636f6c, 0xdcf5bf14, 0xe8150000, 0x381c0000, 0x7078616d, 0xa3012807, 0x28201f82, 0x20082f82, 0x6d616e20, + 0x9e9e2065, 0xa5050009, 0x340000b8, 0x736f7068, 0x67514974, 0xda0500f0, 0x3e000020, 0x2dcb84ac, 0x2f000001, 0x5fd6c9aa, 0x00f53c0f, 0x3682040b, + 0xe1000025, 0x83f14751, 0x51e12a08, 0x23fe34d4, 0xa602e3fe, 0x233f8203, 0x02000800, 0x00203184, 0x032d0583, 0x00b8feb6, 0xfe66028f, 0x02c0ff23, + 0x831786a6, 0x20038534, 0x26118304, 0xa2010d07, 0x83001a00, 0x83012000, 0x30038c04, 0x01660202, 0x00050090, 0x028a0200, 0x002f00bc, 0x2807838c, + 0xe0015cff, 0x02013100, 0x20008300, 0x90398409, 0x6942293d, 0x40006472, 0xfffe0000, 0x03298385, 0x204801b6, 0xdfff003f, 0x224b82fd, 0x82b6030e, + 0x00202630, 0x00660201, 0x84098264, 0x240b8202, 0x00ed0000, 0x2e9382a9, 0x0013005b, 0x000a011d, 0x00cd00a8, 0x8229002e, 0x82532005, 0x00413819, + 0x0084003a, 0x004b004c, 0x00480028, 0x00460043, 0x003f0042, 0x82d100ef, 0x002d2a21, 0xff51002c, 0x001200fb, 0x2817824f, 0x005e0045, 0x00330075, + 0x205d8245, 0x2205823d, 0x8226006c, 0x003a2215, 0x20418256, 0x28098248, 0x003c0018, 0x0002001d, 0x342f8209, 0x00940037, 0x009a003e, 0x00f7ff3d, + 0x004400a7, 0x00520060, 0x2011823d, 0x28698242, 0x00a60061, 0x00710076, 0x2061828d, 0x20478261, 0x2803825f, 0x006a0081, 0x00540080, 0x20b48232, + 0x264b8226, 0x015c0065, 0x82660006, 0x00002493, 0x826900e8, 0x00662211, 0x22bb8212, 0x82a00063, 0x00872621, 0x002c0028, 0x220982b2, 0x8296009f, + 0x00a13409, 0x00ee00a3, 0x00350053, 0x00c600e3, 0x007a00ac, 0x840d0074, 0x82602001, 0x8812208b, 0x82002003, 0x00622147, 0x64200185, 0x0383c582, + 0xc3840420, 0xc3823a20, 0x4b240383, 0x4a000400, 0x12200186, 0x5e202182, 0x4420bb82, 0x14200388, 0x3e20c582, 0x0383c582, 0x86006d22, 0x45210184, + 0x20c38300, 0x83c38245, 0x002c2203, 0x200f8218, 0x24038461, 0x005f0034, 0x207b8234, 0x20038844, 0x8b3f8246, 0x00452203, 0x206f822e, 0x2091823d, + 0x2303903e, 0x004c0033, 0x6783038b, 0x23000122, 0x86209382, 0x44260390, 0x36005800, 0x83827700, 0x5d007126, 0x50006c00, 0x5a26038a, 0x2600fbff, + 0x91824600, 0x00200387, 0x6120df82, 0x4520ef82, 0x24260388, 0x48000700, 0x03829700, 0x07847220, 0x6a004622, 0x03893182, 0x42001822, 0x0385d782, + 0x49824a20, 0x00200393, 0x12200082, 0x3723ef84, 0x87006500, 0x82712003, 0x00032415, 0x82020010, 0x841320e7, 0x820420cf, 0x835f8349, 0x94300853, + 0x98009400, 0xab000101, 0x8f00d200, 0x23feac00, 0x27fe85fe, 0x98fe64fe, 0x7900ee00, 0x8fffe2ff, 0x90ff6cff, 0x16ffa7ff, 0x7900a1ff, 0x53001200, + 0x1222d782, 0x5d826200, 0x13004524, 0xef826400, 0x2b001222, 0xc985a982, 0x3c005622, 0x11245b82, 0x09003b00, 0x2520d982, 0x11248582, 0x55002300, + 0x9b22af82, 0x09821a00, 0x21004c22, 0x55223182, 0x11824d00, 0x9b004526, 0x22005d00, 0x3a220982, 0x15825000, 0x5a002822, 0x3b205d82, 0x1a240b82, + 0x2c002600, 0x2320ef82, 0x1a202182, 0x39831982, 0x51003a22, 0x62227582, 0x7f82e9ff, 0x6f824120, 0x7b826420, 0xd9823620, 0xeeff1622, 0x46222182, + 0x89843e00, 0x9f845320, 0x62001024, 0x15840700, 0x05824620, 0x9f820720, 0x62209d85, 0x18203782, 0x21202982, 0x32209d82, 0x39221982, 0x95822e00, + 0x2d822120, 0x28005526, 0x44001700, 0x78241b82, 0x34009a00, 0x1e200782, 0x6128b584, 0x19007600, 0x5e001f00, 0x5e282d82, 0x52005f00, 0x39006a00, + 0x26221f82, 0x69825c00, 0x09823e20, 0x03821e20, 0x71007122, 0x5920f182, 0x3e203582, 0x9a20b982, 0x6a221982, 0x01827200, 0x08007726, 0x21003500, + 0x61204382, 0x5e223582, 0x4b821000, 0x49823a20, 0x9f006c24, 0xfb822f00, 0x23825720, 0x1e000722, 0x55201182, 0x1f241584, 0x6a005b00, 0x46205982, + 0x18204182, 0x12200982, 0x03839f82, 0x30000926, 0x61005000, 0x2d85f182, 0x2d826c20, 0x4100662a, 0xe3005700, 0x48001200, 0x00220384, 0xc7821400, + 0x3a003e24, 0x03844700, 0x55242985, 0x49000d00, 0x83087942, 0x2203877b, 0x826c0059, 0x85e983af, 0x823f2003, 0x006c2473, 0x82290092, 0x824520cf, + 0x003a23fb, 0x00830042, 0x3f003b26, 0x1b002b00, 0x30220582, 0x05823c00, 0x23002526, 0x5c005d00, 0x1b249982, 0x24004a00, 0x1b20c782, 0x2b221f82, + 0x23822000, 0x11823020, 0x17003022, 0x3120ad82, 0x10200982, 0x4a204982, 0x4e221782, 0xa1822300, 0x2b823a20, 0xea00f032, 0x7100bd00, 0x5900bc00, + 0x33005e00, 0x25006000, 0x5c204982, 0x72200982, 0x3520f982, 0x5e225382, 0x7f84cc00, 0x1f825e20, 0xf1825320, 0xdd824d20, 0x0c006d24, 0x0f825400, + 0x31007922, 0x5b200782, 0x5b200982, 0x5e202382, 0x9b206182, 0x28220782, 0x1f824500, 0x00013824, 0x4b82b200, 0x50005026, 0x1c003700, 0x4f200582, + 0x17205182, 0x50220784, 0x07824900, 0x50201383, 0x17201984, 0x17200582, 0x1c22dd82, 0x09824f00, 0xbd824f20, 0x51004522, 0x59202182, 0x46200382, + 0x43834d82, 0x39004c22, 0x35201b82, 0x3220a782, 0x91231582, 0x8b00cb00, 0x00622200, 0x20d1823e, 0x8b038434, 0x200b8917, 0x228d82b2, 0x849b0047, + 0x828e2010, 0x00e72405, 0x82ca00e7, 0x00692103, 0x51200185, 0xa02a7182, 0xf500a000, 0x28008000, 0x2182e300, 0xd6250283, 0x3f008b00, 0x24058500, + 0x00ff0080, 0x2201827a, 0x82deff00, 0x00e72413, 0x821100ad, 0x00532201, 0x22288265, 0x8286009f, 0x00a5283b, 0x009e009f, 0x848e0098, 0x00ec2201, + 0x24098aec, 0x003d0005, 0x2229822f, 0x82360046, 0x00052205, 0x22058205, 0x827b0016, 0x00162cb1, 0x000f0018, 0x00350017, 0x8213001b, 0x00412215, + 0x22118208, 0x82040034, 0x0025220b, 0x20018c0d, 0x220d8c05, 0x8221000d, 0x82002061, 0x21078303, 0x0185005c, 0x15822120, 0x2c002c22, 0x17831b84, + 0x07850f83, 0x0d859783, 0x39200585, 0x5c263186, 0x20005d00, 0x01822900, 0x3b881920, 0x0b012122, 0x07835784, 0x1582a420, 0x03821620, 0x83002121, + 0x85098505, 0x83578741, 0x004e2107, 0x61890185, 0x83868e20, 0x0c002124, 0x0b827a00, 0x05827a20, 0x21220387, 0x01822300, 0x4f8d1583, 0x03832b83, + 0x3a001226, 0x59005f00, 0x25260182, 0xfdfffdff, 0x018a4100, 0x4c007d22, 0x48200182, 0x2c2ae382, 0x53003300, 0xf5009600, 0x01841e00, 0x14005d2a, + 0x3f003f00, 0x52000901, 0x41200186, 0x1b20d982, 0x5e22df82, 0x0582f400, 0x25002c24, 0x37842b00, 0x05982c20, 0x2b201f8b, 0x25202f82, 0x2320298e, + 0x2d830f8c, 0x53822b20, 0x55870385, 0x09871189, 0x23882c20, 0x7d931183, 0x42004222, 0x2f245988, 0x28002f00, 0x3d8d0198, 0x37820e20, 0x3400422e, + 0x8400f500, 0xfcff2c00, 0x2d00fcff, 0x23830182, 0x998f9b8b, 0x49002826, 0xad00e700, 0x2c260384, 0x3e000001, 0x01858c00, 0x857b0121, 0x83058307, + 0x0601250b, 0x06010800, 0x05200584, 0x002c0982, 0xf6fff6ff, 0xe4000c01, 0x1e001e00, 0x0121078b, 0x200d840c, 0x851f83e4, 0x820f9523, 0x83e42039, + 0xc7278703, 0x238f8707, 0xbc00f6ff, 0xbc227982, 0x5985bc00, 0x77910b97, 0x850c0121, 0xd5ff21b7, 0xe5820184, 0x83340121, 0xe4002413, 0x82003401, + 0x200385d7, 0x82009e00, 0x2321862b, 0x00002302, 0x0b880d89, 0x91000321, 0x006e2201, 0x2215846e, 0x88a200a2, 0x8713871d, 0x93358307, 0x20178313, + 0x8353923a, 0x009c2217, 0x20e7879c, 0x840b8200, 0x207d8b03, 0x21378fa0, 0x118ff6ff, 0x30240f86, 0x57003000, 0x03260182, 0x16001b00, 0x01827800, + 0xb700b322, 0xa222ad82, 0x01826900, 0x67006724, 0x0182e400, 0x7d008c26, 0x3a002a00, 0x17220384, 0x07822500, 0x2f821720, 0x07822a20, 0x3d003022, + 0x1b200182, 0xa8200d82, 0x32220382, 0x05823200, 0x3f003026, 0x1a002b00, 0x49224f82, 0x35862c00, 0x0d822820, 0x1b823a20, 0x13000e22, 0x19200182, + 0x9b201782, 0x0e20b582, 0x94241d82, 0xc4009400, 0x5f240182, 0xceff5f00, 0x00230183, 0x8b9a0000, 0x57012101, 0x6d8d0fed, 0xefef0df1, 0xf1f16f8f, + 0x962a718e, 0xc8009600, 0x3a007d00, 0x01822c00, 0x4b002822, 0x2a220784, 0x01829900, 0x78004622, 0x46210182, 0x420d8300, 0x602009f1, 0xf5442182, + 0x006d2b07, 0x0085008b, 0xffd8ff31, 0x008900c8, 0x0a820320, 0x1c220383, 0x09820100, 0x10040024, 0x09840300, 0x04001c24, 0x1182f403, 0x8000d226, + 0x52000600, 0xce080982, 0x017e000d, 0x0192017f, 0x01b001a4, 0x02ff01e7, 0x02c7021b, 0x030303dd, 0x03230309, 0x03a1038c, 0x04f603ce, 0x0463045f, + 0x049b0473, 0x04b304a5, 0x04c404bb, 0x05f904cc, 0x051d0511, 0x055f0556, 0x0e8a0587, 0x1efc103f, 0x1ebd1e85, 0x20f91ef3, 0x2027200a, 0x203f2037, + 0x204b2049, 0x2070205f, 0x208e207e, 0x21b920b5, 0x21262116, 0x215f2151, 0x22e921dd, 0x22152213, 0x22232220, 0x223d222d, 0x228b2269, 0x22b822a4, + 0x22d122c6, 0x23ef22e9, 0x2310230b, 0x25ae2321, 0x276a26ff, 0x27752756, 0x27af2794, 0x27c627be, 0x27eb27e0, 0x29ff28f7, 0x29982988, 0x2afb29eb, + 0x2a2f2a00, 0x2b0d2b6b, 0x2e182e1a, 0xe02e2e25, 0xfeb3e0a2, 0x82ffffff, 0x000026d1, 0x0020000d, 0x2ed382a0, 0x01af01a0, 0x02fe01e6, 0x02c60218, + 0x840003d8, 0x842608d3, 0xa3038e03, 0x0004f403, 0x72046204, 0xa2049004, 0xba04aa04, 0xc704c004, 0x1005cf04, 0x31051a05, 0x61055905, 0xd3828905, + 0x801ed032, 0xf21ebc1e, 0x0020f81e, 0x2f201020, 0x44203920, 0x7426d386, 0xa0208a20, 0xd382b720, 0x5021222a, 0x90215321, 0xeb21e021, 0x1720d382, + 0x2730d382, 0x41223422, 0x8d226d22, 0xc222b222, 0xda22cd22, 0x0420d382, 0x2024d382, 0x00259b23, 0x6820d384, 0x9830d382, 0xc227b127, 0xe627dc27, + 0x0028f527, 0x97298729, 0xfa20d382, 0x6a24d384, 0x162b052b, 0x1f20d382, 0xa022d382, 0xd384b0e0, 0xff012208, 0xffe3fff5, 0x00b0ffc2, 0xff97ff00, + 0xff4cff62, 0xfe8afe34, 0xfe00007a, 0x0039fe52, 0xfdd6fd00, 0x2e0582d5, 0xfda4fda6, 0xfd7afd96, 0xfd70fd74, 0x8266fd6a, 0x60320811, 0x42fd4afd, + 0x2dfd2ffd, 0x2bfd2cfd, 0xe7f177f4, 0x2ee464e4, 0xf6e3fae3, 0xebe2f0e2, 0x0000e4e2, 0xdde2dee2, 0xbae2cae2, 0xace2b7e2, 0x9ae29be2, 0x13823ee2, + 0xe2072208, 0xe1d6e106, 0xe1d3e1d4, 0xe1d1e1d2, 0xe1cce1cf, 0xe1c3e1c6, 0x00bfe1c0, 0xe1a7e100, 0xe199e1a1, 0x33098294, 0xe06ae179, 0xdfa0dff1, + 0xde4bde36, 0xde1cde3a, 0x0018de19, 0xdd3d0082, 0xddedddf6, 0xdd5edde5, 0xdcfedc50, 0xdcecdcf0, 0xdb84dcbe, 0xd8e3dbeb, 0xd80000e6, 0x242082d6, + 0x000d0800, 0x86078301, 0x0bb54203, 0xc4000022, 0xc6201584, 0xd2200584, 0x048b0584, 0x118b1785, 0xb0200b8f, 0x0f82108f, 0x0382aa20, 0x98200297, + 0x9c201888, 0x088b0988, 0x9e009622, 0x0b8e0e8b, 0x0f828c20, 0x9a009622, 0x00240582, 0x44014301, 0x452e0784, 0x59015801, 0x5a010000, 0x5e015d01, + 0x09825f01, 0x61016024, 0x07826201, 0xa4016322, 0xa5240582, 0x2c022b02, 0x02332983, 0x032e022d, 0x001d031c, 0x031e0300, 0x0320031f, 0x83550321, + 0x280f8217, 0x04640456, 0x04660465, 0x230f8367, 0x84046804, 0x002b0783, 0x04850400, 0x04870486, 0x83d70588, 0xd805250f, 0xda05d905, 0x00250983, + 0x06db0500, 0x390983ff, 0x01070007, 0x03070207, 0x06070507, 0x08070707, 0x0a070907, 0x06000b07, 0x1d830a02, 0x41000121, 0x12850c79, 0x85000221, + 0x20078700, 0x20009600, 0x08178401, 0x040003bc, 0x06000500, 0x08000700, 0x0a000900, 0x0c000b00, 0x0e000d00, 0x10000f00, 0x12001100, 0x14001300, + 0x16001500, 0x18001700, 0x1a001900, 0x1c001b00, 0x1e001d00, 0x20001f00, 0x22002100, 0x24002300, 0x26002500, 0x28002700, 0x2a002900, 0x2c002b00, + 0x2e002d00, 0x30002f00, 0x32003100, 0x34003300, 0x36003500, 0x38003700, 0x3a003900, 0x3c003b00, 0x3e003d00, 0x40003f00, 0x42004100, 0x44004300, + 0x46004500, 0x48004700, 0x4a004900, 0x4c004b00, 0x4e004d00, 0x50004f00, 0x52005100, 0x54005300, 0x56005500, 0x58005700, 0x5a005900, 0x5c005b00, + 0x5e005d00, 0x60005f00, 0xc1826100, 0x0086b608, 0x00890087, 0x0093008b, 0x009e0098, 0x00a200a3, 0x00a600a4, 0x00a700a5, 0x00ab00a9, 0x00ac00aa, + 0x00af00ad, 0x00b000ae, 0x00b300b1, 0x00b400b5, 0x00b800b6, 0x00bc00b7, 0x00bd00bb, 0x000b03be, 0x00640072, 0x03690065, 0x0078000d, 0x007000a1, + 0x0055036b, 0x046a0076, 0x00880023, 0x00ef039a, 0x04270473, 0x00670028, 0x03d50377, 0x01e203e4, 0x00f70395, 0x017c006c, 0x00a8007e, 0x008100ba, + 0x036e0063, 0x044201eb, 0x00d9030b, 0x037d006d, 0x00620011, 0x00850082, 0x01140197, 0x02fe0215, 0x030703ff, 0x03030308, 0x05b90004, 0x01c1006a, + 0x0322033a, 0x05274247, 0x00002108, 0x79000c03, 0x09030503, 0x84001403, 0x83008c00, 0x8a008d00, 0x90008f00, 0x8e009100, 0x96009500, 0x943ce182, + 0x9d009c00, 0xf3009b00, 0x56015001, 0x52017100, 0x54015301, 0x57017a00, 0x51015501, 0x02851f82, 0x06823820, 0xe434038b, 0x18010000, 0x0c020000, + 0xc8030000, 0x24060000, 0x14080000, 0x23820382, 0x00b80829, 0x00440900, 0x82040a00, 0x24078303, 0x0b0000f8, 0x20038220, 0x2f038288, 0x0c0000b0, + 0x0d0000e8, 0x0e00002c, 0x10000084, 0x10243382, 0x11000094, 0x13303382, 0x13000050, 0x150000a4, 0x1600005c, 0x170000ec, 0x18252b82, 0x190000c0, + 0x2003821c, 0x82038254, 0xbc1a240f, 0x821d0000, 0xb41d2433, 0x821e0000, 0x821f200b, 0x2420253b, 0x68200000, 0xac270382, 0xc4210000, 0x82220000, + 0x48222177, 0x97820782, 0x07822320, 0x00742324, 0x83822300, 0x005c2425, 0x82382500, 0x00dc2303, 0x3b822600, 0x4f822720, 0x0044292c, 0x00782900, + 0x00a02a00, 0x67822b00, 0x00082c24, 0x1f822c00, 0x00602d24, 0x4b822d00, 0x37822d20, 0x00582e28, 0x008c2e00, 0x1b822f00, 0xb7822f20, 0x4f822f20, + 0x00d43024, 0x4b823200, 0x00283324, 0x0f823400, 0x03833520, 0x3720d782, 0x37282b82, 0x380000f0, 0x39000098, 0x39201b82, 0x3a24bf82, 0x3b000018, + 0x90230383, 0x823c0000, 0x823d20c7, 0xec3d2447, 0x823e0000, 0x833f2033, 0x24378203, 0x00006c40, 0x29078240, 0x0000cc41, 0x0000ac42, 0x03828043, + 0x0000e024, 0x0382d844, 0x0000fc27, 0x00002046, 0x84438247, 0x20978203, 0x20ab8249, 0x201f8249, 0x2cbb824b, 0x00004c4c, 0x0000884c, 0x0000f44e, + 0x200f824f, 0x25078251, 0x00004453, 0x03820054, 0x5420af82, 0x56201f82, 0x57245b82, 0x5800000c, 0x58201482, 0x59245f82, 0x5b000094, 0x5b200f82, + 0x5c28af82, 0x5c000040, 0x5d0000b0, 0x5d245f82, 0x5e0000b4, 0x5f203782, 0x5f243782, 0x600000e4, 0x62200382, 0x64202382, 0x66208f82, 0x67205382, + 0x67243382, 0x680000d0, 0x6a202f82, 0x6b245782, 0x6c000064, 0x6d202382, 0x6e207782, 0x6f2ca782, 0x6f000068, 0x700000d4, 0x7100005c, 0x7120a382, + 0x71249782, 0x720000f0, 0x7328e782, 0x74000030, 0x75000010, 0x76202b82, 0x77200382, 0x78200382, 0x7a288782, 0x7b000070, 0x7c0000c0, 0x7f240382, + 0x80000008, 0x81246f82, 0x830000a4, 0x84206b82, 0x8520ab82, 0x8620b382, 0x87240b82, 0x890000ec, 0x8c206382, 0x8e2c0b82, 0x90000020, 0x930000d8, + 0x95000024, 0x97208b82, 0x99201782, 0x9b203382, 0x9c200f82, 0x9e280782, 0x9f000028, 0xa00000e0, 0xa1207f82, 0xa1247782, 0xa20000c4, 0xa4201782, + 0xa5241782, 0xa60000a0, 0xa72c5782, 0xa80000b8, 0xaa0000c8, 0xab00007c, 0xac207b82, 0xae28b382, 0xaf00006c, 0xb0000048, 0xb0244782, 0xb20000f8, + 0xb3206b82, 0xb424d382, 0xb500002c, 0xb620d782, 0xb8204f82, 0xb920af82, 0xbb20fb82, 0xbc20fb82, 0xbe203b82, 0xbf245b82, 0xc10000cc, 0xc120ef82, + 0xc220a382, 0xc3203782, 0xc4245782, 0xc50000bc, 0xc7258382, 0xc8000034, 0x82038214, 0x90c9243f, 0x82ca0000, 0x82cb206b, 0x82cc202b, 0x82cc2063, + 0x38ce2493, 0x82ce0000, 0x82cf202b, 0xa8d0253b, 0x18d20000, 0xa3820382, 0x2f82d320, 0x00f0d430, 0x003cd600, 0x008cd700, 0x0054d900, 0x7382da00, + 0x2b82db20, 0x00b4dc2c, 0x00f4dd00, 0x0078de00, 0x3f82df00, 0xcf82df20, 0x2782e020, 0x0084e124, 0x5382e200, 0x00fce224, 0x9b82e300, 0x0782e320, + 0x6f82e420, 0x0b82e520, 0x4382e620, 0x0010e724, 0x3382e700, 0x0020e825, 0x8200e900, 0x201b8203, 0x20ef82ea, 0x207b82ea, 0x247b82eb, 0x000040ec, + 0x25a382ec, 0x000008ed, 0x038258ed, 0x0000d023, 0x242b82ee, 0x000098ee, 0x202f82ef, 0x201b82ef, 0x299f82f0, 0x0000e8f0, 0x000074f1, 0x03822cf2, + 0xf3248b82, 0xf3000050, 0xf420f782, 0xf5240b82, 0xf600005c, 0xf6206782, 0xf7200b82, 0xf8208f82, 0xf9202382, 0xfa245782, 0xfb00006c, 0xfc200382, + 0xfd296f82, 0xff000028, 0x00010034, 0x08038240, 0x0100f427, 0x0100fc01, 0x01009402, 0x0100bc03, 0x01007404, 0x0100c005, 0x01001c07, 0x01009008, + 0x0100080a, 0x0100980c, 0x2923820e, 0x01003011, 0x01003813, 0x03820414, 0x0100f828, 0x01006c15, 0x03821016, 0x03826020, 0x18241f82, 0x1a0100d4, + 0x1b281b82, 0x1b010028, 0x1c0100b8, 0x1d2c0f82, 0x1f010088, 0x20010080, 0x220100e0, 0x22203b82, 0x24203782, 0x25200f82, 0x26203b82, 0x27315f82, + 0x280100b4, 0x29010078, 0x2a0100cc, 0x2b0100c8, 0x23038250, 0x2c0100f0, 0x2d208f82, 0x2d25a382, 0x2e0100d8, 0x8203827c, 0x54302413, 0x82310100, + 0x8232202b, 0x2033283b, 0x9c340100, 0x82350100, 0x8c36280f, 0xe8370100, 0x82390100, 0x403b2407, 0x823c0100, 0xd03d2907, 0x703e0100, 0x583f0100, + 0xa8200382, 0xe7820382, 0x005c4024, 0x0b824001, 0x3f824120, 0xd7824220, 0xb3824220, 0x6f824320, 0x47824320, 0x00e44324, 0x07824401, 0x001c4525, + 0x823c4501, 0x00842703, 0x00444601, 0x0f824701, 0x00a04724, 0x6f824801, 0x00a44824, 0x23824901, 0xc7824b20, 0x93824c20, 0x00984d24, 0x0b824e01, + 0x000c4f24, 0x07834f01, 0x4f20f382, 0x50245382, 0x50010060, 0x52243382, 0x52010028, 0x52296b82, 0x530100ec, 0x54010068, 0x20038200, 0x23038264, + 0x550100b0, 0x55244782, 0x560100d0, 0x56206382, 0x5720e382, 0x58204382, 0x59242b82, 0x5a0100b4, 0x5b24fb82, 0x5c01004c, 0x5d204782, 0x5e207f82, + 0x6020bb82, 0x61244f82, 0x620100f8, 0x63203b82, 0x65282782, 0x66010010, 0x68010080, 0x6824ab82, 0x6a0100d4, 0x6b200782, 0x6c28eb82, 0x6d010088, + 0x6e010004, 0x6e20df82, 0x6f200b82, 0x6f20b782, 0x7024db82, 0x71010090, 0x72202f82, 0x73244382, 0x7401008c, 0x7420af82, 0x76207f82, 0x76302782, + 0x770100dc, 0x78010040, 0x79010024, 0x7a01006c, 0x7b28db82, 0x7c010054, 0x7d0100e0, 0x7f249b82, 0x80010034, 0x81205382, 0x822c1f82, 0x830100ec, + 0x840100c0, 0x850100cc, 0x85204382, 0x872c4f82, 0x87010074, 0x880100c8, 0x89010098, 0x8a201b82, 0x8a202b82, 0x8b240782, 0x8c010050, 0x8d25c382, + 0x8e010018, 0x8203822c, 0x828f20a7, 0x8290200f, 0x8290205f, 0x8291201f, 0x8292200b, 0x8292202b, 0x82932063, 0x82932007, 0x289428a7, 0x14950100, + 0x82960100, 0x829620cf, 0x829720f3, 0x82972097, 0x8298202b, 0x8298202b, 0x8299206b, 0xf4992473, 0x829a0100, 0x9c9a2427, 0x829b0100, 0xa89b247b, + 0x829c0100, 0x829d20eb, 0xb89e2547, 0x009f0100, 0xbc230382, 0x82a00100, 0x5ca02153, 0x17820782, 0xff82a120, 0x0f82a220, 0xf382a220, 0xab82a320, + 0x008ca424, 0x5382a601, 0x00e8a724, 0xe782a801, 0x000ca928, 0x00dca901, 0x1f82aa01, 0x0f82ab20, 0x00f0ac24, 0xbf82ad01, 0x00f8ad24, 0x3b82ae01, + 0xbf82af20, 0x00c4af24, 0x4382b001, 0xe782b020, 0xff82b020, 0x0068b124, 0xcb82b201, 0x00b0b224, 0x1b82b301, 0xb782b520, 0x9b82b520, 0xbb82b620, + 0x4382b620, 0xa382b720, 0x0080b724, 0x1782b801, 0x00b4b824, 0x0f82b901, 0x0010ba24, 0xc382bb01, 0x0034bc28, 0x0064bd01, 0x4782be01, 0xc782bf20, + 0x5782c020, 0x7382c020, 0x1f82c220, 0x2b82c220, 0x0094c329, 0x0024c401, 0x8230c501, 0x25978203, 0x01006cc6, 0x038244c7, 0x0100e423, 0x205f82c9, + 0x205782c9, 0x245782ca, 0x0100c0ca, 0x20fb82cb, 0x208782cc, 0x203782cc, 0x201f82cc, 0x243382cd, 0x010078cd, 0x204b82ce, 0x200f82ce, 0x208b82cf, + 0x205b82d0, 0x203382d2, 0x206782d4, 0x20bf82d4, 0x292382d5, 0x010084d5, 0x0100d8d5, 0x038220d6, 0xd720cb82, 0xd8208f82, 0xd825eb82, 0xd90100d4, + 0x82038218, 0x82da2097, 0xc4da241b, 0x82db0100, 0x58dc281f, 0x48dd0100, 0x82de0100, 0x82de2087, 0xf8de246b, 0x82e00100, 0x82e1201f, 0x82e2209b, + 0x40e328cf, 0xb8e30100, 0x82e40100, 0x82e5209f, 0x82e5200f, 0xf4e53047, 0xd0e60100, 0xe8e80100, 0x00ea0100, 0x82ec0100, 0x82ec203f, 0x82ee20cf, + 0x82ef207b, 0x82f0208b, 0x82f1202b, 0x82f2206b, 0x50f3281b, 0xb0f40100, 0x82f60100, 0x82f720d7, 0x38f9287b, 0xbcfa0100, 0x82fb0100, 0x82fc2053, + 0x82fd200f, 0x8cfd2417, 0x82fe0100, 0xff40088b, 0x00020044, 0x01020074, 0x02020080, 0x03020054, 0x04020048, 0x05020090, 0x070200fc, 0x08020040, + 0x0902009c, 0x0a020094, 0x0c0200bc, 0x0d020018, 0x0e0200a4, 0x100200d0, 0x11020024, 0x12020058, 0x12213b82, 0x2f0782b0, 0x140200ec, 0x15020020, + 0x1602003c, 0x17020064, 0x18204f82, 0x192c3b82, 0x1a020038, 0x1b02001c, 0x1c020000, 0x1c301f82, 0x1d0200e4, 0x1e0200f8, 0x1f0200b8, 0x20020088, + 0x20205782, 0x212c0f82, 0x230200cc, 0x2402006c, 0x25020070, 0x25202f82, 0x26208782, 0x28240782, 0x29020050, 0x2a243b82, 0x2b020010, 0x2c283b82, + 0x2d0200a0, 0x2e0200d4, 0x30205b82, 0x31281b82, 0x32020014, 0x33020084, 0x3420c782, 0x35201b82, 0x37283f82, 0x38020098, 0x3902005c, 0x39203f82, + 0x3b242b82, 0x3c0200dc, 0x3e241382, 0x3e0200c4, 0x40246b82, 0x41020078, 0x42241782, 0x440200c0, 0x45208382, 0x45244382, 0x4502004c, 0x4620e782, + 0x4620cf82, 0x48281782, 0x48020008, 0x49020034, 0x4a290f82, 0x4a020004, 0x4b0200c8, 0x24038260, 0x4c0200f0, 0x230382ac, 0x4d0200e8, 0x4e294782, + 0x4f0200f4, 0x500200fc, 0x2303827c, 0x510200a8, 0x5320a382, 0x54205382, 0x54203f82, 0x56201f82, 0x56203382, 0x58203382, 0x59245b82, 0x59020024, + 0x5a209f82, 0x5b20cf82, 0x5c20bf82, 0x5d207782, 0x5e280782, 0x610200e0, 0x6202003c, 0xb8300383, 0x40630200, 0x90640200, 0x18650200, 0x30660200, + 0xcb820382, 0x00b06724, 0xe7826802, 0x13826920, 0x1b826a20, 0x07826b20, 0xef826b20, 0x5b826b20, 0x47826d20, 0xd7826d20, 0x000c6f24, 0x7b827002, + 0x5f827220, 0x7f827320, 0x0b827420, 0x00d07524, 0x23827602, 0x00a47728, 0x00bc7802, 0x63827a02, 0x83827b20, 0x00287c24, 0x43827d02, 0x6b827e20, + 0x3f827f20, 0x9b828020, 0x03828120, 0x00488224, 0x4b828302, 0x00808524, 0x97828602, 0x7b828820, 0x00448924, 0x43828a02, 0x002c8c24, 0x73828d02, + 0x27828e20, 0xf7828f20, 0xbb829120, 0x13829220, 0xe7829320, 0x00349524, 0x6f829702, 0x03829820, 0x00a89924, 0x03829a02, 0x1f829b20, 0x00c09c2c, + 0x00649e02, 0x007c9f02, 0x4382a002, 0xa382a220, 0x00cca228, 0x00b4a302, 0x1b82a402, 0x00e4a534, 0x00eca602, 0x0010a802, 0x006ca902, 0x00c8aa02, + 0x7782ab02, 0x2f82ad20, 0xa382ae20, 0xeb82af20, 0x2382b020, 0x00dcb223, 0x2403ac02, 0xb30200fc, 0x8203821c, 0x60b321df, 0xcf820782, 0xbb82b320, + 0x00d8b324, 0x6b82b402, 0xe782b420, 0x8274b421, 0x2413820b, 0x0200d0b4, 0x20bf82b5, 0x202382b5, 0x249b82b5, 0x020018b6, 0x25f782b6, 0x0200bcb6, + 0x03823cb7, 0xb7201782, 0xb8209782, 0xb9243382, 0xb9020004, 0x0383a782, 0x1f82bc20, 0x00b8c028, 0x00f4c002, 0x6382c102, 0x00f8c125, 0x8238c202, + 0x00a42303, 0x3782c302, 0x5b82c320, 0x2f82c420, 0x004cc525, 0x82c4c602, 0x00e82303, 0x5782c702, 0x1782c720, 0xe382c720, 0x0020c824, 0x7b82ca02, + 0x9382cc20, 0x5f82ce20, 0x8382cf20, 0xd0240383, 0xd002000c, 0xd1257382, 0xd202002c, 0x82038208, 0x84d32433, 0x82d40200, 0x82d42063, 0x82d4205b, + 0x82d4204b, 0x54d5256b, 0x98d50200, 0x3f820382, 0x0f82d520, 0x2f82d620, 0x0088d624, 0xc382d602, 0x2782d720, 0x4382d920, 0x00b0da24, 0x4382db02, + 0x00d4db24, 0xbf82dd02, 0x0050de24, 0x0782e002, 0x0030e224, 0x7f82e402, 0x8782e420, 0x2382e520, 0xa382e720, 0xc782e720, 0x5b82e820, 0x6b82ec20, + 0x0070ee2c, 0x0058ef02, 0x0078f002, 0x1f82f102, 0x0018f324, 0x4f82f402, 0x007cf724, 0xab82f702, 0x2b82f820, 0xe382fa20, 0x2f82fa20, 0x6f82fb20, + 0xacfc2408, 0x10fe0200, 0x78ff0200, 0x4c010300, 0x84020300, 0x28040300, 0xf0050300, 0x50070300, 0xb4080300, 0x820a0300, 0x2c0c281b, 0x700e0300, + 0x82100300, 0x4012281f, 0xd8120300, 0x82130300, 0xac132507, 0x18140300, 0x17820382, 0x00341529, 0x00e41503, 0x82541603, 0x00c42303, 0x0f821703, + 0x00a41731, 0x005c1803, 0x00141903, 0x00901a03, 0x82001c03, 0x00b82303, 0x4b821d03, 0x67821e20, 0x00e01e29, 0x008c1f03, 0x82382003, 0x00b02303, + 0x13822103, 0x00a02124, 0x53822203, 0x63822220, 0x00d42328, 0x00dc2403, 0x7f822603, 0x007c2724, 0x57822903, 0x03822a20, 0x2b822b20, 0x00242c29, + 0x00942c03, 0x82042d03, 0x82742003, 0x00e82b03, 0x00582e03, 0x00602f03, 0x83823003, 0x37823020, 0x2b823120, 0x17823220, 0x000c3424, 0x13823403, + 0x82983421, 0x20738207, 0x20678235, 0x20838235, 0x208b8235, 0x25938236, 0x03004836, 0x03821037, 0x38206f82, 0x392c2382, 0x39030044, 0x3a0300f0, + 0x3b03009c, 0x3b241b82, 0x3c0300c8, 0x3d200782, 0x3e201782, 0x3f209f82, 0x40201782, 0x40259382, 0x410300bc, 0x8203824c, 0x8242206b, 0x8243206b, + 0x64442497, 0x82450300, 0xcc4528bf, 0x80460300, 0x82470300, 0x8847289f, 0x84480300, 0x82490300, 0x824a200f, 0x824a208b, 0x824b203f, 0x824b203f, + 0x344c283f, 0xac4c0300, 0x824d0300, 0x824d2007, 0x824e200f, 0x824e2063, 0x6c4f246f, 0x82500300, 0x82502013, 0x825120bf, 0x8252200f, 0x82532003, + 0xf8532413, 0x82540300, 0x8255204f, 0xec5624eb, 0x82570300, 0x82582073, 0x28592493, 0x82590300, 0x825a200b, 0x825b2063, 0xd05b280b, 0xc05c0300, + 0x825d0300, 0xa85d2443, 0x825e0300, 0x825f20ef, 0x1460247b, 0x82620300, 0x8262201f, 0x6863240f, 0x82650300, 0x0866244b, 0x82660300, 0x8267200b, + 0xa468242b, 0x82690300, 0x3c6a291b, 0xb86b0300, 0x786c0300, 0xaf820382, 0x4f826c20, 0xcb826d20, 0x00986d24, 0xa7826d03, 0x47826e20, 0x23826e20, + 0x00f46e24, 0xa3826f03, 0x3b827020, 0x00d87028, 0x00747203, 0x83827303, 0x2f827420, 0x00dc7624, 0x5b827703, 0x82487721, 0x20bb8207, 0x28278277, + 0x03006478, 0x03009479, 0x205b827a, 0x20eb827c, 0x2903827e, 0x0300cc80, 0x03008c81, 0x03824c82, 0x0300d423, 0x243b8283, 0x03003084, 0x20178284, + 0x24438285, 0x03001887, 0x20078287, 0x209b8288, 0x283b8289, 0x03007c8a, 0x0300548b, 0x20d7828c, 0x20f3828d, 0x288b828f, 0x03006890, 0x03008492, + 0x206f8294, 0x24178295, 0x0300f897, 0x20af8299, 0x20138299, 0x244b829b, 0x0300249c, 0x25bb829c, 0x0300609d, 0x0382109e, 0x0300c023, 0x20e7829f, + 0x241782a0, 0x0300e4a0, 0x20c782a1, 0x209b82a2, 0x200782a2, 0x243382a3, 0x030028a4, 0x20a382a4, 0x208b82a6, 0x208782a7, 0x246382a9, 0x0300aca9, + 0x245782a9, 0x0300b4aa, 0x219382ab, 0x078288ab, 0xac200f82, 0xad20ef82, 0xad286b82, 0xae0300e0, 0xaf0300bc, 0xb0202782, 0xb1248382, 0xb2030098, + 0xb3244382, 0xb50300ec, 0xb6242f82, 0xb7030040, 0xb9206b82, 0xba202382, 0xbb203b82, 0xbd20c382, 0xbe20af82, 0xbf205f82, 0xbf201f82, 0xc0247f82, + 0xc1030034, 0xc2289f82, 0xc303002c, 0xc4030044, 0xc5202382, 0xc6201782, 0xc6247f82, 0xc70300c4, 0xc8246382, 0xc90300fc, 0xca200b82, 0xcb204382, + 0xcd240f82, 0xce030038, 0xcf242b82, 0xd0030058, 0xd1200782, 0xd125bb82, 0xd103005c, 0x23038290, 0xd20300dc, 0xd2200f82, 0xd2200f82, 0xd4240f82, + 0xd5030050, 0xd820e382, 0xd9204f82, 0xdb309782, 0xdd03008c, 0xdf0300e8, 0xe10300f0, 0xe30300a4, 0xe3203f82, 0xe420df82, 0xe420cf82, 0xe524fb82, + 0xe5030020, 0xe5208382, 0xe5206b82, 0xe625b782, 0xe603001c, 0x82038278, 0x60e7243b, 0x82e80300, 0x82e92003, 0xc8e9244b, 0x82ea0300, 0x82ea200b, + 0x24eb24fb, 0x82ec0300, 0x82ec203f, 0x98ec246b, 0x82ed0300, 0x82ef202b, 0x00f028fb, 0xc0f00300, 0x82f10300, 0x94f128e3, 0x70f20300, 0x82f30300, + 0x82f42017, 0x68f6247b, 0x82f70300, 0x82f72037, 0x82f820cf, 0x10f9245f, 0x82fa0300, 0x82fb2077, 0xf8fc258b, 0x3cfe0300, 0x07820382, 0x0070ff25, + 0x829cff03, 0x256f8203, 0x0400f4ff, 0x03822000, 0x04004c24, 0x03821c01, 0x0400d824, 0x03826402, 0x04008824, 0x03821403, 0x0382a020, 0x0400c423, + 0x211f8204, 0x07827804, 0x03829c20, 0x0382c820, 0x05253782, 0x05040018, 0x24038244, 0x060400a8, 0x82038290, 0x82072013, 0x7c072413, 0x82080400, + 0x82082043, 0xec082527, 0x10090400, 0x34200382, 0x58200382, 0x1b820382, 0x00c00925, 0x82040a04, 0x82502003, 0x82982003, 0x00f02403, 0x82480b04, + 0x20478203, 0x2517820c, 0x0400300c, 0x03825c0c, 0x0c218382, 0x240782b4, 0x0d0400e0, 0x2003820c, 0x82038238, 0x820d2057, 0xbc0d216b, 0xe8230b82, + 0x820e0400, 0x400e21a3, 0x6c200782, 0x4b820382, 0xab820e20, 0x00f80e25, 0x822c0f04, 0x82682003, 0x82a42003, 0x20d38203, 0x20278210, 0x256f8210, + 0x04008410, 0x0382b810, 0x11249782, 0x11040028, 0x11204f82, 0x11243782, 0x120400d4, 0x1220a782, 0x1220cf82, 0x1220e782, 0x12207782, 0x13249782, + 0x13040024, 0x1321b782, 0x23078294, 0x140400d0, 0x14209f82, 0x14218782, 0x200b8274, 0x230382b0, 0x150400e4, 0x1521f382, 0x82078254, 0x82152097, + 0x0816257f, 0x4c160400, 0x0f820382, 0x57821620, 0x1f821720, 0xcf821720, 0x00a01724, 0x77821704, 0x3f821820, 0x87821820, 0x4f821820, 0x97821920, + 0x5f821920, 0x009c1924, 0xe7821904, 0x6f821a20, 0x0f821a20, 0x008c1a29, 0x00c81a04, 0x82001b04, 0x202f8203, 0x206f821b, 0x206f821b, 0x253f821b, + 0x0400341c, 0x0382701c, 0x0382ac20, 0x0400f424, 0x0382301d, 0x1d200f82, 0x1d20d782, 0x1e200f82, 0x1e291f82, 0x1e04007c, 0x1f0400c0, 0x2003820c, + 0x8203826c, 0xfc1f243b, 0x82200400, 0xa8202187, 0x47820782, 0x00482124, 0xa3822104, 0x00d82124, 0x63822204, 0x83822220, 0xdf822320, 0x00882324, + 0x8b822304, 0x13822420, 0x1f822420, 0x00e82424, 0x2b822504, 0x37822520, 0x1b822620, 0x07832620, 0x0400cc27, 0x0400f026, 0x20bf8227, 0x206f8227, + 0x21b38227, 0x0f827827, 0x27204382, 0x28201b82, 0x2820b782, 0x28249782, 0x28040064, 0x28203382, 0x28203382, 0x2820cf82, 0x29247782, 0x29040010, + 0x29203382, 0x29203382, 0x2921a782, 0x200f82a0, 0x820382c4, 0x822a2067, 0x822a20af, 0x542a2437, 0x822a0400, 0x822a204f, 0x822a204f, 0x822c20c7, + 0x822e204f, 0x822f208f, 0x942f24e7, 0x822f0400, 0x822f20eb, 0x822f20b7, 0x203025d3, 0x4c300400, 0x67820382, 0x82b43021, 0x00e42407, 0x82083104, + 0x82442003, 0x202f8203, 0x242f8231, 0x0400d031, 0x20538232, 0x20878232, 0x207b8233, 0x20538233, 0x28038235, 0x04002c37, 0x04009838, 0x2017823d, + 0x20b7823d, 0x25ff823e, 0x0400283e, 0x0382603e, 0x03828420, 0x0400bc23, 0x214b823f, 0x07826c3f, 0x0400b023, 0x202f8240, 0x20538240, 0x20c78240, + 0x20c78241, 0x20178241, 0x20178241, 0x20238242, 0x20838242, 0x20e38242, 0x20c38243, 0x208b8243, 0x244f8243, 0x04004844, 0x20238244, 0x20178244, + 0x292f8245, 0x04008c45, 0x0400d445, 0x03825046, 0x47207f82, 0x48209b82, 0x4a201b82, 0x4b201382, 0x4d208382, 0x4f205f82, 0x51202f82, 0x53204b82, + 0x54241782, 0x55040090, 0x56208382, 0x5724bf82, 0x590400dc, 0x5a256782, 0x5b040064, 0x8203825c, 0x825c2013, 0xd85c24ab, 0x825e0400, 0x585f2493, + 0x825f0400, 0x3c602497, 0x82600400, 0xe86025d3, 0x38610400, 0x67820382, 0x53826220, 0x4b826220, 0x00b46224, 0x6b826204, 0x00f86224, 0xeb826404, + 0x2b826420, 0x82746421, 0x2063820b, 0x240f8265, 0x04005465, 0x20838266, 0x25978266, 0x0400fc66, 0x03826868, 0x69201b82, 0x6920bb82, 0x69287782, + 0x6b0400b8, 0x6c040014, 0x6d245f82, 0x6f0400f4, 0x6f201f82, 0x6f20ff82, 0x70254f82, 0x70040040, 0x2003827c, 0x820382a0, 0x82702093, 0x4471243f, + 0x82720400, 0x82732053, 0x82732053, 0x82742013, 0x8275207f, 0x82752067, 0xcc752413, 0x82760400, 0x8276201f, 0x3477295f, 0xac770400, 0x24780400, + 0x88200382, 0xc7820382, 0x67827a20, 0x9f827b20, 0x00a47b24, 0x1f827c04, 0xc7827c20, 0x004c7d24, 0x7b827d04, 0xb3827e20, 0x4b827e20, 0x000c7f24, + 0x0f827f04, 0x07828020, 0x1b828020, 0x00e48024, 0xa7828104, 0xe3828120, 0x00548224, 0x07828204, 0x00288324, 0xa7828304, 0xaf828320, 0x00808424, + 0xa7828504, 0x00088624, 0x3f828604, 0x00788728, 0x00508804, 0x23828904, 0x00e08929, 0x00708b04, 0x82488c04, 0x249b8203, 0x0400a88d, 0x2027828f, + 0x2017828f, 0x20b38291, 0x20738292, 0x241f8293, 0x04006c95, 0x24378297, 0x0400b898, 0x24a78298, 0x0400189a, 0x207b829b, 0x2003829c, 0x20e7829d, + 0x2027829d, 0x20d3829d, 0x20b3829e, 0x24d3829e, 0x0400909f, 0x241382a0, 0x0400dca0, 0x215b82a1, 0x0782f8a1, 0xa2240382, 0xa2040030, 0xa2209782, + 0xa3206b82, 0xa3205f82, 0xa3200b82, 0xa4240b82, 0xa404005c, 0xa425d382, 0xa50400fc, 0x24038260, 0xa60400f0, 0x23038258, 0xa70400e8, 0xa8207782, + 0xa8203782, 0xa8248382, 0xa90400d0, 0xa9246382, 0xaa0400c4, 0xaa20bf82, 0xab208f82, 0xac255f82, 0xac040000, 0x82038264, 0x84ad25ef, 0x3cae0400, + 0x57820382, 0x0b82af20, 0xfb82b020, 0x0024b124, 0x6382b104, 0x00c0b124, 0x0b82b204, 0x00b4b224, 0xc382b304, 0xef82b320, 0x0038b424, 0x6f82b404, + 0x6f82b520, 0x6f82b520, 0x6f82b620, 0x6f82b720, 0x2b82b720, 0x0b82b820, 0x6f82b920, 0x2b82ba20, 0x007cba25, 0x820cbb04, 0x009c2403, 0x8254bc04, + 0x00e42303, 0x0b82bd04, 0x0b82be20, 0x4382bf20, 0x00c8bf28, 0x0080c004, 0x7b82c104, 0x0020c224, 0xfb82c204, 0x4382c320, 0x00a4c425, 0x82b0c504, + 0x245b8203, 0x04004cc6, 0x200b82c6, 0x209382c7, 0x201782c7, 0x205b82c8, 0x20cb82c8, 0x203782c9, 0x201f82c9, 0x246f82ca, 0x040008cb, 0x201382cb, + 0x245782cc, 0x040010cd, 0x20c782cd, 0x203382ce, 0x208382cf, 0x20af82cf, 0x246b82d0, 0x0400f4d0, 0x20db82d1, 0x244782d2, 0x0400f8d2, 0x256b82d3, + 0x04006cd4, 0x038228d5, 0xd6209782, 0xd7208b82, 0xd8241f82, 0xd9040068, 0xda207382, 0xda20fb82, 0xdb288b82, 0xdb040050, 0xdc0400e0, 0xdd20b782, + 0xdd202b82, 0xde202b82, 0xdf200b82, 0xe0207f82, 0xe0206b82, 0xe1246b82, 0xe2040088, 0xe3204b82, 0xe4201f82, 0xe425ef82, 0xe60400f0, 0x23038200, + 0xe7040090, 0xe8244b82, 0xe8040004, 0xe920ab82, 0xea20bf82, 0xeb202b82, 0xec242b82, 0xed04007c, 0xee249782, 0xef04001c, 0xf0202b82, 0xf0204b82, + 0xf220a382, 0xf3242b82, 0xf4040014, 0xf4203782, 0xf4208f82, 0xf5203782, 0xf5200b82, 0xf620af82, 0xf628bb82, 0xf70400d0, 0xf8040060, 0xf8203782, + 0xf9201f82, 0xf9202b82, 0xfa205782, 0xfa201382, 0xfb247782, 0xfc0400ac, 0xfd20c382, 0xfd253382, 0xfe0400b4, 0x28038244, 0xff0400d4, 0x00050090, + 0x2c038220, 0x010500dc, 0x02050094, 0x03050078, 0x2b038208, 0x040500c4, 0x05050080, 0x06050064, 0x072d1f82, 0x07050004, 0x080500e8, 0x090500f8, + 0x2803825c, 0x0a0500ec, 0x0b05007c, 0x82038238, 0x820c202b, 0x820d202b, 0x1c0e300b, 0xac0e0500, 0x680f0500, 0x24100500, 0x82110500, 0x8211204b, + 0xa8122d1f, 0x8c130500, 0x9c140500, 0x2c150500, 0x4b820382, 0x00a0162c, 0x00841705, 0x00401805, 0x2b821905, 0x2b821a20, 0x00181b2c, 0x00d41b05, + 0x00b81c05, 0x2b821d05, 0x4b821e20, 0xa3821f20, 0x2b822020, 0x00b02124, 0x37822205, 0x004c2324, 0xaf822305, 0x006c2425, 0x82282505, 0x00b42703, + 0x00702605, 0x0b822705, 0x000c2824, 0x37822805, 0x00542925, 0x82102a05, 0x00f42303, 0x37822b05, 0xdb822c20, 0xdb822d20, 0x00882e24, 0x63822f05, + 0x63822f20, 0x8f823020, 0x37823120, 0x8f823220, 0x2b823320, 0x2b823320, 0xe7823520, 0x00c03528, 0x00a43605, 0x2b823705, 0x00983824, 0xe7823905, + 0x2b823a20, 0x57823b20, 0x37823c20, 0x00643d25, 0x82203e05, 0x00d83303, 0x00bc3f05, 0x00744005, 0x00584105, 0x003c4205, 0x9b824305, 0xc7824420, + 0x00ec442c, 0x00d04505, 0x00e04605, 0xff824705, 0x37824820, 0x00e44925, 0x821c4b05, 0x20378203, 0x2037824c, 0x20d3824d, 0x209b824e, 0x209b824f, + 0x206f8250, 0x200b8251, 0x24df8252, 0x0500cc53, 0x20df8254, 0x28438255, 0x05002457, 0x05003458, 0x20eb8259, 0x2023825a, 0x205b825c, 0x2047825c, + 0x243f825d, 0x0500305e, 0x2413825e, 0x0500145f, 0x2083825f, 0x20bf825f, 0x204b8260, 0x20038261, 0x20038262, 0x207f8263, 0x25d78264, 0x05005064, + 0x03829064, 0x0500fc24, 0x03826865, 0x66248b82, 0x66050040, 0x6624db82, 0x670500f0, 0x68200782, 0x68200f82, 0x69207b82, 0x6a202782, 0x6c205382, + 0x6c203782, 0x6d206782, 0x6d200782, 0x6d20d782, 0x6d28f382, 0x6e05008c, 0x6f0500f8, 0x70240382, 0x7105009c, 0x72258382, 0x7205000c, 0x820382ac, + 0x82732013, 0x08038247, 0x64000249, 0xf4012f00, 0x07007802, 0x00000f00, 0x34333237, 0x14232211, 0x14213227, 0x34212211, 0x4be14b96, 0x016432e1, + 0xd4fe642c, 0x6c017961, 0xfe92ab79, 0x00009249, 0xed000200, 0x7e01ffff, 0x1700e402, 0x00003700, 0x85272601, 0x35342701, 0x15143332, 0x01850706, + 0x82172221, 0x22232107, 0x35231b85, 0x83363734, 0x32332301, 0x01831617, 0x07141531, 0x020b0106, 0x01030403, 0x55010202, 0x8201011c, 0x03032e07, + 0x0b493c02, 0x0f0f0d0c, 0x0b0a0d0d, 0x22008205, 0x830d0a0b, 0x0c23080d, 0x06050b0b, 0x09010506, 0x3e41412b, 0x171e1e22, 0x29521f5c, 0x221e1e17, + 0x2b41413e, 0x05040af7, 0x830a0405, 0x82102029, 0x200d8837, 0x83458210, 0x01a926ab, 0x02bf01b9, 0x20e385bd, 0x21a38513, 0x07863322, 0x1641a92b, + 0x1542a941, 0xc3b90141, 0x84018541, 0x00012cdf, 0x02660205, 0x004b00b7, 0x84000057, 0x232221b9, 0xc3833183, 0x32210989, 0x22e18233, 0x83333207, + 0x230b8715, 0x23221514, 0x09871585, 0x85232221, 0x21158335, 0x2d851322, 0x4e302384, 0x0a10100a, 0x32632061, 0x070e0d07, 0x33652263, 0x35210f83, + 0x2105831b, 0x0b892952, 0x5d1e5b31, 0x0d0d082f, 0x601f5e08, 0x11100a30, 0x891a350a, 0x833c2421, 0x82082952, 0x2952353d, 0x050d0e07, 0x253d3c25, + 0x311e1235, 0x12371d31, 0x253c3c25, 0x3729038b, 0x31311d12, 0x2512351e, 0x2117833d, 0x0783253d, 0x1d050125, 0x821d3232, 0x37f38203, 0xff5b0003, + 0x022902ed, 0x007100d2, 0x00970085, 0x35260500, 0x27262726, 0x8206bf41, 0x35342209, 0x05bb4116, 0x34200584, 0xf7411d84, 0x41262005, 0x372007dd, + 0x20055541, 0x20278a14, 0x210b8216, 0x27861514, 0x82050b42, 0x15142153, 0x15214b86, 0x062d4214, 0x22151425, 0x42353403, 0x06240539, 0x06151415, + 0x14234386, 0x84373615, 0x34352101, 0x26083d85, 0x01011701, 0x07080301, 0x0d0d0e0e, 0x1919170e, 0x0c0d0e1a, 0x0b0c0d0c, 0x1515140d, 0x13131617, + 0x0f0f1010, 0x820c190d, 0x1d1a311c, 0x3e252121, 0x0c050614, 0x090b0b0b, 0x0a0b0a0a, 0x0a820082, 0x0c0b0c27, 0x09070909, 0x08008508, 0x23233267, + 0x0e0d1b15, 0x1f1d0e0f, 0x3c262222, 0x12121716, 0x08060a0c, 0x0d060601, 0x6612120f, 0x0d14151c, 0x08080710, 0x150f1007, 0x130a1314, 0x01010b12, + 0x03020202, 0x08070502, 0x081c390a, 0x05060607, 0x08040405, 0x91010404, 0x05050348, 0x09090707, 0x1c1d150b, 0x1d1e2424, 0x0f0e1816, 0x260e2b03, + 0x01020113, 0x21348203, 0x37820102, 0x0303022a, 0x051b3603, 0x05040505, 0x02211384, 0x3acf8202, 0x0f084387, 0x1d17150f, 0x1f24231e, 0x0e18191e, + 0x0e2c020d, 0x4181a401, 0x82090a02, 0x143508ce, 0x0d03020b, 0x0c110e0f, 0x885f0808, 0x07080545, 0x1516130a, 0x11111318, 0x06050a0f, 0x05000000, + 0x11001300, 0xac025402, 0x5b003300, 0xb7008f00, 0x0000cb00, 0x0a7d4313, 0x27262722, 0x2209a341, 0x43363736, 0x63410785, 0x41162006, 0x27250785, + 0x33161716, 0x056f4132, 0x73410583, 0x22232107, 0x2005a541, 0x06d94115, 0x5bda0120, 0x9f820520, 0x51438184, 0x08698205, 0xd1220722, 0x0e0e0e0c, + 0x0d0d0d0f, 0x0a0a0b0c, 0x050a0914, 0x0c090904, 0x120f0f0d, 0x0e0d1411, 0x0b0c0c0d, 0x07301682, 0x02050607, 0x14090a03, 0x5e0b0c09, 0x08070706, + 0x0a2f1782, 0x03040304, 0x05010203, 0x0c0a0a05, 0x830e0d0c, 0x8205203e, 0x030a2500, 0x89010505, 0x3e825484, 0x3d820d20, 0x090a1324, 0x54820504, + 0x100f0c26, 0x0e131211, 0x54886982, 0x83020321, 0x0b0b2254, 0x2254835f, 0x9b0c0b0e, 0xfe280854, 0x22221a96, 0x49484625, 0x1a203f30, 0x46262122, + 0x48304848, 0x0305b501, 0x04030302, 0x09060705, 0x1c161712, 0x0f111112, 0x09228a82, 0x9c820408, 0x07221582, 0x9e820909, 0x0c0d0b2e, 0x17171c0d, + 0x06060912, 0x01010336, 0x04208d82, 0x0620a982, 0x0d2e7482, 0x09090b0b, 0x04040405, 0x0b0b0909, 0x0d820e0e, 0xfe22d682, 0x53820629, 0x04050322, + 0x132be982, 0x131b1716, 0x0f0f1011, 0x82080c0b, 0x84022054, 0x21538215, 0xf4820b0a, 0x171b0d2d, 0x07081316, 0x02023607, 0x82040501, 0x060521e5, + 0x07208882, 0x0a215483, 0x20558204, 0x8254830a, 0x0a29080d, 0x47040403, 0x3f3a392c, 0x517b7a76, 0x4039392c, 0x527a7a76, 0x00030000, 0x02f3ff1d, + 0x00d10262, 0x0093005f, 0x010000ab, 0x062d4214, 0x3d421620, 0x42362006, 0x35270529, 0x27363534, 0x82323334, 0x07d34301, 0x222b2183, 0x22232207, + 0x06272627, 0x85230607, 0x27262209, 0x832b8326, 0x83372035, 0x423f840b, 0x03200993, 0x830e8342, 0x34312327, 0x2b833237, 0x85050144, 0x8207204d, + 0x078f4251, 0x35361325, 0x42262734, 0x998508a5, 0x64085782, 0x06049001, 0x213b1818, 0x14141b1a, 0x0f1a1717, 0x03030908, 0x01010201, 0x05351a01, + 0x0e0a0a05, 0x1810110e, 0x182b1518, 0x0c050517, 0x2e27140d, 0x0503352f, 0x242b2b33, 0x01111223, 0x21220a02, 0x15162b3a, 0x26131301, 0x19171816, + 0x10121110, 0xb211122e, 0x13121210, 0x0c0b0b0b, 0x090c0b0d, 0x06050606, 0x08528305, 0x141a0270, 0x0b0e0f15, 0x11150a0b, 0x12181b11, 0x060b0d12, + 0x190c0c05, 0x570e0f0b, 0x1314201f, 0x111d0507, 0x01020510, 0x13150402, 0x0f0e0c12, 0x0e0d5b02, 0x201a0f0d, 0x232a291f, 0x1c1b1a22, 0x1612211d, + 0x1b181915, 0x0504020f, 0x36031506, 0x1b1a2828, 0x14121616, 0x011b1e1f, 0x1f1a0d0d, 0x10101110, 0x2525201f, 0x0a0a0a2b, 0x302f380b, 0x00822127, + 0x22223137, 0x06050c13, 0x0d050203, 0xcafd1e1e, 0x02040406, 0x04030401, 0x2c908204, 0x02030303, 0x01010103, 0x14191a22, 0x08978212, 0x15161c38, + 0x11111224, 0x15151311, 0x1d1d2316, 0x08090a18, 0x2b1bb701, 0x01070b2c, 0x130e0f05, 0x0b0d0a08, 0x12111316, 0x000a0a07, 0x010a0101, 0x026601ba, + 0x000700bf, 0xcf450100, 0x01222c05, 0x4517450a, 0x41c4ba01, 0x820042c3, 0x00012f00, 0x01aeffa8, 0x0007038d, 0x05000027, 0x05462322, 0x090f470f, + 0x2b08cf45, 0x8d011617, 0x1c261b35, 0x0913111d, 0x25080082, 0x0c0c0913, 0x10100e0e, 0x111a3613, 0x0c0b0f0f, 0x10080a0a, 0x21210909, 0x37363952, + 0x35343634, 0x35343434, 0x00821b36, 0x1b1c1a28, 0x1b1b1c1c, 0x02821a1a, 0x36363633, 0x6b6b6b35, 0x00010000, 0x01b3ffcd, 0x000c03b2, 0x427f842b, + 0x87420641, 0x08234205, 0x32272623, 0x0e654633, 0x361d0139, 0x1819211a, 0x06060811, 0x02020405, 0x08100908, 0x0c0c0a0a, 0x8b110f0f, 0x1c12239b, + 0x6a824d1d, 0x821a3621, 0x1b1b2375, 0x0b821b1c, 0x0b873520, 0x0c823820, 0x35259f84, 0x36353635, 0x2b8b8337, 0x025a002e, 0x00640239, 0x1300003f, + 0x16218983, 0x05354117, 0x16250b85, 0x06070617, 0x83878307, 0x82262007, 0x1514239d, 0x01832322, 0x3520e582, 0x2b831387, 0x2e2c1b82, 0x080e0d09, + 0x16412b81, 0x21373721, 0x07830b83, 0x37213408, 0x0e082136, 0x3621090d, 0x08172137, 0x0b20030a, 0x2131302c, 0x080d0d08, 0x20363720, 0x01373620, + 0x15150dc4, 0x8c18460d, 0x123e7c2e, 0x0d111e1e, 0x820d1516, 0x82122007, 0x0d133403, 0x120e1415, 0x93121d1e, 0x4c143d31, 0x1a1a1727, 0x84140d11, + 0x8211201d, 0x8200201d, 0x00012f00, 0x02640029, 0x0055023d, 0x25000017, 0xdd483534, 0x21c18505, 0xab833332, 0x01340382, 0xa738a708, 0xa9153f38, + 0x3f38a938, 0x3c349c64, 0x9d349d14, 0x9c300582, 0x00010034, 0x0155ffcd, 0x008d007d, 0x05000039, 0xf149c783, 0x06374418, 0x22061342, 0x42070607, + 0x27200637, 0x01273582, 0x07070909, 0x820a0907, 0x05200800, 0x0b050404, 0x0f0d0c0b, 0x0a0d0c10, 0x0105060b, 0x01020101, 0x0f0b0202, 0x11131310, + 0x04061011, 0x042a2082, 0x0f160504, 0x0f0b3b0f, 0xfa49120f, 0x0f102505, 0x0a0a0d0d, 0x22081982, 0x0d0a0a05, 0x02040f0d, 0x080a0a0b, 0x0608080a, + 0x16191a1d, 0x0a101015, 0x06060608, 0x07060605, 0x820f1013, 0x01532eb3, 0x01170234, 0x00090085, 0x35341300, 0x32e78220, 0x53201516, 0x01972c01, + 0x3401adfe, 0x190f143d, 0x82001019, 0xffed2427, 0x827e01ff, 0x001f23db, 0xcd4a2500, 0x0a68231f, 0x86820c0d, 0x4a0b0c21, 0xc18a05b9, 0x12060522, + 0x820c954a, 0x050521a8, 0x1022a885, 0x67830d0d, 0xff413408, 0x022902d0, 0x000700e6, 0x37001700, 0x07003332, 0x26014122, 0xfe184763, 0x304862d9, + 0xfdc55102, 0x0000c6b0, 0xff3a0003, 0x022e02f3, 0x001f00cb, 0x82670047, 0x48939e38, 0x814b0b03, 0x1617220f, 0x14f74717, 0x2113f347, 0xdb856601, + 0x0b0a0d29, 0x05040405, 0x410d0a0b, 0x2008089d, 0x18300605, 0x3f1f1b1b, 0x1f1f2f2f, 0x1010100f, 0x2f2f1f1f, 0x1b1b1f3e, 0x14141818, 0x0f101e10, + 0x3604820f, 0x11f31414, 0x27251c1c, 0x11111c1b, 0x08090908, 0x1b1c1111, 0x821c2527, 0x0809270d, 0x2c010908, 0x0082050a, 0x0d090a23, 0x06c5410d, + 0x2e080d83, 0x100d0c0a, 0xfe0d0d10, 0x05050bd3, 0x2c2d1616, 0x5c5c4545, 0x2d2d4545, 0x05061716, 0x11110b0b, 0x45442e17, 0x44455b5c, 0x1111182d, + 0x8211216f, 0x20213600, 0x4f4e3737, 0x21203737, 0x11101011, 0x37382121, 0x37374c4d, 0x39008200, 0x00840001, 0x02fe0100, 0x001500bd, 0x35343300, + 0x35103332, 0x35260706, 0x09823736, 0x32152208, 0x20151433, 0x20246c84, 0x236b016f, 0x246a1846, 0x143ee5fe, 0x19808001, 0x50215259, 0x9b30fe1a, + 0x2b35823d, 0x4c000100, 0x1e020000, 0x7300ca02, 0xcf4c4384, 0x092b4906, 0x4741098f, 0x22232209, 0x4d6d8507, 0x3d470c01, 0x07834106, 0x82010e21, + 0x091a4324, 0x12880983, 0x5608a183, 0x03034c22, 0x10110f06, 0x15151314, 0x0d0c1117, 0x05091109, 0x0d050405, 0x08080a0b, 0x09050606, 0x09090504, + 0x191c1013, 0x2a03021b, 0x01383236, 0x16261813, 0x1c251819, 0x1a151013, 0x11141417, 0x090c0c0f, 0x05040409, 0x04090b05, 0x0b0b1008, 0x0909070e, + 0x820b0a0a, 0x82092048, 0x07072300, 0x0e820a14, 0x110e0e3a, 0x2ae9b2b2, 0x07070915, 0x11110e06, 0x16151313, 0x0d0d1117, 0x04081309, 0x22086382, + 0x0a0d0d0f, 0x0a0a0a0b, 0x12131213, 0x1116171d, 0x16090a0f, 0x1d3a1f14, 0x08120c0a, 0x02050408, 0x82060803, 0x0f0c2557, 0x1412120f, 0x17353882, + 0x05121718, 0x0d0d180a, 0x0909080f, 0x0c0c0b0b, 0x08090a0d, 0x20768208, 0x350e8310, 0x3e110e0d, 0x00000014, 0xff4b0001, 0x022202f3, 0x008900cb, + 0xf6822100, 0x4f462320, 0x08554e08, 0x220b774c, 0x4a321716, 0x614107a1, 0x3534210a, 0x50411592, 0x35342106, 0x420e6148, 0x23840bf9, 0xa3445f8a, + 0x8a013107, 0x1f1c1c18, 0x0e0c0c0d, 0x0e0d0d0d, 0x0e0c0d0b, 0x0e220882, 0x11820c0d, 0x06840483, 0x0c0c5c08, 0x1620202a, 0x0a0a0b17, 0x1e16170b, + 0x133a261e, 0x1b231a33, 0x0a13131b, 0x1209090a, 0x231a1b11, 0x18171615, 0x1a191918, 0x181b1a1f, 0x14161516, 0x1618181a, 0x10141416, 0x02101020, + 0x07040502, 0x19110806, 0x1c252119, 0x070a131d, 0x02040508, 0x23111103, 0x07151511, 0x82010303, 0x02023100, 0x03030401, 0x05040403, 0x0606203f, + 0x05040505, 0x02270e83, 0x08010201, 0x82121109, 0x1f220838, 0x12121819, 0x143a0909, 0x0e0e0707, 0x1b1b1415, 0x0f0e1514, 0x03030707, 0x07060504, + 0x081d3a0a, 0x31820605, 0x03040236, 0x09090607, 0x22221a0d, 0x0e0d0f2b, 0x0b0b0c0c, 0x0e0d1309, 0x11364382, 0x0d0d0c17, 0x10100f0f, 0x26263010, + 0x0b0a0e1c, 0x02000000, 0x04822800, 0xbd024029, 0x2b001b00, 0x46210000, 0x934b0511, 0x15102109, 0x22081546, 0x4d333227, 0x210808b1, 0x06070607, + 0x52f56f01, 0x32343323, 0x1318181b, 0x1e592265, 0xfd441e59, 0x1f133db5, 0x1a12121f, 0x7882191a, 0x2a7d2008, 0x50362141, 0x252a4d50, 0xaafe1c26, + 0x7d133b72, 0x7bf7f52a, 0x1c2e2f1b, 0x2729291b, 0x82131316, 0x0001267f, 0x02f3ff48, 0x207f8217, 0x07734563, 0x42075f48, 0x07420f0f, 0x4a1f860f, + 0x07230807, 0x46203510, 0x014206c1, 0x7c01251a, 0x221e1d19, 0x2906e141, 0x0c0c0d0c, 0x0a0a0b0a, 0x0086170a, 0x21212c39, 0x0b0c1616, 0x06060303, + 0x0b0b0909, 0x10100d0d, 0x13171414, 0x82131413, 0x01112a00, 0x4ae06225, 0x0b0b0b0a, 0x351a8209, 0x171b1a1e, 0x10141317, 0x12111122, 0x15112312, + 0x04080316, 0x00830104, 0x01023508, 0x03030203, 0x41030403, 0x09090c20, 0x02030605, 0x14150a0a, 0x15251e1d, 0x0e0f1111, 0x090a0c0d, 0x05060708, + 0x02020303, 0x06070504, 0x58080109, 0x3973143b, 0x02203182, 0x053f3d82, 0x0c080904, 0x2b200f0c, 0x2c38372b, 0x0c0f202c, 0x0002000b, 0x02f6ff43, + 0x00bf0226, 0x468b0057, 0x03410d99, 0x09ed4507, 0x33323722, 0xe3420183, 0x088d4f09, 0x23222324, 0x72442326, 0x0e214107, 0x82141521, 0x0a894b91, + 0x83076b43, 0x4e23205f, 0x0720060d, 0x440add49, 0x320807cd, 0x2c1de901, 0x1c22382c, 0x1317171c, 0x0c100f12, 0x0308080b, 0x2d161603, 0x3331312c, + 0x0a0a0909, 0x07090204, 0x090a0708, 0x0809090a, 0x10110809, 0x82081211, 0x080e830a, 0x23242521, 0x0e0d1922, 0x11100c01, 0x19191615, 0x2929331e, + 0x0f0f1e1d, 0xf9fe100f, 0x10100f0d, 0x46191a21, 0x092d063c, 0x0d0d0b0a, 0x11100e0e, 0x0d0d0f10, 0x0860820a, 0x05070829, 0x02020304, 0x07050403, + 0x0b080808, 0x0e1f320a, 0x0a06050f, 0x160f100b, 0x211c1c17, 0x2b262721, 0x2a45455f, 0x4816162b, 0x2b820549, 0x3b030224, 0xe182091d, 0x02010236, + 0x13120101, 0x2f2f2323, 0x1212173b, 0x06060d0d, 0x1f200f10, 0x3931c282, 0x06052c2c, 0x0b0a0203, 0x1e1e1514, 0x1e1f2926, 0x21698215, 0x66820505, + 0x06050327, 0x0a0a0808, 0x057f4e0d, 0x11111439, 0x0c0c0f0e, 0x08090a0a, 0x46000100, 0x1c020000, 0x1900bd02, 0x41330000, 0x37220651, 0x61482320, + 0x08175305, 0x1fa73b08, 0x182f3030, 0xfe111617, 0x600159f4, 0x31312176, 0x17171930, 0x724c4f12, 0x353b6e73, 0x143b2936, 0x7a510d1a, 0x393f7679, + 0x03002b39, 0xf3ff4200, 0xcb022702, 0x6f004f00, 0xed419300, 0x07e5410d, 0x4f0c1b4d, 0xd94416eb, 0x4b072007, 0xe5410f13, 0x08494d12, 0x16171423, + 0x421f9213, 0x42080b05, 0x16171415, 0x2d20e601, 0x2c39392d, 0x1020202c, 0x130a0a10, 0x2618190c, 0x090c0b10, 0x0909080a, 0x05070709, 0x0f020304, + 0x120f1e0f, 0x17151511, 0x2a341b17, 0x0f1e1e29, 0x0e070710, 0x2117170e, 0x821b1c25, 0x0820080b, 0x09080404, 0xe1fe0c0c, 0x1e171810, 0x1017171f, + 0x08080711, 0x17101107, 0x171e1f17, 0x08101018, 0x052d0082, 0x221a1a13, 0x131a1a21, 0x030a0912, 0x05f94e03, 0x22241182, 0x13121a1a, 0x09236782, + 0x820d1b28, 0x1a1a2d00, 0x26302526, 0x18181e1e, 0x04080f10, 0x08069051, 0x0c0c0b3f, 0x0e0f0d0d, 0x2121280f, 0x08090c19, 0x04030706, 0x19180c0d, + 0x1f292121, 0x15151a1a, 0x08070f0e, 0x1818100f, 0x18251e1e, 0x12131616, 0x80010f10, 0x0707080e, 0x150f0e08, 0x161d1c16, 0x2ca18216, 0x10070707, + 0x1d16160f, 0xfe15161c, 0x2081829d, 0x0583450a, 0x0f112408, 0x0b0c0c0f, 0x0812080b, 0x12080909, 0x20191912, 0x00191821, 0x00020000, 0x02f9ff3f, + 0x00cb0223, 0x41850059, 0x072505b5, 0x23222726, 0x06515322, 0x42084d53, 0xfc470827, 0x0f35550a, 0xb3513720, 0x4f25201a, 0xa9430e2f, 0x14152c17, + 0xd1011617, 0x3f2f2f1d, 0x820d0c12, 0x095808da, 0x1413150a, 0x11121111, 0x1212130f, 0x23222b12, 0x0e0f1918, 0x08070606, 0x0a0a0808, 0x1a19150a, + 0x2829331e, 0x0f0f1e1e, 0x08080304, 0x1e100c0b, 0x23392a2b, 0x17171c1c, 0x110e1313, 0x07060c0b, 0x05060404, 0x0f0f0b0c, 0x1910e2fe, 0x0e12211a, + 0x0b0d0d0f, 0x0913080a, 0x132b0082, 0x0d0b0a08, 0x120e0f0d, 0x820e0f0f, 0x080b2c15, 0x08080911, 0x17285209, 0x82010416, 0x82042000, 0x1a342600, + 0x03060507, 0x08008201, 0x22111241, 0x41303123, 0x090a0b0c, 0x06070809, 0x0f06070c, 0x2d1f1f10, 0x191c382c, 0x13181718, 0x0f1f1013, 0x0c060610, + 0x1510110b, 0x221c1c18, 0x2b252622, 0x2229292e, 0xf61c1d23, 0x030a0b14, 0x82050603, 0x1e162db1, 0x1f27271e, 0x080a161e, 0x03050608, 0x042c0082, + 0x0b070805, 0x291f1f15, 0x001f1e29, 0x022c0082, 0x6f00ef00, 0x42028101, 0x3f001f00, 0x56154543, 0x03200b9b, 0x2d1e594b, 0x0d0a6a01, 0x0d0f100d, + 0x050a0a0c, 0xaf4c0506, 0x0d0d2806, 0x05050b0a, 0x4b0a0605, 0x82201a2d, 0x2009a44c, 0x4a3d8410, 0x0f2407ec, 0x3c010d0d, 0x841a094b, 0xffd122c3, + 0x20c386c5, 0x21fd4b59, 0x8d4d0320, 0x9a6b2039, 0x096927c1, 0x09070706, 0xf982090a, 0x2128a94d, 0xd99ac801, 0x0c63fe2c, 0x04130f0e, 0x0d0a0a05, + 0x14410f0d, 0x0432080d, 0x0a090b02, 0x08080909, 0x19191d07, 0x10101516, 0x0607070a, 0x06060605, 0x100f1307, 0x29000100, 0x39027400, 0x19004b02, + 0x24250000, 0x24353427, 0x7f581437, 0x06e74408, 0x02141736, 0x8474fe39, 0x1c848c01, 0x4c282524, 0x1c344e4e, 0x4b282525, 0x74280782, 0x133b3193, + 0x1c3a3194, 0x0e397782, 0x131b1c1b, 0x0e0d0d09, 0x121b1b1b, 0x00000041, 0x002d0002, 0x013d02cd, 0x083758f5, 0x14332025, 0x45072015, 0x202105cb, + 0x854f822d, 0x74fe2d55, 0x143ca501, 0x3cd8143c, 0x00143d15, 0x2c269382, 0x3c027200, 0x93834902, 0x82040121, 0x0707462f, 0x20092559, 0x20938204, + 0x233d823c, 0x2924251c, 0x34278883, 0x294b4e4e, 0x821c2524, 0x36012553, 0x1d393193, 0x1c238884, 0x8213121b, 0x0d0e2595, 0x163f0a0d, 0x9383a682, + 0xffff512a, 0xdf022102, 0x5b003b00, 0xd94a6a82, 0x83372008, 0x061f5763, 0x23222323, 0x065b4f22, 0x20063544, 0x09134115, 0x06070622, 0x14210d82, + 0x219b5915, 0x01012408, 0x0f181010, 0x1f111111, 0x08011716, 0x22170d07, 0x0504171c, 0x1c2c3225, 0x190b0a1a, 0x4e414121, 0x823a3b6a, 0x0f162923, + 0x1d101011, 0x4f481616, 0x081bb859, 0x12240726, 0x151a1a22, 0x0c0d0c0e, 0x1e171616, 0x0a0e0e14, 0x1e040512, 0x0611301b, 0x2b341007, 0x492a2c2a, + 0x1b250202, 0x0b2a2183, 0x1616150b, 0x0d0e0e1e, 0x344ff50e, 0x100f2108, 0x2d10d859, 0xfffbff02, 0x02a202e1, 0x00ad00e0, 0x394c00d1, 0x0afb5106, + 0x5a0e0547, 0x07280f7b, 0x23060706, 0x23261514, 0x8b08c14a, 0x0857473b, 0x37833620, 0x33363723, 0x06df4836, 0x07823020, 0x89333221, 0x37162601, + 0x35343536, 0x10794a36, 0x69415d82, 0x0a095905, 0x16204b83, 0x1b820f82, 0x4c0bb345, 0x2a2308c5, 0x49262302, 0x26820652, 0x31023408, 0x2c2d2d1c, + 0x2629292a, 0x1c212127, 0x0e14141a, 0x0707070f, 0x130d0e06, 0x1c181913, 0x1e20201c, 0x45671a1e, 0x06142c44, 0x13080805, 0x130e0f0b, 0x820a1238, + 0x112a0805, 0x290c0f0e, 0x0c211717, 0x06070a0a, 0x03030404, 0x0b0a0706, 0x0f0f0f0d, 0x12111111, 0x0f0e0d13, 0x08090b10, 0x0c090e07, 0x1d830505, + 0x01030239, 0x0c010102, 0x0b01050b, 0x1a121208, 0x1b161f2d, 0x2513120f, 0x8216161b, 0x2320082c, 0x14160d0e, 0x15161228, 0x1e1d1818, 0x3b3a5124, + 0x0e0e0d34, 0x18190c0c, 0x1110c6fe, 0x11131311, 0x94826c82, 0x82100721, 0x126b085c, 0x02020402, 0x1010120a, 0x0206070b, 0x0d070703, 0x07060909, + 0x15150c0c, 0x1c1d1c1e, 0x28281d1e, 0x28283033, 0x1e1e2121, 0x1313191b, 0x07060d0d, 0x18311918, 0x12141b1a, 0x0b131a1a, 0x44ca0706, 0x110f1e01, + 0x08080c0d, 0x04010203, 0x0e1d0e0d, 0x12111010, 0x17191515, 0x14141516, 0x100f1212, 0x08080d0c, 0x04010404, 0x82060803, 0x090e37ba, 0x0a17020d, + 0x0b01010b, 0x10110e13, 0x0304150c, 0x0a0d0101, 0x96820e0d, 0x30342b08, 0x07052f2d, 0x31353b36, 0x0c101013, 0x0107070c, 0x31151401, 0x0e101010, + 0xec15160a, 0x09080810, 0x18111109, 0x181f1d17, 0x0d821217, 0x0809012b, 0x17170f14, 0x1818201f, 0x2c008200, 0x00120002, 0x02560200, 0x001f00bd, + 0x0ac54931, 0x30084b54, 0x26232217, 0x22272627, 0x06070623, 0x32132207, 0x07d74333, 0x03820f83, 0x2a1c1224, 0xb382292a, 0x520f3508, 0x292a1c29, + 0x14131629, 0x0a22460f, 0xae0a1212, 0x11110a57, 0x8e9d4e0a, 0x13140d47, 0x09090b13, 0x14130d07, 0x09090a13, 0x7c828155, 0x2e3c3c43, 0x7d818155, + 0x23360783, 0x22223939, 0x01233939, 0x42422c03, 0x1f1f2240, 0x42432b17, 0xc746233f, 0x00032205, 0x209f824f, 0x249f823a, 0x0043002d, 0x22a18259, + 0x46323510, 0x172107b9, 0x0e445014, 0x200eeb49, 0x59af8323, 0x774206df, 0x23222308, 0x3d4f1114, 0x23330812, 0x458a4f14, 0x202c2b39, 0x01100f1e, + 0x05050102, 0x08070606, 0x05050606, 0x29110d0d, 0x150e1b1c, 0x10110a0a, 0x31322221, 0x5527aa41, 0x191a232a, 0x82081110, 0x11230800, 0x231a1910, + 0x3164205f, 0x121f1e2b, 0x0a0a0913, 0x1e14140a, 0x2570281e, 0x0baf0e02, 0x2117170c, 0x49102b21, 0x32080532, 0x06070909, 0x05040404, 0x0e0f0b07, + 0x1e1f1814, 0x23243026, 0x0c0d1819, 0x07069d01, 0x15150d0d, 0x14131c1c, 0x06060c0b, 0x077dfe9f, 0x170e0f08, 0x82222118, 0x08102464, 0x8200c108, + 0x00012d00, 0x02f3ff46, 0x00cb0219, 0x05000047, 0x5a0aad47, 0xf74c18eb, 0x09cd5a0a, 0x4607434e, 0x23080537, 0x1614ca01, 0x1f241716, 0x181d1c1f, + 0x14271418, 0x11090913, 0x221a1a12, 0x2f292822, 0x13171618, 0x14141313, 0x15210282, 0x22018216, 0x83252431, 0x313122ad, 0x210c8263, 0x18841416, + 0x04134508, 0x06020205, 0x120c0b06, 0x43301911, 0x313a5642, 0x20282931, 0x0b15161f, 0x0402030c, 0x0a070805, 0x0b0e2041, 0x0407080b, 0x24121103, + 0x48363624, 0x0448488f, 0x0a080804, 0x20410f0a, 0x0007070a, 0x45000200, 0x2c260482, 0x1500bd02, 0xdd412f00, 0x4115200d, 0x232206dd, 0xaf413722, + 0x08f58310, 0x23222357, 0x3f7e4510, 0x203b3b55, 0x1410101f, 0x37282613, 0x368e4737, 0x25311d39, 0x0c1a1825, 0x1a0c0c0d, 0x100d0e0d, 0x1f17170f, + 0x0e021541, 0x2b1515af, 0x5b42422b, 0x2b42415a, 0x4e16152b, 0x1d1e0e0f, 0x4e4d3636, 0x101d3635, 0x07070b0a, 0x66fe0404, 0x00010000, 0x208f825e, + 0x208f8223, 0x268d8417, 0x15143320, 0x50142320, 0x0f840805, 0x53015e2f, 0x57f8fe71, 0x4de84ee7, 0xfe580801, 0x295c82ac, 0x349c143b, 0x3fbf143c, + 0x4383143c, 0x43827520, 0xbe022924, 0x43841900, 0x934e3220, 0x15142206, 0x3c498a22, 0x261c7522, 0x504d2a25, 0x55fd3551, 0x3db93eb8, 0xe9d4014a, + 0xa6133901, 0xf6133938, 0x28878252, 0x02f3ff33, 0x00cb0228, 0x0dbd495f, 0x430bef41, 0x715e0907, 0x0813500e, 0x2007315a, 0x0e354b17, 0xe7503720, + 0x06bf6005, 0xcd012408, 0x1e1c1b1a, 0x1c1f2024, 0x1318181b, 0x14141327, 0x37282814, 0x17194637, 0x14171517, 0x0b0a1315, 0x830a0b0b, 0x0b0c2200, + 0x270a820c, 0x2625300c, 0x0c0c1918, 0x2c052550, 0x2424180c, 0x0f0f1032, 0x0606060d, 0x08018205, 0x21650635, 0x16153aac, 0x05090517, 0x0c060604, + 0x1811110d, 0x55434330, 0x2f444357, 0x03191830, 0x0a060703, 0x21410c09, 0x0707080a, 0x04060507, 0x02030304, 0x42010102, 0x4931051f, 0x1a202025, + 0x1216161a, 0x02121223, 0x02010402, 0x27008303, 0x3b308d04, 0x1165ca13, 0x24053b56, 0x02000045, 0x089f4124, 0x3220c183, 0x2205e354, 0x83232215, + 0x15142bd5, 0x194c4522, 0x1a4c45cf, 0x05821a4c, 0xaf0e0231, 0x47d848d7, 0xfaaff2fd, 0x0053fb54, 0x82640001, 0x8603203f, 0x3534253f, 0x35103332, + 0x39513783, 0x15102105, 0x203b4f83, 0x75277664, 0x68370128, 0x27762875, 0x143cc9fe, 0x3b889601, 0xfe143b14, 0x533c8769, 0x3d2405c3, 0xde01f7ff, + 0x2b204382, 0x8308b351, 0x33322143, 0x2408a742, 0x36373637, 0x22598535, 0x42103332, 0x280807c9, 0x1c127e01, 0x1c54291d, 0x143e1746, 0x0f112245, + 0x0b0e0e0f, 0x070e070a, 0xdb308f07, 0x0b060649, 0x0a12120c, 0x3905040a, 0x29f88314, 0x12090606, 0x012f2121, 0x79826227, 0x2c9ec629, 0x1b1b2324, + 0x82001213, 0x00012200, 0x20c38245, 0x207f8264, 0x055f4229, 0x35603320, 0x32372208, 0x057d5933, 0x16171622, 0x2506b945, 0x27262726, 0x15410706, + 0x26390805, 0x1e383a3a, 0x59141c1b, 0x2561c21e, 0x1c353737, 0x51131a1a, 0x2d2d1d29, 0x1515172b, 0x4c133a10, 0xd0af0e02, 0x3a392668, 0x1b1b1d38, + 0x335fbf14, 0x274a4c4c, 0x2b1b2424, 0x05876240, 0xcd143922, 0x01227a82, 0x7f826c00, 0x7f823920, 0x7f860b20, 0x20151022, 0x20288382, 0x01194c6c, + 0xa6fe5a0e, 0xfe224582, 0x2b419b2e, 0x82262006, 0x4144202b, 0x3326052b, 0x33323510, 0x5d531716, 0x2322230b, 0x29503510, 0x08f95208, 0x15102608, + 0x22652622, 0x19112d5a, 0x0c0d1819, 0x2266080c, 0x1b121642, 0x0c0e1a1a, 0x1a330a0c, 0x0e0d0c09, 0x111b1b19, 0x08678242, 0x2a73e522, 0x213d3f40, + 0xfd161e1d, 0x9a01aff2, 0x44452ccc, 0x20202342, 0x20201818, 0x45444223, 0x9a34fe2c, 0x2006a750, 0x20838223, 0x46af861f, 0x17200627, 0x6b828f83, + 0x4637778b, 0x2e1f2b55, 0x15182d2e, 0x19481116, 0x2e1f2a56, 0x16182c2f, 0x82491115, 0x69452a6b, 0x31366669, 0xad012631, 0x2b6c828e, 0x65696946, + 0x25313137, 0x008f54fe, 0x002be282, 0x02f7ff3a, 0x00c6022e, 0x43470027, 0x89580db1, 0x58a1203c, 0x0c2d3e6d, 0x1705060a, 0x442c2d16, 0x445a5a43, + 0x0b4f5843, 0x5a434324, 0x4f584359, 0x82102006, 0x20212800, 0x4b4b3637, 0x58203637, 0x2226055d, 0x4a4b3635, 0xda823636, 0x0002002d, 0x02000056, + 0x00bd022e, 0x4537001d, 0x5b560da3, 0x2223240b, 0x47151423, 0x9f5c0a71, 0x081b830b, 0x49915624, 0x21302f3e, 0x080c0d10, 0x10040407, 0x2f202010, + 0x1e573f30, 0x274e4c4c, 0x0e101013, 0x0a0b0b0d, 0x00820a13, 0x14133208, 0x57241b1b, 0xaf0e021e, 0x0e1b0d0d, 0x14141010, 0x34181717, 0x1b1b2727, + 0x46d40d0d, 0x02036801, 0x07070405, 0x18181207, 0x18181f20, 0x09081112, 0x057f41c6, 0x68029f24, 0xa382c602, 0x00004a23, 0x0aef4437, 0x2008284c, + 0x07435f06, 0x1d820520, 0xab821720, 0x1b432320, 0x21178205, 0x0a832223, 0x3734262b, 0x3637013e, 0x1e173233, 0x20d98702, 0x12ca59c6, 0x1111383a, + 0x09080809, 0x1a1a4301, 0x152b1e1e, 0x18171f1f, 0x1c170e0c, 0x5e3f1f1b, 0x2005155a, 0x05145a3e, 0x10283028, 0x0f0f101e, 0xa259870e, 0x36202305, + 0x5f419636, 0x222f0805, 0x36352221, 0x36354a4b, 0x231f1d4d, 0x230f2c23, 0x081b1b23, 0x05060a06, 0x442c2d2c, 0x4344b443, 0x0617165a, 0x17221605, + 0x5a43432e, 0x833b3f5d, 0x824820df, 0x02322604, 0x003900bd, 0x0d834153, 0x830fe952, 0x0afb43b9, 0x2205bd49, 0x41262322, 0x39510f9f, 0x2386080d, + 0x49924814, 0x1b2c2d3d, 0x0c111021, 0x1613180b, 0x0a101a17, 0x07030309, 0x1d190a06, 0x2348131c, 0x101c1c11, 0x0508080a, 0x09080706, 0x0c0a0d18, + 0x0c250c0c, 0x254a4c4c, 0x111d1d28, 0x0a090912, 0x0a091309, 0x100d0d0b, 0x1d591210, 0x0daf0e02, 0x251e1a0d, 0x1e2d2c25, 0x0f121a1e, 0x111d0d0e, + 0x0c070611, 0x362f130c, 0x38212436, 0x10132137, 0x0f0a0b0f, 0xde01120e, 0x0777014a, 0x170f1008, 0x181e1f17, 0x5f821018, 0x02050424, 0xe744bb02, + 0xff462805, 0x022502f3, 0x438700cb, 0x27200d51, 0x49094d52, 0xd54c0edd, 0x0f1b560b, 0x65105552, 0xf3630ca7, 0x0ed3650f, 0x2f083b5c, 0x2f21e301, + 0x1a1b3f30, 0x1a1b1b1b, 0x1c1c1b1a, 0x35080582, 0x261a1a19, 0x15161d1e, 0x07070b0b, 0x0b0a080f, 0x0f100c0c, 0x07070e12, 0x1616191b, 0x100f1313, + 0x0b0c180c, 0x10221011, 0x16161314, 0x161c191a, 0x0b181716, 0x01820c0d, 0x0c0d0d23, 0x0552470c, 0x18172008, 0x1b251717, 0x0a15151c, 0x0401020b, + 0x07050504, 0x2519190e, 0x1b06070d, 0x19262634, 0x570c0c18, 0x22080516, 0x0d0d1a27, 0x05050302, 0x430a0908, 0x0d0c1122, 0x05040808, 0x10100808, + 0x1a1e1718, 0x080e1213, 0x82050607, 0x0304373b, 0x05070101, 0x08080607, 0x160c0a0a, 0x2f261e1e, 0x0d1b2627, 0x99540a0b, 0x47042005, 0x052f0553, + 0x07204004, 0x06050606, 0x07040404, 0x82070303, 0x15162345, 0x94520c1c, 0x0d062105, 0x032fcb82, 0x0a060102, 0x19191212, 0x1b2a2122, 0x82141617, + 0x00002fc9, 0x00180001, 0x02510200, 0x000f00bd, 0x3b472100, 0x0122350d, 0x013ab002, 0x3baf8eab, 0x9cd2014c, 0x143b143b, 0x009b2dfe, 0x3c243383, + 0x2b02f3ff, 0x63243382, 0x06050000, 0x20062163, 0x13ab4126, 0x35262722, 0x20059345, 0x0bb94814, 0x230da565, 0x36353637, 0xff4b2587, 0x8506200e, + 0x7001330f, 0x0f0e0f0f, 0x201b1c15, 0x0b090a0a, 0x0809090b, 0xb8660708, 0x03330806, 0x01020103, 0x021a4d02, 0x04030301, 0x0f0c0b08, 0x1b161510, + 0x0f15151d, 0x070c0b10, 0x02030304, 0x194c0101, 0x02020101, 0x07030203, 0x09110c0c, 0x830a0909, 0x0d092300, 0x33830a0c, 0x0503072b, 0x05060504, + 0x08070706, 0x3c5b8307, 0x0f0f0b0d, 0x17171212, 0x6c44011d, 0x199fc4fe, 0x0b0a1312, 0x0e060809, 0x07070a0b, 0x3f008204, 0x0b0a0807, 0x0808070d, + 0x12130a0a, 0x77650119, 0x1e90e0fe, 0x11111819, 0x170a0f0e, 0x070f1313, 0x50824a82, 0x00820320, 0x0100002e, 0x00001d00, 0xbd024c02, 0x00002500, + 0x4d08674d, 0x29660989, 0x1bf72a12, 0x15272828, 0x410e1312, 0x29ca8221, 0x21222011, 0x21221616, 0xce821220, 0x87214221, 0x4d5c201b, 0x282f0769, + 0x6e3a3535, 0x4b4b7171, 0x3a6e7171, 0x83283535, 0x3d422417, 0x83002e3c, 0x8202207b, 0x8266207b, 0x9e4b207b, 0x073b477b, 0x66371221, 0x41470ab1, + 0x08514508, 0x08058941, 0x70220720, 0x1314140e, 0x070a090b, 0x0e0a1d39, 0x07070e0e, 0x100a0507, 0x07081010, 0x264a0508, 0x09821109, 0x07082908, + 0x3a133a06, 0x0a09071c, 0x1414140a, 0x0721420d, 0x060c0b0a, 0x0a060706, 0x04060908, 0x0a060505, 0x090c0c0c, 0x4a060809, 0x442fc787, 0x36636767, + 0x3b253030, 0x37676c6c, 0x85202f30, 0x30200807, 0x8ca50120, 0x433c3c2e, 0x5581817d, 0x49414129, 0x26282827, 0x2233333b, 0x221d1e16, 0x474b4b41, + 0x00200b83, 0x0920eb84, 0x5f20eb82, 0x4320eb82, 0x420af14e, 0x6f41078f, 0x116b4105, 0x0f4ff787, 0x08e78b05, 0x11092280, 0x2d171615, 0x111e2e2e, + 0x28161414, 0x48212a29, 0x32322724, 0x1f1e152c, 0x0e0e101e, 0x1c24490b, 0x15282928, 0x1d0e1413, 0x162b2c2c, 0x480f1515, 0x10100c24, 0x21222111, + 0x24241817, 0x11111323, 0x2018520d, 0x44422420, 0x1c172e44, 0x3a381e1c, 0x48392f3b, 0x30214047, 0x17192f30, 0x3c281117, 0x1c203a3d, 0x442e161c, + 0x20244244, 0x1a141820, 0x38351d1a, 0x37252537, 0x1a1d3538, 0xd384141a, 0x2307c74f, 0x21000029, 0x4209ad6a, 0x14241b3d, 0x01012215, 0x2a2e9282, + 0x10151417, 0x22162448, 0x10112121, 0x40420c0f, 0x24492107, 0x2b201b82, 0x4c3e1b83, 0x472f69d2, 0x21254547, 0x38261921, 0x1b1d3739, 0x3926151a, + 0x1b1e3639, 0x482e141a, 0x17824447, 0x4fec1a2b, 0x00010000, 0x02000037, 0x06674931, 0x5a09ad53, 0x36080f11, 0x15143320, 0x452f3720, 0x21244346, + 0xecfe1920, 0x796c015c, 0x2522211a, 0x2f484845, 0xfe642c01, 0x43193085, 0x34626564, 0x3b24302f, 0x24182f14, 0x6234302f, 0x4a436565, 0x942d064f, + 0xcd01a6ff, 0x0f001803, 0x10170000, 0x059d5d35, 0x3405b74b, 0x4eeb9422, 0x37a537a5, 0x95025aea, 0xfd1238dd, 0x1338b7da, 0x2d008200, 0xff3e0001, + 0x022802d2, 0x001b00e9, 0xc7411300, 0x0d214b07, 0x26272638, 0x1f9e3227, 0x182f2b2a, 0x2519191a, 0x401a2222, 0x22221a20, 0x00821925, 0x2b2e2608, + 0x0248202a, 0x55563ee9, 0x3332335d, 0x44444b32, 0x44443434, 0x3333314b, 0x56555d33, 0x0001003e, 0x01a7ff9a, 0x4c9386d2, 0x32250953, 0x22151033, + 0x2c91849a, 0x3859ea4e, 0xb7250213, 0x6bfd1337, 0x249385dc, 0x02b1013d, 0x05eb432b, 0x6d421320, 0x1a654209, 0x25193d3d, 0x12132426, 0x1d3b0d11, + 0x25252519, 0x0d121113, 0x0c08254a, 0x19180d0c, 0x82101119, 0x0d4608a7, 0x53090c0b, 0x3121b101, 0x171a3031, 0x31201117, 0x17193032, 0x100d1217, + 0x24221210, 0x23171723, 0x10122224, 0x01000d10, 0xa7fff7ff, 0xf3ff7202, 0x00000700, 0x20353407, 0x20151433, 0x9fdc0109, 0x395924fe, 0x33413913, + 0x02a72706, 0x03a90133, 0x0e820002, 0xf3420120, 0x084f4209, 0xa9013308, 0x1b12264a, 0x0d0e191b, 0x254a0a0c, 0x0e0d0d09, 0x021b1b1a, 0x27261933, + 0x12121424, 0x12120d0d, 0x26262514, 0x44000200, 0x1302f3ff, 0x5b001b02, 0xc5477f00, 0x07174b0d, 0x21059747, 0xa1513433, 0x0722220a, 0x25978222, + 0x37323332, 0xbd6b3332, 0x14152112, 0x07270183, 0x27222322, 0x83363536, 0x06352337, 0xcd6b0607, 0x56352011, 0x1546051b, 0x15340806, 0x01161714, + 0x1c1b1b6e, 0x2221291d, 0x0d0e1a1a, 0x12110909, 0x1c1d1617, 0x5d201e1e, 0x1309081e, 0x211a1912, 0x12111c38, 0x12161413, 0x14101013, 0x18191914, + 0x152f0082, 0x0c111114, 0x0204050c, 0x0b140102, 0x82012a0a, 0x0e790800, 0x10c71415, 0x1c1b1515, 0x11121717, 0x08090d0d, 0x264e0404, 0x12131314, + 0x0d0f0f13, 0x0806060c, 0x04090408, 0x170a0b04, 0x2a1f1f16, 0x131b1b21, 0x070d0e13, 0x09050408, 0x17172204, 0x07070d0d, 0x19300101, 0x04030101, + 0x0b0b0606, 0x13140e0f, 0x1b1a1218, 0x411a5123, 0x18181b21, 0x090f0115, 0x0705050a, 0x10180b08, 0x060c4611, 0x0d070707, 0x1611110d, 0x19171715, + 0x2585820e, 0x07080404, 0x10820b0c, 0x13131930, 0x60000200, 0x2c02f3ff, 0x3700f602, 0x5f417700, 0x21f3830a, 0x1f432322, 0x0eeb5e05, 0x830e8963, + 0x103b4129, 0x550bbb4b, 0x072115ed, 0x0ba14706, 0x14bb0132, 0x351e191a, 0x02182726, 0x3e020203, 0x0c174515, 0x2b05b84b, 0x1a191e19, 0x11101514, + 0x08090c0c, 0x3c05a95a, 0x09090605, 0x10110c0c, 0x13120ec9, 0x13131717, 0x0b0b0e0e, 0x05050807, 0x01020202, 0x28048201, 0x07080505, 0x0e0e0b0b, + 0x201d8313, 0x251d8312, 0x05060708, 0x1b820302, 0x03012208, 0x07060502, 0x0b0b0b08, 0x1406060c, 0x13112814, 0x39020c13, 0x1464c7bd, 0x0a0a0f0f, + 0x06060505, 0x2276850c, 0x84181916, 0x26048201, 0x14141616, 0x82371010, 0x0505311d, 0x0d0c0a0a, 0x11110f0f, 0x11111112, 0x10111010, 0x0f230783, + 0x830c0c10, 0x231d843b, 0x100f100c, 0x1d821e84, 0x0f290784, 0x000c0d0f, 0xff520001, 0x22d782f3, 0x424f001b, 0x7b530dc1, 0x07794c29, 0x53077b41, + 0x022d0987, 0x28292403, 0x25252c2e, 0x17171e1e, 0x067a6f0f, 0x1e18172f, 0x2c26251e, 0x12151617, 0x13141313, 0x08008212, 0x14141133, 0x1b1b2118, + 0x0e0f1414, 0x05040909, 0x090a0404, 0x14140f0e, 0x17211b1b, 0x14131414, 0x1b101211, 0x080a0a14, 0x18111209, 0x241f2018, 0x23292924, 0x051f4d24, + 0x09092708, 0x05060202, 0x3d0a0708, 0x0c0b0e1e, 0x04040607, 0x0e0e0707, 0x17171211, 0x1b1d191a, 0x17171a1a, 0x0e0e1213, 0x17830707, 0x0f0b0a27, + 0x00020044, 0x26ef823d, 0x00f50209, 0x916f002f, 0x148152f1, 0x32353425, 0x44151033, 0x7b4d0527, 0x7037200a, 0x4b420ecd, 0xad380824, 0x33262519, + 0x151a1a1f, 0x0c111015, 0x0509080d, 0x0f030306, 0x281d1d0f, 0x16183228, 0x10131416, 0x17450b10, 0x03011c37, 0x120dd003, 0x12151612, 0x0a0d0e11, + 0x0607060b, 0x82094342, 0x0a0b220c, 0x24e4820d, 0x12121615, 0x821d820d, 0x081d89de, 0x0707042e, 0x28430a0b, 0x06061414, 0x100f0d0c, 0x17161515, + 0x19191819, 0x32323f19, 0x12122525, 0x0a0a0505, 0xdf140f0f, 0xbdc8fd4b, 0x1915150c, 0x24133b42, 0x11111211, 0x223b4210, 0x3e00022c, 0x2c02f3ff, + 0x3b001b02, 0xb9555500, 0x0dff440d, 0x24051942, 0x20151415, 0x08fb4a23, 0x210ead55, 0xca4e3332, 0x05fd5406, 0x2109fb4a, 0xbd83b601, 0x33324122, + 0x133ebd82, 0x0f0e0708, 0x1d1c1616, 0x382b2324, 0x1e1f2c2b, 0xd5fe0f10, 0x170c0b63, 0x2d222217, 0xe782191a, 0x18171722, 0x54080082, 0x65cad3fe, + 0x07060404, 0x100f0b0c, 0x1a191414, 0x11111515, 0x090a0e0e, 0x05030606, 0x12120203, 0x32322524, 0x2424273f, 0x1919201f, 0x0a091213, 0x22221011, + 0x203c2e2f, 0x2a01020a, 0x19182120, 0x04040d0c, 0x0a0a0708, 0x0a1c3a0b, 0x34010807, 0x12131416, 0x3b408212, 0x0505060a, 0x0e0a0b06, 0x1312120d, + 0x01000014, 0x00004200, 0xe0022802, 0x00002b00, 0x82066b53, 0x091351c7, 0x15143322, 0x8208a545, 0x07cf47fd, 0xe7224908, 0x297c297c, 0x16150b0b, + 0x6e2d2120, 0x192f5d24, 0x0a0a1111, 0x2b7e0405, 0x01462a7f, 0x133b632c, 0x2a2b182f, 0x0a15142a, 0x0512370a, 0x10090a04, 0x1a4c1810, 0xd5fe143a, + 0x00020064, 0x0203ff4c, 0x001b0217, 0x007f0057, 0x21062d57, 0xd1740607, 0x37362408, 0x52343534, 0x7b600775, 0x132d4e07, 0x260c314e, 0x35342734, + 0x82063332, 0x240382a3, 0x06071407, 0x0ae74201, 0x620b4b4f, 0xde3e102d, 0x2d1e1e19, 0x383f4027, 0x24353630, 0x01212242, 0x12121211, 0x1a161513, + 0x151a191e, 0x025e1114, 0x82032006, 0x055a0800, 0x0d090a05, 0x1411110d, 0x1e191a15, 0x15161719, 0x0e111115, 0x011c3701, 0x09080101, 0x1a13cbfe, + 0x1921211a, 0x09101119, 0x03010108, 0x07050502, 0x0d0a0a07, 0x1611120d, 0x121a1a21, 0x090a0913, 0x131bbb0a, 0x34010112, 0x0201011a, 0x1e3c2e2e, + 0x140c180b, 0x05060c0d, 0xea420303, 0x14142405, 0x87181616, 0x17300800, 0x14141716, 0x0c0c100f, 0x04040606, 0x0c0d0809, 0x0e0f0d11, 0x2d2d220a, + 0x60615d32, 0x31323140, 0x0d1a0c01, 0x1a0c0d0c, 0x31252519, 0x11101110, 0x0e3e0282, 0x090c0b10, 0x0d05050a, 0x2519180d, 0x25313124, 0x01000025, + 0x00006100, 0xf5020d02, 0x8f543500, 0x5933200b, 0x162009a7, 0x1423ca82, 0x47232215, 0xbd420ae3, 0x82152009, 0x45613519, 0x26281b17, 0x23060433, + 0x12131a1a, 0x07070d0d, 0x17450303, 0x3d08b383, 0x1a1b1414, 0x10101415, 0x06060b0b, 0x02450403, 0x62c4bd38, 0x0812132b, 0x14101008, 0x1a181914, + 0x52f51b1a, 0x1a236dda, 0x08111119, 0x0d060609, 0x130f0f0c, 0x15141413, 0x02004ae0, 0x9c82a600, 0xdb028126, 0x41001700, 0x22250982, 0x26272223, + 0x21838235, 0x9b853637, 0x14237982, 0x84130607, 0x36352197, 0xc5551982, 0x15142305, 0x03820714, 0x15211d83, 0x83058216, 0x25138403, 0x182f7101, + 0x00820408, 0x17300830, 0x04040308, 0x17450703, 0xa3205f01, 0x00820137, 0x036e0227, 0x1b360704, 0x82178407, 0x04300807, 0x3392fd03, 0x1c1b0a1a, + 0x3a42c42d, 0x10152b13, 0x36151211, 0x0e0f1d12, 0x0b240b0c, 0x0e151010, 0x100f1e04, 0x00001213, 0x76000200, 0xbb0104ff, 0x3320a784, 0x0120a799, + 0x5606f569, 0x23271157, 0x31a60122, 0x82030818, 0x86082000, 0xc8fe3207, 0x162e4748, 0xb1246c16, 0x170b0b3b, 0x29202016, 0x39a0914d, 0x143c96fc, + 0x013a2828, 0x133a796a, 0x2ebb8bfe, 0x19193030, 0x01000d0d, 0x94827100, 0xda025424, 0xcf413100, 0x15102106, 0x2009a14a, 0x06b94106, 0x0815a94a, + 0x22151434, 0x1d184771, 0x172b2c2d, 0x4a101515, 0x29281b25, 0x13131527, 0x2f2f1f0e, 0x1616182d, 0x19264b11, 0x13252626, 0x0d0e1212, 0x480d1515, + 0xfeb62402, 0xa84e8de7, 0x24183d07, 0x11132325, 0x3c280d11, 0x1c1f3a3d, 0x3221161c, 0x171a3032, 0x130b1118, 0x359e0b13, 0x8d2b9782, 0x77010000, + 0x2100be02, 0x41210000, 0x342105b5, 0x20018235, 0x06b74127, 0x2005835e, 0x05bb4115, 0x01222708, 0x010a1f42, 0x4e9c2368, 0x9b260101, 0x332d8534, + 0x2828131a, 0x25143a3f, 0x3a243c3b, 0x41103313, 0x65246d15, 0x52820022, 0x82290021, 0x024524ef, 0x865b001b, 0x071421ef, 0x23055157, 0x17161732, + 0x54065560, 0xc342050f, 0x0f85450b, 0x93857782, 0x6808d950, 0x1d830b39, 0x33292a08, 0x1e11011a, 0x161e2c1f, 0x21170e16, 0x17222b20, 0x070e0e18, + 0x02153f07, 0x02020101, 0x0c060403, 0x1013140d, 0x03050c10, 0x31118302, 0x0201153f, 0x04030301, 0x120d0c07, 0x07101019, 0x17840204, 0x013f3d08, + 0x0f08838b, 0x0f1d090e, 0x1011010e, 0x11102121, 0x19170c0c, 0xe5452e2f, 0x1e64c94c, 0x10101717, 0x0d070c0d, 0x08070607, 0x0c0c080e, 0x16161010, + 0xc94be21d, 0x16171c64, 0x0d0c1111, 0x07261982, 0x070e0707, 0x19820d0d, 0xe21c1723, 0x09bf434b, 0x29001b22, 0x610a1f57, 0xb743094d, 0x3ecd8312, + 0x021b3861, 0x1a010303, 0x56392929, 0x17452a2b, 0x0e0d0607, 0x211b1414, 0x1112191a, 0x82450909, 0x190e29a5, 0x162f0f19, 0x6a353517, 0x320aa343, + 0x16150b0b, 0xe0281f1e, 0x0002004a, 0x02f3ff45, 0x641b0224, 0x456025a3, 0x42222014, 0x152f058d, 0x01161714, 0x2c2c1ee6, 0x2d2d3a3b, 0x820f1f1f, + 0x1f270800, 0x3a2d2c1f, 0x1e2d2c3b, 0x10100f1f, 0x12c6fe0f, 0x23221b1a, 0x12131a1a, 0x090a0a09, 0x1a1a1312, 0x1a1b2223, 0x82091312, 0x23393e00, + 0x12111112, 0x33332423, 0x34334343, 0x12112424, 0x23231212, 0x43443334, 0x1a143333, 0x2a00820e, 0x26251a1a, 0x26263131, 0x820d1a1a, 0x1a1a2200, + 0x2a0d8326, 0x00000025, 0xff5f0002, 0x822a0203, 0x002322c3, 0x06914e3b, 0x35421620, 0x28a3850f, 0x26272223, 0x22151427, 0x241f8213, 0x36373233, + 0x0bc37535, 0x16171423, 0x054f415f, 0x2526183d, 0x27283234, 0x0e0e1d1e, 0x1e1d0e0f, 0x34322727, 0x45172626, 0x191a1275, 0x82214222, 0x22422500, + 0x11121a19, 0x2008b682, 0x4902fd09, 0x16150cc2, 0x1414280c, 0x25251213, 0x40403233, 0x24253333, 0x14141213, 0x0150f028, 0x27ba826e, 0x66653334, + 0x0d0e3332, 0x2520b282, 0xb283c082, 0x452fb382, 0x0f0204ff, 0x2b001a02, 0x00004b00, 0x5e353405, 0xe1490e4f, 0x37362110, 0x20053b70, 0x13f34622, + 0x2007e542, 0x35c38215, 0x2518b301, 0x1a1e3526, 0x11141519, 0x090d0c10, 0x02060509, 0xbb490e03, 0x25333c05, 0x02031825, 0x143f0103, 0x11f4fe45, + 0x20201919, 0x12111a19, 0x08090908, 0x831a1112, 0x1119320d, 0x08080912, 0x6ad4fc09, 0x05141429, 0x110c0c06, 0x07af4610, 0x32411927, 0x14252633, + 0x2ed88213, 0x0c131211, 0x01c2bafd, 0x0e0d1b6b, 0x411b0d0e, 0x302e1198, 0x00002626, 0x00810001, 0x02190200, 0x555e001b, 0x14162207, 0x07c54406, + 0xc54e3320, 0x15142605, 0x23262726, 0x08bf8930, 0x17141550, 0x15161514, 0x1e3c8122, 0x120e0201, 0x1b171813, 0x02031f1b, 0x1a212127, 0x2826231b, + 0x251a0a27, 0x0c0c1713, 0x01450101, 0x1206838b, 0x10151718, 0x050a0b10, 0x090a0105, 0x171d3b14, 0x0e0a0d0c, 0x16161713, 0x1e1e0c17, 0x3f3f3a27, + 0x8783001f, 0x3b4c6a20, 0x4b552006, 0x34210a49, 0x1a3b4835, 0x85107d41, 0x4d2220a7, 0x17200d71, 0xd1724182, 0x01760805, 0x28281ec8, 0x302f2833, + 0x2f2f3536, 0x17171d29, 0x09081212, 0x0e0f0707, 0x0a201818, 0x27130504, 0x12131d1d, 0x0e0d0909, 0x27271b1c, 0x2a2a2b32, 0x28292728, 0x1e1e3d2b, + 0x05050302, 0x0e0f0a0a, 0x191c1617, 0x2323450c, 0x17200f0f, 0x08080b0b, 0x191e3c10, 0x06060d0d, 0x0f100b0c, 0x0e0e1113, 0x08080a0a, 0x01010206, + 0x0d0d0704, 0x18171111, 0x1d1d261e, 0x15831415, 0x1c380f3b, 0x140b0b15, 0x0a0d2713, 0x07070809, 0x05050506, 0x02040506, 0x3a23240d, 0x05bf6128, + 0x8000012d, 0xe601feff, 0x2900ae02, 0x79050000, 0x10230b11, 0x83333235, 0x095b5f01, 0xd3851420, 0x14281582, 0x3871e601, 0x16242434, 0x1f295d82, + 0x1a040c0a, 0xa637a609, 0x08918337, 0x1d151520, 0x09022878, 0x2214140a, 0x13373021, 0x786e4a01, 0xb7143b28, 0x14131d5c, 0x04050909, 0x0082003b, + 0x5400012a, 0x1402f2ff, 0x2f000d02, 0x26207384, 0x2306f747, 0x15143332, 0x816a6382, 0x36352307, 0x83823637, 0x46171421, 0x1b65062f, 0x014f0805, + 0x0404051e, 0x2e2e5c05, 0x201f1744, 0x1a1a233d, 0x08091110, 0x3e010101, 0x1640011e, 0x0e282813, 0x6b353501, 0x6cd951f4, 0x04232345, 0x14130b0a, + 0x501d1818, 0x3f3c5b5c, 0x325d6161, 0x26222e2d, 0x11122413, 0x00010000, 0x02000032, 0x550e0236, 0x200829cb, 0x242419f9, 0x11111324, 0x141f400d, + 0x0f1d1e1e, 0x0b0b0e0e, 0x1d0f0e0e, 0x40141e1e, 0x2425181f, 0x211b8323, 0x67864059, 0x5151362f, 0x26262a4e, 0x26261d1d, 0x51514e2a, 0x21178536, + 0xff84232d, 0x02210482, 0x207b8268, 0x26cb5549, 0x5111dd47, 0x9d5d09f1, 0x832e0808, 0x17181810, 0x090b0b0d, 0x110c1e3d, 0x08091011, 0x06050608, + 0x0d0d0706, 0x2244090d, 0x0e100f0a, 0x05070708, 0x0f100f0b, 0x05080708, 0x2d871e3d, 0x0b1e3a29, 0x09101010, 0x87060807, 0x85422007, 0x222e39ab, + 0x494c4b32, 0x1b232327, 0x19161611, 0x2030302e, 0x2e303020, 0x11161619, 0x27851787, 0x23232d31, 0x1b333635, 0x23131919, 0x1c333536, 0x84131918, + 0x002624e3, 0x82430200, 0x554720e3, 0x874518c3, 0x0e5d7d06, 0x2515b748, 0x07060706, 0xad482622, 0x25182e07, 0x11132425, 0x22450e11, 0x1a1c1b12, + 0x84e1820e, 0x0d0c2407, 0x8722450a, 0x130f311b, 0x28271513, 0x24471b29, 0x1d1e1e14, 0x0b0e0e10, 0x4f380787, 0x31323321, 0x1217181a, 0x2c2e2f1f, + 0x10161618, 0x22232317, 0x0c111012, 0x11220784, 0x605e0c10, 0x17122f07, 0x32311a18, 0x271a2133, 0x12142626, 0x07870e12, 0x462fdf84, 0x190202ff, + 0x54000f02, 0x32170000, 0x60333633, 0x3524085d, 0x22273436, 0x2b06d242, 0x37343534, 0x37323534, 0x15143332, 0x40430182, 0x33322108, 0x35221982, + 0x38832726, 0xc44a1420, 0x83162008, 0x07600823, 0x23222306, 0x77363526, 0x302d2c0f, 0x1118181a, 0x06101127, 0x7e010103, 0x3232543f, 0x1c1d1101, + 0x0b070612, 0x2015160c, 0x1134194b, 0x0c170101, 0x01012f0b, 0x422c2c01, 0x010158b0, 0x1c1e01ae, 0x0a141428, 0x32320812, 0x41413747, 0x1c1c203b, + 0x27760116, 0x1e223366, 0x070d0e1e, 0x384c9907, 0x24089f82, 0x29282b01, 0x28282524, 0x3332592a, 0x5101023d, 0x1315403f, 0x00010014, 0x02000065, + 0x000f0208, 0x3300001f, 0x07a77434, 0x70223721, 0xcc830e31, 0x27652030, 0x1f393b3c, 0xe8151c1b, 0x6531014d, 0x0c823b27, 0x151b1c38, 0xc6fe50f1, + 0x462e1b35, 0x20244445, 0x11331921, 0x462e1a34, 0x0b824346, 0x12351822, 0x5c285f82, 0x030297ff, 0x59002603, 0x4f0e6b44, 0xf8820637, 0x4e0c3975, + 0x14201885, 0x410de34a, 0x3b080c5a, 0x16030214, 0x292a3d0b, 0x0b0b1516, 0x0e0d0706, 0x2c231718, 0x2314270f, 0x0d0d1818, 0x0b0b0607, 0x29291515, + 0x1808193f, 0x1616230c, 0x05050b0b, 0x0b0c0506, 0x1b1b1212, 0x0c0b1212, 0x32053b6d, 0x1b231616, 0x09086909, 0x25261111, 0x23264b34, 0x820e1819, + 0x42440819, 0x0b050516, 0x2219180e, 0x2634264c, 0x09111125, 0x04153f09, 0x140a0703, 0x274e2213, 0x111b1a25, 0x060e0e11, 0x100f0e06, 0x251a1b11, + 0x1421274e, 0x04070a13, 0x00003e04, 0x06010100, 0x5c01b5ff, 0x07000903, 0x3f5bf782, 0x01222c05, 0x40154106, 0xd57f024b, 0x83d581fd, 0x66002c23, + 0x100297ff, 0x69002603, 0x41170000, 0x55711405, 0x4d35200b, 0x23200aa9, 0x5a422d84, 0x09094105, 0x33220f85, 0xb14f3316, 0x06874905, 0x2005e752, + 0x063f4115, 0x66222329, 0x17240b17, 0x820b0a17, 0x062e08f8, 0x11110c0b, 0x11101c1c, 0x0504050c, 0x01020303, 0x0a0b0506, 0x19241717, 0x3f0a1509, + 0x1515292a, 0x03020b0a, 0x08070605, 0x0d0c0a0b, 0xe7820f0e, 0x08187e08, 0x1c250b15, 0x080b131c, 0x03050607, 0x150a0b02, 0x3e2a2a15, 0x153e6917, + 0x0a080404, 0x4d211314, 0x1b1b2527, 0x0e0f1011, 0x0e0f0606, 0x0a0a0810, 0x10100d0d, 0x21274e14, 0x070a1414, 0x153f0304, 0x11110909, 0x4b342625, + 0x0f0f1226, 0x090a0b0c, 0x05040707, 0x42010302, 0x0c050616, 0x0c0a0907, 0x12100f0b, 0x2534264a, 0x09111226, 0x00010008, 0x02f10028, 0x00d7013d, + 0x0100004f, 0x68e18216, 0x27500a5f, 0x0735480f, 0x27260724, 0x61552726, 0x0b756516, 0x13f00135, 0x0227090a, 0x06040402, 0x1e120906, 0x1114291e, + 0x820d0f11, 0x0e142a7f, 0x090a0a0e, 0x0d14090a, 0x3ae7820e, 0x0a130206, 0x0906270a, 0x1e140b08, 0x1113251d, 0x08080f10, 0x09080907, 0x820d0809, + 0x0a0b2300, 0x2f820c0b, 0x0409082a, 0x04b40105, 0x0c080302, 0x0e201482, 0x223ffb82, 0x04041111, 0x100f0808, 0x10101b17, 0x03030706, 0x1b100908, + 0x05111616, 0x23090202, 0x85131b1c, 0x0605231f, 0x4a820806, 0x0f110b26, 0x050a0b0f, 0x11326482, 0x00161611, 0xe8000200, 0x8a01e3ff, 0x1f00c102, + 0xf9823700, 0x4a0cf14c, 0x636c0abb, 0x58172006, 0x17200803, 0x8605d34f, 0xff002bfd, 0x110f0f0b, 0x0c0e0e12, 0x0082060b, 0x0e0c0b23, 0x22e2820f, + 0x820c0b0f, 0x29053676, 0x06041428, 0x03030607, 0x21630203, 0x03040302, 0x02070707, 0x201a84aa, 0x2436820c, 0x0f0e1312, 0x06487c0b, 0x130e0f3a, + 0xe00f0f12, 0x2f313120, 0x12171719, 0x468c359d, 0x19171712, 0x0031312f, 0x692dab83, 0x12026dff, 0x6100a102, 0x00007300, 0x09e95a05, 0x8f559d82, + 0x8337200f, 0x35342499, 0x18143332, 0x82077f45, 0x089d4db1, 0xd74e2d82, 0x69c38609, 0xf3850517, 0x23060722, 0x2720df82, 0x56089f64, 0x013007ef, + 0x191a1b5d, 0x13141616, 0x0c0c1010, 0x05040909, 0x079e4318, 0x1613132c, 0x1d1a1a15, 0x0f100c27, 0xfb82100f, 0x10282082, 0x09080911, 0x08070808, + 0x0c820087, 0x09241083, 0x0a090b07, 0x072d1582, 0x100f1108, 0x210d260e, 0x14141a1b, 0x0800820a, 0x1a14143d, 0x2d5a931b, 0x0a060702, 0x140e0f0a, + 0x19151512, 0x1c1b1a18, 0x191b1b1d, 0x12151618, 0x0b0e0e11, 0x0307070b, 0x2c5a2264, 0x03030202, 0x08060603, 0x08091b36, 0x02030607, 0x82010201, + 0xeffe2200, 0x20088389, 0x291d8202, 0x04030302, 0x04050404, 0x06821b36, 0x01391083, 0x66030204, 0x0f01ce21, 0x0f100388, 0x24231b1c, 0x24242b2b, + 0x100f1c1b, 0x06236500, 0xcb022c2a, 0x00004700, 0x32353433, 0x22210382, 0x18078523, 0x200ecb48, 0xe3461817, 0x0a414b10, 0x49050d44, 0x203805d3, + 0x4a1d5846, 0x0e184b19, 0x291b1c0e, 0x11123629, 0x08061111, 0x090a0a08, 0x0f410282, 0x06220805, 0x1110100f, 0x11181922, 0x8b080710, 0xc92e8b2e, + 0x3c93fe43, 0x3337a314, 0x3c254a11, 0x1e1d2c2d, 0xc7830f0f, 0xc9820120, 0x3925cb82, 0x0505051d, 0x20088204, 0x060d4402, 0x2d21212b, 0x1133194d, + 0x143c36a4, 0x2f008200, 0x00660002, 0x0226025c, 0x00670000, 0x37000087, 0x42079943, 0x17870f19, 0x200a1f48, 0x06e94f33, 0xb16e3720, 0x0f357606, + 0x06230f84, 0x5d070607, 0x23240af7, 0x27262722, 0x6b641382, 0x09c35a0b, 0x3f09974e, 0x0e0f0894, 0x1a1a1009, 0x0606080f, 0x01020303, 0x04040202, + 0x14070506, 0x09111718, 0x0f090f0f, 0x0c221982, 0x02820c0b, 0x170d0b2f, 0x15191818, 0x08101717, 0x0f090e0e, 0x2331831b, 0x02040305, 0x04280082, + 0x08060603, 0x10181715, 0x08203182, 0x0c224b83, 0x33820b0b, 0x180c0d22, 0x142a0082, 0x10561717, 0x17171313, 0x40581313, 0x320d8707, 0x07080808, + 0x0d0d085c, 0x18180f08, 0x0b0c0d0f, 0x830b0a0a, 0x263b8268, 0x130a0a0a, 0x820f1617, 0x2d1b8269, 0x05070f19, 0x02030406, 0x0e070702, 0x15831613, + 0x19273183, 0x0b0b0d0f, 0x820b0b09, 0x82048232, 0x860a2002, 0x8309201b, 0x2631884d, 0x1515130d, 0x82070e7a, 0x100e2800, 0x16151212, 0x850f1211, + 0x120e280d, 0x12151612, 0x6e010012, 0x4d200863, 0x2108617b, 0xb9433332, 0x05634205, 0x410d7b5f, 0x37200a97, 0x42096360, 0x06230559, 0x4c070607, + 0x22360931, 0x32960101, 0x0f083296, 0x2774080e, 0x1e132852, 0x0d101c1e, 0xcb5e0b0e, 0x14280813, 0x101d1f1e, 0x5f0b0e0e, 0x0735691f, 0x97080e0e, + 0x4c339632, 0x0d263eb9, 0x170d050c, 0x0d270d16, 0x2f303120, 0x11161719, 0x200fe15e, 0x06845f20, 0x0d0d273d, 0x0d0d1716, 0xb90d2604, 0x0200003e, + 0xbcff0a01, 0x02036001, 0x0f000700, 0x47010000, 0x03200675, 0x01250786, 0x4015410a, 0x2b038216, 0x0b019e01, 0x59f5fe59, 0x0c011efe, 0x5a210782, + 0x2d008200, 0xff630002, 0x020602a4, 0x00a500cb, 0x9f5600d1, 0x0c416106, 0x44201f4e, 0xdf420ce9, 0x06bf450f, 0xe94a3320, 0x083f4e07, 0x4e097355, + 0x514e134b, 0x13257e09, 0x95410320, 0x0ced560a, 0x18071f4c, 0x260a9f46, 0x2219b201, 0x830a2b22, 0x09430800, 0x0a090809, 0x0b200b0a, 0x1e25252c, + 0x0e141319, 0x0707080d, 0x160d0d06, 0x02031c15, 0x15190602, 0x0d111115, 0x08100b0e, 0x0c060608, 0x1611120b, 0x070b0b0f, 0x0d040407, 0x100d190c, + 0x1211110f, 0x820a1212, 0x0a0a3040, 0x13120809, 0x232a1613, 0x0b0d1e23, 0x820a090b, 0x05072344, 0x43830306, 0x153d3782, 0x03051b14, 0x171e0a02, + 0x0c100f17, 0x0811070c, 0x0b060508, 0x1712110c, 0x080b0b0f, 0x05f47104, 0xbc0c0d3c, 0x22191a12, 0x070c0b10, 0x03040308, 0x06050502, 0x27120807, + 0x0c103c28, 0x0f82070b, 0x0102032e, 0x12090901, 0x340e0e0a, 0x010a0a14, 0x023b0083, 0x03020102, 0x19340309, 0x05090912, 0x0d0a0a05, 0x0e0e100d, + 0x0d0d0c0d, 0x8201100e, 0x0b0e3219, 0x0b0b0b0c, 0x15120c0a, 0x13151914, 0x0e111213, 0x820d820e, 0x0e0f2a1e, 0x18191f11, 0x07060a13, 0x827c8305, + 0x0102324a, 0x07050603, 0x09131a33, 0x02020109, 0x04040402, 0x827e8205, 0x063908c4, 0x0c0c0b0c, 0x0f0d0e0b, 0x05010103, 0x0a0e0e0f, 0x080a0a0b, + 0x18151513, 0x11121215, 0x0c0f0e11, 0x0d0c0c0d, 0x07060607, 0x09080807, 0x011a1a20, 0x0e0e0b18, 0x0b0b0a10, 0x2f7c8309, 0x0809090a, 0x07070809, + 0x1e181810, 0x0a0b0c0a, 0x05215582, 0x3d588206, 0x10111111, 0x00090a09, 0x00020000, 0x017b02a0, 0x00d902c9, 0x002f0017, 0x33321300, 0x064c1732, + 0x140f5709, 0x5c4c2320, 0x36372408, 0x641830ae, 0x302005c6, 0x23055e56, 0x08172fcd, 0x0421bc82, 0x28078608, 0x0303d902, 0x07172d07, 0x95008203, + 0x20838207, 0x2a038203, 0x0268023a, 0x004b007e, 0x5cd70093, 0x7f741151, 0x67a38210, 0x40180f7f, 0x062110c5, 0x5f018407, 0x37200ff5, 0x8332715c, + 0x5337205b, 0xb16b0a03, 0x6f142010, 0x6f76095f, 0x0a536006, 0x2e08e549, 0x1baa0114, 0x3f201e1d, 0x152d3737, 0x480c1111, 0x310805dc, 0x1611110c, + 0x1c191816, 0x1f1e1e1b, 0x1c1d1d20, 0x0c0d0d0f, 0x0a0c0b0d, 0x080a0a0d, 0x05070709, 0x0505060b, 0x08050b06, 0x0a080907, 0x0c0a0c09, 0x20820d0c, + 0x1817e62d, 0x181a1a18, 0x15171818, 0x82091215, 0x06083927, 0x05090506, 0x09050504, 0x130e0f09, 0x16151512, 0x1b191817, 0x1519191b, 0x13232183, + 0x5c090e0e, 0x284205a4, 0x07072e05, 0xf4151612, 0x1e1d1c1a, 0x1a24242d, 0x2c70821a, 0x241a1a0d, 0x0f0e2c24, 0x0d0d100e, 0x2200840e, 0x82070807, + 0x06062200, 0x3c1d820f, 0x090a0b0c, 0x08080811, 0x19121109, 0x1a1c211a, 0x0b501819, 0x15160605, 0x1817152b, 0x2366821b, 0x1b1c1e1e, 0x15248e83, + 0x0a101015, 0x2305a549, 0x08070705, 0xaf829882, 0x00830c20, 0x1b1a0b22, 0x1c23e082, 0x820d181c, 0x0b0c24c0, 0x830a0b0b, 0x0807241d, 0x82050928, + 0x0a092900, 0x08110c0d, 0x0a0a0a09, 0xba821982, 0x1719192c, 0x14161518, 0x0d121114, 0x4049080d, 0x11122c08, 0x15161414, 0x18191717, 0x82161717, + 0x09093947, 0x11070809, 0x0b3d0d0e, 0x0b0c0506, 0x1f201818, 0x20202929, 0x0b0c1818, 0x27054243, 0x07112205, 0x02030504, 0x2c05a943, 0x06060404, + 0x1819110a, 0x18171e1f, 0x050a5a11, 0x00002532, 0x87000300, 0xe001dc00, 0x4d00cb02, 0x75006d00, 0x2217457a, 0x5d313433, 0xa34e135b, 0x37322109, + 0x24088762, 0x22151415, 0x06074823, 0x210b7d42, 0x6f623435, 0x072b4a09, 0x7d4a0720, 0x01223d05, 0x1213105c, 0x1a191f16, 0x090a1213, 0x18170b0c, + 0x452b2121, 0x0f070817, 0x0b0a0a09, 0x10300083, 0x10100f0e, 0x11101110, 0x09101211, 0x08070808, 0x3e08fd82, 0x1621212c, 0x2b0b0b16, 0x02020215, + 0x0f0e0d01, 0x0e0f0b86, 0x16151a12, 0x09081010, 0x1a24152b, 0x07100f1a, 0x03020108, 0x4f040403, 0x01fa53fb, 0x04040858, 0x11100808, 0x1e1a1615, + 0x82111718, 0x82012047, 0x060b262b, 0x03020404, 0x05764801, 0x27070627, 0x05050714, 0x052b4a03, 0x140a0b36, 0x2c1f1f14, 0x100a359e, 0x0b0f0a10, + 0x0409320b, 0x11090805, 0x28084082, 0x04030b1b, 0x0c090705, 0x0709120d, 0x06050508, 0x0f2cba05, 0x00000f2c, 0x28000200, 0xf5014300, 0x1d00f201, + 0x00003b00, 0x09e57925, 0x250d414b, 0x17161716, 0x1d9c1714, 0x0f120135, 0x29171414, 0x1c1c2c2b, 0x17292b2c, 0x1c0f1414, 0x831c2f2f, 0x1de32803, + 0x162a2b2b, 0x88101414, 0x2e2f3107, 0x2f2e1d1d, 0x110c431d, 0x24231311, 0x0d191824, 0x25073867, 0x27181e3c, 0x03831728, 0x84164321, 0x11102213, + 0x7a1d940d, 0xae2605ab, 0x96013c02, 0xb9820b00, 0x66353421, 0x22300797, 0xb3fee801, 0x848c016f, 0x2671ae3f, 0x3aae153c, 0x012de782, 0xe100b200, + 0x2e01b601, 0x00000700, 0x06c54137, 0x41c3b22b, 0x133ae1c3, 0x0000133a, 0x0cd34404, 0xe300c922, 0x2095d544, 0x0cbb4f27, 0x450dd550, 0xeb530861, + 0x06236e09, 0x44186f75, 0x46088de1, 0x26284f07, 0x11121b1b, 0x05050909, 0x10100b0b, 0x05060514, 0x04040308, 0x04040605, 0x10100e04, 0x2312360b, + 0x0b0a0c12, 0x0a090707, 0x3107140c, 0x16112231, 0x0a091010, 0x01010504, 0x03030302, 0x10100906, 0x440d2616, 0x38238beb, 0x480652f5, 0x230805b9, + 0x0a0e0e11, 0x0307080b, 0x07050501, 0x06050604, 0x05050606, 0x11191916, 0x0c141b37, 0x0204050c, 0xb3236903, 0x0624c282, 0x070f0a0b, 0x06281b82, + 0x06030504, 0x00510303, 0x012d0082, 0x87029f00, 0xcd02ca01, 0x00000700, 0x05a34f01, 0xca01322b, 0x02e04ae1, 0x341234cd, 0x2d228212, 0x96000200, + 0xd301a001, 0x3f00cb02, 0x15456b00, 0x0f09610d, 0x18086576, 0x580d9748, 0x0720087f, 0x66127b67, 0x235a0f3f, 0x0f72300c, 0x10111010, 0x0f0e0f0f, + 0x0a0b0d0d, 0x82060808, 0x0b0b2ab8, 0x1c1c1617, 0x07080822, 0x21038209, 0x9c460708, 0x82052005, 0x33d882f4, 0x03050303, 0x170b0c03, 0x8f0d0d0b, + 0x1311110d, 0x09090a0a, 0x06202682, 0x2405014a, 0x0e070601, 0x053f4706, 0x11140b25, 0x830e0d11, 0xab01213b, 0x37823282, 0x08080532, 0x0c0b090b, + 0x0f0f0d0d, 0x1b1b2010, 0x0c0b1516, 0x086a4818, 0x04050429, 0x06040505, 0x82070606, 0x0d052448, 0x820f0e0f, 0x0a142a21, 0x0d450908, 0x01020706, + 0x821d8204, 0x0807291a, 0x08080809, 0x0d101013, 0x04262c82, 0x05010204, 0x84830d06, 0x45101221, 0x2c2d050f, 0x3c020000, 0x17002602, 0x00001f00, + 0x514e1825, 0x07656916, 0xa60a0139, 0x3f37a738, 0xa637a715, 0x01f33f38, 0x74fe848c, 0x3c2774a0, 0x85277414, 0x3ca02205, 0x05cb4e14, 0xa100012d, + 0xbe010e02, 0x4d009f03, 0x7e130000, 0x36200df9, 0x5e053b5c, 0x49180c7f, 0x063121f5, 0x32070607, 0x22151433, 0x242515a1, 0x0c0b1015, 0x08108208, + 0x050a0443, 0x0c070706, 0x1311100c, 0x0e0d0d0e, 0x100f0f0e, 0x0e101011, 0x100e0f10, 0x151c1c23, 0x0509080b, 0x01020206, 0x03020301, 0x130c0503, + 0x1e1a1c13, 0x3399141d, 0x230e02d6, 0x21201412, 0x0b0b0e14, 0x3f008208, 0x0d0e0e07, 0x0c0b0e0c, 0x05040909, 0x04050202, 0x27080607, 0x06050713, + 0x02010303, 0x080f0808, 0x3e05fa47, 0x0708080c, 0x07060607, 0x15161006, 0x1b1b1819, 0x000e2812, 0x02a30001, 0x03ce0109, 0x428100a1, 0x69530785, + 0x1834200e, 0x180b8757, 0x2215ad55, 0x7a353423, 0x47181021, 0x3f410cb5, 0x07cf420c, 0x830f3773, 0x9f01260f, 0x2b212218, 0x21a78209, 0x04820707, + 0x0623b082, 0x51070807, 0x072106c2, 0x08e4820d, 0x14141828, 0x0505070f, 0x02020404, 0x0d0e0707, 0x181b1515, 0x170d1808, 0x0d0c1211, 0x05060606, + 0x11110b0d, 0x0d0c0d15, 0x4384060e, 0xd0423a83, 0x0e0e3305, 0x1d230d0e, 0x0b14161c, 0x0b06060b, 0x1410100b, 0x33841217, 0x020b0c26, 0x08081029, + 0x2a05704c, 0x02010201, 0x25030202, 0x82030313, 0x02022b06, 0x02010401, 0x040a0505, 0x8f830505, 0x0d100931, 0x040a090d, 0x040d2604, 0x0b070704, + 0x4d0d0e0a, 0x2a82052c, 0x03213e82, 0x21348202, 0x3f821326, 0xe2420220, 0x82012005, 0x120e3ea0, 0x0d111713, 0x080b0b0e, 0x09040508, 0x0f0d0d08, + 0x171c1410, 0x00010016, 0x015102ee, 0x06df6bdd, 0x2008e359, 0x07c54723, 0xdd013224, 0x7c5a0e0b, 0x19333d05, 0x191a1911, 0x090c0c0e, 0x0c02034a, + 0x1f110f0f, 0x15152121, 0x111f2121, 0x000c0f0f, 0x012a0082, 0x37ff5300, 0x0e024102, 0x936d5100, 0x06cb5b08, 0x82081b4b, 0x68352057, 0x19860523, + 0x33323327, 0x37323732, 0x09715336, 0x8608f741, 0x3b0f848d, 0x53221514, 0x02021744, 0x06060404, 0x15150f07, 0x18181f1d, 0x08081010, 0x01021746, + 0x08201383, 0x052df482, 0x07060504, 0x080a090a, 0x0808080a, 0x23a78210, 0x0307060a, 0x1025bd82, 0x17141410, 0x08ac822c, 0x02c93e25, 0x6dd9b522, + 0x0d0f0f13, 0x090a0a0c, 0x0a0a0911, 0x1e14140a, 0x4ce7271d, 0x0e87f1fe, 0x0707090a, 0x82020303, 0x172f2301, 0x09820405, 0x05385a82, 0x0d0e0a09, + 0x0e0d1312, 0x04050909, 0xc3241212, 0x01000041, 0xa4ff3500, 0xbd262682, 0x00002300, 0x5a181005, 0xd5821311, 0x22151025, 0x82351023, 0x153d0803, + 0x36170122, 0x0f1d2a2a, 0x08070b0a, 0x10110404, 0x2b2a2121, 0x3538a836, 0x35184712, 0x8409015c, 0x1b0f0f04, 0x110e0e0d, 0x16141411, 0x1b24252c, + 0xfd0d0e1b, 0x2802c6ad, 0xb8d8fdb8, 0x2a008200, 0x01e30001, 0x0185010e, 0x451f00ae, 0x9f4c0da1, 0x14152f0f, 0x6e010607, 0x110f0e0c, 0x0b0f0e11, + 0x0082060c, 0x0f0b0c22, 0x0f215882, 0x058b550e, 0x0b250122, 0x06221382, 0x22820b0b, 0x22821220, 0x0d830a20, 0x22820a20, 0x0f11122b, 0x0001000e, + 0x0147ffc6, 0x23718294, 0x21000033, 0x1809dd55, 0x290a3151, 0x06070607, 0x22232223, 0x01822627, 0x18089d50, 0x2708a35a, 0x0e142723, 0x03070a0a, + 0x22058454, 0x730f0707, 0x6982051b, 0x0a0b0b23, 0x3203820c, 0x14131311, 0x03100f1f, 0x08060503, 0x0d0e0e08, 0x8205060d, 0x07210882, 0x10140607, + 0x04050b0f, 0x01030303, 0x03010201, 0x14290302, 0x0b040407, 0x0908150b, 0x0c0a0a09, 0x319b820c, 0x010e02ac, 0x009703ca, 0x13000019, 0x33323534, + 0x8b823534, 0xd1430720, 0x05fd7b05, 0x15143608, 0x1a4db522, 0x15232315, 0x16242316, 0x1a4d1133, 0x280e02d0, 0x045fbf0d, 0x24040605, 0x06060312, + 0x2855ff04, 0x0003000d, 0x01dc007a, 0x00cb02ef, 0x005b0033, 0x0d534163, 0x670ff546, 0x09410cfb, 0x0bf14b0a, 0x4b1be546, 0x832b08f9, 0x17141311, + 0x10141418, 0x580e0e10, 0x26080583, 0x0d0c0303, 0x0e0e0c19, 0x13141111, 0x14141617, 0x0f0e1111, 0x0d0c1a0b, 0x0b1a0c0d, 0x0fb00e0f, 0x1a191414, + 0x530e1414, 0x0f2e0860, 0x0a080807, 0x0e0c0b0a, 0x0f14131a, 0x0082070e, 0xfe4c2108, 0x5601fd54, 0x04030407, 0x09070704, 0x0f0c0c09, 0x1512110f, + 0x232c1714, 0x0a0c1b23, 0x0407060a, 0x07280082, 0x0c0a0a06, 0x2c23231b, 0x1a201582, 0x46221582, 0x00820912, 0x0b08133e, 0x0f0d0d0a, 0x1a20110e, + 0x07081319, 0x02050408, 0x12090802, 0x211a1913, 0xd91a1921, 0x2706e64b, 0x74000200, 0x41024300, 0x2007e74b, 0x056f4137, 0x2108fd41, 0x01821617, + 0x08674518, 0x1d9c1720, 0x4b1c7421, 0x1c2706d6, 0x17292c2b, 0x820f1414, 0x291724e0, 0x82c62b2c, 0x1d1d2117, 0x1d221b82, 0x17832b2b, 0x2805ed4b, + 0x3b431415, 0x2728171e, 0x33038318, 0x25181e3c, 0x11132224, 0x0d190d11, 0x1310110d, 0x18242423, 0x18201d95, 0x31054773, 0x0d000400, 0x2d0281ff, + 0x19000b03, 0x4d003100, 0x35425900, 0x5607201b, 0x44180709, 0x07240aab, 0x01060706, 0x0f055018, 0x200a7154, 0x07814227, 0x34202782, 0x080e7542, + 0x04035f59, 0x61410303, 0x2d335e62, 0x0402232e, 0x62410205, 0x2e335e61, 0x9167012d, 0x21221631, 0x10101120, 0x2c143c0c, 0x330f2c0f, 0x0922679a, + 0x180d0c0c, 0x83011a19, 0x60bf0d27, 0x03060604, 0x06031324, 0x55ff0305, 0x09960d27, 0x0f091110, 0x0b161716, 0x0a080b0b, 0x830a100f, 0x0c21080b, + 0x8cfe0a0b, 0x13261641, 0x2c2e2d1f, 0x10161517, 0x0d2740bd, 0x828b1641, 0x11100d41, 0x24242213, 0x20008200, 0x20ff8c03, 0x48fdb37f, 0x23414d6d, + 0x16c83b27, 0x0f162424, 0x08080b0c, 0x09060606, 0x06060505, 0x10110c0d, 0x0e0d0d14, 0x95480f0d, 0x3e068205, 0x1c230f0f, 0x090a161c, 0x02050608, + 0x02010203, 0x05030303, 0x1c13140b, 0x141e1d1a, 0x41d6339a, 0x23232d4a, 0x48211411, 0x072505c1, 0x0f060908, 0x276a820d, 0x09090c0b, 0x01020404, + 0x09207e83, 0x8205294f, 0x08072c66, 0x090a080f, 0x0c0b0a0a, 0x8207090b, 0x06072e9e, 0x15151007, 0x1b1b1819, 0x000d2813, 0x08734200, 0x81001328, + 0xb5009900, 0x5944c100, 0x27222208, 0x08d54626, 0xb57a2620, 0x0b154709, 0x480e257d, 0x5f6b2bc9, 0x13c94808, 0xdb420520, 0x2d012a3e, 0x2b212118, + 0x07080809, 0x84f38207, 0x05f25106, 0x08220a82, 0x00820d07, 0x13141825, 0x49050610, 0x06390509, 0x14150e0e, 0x1908191b, 0x1112170c, 0x06060c0d, + 0x0c0c0605, 0x0b161011, 0x058e4b0d, 0x08253a82, 0x07090909, 0x323d8208, 0x0d0d0d0f, 0x161c1c24, 0x050b0a15, 0x110a0b06, 0x85181510, 0x0c0b2333, + 0x4143d5fe, 0x109c2834, 0x01010808, 0x49020201, 0x0223053e, 0x82031327, 0x82022000, 0x49032000, 0x083a0a3e, 0x0d0c1009, 0x04050909, 0x04030d26, + 0x0b0a0708, 0x0a0b0d0e, 0x03040708, 0x26820101, 0x02232c83, 0x82132502, 0x83458207, 0x07062712, 0x13120e0e, 0x26821117, 0x07080b2f, 0x09090505, + 0x0f100c0d, 0x16161d14, 0x359e43bf, 0x6000022c, 0xef01f4ff, 0x2300db02, 0x7d469b00, 0x07d1470d, 0x250b7546, 0x06071415, 0x2d7b0603, 0x0f255509, + 0x4207e954, 0x31240541, 0x35343734, 0x32220183, 0x0f421433, 0x0a9b5708, 0x0b840720, 0x210dbf5f, 0x4f183233, 0x8749088d, 0x2f29830a, 0x0d0b7c01, + 0x0c100f0d, 0x060a0b0d, 0x0a050505, 0x073d0382, 0x09070807, 0x0b0d0d0f, 0x0404050b, 0x0d0c2805, 0x252f0c0d, 0x0e1c1b26, 0x0302020e, 0x2a1d8203, + 0x100c0d08, 0x1606050b, 0x82060608, 0x03042f33, 0x01020205, 0x04041848, 0x0e0f0708, 0x18820c15, 0x05060523, 0x30198407, 0x02010302, 0x04050202, + 0x11070606, 0x0b1a1615, 0x0519540b, 0x17171723, 0x073f5419, 0x0c0c0c24, 0x4b186002, 0x10260810, 0x0a0d0c11, 0x00820304, 0x05010236, 0x0d0a0a04, + 0x0d10110c, 0x028dfd0d, 0x170a0b01, 0x261e1e17, 0x0b229582, 0x48820b0a, 0x0f0d0e22, 0x1422ac82, 0x5b820707, 0x06060528, 0x0f0c0d09, 0x01820302, + 0x2b030834, 0x1718300e, 0x10111314, 0x0b131211, 0x05150505, 0x25830605, 0x00860620, 0x0a0a042c, 0x07090809, 0x060d0508, 0x31820106, 0x0804032d, + 0x3b100c0c, 0x0606071e, 0x82050405, 0x0302217b, 0x33055f45, 0x02000012, 0x00650356, 0x002b000b, 0x0100003d, 0x27262726, 0x21053349, 0x3d4b0122, + 0x087b5908, 0x1e3d4918, 0x1625012e, 0x3e162323, 0x1e1f131e, 0xdafe3a13, 0x304b4918, 0x17e8022b, 0x17172728, 0xfd172827, 0x57491818, 0x20c7852e, + 0x20c78768, 0x5bbb8313, 0x2221056d, 0x2cc7b003, 0x1f1f12f7, 0x151f3e12, 0x3a152424, 0x22c5b1f8, 0x832617ed, 0x172623c5, 0xc5aa13fd, 0x575c0320, + 0x66032905, 0x35001500, 0x00004700, 0xd979c386, 0x07062309, 0xcdb20706, 0x20149c30, 0x1f3f1421, 0x14212114, 0x1a0f172f, 0x0383101a, 0xb19b3421, + 0x18e922d7, 0x2bd78327, 0x1a101827, 0x1b0f0f1b, 0x17fd101a, 0x5126dfb2, 0x79005900, 0xdf828b00, 0x5f232221, 0x9d4a068b, 0x8317200f, 0x331622f3, + 0x23581816, 0x5d352009, 0x23210839, 0xd7661822, 0x8226200c, 0x2326210d, 0x3d6d0585, 0x31f14108, 0x152ace3a, 0x03040102, 0x0d070505, 0x06161011, + 0x07090909, 0x070d090a, 0x050f0304, 0x04200082, 0x07340082, 0x06050607, 0x15290302, 0x0e060601, 0x1511100d, 0x09080807, 0x043a1782, 0x08060605, + 0x0e040307, 0x03020304, 0x03040306, 0x07090403, 0x03050506, 0x6141bc02, 0x0b0c3432, 0x080a090a, 0x070e0709, 0x01020107, 0x07040402, 0x83020203, + 0x210d8203, 0x69820303, 0x0209082a, 0x13121801, 0x08070e0e, 0x02821f82, 0x70820120, 0x23820420, 0x364f0220, 0x03012205, 0x23258304, 0x16fd030a, + 0x202a9b41, 0x067b4204, 0x1700652b, 0x4f002f00, 0x00006100, 0x0a375b13, 0x200b5f72, 0x44179633, 0xf624312d, 0x03081830, 0x08200082, 0x2006955b, + 0x0e8d5bbc, 0x4151fe21, 0x032e3040, 0x06040406, 0x0407162d, 0x07040303, 0x0d82172c, 0xfc210f8f, 0x2a1641fa, 0x93430020, 0x007e2607, 0x006d0049, + 0x119b697f, 0x7a13e946, 0xa3691091, 0x7b4e180d, 0x16336d07, 0x200b5b54, 0x9f4e1803, 0x0e380811, 0x26151213, 0x0e1a2727, 0x08080b0c, 0x04050404, + 0x0c0c0a09, 0x12110f10, 0x0d0e0f13, 0x0a0b0d0c, 0x0807080a, 0x03020605, 0x08080404, 0x230f0b0b, 0x13232627, 0x460e1111, 0x0bc54e18, 0x0d0bd230, + 0x0e10100d, 0x060b0a0e, 0x0b060505, 0x00830705, 0x10070827, 0x0b0b0c0d, 0x08008206, 0x478e2a20, 0x0a0a0907, 0x0d141313, 0x1314130d, 0x2b09090a, + 0x743f3839, 0x08507979, 0x0e0d0c0b, 0xcd5d0f10, 0x0b230806, 0x05040809, 0x06050302, 0x08090607, 0x0b0c0a0a, 0x110e0e0d, 0x0d0e100f, 0x6a0a0b0b, + 0x3a6c7677, 0x182b3534, 0x22070f4f, 0x830aca02, 0x0a0a316c, 0x0f0f0c0d, 0x050a0d0d, 0x03020404, 0x05060201, 0x0d3a1182, 0x0d0c0f0f, 0x1f172ffe, + 0x423f221f, 0x422b2b42, 0x1f223f42, 0x0000001f, 0x00820002, 0x024e022b, 0x002700bd, 0x31000035, 0x06254836, 0x18332021, 0x200d7d4c, 0x210f8432, + 0x5b413534, 0x33322207, 0x820b8610, 0x192f089a, 0x13252526, 0x010e1112, 0x2a7f5e1a, 0x26732673, 0x44cc2d85, 0x10093b75, 0x8d450910, 0x12232674, + 0x1113130c, 0x5508090a, 0x437d8181, 0x182e3c3c, 0x2f09fc4c, 0x38222d87, 0x03012238, 0x2d5b1001, 0x23404243, 0x012a9384, 0x47ff4600, 0xcb021902, + 0x2f478300, 0x0bb14105, 0x5307fb41, 0x554e08d9, 0x07222107, 0x09c94a18, 0x20288950, 0x0add6527, 0x21146942, 0x21821514, 0x16c90122, 0x09d14e18, + 0x180d0c32, 0x130f0e0c, 0x1a151612, 0x16161615, 0x13141414, 0x06280283, 0x10060605, 0x08080a08, 0x22051052, 0x50080201, 0x2a080bd5, 0x0b0c0b0a, + 0x12110b0a, 0x101e1513, 0x05030310, 0x03020103, 0x04040304, 0x25323340, 0x04131427, 0x0f0a0a05, 0x38271410, 0x83174737, 0x23518452, 0x076f0214, + 0x08084f18, 0x3635482c, 0x0e0d1124, 0x05050909, 0x4f180404, 0x05290910, 0x02010102, 0x0b0a0d01, 0x23205109, 0x00820420, 0x20083f82, 0x18170406, + 0x4243302c, 0x27272a56, 0x1d1c2222, 0x19183018, 0x05040303, 0x410a0707, 0x0b0b0e20, 0x2c008200, 0x00620002, 0x03270200, 0x000b0068, 0x0db54823, + 0x35100323, 0xe54e1820, 0x37013d13, 0x15232415, 0x1f121f3d, 0xe83a121f, 0xfe6f4d01, 0x51f555ff, 0x070151f5, 0x02acfe58, 0x180ab247, 0x200efe4e, + 0x486b8e00, 0x6b960c59, 0x200b3f48, 0x886aaaa8, 0x0066246b, 0x482d0015, 0x75961801, 0x2114a52c, 0x203f1420, 0x14212014, 0xe747182e, 0x8f542008, + 0x12c5477f, 0x0021f28f, 0x065f4103, 0x23050f46, 0x01000047, 0x4616f545, 0xa396180d, 0x30ff0023, 0x059d4518, 0x08183030, 0x03040403, 0x081730bc, + 0x04030304, 0x9a612f08, 0x98fe2105, 0xd245af8e, 0x26bf9023, 0x00640002, 0x42030200, 0x4218141f, 0x4f1809d1, 0x012d0c25, 0x2323152b, 0x121f3d16, + 0x3b131f1f, 0x324f18da, 0x0b1d420c, 0x103e4f18, 0x6b8e0020, 0x960c1f42, 0x0b1f426b, 0x6aa7a620, 0x1b426787, 0x2571961d, 0x2120149b, 0x034a4014, + 0x061b4205, 0x35101923, 0x427b8d48, 0xee8e1219, 0x57410320, 0x08174206, 0x96302548, 0x200b489f, 0xaa8ca320, 0x8e231442, 0x020030ba, 0x00000400, + 0xbd022702, 0x4f002100, 0x5a330000, 0xa1630bdb, 0x0b694e06, 0x0ba75318, 0x20198563, 0x084b5323, 0x102f432c, 0x3265102f, 0x293f3f55, 0x00821429, + 0x1a15293a, 0x25201f1a, 0x42722a25, 0x1b231020, 0x1114151c, 0x0a0d0c11, 0x0306060a, 0x34080082, 0x090a0606, 0x12110d0d, 0x1c1b1615, 0x630c2420, + 0xfa216321, 0xe0113553, 0x2b15154a, 0x5a43422b, 0x2b42415a, 0x0b111115, 0x4e05050a, 0x08070404, 0x100e0b0b, 0x2b518214, 0x2a282021, 0x19182221, + 0x100f1414, 0x25052d59, 0x113537a6, 0x008200bf, 0x4600022c, 0x23020000, 0x5b006603, 0x5d4b7b00, 0x854a1821, 0x34352209, 0x0d5d4b31, 0x460a7546, + 0x29640981, 0x14152409, 0x57351003, 0x50180957, 0x4d4b1275, 0x02022346, 0x4f4b0203, 0x55882c0a, 0x1616102b, 0x2f2e2c18, 0x1819481f, 0x230acb50, + 0x0a0c0003, 0x0805425d, 0x07060e23, 0x01020101, 0x04070404, 0x03070101, 0x01020203, 0x03030101, 0x08070607, 0x13170309, 0x070e0d13, 0x20118207, + 0x28238201, 0x03030302, 0x08020204, 0x82238401, 0x03270811, 0x09060603, 0xfc010a08, 0xaf0e02ff, 0x37323225, 0x466b6a66, 0xfd90b101, 0x6b46aff2, + 0x3138666a, 0x4efe2632, 0x18000090, 0x2707c769, 0x0b006803, 0x53003300, 0x200d7d46, 0x1b776513, 0x6b167757, 0x01211365, 0x078d4430, 0x3a122024, + 0x6918185d, 0xbf443da3, 0x181b200a, 0x26419069, 0xff3a0003, 0x892e02f3, 0x0bf144ff, 0xfc20ffc7, 0x200a814f, 0x8cfe4092, 0x2608ff41, 0x00150066, + 0x475d003d, 0x094117a5, 0x15d54747, 0x1341eb20, 0x11eb453f, 0x1a421f20, 0x0a1b4141, 0x83005b24, 0x8544a300, 0x4761415d, 0x2055ad44, 0x3ea141d3, + 0x214dd544, 0xdd4107fd, 0x43042040, 0xfb4706f7, 0x00572205, 0x31235077, 0x1d450320, 0x1f2d4846, 0x7b412020, 0x2046503f, 0x4102fd21, 0x012b404f, + 0x52004b00, 0x09021e02, 0x71004f00, 0x362309dd, 0x47373637, 0x0b83077f, 0x0ca77518, 0xd1711b82, 0x4e062007, 0x0b830a4f, 0x0ec75e18, 0x130b8638, + 0x20150b12, 0x0f102020, 0x20160c0f, 0x0f111f20, 0x120b0b0f, 0x0b870b12, 0x0f0f0c27, 0x20201f11, 0x88278315, 0x0f0f221f, 0x84328210, 0x830b2013, + 0x201f221f, 0x2d078416, 0x0b522020, 0x140b1011, 0x0f1e1e1e, 0x07820e0e, 0x23057c70, 0x0a11120a, 0x10201383, 0x0b231382, 0x82100e0e, 0x0a14231e, + 0x13821211, 0x13821f85, 0x13830f20, 0x11100b23, 0x240b820b, 0x1f1e1d10, 0x36078414, 0x00001e1f, 0x04000300, 0x5802dfff, 0x6700dd02, 0xc5009100, + 0x72170000, 0x15700ee1, 0x06f94f0c, 0x5c0cbd65, 0xcd650be7, 0x1615210c, 0x200dc949, 0x05e95f27, 0x4106e56a, 0x11820a61, 0x240c5963, 0x15060706, + 0x21018214, 0x05821716, 0x5a141721, 0x9b580fd9, 0x34272605, 0x26273435, 0x20018235, 0x20078227, 0x0b955827, 0x17164208, 0x0f0a3716, 0x1c110a10, + 0x0707111b, 0x01030407, 0x01010201, 0x08040401, 0x100c0c07, 0x17141310, 0x1f1b1b17, 0x0c0e0d10, 0x0b0c0b0d, 0x0e121215, 0x0d141312, 0x09101009, + 0x101a1a10, 0x04050505, 0x05a04f03, 0x02022108, 0x1e100f01, 0x17131310, 0x221c1d17, 0x0d0d0e0e, 0x0c0c0c0d, 0x0f131317, 0x65151412, 0x050354a8, + 0x82054567, 0x1516233f, 0x1d821110, 0x09070b26, 0x04040606, 0x01283882, 0x12114201, 0x11151513, 0x0b2a1682, 0x0707080b, 0x02050406, 0x00840103, + 0x01023508, 0x15152102, 0x0d0e0b1a, 0x19191311, 0x0c0c0820, 0x0a0b0621, 0x26251606, 0x18181016, 0x100f0f1f, 0x12111110, 0x29283014, 0x1d1c2222, + 0x10111717, 0x06060b0b, 0x32083582, 0x05040303, 0x130f0e09, 0x111b1b18, 0x070b0b06, 0x14242414, 0x0d0a0b0a, 0x0f0d0e0d, 0x120f100d, 0x14131312, + 0x2d44445b, 0x0c111116, 0x0105060b, 0x83040203, 0x130e2130, 0xec25f082, 0x090a71e1, 0x22878209, 0x820a0406, 0x090421e2, 0x2e083682, 0x17181111, + 0x26261d1d, 0x060b172e, 0x09080707, 0x06060505, 0x06050b91, 0x08090405, 0x0f100c0d, 0x1a1a1516, 0x0d2b2222, 0x0b0a0c0b, 0x83080909, 0x070627c5, + 0x1c2d0606, 0x6c82241b, 0x211a1728, 0x0e122b21, 0x0082000e, 0x4a00022c, 0x1f02f3ff, 0x0b006603, 0x8d496f00, 0x65222010, 0x27430e7f, 0x05fb5f07, + 0x6305bb4a, 0xf1410add, 0x18342012, 0x381e9d55, 0x2324152e, 0x121f3e16, 0x3a131e1f, 0x0d0e0b28, 0x18181a0f, 0x090a0a15, 0x20b7830b, 0x21f58207, + 0xf4820407, 0x0103033f, 0x194c0102, 0x02010101, 0x08030302, 0x100f0b0c, 0x16151312, 0x0f0f1312, 0x04080b0c, 0x241e8402, 0x0201011a, 0x261e8203, + 0x120c0c07, 0x760a0908, 0x0a24055b, 0x18ea020b, 0x22055058, 0x180cfd18, 0x215fb555, 0x4f410000, 0x41682007, 0xdd49054f, 0x604f410e, 0x1f12ee2c, + 0x1f3e131e, 0x16242415, 0x4e416839, 0x09ec5155, 0x4e410920, 0x099b425e, 0x79001522, 0x411a294a, 0x035a6055, 0x41bc2015, 0x5b4a555f, 0x410d2011, + 0x03205e67, 0x48060344, 0x9320059b, 0x41349948, 0xb5486083, 0x4158201f, 0x2a51548d, 0x41f02022, 0x00225e9d, 0xdb5c0200, 0x000b2208, 0x08074335, + 0x06070626, 0x34112207, 0x18087968, 0x441edd57, 0x57180b19, 0x374524e7, 0x1816200a, 0x5325f357, 0x47260563, 0x2100bd02, 0x4d183f00, 0x996208fd, + 0x24b98211, 0x14232223, 0xcb651815, 0x26272316, 0x1f832627, 0x4c647308, 0x402b541a, 0x1f1f3030, 0x04051010, 0x0b0c0708, 0x30301f10, 0x4c1f6040, + 0x28264e4c, 0x13141e1d, 0x02020a0a, 0x08070505, 0x0c0c090a, 0x12120e0f, 0x021d5715, 0x205faf0e, 0x18190c0c, 0x1a332627, 0x13121617, 0x180c100f, + 0x2b810d0d, 0x100708fa, 0x1f18170f, 0x0c0d0e0e, 0x080a090c, 0x03060607, 0xb9030204, 0x01000000, 0xf3ff5e00, 0xdb023e02, 0xb971a100, 0x09a96311, + 0x51136f6c, 0x6d5809e1, 0x078f4a17, 0x6a08e758, 0x477d0513, 0x0e43760f, 0x49088f71, 0x95490a99, 0x06022c07, 0x3026261c, 0x10111113, 0x83090805, + 0x120a2100, 0x61080082, 0x100f1010, 0x1115161a, 0x04060608, 0x04010204, 0x08060804, 0x0b0a0a08, 0x0c160c0b, 0x090a0a0b, 0x05080708, 0x03050406, + 0x03010103, 0x07060502, 0x1e140a07, 0x0701271e, 0x160f1007, 0x161e1c16, 0x070f0f16, 0x0d184507, 0x281b1a0d, 0x28343527, 0x0d1a1a27, 0x1e26010d, + 0x0b14161e, 0x0704040b, 0x00820504, 0x07384482, 0x140e0403, 0x0c0c1110, 0x0e070a0a, 0x04030607, 0x0a0b0606, 0x0a0a151c, 0x24093963, 0x071a3303, + 0x30198205, 0x05060202, 0x0807060c, 0x0a090708, 0x0c0d0f0a, 0x2409820c, 0x06070707, 0x84148207, 0x210f8216, 0xc3820808, 0x0e0a0a32, 0x0d0d0e0d, + 0x140a0b0b, 0x19080f0e, 0x0d0d1314, 0x25082582, 0x18100f08, 0x71fe2217, 0xb3640185, 0x19252531, 0x0c0c0b19, 0x271a1a0d, 0x09033326, 0x130e0f09, + 0x0a0c1713, 0xd382090b, 0x9b820520, 0x02050424, 0x40820902, 0x6a820a20, 0x17140a2c, 0x10111a18, 0x0d0f0e10, 0x0082000e, 0x4400032e, 0x3002f3ff, + 0x13001203, 0xb5009500, 0x6106e548, 0x162409ab, 0x22171617, 0x180b0f4f, 0x200d7549, 0xff421833, 0x5779180a, 0x157b5f0f, 0x2305bd41, 0x16151415, + 0x410d6363, 0x657308d5, 0x7e352008, 0x3f760a43, 0x0141081f, 0x1e1d142f, 0x0e0e0f1d, 0x0921420b, 0x190e0c0c, 0x3a111a1a, 0x1b1c172a, 0x22222c1f, + 0x09080d19, 0x03040707, 0x1f1f1010, 0x5d3c2f2e, 0x1109081e, 0x251b1a10, 0x18171818, 0x16171819, 0x0d0c0c0a, 0x2802820d, 0x18171716, 0x1a1d1c23, + 0x8200830b, 0x04052332, 0x00820305, 0xfa4a0120, 0x01022105, 0x7e6b0183, 0x02022905, 0x3d010101, 0x0403031f, 0x0805c96b, 0x06010140, 0x0c0b090a, + 0x0b960c0b, 0x260e0d0c, 0x17151e1e, 0x264e0b0a, 0x141f1e28, 0x070a0a15, 0x09070f08, 0x16610209, 0x10202120, 0x0b0b0f10, 0x20110f0f, 0xfd162120, + 0x05060ba8, 0x0a170b0b, 0x11820d0d, 0x2b151234, 0x17172122, 0x04090c0b, 0x0e171620, 0x0408070e, 0x37820603, 0x1d3a0c23, 0x20688204, 0x2b6a8204, + 0x05020205, 0x06040a05, 0x09070706, 0x073d9f82, 0x07080807, 0x1b100708, 0x2348231a, 0x0a0d0c0e, 0x0a09090a, 0x080a0a09, 0x05060609, 0x20008207, + 0x24338206, 0x0d0b0a07, 0x2b008205, 0x04050406, 0x090b0a0c, 0x33070709, 0x0d27d082, 0x2219190d, 0x820e2b23, 0x0d0d2c4c, 0x181b1414, 0x060d1213, + 0x42000505, 0x1320100f, 0x12f34818, 0x22a10f42, 0x6f1a11ef, 0x412b058a, 0x0e0d0b21, 0x1e1e1c10, 0x426b3a14, 0x212d8f0e, 0x0f112020, 0x0f0b0b0f, + 0x21201010, 0x940e4220, 0x240a0f42, 0x00970015, 0x1a694ab7, 0x0f4d0620, 0x09796f0b, 0x36872144, 0x27261796, 0x17183117, 0x2e172627, 0x1d1c1117, + 0x1c1c1111, 0x42c63411, 0x212b8e13, 0x21213738, 0x16213837, 0x83162424, 0x93224403, 0x2a071342, 0x4f00fa02, 0xf100d100, 0x65130000, 0x4551086f, + 0x069f470c, 0x21086b65, 0x48183332, 0x114808ef, 0x220b850b, 0x18272623, 0x4408df58, 0xcf2aa15f, 0x06071529, 0x11120d0d, 0x00820917, 0x03830720, + 0x0f030427, 0x03050505, 0x34008204, 0x04070709, 0x29030205, 0x0d060615, 0x1612110e, 0x080a0909, 0x2e238308, 0x040e0403, 0x02030302, 0x04020102, + 0x82040304, 0x05052427, 0x429d0202, 0x76348d84, 0x1218181f, 0x02090812, 0x06040301, 0x03060805, 0x04050d03, 0x0137b482, 0x09040501, 0x130d0e09, + 0x11181820, 0x01080912, 0x05040302, 0x82070706, 0x0203231f, 0xd3820103, 0x04010329, 0x0e080904, 0x4680fd0e, 0x002391d8, 0x48040000, 0x022905eb, + 0x001700d9, 0x00b1002f, 0x34cd4dd1, 0x209ee744, 0x06fe60f8, 0x0e610820, 0x2fbc2806, 0x04030818, 0x86080304, 0x42562007, 0x7b208d6c, 0x1f174318, + 0x428efd21, 0x03299b4b, 0x001f004d, 0x00c1003f, 0x15a76ee1, 0x4a0b4379, 0xf5440dc3, 0x4b222006, 0x15230535, 0x44161714, 0x0136a1f5, 0x19191498, + 0x18181c1d, 0x0b0a1414, 0x14140a0b, 0x1d1c1818, 0x0d821919, 0x0a090923, 0x06fa67ac, 0x8d670b20, 0x0e0b2d05, 0x0d10100e, 0x050b0b0d, 0x78050606, + 0x228d7442, 0x820a1371, 0x121329b0, 0x1b1b1717, 0x12121817, 0x12220d83, 0x0d831812, 0x85171721, 0x0c0a26be, 0x0e0e100c, 0x9289180d, 0x0c0c230b, + 0x8b4265fd, 0x00032e94, 0x02f3ff14, 0x001b0258, 0x00af0091, 0x11a74fcf, 0x490de167, 0x06231291, 0x7b070607, 0x5b1814fb, 0x142610d5, 0x30151415, + 0xbb4d0615, 0x10976811, 0x82092745, 0x3213215d, 0x62187589, 0x15220fdb, 0xb16a0714, 0x0509590a, 0x0d214418, 0x1106012c, 0x26191514, 0x0a141e1e, + 0x944d0808, 0x06063605, 0x190d0a0a, 0x2c302424, 0x0c06060e, 0x1812120c, 0x100f0f0f, 0x22008608, 0x82090a09, 0x08480800, 0x0f101009, 0x13131710, + 0x0c0c100f, 0x20201109, 0x1f1f2c2f, 0x09091211, 0x02013eb8, 0x04040302, 0x08070605, 0x0c0a0a09, 0x12120e0d, 0x0d111012, 0x0e100d0e, 0x110f100f, + 0x171b1411, 0x0d131217, 0x0d0a080e, 0x297b4c0d, 0x02212d82, 0x212e8304, 0x2f820805, 0x150c2908, 0x09091010, 0x0be50506, 0x18140f10, 0x05091110, + 0x03020303, 0x08100101, 0x0f1d1d2a, 0x0608070f, 0x05090505, 0x140a0a04, 0x39054078, 0x12141210, 0x0e0f0f12, 0x0b150a0e, 0x1d0d1c0a, 0x100f1515, + 0x03030807, 0x03830304, 0x35225682, 0x0c84041a, 0x04010323, 0x25678202, 0x0b0b0707, 0x30831e10, 0x321b1c29, 0x0a204832, 0x82050206, 0x0902255e, + 0x12121705, 0x0b274582, 0x07060908, 0x82020403, 0x0606333d, 0x350c0809, 0x07080a1b, 0x02020505, 0x0a0a0504, 0x23830d0e, 0x1026012f, 0x0f101208, + 0x0a0a0d0d, 0x06060707, 0x2b578205, 0x10100808, 0x0f251a1b, 0x06060ce8, 0x08200b82, 0x0e302a82, 0x19181313, 0x0b050609, 0x1a12120b, 0x00111015, + 0x012a0082, 0x47ff5200, 0x1b020302, 0x836a8f00, 0x071b4e22, 0x51151421, 0x072206a3, 0x8f6a0706, 0x13ba335b, 0x2b171415, 0x17172222, 0x02030c0b, + 0x09090605, 0xcb59180c, 0x0a0b2e05, 0x0c08090a, 0x09080a09, 0x08080708, 0x05e2580a, 0x00820520, 0x0a070f25, 0x48050808, 0x012005a0, 0x0805894f, + 0x0e0b0b33, 0x0b0b0f0d, 0x0a0c0a0c, 0x13110b0b, 0x101f1413, 0x06030310, 0x03020202, 0x04030403, 0x212e2d3a, 0x05121225, 0x0e0a0a04, 0x3225120d, + 0x14173f32, 0x3e268215, 0x12131513, 0x07c50112, 0x0d0e0303, 0x25251b1a, 0x16151631, 0x11111313, 0x0e0d1b0d, 0x82010102, 0x04032e3c, 0x06050504, + 0x3c070606, 0x0504051e, 0x204b8204, 0x24188302, 0x0b0b0b01, 0x2ba76a0a, 0x12120332, 0x34332521, 0x1e1d2240, 0x15151919, 0x13122412, 0x0420ed82, + 0x3d25d782, 0x0b0b101e, 0x2c008200, 0xff3e0003, 0x032c02f3, 0x00130012, 0x072f6c63, 0xb7512720, 0x088b7c10, 0x15752620, 0x0999460f, 0x18201521, + 0x5a094965, 0xd94110a5, 0x0306260b, 0x33363332, 0x5a018632, 0xbf530aef, 0x35012107, 0x3c0c8551, 0x1a1a190d, 0x0c3a3a11, 0x410b0c0c, 0x25253333, + 0x05051212, 0x0d0d0909, 0x16151311, 0x351b8218, 0x2b2b361d, 0x0f0f1e1f, 0x0c63d5fe, 0x0f0b180c, 0x1410100e, 0x00831713, 0x0c0d0c23, 0x2800820d, + 0x0d0d0e0e, 0x0c0b0e0e, 0x3f42820a, 0x191828ec, 0x0f100e1e, 0x1d1d1615, 0x03020126, 0x07060605, 0x1b1a1208, 0x1c1b2221, 0x0d0c1615, 0x4f0b5e51, + 0x9429064f, 0x24131202, 0x40333225, 0x06474121, 0x0e0e1326, 0x05050909, 0x0aa26518, 0x21222b2d, 0x08090b18, 0x03040606, 0x41070304, 0x072a06bf, + 0x04061c3a, 0x03040405, 0x00820203, 0x013f0135, 0x0f111214, 0x090b0c0e, 0x0b0a0a14, 0x1c15150a, 0x4100001d, 0x2751107f, 0x6d7f4115, 0x1a11f534, + 0x0c0e1919, 0x2142090c, 0x100e0e0a, 0x131e1e1d, 0x7e417a3a, 0x0a7f41d4, 0x65001524, 0x97508500, 0x6d814119, 0x26179c24, 0x65501826, 0x1c1d2108, + 0x20056550, 0x678341d5, 0x43103e50, 0x00215b02, 0x05834404, 0x22064f4d, 0x4d9f007f, 0x9f41334f, 0x18fe206d, 0x210ea74f, 0x4f1830bb, 0x246e07a7, + 0x41462005, 0xf64c66a9, 0x447a2021, 0x022a59bc, 0xfcff6d00, 0x06032202, 0x9f181300, 0x255b0ca7, 0x6f222009, 0x41180595, 0x352209eb, 0x9d182322, + 0x332d0cc3, 0x01143332, 0x1e1d140f, 0x0e0e101d, 0x0573570a, 0x1a185308, 0x0039111a, 0x14274eff, 0x10111112, 0x170c0e0d, 0x1f5b0c0b, 0x060635a1, + 0x10110b0c, 0x021b5116, 0x21211555, 0x100f111f, 0x0f100b0b, 0x21211f11, 0x03a7fd15, 0x0a060603, 0x23190d09, 0x44cc2d24, 0x71e21132, 0x0f16151e, + 0x3807080e, 0x02000000, 0xa78c8600, 0xa4128956, 0x560020a7, 0x4225070c, 0x0e0e0b21, 0x23b4820f, 0x0f013b14, 0x1621a79b, 0x31a7b520, 0x0031000d, + 0x37361300, 0x17163332, 0x27262322, 0x49410706, 0x5c862f24, 0x5c13371f, 0x4411351f, 0x34164416, 0x9a9a8a01, 0x2c84562a, 0x1d562c84, 0xa6fd1d56, + 0x211b3a41, 0x3b410300, 0x069b4305, 0x99435320, 0x057f6f31, 0x201d0142, 0x106777ec, 0x20054543, 0x067a7107, 0xc89a6b20, 0x20210143, 0x34e09b81, + 0xff450002, 0x022402f3, 0x002700db, 0x37000084, 0x33161716, 0x10a01832, 0x012e2109, 0x2f08654c, 0x23222326, 0x0e070622, 0x17141501, 0x010e1716, + 0x0f448d18, 0x82323321, 0x33162701, 0x32013b30, 0x35822617, 0x27203a89, 0x09869918, 0x76181482, 0x162009ef, 0x07224784, 0x0782011e, 0x1e171622, + 0xc44f5882, 0x12cb3105, 0x23221b1a, 0x09121334, 0x0803040a, 0x040d1407, 0x08067759, 0x0a090a2e, 0x133a250a, 0x09091413, 0x1c3217e1, 0x202c2c39, + 0x0f0f101f, 0x2e1f1f0f, 0x030a3d2f, 0x02050202, 0x04020102, 0x05040401, 0x04050a06, 0x0805b35b, 0x2722053e, 0x04031a28, 0x284f0305, 0x49103a11, + 0x13140c24, 0x2d2e1a0d, 0x0505031b, 0x184e1703, 0x0b174832, 0x05060809, 0x200f1006, 0x6e131310, 0x1a0d0d19, 0x23231919, 0x19191b2d, 0x10281818, + 0x3a06ae5a, 0x18191802, 0x242d2f48, 0x08088423, 0x24221211, 0x3f3e3130, 0x23223130, 0x82011112, 0x06052371, 0xa3820e07, 0x83060521, 0x0b200804, + 0x08080c0c, 0x19080f0f, 0x123a120c, 0x0d14150d, 0x090d0e08, 0x080f0e09, 0x32071807, 0x17162d5e, 0x30290082, 0x2f2f3e19, 0x0d0e1124, 0x2c008200, + 0x00610002, 0x020d0200, 0x004f00e1, 0x1e055681, 0x09774a18, 0x181c0556, 0x700bab4b, 0x5d18080b, 0x6a180a67, 0x7b4a115d, 0x14153507, 0x2ace2215, + 0x0d070715, 0x1711110d, 0x080a0909, 0x09080908, 0x2805677b, 0x04040306, 0x07090403, 0x07955508, 0x550d0e21, 0x03230f95, 0x82020302, 0x04340800, + 0x0a040303, 0x05050707, 0x386e0201, 0x0303021b, 0x2a291a01, 0x13121739, 0x0d0d1010, 0x0a0b150a, 0x06071745, 0x15150e0d, 0x1918211c, 0x09091111, + 0x205c0245, 0x122d0982, 0x02020809, 0x05050403, 0x04030707, 0x05104e0d, 0x08050428, 0x120e0e09, 0x4d55191f, 0x2b1e8405, 0x03030608, 0x0202040d, + 0x01020102, 0x053c0283, 0x0e080904, 0x0191fd0e, 0x190e838b, 0x162f0f19, 0x07030417, 0x0d0a0907, 0x3528281a, 0x0f0c6a18, 0xe0291e24, 0x0082004a, + 0xfb420320, 0x12032705, 0x37001300, 0xb35d5700, 0x1617212f, 0x21054541, 0x6a180607, 0x2e2d2029, 0x1c1e1e14, 0x0b0e0e10, 0x0c092242, 0x05cf4b0c, + 0x2c1ea532, 0x2d3a3b2d, 0x0b101f2c, 0x0408080b, 0x1f0f0f03, 0x0d416a18, 0x1b11c538, 0x1a24231b, 0x0911121b, 0x11090a0a, 0x241a1b12, 0x111b1b23, + 0x00820912, 0x3412a54b, 0x111223d8, 0x13231211, 0x1b1a1516, 0x43211d1d, 0x23243333, 0x38008212, 0x33332423, 0x33344443, 0x0d0e1a14, 0x191a0e0d, + 0x32322626, 0x191a2626, 0x2100820d, 0x0d851a19, 0x41000021, 0x874b100b, 0x55072015, 0x0b4116b5, 0x18ee2029, 0x4607dc4b, 0x1e230744, 0x41e53914, + 0x0b418c0a, 0x0015240a, 0x4b590039, 0xa3181713, 0x114e17a5, 0x21194209, 0x26189425, 0x5b321726, 0x1822054d, 0xe74a1c11, 0x40012106, 0x4a3d1041, + 0x1b4210be, 0xe1022644, 0x73004f00, 0x05bb6500, 0x620f5b62, 0xa1440943, 0x43494132, 0x214cb344, 0x80411701, 0x43ca443c, 0xce43ca20, 0x0400213c, + 0x4805db44, 0x732008b7, 0x7032b948, 0xad620a0b, 0x29ed430d, 0x201f5167, 0x3c674125, 0x2021fb48, 0x3b4541be, 0x2c00032e, 0x3c024700, 0x17001602, + 0x37001f00, 0x2119637b, 0xd17c3405, 0x7b172005, 0x01231683, 0x5a1f3d62, 0x3e23053c, 0x8204081e, 0xc2fe2700, 0xfe848c01, 0x168eb274, 0x04a20127, + 0x1d3a0703, 0x20218207, 0x28078304, 0x3c9c0403, 0xbf143c14, 0x210d8503, 0x1d850303, 0x00000332, 0x18000300, 0x4b02d3ff, 0x57003902, 0xaf007f00, + 0x5e1d9b6f, 0x976f104d, 0x5e152012, 0x60180853, 0x06220a19, 0x59790607, 0x20078407, 0x0d6d5926, 0x17657a18, 0x82343521, 0x6f038727, 0x3b420e7d, + 0x16172d05, 0x0f0e0946, 0x1a1a1008, 0x05050611, 0x0332d882, 0x02020602, 0x1f1f0f0f, 0x0c3a2c2c, 0x0c0b0c0d, 0x7c560b0a, 0x08083106, 0x0e151512, + 0x090e0f08, 0x0f1a1910, 0x0608070b, 0x102b2f82, 0x2d1e1f0f, 0x0c0e3b2d, 0x820b0b0c, 0x11143f29, 0x17140d11, 0x131e5d16, 0x0c0a1812, 0x1611100c, + 0x0a091d16, 0x0f0d0d0a, 0x1b22100f, 0x205e121b, 0x64032005, 0x66250574, 0x08080807, 0x22158224, 0x830a0911, 0x8b158411, 0x82052039, 0x05062292, + 0x2a008206, 0x0b072d07, 0x1e11070b, 0x830a121d, 0x236a828d, 0x1b191916, 0x6e065a47, 0x032b0629, 0x05050404, 0x15070605, 0x820f1717, 0x8206202d, + 0x112b082d, 0x16131210, 0x1d191a17, 0x23333444, 0x01111223, 0x03030102, 0x0a0b0703, 0x1918160e, 0x151522bd, 0x0e0d0c1b, 0x19191312, 0x84080b21, + 0x0d0c22ce, 0x25aa8219, 0x14151112, 0x00820d19, 0x0f0f0e23, 0x265d8272, 0x191a0e0d, 0x82312625, 0x820d2010, 0x8207208d, 0x23092e00, 0x0c1a1615, + 0x13110e0e, 0x06211a19, 0x055b5305, 0x02020331, 0x00020000, 0x02f3ff61, 0x0005030d, 0x48490013, 0x352021c9, 0x540c854e, 0x19840bad, 0x5c181020, + 0x01200971, 0x3a13bb48, 0x1819162e, 0x20202b1d, 0x0b0b1415, 0x06071745, 0x0809060e, 0x0d0c0a0a, 0x4919200f, 0x172b05cd, 0x03011c37, 0x110c0203, + 0x4e540211, 0xb63310ac, 0x0d06060b, 0x281a1b0d, 0x51f43628, 0x1b246cd9, 0x7107101a, 0x0b330502, 0x1f16150b, 0x4adf281f, 0x0f8376fe, 0x170f1918, + 0x90001111, 0x1f9948db, 0xee20dba9, 0x21078c49, 0xa0492142, 0x6e392107, 0x5418daab, 0xfd200f9d, 0xb741daaf, 0x1811200a, 0x21125148, 0x33680706, + 0x48d9a90c, 0x34270a57, 0x43174312, 0xabc93417, 0x074048d7, 0x561d5623, 0x20d3b11d, 0x058b4203, 0x20067b46, 0x31794665, 0x220d8576, 0x18333235, + 0x180c9d87, 0x420c7348, 0x6b460aa9, 0x4152201f, 0x59462a01, 0x428f2021, 0x022e2dc4, 0x37ff3400, 0x05034102, 0x71001300, 0xc3420000, 0x34032113, + 0x09555818, 0x18087545, 0x1823a966, 0x4f10754d, 0x058b0546, 0x42222321, 0xa52b13eb, 0x090c1224, 0x0608070a, 0x83050507, 0x08092c44, 0x2627230a, + 0x12111324, 0x1821410e, 0x2107c066, 0x106a1f14, 0x21413a05, 0x1a1b1c12, 0x0a0c0d0e, 0x0608080b, 0x03040405, 0x02020302, 0x080a0a0d, 0x243f8209, + 0x07070708, 0x08038206, 0x090a0924, 0x0a0b0b0b, 0x5502370a, 0x110f0f0c, 0x1521201f, 0x1f202115, 0x0c0f0f11, 0x1237e2fc, 0x03030102, 0xbe580405, + 0x14270805, 0x5d551913, 0x292e545e, 0x4b322229, 0x2427494c, 0x4c321b23, 0x2328494b, 0x422b1b23, 0x1f223f42, 0x141a171f, 0x820d0d14, 0x255a82a1, + 0x191a2106, 0x0d821010, 0x09090d23, 0x367e8306, 0x03030305, 0x00020102, 0x00020000, 0x0237ff5f, 0x00e0022a, 0x18410029, 0x4e081158, 0xdb460aed, + 0x0a2f6509, 0x22151423, 0x19771813, 0x17452917, 0x33262618, 0x1e272733, 0x08157718, 0x0c0f3322, 0x0a2ef982, 0x1013090a, 0x68450b0f, 0x221a1911, + 0x00822242, 0x1a224226, 0x09111119, 0xc9250082, 0xb9eabf02, 0x1b77185c, 0x41210808, 0x24343340, 0x01121224, 0x04030301, 0x0f0b0404, 0x43c9140e, + 0x0e1a3901, 0x6533340d, 0x0d333266, 0x097d4d0d, 0x03000022, 0x25051f42, 0x1700cc02, 0x634b2f00, 0x27222206, 0x3d7c1826, 0xcf431811, 0x5a3d4218, + 0x21054942, 0x61432223, 0x9bfe211f, 0x28355042, 0x03060507, 0x02020304, 0x82028201, 0x02022803, 0x0a040304, 0x82060809, 0x08043600, 0x07060504, + 0x08080706, 0x1415110a, 0x6d023717, 0x2c070403, 0x05224916, 0x03200783, 0xfc210f8f, 0x306642ca, 0x0d0c1225, 0x82060908, 0x3d858253, 0x07040403, + 0x0c090905, 0x0e15141a, 0x070c0b0f, 0x08090811, 0x06070708, 0x05090506, 0x4a180005, 0x4e2f086f, 0x27000700, 0x00003900, 0x32353413, 0x18151433, + 0x2432f54d, 0xe14be09f, 0x404b18d7, 0x34082631, 0xfc123412, 0x244b18f8, 0x068b6c2a, 0x82bf0221, 0x008922b3, 0x63b389a9, 0xa024a129, 0x83e14be0, + 0x268df462, 0x3411347a, 0x628ffd11, 0x4d1892c1, 0x5c26070b, 0x33001300, 0x49654500, 0x3332210a, 0x2106e944, 0x4e183237, 0x01363105, 0x272805d1, + 0x27284849, 0x06142705, 0x292b1819, 0x2c081818, 0xb94250fe, 0x395c2831, 0x1c1d1d1c, 0x820d1a39, 0xfc1a2200, 0x2ac142a4, 0x2b6b0020, 0x00e82608, + 0x00990017, 0x4adb8fb9, 0x322008c1, 0x4e0b3b48, 0xaf630db5, 0x15ab6312, 0x8409cb50, 0x50637109, 0x2805d338, 0x27484928, 0x14280528, 0x0c060703, + 0x1711110b, 0x0718192a, 0xe842572d, 0x43e8228d, 0x2c008222, 0x0d0e1043, 0x04050909, 0xfd231211, 0x91f44221, 0x12000232, 0x680247ff, 0x4b00bd02, + 0x00005d00, 0x16171405, 0x220d4165, 0x4f070623, 0x53490695, 0x33322406, 0x18262726, 0x18075f9e, 0x18097f60, 0x490a4155, 0x0120064f, 0x3d732985, + 0xfb01250a, 0x081b0e0e, 0x06261e82, 0x0a070707, 0x06830909, 0x1d3a082d, 0x0703031d, 0x100a0a06, 0x180a0101, 0x2108879e, 0x1f432346, 0x101f2a11, + 0x0509080c, 0xfe020305, 0xa49e18cf, 0x15563c10, 0x02010b0a, 0x02020201, 0x03152904, 0x01010202, 0x0b291414, 0x0c0d0b0c, 0x18100f0e, 0x4307a14f, + 0x0f230f31, 0x820a0c0d, 0x51012286, 0xc89e182c, 0x00022c10, 0x0248ff44, 0x001b0259, 0x41cb00ab, 0x14240a17, 0x06070615, 0x43071341, 0x43760b1f, + 0x0b2d7407, 0x01520720, 0x544b4318, 0x20067741, 0xd76a1803, 0x08df4312, 0x37362108, 0x0ee40136, 0x100f1c0d, 0x090b0f10, 0x09070809, 0x161b0a09, + 0x080e0f15, 0x05030307, 0x0f0b0b05, 0x20114c74, 0x5d57430a, 0x820b1621, 0x05042488, 0x742e0302, 0x0a200ea9, 0x3f0ac474, 0x0a0a1555, 0x29070303, + 0x03020215, 0x05050101, 0x0f100a0a, 0x0c0c0b15, 0x0e0e0b0c, 0x0a0a0710, 0x74053e5a, 0x0620095b, 0x42626a43, 0x0822053e, 0xbd744301, 0x7403200f, + 0x003008d8, 0xff460002, 0x031902f3, 0x000b0066, 0x01000057, 0x0ab55718, 0x13dd4518, 0x210cab76, 0x2f521514, 0xc18d180e, 0x0da5430b, 0x7e1b0121, + 0x9c280a54, 0x17161614, 0x28383748, 0x18d95018, 0x0b21a018, 0x154f5118, 0x260a597a, 0x02020512, 0x18301817, 0x181ab050, 0x180a30a0, 0x2d162751, + 0x52000200, 0x0302f3ff, 0x13001203, 0x07416f00, 0x090b4106, 0x06070625, 0x18132207, 0x4d0c81b9, 0x6d1808c1, 0x781808c7, 0x5218090b, 0x0b681c8f, + 0x01062a13, 0x1a1a110b, 0x0c0c0d19, 0x0936590a, 0x0a723a2b, 0x3f0d0a0b, 0x25253232, 0x16656713, 0xe7671220, 0x0a08222d, 0x12585a0a, 0x2105fb62, + 0x46673333, 0x67072017, 0x02202ec9, 0x4205b34d, 0x15220757, 0x61594500, 0x22132117, 0x1805af4d, 0x180c7f64, 0x20085d74, 0x07eb4515, 0x35691420, + 0x14b92607, 0x3f142121, 0x2c05821f, 0x0f172e13, 0x0f0f1a1b, 0x350f1a1a, 0x064a42a8, 0x28141439, 0x47373827, 0x27292a2c, 0x2d292a26, 0x31313162, + 0x292d6330, 0x8314262a, 0x15162200, 0x11157f02, 0x18170a26, 0x43433030, 0x074ca018, 0x130a0a37, 0x0e1d2041, 0x9047480f, 0x0f48488f, 0x20411d0f, + 0x0507070a, 0x42d18205, 0x1520091f, 0x9419315a, 0xdd7818cf, 0x0f19420c, 0x20082543, 0xb9661836, 0x75a62007, 0x1821057f, 0x057f7526, 0x11111c31, + 0x35101d1c, 0x323340ad, 0x12122524, 0x69251312, 0x14270568, 0x13131312, 0x82131215, 0x15142101, 0x2e07ea69, 0x18180b0c, 0x182b2221, 0x0a121515, + 0x8308090a, 0x28232401, 0x5a610228, 0x922b102f, 0x25241212, 0x41403433, 0x82253332, 0x08346955, 0x0c0b0f22, 0x3a06ed41, 0x3125261a, 0x1a252631, + 0x040e0e1a, 0x04040704, 0x06060504, 0x1e3c0806, 0x440a0a14, 0x17210a33, 0x99521800, 0x133f441a, 0x17323323, 0x0d274316, 0x2209e541, 0x61317e01, + 0x31230616, 0x82030818, 0x26933700, 0x482c2a29, 0x27283838, 0x14141314, 0x38382728, 0x29292c48, 0x0c821326, 0x46821520, 0x31306238, 0x2e623031, + 0x03262a29, 0x06040406, 0x0407162e, 0x07040303, 0x0d82172d, 0x1413fd3b, 0x18170909, 0x43423030, 0x43445656, 0x18183130, 0x41130a0a, 0x0b0b0d20, + 0x41cd8208, 0x492108e0, 0x41008200, 0x022506db, 0x001700d9, 0x19055853, 0xe141cf98, 0x01142521, 0x0818306e, 0x08209e83, 0x25065865, 0x2727268e, + 0xdb434129, 0x05d44105, 0x14144123, 0x21da8314, 0x01831213, 0x1715153d, 0x1721222b, 0x0c0c0b17, 0x2217170b, 0x272f2b21, 0x7a021f28, 0x2e070303, + 0x82030717, 0x24078500, 0x0a14a1fd, 0x1dcc410a, 0x180d0d21, 0x27075e88, 0x0e0e1a1a, 0x441d0e0f, 0x9f43f385, 0x56612009, 0xb961064f, 0x33322109, + 0x5e06f144, 0xa343090f, 0x38014607, 0x2114322a, 0x172e1420, 0x0f1a1a10, 0x2f270383, 0x21211417, 0x46804614, 0xe932430b, 0x17272718, 0x101a1b0f, + 0x0f1b1a10, 0x18272717, 0x134613fd, 0x0015224d, 0x19234171, 0x59159967, 0x25470893, 0x15154625, 0x26172d26, 0x172f1727, 0x2707385e, 0x2717182e, + 0x51381726, 0x30541746, 0x21373821, 0x15252415, 0x15242515, 0x21383721, 0x541746fd, 0x45000331, 0x29020000, 0x15006603, 0x49002b00, 0x6d130000, + 0x6f47098b, 0x03222309, 0x41183510, 0x541810f3, 0x7a180f0f, 0x23240b35, 0xde102322, 0x20146042, 0x115418b1, 0x3f29310b, 0x4072553f, 0x222a1020, + 0x111a1922, 0x050b0b12, 0x0b2a0082, 0x1a11120b, 0x2a222219, 0x22460c24, 0x0c494205, 0x18021721, 0x0807e9a7, 0x425a5a21, 0x152b2b42, 0x06064e16, + 0x15150d0d, 0x28291e1e, 0x29293433, 0x15151e1e, 0x07060d0c, 0x820066fe, 0x00032e00, 0x02f3ff2e, 0x00dc0290, 0x002f000b, 0x0d51493f, 0x460bbb4e, + 0x34200cf3, 0xe956ed82, 0x46252006, 0xdd8306f5, 0x0722233e, 0x060a0206, 0x42060b0c, 0x12120a21, 0x177f3a0b, 0x32342626, 0x1d1e2728, 0x0f0f0f0e, + 0x09cc8b18, 0x1c37172c, 0xfe030302, 0x442122f0, 0x00822244, 0x21444425, 0x452b0222, 0xfe2a07f6, 0x14142818, 0x25241312, 0xf1453333, 0x14142e07, + 0xfd44cc28, 0x150cb7dc, 0x3365d115, 0x05b15434, 0x00323322, 0x0aa35518, 0x43001d23, 0xa3551800, 0x1e8f411c, 0x19975518, 0x3f3f2925, 0x41427255, + 0x55181985, 0x7841148b, 0x7f551819, 0xff3d260a, 0x026802f3, 0x20b982db, 0x19dd736b, 0x18089943, 0x870b7f56, 0x0a6f58ad, 0x18060721, 0x420d039a, + 0x8f760d6f, 0x16173309, 0x70011617, 0x19161514, 0x1418171b, 0x0e101014, 0x00820f1d, 0x281d1d36, 0x16193229, 0x0f131416, 0x27720b0f, 0x17452673, + 0x18471748, 0x2c05385b, 0x07070705, 0x8e090a06, 0x100e0e0d, 0x05535b22, 0x1109092a, 0x0d0a0b07, 0x120f0f0c, 0x10391182, 0x08080911, 0x0b081109, + 0x050a070a, 0x0a050405, 0x110e0d0a, 0x40343325, 0x05b24740, 0x11820520, 0x13100f3e, 0x0f2b246d, 0x11341134, 0x3bfe0e2c, 0x15150c97, 0x09080a0d, + 0x06060807, 0x0304063b, 0x260a0c64, 0x070a090c, 0x56030307, 0x1a230992, 0x180a0a0d, 0x2408eb5a, 0x0007004e, 0x0935541f, 0x17bf5b18, 0x4be0a824, + 0x5a1891e0, 0xad540f1b, 0xff591806, 0x06f76f10, 0x82bf0221, 0x003f225b, 0x1593545b, 0x18135346, 0x2512b196, 0x07061514, 0x53710106, 0x074d4912, + 0x9982b020, 0x1718b725, 0x71411818, 0x0830053e, 0x17101008, 0x221e1d17, 0x2b372822, 0x101e1f2b, 0x2c063a71, 0x2b222118, 0x3631302c, 0xfe19191b, + 0x0c2771d8, 0x12090a2e, 0x211a1a12, 0x151c1c22, 0x020d0c16, 0x22050354, 0x6c030583, 0x3708055c, 0x252a4032, 0x181f2025, 0x08111118, 0x22111109, + 0x3b2f2e22, 0x01020a20, 0x1821222b, 0x0e0c0c17, 0x1c3a1b0d, 0x0107080a, 0x1d250133, 0x0a15151c, 0x140a0b0a, 0x001d1d14, 0x0a275d18, 0x13006a24, + 0xd5522b00, 0x3233260f, 0x32373637, 0xa95b1801, 0xe5013616, 0x49272805, 0x05282749, 0x18071428, 0x19282b18, 0xfe2d0818, 0x0f81418b, 0x1d386a27, + 0x381d1c1c, 0x0575531a, 0x89419620, 0x0787410e, 0x1f00e826, 0x8b006b00, 0xc772818f, 0x3332250c, 0x03060706, 0x1816e54c, 0x730d4968, 0x0773250b, + 0x14b23a20, 0x49241c1c, 0x27052727, 0x07080314, 0x10110b0c, 0x11111517, 0x08080c0b, 0x22118204, 0x6e440b0b, 0x1b233a66, 0x73191918, 0x8439230f, + 0x22090811, 0x0d114321, 0x0508090d, 0x08050404, 0x110d0d09, 0xfd191921, 0x39596e60, 0x08080a23, 0x18127305, 0x24087743, 0x00170066, 0x196f4a2f, + 0x24181742, 0x08183061, 0x20008204, 0x25078208, 0x03040403, 0x1342f9fe, 0x100f4b0f, 0x42fafc21, 0xd9201617, 0x4f228382, 0x85996b00, 0x4213f54a, + 0x3320190b, 0x08817318, 0x211baf43, 0x7c7d5f01, 0x20c98409, 0x4cbc434b, 0x4310244b, 0x012f42c8, 0x47ff6200, 0xbd022702, 0x00004300, 0x18232221, + 0x890a6b49, 0x147753f3, 0x43232221, 0x022f14df, 0x0c193227, 0x05060808, 0x0e0e0302, 0x520f101b, 0x082305ee, 0x52090909, 0x082905ee, 0x06060303, + 0xef100a0b, 0x0cdc4150, 0x2505d351, 0x0a150809, 0x6e52040b, 0x05042808, 0x10100a0a, 0x540b0b15, 0xea41054e, 0x0583440b, 0xbb823e20, 0x1b022c29, + 0x81006500, 0x76250000, 0xbb890ac7, 0x0fcb8318, 0x6c18d59e, 0x1b691647, 0x0ba16c09, 0xbb450720, 0x2c02210e, 0x4505ca76, 0x0c20078f, 0x0a20b982, + 0x09250483, 0x02060508, 0x0dfe5302, 0x161c0932, 0x070e0f16, 0x05020207, 0x0c090805, 0x0a090a09, 0x2018e645, 0x0ac44581, 0xe0450420, 0x45f3200e, + 0x05230daf, 0x82030404, 0x0f022700, 0x0a0a0d0d, 0x50410809, 0x0a0a2e14, 0x0d0a0b0b, 0x01010e0d, 0x25241312, 0x14064632, 0xee45ac20, 0x01262408, + 0x451c1d25, 0x66240bf3, 0x2d001500, 0x4717374c, 0x01301765, 0x21211417, 0x0f182f14, 0x0f10191a, 0x2f101a1a, 0x20230f82, 0x42cc4814, 0xfe210c05, + 0x16a94aac, 0x09396518, 0x240cfb78, 0x004d0015, 0x43899769, 0x223054e1, 0x17262717, 0x1d10172e, 0x1c11111c, 0x172e111d, 0x18220f82, 0xe7437e36, + 0x4c61204b, 0x9c2010b1, 0x2c41b047, 0xff330002, 0x032802f3, 0x00150066, 0x17b75261, 0xb9180320, 0xd1500a1d, 0x0f356711, 0x4a086347, 0x1421076f, + 0x0a775715, 0x0815d352, 0x0812753c, 0x28141409, 0x46373728, 0x272c2c30, 0x17141513, 0x18161715, 0x19252530, 0x030c0c19, 0x06050603, 0x0e090a07, + 0x1912130d, 0x1a211f19, 0x1b52141a, 0x3229339a, 0x282f3c33, 0x0f822129, 0x0812eb52, 0x3128b24e, 0x44563930, 0x18303043, 0x190c0d19, 0x0d112141, + 0x04080a0e, 0x24121104, 0x49363624, 0x1a201f25, 0x13131315, 0x0c0e0f12, 0x0806050c, 0x308d0f07, 0x65ca133b, 0x0a111124, 0x2015160b, 0x0300001f, + 0x31ff4c00, 0x12031702, 0x55001500, 0x5008e562, 0x22210535, 0x07475923, 0x22132222, 0x0bd37718, 0x37363724, 0x98183536, 0xfd4c1011, 0x05f74d0c, + 0x68151021, 0x132006a1, 0x27213184, 0x132b5326, 0x4818a420, 0x55080c9d, 0x11101d1d, 0x34111c1c, 0x28292677, 0x29292f2b, 0x1b1b2423, 0x09091011, + 0x36272615, 0x191c1d20, 0x0d131318, 0x0e07060d, 0x281e1d0f, 0x26343127, 0x02031726, 0x153e0202, 0x1e1e0f0f, 0x10342b2c, 0x22210809, 0x19192242, + 0x09091212, 0x1212090a, 0x21211a19, 0x2f531918, 0xfc520811, 0x0d0706d0, 0x0a161d39, 0x1409090a, 0x2a1e1f12, 0x162c1529, 0x11090816, 0x1f181711, + 0x2824231f, 0x2532313e, 0x15131225, 0x12112914, 0xb9fe0d13, 0x2d2d3ba3, 0x100f1f1e, 0x26194601, 0x32633025, 0x190d0c32, 0x3125251a, 0x1a25252f, + 0x0c0c0d1a, 0x6742000c, 0x005c2407, 0x49730013, 0x33240f95, 0x37363732, 0x5618e95c, 0x79420779, 0x0549550d, 0x18113541, 0x420c0f69, 0x5f4a0c81, + 0x1a0a2114, 0x0db9b518, 0x0a050536, 0x140f0e0a, 0x1b181813, 0x241f201c, 0x262c2c31, 0x0b0b0b0a, 0x19bdb518, 0x100f0c29, 0x15151312, 0x421b2018, + 0x15230594, 0x5e031716, 0xa9220d18, 0xb5180509, 0x2a310bc8, 0x22222727, 0x18181d1c, 0x0c0c1211, 0x0c0d0707, 0xccb51819, 0x0e12261f, 0x0409080e, + 0x08a24204, 0x0d0d1122, 0x25079b42, 0x1f00e802, 0x73187700, 0x9f420c0d, 0x071f5f05, 0x44086350, 0x5a1806f5, 0x7e180997, 0x35201a17, 0x7506ed47, + 0x5d411112, 0x0ac14206, 0x18132b72, 0x4a10c1a1, 0x15241ff7, 0x3a2c2c1d, 0x26069c7f, 0x1415140b, 0x6b0b0d16, 0x2c080532, 0x12131214, 0x111b1b24, + 0x04070608, 0x0a020205, 0x13130f10, 0x311b1717, 0x1d1d2728, 0x0f0e0e0f, 0x28281d1d, 0x17161a31, 0x0f101213, 0x07ec420c, 0x42d8fe21, 0x112a06d9, + 0x08080910, 0x0b091009, 0x784e0c0b, 0x05f94206, 0x034b0220, 0xdafc2517, 0x01100f1f, 0x03250084, 0x39070505, 0x07936a1d, 0x0203053d, 0x09140909, + 0x0e0f0c0c, 0x29161213, 0x11111615, 0x05060a0b, 0x24251312, 0x433d3232, 0xa34e060e, 0x43152005, 0xeb350912, 0x0d0d0c1a, 0x25191a0c, 0x26313025, + 0x090d1925, 0x03060709, 0x061b4303, 0x25253024, 0x17430000, 0x00662408, 0x4a5f0017, 0x63563995, 0x0b91450d, 0x37323324, 0x07433736, 0x10735608, + 0x3229a22c, 0x38463c33, 0x14272737, 0x144e0914, 0x28282906, 0x1717192f, 0x14151615, 0x06820082, 0x18161731, 0x18252532, 0x0c0b0c19, 0x2418180c, + 0x45203225, 0x87560680, 0x24332312, 0x87561111, 0xcdba1806, 0x03043d0a, 0x08090607, 0x1321410d, 0x08090d0d, 0x12120404, 0x37362424, 0x35364849, + 0x12122223, 0x2106d842, 0x008200e3, 0x27067345, 0x1700d902, 0x77005b00, 0x201a1141, 0x06ab5514, 0x8408c742, 0x1c7d45e9, 0x4208c74b, 0x052006bf, + 0x520a2543, 0x3b41077f, 0x66012107, 0x2d0e754c, 0x763a3ba9, 0x2b282926, 0x1416151a, 0x96421314, 0x09102905, 0x25261508, 0x1d1d2136, 0x2e077b45, + 0x0d0d0606, 0x19181314, 0x34221d1c, 0x42162626, 0xfe290592, 0x1a1912b9, 0x19192121, 0x22308211, 0x82432221, 0x74122009, 0xe05605f6, 0x79a83611, + 0x07063c3c, 0x0b1d390d, 0x05050908, 0x09090202, 0x1f1e1314, 0x09814529, 0x1f1f1730, 0x2a292424, 0x1e1f2423, 0x11111718, 0x85450808, 0x25902307, + 0x00820c1a, 0x25191a24, 0x82453125, 0x25242606, 0x26253131, 0x2c008200, 0xfe330002, 0x022802f3, 0x004700cb, 0x0d2b5253, 0x42139550, 0x5f44284f, + 0x22072308, 0x4b422802, 0xe4fe2d3b, 0x080f0f09, 0x1d112750, 0x3937121d, 0x293a4542, 0x331e6efe, 0x321e1e32, 0x4f421e33, 0x0403240a, 0x4d000b00, + 0xb18a05f7, 0x43421320, 0x1201265f, 0x31111d1d, 0x21d98319, 0x3f42f85a, 0x1f612a53, 0x1f1f3233, 0xfd1f3332, 0x573742c1, 0x00004525, 0x18032402, + 0x211d036c, 0xbc183510, 0x5c181447, 0x68201503, 0x0b5dbc18, 0x2111a35c, 0xbc180217, 0x7e820d71, 0x82610021, 0x840d2004, 0x4a412083, 0x838518a3, + 0x180c256b, 0x2a1331a7, 0x22151415, 0x212114dc, 0x57203e14, 0x342b0d3f, 0x1a17458d, 0x2b392a29, 0x79152020, 0xaa9314d0, 0xbdb72426, 0x17162f5f, + 0x7905fd6f, 0x02221798, 0xbf820100, 0xbd026728, 0x2f002700, 0xa9180000, 0x35410ac5, 0x0b8f5509, 0x22353423, 0x22a58223, 0x84333213, 0x33452409, + 0x41113311, 0x33340533, 0x4c113210, 0x4c45cf1a, 0xcf45cf4c, 0x82850145, 0x1a4f133a, 0x3a2a0185, 0x827bfe13, 0x53fb54fa, 0x10829e01, 0x23207182, + 0x0d247382, 0x3700db02, 0x5d827192, 0xa4186182, 0x2f3021a1, 0x450f2f0f, 0x852c8517, 0x2a29192c, 0x2a2a563a, 0x2305e67a, 0x211c1514, 0x2d05c455, + 0x95c00145, 0x0e2b133a, 0x133a0e2b, 0xa4183264, 0x1e2315ab, 0x184ae029, 0x2308b36e, 0x005b0066, 0x1805bb75, 0x641c8977, 0x352009f5, 0x312b6c18, + 0x32353422, 0x18066341, 0x180c6f6f, 0x20557567, 0x266e186a, 0x196c180d, 0x526e184e, 0xfb40180f, 0xd4022607, 0x63003f00, 0x61531800, 0x080d471a, + 0x1814577d, 0x18089947, 0x200c835e, 0x08274835, 0x2007d962, 0x343d8233, 0x071529c4, 0x120c0d06, 0x12121712, 0x04071111, 0x05060f03, 0x27008404, + 0x04070609, 0x2a020305, 0x13211f85, 0x841e8217, 0x080a251f, 0x07090809, 0x02231b82, 0x7f5e0103, 0x50251aeb, 0x1218181f, 0x322a8312, 0x0303060f, + 0x0403060d, 0x02010102, 0x09090405, 0x82120e0e, 0x1211221b, 0x84468209, 0x0509221b, 0x24178205, 0xfd0e0e08, 0x1bfe7f99, 0x57086742, 0x13420fe3, + 0xe0a82416, 0x418fe04b, 0xe1570dc1, 0x0e794106, 0x8600022c, 0x2202fcff, 0x0700b202, 0xdd572b00, 0x67421809, 0x82862023, 0x51012163, 0x201a0641, + 0x05816b6d, 0x5757d7a4, 0x36e3961b, 0x2805d101, 0x28484928, 0x14280527, 0x2b181806, 0x08191829, 0x8da2fe2c, 0x0e5557f5, 0x4318fd8e, 0x02250873, + 0x001f00e8, 0x0fbf4d43, 0x18115557, 0x29232542, 0x1d149f01, 0x2748241c, 0x376a0627, 0x110c2b05, 0x10161611, 0x080c0c11, 0x11820308, 0x6f0b0b22, + 0x4b1a3341, 0xfd2117c1, 0x19464167, 0x64000126, 0x030247ff, 0x2405d354, 0x10232201, 0x13991815, 0x07062209, 0x0d7f6306, 0x4116db54, 0x02270c63, + 0x76287503, 0x82356827, 0x060535b1, 0x0e0e0302, 0x0f0f101c, 0x09090b0f, 0x08090708, 0x16161b0a, 0x2407c667, 0x950f0b0c, 0x06704132, 0xfe6e0226, + 0x143c8769, 0x4123d854, 0x00200785, 0x28057f41, 0x0224024c, 0x001700db, 0x1b154b61, 0x21063945, 0xc34d1514, 0x08df4305, 0x1808e549, 0x1808ed98, + 0x2013bb45, 0x08e95515, 0x2e4c0125, 0x82040817, 0x86082000, 0x0e5b2707, 0x0f101b0e, 0xde83100f, 0x290bb655, 0x09050602, 0x1b210e08, 0x4518141a, + 0x34280fd7, 0x07070a1a, 0x02020405, 0x1139ad18, 0x1541fd29, 0x04040b0a, 0x82152906, 0x0101351d, 0x0a040501, 0x1510100a, 0x0b0b0c0a, 0x0f0d0d0a, + 0x150d0c03, 0x11fa4518, 0x0b0d1222, 0x00207c84, 0x02270082, 0x00006400, 0x58030302, 0x03201e53, 0x820caf41, 0x05f341dd, 0x58012025, 0x82071930, + 0x070429dc, 0x04081831, 0xfc040303, 0x580d0e43, 0x12431250, 0x01002110, 0x23061344, 0x0023000e, 0x0a9ba718, 0x4105856a, 0x0221135d, 0x19d14222, + 0x46188482, 0x022217f1, 0xeb824400, 0xbe022629, 0x3d003500, 0x73330000, 0x35230e19, 0x85262734, 0x3237226d, 0x23018333, 0x17141514, 0x5f520382, + 0x06f56a07, 0x735f1020, 0x446e0805, 0x0d0e5db9, 0x090c0b0d, 0x04070709, 0x77010104, 0x30302028, 0x1716192e, 0x07070111, 0x12120e0e, 0x1a191817, + 0x4c45d11c, 0x18474c19, 0x06070403, 0x0b0a0909, 0x6c0d0b0c, 0x35517a79, 0x5e3e011a, 0x2c315b5e, 0x171a222c, 0x11161618, 0x070d0d11, 0x8001be06, + 0x8081fe7f, 0x00040000, 0x0237ff58, 0x00db0216, 0x002f0017, 0x00530037, 0xf3731300, 0x22232214, 0x20179621, 0x18a58601, 0x180761a3, 0x2013abaf, + 0x05b84167, 0x22076064, 0x89450136, 0x04043b10, 0xfe360804, 0x4517458d, 0x2d356c45, 0x21641617, 0x0b0a38a9, 0x20201617, 0x8542802a, 0x70b01811, + 0x01270811, 0x76fe838b, 0x1238c984, 0x013b1d1e, 0x1132755f, 0x2eb29bfe, 0x18192324, 0x00000d0d, 0xff360002, 0x034502f3, 0x60130066, 0x162e0ae9, + 0x22171617, 0x06272623, 0x22070607, 0x0b542603, 0x1837200f, 0x2014c9c6, 0x21ff8223, 0xde671301, 0x142b0808, 0x1c381135, 0x0f1a1a0f, 0x19188b34, + 0x312e1a19, 0x13183431, 0x0a0d0e13, 0x0306060a, 0xdb308f03, 0x1b0d0d49, 0x3c2b2c1b, 0x54181919, 0x328209ea, 0x1a1b2a08, 0x0514fd10, 0x490b0808, + 0x13132625, 0x08080304, 0x12120d0c, 0x01201919, 0x143b6227, 0x429ec6fe, 0x1c1c2e2f, 0x03020e0d, 0x2fbf8300, 0x0237ff77, 0x00060314, 0x002d0011, + 0x37361300, 0x210dcb54, 0xb1180322, 0xd5241a21, 0x19301f5c, 0x0805e456, 0x1c1d1128, 0x34164411, 0x2d274e6f, 0x27771716, 0x0b0b3fbb, 0x20201716, + 0x56025f29, 0x37212c84, 0x23162137, 0x1d561624, 0x4641e1fc, 0x02002c15, 0x00ff4500, 0xbd026402, 0x18002900, 0x180cf1b2, 0x180869a8, 0x550dbf7e, + 0x14220569, 0x6a182215, 0x45240b19, 0x3a26194c, 0x1e8dc718, 0x1008a32c, 0x2850080f, 0x111e1d12, 0xc7180237, 0xff2a2199, 0x33321f00, 0x32331f1f, + 0xa382001f, 0xa3827120, 0xdb025429, 0x3d003100, 0x42330000, 0x36200597, 0x3621a184, 0xbd761837, 0x93072008, 0x070621a9, 0xb118ab8e, 0x82202bd1, + 0x2905064f, 0x121d1c12, 0xb7240237, 0xb118e6fe, 0xbc8a26dd, 0x5d000122, 0x3f22c082, 0xbb820e02, 0x1420b985, 0x2b7fb218, 0x17485d3f, 0x2b2c2c1e, + 0x10141517, 0x291b264b, 0x13152729, 0x2f1e0e13, 0x16182e2f, 0x254a1016, 0x7fb2181a, 0x01472e0a, 0x4991838b, 0x2728281b, 0x0e131215, 0x7eb21818, + 0x0200231d, 0x97826c00, 0x68033926, 0x17000b00, 0x4308c74d, 0x5f410537, 0x33202505, 0x6c201514, 0x270a3a6d, 0x01194c13, 0xa6fe5a0e, 0x0a507618, + 0x0e021328, 0x9b2efeaf, 0x4f82143c, 0xfcff5026, 0x74030502, 0x27204f82, 0x97494f8d, 0x0b414409, 0x16172b08, 0x14333233, 0x1e1f13be, 0x161f3e13, + 0x39162423, 0x274e3301, 0x17202029, 0x6e0c0b16, 0x173bb425, 0x1b502e16, 0x2717f802, 0x03831727, 0x0d04fd34, 0x2319180d, 0x66012e23, 0xfe113277, + 0x1e3ab696, 0xc282381d, 0xff6c0027, 0x02390200, 0x42c785bd, 0xbb84061b, 0x200ba142, 0x20bb866c, 0x0d854220, 0xad41bb84, 0x204f830a, 0x254f8250, + 0x00db0205, 0xc782001b, 0xb3470520, 0x01cb1809, 0x6ebb850a, 0x02210baf, 0x2cbb9105, 0x0f08c5fe, 0x284f090f, 0x121d1d12, 0x21bd9336, 0xe342f2fe, + 0x87ca180b, 0x42172009, 0xc79808e3, 0x0b06662b, 0x2142060b, 0x0b12110b, 0x07834139, 0x210c0225, 0x83213737, 0x85002003, 0x02fc22c7, 0x20c7a343, + 0x0a855103, 0x4822c793, 0x6b820a07, 0x120b2225, 0x93390b11, 0x1d0221c6, 0xc789778c, 0xc78d2320, 0x67463720, 0x079b4116, 0x04488220, 0x82032008, + 0x37082100, 0xfe22d787, 0x9f180304, 0x04200c8e, 0x0027de82, 0xff5a0002, 0x840f02fc, 0x003323df, 0x5b820500, 0x27262723, 0x11614226, 0x03221522, + 0x01337796, 0x2020299b, 0x0b0b1717, 0x3cb4256f, 0x502d1716, 0x6b01571b, 0x874805c6, 0x37082106, 0x2421ee85, 0x0b73422d, 0x02011222, 0x01239092, + 0x4200fbff, 0x2b200587, 0x3421f582, 0x964c1835, 0x37362109, 0x20080d51, 0xbf731837, 0x1514230b, 0x03823320, 0x170e6c33, 0x0c080e16, 0x2315080c, + 0x194c1524, 0x1e31321d, 0x080d8207, 0x11110d23, 0x24242313, 0x5a0e0118, 0x59b3a6fe, 0x09101009, 0x0a10100a, 0x0e17170e, 0xc0590c01, 0x20201360, + 0x2c108313, 0x0c0b0c08, 0x0f181817, 0x143c3fbf, 0x2b008200, 0xff260001, 0x020502fc, 0x004700db, 0x8b110749, 0x56362095, 0x15200b8b, 0x0bb54318, + 0x157f2583, 0x32333608, 0x05021433, 0x1114274e, 0x0e101012, 0x0b170d0d, 0x302f1b0c, 0x2fb1831b, 0x1211100c, 0x17232321, 0x3bb4256e, 0x1d32311e, + 0x77441383, 0x05062207, 0x221e820c, 0x491b5017, 0x5c240b4b, 0x1e1f132e, 0x1131b682, 0x0b0a080a, 0x1617160c, 0x3242c40f, 0x135ab411, 0x3fcc8521, + 0x17171810, 0x090b0b0c, 0x151e4282, 0x080e0f16, 0x02003807, 0x00004600, 0x68032302, 0x2b000b00, 0x180ed168, 0x2e1e877c, 0x1e130b01, 0x1f3e131f, + 0x16232416, 0x1855d83a, 0x44153e7c, 0x25210ecc, 0xfa7b1832, 0x528b8219, 0x122405fb, 0x3d001300, 0x8716677f, 0x20cf5193, 0x1a11f825, 0x180e181a, + 0x290a0756, 0xaa3a141d, 0x03021b38, 0xdf510103, 0x123f7117, 0xb6189f20, 0x1e331c99, 0x004ae029, 0x00020000, 0x0200ff46, 0x00bd0223, 0x432b001f, + 0x2b470693, 0xbf7d1807, 0x0b374512, 0x36414620, 0x56832016, 0x7d180a20, 0x5b451b31, 0x8261200e, 0x020d2287, 0x0a6b481b, 0x2b418783, 0x20918b20, + 0x1d234161, 0x98896c20, 0x1b413620, 0x429d8a20, 0x66240767, 0x35001500, 0x1817ad60, 0x611ff97e, 0xe820163f, 0x61164441, 0x83421647, 0x00152226, + 0x41a7a03f, 0x01212059, 0x0de56d09, 0x17172f27, 0x37172627, 0x1d6441bb, 0x6d05a55e, 0x88420cb0, 0x00022123, 0x02360082, 0x00db0266, 0x0039000b, + 0x37361100, 0x33323534, 0x07061514, 0x37431322, 0x4350180e, 0x0c25271d, 0x184a1f5f, 0xa582a73a, 0x02030228, 0x392a2919, 0x2856212b, 0x07182505, + 0x150d0d06, 0x2d071255, 0xc7014508, 0x18482d87, 0x2d871848, 0x0e4239fe, 0x0d0d2309, 0x4f181a1b, 0x012d1abb, 0x37ff4a00, 0xcc021f02, 0x00003d00, + 0x0ae14d05, 0x18103521, 0x2310ad7f, 0x23221510, 0x1520bb8e, 0x08084d60, 0x01222345, 0x171b380c, 0x0b0b1111, 0x08070605, 0x17170f0e, 0x1b1b241e, + 0x090a1313, 0x1f3d194b, 0x01030301, 0x3f2e2d1c, 0x0c2f2f5d, 0x1f17160b, 0xc94d2920, 0x07081238, 0x18180e0f, 0x9e3c0123, 0x141f202a, 0x5c0a0914, + 0x303305a3, 0x026eb6fe, 0x1d11af0e, 0x1c35121d, 0x7b3d3e1b, 0x4da0c1fe, 0x0024080d, 0x61000100, 0x0d25b382, 0x39001b02, 0x13b11800, 0x18352008, + 0x2110f96d, 0xaf921415, 0x9d4e1420, 0x22232b07, 0x2d1f3dfb, 0x06071716, 0x57560e0d, 0x4217200a, 0x0b260c0d, 0x2016170a, 0xaa832a20, 0x3b1d1e34, + 0x1a2370e0, 0x08111119, 0x150b0b09, 0x291e1e16, 0x75434ae0, 0x70e0210c, 0x8018a38a, 0x4e26073b, 0x23000700, 0xb9534300, 0x07fb590a, 0x220fdb62, + 0x18161716, 0x081fa5b9, 0x4be09f20, 0x3f4501e1, 0x2f3f7d3f, 0x0f1f1f2e, 0x1f0f1010, 0x3f2f2f1f, 0x1f2f303f, 0xfe0f101e, 0xea181198, 0x033519bd, + 0x34123408, 0xb656fe12, 0x16165a5b, 0x44452c2d, 0x45455c5c, 0x28ff822e, 0x2e2d1617, 0xc8fe4544, 0x9bea1821, 0x00032e1d, 0x02f3ff45, 0x00be0224, + 0x00270007, 0x1d676c37, 0x21099d66, 0x676f0607, 0x27c3830f, 0x2c2d1efd, 0x2d2d3a3b, 0x0e20c382, 0x10ae5118, 0x2424a136, 0x24234846, 0x46482324, + 0x79022424, 0x11341134, 0x1223c0fd, 0x232a9e82, 0x43343324, 0x23343344, 0x00821223, 0x07e8bb18, 0x576faa20, 0x0777410c, 0x13005c26, 0x5b003b00, + 0x610f3154, 0x216311f1, 0x1816200c, 0x6e09914d, 0x23201795, 0x0a216518, 0x2206d17f, 0x7f062727, 0x21210ad1, 0xc3821818, 0x0ec5613d, 0x7d18ac20, + 0x0020407e, 0x2407bb41, 0x001f00e8, 0x3f9b1843, 0x1db3610c, 0x08515f18, 0x210f2341, 0x51181415, 0x01212191, 0x0a736ca4, 0x0d070723, 0x0765550b, + 0x04080729, 0x0b031427, 0x181e2e0b, 0x553bb753, 0xa4201887, 0x3ba94e18, 0x04000032, 0xf3ff3a00, 0x69032e02, 0x17000b00, 0x53003300, 0x200ddf4d, + 0x0a3f4c33, 0x4308c55d, 0xac2c32c9, 0x121f1f12, 0x2416203e, 0x8d3a1524, 0x1f210b84, 0x200b8315, 0x34dc43cf, 0x17ee0229, 0x17172627, 0x87172726, + 0x70fe2107, 0x2036e843, 0xcb551804, 0x20ff8308, 0x4b4b1837, 0x0706240a, 0x8c220706, 0xe38018ff, 0x1415211a, 0x3811f943, 0x1e1e12ac, 0x141c3911, + 0x34142324, 0x2020138f, 0x171d3c13, 0x32172727, 0x290d4489, 0x73086179, 0xfd210772, 0x281944d8, 0x02000024, 0x04822400, 0xbd026029, 0x4f003100, + 0x4e210000, 0xbf7f08ef, 0x066b510c, 0xa3573320, 0x071f5d05, 0x25230784, 0x18103332, 0x62090966, 0x3e080bed, 0x16171617, 0x65c96002, 0x19202127, + 0x0f141418, 0x0410101e, 0x0b080705, 0x14100e0c, 0x201a1914, 0x4adf2620, 0x297b2d86, 0x2e8a297b, 0x0817c7fe, 0x1e2d0a15, 0x0708111f, 0x02040506, + 0x82020203, 0x08073e2b, 0x051e1f11, 0x0f0a0a05, 0x4428130f, 0x2a346143, 0x1a21212a, 0x0e131419, 0x050a0a0f, 0x08706a04, 0x96013c33, 0x1b0e0e88, + 0x1b13140d, 0x2b23221a, 0x1a23222a, 0x3224821a, 0x000e0d1b, 0xff070003, 0x025d02f3, 0x0063001b, 0x61b5009b, 0xe38f0d6d, 0x5e089d73, 0x0d4d0fb9, + 0x097b7d0a, 0x09eda118, 0x08cb4018, 0x16c7ad18, 0x8313bd73, 0x0f2d4133, 0x33323725, 0x47343734, 0x3f0813b5, 0x130f0401, 0x15181713, 0x0d101114, + 0x0b150a0d, 0x0503030b, 0x0a080706, 0x2f222216, 0x0f131417, 0x0b0e0e10, 0x2d202013, 0x111f202b, 0xb8090912, 0x0c06073e, 0x1c15150c, 0x090a0909, + 0x09080909, 0x0c311f82, 0x09070708, 0x06070808, 0x14111110, 0x18252431, 0x08008307, 0x7c070820, 0x0c0a0a0a, 0x0a12121a, 0x02040405, 0x03020103, + 0x07040502, 0x0e0a0a07, 0x0b0d110e, 0x3582090b, 0x19820420, 0x01030324, 0x1c820201, 0x06040329, 0xe0070705, 0x6d01366e, 0x220805f8, 0x10101516, + 0x05050a09, 0x04030802, 0x09080404, 0x200f0c0c, 0x28493535, 0x1a192120, 0x21101414, 0x82041010, 0x2c67184d, 0x0d1b290e, 0x121b1b26, 0x01090911, + 0x03295482, 0x09060303, 0x1b350c08, 0x08678606, 0x02020522, 0x091f100f, 0x05060707, 0x053d0405, 0x0a0a0302, 0x0e0f0a14, 0x1a1a1213, 0x21222a21, + 0x0f101616, 0x08799218, 0x0a090736, 0x13120f0e, 0x22241c1b, 0x14131b1b, 0x0a0a0e0e, 0x02ee0808, 0x06285282, 0x1a192404, 0x08081010, 0x1033fc82, + 0x0f251a1b, 0x00030000, 0x02000048, 0x00680368, 0x7d47000b, 0xf5520a49, 0x098c1809, 0x06fb460f, 0x11f77618, 0x6009f168, 0x3220061d, 0x0bc7a618, + 0x14235208, 0x1f1e13d9, 0x161f3f12, 0x3a152424, 0x3d468aa4, 0x21212f2f, 0x0a0b1110, 0x1c1d1414, 0x0c0b0e24, 0x0b0a0a0a, 0x0b0c0a0a, 0x1c1d190e, + 0x11244813, 0x0d111b1c, 0x0b0a0d0c, 0x0c0c0b0c, 0x48100e0e, 0x4a4c4c18, 0x24244725, 0x13130a09, 0x50241b1b, 0x0ea74e1b, 0x0d0d3d08, 0x25241a1a, + 0x1d1e262f, 0x0d0c1616, 0x06050405, 0x0b0a0606, 0x14140d0e, 0x36362f1a, 0x37382124, 0x13141921, 0x08080d0d, 0x02030405, 0x77014adf, 0x203d1f1e, + 0x10101817, 0x00bb0808, 0x022c0082, 0x00009700, 0x12032402, 0x39001300, 0x4506574f, 0x114109c7, 0x57b61809, 0x08217f0f, 0x23820720, 0x14156a08, + 0x0e012215, 0x0d0c0c0a, 0x111a1a19, 0x1e142142, 0x0e0f1d1e, 0x8b390b0e, 0x03021b38, 0x110b0203, 0x1d171711, 0x1e22231d, 0x201d1a1e, 0x222b2220, + 0x0b171621, 0x6202460b, 0x110f0f0c, 0x1520211f, 0x1f212015, 0x0c0f0f11, 0x8b019efd, 0x20201383, 0x16151b13, 0x08070f0f, 0x3b100809, 0x0a0a151d, + 0x1a190c0d, 0xc4312424, 0x2db28242, 0x48000300, 0x680200ff, 0x3b00bd02, 0xe3184d00, 0x15200f3f, 0x0ee7bc18, 0x4e31b341, 0x48200b65, 0x2e43b341, + 0x0f0f0958, 0x12284f08, 0x37111d1d, 0x41af0e02, 0xfd213cb3, 0x0b2b544b, 0x00ff7228, 0x1b022402, 0x55562500, 0x20a74108, 0x200be553, 0x1d9e4197, + 0x0f083c25, 0x8350090f, 0x371221b7, 0x4f1e9641, 0x5f430cdf, 0x00662707, 0x00510015, 0x5f7b0063, 0x08bb572a, 0x4911c357, 0x23200671, 0x43078763, + 0xea220e69, 0xb2702213, 0xba472111, 0x4f43bf41, 0xc741169f, 0x4300203c, 0x15220c7b, 0xc34f3b00, 0x46372023, 0x7d43078f, 0x70242011, 0x172212eb, + 0xe0419f37, 0x16bf4f1d, 0x271f7f43, 0xff460002, 0x032502f3, 0x151b8418, 0xa16c0620, 0x18272007, 0x180853a7, 0x450b0fa2, 0x73470731, 0x43d78e14, + 0x7f4508bb, 0x14152308, 0x8e180607, 0x40080b15, 0x302f21d4, 0x1b1b1c3e, 0x1a1b1a1a, 0x3536371b, 0x1d1e2633, 0x0b0a1516, 0x0f0f0707, 0x0e241a19, + 0x341b0707, 0x17172626, 0x08070b0c, 0x1515100f, 0x21201c1b, 0x30302b25, 0x2f2f2e34, 0x1b1c232f, 0x312b8415, 0x191a0d0e, 0x06070d25, 0x2627351b, + 0x0c0b1818, 0x66451110, 0x3a60080a, 0x020d0d1a, 0x08050503, 0x22430b08, 0x08111121, 0x18101008, 0x13181f18, 0x0b0e0e12, 0x0103080b, 0x110b0701, + 0x1e161611, 0x1c1f251d, 0x1217171c, 0x070d0d12, 0x120a0907, 0x0e1b2040, 0x1007080e, 0x1d17160f, 0x0d101015, 0x070a0b0d, 0x06010203, 0x1912120b, + 0x2921201a, 0x00272733, 0x6a000200, 0x08f34518, 0x4b547520, 0x414f1815, 0x1553410c, 0x30272223, 0x08914c23, 0x4c262721, 0xfb7f0c93, 0x81dc180c, + 0x055d510d, 0xfb060727, 0x191a1a11, 0x0983540d, 0x141e1d37, 0x281eba3a, 0x16163329, 0x19161617, 0x2f341b19, 0x171f2a2f, 0x08fc8217, 0x0707093d, + 0x18180e0e, 0x01010121, 0x060c0b06, 0x121e1d29, 0x0d080911, 0x271b1b0e, 0x2a2b3327, 0x1414282a, 0x15141314, 0x1e3d1615, 0x0b06051e, 0x0e0b0b06, + 0x1612120f, 0x23450c19, 0x540f0f23, 0xbe2a12b9, 0x020b0a17, 0x06040402, 0xc7180806, 0x103c09a2, 0x0d0e1012, 0x08080a0b, 0x01020107, 0x0d070202, + 0x1811120c, 0x1e261d17, 0x0a14151d, 0x22081682, 0x0b1c380f, 0x05060807, 0x13140303, 0x0d0d1227, 0x05040508, 0x04050304, 0x0c020404, 0x283b2524, + 0x82001e1e, 0x07a74200, 0x15006624, 0xa3687d00, 0x5e132017, 0xa549101d, 0x41ad420b, 0x1807134a, 0x2815c18f, 0x1b1b1904, 0x3535381c, 0x37da8232, + 0x0b0b1516, 0x080f0707, 0x0b0c090a, 0x0e141010, 0x341b0707, 0x18182525, 0x3706bb42, 0x201c1b16, 0x302d2421, 0x2f2e332f, 0x1c252e2e, 0x0a15151c, + 0x0e07070a, 0x0e54df18, 0x21111029, 0x3f302f21, 0x731a1a1c, 0x1420127f, 0x220dc542, 0x181a1e17, 0x310e61df, 0x1611110a, 0x261e1e16, 0x171c1c1f, + 0x0d121118, 0xc942060d, 0x1c16260d, 0x0d101115, 0x34a8820d, 0x06010203, 0x1812130a, 0x2a212219, 0x1a262733, 0x020d0d1a, 0x0bcf4203, 0x7f001522, + 0x64217341, 0x77410ba5, 0x20cd4208, 0xca182320, 0x2d441437, 0x09c55207, 0x97262722, 0x350bab73, 0x111d1d10, 0x111c1c11, 0x19172634, 0x191b1b19, + 0x17181619, 0xb16d1416, 0x53092005, 0x1f20056e, 0x2606d742, 0x131d1c28, 0x42090912, 0x28080ad7, 0x2a292827, 0x011e1f3d, 0x04030302, 0x0a060604, + 0x130d0d09, 0x0c191913, 0x111a1a23, 0x0f090812, 0x281e1e0e, 0x16163328, 0x11ba7316, 0x429afd21, 0x0d2405dd, 0x06060909, 0x0c2c3c83, 0x1310100b, + 0x0a0e0d11, 0x0608080a, 0x2807e142, 0x18181111, 0x1d1e261e, 0x85ca1814, 0x0708360d, 0x07060708, 0x03050406, 0x04050304, 0x02040504, 0x110d0c07, + 0x292b8212, 0x161e1e27, 0x020b0a17, 0x00820002, 0x4600012d, 0x250247ff, 0xdf00cb02, 0x51010000, 0xbc180eab, 0xba180ffb, 0x44180f77, 0xad18083d, + 0x27211005, 0x4e018226, 0x84180c0b, 0x61660947, 0x4a36200c, 0x7c1809f7, 0x1189112f, 0x8314d76e, 0x08a544ad, 0x4d0ba772, 0xe1410f17, 0xb3012507, + 0x0d111113, 0x0841e218, 0x1f17102d, 0x0506281f, 0x04040504, 0x18030203, 0x2122afad, 0x26820203, 0x0403032d, 0x1a1e0306, 0x0d0d181b, 0x820e0e0d, + 0x1c1c2304, 0x07831a1b, 0x0d0c0d2d, 0x1e1e250c, 0x08080a16, 0x82030605, 0x03042c4f, 0x08070505, 0x0d0d0b0a, 0x18110f0f, 0x230b03e3, 0x0609080c, + 0x5a462182, 0x07e3180a, 0x0c0d360c, 0x0b0b0c0b, 0x1718170a, 0x10101317, 0x0c0c0f0f, 0x0a0a1509, 0x357b8201, 0x0e080605, 0x0d241a19, 0x191b0607, + 0x73011615, 0x0d0b0b09, 0xe2182219, 0x0c250892, 0x050c0c13, 0x82008206, 0x18042004, 0x082b8c72, 0x05030226, 0x04040302, 0x05050405, 0x0c112243, + 0x0305080d, 0x01020103, 0x10080802, 0x0b0a0908, 0x100d0d0c, 0x0a0b0c0d, 0x0721d982, 0x26578208, 0x04040505, 0x18010103, 0x820857e3, 0x0f0e33e1, + 0x20141111, 0x18171b1c, 0x0d0c1212, 0x02030706, 0x00830304, 0x04050426, 0x06072040, 0x04253482, 0x03070305, 0x05b24503, 0x1610072c, 0x090a1c15, + 0x08080909, 0x15440608, 0x07052f07, 0x01000007, 0x47ff6a00, 0x1b020302, 0x8f42d100, 0x1893426b, 0x480e5344, 0x3543147d, 0x12677106, 0x220fff4d, + 0x43780116, 0x042e06f7, 0x0b080704, 0x18140e0b, 0x05061e18, 0x2c410405, 0x01022505, 0x07010102, 0x0b5b9f18, 0x0f31b018, 0x81420320, 0x02043206, + 0x16161717, 0x0d0b0b0a, 0x0e0d0e0d, 0x0c0d0d11, 0x8300830b, 0x0b0a2d05, 0x17181e0c, 0x07060911, 0x02020404, 0x270d9e44, 0x0e111112, 0x0a0d0c0f, + 0x2705a244, 0x1411110e, 0x18161614, 0x14254982, 0x0a0a0909, 0x4701820b, 0x15250686, 0x1017171e, 0x0546470f, 0x0404012e, 0x0a0b0606, 0x13130d0d, + 0x29011c19, 0x2a074644, 0x0f111214, 0x0a0d0d0f, 0x820a0a0f, 0x05e2411f, 0x272b7342, 0x01040201, 0x03030304, 0x3c24fb82, 0x0606081e, 0x0d820782, + 0x012de082, 0x06060201, 0x0707060c, 0x09080809, 0x0cee4408, 0x05050327, 0x08070606, 0x07f24409, 0x08080a25, 0x82020504, 0x01042233, 0x223c8202, + 0x47040304, 0x052c08e0, 0x0f090a05, 0x0809140e, 0x05060707, 0x5e820082, 0x04050424, 0xdf470505, 0x4bbd200e, 0x3d49173f, 0xebaf180c, 0x0a69740d, + 0x4417a14a, 0xbf440fcb, 0x0fa94645, 0x07060728, 0x140d0106, 0x4a182120, 0x13260f9b, 0x1b186c47, 0xa5441f1b, 0x45132084, 0x10220d73, 0x174d1514, + 0x06162312, 0x84440303, 0x45082087, 0x0d220f55, 0x6f4b0a0b, 0x0015220a, 0x353342af, 0x42676344, 0x0f251425, 0x18262617, 0x8d4b182f, 0x172f2b08, + 0x17272617, 0x16155f37, 0x49441817, 0x08014975, 0x22060945, 0x4e111110, 0x9c231256, 0x44020305, 0x2f497528, 0x07e84409, 0x09080c2f, 0x00010000, + 0x0247ff18, 0x00bd0251, 0x240c8245, 0x23221514, 0x45038210, 0x4b4a10e7, 0x09f9480b, 0x7b503320, 0x8227200a, 0x35320839, 0x35342322, 0xaf510220, + 0x04091a3b, 0x03030202, 0x05050705, 0x02030304, 0x03040603, 0x0f100707, 0x171d1717, 0x09151615, 0x0908090a, 0x1f0c0909, 0x3f470f10, 0x14092e05, + 0x013ab007, 0x3bbd02ab, 0x9b2dfe14, 0x21148204, 0x3a830303, 0x0304042e, 0x0d0d0d04, 0x0f10140a, 0x05040b0b, 0x29215082, 0x244f8314, 0x0b010101, + 0x2b46820b, 0x0b0a0a0a, 0xd2010d0c, 0x00143b9c, 0x0025be82, 0x024fff42, 0x20cb8204, 0x570c8257, 0x9418079b, 0xaf570acf, 0x0e154a06, 0x6b222321, + 0xd1420717, 0x08814b07, 0x26272622, 0x08087772, 0x36353420, 0x14373637, 0x349d3301, 0x0203349d, 0x08080605, 0x10100b0b, 0x551a4d14, 0x0809092a, + 0xb2820607, 0x1627e282, 0x16171e16, 0x820a1516, 0x82092012, 0x0f1f3b9d, 0x150a0b10, 0x0c15141d, 0x7007060d, 0x11257025, 0x02111d1d, 0xbf11320e, + 0x1a821460, 0x08080c30, 0x02020604, 0x0b0a1135, 0x0d0d0b0c, 0xe9830b0c, 0x84050a21, 0x821520e9, 0x85022005, 0x150c36e9, 0x0d071d15, 0x1c14130c, + 0x48d7261d, 0x2f5c1132, 0x060c0c06, 0x2cf38283, 0x00180002, 0x03510200, 0x00150066, 0x17c74325, 0xab670320, 0x07717405, 0x08012222, 0x2f0d5e76, + 0x2114172f, 0x1e461421, 0xab013ab0, 0x4c3baf8e, 0x2312d044, 0x9cd20117, 0x07f5eb18, 0x42000228, 0x0402feff, 0xb7601703, 0x0bf76705, 0x41095b71, + 0x15200f37, 0x200e8f41, 0x360f8233, 0x0b067801, 0x2142070a, 0x0a12110b, 0x264b793a, 0x16242533, 0x410a0b15, 0x9d320726, 0x06349d34, 0x150b0c06, + 0x1a4d1e14, 0x38216502, 0x03832138, 0x0a99fd28, 0x2213130a, 0x09413022, 0x322c2d0a, 0x1d60bf11, 0x0b0c1415, 0x00350506, 0x01200082, 0x23051741, + 0x1f00bd02, 0x0c97ca18, 0x090ff418, 0x91881420, 0x02012226, 0x21632163, 0x632afd86, 0x4c216422, 0x143c43cc, 0xf08344cb, 0x8344cb21, 0x01002109, + 0x4f82f385, 0x47663d20, 0x83e58a0b, 0x33322159, 0x88062542, 0x21f5925b, 0xe9880402, 0x561d5623, 0x83ed8b1d, 0x86f1890f, 0x1c532ee6, 0x1c521032, + 0x305f1132, 0x060a0a06, 0x82ea8283, 0x4a10220d, 0x20ee8825, 0xf3971802, 0x00472208, 0x247775a3, 0x5e1ab776, 0x314809bb, 0x09595110, 0x18353421, + 0x23232b98, 0x37363536, 0x46182988, 0x07380bd3, 0x152ace06, 0x0c0c0707, 0x0a181212, 0x08070909, 0x07090809, 0x0b0f0304, 0xae180b82, 0x0d250b59, + 0x1712110c, 0x26008308, 0x070c0a09, 0x820e0403, 0x09063620, 0x05050706, 0x16c50203, 0x1b1a1717, 0x16151919, 0x09101212, 0x20368208, 0x20008204, + 0x58981803, 0x03042909, 0x0a0a0607, 0x1312100e, 0x13252282, 0x0b0b1010, 0x5f741807, 0x01260807, 0x01021a4c, 0x03020201, 0x0d0e0704, 0x13121111, + 0x12180003, 0x060e0e13, 0x03010107, 0x05030403, 0x07010104, 0x00820307, 0x0723b582, 0x8217030a, 0x830f201c, 0x0202291c, 0x04050404, 0x06080202, + 0x03281b82, 0x08080606, 0xfffc010b, 0x04292983, 0x0a0a0707, 0x0908080d, 0x2100820a, 0xac700b0c, 0x181d2005, 0x240938ee, 0x0a0b0b0a, 0x20a6830b, + 0x24a58203, 0x0b0b0707, 0x8241820d, 0x0605234b, 0xee18130a, 0x1728083c, 0x0e121217, 0x13190c0e, 0x0a2f8b82, 0x0002000a, 0x02f3ff61, 0x00d3020d, + 0x4169003f, 0x322124d7, 0x596c1833, 0x09b14908, 0x4107d141, 0x681807cf, 0x8b770dd9, 0x71342008, 0x23230583, 0x41262726, 0x1120099d, 0x20085577, + 0x21b88206, 0x8a180403, 0x07270825, 0x120c0d06, 0x82121811, 0x03073a20, 0x090a0e04, 0x060a0709, 0x01050507, 0x2a18e202, 0x2b543b29, 0x0717452b, + 0x067b6407, 0x1111182d, 0x17450909, 0x03011c37, 0x774f0203, 0xed2e3358, 0x3517172e, 0x51f46b35, 0x1a246cd9, 0x5f63111a, 0xbe6a1806, 0x8200200a, + 0x07074300, 0x07004e24, 0x7d626300, 0x0ec74a15, 0x2440c742, 0xe14be09f, 0x4c8942aa, 0x12340826, 0xf8fc1234, 0x245f5342, 0x000700b1, 0x11234131, + 0x83211b42, 0x41c820f1, 0x6c261ee2, 0x11341134, 0xb341e3fd, 0x005c2b2b, 0x005f0013, 0x33320100, 0x39570706, 0x47631805, 0x82132008, 0x08515e11, + 0x20098344, 0x20834426, 0x4408dd41, 0x0123097b, 0x18142796, 0x08106163, 0x130f5234, 0x18161612, 0x19181b19, 0x13181618, 0x0c101012, 0x0308090b, + 0x01194c03, 0x04020101, 0x0b060705, 0x120d0e0b, 0x151a1512, 0x0a131216, 0x0102030b, 0x19821a4c, 0x03040326, 0x0a0b0606, 0x2d0c8c63, 0x0a0de7fc, + 0x0407070a, 0x07030303, 0x644e0a08, 0x27152305, 0x09443626, 0x131b3505, 0x0b0d0a13, 0x070a090a, 0x03070608, 0x0b050504, 0x1811110b, 0x2b0a0144, + 0x1313191a, 0x10101111, 0x00000f0f, 0x2408ff43, 0x001300e8, 0x161b413d, 0x21057f72, 0xd36d2306, 0x18322005, 0x4309bd6b, 0x01220fd7, 0xf9822899, + 0x48492837, 0x27052827, 0x19180514, 0x18182b2b, 0x03030128, 0x292a1902, 0x05af433a, 0x0d0e0625, 0x181c1515, 0x2a08576e, 0x43e8023e, 0x21222221, + 0x82112343, 0x3bfd2500, 0x0f19180f, 0x220ad341, 0x43101a1b, 0xb3820e87, 0x8b460320, 0x007e2606, 0x004f002f, 0x618a18ab, 0x1b6d500d, 0x2007614a, + 0xf7421827, 0x0b07530e, 0x13718a18, 0x430ad143, 0x013c40cd, 0x11120f7f, 0x12111314, 0x0d0c100f, 0x04040a09, 0x090a0405, 0x10100c0c, 0x14131111, + 0x0f251582, 0x09090c0d, 0x20008205, 0x2a158209, 0x0d0e0b8c, 0x0d0e1010, 0x82060a0b, 0x0b0a2900, 0x10100e0d, 0x0b0b0e0d, 0x05211e82, 0x4b12449b, + 0x088d0223, 0x298a8205, 0x0c0b0908, 0x10100f0e, 0x75821213, 0x0c0c0f29, 0x05040809, 0x82080405, 0x820f2089, 0x13122a79, 0x0e0f1010, 0x0a340b0c, + 0x30808206, 0x0d0d0a0b, 0x0d0c0f0f, 0x06050a0a, 0x0a0a0506, 0x230d820c, 0x2cfd0d0d, 0x22575544, 0x46030000, 0x032705ab, 0x002f0038, 0x4179004f, + 0xa14459f7, 0x82013021, 0x1411120f, 0x0f121213, 0x090c0c10, 0x4105040a, 0x122007c5, 0x2e0bc541, 0x09050404, 0x8b0d0c09, 0x100d0d0b, 0x180e0d11, + 0x2008018c, 0x05d7570d, 0x06060524, 0xe644b605, 0x0948211e, 0x092d5b83, 0x0f0b0c08, 0x1210110e, 0x0f101012, 0x4171820e, 0x0c2406ad, 0x100f0e0c, + 0x11261583, 0x0c0b0f0e, 0x86820a34, 0x820b0521, 0x0f0e336d, 0x0a0a0c0d, 0x06050506, 0x0c0c0a0a, 0x0d0d0f10, 0x2945c1fd, 0x07574321, 0x0b006626, + 0x73001700, 0x65085158, 0xed461c71, 0x1791664f, 0xee423420, 0x18ea284c, 0x17172726, 0x87182627, 0x16fd2107, 0x2661b742, 0x000b0005, 0x41410017, + 0x7f422157, 0x17c36621, 0x4e425420, 0x6654201e, 0xb86607b0, 0x42fb2008, 0x012f2117, 0x3eff4a00, 0xbd021f02, 0x00008500, 0x6d333201, 0xf346086b, + 0x06072109, 0x18215318, 0x22230622, 0x53052342, 0x5f4708cf, 0x3759450a, 0x4bb90121, 0x30080f5e, 0x12111014, 0x08080b12, 0x02010505, 0x101b0e0d, + 0x0b100f10, 0x08070a09, 0x1c090909, 0x0f0f1515, 0x02030807, 0x0a0a0605, 0x1314150e, 0x0f0f1111, 0x2fcf4b0d, 0xfebd0225, 0x4b1e90e0, 0x30080d3e, + 0x04030506, 0x090c0c0f, 0x0709080a, 0x040a0a15, 0x15290703, 0x01030203, 0x05060101, 0x100f0a0a, 0x0c0c0b14, 0x0d0e0c0b, 0x04050110, 0x08090707, + 0x39bc4b0b, 0x00000032, 0xff610001, 0x02580246, 0x0055000c, 0x31140500, 0x0c2f6318, 0x53182320, 0x222313a1, 0x48353423, 0x534206eb, 0x3136211c, + 0x07202582, 0x01210382, 0x8c5318e3, 0x8b67180d, 0x03022807, 0x0b0b0606, 0x42091a0f, 0x0236185f, 0x0508090c, 0x56020206, 0x0b0a1501, 0x29070304, + 0x02030215, 0xb1660101, 0x0b152a05, 0x0c0d0b0c, 0x35100e0e, 0x1c6e421a, 0x0d0f012b, 0x090a0a0c, 0x02000009, 0x27008200, 0x66036802, 0x5f001500, + 0x2017db5c, 0x07494203, 0x20083f6c, 0x09a17a17, 0x8a068151, 0x21e38611, 0xbf5f2207, 0x18118808, 0x0815a947, 0x140e3d49, 0x090b1415, 0x2042070a, + 0x0d0d0d09, 0x05060607, 0x08070706, 0x0b0f100f, 0x100b2346, 0x07080f10, 0x06050508, 0x0d0d0706, 0x2042080e, 0x0b0a0907, 0x0d151414, 0x09071f40, + 0x13120909, 0x130c0d12, 0x090a1212, 0x5e480708, 0x4008121f, 0x81815517, 0x3c3c437d, 0x6869452e, 0x31313765, 0x21201925, 0x45464224, 0x45462e2e, + 0x20212443, 0x31312519, 0x69696537, 0x3c3c2e45, 0x81817d43, 0x24241b55, 0x4d4d4928, 0x4d4d3333, 0x24242849, 0x0823411b, 0x23410620, 0x83761865, + 0x182e200a, 0x0809db7e, 0x18102321, 0x0b0d1718, 0x1e3d090b, 0x0a080807, 0x0c111211, 0x0f0e0f0a, 0x05070707, 0x0f0a1a35, 0x82080e0f, 0x120c2809, + 0x08091112, 0x183d0609, 0x211bd5e5, 0x94445502, 0x15210807, 0x16162425, 0xfd152524, 0x616140ab, 0x2e2d325d, 0x25241c22, 0x4e4e4c28, 0x32322134, + 0x17181a30, 0x2a078412, 0x34121817, 0x284c4e4e, 0x181c2425, 0x2018e9e5, 0x07a31802, 0x00152208, 0x1747423f, 0xa3181320, 0x27422811, 0x18542015, + 0x18251ca3, 0x20124049, 0x18fb18d2, 0x00022c23, 0x0237ff34, 0x00060341, 0x976f0015, 0x6d7618c3, 0x22232357, 0x8b18179b, 0x182309bb, 0x5f1c1d10, + 0x502105d7, 0x6b761824, 0x05072834, 0x03040306, 0x83020302, 0x04052602, 0x0a0b0d05, 0x29008207, 0x0e0d0b06, 0x15151010, 0x05423719, 0x67761811, + 0x11200832, 0x09080d0c, 0x05060607, 0x07060707, 0x210d0b0a, 0x11111919, 0x12090d0d, 0x09090e0d, 0x00000506, 0x08f77318, 0x17006626, 0x59002f00, + 0x32d37818, 0x18283342, 0x201f6575, 0x243d42c0, 0x04070328, 0x162c0704, 0x75180407, 0x03201020, 0x04221785, 0x4d42f9fc, 0x00002424, 0x82370002, + 0x03312204, 0x05df7966, 0x0e3fb918, 0x20074145, 0x55e71820, 0x3320250e, 0xe4201514, 0x28063b7e, 0x39162324, 0x46452fc1, 0x81fd1843, 0xae6b1816, + 0x1816200a, 0x22188dfd, 0x82650002, 0x03082687, 0x00130007, 0x160f6b33, 0x87353421, 0x0755558f, 0x2007b345, 0x218f8332, 0x84181901, 0xc726127e, + 0x393b3c27, 0xe7181b1f, 0x022212fa, 0x8b181556, 0xaa210f69, 0x0ee81835, 0x0a274117, 0x80181720, 0x01201b2d, 0x3341a389, 0x5a012114, 0x0e6b4518, + 0x41d5fe21, 0x52181a39, 0xfc211153, 0x184141fa, 0xa3820020, 0x04826520, 0xcd020823, 0x20a39c00, 0x1f474103, 0x0f0f4618, 0x4341fb20, 0x036e2419, + 0x422d0704, 0x07840688, 0x4192fd21, 0x15232343, 0x6a003500, 0x4141179d, 0x18ee201e, 0x2410225b, 0x48142120, 0x1a4541ce, 0x41135d58, 0x87421845, + 0x20a38409, 0xa1661801, 0x1f414115, 0x20152d5c, 0x194741bd, 0x38215624, 0xea462137, 0x37212407, 0x42fd2138, 0x012d1a8b, 0x81ff7100, 0xdb023702, + 0x00002700, 0x056b5905, 0x1807f918, 0x06074d08, 0x10150607, 0x1b012215, 0x2b7f2a80, 0x15160a0a, 0x532c2122, 0x0e23451b, 0x09080b0b, 0x0a050605, + 0x7f450504, 0x3293b701, 0x2c0c1911, 0x15141f20, 0x12360a0a, 0x02030101, 0x0a050303, 0xfd191110, 0x0000aff3, 0x00000100, 0x580237ff, 0x79237382, + 0x4a170000, 0x27200647, 0x201cd75f, 0x05a15837, 0x8407b343, 0x08e17107, 0x210c7764, 0x58182227, 0x474c09bb, 0x05c95808, 0x0eff7c18, 0x2419f62e, + 0x0e0d3024, 0x0c0d0c0e, 0x06070c0b, 0x05231d82, 0x820c0606, 0x141a3e00, 0x0a0f0e14, 0x100f070b, 0x1f5f0b11, 0x08102366, 0x08050604, 0x0c0a0a08, + 0x261f1f18, 0x252f830c, 0x040d0d0d, 0xf1820504, 0x82060421, 0x08378206, 0x0d060732, 0x0a0a0b0a, 0x0e070908, 0x0505090a, 0x72040607, 0x06366d25, + 0x0509090a, 0x05040404, 0x09090706, 0x1b920a0b, 0x01020e0e, 0x03040302, 0x041a3306, 0x2b080682, 0x02020203, 0x09020104, 0x1a111109, 0x5b51241b, + 0x10323d5b, 0x13153468, 0x0e101013, 0x0b180b0e, 0x0201010c, 0x04030302, 0x03031a34, 0x03200782, 0x22060458, 0x82020301, 0x052c0842, 0x17160f07, + 0x2929251e, 0x2510321c, 0x1c363736, 0x1d131a1a, 0x17171a1b, 0x00001313, 0xff030002, 0x025402f3, 0x004100dc, 0x01000061, 0x5d08c94a, 0x16220c0d, + 0x0f831617, 0x410f494d, 0xcf520859, 0x34352506, 0x32012627, 0x7b052d73, 0xa35c1035, 0x07022706, 0x0103162d, 0x00820102, 0x06053f08, 0x10110a0b, + 0x0a090916, 0x08080f09, 0x3f7d3f3f, 0x1f1e2f2f, 0x100f0f10, 0x2f301e1f, 0x2a2b373f, 0x090a0b1e, 0x08080708, 0x0b0a1706, 0xeefe0304, 0x111c1c26, + 0x08080910, 0x1c111009, 0x0d83261c, 0x82081121, 0x82112000, 0xdc02260d, 0x0809080a, 0x2d1c8207, 0x0e13141b, 0x0207080e, 0x35290301, 0xff754135, + 0x11113410, 0x05040722, 0x01020303, 0x0e1a0d0d, 0x71fd0f0f, 0x19211111, 0x24148b24, 0x11112122, 0x2c008200, 0xff100002, 0x025902f3, 0x0043001b, + 0x09234153, 0x41161521, 0x23240923, 0x27262722, 0x0aedbb18, 0x5e172941, 0x0120074d, 0x0f756918, 0x162d0c3f, 0x01020203, 0x06050101, 0x11100b0a, + 0x04040a16, 0x06040403, 0x0f100302, 0x2d2c1f1f, 0x05257a3a, 0x0d860f20, 0x33472b08, 0x090a1e32, 0x0b16090a, 0xfe04040b, 0x4723245e, 0x23232447, + 0x23474724, 0x0a170224, 0x08070909, 0x1a080908, 0x0e0e1414, 0x53820707, 0x19191627, 0x3333431c, 0x10237624, 0x351a1b2e, 0x0d020304, 0x0e0f1a0d, + 0x65fffe0f, 0x0a986918, 0x02000238, 0x66020000, 0x2900bd02, 0x00003f00, 0x22351033, 0x22150607, 0x6f6c3423, 0x87d81809, 0x0bad6f0f, 0x830b6363, + 0x1a8e3417, 0x16420d0d, 0x10211111, 0x92141312, 0x2f2f3f48, 0x82102021, 0x20310800, 0x3f302f20, 0x4c4c1d58, 0x1a24274e, 0x0a14141b, 0x130b0a0a, + 0x241b1b13, 0xa0011d58, 0x311819d0, 0x1b261224, 0x04070f1b, 0x1b0d0d03, 0x3427271a, 0x470d1934, 0x09093b09, 0x18181211, 0x18191e20, 0x09091111, + 0x010000c6, 0xf3ff0400, 0xdd026402, 0xa5418300, 0x41152007, 0x27251293, 0x07141514, 0x0dab5b14, 0x8c180720, 0x096c0c87, 0x07055c0c, 0x6106bf42, + 0x332005a9, 0x4206e542, 0x058505eb, 0x29833520, 0x43151421, 0x02220a0b, 0xd5412c18, 0x0b052807, 0x1710100b, 0x82070606, 0x07073d02, 0x02020201, + 0x0d080403, 0x1311100d, 0x18161412, 0x191b1918, 0x13151619, 0x070a0f12, 0x042b2182, 0x03030405, 0x02010203, 0x82194d01, 0x04042904, 0x0a0b0606, + 0x12120f0f, 0x10242283, 0x060c0c10, 0x02211b82, 0x36008501, 0x0909194b, 0x0b160709, 0x0204040b, 0x08080add, 0x08090708, 0x41151a08, 0x022007fb, + 0xc8216982, 0x0f375065, 0x22446c52, 0x4304172f, 0x0e2c0644, 0x13000100, 0x5502f3ff, 0x4d001702, 0x22152143, 0x18272627, 0x570aeb6a, 0x45411ecb, + 0x4308200d, 0x0b2e091b, 0x1610110a, 0x110f100f, 0x03021c37, 0x0d500202, 0x17463506, 0x0d0d0706, 0x211b1615, 0x10111919, 0x17450909, 0x0a0b0a0e, + 0x43051241, 0x05250f0e, 0xe5fe0904, 0x0ee6575e, 0x240e6e5b, 0x03061e3b, 0x05154303, 0x5c180020, 0x15220c23, 0x7f605d00, 0x7a132017, 0xc3711205, + 0x0cf56a08, 0x13676018, 0x0a215c18, 0xb7603220, 0x18de2014, 0x483bdb59, 0x5020128d, 0x3ae15918, 0x00820020, 0x61180320, 0x59220a9b, 0x15417500, + 0xe1591818, 0x731e205f, 0x1128050b, 0x10111c1c, 0x2e111d1d, 0x20052365, 0xeb5918e7, 0xff631854, 0xf3591810, 0x00043056, 0x02dfff04, 0x00680358, + 0x0047000b, 0x55890065, 0x03240db1, 0x27262726, 0x0a35bc18, 0x37343523, 0xffed1836, 0x1823201f, 0x2007ebed, 0x977b1836, 0x05bb1807, 0x11d94411, + 0x49082364, 0xc6180a11, 0xd3200bc9, 0x0bf9ba18, 0x0302052b, 0x3b7c3e3f, 0x121c2b2b, 0xe1ba1813, 0x0b200809, 0x05060708, 0x10100203, 0x2f301f1e, + 0x2c2d3b40, 0x1514121f, 0x0654a865, 0x0e0e0a0a, 0x15171312, 0x32058a58, 0x07060a07, 0x02010404, 0x11120201, 0x262d1f1f, 0x18111c1b, 0x2509c5ba, + 0x03010202, 0xba181521, 0xaf7308c3, 0xf2fc3709, 0x060a0b06, 0x16262516, 0x1f181711, 0x2521221f, 0x135c5cb6, 0xba182614, 0x27080bb2, 0x1e191913, + 0x2723221e, 0x2d44445b, 0x1216162e, 0x1b172613, 0x71e1ec1b, 0x0a0e0e13, 0x0405060a, 0x0d0a0904, 0x1913100d, 0x252d3f82, 0x19232b25, 0x14275f18, + 0x21111114, 0x2b708210, 0x2c24231a, 0x10131418, 0x0a0e0d10, 0x0a87ba18, 0x00820020, 0x18000430, 0x4b02d3ff, 0x13001203, 0x6f004b00, 0xa3418f00, + 0x0f4f7906, 0x730aab41, 0x49180ca9, 0xa3460b7b, 0x258d180f, 0x0bd7731e, 0x4609015d, 0xa94106b3, 0x1993180a, 0x18bb2013, 0x2d07258d, 0x0f0a0a14, + 0x2d1f1f0f, 0x27323a2d, 0x8d181d28, 0x152d0b11, 0x0f100b0b, 0x2c2d1e1f, 0x2828323b, 0x058d181c, 0x0a0a390f, 0x0e0d0c0b, 0x1b23100e, 0x0913121b, + 0x0201010a, 0x21020301, 0x20191912, 0x0a018d18, 0x03030223, 0x398d181e, 0x12087409, 0x0b077236, 0x1e11070b, 0x2c23121d, 0x3343372d, 0x12232333, + 0x1b0c0d12, 0x0bf28c18, 0x2c2d1f2d, 0x3334443a, 0x11112324, 0x181c0d0e, 0x0810e78c, 0x06080921, 0x0c030205, 0x231a190d, 0x0d0d2e23, 0x0f0e0e0e, + 0x0b164a0e, 0x1a0e0d0b, 0x3025241a, 0x820d0e0e, 0x0e0d2114, 0x0adf8c18, 0x0200002c, 0x01ff4600, 0xcb022502, 0x08196300, 0x0d711017, 0x171d6c08, + 0x77083d58, 0xbf761697, 0x0b376615, 0x76e30121, 0xfe2256c0, 0xbc7908c8, 0x38112207, 0x5ac27627, 0x1fc0fe3a, 0x1f1f3332, 0x001f3233, 0xff6a0002, + 0x02030201, 0x0061001b, 0x2500006d, 0x42109d4d, 0x956f1099, 0x0c0d430e, 0x4122b776, 0xc8200c49, 0x2153b076, 0x4641e7fe, 0x171f210a, 0x2154aa76, + 0x4141ccfe, 0x0b976a08, 0x0c823720, 0x4d0a936a, 0x6318086b, 0x8d450c5b, 0x08856a08, 0x15143339, 0x06670122, 0x0a0a0f03, 0x03040606, 0x163c1e1d, + 0x07161615, 0x820a0809, 0x21092c00, 0x0302100f, 0x09090504, 0x6708190c, 0x023305f7, 0x9b2dfe6e, 0x0c0d0d0f, 0x0d0c0c0d, 0x0314142a, 0x82290503, + 0x02032604, 0x0a010201, 0x2638820a, 0x0c0a0a09, 0x6901100d, 0x002b0506, 0xff420001, 0x0204024e, 0x825300bd, 0x1822209f, 0x6a098da4, 0x5f6a1163, + 0x9157181d, 0x05c7500c, 0x32151426, 0x04021433, 0x2b0afc68, 0x090c2041, 0x03050608, 0x3c1e1e03, 0x1620c582, 0x2e06aa5a, 0x0f102009, 0x05050102, + 0x210b0707, 0x6910191a, 0x01210c3a, 0x091069cb, 0xd3821120, 0x0b0b0b24, 0xd7860c0c, 0x436b1520, 0x0b0a2306, 0x4a820715, 0x0b0c0828, 0x0909040f, + 0x5369130f, 0x8200200f, 0x940029da, 0xd4015102, 0x15000203, 0x56180c82, 0x2632074f, 0x06070627, 0x36232207, 0x32373637, 0x27175901, 0x76581726, + 0x182e2809, 0x17262618, 0x51020338, 0x4e820f43, 0x8b010021, 0x4f13204f, 0x17460551, 0x23222509, 0x94262726, 0x260fd66d, 0x26171931, 0x51020326, + 0x3826088e, 0x37212137, 0x4b820038, 0x6d02982a, 0xf402d101, 0x00001f00, 0x68184b86, 0x3964105b, 0x27982307, 0x46180314, 0x142c1362, 0x241c1c14, + 0x02272848, 0x0d0e12f4, 0x2b075361, 0x22120e0d, 0x11111a19, 0x22210808, 0x01296782, 0x017a0201, 0x00d90267, 0x180c8217, 0x211665f1, 0x7c181001, + 0x02210e55, 0xfb7018d9, 0x28ff830f, 0x02ab0002, 0x03bd014b, 0x20b3824d, 0x0551413f, 0x180c4d50, 0x200e2746, 0x0a4f7607, 0x23131b4b, 0x0a139601, + 0x13290082, 0x1d181914, 0x1418191c, 0x390c8214, 0x1814140a, 0x181d1c19, 0x060b1819, 0x0b060505, 0x100f0e0a, 0x0b0c0d10, 0x0082060b, 0x0d0b0b31, + 0x0e10100d, 0x1228030e, 0x1b1b1718, 0x18121717, 0x211257ac, 0xac180aa0, 0x0a211349, 0x824e830a, 0x000126c4, 0x0147ffd2, 0x2309828c, 0x21000033, + 0x086f5618, 0x4d077b47, 0x142608ff, 0x06070615, 0x7b180623, 0x012b1193, 0x0c142808, 0x06050808, 0x69030203, 0x09230538, 0x82070808, 0x09072102, + 0x08370083, 0x171f0608, 0x070f0d17, 0x07030307, 0x0f0a0a07, 0x0a0a0c0c, 0x49080909, 0x032a052f, 0x02010101, 0x29040203, 0x06830215, 0x0a0a0525, + 0x82171010, 0x0d0d30b0, 0x00000e0d, 0x028f0001, 0x02d90167, 0x824f00ec, 0x0acd5e0c, 0x1808d349, 0x791cf7b3, 0x4d690c87, 0x32012b10, 0x0e040307, + 0x04050406, 0x9d180404, 0x01290873, 0x0707152a, 0x12110d0d, 0x21bb8217, 0xca6a0808, 0x59032006, 0x29830646, 0x07070a2b, 0x03020504, 0x06061529, + 0x3b27890e, 0x06840209, 0x050d0403, 0x02020304, 0x05040101, 0x0d0e0908, 0x18182014, 0x09091112, 0x0323d982, 0x83080506, 0x8202201f, 0x82012000, + 0x84248220, 0x130e2123, 0x01212387, 0x42238204, 0xac2a0553, 0x0b025102, 0x0b000203, 0xf5821700, 0x200a9b43, 0x380b8a33, 0x24146001, 0x172e1423, + 0x111e1e12, 0x2717c040, 0x162d1727, 0x13202013, 0x05a94343, 0x38372123, 0x07e45b21, 0xfe254482, 0xff510223, 0x20538212, 0xe1941813, 0xc6fe2515, + 0x1d1e1e14, 0x0bbdba18, 0x39111924, 0xc3575102, 0x0c0f2905, 0x110f0f0c, 0x1521211f, 0x01229f83, 0x4b8285fe, 0x14197520, 0x5818086f, 0xfe2310a9, + 0x7d1a33d2, 0x4328077a, 0x0e0e0b21, 0x1e1e1c10, 0x002e4b90, 0x0227fe01, 0x0271ff67, 0x003b00ec, 0xb9600300, 0x0b1f6606, 0xdb410720, 0x086d4714, + 0x3408cf41, 0x111211f1, 0x09090611, 0x09080a05, 0x08070907, 0x02020504, 0x089e4101, 0x240ad36a, 0x07070a06, 0x411c8205, 0x022c07e2, 0x0e080767, + 0x05080805, 0x04040509, 0x2c06b141, 0x11111919, 0x07080908, 0x0403060e, 0x2317870d, 0x1820130e, 0x09211782, 0x2bff8509, 0xff530264, 0x002f0333, + 0x01000029, 0x51092349, 0xfd180767, 0x69180c69, 0x2c0808eb, 0x1664fe34, 0x3a171516, 0x05021e1d, 0x0b0a0a04, 0x12380d0b, 0x0c0e0e11, 0x10030306, + 0x14151e0f, 0x24031113, 0x14030305, 0x02032814, 0x3617820e, 0x080a0a0c, 0x11220a1f, 0x0c080706, 0x0d080805, 0x040b0b16, 0x822e0803, 0xfe012d80, + 0xfe3dff98, 0x009effff, 0x05000007, 0x2d050556, 0x4efffe14, 0xc31a4d19, 0x00481849, 0xea180001, 0x13200a2f, 0x21109d41, 0x2d4b2207, 0x109e4113, + 0x03001530, 0x70027900, 0x7a03e201, 0x2b001300, 0xf54b4300, 0x22072115, 0x15a90d19, 0x176b9118, 0x445af320, 0x0e0a2d09, 0x1e1d100e, 0x3639141e, + 0x04071830, 0x07240082, 0x03081830, 0xe5200082, 0x0e2bdb18, 0x18ca0221, 0x36074745, 0x110f0f0c, 0x1521201f, 0x0703035a, 0x0406172d, 0x06040303, + 0x8207162e, 0x200f8e33, 0x28008200, 0x00e2ff03, 0x02560200, 0x22bf82bd, 0x82450033, 0x05e146bf, 0x200cb74c, 0x18138b13, 0x270d9d43, 0x07062322, + 0x33323706, 0x4c077544, 0x2f20066f, 0x2608dc42, 0x0b21420a, 0x820f0e0e, 0x463822c3, 0xb38a1823, 0x95da1811, 0x1845200a, 0x2a10b48a, 0x20160d02, + 0x10102020, 0x830b0b0f, 0x202123d3, 0x8a18ddfd, 0x23270fa2, 0x22223939, 0x18e03939, 0x220fa18a, 0x828fff02, 0x846820d7, 0x002b23d7, 0xe1410300, + 0xdf781812, 0x43712017, 0xb9820696, 0x3107ee43, 0x01010139, 0x00ff6f4c, 0xf552f556, 0x57080152, 0x9a89adfe, 0x08be4618, 0x7618f320, 0x14210bf7, + 0x217e8200, 0x04826cff, 0x839e6020, 0x14a96918, 0x1a10942a, 0x0d0d191a, 0x2142090c, 0x08399818, 0x4d01012c, 0x4c45d019, 0xcf194c19, 0x7f964c46, + 0x1948d721, 0x23091a26, 0x90ff0200, 0x44207f82, 0x61187f9c, 0x7020168f, 0x41090341, 0x142a06bd, 0x75020139, 0x01277527, 0x06836836, 0x41c9fe21, + 0x1622109c, 0x6118f3fd, 0x03311193, 0xf3ffa7ff, 0xcb024c02, 0x2f001b00, 0x00004f00, 0xe7511801, 0x4125201a, 0xdd4813a5, 0x1343580a, 0x3f4c0232, + 0x2f3f7d3e, 0x101f1e30, 0x1f10100f, 0x3f2f2f1e, 0x0f2d0d84, 0x115bfd10, 0x0d1a191a, 0x42090c0c, 0x2bc48222, 0x1e1d1d10, 0x2a013a14, 0x261b1c11, + 0x290e3758, 0x11111c1b, 0x09080809, 0x1d585e01, 0x5c452407, 0x1844455c, 0x20090652, 0x0e874253, 0x75fe1622, 0x1e175218, 0x16ff022f, 0x64020000, + 0x7900c302, 0x00008d00, 0x85531821, 0x0e9f6808, 0x2223262b, 0x06230623, 0x34072207, 0x05254535, 0x64051f4a, 0x36230f2d, 0x82333237, 0x05554e01, + 0x15141523, 0x0bb15606, 0x08754518, 0x820ea95a, 0x01222127, 0x3a135341, 0x04020203, 0x09060605, 0x0b0a0a07, 0x0d0b0b0a, 0x0c090906, 0x0a0b0b0b, + 0x84050404, 0x82082000, 0x09073113, 0x090a0a08, 0x1b220809, 0x1015161b, 0x12100a0f, 0x3505306e, 0x04040406, 0x11140408, 0x080f1011, 0x02010107, + 0x06040302, 0x00830705, 0x0d0c0c29, 0x06060c0b, 0x820d0e03, 0x2039824c, 0x250b8207, 0x4c020204, 0xcd42f9fd, 0x66cb2712, 0x18161616, 0xd1821718, + 0x10141327, 0x060b0b10, 0x06a14b03, 0x01010128, 0x01031a35, 0x02820102, 0x10060239, 0x2419190f, 0x25303225, 0x10191925, 0x01020610, 0x0b0b0505, + 0x7f131010, 0x0522051b, 0x64820907, 0x0830ce84, 0x100c0b09, 0x120d0d09, 0x16141312, 0x16171615, 0x13210482, 0x122843e5, 0xff02002d, 0x020000a1, + 0x00ae025a, 0x446f0013, 0x1322151b, 0xd3443534, 0x10e94f08, 0x4a069b41, 0x072007c3, 0x5d05255c, 0xa542088f, 0x05b74113, 0x14240582, 0x115f2215, + 0x08fdaf18, 0x0798ab18, 0x873a5608, 0x161e2952, 0x070e0e16, 0x10080807, 0x1d181710, 0x2823231e, 0x1e232328, 0x1017171e, 0x07080910, 0x160e0e07, + 0x1f5d1f16, 0x171d3aad, 0x09111117, 0x160b0c09, 0x261f1e17, 0x161f1e27, 0x040b0c16, 0x0a080704, 0x110f0e0a, 0x01ae1511, 0x202115fe, 0x0f0f111f, + 0x3307870c, 0x143d02fe, 0x2220201f, 0x2d272622, 0x252a2b31, 0x131c1b24, 0x0805434b, 0x1b1c1321, 0x2b2a2524, 0x27272b31, 0x21202222, 0x36143d1f, + 0x1b1c111b, 0x2d2c2728, 0x2c2c3932, 0x820f1f1f, 0x1f1f3c00, 0x20392c2c, 0x1d1c1f1e, 0x16171919, 0x3d0b1111, 0x00040014, 0x01fcff79, 0x467903e7, + 0x672006f7, 0x7745f946, 0x4f18124b, 0xa74a0877, 0x14332105, 0x3c331d47, 0x2d132422, 0x15152021, 0x1a4f0a0a, 0x02023295, 0x06070403, 0x0f0e0a09, + 0x020b2111, 0x0f3847c9, 0x1d825c20, 0x1c029818, 0x0b8ffd3b, 0x2517160c, 0x44cc3224, 0x73e51132, 0x0c121117, 0x0408080d, 0x38020205, 0x65008200, + 0x022806e3, 0x001f00bd, 0x33000031, 0x18110368, 0x191e45e7, 0x24608330, 0x02000053, 0x249f8238, 0x0033001d, 0x18a18249, 0x420fed86, 0x23200ae1, + 0x2c733019, 0x93537308, 0x2c2c3a4a, 0x10101f1e, 0x24412121, 0x16151d1c, 0x42420a0a, 0x4f2ea684, 0x1b1a2427, 0x08081011, 0x11100807, 0x58261a1a, + 0x2c28501e, 0x1212201f, 0x090a0a0a, 0x1f1f1414, 0x021e5a2a, 0x0c0baf0e, 0x22211717, 0x2424402c, 0x0f0e0609, 0x1f1f1819, 0x302f6027, 0x06069d01, + 0x15150d0d, 0x15141b1c, 0x06060c0b, 0x077dfe9f, 0x180f0e07, 0x1a222118, 0x54821019, 0x0100c123, 0x73601800, 0x33003409, 0x33203510, 0x23201514, + 0x6c221510, 0xfe735a01, 0x824c5af2, 0x143b245c, 0x419b2dfe, 0x13220c9f, 0x9f412500, 0x27202114, 0x4110d148, 0xfe331293, 0x6bd7104d, 0x1c1e1e13, + 0x0b0e0d10, 0x1d1d1e13, 0x480e0e0f, 0x502f0f9f, 0x5f646341, 0x232e2e34, 0x60636341, 0x822e2f33, 0x28ab827e, 0x02000062, 0x00bd0227, 0x877d8217, + 0x791420ab, 0xbb84083f, 0x18016221, 0x210ea0e0, 0x5218af0e, 0x142108eb, 0x20438200, 0x19438237, 0x205f9b22, 0x9b2e1945, 0x5c03203c, 0x8e2b0603, + 0x7f004f00, 0x00008700, 0x5e373413, 0x7a18082f, 0xd7460945, 0x07254509, 0x69181520, 0xcf500e2d, 0x09534f05, 0x20074347, 0x79461805, 0x08ef4e0e, + 0x06070622, 0x28131557, 0x32353425, 0x22151433, 0x05444613, 0x140f3308, 0x1b181814, 0x1d1c1b19, 0x03040204, 0x1a1d1a1b, 0x1316171a, 0x0b0e0f13, + 0x05050609, 0x100b0c06, 0x1814150f, 0x1a1a1b17, 0x03041c1a, 0x181c0303, 0x21821b1c, 0x0f131429, 0x050a0b0f, 0x82c70106, 0x04052404, 0x820f0a0a, + 0x1b1b3148, 0x1b1a2121, 0x100f1514, 0x05040a0a, 0x0a0a0505, 0x2c083c82, 0x1f1a1a15, 0x151a1a20, 0xfe0f1014, 0xaf3ab0ef, 0x01023701, 0x20230102, + 0x1b1f1e21, 0x1218181b, 0x060c0d13, 0x0d060506, 0x1712130d, 0x34868217, 0x201e1e1e, 0x04050204, 0x1f211d20, 0x171b1c1e, 0x0d111117, 0x2021850b, + 0x08218312, 0x1d1e1a24, 0x1c511f1e, 0x20221f1f, 0x1d1c1e1e, 0x12101716, 0x09080809, 0x16171112, 0x1e1e1c1d, 0x1f1f2122, 0x35821c1b, 0x82081021, + 0x10112915, 0x3b6f1617, 0x00143b14, 0x45233019, 0x7fa32f19, 0x00001226, 0xbd025602, 0x6d16b143, 0xb1431243, 0x22462d12, 0x21222217, 0x0c101012, + 0x20232216, 0x4e200783, 0x270fb043, 0x6e72724b, 0x2835353b, 0x6d2a0782, 0x2836353b, 0x01000000, 0x7b822b00, 0x7b823d20, 0x00003123, 0xe95d1833, + 0x6d511807, 0x3237250a, 0x22151033, 0x17f92f19, 0x5a2b5508, 0x0b0b092d, 0x1818170c, 0x1818100f, 0x0c0b0c17, 0x46226608, 0x0b0c0818, 0x1918180d, + 0x101a3210, 0x0d181819, 0x46090c0b, 0x17af0e02, 0x40221e1f, 0x2b2b4242, 0x22404242, 0xfd171f1e, 0x9d01aff2, 0x201f19cf, 0x44444124, 0x44442d2d, + 0x1f202441, 0x9b2ffe19, 0x46209784, 0x23209782, 0x1f209782, 0x6118978e, 0x611812d1, 0x611817c5, 0x63821bb9, 0x45000322, 0x28060344, 0x000f0007, + 0x13000017, 0x055b4534, 0x4b430320, 0x2f078206, 0x15143320, 0x67014520, 0x1298fe78, 0xaacf45cf, 0x022d0984, 0x3b143b6e, 0x3ce0fe14, 0xfe143c14, + 0x2d0583b2, 0x3a000200, 0x2e02f3ff, 0x1b00cb02, 0x094c4b00, 0x4b01201d, 0x29440af5, 0x08ef5607, 0x7e182620, 0x02221165, 0x5d183f2e, 0xc42417fd, + 0x1411100d, 0x0e0ad718, 0x0502032d, 0x07070604, 0x261c1c11, 0x4b1b1c26, 0x112305fc, 0x4c0c0b08, 0x5e180900, 0x96240f07, 0x05040409, 0x0a99d618, + 0x2a22233c, 0x1a22222a, 0x1015141b, 0x11101121, 0x38212111, 0x374d4c37, 0x0d102137, 0x3219000d, 0x242508d3, 0x0f00bd02, 0x058f4600, 0x21052142, + 0x07822322, 0x67014539, 0xcf1a4c78, 0x0e024c45, 0xaff2fdaf, 0xfe9cd201, 0x00009b2d, 0x82560002, 0x822e2004, 0x00112233, 0x09954727, 0x1805fd57, + 0x63096356, 0x56320f4b, 0x3f7f4991, 0x7f3f4040, 0x4c4c1e57, 0x1c23274e, 0xdc49141b, 0x1b142505, 0x1e57231c, 0x34366382, 0x35696934, 0x0146d434, + 0x11080968, 0x20191911, 0x1119181f, 0x23630811, 0x823c2005, 0x82362073, 0x002f2373, 0xc34a3300, 0x07155e08, 0xed412720, 0x48232006, 0x17200611, + 0x3b07614c, 0x15143320, 0x291c3c20, 0x1316282a, 0x130f0f14, 0x29281614, 0x7c011c2a, 0x85f5fe7e, 0x1d870d87, 0x642c0126, 0x1b3585fe, 0x2d05236f, + 0x17121217, 0x32301a17, 0x143b2132, 0x0b87143b, 0x3c221b87, 0x2d190014, 0x11203793, 0x5c24c782, 0x7900c302, 0x3420c784, 0x850f674d, 0x366d4d0f, + 0x4d0c1d64, 0xfc2b1b6d, 0x05040302, 0x08090606, 0x820b0909, 0x4d0c2000, 0x052f0858, 0x04060505, 0x0b090604, 0x09080d0a, 0x820a0a08, 0x1b223104, + 0x1015161c, 0x120f0a0f, 0x19151612, 0x05051c18, 0x2905584d, 0x07100f12, 0x01010107, 0x33820302, 0x0806073c, 0x0b0d0707, 0x070c0b0c, 0x0c0f0207, + 0x090b0b0c, 0x06070808, 0x03030406, 0x434d4c02, 0x00003767, 0x3b000300, 0x2d020000, 0x4b00bd02, 0x73005d00, 0x34330000, 0x03823235, 0x180a6d56, + 0x180cb9be, 0x2109b976, 0x10192322, 0xd95e09ad, 0x0607210a, 0xf3480182, 0x34372206, 0x06574235, 0x2007b547, 0x216d1813, 0x0ae34709, 0x1237b83f, + 0x161a1a1d, 0x0c121117, 0x0707060c, 0x120c0c06, 0x1a161711, 0x12371d1a, 0x13363eba, 0x2d1b821e, 0x0c111216, 0x0606050e, 0x110c0d06, 0x1b821612, + 0x1b821e20, 0x0f130b38, 0x09110a0e, 0x11090808, 0x790f0e0a, 0x0709090b, 0x05050608, 0x00820811, 0x0b112708, 0x143c0e0f, 0x07031224, 0x110b0c07, + 0x1e171711, 0x1e25251d, 0x1117171d, 0x070b0c11, 0x0e2a0307, 0x143b143b, 0x1f821325, 0x830c0b21, 0x1e1d251f, 0x1e1d2525, 0x0b211f83, 0x3e1f820c, + 0x143c0d29, 0x0458b2d9, 0x100a0606, 0x25251b1b, 0x0a101a1a, 0x06010707, 0x030259b1, 0x82040304, 0x1a103700, 0x1a26251a, 0x060a101b, 0x01000006, + 0x00000900, 0xbd025f02, 0x794a4700, 0x1b37740a, 0x20061941, 0x0d775307, 0x0a359e18, 0x09220722, 0x07af2d19, 0x12130e29, 0x27282615, 0x5425481b, + 0x2d190737, 0x153434b3, 0x3a201c1d, 0x11283d3c, 0x2e1a1617, 0x21213031, 0x192f3030, 0x2820f182, 0x23b72d19, 0xdf823a20, 0xdf822d20, 0x23424320, + 0x0df1750f, 0xcf831720, 0x2005a746, 0x05e14536, 0x07201f87, 0x1b42f185, 0xb7550806, 0x222c1238, 0x0f1f1823, 0x021a4c10, 0x07050503, 0x0f0b0a06, + 0x194c120f, 0x0c0e0f13, 0x4c0a0a12, 0x1e100f19, 0x2c232219, 0x3cba1238, 0x07214314, 0x2d241516, 0x785c4545, 0x29356b28, 0x1b1a2221, 0x15101516, + 0x01080e0f, 0xdcfe6d49, 0x0f0e0892, 0x38372115, 0x2f1d834c, 0x2d45455c, 0x07161524, 0x143c194b, 0x25000100, 0x4424b782, 0x5f00ae02, 0x7518b786, + 0x9d850897, 0x4f0bdb6a, 0x6b441ff9, 0x09a54605, 0x0ccb5018, 0x15144008, 0x29522522, 0x0d17161f, 0x1207070e, 0x30242412, 0x1b203c30, 0x1418181c, + 0x12241215, 0x0e070611, 0x1e16160f, 0x3aae1f5d, 0x1117171e, 0x03080911, 0x08060503, 0x0d0b0c08, 0x11100f0d, 0x7d151312, 0x2a0805aa, 0x0c0b160a, + 0x11110809, 0xad1d1718, 0x211f143d, 0x27212221, 0x39492e26, 0x162b2c3a, 0x0a060515, 0x1510110b, 0x493a3a2b, 0x8227262e, 0x05d94f1a, 0x1c123208, + 0x2c26271d, 0x181b322d, 0x13161619, 0x0c0e1013, 0x0408090b, 0x08050404, 0x0e0b0b09, 0x392b2b1f, 0x262c2d32, 0x121c1c28, 0x0000143d, 0x65000300, + 0xd3751800, 0x72472009, 0x01203193, 0x72165d54, 0xfe281f81, 0x752775a4, 0x67370127, 0xfe210683, 0x236a72ca, 0x220f7954, 0x82110003, 0x035c21bb, + 0x20054f73, 0x20bbb1a9, 0x4fb15303, 0x41284346, 0xc5201f1d, 0x416c6346, 0x8746237c, 0xff232a6c, 0x034a02f5, 0x00130012, 0x1765655f, 0x58207b69, + 0x59450cdd, 0x17162208, 0x06c96016, 0x2007675b, 0x81951806, 0x0815490d, 0x180a814a, 0x5a0fc361, 0x62081337, 0x1a191163, 0x28283322, 0x0f0f1d1d, + 0x0f100808, 0x1b191415, 0x221e1c1b, 0x17171d1c, 0x0c070f0f, 0x37090e0f, 0x0909061b, 0x1313120a, 0x0506040c, 0x06050304, 0x09080a0a, 0x240b2108, + 0x14141713, 0x0a0a100f, 0x0e0e0c04, 0x0e0f0db2, 0x1a19200f, 0x09090811, 0x07070405, 0x0b0a0604, 0x10100e0f, 0x820b0c10, 0x20318401, 0x263c8208, + 0x0a040402, 0x650b0b09, 0xb22f1267, 0x1107080f, 0x32242411, 0x27304032, 0x831e1f28, 0x0808227e, 0x3377820a, 0x23261c1b, 0x131a2626, 0x331b1918, + 0x14233434, 0x0b132020, 0x47080083, 0x12380504, 0x0e0f0708, 0x19141212, 0x0b2f1414, 0x191a0606, 0x18181532, 0x22221410, 0x15161f14, 0x06070d0d, + 0x07060304, 0x0f0d0a0a, 0x14141211, 0x21171615, 0x16171b1b, 0x00001010, 0xff550002, 0x031402f6, 0x00130013, 0x22df5a18, 0x640f8f7d, 0x4f451911, + 0x07b1410b, 0x5f058741, 0x14240c8f, 0x06070615, 0x08138f41, 0x1716b555, 0x303e1817, 0x11232230, 0x13090911, 0x20191a13, 0x1017171e, 0x10080810, + 0x291f1f0f, 0x2e273529, 0x181a342f, 0x14161519, 0x1b231213, 0x0912131b, 0x11090809, 0x221b1a12, 0x1a36153e, 0x151d1d26, 0x0c0b0a15, 0x2116160b, + 0x2d312b22, 0x1818272e, 0x18620217, 0x080936d8, 0x20101024, 0xfd162021, 0x0102039a, 0x15160a0b, 0x1b251e1e, 0x11111717, 0x06060b0b, 0x0f10090a, + 0x20161313, 0x54821819, 0x05060a3e, 0x061a340c, 0x03030505, 0x06050201, 0x0d0d0a0a, 0x0d0d1010, 0x06050a0a, 0x07061132, 0x11280d82, 0x11111615, + 0x06060c0c, 0x36259a82, 0x0505071b, 0x2a008200, 0xff610002, 0x030d0237, 0x18130013, 0x21178370, 0x85561013, 0x22152111, 0x12a56c18, 0x2114e75c, + 0x6b1807b0, 0x45201bfc, 0xfc24ea91, 0xb06001d5, 0x1c046c18, 0x8474fe2c, 0x9b000200, 0xe701fcff, 0xb7820603, 0x2f563f20, 0x09ff5515, 0x19d1c018, + 0xa7431720, 0x09ee2106, 0x0b746218, 0x0e101c37, 0xe6390b0e, 0x14181324, 0x0d101014, 0x080a090d, 0x02050607, 0x11ef5503, 0x205d5620, 0x071e5707, + 0x03a6fd30, 0x08060603, 0x100b0b08, 0x1513120f, 0xd6551816, 0x00042612, 0x02fdff1a, 0x08e75d34, 0xbf959720, 0x202fe95d, 0x0c256e03, 0x35263522, + 0x5206a95e, 0x372113bd, 0x18018236, 0x200c1b66, 0x082b5a27, 0x82089148, 0x331f574f, 0x1c19232d, 0x212d201d, 0x0a151521, 0x574e010a, 0x1a3c0d22, + 0x10101514, 0x090a0d0d, 0x01020605, 0x09080404, 0x3e17100f, 0x0e0e121f, 0x05060a0b, 0x0b250f83, 0x1510100c, 0x32805e15, 0x0ea8fd33, 0x0c0b0706, + 0x24241717, 0x4b4c4332, 0xe2103233, 0x0a4c5772, 0x08082008, 0x15141110, 0x1c1b1b1a, 0x0304031d, 0x16050803, 0x191a1718, 0x151b1a1a, 0x1c1c1819, + 0x82242020, 0x1a1b270a, 0x15161918, 0x17431212, 0xff232a05, 0x024a02f5, 0x004b001b, 0x0d83687b, 0x4614c359, 0x01215a05, 0x74f24564, 0xdf451320, + 0xff4c2e6e, 0x02310237, 0x004900e2, 0x1700009e, 0x14654110, 0x860f2d5b, 0x875c180f, 0x06f14311, 0x22151423, 0x0c314e13, 0x0fb3e018, 0x23222324, + 0x27430722, 0x33302105, 0x32250185, 0x33013a33, 0x0d687616, 0x360c2463, 0x4c060706, 0x100f0807, 0x19181413, 0x121b1919, 0x14131313, 0x45101212, + 0x0534056c, 0x0a0b0506, 0x15151011, 0x10111213, 0x08090c0c, 0x07070405, 0x163b0f82, 0x1f1f1a1c, 0x12121224, 0x13141111, 0x07464617, 0x0d0d0a0a, + 0x1709160f, 0x8210110b, 0x0e5a083b, 0x0a0c0d0f, 0x31050607, 0x060c6331, 0x05040405, 0x080b0808, 0x02020305, 0x06010201, 0x18102619, 0x05050c0a, + 0x0c0b0a0a, 0x0d0d0e0f, 0x0f0f100d, 0x0c0c0e0f, 0x0404090a, 0xf1e301c9, 0x181e1f26, 0x0c111118, 0x0305060b, 0x09050503, 0x0f0b0c08, 0x1513120f, + 0x181a1916, 0x19821718, 0x08050b3a, 0x110e0e09, 0x14141311, 0x1b1e1515, 0x1217171a, 0x070d0d13, 0x05020207, 0x33086882, 0x023baf0d, 0x0b78efd1, + 0x09080a0a, 0x06030a07, 0x03030201, 0x0a0a0606, 0x11160a0e, 0x20204016, 0x011b3501, 0x140e0c08, 0x141d1817, 0x0c0b1010, 0x05050808, 0x5a662282, + 0x120e2f05, 0x00010013, 0x0237ff21, 0x000e0248, 0x20190031, 0x23200e75, 0x20055b41, 0x5b901832, 0x0d29430a, 0x22151428, 0x1c131601, 0xd7821b1b, + 0x110c0a3f, 0x06121811, 0x21300c17, 0x23201021, 0x1e141824, 0x0e101d1e, 0x20400a0e, 0x2527271a, 0x08b48214, 0x86c9482b, 0x48483043, 0x21222646, + 0x0f0f1e1a, 0x15141237, 0x5a5a502a, 0x4a4b313d, 0x23232648, 0x6061401a, 0x2d2d325e, 0x00329723, 0x432d1900, 0x00e12408, 0x437c006c, 0x894919c3, + 0x614b180b, 0x054b580b, 0x63423320, 0x15142905, 0x27302726, 0x30232226, 0x0de41819, 0x830b3e48, 0x182e83e4, 0x0813986d, 0x1ee70121, 0x3a3b2d2d, + 0x1f1f2c2d, 0x04040f0f, 0x0b0b0808, 0x0909070f, 0x0303020c, 0x04040504, 0x82060805, 0x02022a05, 0x1d1d0f0f, 0x09352929, 0x2f00820a, 0x14060807, + 0x100e1515, 0x141d2612, 0x0908140a, 0x083d0184, 0x02050808, 0x03070a03, 0x04010203, 0x0a080704, 0x19101007, 0x0f3c3c78, 0x24a0fe0f, 0xd4711824, + 0x23382209, 0x2c008211, 0x34342423, 0x1e1f2343, 0x15161919, 0x213f8310, 0x70830201, 0x84040321, 0x0a093a4c, 0x1a1a200a, 0x09091413, 0x02010101, + 0x03050504, 0x05051b36, 0x01010608, 0x2f0d8403, 0x06070101, 0x080b0809, 0x05060606, 0x03040505, 0x45263b82, 0x34448745, 0x7218ab33, 0x00210c0e, + 0x059b4901, 0x001b0226, 0x05000061, 0x430c8546, 0x61410546, 0x45854907, 0x49b60121, 0xdd825272, 0x2f545f49, 0xff4d0001, 0x02130236, 0x006500db, + 0x35340500, 0x54125844, 0xfb520f5d, 0x1940180c, 0x83d5180e, 0x080d6011, 0xb7471620, 0x01450807, 0x0c0c0d71, 0x05060b0c, 0x07070403, 0x09100c0b, + 0x12110e0e, 0x16151413, 0x13131514, 0x0c0d1010, 0x08080607, 0x17180f10, 0x28291f20, 0x0143c72f, 0x445a6c47, 0x172d2d45, 0x07040117, 0x0d0b0c08, + 0x100f0f0e, 0x27018211, 0x1c230f0f, 0x0914131b, 0x14330082, 0xca1f1e13, 0x0301182f, 0x0c070703, 0x090c100b, 0x8208070a, 0x02012160, 0x22080082, + 0x06060404, 0x0d0d090a, 0x16171111, 0x25231d1e, 0x25252524, 0x22222223, 0x411c1e1f, 0x2e1d3a16, 0x822e2d2e, 0x06302d00, 0x21050706, 0x13141a1a, + 0x09090e0d, 0x03203b82, 0x022f3a82, 0x11100909, 0x1b1e1616, 0x14141818, 0x18000a09, 0x230b7776, 0x05000029, 0x2128794a, 0x664ab101, 0x4ac9201d, + 0x73182353, 0xc12407c3, 0x39001f00, 0x17499118, 0x180b997a, 0x4d0a75b1, 0x13200ec5, 0x200f7358, 0x07f55622, 0x1ee60124, 0x08442c2d, 0x0f0f2107, + 0x0e47c718, 0x5fbca23b, 0x08040501, 0x0f0c0c08, 0x1813130f, 0x10131317, 0x080c0c0f, 0x3e040507, 0x080f8210, 0x13131825, 0x0b0c0f0f, 0x05050808, + 0x015ebd01, 0x08070504, 0x2e4e0b0c, 0x17161617, 0x43432e2e, 0x43435857, 0x82172e2e, 0x2f0d8300, 0x43435758, 0x20230901, 0x161b1b1f, 0x080f0f16, + 0x22080082, 0x16160f0f, 0x201f1b1b, 0x080fb4fe, 0x0f080909, 0x1b151510, 0x23201f1c, 0x1c1f1f23, 0x0015161b, 0x4b010000, 0x02230557, 0x182b000e, + 0x4b0ba757, 0x01212141, 0x212e4be7, 0x1b4b0420, 0xdf821821, 0x00012a97, 0x02000022, 0x00db0243, 0x126b553f, 0x26272622, 0x2006e946, 0x062f4616, + 0x5c099948, 0x5408124d, 0x15151022, 0x2e2d2b18, 0x0b0c071e, 0x0a0a0607, 0x0f100c0c, 0x07061214, 0x21070b0a, 0x16151c1b, 0x16080f0e, 0x2d181918, + 0x41202b2b, 0x1c1d1321, 0x0d0e0f1c, 0x10110d0a, 0x23242213, 0x2b214918, 0x5d5a302c, 0x1d113e5c, 0x0b10121d, 0x0407070b, 0x01183203, 0x053d5e01, + 0x3d391538, 0x6c723e3c, 0x482f4f6c, 0x21254548, 0x22191922, 0x48452521, 0x5b432f48, 0x024f2408, 0x183d000e, 0x200879bc, 0x09997714, 0x35343526, + 0x15103332, 0x33211182, 0x7f141932, 0x7723200b, 0xab5806df, 0x146a0808, 0x45612215, 0x0e080817, 0x1b16160f, 0x45202040, 0x10080917, 0x04030302, + 0x07050504, 0x10121113, 0x0712131f, 0x2d222116, 0x10141317, 0x0c0d0d0f, 0x2202c93f, 0x226dd9b5, 0x1112191a, 0x27280a09, 0xfe4ce74f, 0x0e1b87f2, + 0x0203020d, 0x0b172f03, 0x13120504, 0x12132424, 0x09080504, 0xc3130e0d, 0x01000041, 0x00003a00, 0xab822102, 0x00004d22, 0x4c08116a, 0x4a1808a3, + 0xb55f08f9, 0x0dd7180e, 0x0f23580e, 0x07064208, 0xe5220706, 0x110e0f0b, 0x15201f1e, 0x1b112142, 0x0c0e1a1a, 0x1315090d, 0x0d111113, 0x050a0a0e, + 0x01010106, 0x03020202, 0x07060504, 0x0f0b0b07, 0x090b1f3e, 0x0709090a, 0x02050607, 0x0b050603, 0x3c3b820a, 0x13121211, 0x0f111212, 0x2d2d2349, + 0x61605e32, 0x51523540, 0x26262a4e, 0x1615141d, 0x2e008217, 0x13141616, 0x07080510, 0x0a0a090a, 0x820e0d0b, 0x100f2800, 0x0f100d11, 0x82121111, + 0x100f2201, 0x2825830e, 0x16171718, 0x13151517, 0x201a8214, 0x28ef8300, 0x0236ff50, 0x00db021c, 0x3027467f, 0x200e5d56, 0x07334637, 0x0a457918, + 0x16236b82, 0x59151417, 0x57760e19, 0x0841460f, 0x0d107e28, 0x050a0a0c, 0x41460405, 0x08480805, 0x12120e0d, 0x16161415, 0x15151415, 0x0d0e1011, + 0x0c0b0706, 0x1f1f1616, 0x1a1a2427, 0x08091112, 0x0d0d0706, 0x4d1c1515, 0x6327011a, 0x283a3b4f, 0x0f131427, 0x331f1f10, 0x36494533, 0x11232236, + 0x0c060612, 0x120f0f0b, 0x1337ff82, 0x0e101012, 0x101d1d29, 0x0a090810, 0x1e131309, 0x182fca1e, 0x82040301, 0x0e0a320d, 0x080a0a0b, 0x03050509, + 0x02010101, 0x05020301, 0x07594605, 0x1b161633, 0x1c1f1f21, 0x0d14141c, 0x120b0b04, 0x1c181711, 0x064a4e19, 0x16412408, 0x09081d3a, 0x18181111, + 0x12131a1e, 0x07070b0c, 0x061a3601, 0x17160e0d, 0x121d1919, 0x0b0b0f0f, 0x82060808, 0x030221ca, 0x4b610182, 0x1b142805, 0x1319191d, 0x4a0a0a13, + 0x1b240923, 0x2f001f00, 0x4515234a, 0x7b180bf1, 0xcd450f69, 0x667b1807, 0x18392022, 0x20102141, 0x48371912, 0x49aa2008, 0x012a0c50, 0xeeff2800, + 0x05024f02, 0x4a193f00, 0x35261113, 0x23223534, 0xa7751510, 0x0c3d750c, 0x33366208, 0x33323336, 0x33363132, 0x07061514, 0x092b0206, 0x1c09090a, + 0x050c1414, 0x03030405, 0x35a10101, 0x12361644, 0x35879201, 0x06030312, 0x0d090a06, 0x06050505, 0x01020304, 0x08020101, 0x020f0809, 0x0f080701, + 0x0e0a0b08, 0x1611120e, 0xb1fe50f1, 0x6f500170, 0x12341135, 0x0c116edc, 0x0408070c, 0x35298204, 0x03031529, 0x00000002, 0xff5a0002, 0x02250237, + 0x0021001b, 0xb74d0031, 0x0b35410a, 0x087d5818, 0x2215142c, 0x16171413, 0x36373233, 0xd3583435, 0x5a200805, 0x1d1e100f, 0x3b35292a, 0x1e1d2b2b, + 0x0e0f0f0e, 0x27271d1e, 0x26263432, 0x22454517, 0x22434422, 0x23080082, 0x22224443, 0x982f01c9, 0x2336364a, 0x12111023, 0x33252512, 0x33424032, + 0x12242533, 0x28141412, 0xd00143c9, 0x280c4141, 0x00010000, 0x0236ff53, 0x20978203, 0x2f4f4367, 0x0d8b9e18, 0x45432320, 0x09d9450f, 0x4308eb45, + 0x3c080837, 0x0d0c105c, 0x05060a0a, 0x07060404, 0x07110b0c, 0x10100d0d, 0x14131212, 0x12121213, 0x0b0c0f0e, 0x13120506, 0x32322424, 0x28282a3f, + 0x12111126, 0x14151213, 0x23222c18, 0x0c0b1717, 0x8f8d1804, 0x0c0c3207, 0x0c0c0b0d, 0x060a090b, 0x121c1c25, 0x0a090a12, 0x0726430a, 0x082d2382, + 0x0a0e0b0b, 0x09080a09, 0x01030605, 0x067e4901, 0x0e0a0b2f, 0x1913140e, 0x27202119, 0x25343444, 0x3c358225, 0x1e3d140a, 0x070c0b0e, 0x0e040406, + 0x261a1a0d, 0x181c3126, 0x10121218, 0x080b0a0f, 0x213b8208, 0x3d830203, 0x120a0929, 0x1b171611, 0x4917181b, 0x022c067f, 0xf3ff3b00, 0x0e022c02, + 0x45002500, 0x24170f43, 0x22151433, 0x0a5b4523, 0x61071543, 0x3b41105d, 0x01710806, 0x20201ca9, 0x2b2c3726, 0x100f201f, 0x1e1e0f0f, 0xc13c2d2d, + 0x34285040, 0x07071a19, 0x15150f0f, 0x2323d8fe, 0x14141846, 0x0c0c1010, 0x04040808, 0x0f2b1615, 0x220f0f0e, 0x12111a1a, 0x10110909, 0x11110707, + 0x33322423, 0x31314043, 0x11122223, 0x34261640, 0x1f244235, 0x161b1c20, 0x3365e515, 0x0c060634, 0x140f100b, 0x18161714, 0x1e2c2c39, 0x2644820a, + 0x13140909, 0x82002322, 0x00012900, 0x02000050, 0x000d0219, 0x21200e82, 0x08856c18, 0x35343522, 0x43082945, 0x14220c41, 0xe269e701, 0x872a0808, + 0x7356012d, 0x04042e89, 0x13120909, 0x0b0b211a, 0x2417170b, 0x3ebc3125, 0x163f1540, 0x172155aa, 0x060b0b16, 0x01003805, 0x63821a00, 0x0e023424, + 0x35414f00, 0x1189530f, 0x0ce14318, 0x3e228553, 0x1e1aa201, 0x2029231d, 0x0a15151f, 0x1a4e010b, 0x03043295, 0x0f100708, 0x17181c18, 0x530e1211, + 0x13260f4e, 0x0a0b0e0e, 0x23820505, 0x0c0c082a, 0x15151010, 0x07070d1b, 0x432eb886, 0x32334b4c, 0x1e72e311, 0x0d0d1515, 0x45820706, 0x14141128, + 0x1c1c1b1a, 0x0082031e, 0x050a2f08, 0x19181815, 0x1b1a1a19, 0x1c191916, 0x211f1f1c, 0x1a1b1b1b, 0x1718191b, 0x00111216, 0xff260002, 0x02430237, + 0x004d0012, 0x0500006f, 0x54183534, 0x36220ffd, 0x7a183637, 0x3f5709c5, 0x08a76708, 0x2a14f75c, 0x23060706, 0x13221514, 0x19321514, 0x5c116d74, + 0x01300bfd, 0x28283206, 0x0f101f20, 0x0d0e0607, 0x16151212, 0x7908aa82, 0x0c0f0e10, 0x0a0a0913, 0x17131309, 0x09081916, 0x17160f0f, 0x1817191c, + 0x12131616, 0x07080e0f, 0x0f0e0808, 0x19191414, 0x45211c1d, 0x0f0f1045, 0x0d0c0e0f, 0x04050909, 0x05050302, 0x07090707, 0x09080809, 0x0f050706, + 0x7fc90807, 0x2411123f, 0x43343425, 0x1c24232d, 0x0e14151b, 0x04090a0d, 0x0b071933, 0x241b110c, 0x25322d25, 0x0c181726, 0x246bd70c, 0x11121a1b, + 0x456d0909, 0x1d240805, 0x2e25261d, 0x1e26262d, 0x1117171f, 0x8e080710, 0xd74d0230, 0x0a05056b, 0x170f100a, 0x251d1e16, 0x1116161a, 0x0c218982, + 0x0574430a, 0x00111231, 0x00010000, 0x0237ff2c, 0x000e023c, 0x4800005b, 0xfd6008c9, 0x2035510a, 0x230b8344, 0x15143332, 0x2008d342, 0x0ccb5f27, + 0x0c4c3708, 0x21121010, 0x0b162322, 0x08111011, 0x0c060808, 0x13271a19, 0x400c1806, 0x11102928, 0x100d1415, 0x0d171919, 0x40080c0b, 0x10100d20, + 0x22232111, 0x11110b17, 0xab820910, 0x1a1a0c31, 0x17061227, 0x191a200c, 0x0f0e1515, 0x82141208, 0x1918382d, 0x0b0b0d18, 0x18c94709, 0x41231f20, + 0x1c2d4343, 0x16282a2a, 0x510f1314, 0x2c2e078a, 0x20223232, 0x192e3030, 0x18111617, 0x2386201f, 0x16282935, 0x1e0f1413, 0x13380f0e, 0x0a0a0506, + 0x2d15100f, 0x84213232, 0x17162f27, 0x01000011, 0x37ff4200, 0x0e022702, 0x55424b00, 0x058b510b, 0xdf833520, 0x5f06a54a, 0x314211e7, 0x0eef5f07, + 0x3d065342, 0x17180601, 0x13161618, 0x070e0f13, 0x03174507, 0x08050503, 0x0f0e0a08, 0x17451110, 0x00820807, 0x07080929, 0x0508070a, 0x82030306, + 0x0f072f10, 0x1812130e, 0x18181716, 0x3f7fc945, 0xa7820707, 0x1a143c08, 0x221e1f1a, 0x65c84ce4, 0x0d121314, 0x0a0d0c0e, 0x060a0a0e, 0xfe735901, + 0x040299cd, 0x07050504, 0x0d0a0706, 0x120d0e0c, 0x4be21413, 0x1e2266ca, 0x141a1a1f, 0x070f1015, 0x82308e07, 0xff2324d7, 0x824602f3, 0xa35319d7, + 0x0ce14f0e, 0x5208ff79, 0x1d44074a, 0x3536220c, 0x10014136, 0x6a181620, 0x37240f39, 0x35343736, 0x4b05635e, 0x41180921, 0x19420ff9, 0x0a013206, + 0x1a14150f, 0x101d1e29, 0x02080811, 0x05030302, 0x33c38206, 0x20400c09, 0x0709090c, 0x03060507, 0x10020103, 0x0809200f, 0x06240182, 0x02030406, + 0x01230f82, 0x83011c39, 0x02023400, 0x06030301, 0x08070705, 0x0a0a0907, 0x0607080a, 0x82020405, 0x01022918, 0x3f1f100f, 0x0a0a0c1f, 0x25084182, + 0x01040305, 0x11080802, 0x2a1d1d11, 0x1014141a, 0x060a0b0f, 0x0b0a0b05, 0x1106060c, 0x30242311, 0x191b3e30, 0x00821619, 0x16161523, 0x22008317, + 0x82181516, 0x1a1a2806, 0x2e2d5b1c, 0x82070404, 0x0a0d315a, 0x19181211, 0x21312425, 0x15151b1c, 0x0d0c1110, 0x03835982, 0x04040722, 0x0b234b82, + 0x820c0c0b, 0x0c0c2f25, 0x0a1d1415, 0x42424405, 0x16171740, 0x52821516, 0x19191635, 0x30303e1b, 0x11112324, 0x0d0c0606, 0x12120f0e, 0x82000e0f, + 0x4e032000, 0xcc2606d7, 0x2f001700, 0xc35f5b00, 0x2b4d5a31, 0x201f755f, 0x212a4f26, 0x706d0221, 0x4d4f2138, 0x00002221, 0x06974603, 0x7f20f785, + 0x555af7b1, 0x0cad421f, 0x4122cb46, 0x1f201f1b, 0x213dea46, 0x37416e02, 0x97032006, 0xadfd2107, 0x18450d47, 0x240987d8, 0x00130013, 0x17af7933, + 0x4c133f60, 0x635e1b51, 0x18e52013, 0x5e29bd83, 0xd7201139, 0x2028774c, 0x052b4202, 0x82060321, 0x5c6320cf, 0xcd8d1593, 0x5d41d948, 0xa1201377, + 0x5d3e0142, 0xc5201193, 0x2c45f141, 0xff230002, 0x034602f3, 0x00130006, 0x231f419b, 0x1809cf48, 0x180a5596, 0x180b8d9c, 0x45084b52, 0x57414fe5, + 0x45092013, 0x022076f8, 0x20119041, 0x7e0b46b5, 0x22093b6e, 0x6e430031, 0x05201d3d, 0x4e08bd73, 0x07230709, 0x55060706, 0x22240cdf, 0x16171623, + 0x081a356e, 0x5fbe7825, 0x0f090804, 0x271a1a10, 0x0f15141a, 0x070b0b0e, 0x1f040407, 0x261b1b11, 0x101c1b27, 0x01090910, 0x7a0160c1, 0x316e0b32, + 0x1c20080e, 0x1e2a2934, 0x060e0e1e, 0x130e0e07, 0x1e191a13, 0x20c2fe1e, 0x10111111, 0x33342020, 0x34334647, 0x0029c282, 0x02f3ff51, 0x001b0204, + 0x077f4c5b, 0xe17f2320, 0xeb451809, 0x7ba31808, 0x22372209, 0x0a977823, 0x0cb14b18, 0x36353425, 0x87333637, 0x18322003, 0x380daf8b, 0x27217d01, + 0x0d0d2e26, 0x0c0e0e0e, 0x0b0a0b0d, 0x0d18080b, 0x0d0c0b09, 0x3302820d, 0x17262531, 0x060e0f18, 0x71e255fe, 0x190f0e05, 0x30232418, 0x1b822582, + 0x0b0c3008, 0x0a090909, 0x03060506, 0x06050504, 0x181a1a1b, 0x27353545, 0x08131427, 0x19111209, 0x08101319, 0x02010208, 0x02020203, 0x143b0103, + 0x82030408, 0x0101330a, 0x160b0c01, 0x281f1f17, 0x1f271133, 0x0b17171f, 0x2482010b, 0x02252382, 0x34040303, 0x82088219, 0x02062222, 0x050f5003, + 0x252b412c, 0x181f1e26, 0x02000018, 0x04826200, 0x66032723, 0xcf151900, 0x152e2c29, 0x3e162324, 0x1e1f121f, 0x75df3a13, 0xea2a0f2e, 0x17272618, + 0x18262717, 0x977d16fd, 0x8803200f, 0x0017236b, 0xc218002f, 0x9f7f1a41, 0x17397e17, 0x2f120125, 0x82040818, 0x30082c00, 0x04030817, 0x2fbb0304, + 0x82040718, 0x830720f8, 0x21078217, 0xa68e85fe, 0x8f235d67, 0x01002cbe, 0x23ffe9ff, 0xbe023702, 0x19008900, 0x24086d39, 0x34232223, 0x05334227, + 0x18333221, 0x230823dd, 0x36373637, 0x114b8818, 0x277c0720, 0x10232112, 0x440c594f, 0x418208e5, 0x2007e34d, 0x0b837c32, 0x17161724, 0x03831516, + 0x08399018, 0x1ad50126, 0x062b2423, 0x0b3d0082, 0x0c070106, 0x0205080c, 0x13160307, 0x090d0d13, 0x03060709, 0x0e070603, 0x1d16150e, 0x3d00820c, + 0x0b0b0c0b, 0x03060505, 0x04030404, 0x04070608, 0x4c030205, 0x011d5419, 0x38a76d48, 0x00830506, 0x06063008, 0x02020304, 0x05040301, 0x261b1b0f, + 0x02030303, 0x1f290408, 0x0202161e, 0x01020103, 0x0a0a1602, 0x0c0b0606, 0x0bc61312, 0x15010606, 0x83101818, 0x03033418, 0x0d0c0808, 0x19191212, + 0x24418220, 0x10111a1b, 0x82020808, 0x04042300, 0x41820204, 0x04364582, 0x100d0d09, 0x14131210, 0xd3012f8d, 0x3b143b9c, 0x0652a514, 0x19820405, + 0x01040322, 0x02295883, 0x06060803, 0x0a0a0102, 0x830d8214, 0x1a012d81, 0x8a362828, 0x24232d45, 0x13131b1b, 0x08339b18, 0x0b006624, 0x96181700, + 0x7578108b, 0x11012308, 0x9a181f13, 0xb92008d4, 0x42078278, 0xfe230f93, 0x82009b2d, 0x00012800, 0x02f3ff41, 0x51cb0213, 0x172219bd, 0x83181716, + 0x07210c1f, 0x4e018206, 0x574e0545, 0x06bd460c, 0x02144208, 0x2a292613, 0x3838482b, 0x13132828, 0x28281413, 0x2b483738, 0x2526292a, 0x202f2b2a, + 0x13131a1a, 0x0a0a0e0f, 0xec040708, 0x0169d34e, 0x0a0b0605, 0x16151110, 0x16211b1b, 0x15161515, 0x19121414, 0xbec41814, 0x572e0808, 0x31304343, + 0x0a0a1818, 0x1d204113, 0x07070f0e, 0x15140e0e, 0x22231b1c, 0x23143c28, 0x1b1c2020, 0x10101716, 0x03040808, 0x0b0a0808, 0xcf84490f, 0xcf824620, + 0xcf822520, 0x57516320, 0x059f420d, 0x089b4418, 0x6212a371, 0xf58c1041, 0x57079d50, 0x15230b03, 0x18060714, 0x1858494d, 0x205b3c4d, 0x44977700, + 0x64000322, 0x2d76a36d, 0x752776a3, 0x68370128, 0x27762875, 0xc844c9fe, 0x0fa36d23, 0x36000128, 0xde01f3ff, 0xc557bd02, 0x6d77180f, 0x082f500d, + 0x0a7d9d18, 0x01060730, 0x2b2c1aaa, 0x1818193c, 0x1a1a1717, 0x0782171c, 0x07831820, 0x13122508, 0x090a0d0e, 0x03030607, 0x49db308f, 0x1c2a0d0d, + 0x02020e0d, 0x08080505, 0x1325490c, 0x09090e0e, 0x04040605, 0x2b072644, 0x6227011f, 0xc6fe143b, 0x2f2f419e, 0x08e36518, 0x4b278f82, 0x00006100, + 0x52353431, 0x85820add, 0x36373426, 0x34353635, 0x1806b750, 0x64088d41, 0x232011c9, 0x1745a983, 0x06072408, 0x45250607, 0x35200891, 0x2506f542, + 0x14232223, 0x1c451218, 0x04042306, 0x00830102, 0x0645cc25, 0x82171804, 0x12132cd2, 0x07080f10, 0x100f0707, 0x82171313, 0x4e182410, 0x8316401a, + 0x0e0d2cc7, 0x28291915, 0x04065c01, 0x89131416, 0x18440823, 0x1a330208, 0x07070304, 0x13110d0d, 0x0e211919, 0x16151112, 0x49181716, 0xd3319619, + 0x0c060646, 0x1712120b, 0x221e1d17, 0x171d1d23, 0x0c121117, 0x0106060c, 0x40819cd2, 0x30393941, 0x19242431, 0x4e0e0f1b, 0x36059159, 0x19181f20, + 0x09091211, 0x000200c6, 0x02000016, 0x00bd0268, 0x7643002d, 0x1427068f, 0x34333215, 0x83333235, 0x0e654807, 0xd582e783, 0x82353421, 0x221521d9, + 0x162ff195, 0x31941845, 0x04061846, 0x1b25252c, 0x8c0d0e1c, 0x211982e1, 0xd8896901, 0x0f0e0824, 0xd8821314, 0x0e022308, 0xd848d7af, 0x0d46d347, + 0x251a190c, 0x1f263226, 0x1218191f, 0x050c0b12, 0xfb54fa06, 0x08084e53, 0xd3761011, 0x23b68406, 0xeeff0100, 0x3724b782, 0x6100be02, 0x086bad18, + 0xb1822020, 0xd7469783, 0x2322212b, 0x20059f51, 0x0dc97126, 0x290b3d47, 0x22151415, 0x011b515a, 0xb8466c44, 0x194c2129, 0x461e0947, 0xac232b99, + 0x46489139, 0x00201fe9, 0x022c0082, 0x00004500, 0x66036402, 0x35000b00, 0x5206074d, 0x222405c5, 0x32351003, 0x25716b19, 0x9318fb20, 0xc9220a91, + 0xa318194c, 0x022120ef, 0x2f2619e9, 0x17fd2207, 0xefa31802, 0x27a68221, 0x46000200, 0x23020000, 0x2b22a784, 0x60180000, 0xa7850afb, 0x41151021, + 0x737b07c1, 0x4a012010, 0xfb2c0b0f, 0x2e1f1849, 0x16182d2e, 0x20601115, 0x2f270b82, 0x16182c2e, 0x8e601016, 0x7ffe3892, 0x6a6b46c0, 0x32323766, + 0xaff2fd25, 0x47c18101, 0x37676a6a, 0x85263132, 0x003e248b, 0x824b0200, 0x0013228b, 0x188b825d, 0x2410a573, 0x34013237, 0x0c6b4935, 0x57183720, + 0x27200a87, 0x5411f95e, 0x47420c37, 0x22232a0b, 0x2705db01, 0x27484928, 0x05d71828, 0x259a2e0c, 0x10101412, 0x0a0a0b0b, 0x02020208, 0x08028201, + 0x14120338, 0x23251414, 0x24491a24, 0x1b1d1c13, 0x0b0d0d0f, 0x1c1c1c13, 0x0a0d0e0e, 0x110e2447, 0x26241412, 0x08081926, 0x08080907, 0x0e0b0908, + 0x1510100f, 0x03371a15, 0xc3183866, 0x39080ba5, 0x06143d9a, 0x0f0b0a06, 0x0304120e, 0x05030304, 0x2f2c0706, 0x54593030, 0x482f3e53, 0x22254548, + 0x48301a21, 0x21254647, 0x2b211922, 0x5c59302b, 0x11133d5c, 0x0e101012, 0x03820c0e, 0x050a0a2f, 0x00010005, 0x0268ff45, 0x00bd0224, 0x05ff5517, + 0x35102326, 0x15103332, 0x07840382, 0x23222408, 0x01221514, 0x4c319309, 0x4c45cf19, 0x4031941a, 0x02267298, 0x2efeaf0e, 0x9bd2019b, 0x72aff2fd, + 0x19020026, 0x219eab73, 0x43180002, 0x21220727, 0x41183700, 0xc56a0ea9, 0x22232212, 0x14e54537, 0x5201533d, 0x58fafe71, 0x3b5f274f, 0x05071a3c, + 0x02030305, 0x20101001, 0x44323220, 0x18502ea6, 0x37130543, 0x349f133a, 0x2d181904, 0x100e0e0c, 0x0f0f1010, 0x19242532, 0x4e0c0d18, 0x0ff44218, + 0x00000023, 0x18a38803, 0x2af7cb43, 0x0268ff10, 0x00bd0258, 0x184f002b, 0x5109f59c, 0x36200ac5, 0x35260b83, 0x33203534, 0x314b1510, 0x260b8205, + 0x22151423, 0x47333237, 0x142007a7, 0x570f114d, 0x102907d7, 0x05050d1a, 0x04040504, 0x22028203, 0x4e030303, 0x013305bf, 0x0f2d6b3f, 0xcafe1540, + 0xaea83f68, 0x0138a73a, 0x82010202, 0x871c8203, 0x01360820, 0x06060101, 0x073aae98, 0x100d0c06, 0x18161511, 0x1c1a1a18, 0x1b1b1c1b, 0x36a5191a, + 0xae9b2efe, 0x7226723a, 0x9601e826, 0x152f5d88, 0x19191717, 0x19181a19, 0xa77e1817, 0x07082205, 0x23698302, 0x00020305, 0x462b4418, 0x00000729, + 0xbd026102, 0x18004f00, 0x20098d46, 0x0a9f4426, 0x4505d147, 0x06200959, 0x65081375, 0x14250d09, 0x34232215, 0x0caf5a35, 0x13072708, 0x0f1b1c1c, + 0x6c0a0d0d, 0x11234524, 0x0d191a1a, 0x47090c0d, 0x191a1217, 0x0c0c0e19, 0x601a4d0a, 0x1c1c122f, 0x21820e1c, 0x0d21412f, 0x0a141515, 0x0808090a, + 0x46090d0e, 0x22058318, 0x8414150d, 0x334a3a11, 0x294a4d4d, 0xd41c2324, 0x33342146, 0x18181b32, 0xba45d212, 0x3433225d, 0x210b8331, 0x1f825ebc, + 0x24284b38, 0x38251b24, 0x1a1e3638, 0x1b10141a, 0x37a3101c, 0x1c104991, 0x1383101b, 0x1b1a1d31, 0x00000014, 0xff450001, 0x021c02f3, 0x4c6500cb, + 0x4b510a7b, 0x0f7b4c08, 0x51512320, 0xa3641805, 0x34072216, 0x06134135, 0x6e10055d, 0x28080ad5, 0x3023d601, 0x34333f30, 0x191a3533, 0x18191918, + 0x212a1818, 0x0a171620, 0x170a0b0b, 0x261f1e16, 0x19331339, 0x131b1b24, 0x08f98213, 0x12120a26, 0x14231a1b, 0x18171615, 0x1e1b191a, 0x17181b1b, + 0x23141516, 0x1a1b1f1f, 0x0f0f1515, 0x22210708, 0x1d1c2543, 0x27082b83, 0x1c291112, 0x09080d0d, 0x0d203e12, 0x0606090a, 0x09080203, 0x18191211, + 0x18192021, 0x09091212, 0x0707143a, 0x14150f0e, 0x14293982, 0x07070f0e, 0x05040302, 0x36861907, 0x06063a0a, 0x10110b0c, 0x18191515, 0x26253c1d, + 0x11110910, 0x1d1d1717, 0x25263124, 0x3b421800, 0x1a594714, 0x4c474620, 0xaf0e2117, 0x471b4047, 0x132209cb, 0x3f473300, 0x05354616, 0x18097942, + 0x200e4743, 0x1bde1801, 0x2a2a270d, 0x2c081818, 0x8f9684fe, 0x200fe546, 0x209f9d02, 0x05134901, 0x00bd0223, 0x08dd4a29, 0x03438989, 0x15142315, + 0xf9484522, 0x23ed4823, 0x07000126, 0x28020000, 0x37207f82, 0x6d4c7f82, 0x4c36200f, 0x3721056b, 0x06bb4434, 0x4c053d64, 0x07210c55, 0x29018206, + 0x0e121318, 0x060b0a0e, 0x444c0407, 0x31013406, 0x99194c66, 0x01020133, 0x07040402, 0x0f0b0a06, 0x4c2d2c19, 0x2108141d, 0x18181919, 0xf2fd3196, + 0x9cd201af, 0x26284488, 0x1f232426, 0x151b1b20, 0x0f1b1015, 0x0100000e, 0x9f822b00, 0x44183c20, 0x21214bf7, 0xf7441845, 0x1a332508, 0x17181910, + 0x35f74418, 0x97824520, 0x20067b48, 0x05bd4a33, 0x2305954c, 0x23221510, 0x20067f4c, 0x05784845, 0x07664318, 0x0b185118, 0x0b874418, 0x49563b20, + 0x8744181d, 0x1151770b, 0x181c4156, 0x181b75a2, 0x18196744, 0x421f6fa2, 0x441805b3, 0x62242f57, 0x3a020000, 0x2f574418, 0x4892622f, 0x3f3f407f, + 0x1d577f40, 0x264e4c4c, 0x344e1824, 0x1d57210c, 0x1f574418, 0xf3ff4628, 0xcb021902, 0x5f704700, 0x0521600d, 0x27bdda18, 0x2608a95c, 0x07061514, + 0x19ca0106, 0x1880df7b, 0x23096385, 0x2100000f, 0x260b3355, 0x01221510, 0x193ab002, 0x28142f72, 0x0200003e, 0x00bd024b, 0x2db41849, 0x39314c11, + 0x1b4c6620, 0x400b4c46, 0x21000322, 0x4820df82, 0x3b27df82, 0x6f005500, 0x19210000, 0x610cc554, 0x69480c39, 0x123d4b05, 0x82060721, 0x15142401, + 0x18102722, 0x73070b44, 0x13200fa6, 0x6c09a146, 0x012b0e41, 0x22222b01, 0x11111918, 0x82050a0a, 0x0a0a3400, 0x18191111, 0x4d2b2222, 0x22222e19, + 0x10111819, 0x85060909, 0x18123017, 0x2c222119, 0x141c1a4c, 0x080c0c14, 0x58030408, 0x09260599, 0x140c0c08, 0x15838214, 0x08070d2d, 0x01020404, + 0x04040201, 0x820d0708, 0x302f0815, 0x0b0b0118, 0x1a1a1314, 0x25242020, 0x23242827, 0x191a1f20, 0x0a091312, 0x260e2b01, 0x0a0b0113, 0x191a1313, + 0x23232120, 0x26252928, 0x8519201f, 0x1236301b, 0x8b180194, 0x0d080804, 0x1512110e, 0x821b1a16, 0x151b2e35, 0x0d121116, 0x0108080d, 0x8ce9fe9e, + 0x2f1b8205, 0x1611120d, 0x1f1a1b15, 0x161a1b20, 0x0e111215, 0x00201b82, 0xe3234418, 0x68ff3224, 0x3b4e5502, 0x4e202008, 0x32310e3b, 0x22151433, + 0xa6fe0002, 0xcf1a4c74, 0x33194c45, 0x0c3c4e11, 0x9b2efe25, 0x82003aae, 0x050b4500, 0x47822220, 0x00003f23, 0x43461821, 0x0a435b08, 0x8f642620, + 0x0dff6015, 0x32353008, 0x22151033, 0x161abc01, 0x14131416, 0x14141714, 0x10131214, 0x0b0e0f10, 0x0408080a, 0x04194c04, 0x0a060603, 0x120e0e0a, + 0x0d0f1611, 0x830c0b0e, 0x0d0c3001, 0x4c1a4c0e, 0x080c67ce, 0x01040308, 0x83010202, 0x09093524, 0x14130e0e, 0xb4201a19, 0x1a4c983c, 0x0c0d1313, + 0x04030708, 0x012e1c82, 0x03030201, 0x08080405, 0xfd4adf0a, 0xbb84aff2, 0x00003924, 0x50183002, 0x3b4f0803, 0x07434f0b, 0x45392027, 0x461c5418, + 0x21038317, 0x3c4f87fe, 0x08424f08, 0x24050341, 0x0268ff2e, 0x25478268, 0x0500001f, 0x4b413534, 0x05614911, 0x28055341, 0x7994fe13, 0x1c551746, + 0x24038245, 0x10321746, 0x0b944f3f, 0x5d415785, 0x05576006, 0x57824520, 0x19001521, 0x530be96a, 0x152306f7, 0x4e060714, 0x9d2817ef, 0x3aad2063, + 0x407e182e, 0x7e210082, 0x25098280, 0x131b1c23, 0x00820a13, 0x13132308, 0x35231c1b, 0x9cd20111, 0x46d3143b, 0x69683535, 0x094e3435, 0x18111109, + 0x191f2018, 0x09111118, 0xd482c609, 0x20054f44, 0x207b8237, 0x6d6e1821, 0x0c715408, 0x20117155, 0x54e58521, 0x27081675, 0x1f194b21, 0x1d1e200f, + 0x14141919, 0x07080e0f, 0x0f0e0807, 0x19191514, 0x6e201d1d, 0x194c8d01, 0x1f9afe4c, 0x15151a0f, 0x072b8083, 0x160f1007, 0x0c221e17, 0x55af0e02, + 0x1a821739, 0xaff2fd24, 0x2a82084e, 0x231a1922, 0xc35cb988, 0x0d674705, 0x24222f41, 0x4e1a4c62, 0x05694726, 0x472fa321, 0x2b411467, 0x0001261a, + 0x02f3ff55, 0x0e3b5a28, 0x2410ef4c, 0x36373637, 0x0c3d5e35, 0x21081e7b, 0x1b823534, 0x2d0c2175, 0x383728d8, 0x2a292c47, 0x14141226, 0x01821516, + 0x1b202808, 0x1016151b, 0x060b0b10, 0xd14fed06, 0x07080568, 0x0e0f0a0a, 0x19191214, 0x2a2a301f, 0x292a2626, 0x3738472c, 0x82142828, 0x30522900, + 0x09091718, 0x0f214014, 0x0805325f, 0x1008082d, 0x1b161610, 0x2420201c, 0x242b143c, 0x141b1a24, 0x070d0d14, 0x1d0e0f06, 0x0a132140, 0x3118180a, + 0x57434330, 0x00424356, 0x82280002, 0x825520cb, 0x002921cb, 0x0b5d6419, 0xab822620, 0x14232225, 0x49232215, 0x954d07eb, 0x1415210a, 0x0ea34318, + 0x880e1b46, 0x06c361e7, 0x23023908, 0x33262519, 0x18252432, 0x020d0d18, 0x194c0e2a, 0x1325194c, 0x170e0d02, 0x32252517, 0x0d323364, 0x140cfc0d, + 0x131b1b13, 0x05060b13, 0x01030404, 0x03010202, 0x06050404, 0x0923f683, 0x820f0c0b, 0x0c270819, 0x0606050c, 0x162e4d05, 0x2b141516, 0x4f3c3d2a, + 0x0e024eeb, 0x4c4de7af, 0x2a2a3c3b, 0x5b5c1615, 0x44445cb6, 0x82112108, 0x21260800, 0x1b151610, 0x2821221b, 0x1b212228, 0x1115161b, 0x090c0c11, + 0x10040408, 0x37212111, 0x374d4e37, 0x00020037, 0x074c0017, 0x002f2205, 0x0ca14f41, 0x47085f6a, 0x33220743, 0xe34a3332, 0x2b7e1807, 0x32012208, + 0xd1e61833, 0x0c2e080f, 0x2112100f, 0x12172222, 0x10101212, 0x0a0b0d0d, 0x11100505, 0x2f302020, 0x4d3ab03d, 0x0b306119, 0x1f100f10, 0x51152120, + 0x22660901, 0x9d4e2c58, 0x09390805, 0x1b142424, 0x3a381e1b, 0x09062639, 0x0f0b0b08, 0x1812130f, 0x25301d17, 0x0d1a1a25, 0xaff2fd0d, 0x1a134adf, + 0x36351c1a, 0x77012437, 0x08083fba, 0x17181010, 0x1e1f3d20, 0x2b008200, 0xff440002, 0x023002f3, 0x0081001b, 0x12811e19, 0x5357bf8a, 0x4f342011, + 0x6f180765, 0x23480c1f, 0x05ef430a, 0x4e891c19, 0x1c176d22, 0x8a751c19, 0x060b0922, 0x8f621c19, 0x0002002b, 0x02f3ff3e, 0x00ec0224, 0xb17e1977, + 0x3435210f, 0x26210186, 0x21018227, 0x0d822635, 0x37200382, 0x4b0cc941, 0x36220ae3, 0x2a193633, 0x22200cb9, 0x21136f53, 0x01821407, 0x7d0e6f51, + 0x8d791496, 0x8601200b, 0x05043900, 0x0d080806, 0x1610100c, 0x17161a15, 0x1d1a1a17, 0x06061e1c, 0x05040505, 0x05231882, 0x82051205, 0x06052c07, + 0x101e0605, 0x0a0b3c0f, 0x820b0b0a, 0x13172d02, 0x090e0f12, 0x03010309, 0x15131410, 0x18313582, 0x1e2c2c3a, 0x10100f1f, 0x24a1fe0f, 0x23474724, + 0x21058324, 0x06742324, 0x23223905, 0x0e3f3130, 0x03030904, 0x14030402, 0x0d270a0a, 0x0b0b0c0b, 0x06050807, 0x162f6882, 0x16161617, 0x13121515, + 0x0a0b0f0f, 0x82030607, 0x26998300, 0x11030102, 0x5b210809, 0x013905dd, 0x05010203, 0x03020202, 0x05040403, 0x110f0e0c, 0x11111112, 0x0e040407, + 0x22328210, 0x74040307, 0x663b0a5b, 0x33343333, 0x33326665, 0x00003233, 0x00780003, 0x020f0200, 0x0029000e, 0x1855003f, 0x18091952, 0x41092f57, + 0x3343064f, 0x07db7206, 0x2dbb5918, 0x4284782c, 0x1517171a, 0x0c111214, 0xd282070c, 0x120c0d3c, 0x18211813, 0x060e0e17, 0x1a0d0d07, 0x3026251a, + 0x264c299b, 0x0b0f1015, 0x0082050b, 0x0b0b2f08, 0x55151010, 0x18284f1c, 0x0d0c1212, 0x06050706, 0x13130b0a, 0x011e5b1a, 0x0403838b, 0x0b0b0707, + 0x13130f0f, 0x12121516, 0x09091011, 0x2f820603, 0x14112708, 0x1c271915, 0x0a14141d, 0x06380109, 0x0c0a0a05, 0x0d10100d, 0x050a0a0c, 0xebfe6c06, + 0x0d0d0606, 0x11141111, 0x60820e0f, 0x00810625, 0x829a0001, 0x821120f7, 0x840b20f7, 0x05c35bf3, 0x22151029, 0x5e19019a, 0x824547d4, 0x11352567, + 0x0072aafe, 0x02260082, 0x7aff3400, 0x2b823402, 0x4b002b22, 0x23140756, 0x35363734, 0x21074b51, 0xc9543332, 0x56202005, 0x15200d07, 0x2a0c1763, + 0x16151415, 0x32171633, 0x820b1734, 0x040321ed, 0x4105fe55, 0x193105ca, 0x380f2d5e, 0x5af1fe13, 0x31919239, 0x0101308e, 0x05fc5501, 0x1e830120, + 0x04010227, 0x34998604, 0x08df8205, 0x100d0e2a, 0x12111111, 0x11101112, 0x090d0c10, 0xabfe3192, 0x64339a72, 0xcd216522, 0x55612001, 0x0e0f072a, + 0x1b1b1415, 0x13122320, 0x04226082, 0x40830202, 0x3e2acf85, 0x2c02f3ff, 0x37001b02, 0x414f5300, 0x1023610d, 0x16171622, 0x33b5de18, 0x18b20123, + 0xb2de1817, 0x18032048, 0x2b41fad6, 0x1e000100, 0x4c020000, 0x5b000e02, 0x5b120547, 0xad56094d, 0x05b74111, 0x15215118, 0x3f12b356, 0x0b0b081e, + 0x1817170d, 0x16160f10, 0x0a0a0b15, 0x10214208, 0x0c171717, 0x3f080b0b, 0x18171015, 0x42210984, 0x3b1d8322, 0x070b0a0c, 0x0c0c0b08, 0x10181817, + 0x08071e3c, 0x12110908, 0x100a0c11, 0x153f0a10, 0x24080583, 0x1112120b, 0x06080809, 0x1d1d1643, 0x3e3e3c20, 0x23231729, 0x10101321, 0x2525190c, + 0x12111324, 0x8732980d, 0x830b8743, 0x1112231b, 0x2b870c10, 0x1516103e, 0x2d2d2c18, 0x1a1a101f, 0x6e297c0f, 0x1a1a0f37, 0x2d2d1f10, 0x1615182c, + 0x00000010, 0x09a34118, 0xcb565d20, 0x33c7560f, 0x570fdd77, 0x730807e3, 0x06071415, 0x3023cf01, 0x2e2b3f30, 0x2d26312e, 0x212c332c, 0x0b171621, + 0x160a0a0b, 0x251e1d15, 0x1c37133c, 0x121a1a22, 0x0a090912, 0x1c121309, 0x1312231b, 0x18161514, 0x2e351b17, 0x2934272e, 0x101e1f2a, 0x1009080f, + 0x1e171710, 0x14191a20, 0x11090a13, 0x0a162112, 0x0d06070b, 0x08101b36, 0x0c060608, 0x1611110c, 0x0d101115, 0x3306070d, 0x0a050610, 0x08e94a18, + 0x05062808, 0x03030102, 0x34060505, 0x06050c1a, 0x1312090a, 0x16201918, 0x100f1313, 0x06060a09, 0x11110b0b, 0x251b1717, 0x82001e1e, 0x00012a00, + 0x02000061, 0x000e020d, 0x12af551f, 0x42051749, 0x36080509, 0x61220706, 0x15101745, 0x2d2c1715, 0x17451d2d, 0x2d1d1745, 0x15172c2d, 0x01451015, + 0x7ffd838b, 0x24212119, 0x2e464643, 0xfd8476fe, 0x46452f7f, 0x21202543, 0x86020019, 0x00dd245f, 0x56370017, 0x17210faf, 0x06876916, 0x5f013221, + 0x798e0f2f, 0x2e0bb356, 0x0c070703, 0x1710110b, 0x0719192a, 0x969ffe2c, 0xdd022393, 0x00822243, 0x0d114322, 0x080af318, 0xa79a2320, 0x76000126, + 0x59020000, 0x374fc218, 0x74197620, 0x123810cf, 0x2f1f0f13, 0x15192d2f, 0x264b1116, 0x24262619, 0x0d121214, 0x0d15160d, 0x2d4fc218, 0x19000122, + 0x17209782, 0xcf569782, 0xb9471806, 0x097d450c, 0x1808c956, 0x080dc564, 0x07060756, 0x19222306, 0x1116060c, 0x070a0b11, 0x01010307, 0x26010102, + 0x9c174563, 0x04010135, 0x09050603, 0x0d0a0d09, 0x140f0f0d, 0x35151914, 0x0e070712, 0x2016170f, 0x1510100d, 0x15141415, 0x76fe2f8c, 0x72560184, + 0x1a19264d, 0x191b1a1a, 0x14181819, 0x0a0e1115, 0x04284983, 0x1f000100, 0x4e020000, 0x180a3341, 0x4b0f6165, 0x41420759, 0x26232208, 0x2d018527, + 0x1f221510, 0x100c1f3d, 0x23211210, 0x6f821722, 0x22211225, 0x82451723, 0x0c0a2301, 0x6d820d0c, 0x1f3d1222, 0x2b07f95a, 0x838b0145, 0x1f1c1c15, + 0x273c3c39, 0x97820787, 0x0f74e835, 0x28161313, 0x1b1b2a2a, 0x16282a2a, 0xfe0f1313, 0x820057fb, 0x00012200, 0x2097825e, 0x2097820a, 0x0e616317, + 0x29055542, 0x15142322, 0x17455e22, 0x6f833db7, 0x5f820582, 0xa136a023, 0x23538235, 0x3cb63db5, 0x082f4718, 0x878d0b7d, 0xfb5a18d3, 0x015e2312, + 0xce846b41, 0xb041c882, 0xaafe2305, 0xfd180072, 0x1b290863, 0x33002300, 0x10170000, 0x05ef4535, 0x7c0e9b4e, 0x5f321b95, 0x03021b38, 0x26180103, + 0x27323426, 0x0e1d1e26, 0x74190f0f, 0x45250a6f, 0x42452222, 0x20008222, 0x32098242, 0xb52202c9, 0x0c16150c, 0x13141428, 0x33252512, 0x7c404132, + 0x01261a98, 0xf3ff5200, 0xa76d0302, 0x18052005, 0x4c12db6f, 0x14200cb7, 0x2495f218, 0x1806e74a, 0x2c0d3fb4, 0x0b0a9001, 0x33400d0a, 0x12252432, + 0xd7181912, 0x13122115, 0x2c591919, 0x0a0a0829, 0x1212020b, 0x19332524, 0x2018a518, 0x5ef11807, 0x01002a33, 0x00006a00, 0x0e02fe01, 0x13075700, + 0x2775062d, 0x75652f01, 0x56014527, 0x49113572, 0x012607a4, 0x37ff3900, 0x33824602, 0xa1495920, 0x8b7a1814, 0x2b396308, 0x2d0f494c, 0x24612223, + 0x0a090b13, 0x07060807, 0x1d820505, 0x0808072b, 0x2726230a, 0x11111324, 0x7500190f, 0x130c3208, 0x0f1d1e1f, 0x410a0e0f, 0x1c1b1221, 0x0d0c0e1a, + 0x252d820a, 0x02030404, 0x02830203, 0x18050421, 0x2111098a, 0x001937c9, 0x89182f5e, 0x002a21f6, 0xff340003, 0x02350237, 0x3b5700db, 0x016c1906, + 0x2d3b570d, 0x3b570320, 0x25063a33, 0x17171e1e, 0x0b0a1211, 0x05060605, 0x11120a0b, 0x1e1e1717, 0x25174525, 0x2317831f, 0x060a0b11, 0x0a230082, + 0x8612110b, 0x14510817, 0x0d0c1010, 0x06050a09, 0x03020203, 0x090a0506, 0x10100c0d, 0x11111470, 0x09090c0c, 0x03040506, 0x06050403, 0x0c0c0909, + 0x7dc91111, 0x0908043f, 0x16160e0f, 0x26261d1e, 0x26262f2f, 0x16161d1d, 0x09090e0f, 0x80309004, 0x09090440, 0x16160f0e, 0x081b871d, 0x16161e21, + 0x08090f0e, 0x012f8d04, 0x860d0104, 0x09060604, 0x140f0f08, 0x271c1d14, 0x151e1e26, 0x820f0f14, 0x01072a60, 0x87f4fe8f, 0x09060704, 0x381b8209, + 0x261e1e15, 0x141d1d27, 0x080e0e14, 0x00070609, 0x00260001, 0x02430200, 0x5f5b180e, 0x1b26364b, 0x15272928, 0x180e1313, 0x13242525, 0x450e1111, + 0x1c1b1222, 0x4773191a, 0xff5c2475, 0x464d027a, 0xef55052f, 0x15143c14, 0xfe020222, 0x17456ac4, 0x17453db6, 0x86381234, 0x8b012264, 0x72abfe83, + 0x82725501, 0x339a2205, 0x2a008200, 0x00530001, 0x02ff0100, 0x5737000f, 0x5f450b3b, 0x27262208, 0x06e76a26, 0x470ac77b, 0x342008cf, 0x23063357, + 0x060703a3, 0x3b05cb49, 0x2a161313, 0x18192121, 0x17440c0d, 0x09080405, 0x0d0e0b0b, 0x11100f0f, 0x0f0e1010, 0x24080782, 0x92451745, 0x02020149, + 0x04030404, 0x02020303, 0x1413090a, 0x812c2020, 0x143a722b, 0x0a0a0f0f, 0x03030706, 0x29008201, 0x05060303, 0xfe3bb009, 0xa3848475, 0x00003e24, + 0x1b472b02, 0x095f660a, 0x24082357, 0x5a153f3e, 0x2303831e, 0x8ffe1540, 0xed83e78b, 0x46837620, 0x00010027, 0x027aff34, 0x05374a68, 0x57143341, + 0x1e230b23, 0x857b91fe, 0x2157834f, 0x3f411136, 0x0945410f, 0x1e000222, 0x55209f82, 0x1d225782, 0x696a3300, 0x0ca95608, 0x6609894f, 0x9a2b151b, + 0x36a21f5d, 0x29342b55, 0x461e1e29, 0x410805af, 0xa5362829, 0x1e2a5225, 0x11111819, 0x08090808, 0x18181111, 0x011f5d1e, 0x11357256, 0x090a369f, + 0x1d1e1314, 0x1d1d2828, 0x0a0a1313, 0x0a05054a, 0x160f100a, 0x0b0f1015, 0x7e06050b, 0x03000000, 0x93823400, 0x93823420, 0x66001921, 0x919607b5, + 0x261d3357, 0x1e164534, 0x8228350f, 0x820f2097, 0x1d1d3400, 0x66362929, 0x17458201, 0x1ca0fe45, 0x18181f0d, 0x82091011, 0x8210209e, 0x1e1f259d, + 0x838b010b, 0xde479b8f, 0x84492005, 0x821020a1, 0x831020a1, 0x008024a1, 0x82710002, 0x842b209f, 0x4827209f, 0x4b6c0af1, 0x075b580e, 0x2734352d, + 0x23222326, 0x17457114, 0x83342b55, 0x0f0e2e8d, 0x1e1d0e0e, 0xa5362928, 0x402a5225, 0x22008220, 0x891f5d40, 0x281e227f, 0x053e6328, 0x15154835, + 0x16152a2b, 0x00000080, 0xff710001, 0x022202f3, 0x4d4d001b, 0xb1180a47, 0x5d7510fb, 0x0b37560d, 0x18110764, 0x29083d44, 0x24241fa2, 0x1414152b, + 0x01821314, 0x271f2308, 0x212e2d26, 0x0d161521, 0x44cc030c, 0x060359b3, 0x0f090906, 0x1813120f, 0x15171e18, 0x12121314, 0x29821112, 0x14132c08, + 0x40141514, 0x25253132, 0x08091312, 0x17171111, 0x08081013, 0x05050202, 0x3c0b0807, 0x0f0e1d1e, 0x191a0c0d, 0x322a2121, 0x82131511, 0x0f0e3334, + 0x05060b0a, 0x07060404, 0x3c0e0b0c, 0x08080a1f, 0x41750504, 0x00002411, 0x823b0002, 0x825c20e7, 0x643520e7, 0x3f570cfd, 0x0f43521c, 0x18162721, + 0x1811f781, 0x470d7164, 0x52080971, 0x16171415, 0x1716fc01, 0x21271918, 0x0f1b1b20, 0x1136040f, 0x17451745, 0x0f04182f, 0x201b1b0f, 0x181b2620, + 0x11151618, 0x060d0e11, 0x0d060707, 0xcc12110e, 0x06050503, 0x1511120d, 0x0a09090a, 0x06080709, 0x03050506, 0x08020203, 0x100d0e07, 0x82141310, + 0x8207202b, 0x043e0811, 0x01020202, 0x07070e0f, 0x20201010, 0xaa382c2c, 0x838b0139, 0x2d3c39ab, 0x0f1f1f2c, 0x0f07080f, 0x1e18170f, 0x2f27261f, + 0x1f27282f, 0x9216171e, 0x0d0f0f12, 0x040e0e1c, 0x0c070803, 0x4a830f0b, 0x16132608, 0x242f1716, 0x0c191a25, 0x1c0e0f0d, 0x1211110e, 0x17151512, + 0x00141517, 0x00590002, 0x02f10100, 0x0037000e, 0x12695055, 0x2005f54b, 0x0d675126, 0x20117757, 0x0c775713, 0x2b0fad5e, 0x19191159, 0x0b0c0d18, + 0x08080609, 0xed82e982, 0xec820720, 0x52030321, 0x898305e4, 0x32941936, 0x21411645, 0x0d0b0b08, 0x10181816, 0x1d56b343, 0x0a09264c, 0x08240082, + 0x03070708, 0x07380082, 0x0a080807, 0x1b0a090a, 0x1628292a, 0x030f1313, 0x04050403, 0x09080706, 0x36083282, 0x1311100d, 0x1116151b, 0x080c0c11, + 0xfe040408, 0x35a18476, 0x1413120e, 0x1a282726, 0x2b801d01, 0x04050203, 0x09090707, 0x100f0c0d, 0x0a090c0c, 0x05040707, 0x19000102, 0x230b0f21, + 0x0067004b, 0x1905616d, 0x18108f22, 0x4109ff88, 0x1b420d05, 0x346d5205, 0x79182020, 0x1a230f3b, 0x527f3a11, 0x5c184a81, 0x9c2012ee, 0x21419452, + 0x87530004, 0x00d82805, 0x002f0017, 0x18830067, 0x7819ebd7, 0x8d7f172d, 0x11f9620d, 0x21344d41, 0x1f193008, 0x08290810, 0x03040403, 0x081830bc, + 0x28008203, 0x07183008, 0x04030304, 0x4b594121, 0x03047927, 0x07162d07, 0x95678203, 0x84fd2107, 0x2d3f6941, 0xff260001, 0x023e0237, 0x004b00db, + 0x47580500, 0x1177650c, 0x08494b18, 0x18098b72, 0x5e0c41df, 0x013d0b1f, 0x1312144b, 0x0d0e1110, 0x05040a0a, 0x0c0b0605, 0x25211616, 0x11111b1a, + 0x17450909, 0x08018247, 0xa8174558, 0x1938a939, 0x2f3c2a2b, 0x16152222, 0x100f0b0b, 0x2d2d1f1f, 0x041a34c9, 0x10100a0a, 0x1d1c1716, 0x24282222, + 0x12131b1b, 0x0b0a090a, 0x1e1f1615, 0x011f5c29, 0x11327358, 0x3499339a, 0x3f7c1132, 0x0f17182e, 0x2b1b1c0e, 0x3944392a, 0x1d2d2d3a, 0x0200001c, + 0x04829a00, 0x05031f29, 0x1f001300, 0x68010000, 0x06210b57, 0x23018307, 0x35100322, 0x2b08d156, 0x0c092f01, 0x1a190e0c, 0x21431119, 0x21072743, + 0xe656a83a, 0x54022105, 0x10061019, 0xfa56ac20, 0x00012208, 0x069b4e53, 0x25564f20, 0x2627210d, 0x0e0bba18, 0x16171622, 0x46054378, 0x89830cd9, + 0x78373221, 0x33230c49, 0x4e363732, 0x4e080597, 0x1413b401, 0x242a1614, 0x171f1f24, 0x09101117, 0x25121208, 0x3f323225, 0x13141415, 0x15131413, + 0x13111111, 0x18151512, 0x1319191d, 0x090e0e12, 0x03070709, 0x334c4b43, 0x0c035ab5, 0x2116150c, 0x262e2d21, 0x14141f27, 0x02050414, 0x48080802, + 0x2624052c, 0x32412b25, 0x0df6fd18, 0x0b0e2908, 0x0406070c, 0x0b060504, 0x120e0f0a, 0x15141312, 0x2a113201, 0x1a192121, 0x0e0f0d0c, 0x0b1e3c1d, + 0x00000708, 0x6a000100, 0x6120eb86, 0x181bc747, 0x1808276c, 0x183f6184, 0x18545584, 0x20564884, 0x2c008200, 0xff720002, 0x020e02fc, 0x001700db, + 0x19a7443b, 0x18141721, 0x4108e549, 0x737e05f7, 0xf9ad1809, 0x38012908, 0x0408152b, 0x08040505, 0x093e0786, 0x0c0b0605, 0x50161111, 0x14274d1b, + 0x10101212, 0x170c0e0e, 0x1e5d0b0b, 0x036e02a1, 0x8a190704, 0x60200c27, 0x091d2219, 0x07ae4e18, 0x24231929, 0x3244cc2d, 0x86030011, 0x82cc20a3, + 0x002f21a3, 0x32ef2019, 0xbda20720, 0x3119c920, 0x4b201e5b, 0x4518cc99, 0x5f2020c2, 0x002bdc9a, 0x00020000, 0x0137ff77, 0x82db02a2, 0x413320df, + 0x01201983, 0x1ad9d918, 0x2b920125, 0x82040816, 0x2c082200, 0x24078415, 0x274eddfe, 0xd9d9182d, 0x1074410e, 0x38c9fc24, 0xdb181e12, 0x022c1124, + 0x00000800, 0x0e026802, 0x5f005100, 0x250f7d68, 0x36373635, 0xcf783635, 0x44072033, 0x062105c3, 0x06716323, 0x2b07a74b, 0x16060c08, 0x0b0b1011, + 0x01030807, 0xd33d0083, 0x1b040747, 0x16161818, 0x0e0e1213, 0x07060607, 0x13120d0d, 0x19191616, 0x5617481b, 0x3c21821c, 0x05040302, 0x0d090a06, + 0x0d0b0b09, 0x1b15150e, 0x048b010f, 0x191a3403, 0x06341a19, 0x12e35501, 0x04369f3c, 0x0d090805, 0x1612110d, 0x161a1b15, 0x0d111116, 0x0508090d, + 0x72560104, 0x13823163, 0x1718182f, 0x14171817, 0x080b1015, 0x03070709, 0x0a064c04, 0x0002002d, 0x02000035, 0x000e0263, 0x4c3f0031, 0xcf780a7b, + 0x115d640e, 0xd3782320, 0x26eb870c, 0x89153f35, 0x83153f2d, 0x161923e0, 0xe0821216, 0x83070621, 0x121321e0, 0x4730e084, 0x3f2e8818, 0x02054901, + 0x1a1a1934, 0x02053419, 0x9706b955, 0x3db523c1, 0xad893cb6, 0x21000122, 0x2b20ab82, 0x3d2fe618, 0x18478033, 0x17441847, 0x38a838a8, 0x3a2a2919, + 0x452a2b55, 0x2aa18317, 0x211d1415, 0x11111919, 0x46440909, 0x362d0fc7, 0x26726a35, 0x1a233365, 0x0811111a, 0x08ee4608, 0x58020021, 0x03250573, + 0x00130006, 0x18cf4645, 0x5b0f4778, 0x01351e97, 0x1a1a1105, 0x0c0c0e19, 0x0b214209, 0x1d0f0e0e, 0x3a141e1d, 0x2a9e58a3, 0x16550222, 0x0f012619, + 0xdb18ab20, 0xd7822c02, 0x00006124, 0xd7840d02, 0x0d4b3320, 0x20ef5915, 0xd94a4e20, 0x0c0d290a, 0x1a1a190d, 0x00ff3a11, 0x1917eb59, 0x83115c27, + 0x19935ab2, 0x24053355, 0x001700dc, 0x1a935a71, 0x55468778, 0x0124114d, 0x272805d6, 0x5a069778, 0x2b2607cd, 0x2c071918, 0x67559afe, 0xdc022156, + 0x210f0d5b, 0x7a555bfc, 0x00012550, 0x027aff5e, 0x22067759, 0x66353405, 0x5f52055b, 0x23223109, 0x01221514, 0x452c840e, 0x453db717, 0x392c8417, + 0x280c4653, 0x21658476, 0x10000200, 0x05576f00, 0x67076951, 0x4f440561, 0x05934a07, 0x32333222, 0x072d9918, 0x2c150352, 0x62216192, 0x8a1a4c20, + 0x2e2e8a2e, 0x05076816, 0x2e3b7f23, 0x0d6f6f16, 0x01113322, 0x075dea18, 0x4a133a23, 0x183b6919, 0x19000222, 0x50229382, 0x3969db02, 0x44939808, + 0xcb690be7, 0x5e963a17, 0x44205d1f, 0xa0369f17, 0x342b5535, 0x1e1d2929, 0x0e0f0f0f, 0x29291e1d, 0x14a55235, 0x3373572b, 0x99339a11, 0x6d113334, + 0x22ab5224, 0x09d34718, 0x3f002d22, 0x181d8971, 0x2011d347, 0xaf5d1813, 0x1822200b, 0x361ecf47, 0x0360bf77, 0x10100908, 0x26271a1b, 0x10101b1b, + 0x0f210809, 0x83261c1b, 0x090f280b, 0x5fc00309, 0x71080902, 0x35211895, 0x889a183e, 0x2f2f2309, 0x5518bbfe, 0x39220911, 0x4c182c2d, 0x02260853, + 0x0023001b, 0x54180035, 0xf14d104b, 0x06072213, 0xa3481825, 0x08615e10, 0x84072b4c, 0x201583d3, 0x0bf16401, 0x1f0f0f2d, 0x1612130f, 0x1e1a1a15, + 0x642d2d3b, 0xa23206ae, 0x09035fbc, 0x1a111108, 0x1a23241a, 0x0911111a, 0x24823f09, 0x1318182e, 0x0a0f0f12, 0x0408080b, 0x5db90205, 0x08056052, + 0x23390b27, 0x12111112, 0x34332423, 0x33334343, 0x0e0d1124, 0x04050909, 0x23231212, 0x43443333, 0x29c23334, 0x18182121, 0x3600820c, 0x21211818, + 0x06050af8, 0x0a0a0506, 0x11110d0e, 0x15151313, 0x82111313, 0x6f7d1831, 0x4e032307, 0x49471100, 0x34240806, 0x32353637, 0x20151433, 0x22151023, + 0x017dfb6c, 0xfe143f01, 0x024c5af2, 0x2e1baf0e, 0x38a81b2d, 0x009b2dfe, 0x9f273782, 0x17020000, 0x5c00a202, 0xc14d051b, 0x83222007, 0xd49f3135, + 0xd5184547, 0x8b014547, 0xaf256f83, 0x6eb6fe3b, 0x2f202f82, 0x3e242f82, 0x1b00bd02, 0x220a6155, 0x84203534, 0xa5ed1869, 0x3271270a, 0x01113110, + 0x7282735a, 0xcd44cd35, 0x25014c44, 0xae143c61, 0x72143b39, 0xfe143c26, 0x830062dc, 0x825d207b, 0x0217224b, 0x214b840e, 0x19433534, 0x05854d07, + 0x14254b87, 0x319f2215, 0x364b8211, 0x47d55e1a, 0x349c349c, 0x3d3ab045, 0x40349f14, 0x3c205d16, 0x833baf15, 0xff572447, 0x7526023f, 0x052005b7, + 0x210a7945, 0x1b483435, 0x18152007, 0x540d75fd, 0x0f5608dd, 0x01500809, 0x210b1427, 0x0e0e1718, 0x1f200807, 0x4c22653e, 0x745b011a, 0x685bf2fe, + 0x26252f33, 0x0e0f1b1c, 0x1a1a0d0d, 0x1d392929, 0x09143cc1, 0x20121109, 0x2d5b2d20, 0xfb25254b, 0xaf0e0253, 0x349c143b, 0x1b1c0e0e, 0x6037292a, + 0x2e2e3f30, 0x0f0e1d1d, 0x72249783, 0x1a0237ff, 0x434fdf82, 0x5f322005, 0x77690c7f, 0x05ff4d08, 0x89064f6b, 0x54a386fb, 0xab8a090f, 0x1c3a0d2c, + 0x0a0e0e13, 0x0406060a, 0x00820204, 0x04056708, 0x0c0d0808, 0x62161111, 0x01174520, 0x47d45d1a, 0x1a212a53, 0x0f15141b, 0x080a0b10, 0x02040308, + 0x140a0b03, 0x2d202115, 0x1238c949, 0x06050302, 0x0d0d0908, 0x52171212, 0x13131b2a, 0x07070c0d, 0x02020303, 0x8b0139ac, 0x6b164083, 0x04020224, + 0x0a070704, 0x110e0e0a, 0x1b151612, 0x24322a55, 0x0b171725, 0xd383000c, 0x68ff072d, 0xbd026102, 0x00005700, 0x7a353405, 0x2320208f, 0x7a073d43, + 0x322825df, 0x22151433, 0x04090c02, 0x21199a7a, 0xe27a2142, 0x0a082d21, 0x17150c0b, 0x07160f17, 0x2672983f, 0x7a1ba37a, 0x16351fe7, 0x3c201d1e, + 0xae293f3e, 0x0001003a, 0x027aff1e, 0x000e0257, 0x54fbb05d, 0x336505c3, 0x06014123, 0x64091121, 0x3c2119dc, 0x2d30651d, 0x1d194d27, 0x6486380a, + 0x1bdf6422, 0x312b2f65, 0x339a42c8, 0x01000000, 0x47ff4500, 0xcb021c02, 0x0c828b00, 0x0a2b5518, 0x220bc964, 0x19272223, 0x180a996e, 0x570cadbd, + 0x694508f1, 0x072d500b, 0x083b097c, 0x13f50124, 0x0e0e0a0a, 0x28281c1d, 0x08090b33, 0x03020605, 0x163c1e1e, 0x07161615, 0x0a0a090a, 0x21090909, + 0xe4421010, 0x30092405, 0x7c323031, 0x01354827, 0x1d1d1736, 0x23242b24, 0x100f1b1b, 0x0c0c0d05, 0x0b0c0b0a, 0xc993180b, 0x07072a12, 0x0b0b0809, + 0x0809010d, 0x484e7c11, 0x0001002e, 0x0247ff55, 0x001b0214, 0x25000087, 0x50318f41, 0x34210777, 0x0ac94735, 0x662b8f41, 0x013113d1, 0x090a13ee, + 0x1b1b0e0d, 0x0c322627, 0x06050909, 0x078b4103, 0x09090824, 0x03820a0a, 0x100f2031, 0x04040102, 0x150a0807, 0x15161616, 0x66191817, 0xf13340f3, + 0x1b171711, 0x151b1b21, 0x040d0d15, 0x0b0c0d0d, 0x180b0b0c, 0x22077894, 0x18030314, 0x2d085095, 0x08090808, 0x010e0b0b, 0x05030302, 0x1c670705, + 0x06134340, 0x64026826, 0x3100bd02, 0x71102344, 0xd57c0931, 0x33322113, 0x012f1f82, 0x1d060afa, 0x172b2d2d, 0x3a101515, 0x7c194c13, 0x1e210dda, + 0x3419822c, 0x2b101514, 0x7298500e, 0x41402b26, 0x1e1e223e, 0xcd143917, 0xcd451845, 0x3e29270e, 0x1c203c3d, 0x9775161d, 0xff6c2807, 0x024f027a, + 0x9033000e, 0x07062193, 0x294e9595, 0x30958507, 0x19050aed, 0x13252626, 0x0d0e1212, 0x480d1515, 0x08134e17, 0x254b0f22, 0x35078c5f, 0x11322f8d, + 0x2264864a, 0x30323221, 0x1118171a, 0x0b13130b, 0xfe4d359e, 0x3cb62814, 0x000037a5, 0x751f0001, 0x2b7c0c2b, 0x08577208, 0x32353425, 0x85151033, + 0x4cfe2183, 0x096d8d18, 0x1a50192a, 0x2672984f, 0x53fb54fa, 0xd723f982, 0x7547d848, 0x53820626, 0x5b5e5b20, 0x21539c0c, 0x4d4c0702, 0x22058505, + 0x82491849, 0x3cb223bd, 0xb3823bb3, 0x9d359c27, 0x6eb6fe34, 0x82a682a5, 0x006a2453, 0x48680200, 0xbf5d08f3, 0x05554c05, 0x66232221, 0x6a2d0a17, + 0x2e881846, 0x246a3ab0, 0x2d891745, 0x24998646, 0x2dfe143b, 0x82a9839b, 0x845c2047, 0x05ef4847, 0x210b277d, 0x478c1514, 0x153f5c28, 0x3ab0349a, + 0x07832670, 0xa7503f20, 0x11352806, 0xb572aafe, 0x823cb63d, 0xff462847, 0x02190247, 0x4f5500cb, 0x23250521, 0x15060722, 0xd9f01814, 0x0a796e0c, + 0x561e8145, 0x14210f97, 0x33118215, 0x1715cb01, 0x30621716, 0x62303131, 0x262a292e, 0x211f201e, 0x430e4945, 0x102007bd, 0x0805bd43, 0x4309072a, + 0x25253434, 0x14141212, 0x38382728, 0x29292c48, 0x14131326, 0x04076e02, 0x90474804, 0x0f48488f, 0x20411d0f, 0x03090810, 0x2f1a1745, 0x08090708, + 0x030d0b0a, 0x30301919, 0x56534141, 0x0daa1319, 0xee820020, 0x82530021, 0x020324fb, 0x8965001b, 0x0beb5bfb, 0x20086349, 0x083d6e14, 0x83390b41, + 0x02143e39, 0x26272203, 0x23222c2b, 0x0c0b1717, 0x17170c0c, 0x172c2223, 0x14131414, 0x0f101211, 0x3101820e, 0x0c100e0f, 0x05050908, 0x1e1e0203, + 0x1516163b, 0xc4820817, 0x0a0a0a34, 0x10102009, 0x04030202, 0x3b090707, 0x23222f2f, 0xaf571011, 0x9801220e, 0x213f821d, 0x15191a0d, 0x07260d5c, + 0x3c0f0b0a, 0x895d091e, 0x41012005, 0x44461a2c, 0x13032706, 0x31242513, 0xc5573f32, 0x0045290d, 0x18000100, 0x510268ff, 0x0c134818, 0x09ad6118, + 0x22075743, 0x7d194c67, 0x50310625, 0x7298501b, 0x9cd20126, 0x143b143b, 0xae8769fe, 0x2443833a, 0x017aff6a, 0x08df62fe, 0x0d336518, 0x62224387, + 0x61661745, 0x19492f06, 0x22648649, 0x3f6e4c01, 0xfe153f15, 0xe74359f5, 0x00122405, 0x82560200, 0x7c292087, 0x0d490c8b, 0x118d5909, 0x22151424, + 0xae180101, 0xae1824f8, 0x012625d4, 0x37ff2e00, 0xc7823a02, 0x05208382, 0x289baf18, 0x5d040121, 0x412e07c3, 0x1e1f1420, 0x0e0e101d, 0x1f1e140b, + 0x07820f1d, 0x0e204235, 0x26151212, 0x481a2827, 0x22458cc9, 0x5b322d2c, 0x193f5f60, 0x2b0fda26, 0x322c2d21, 0x3f605f5c, 0x0100359c, 0x085f4918, + 0x00003923, 0x09ef4c21, 0x236d8018, 0x250a0d4d, 0x21630101, 0x1b412163, 0x22642e23, 0x944c2264, 0x19143c32, 0x47472f0c, 0x5fad1945, 0x091c261b, + 0x3195143c, 0x41a38200, 0xa3820727, 0xa3b90520, 0x194b0424, 0x3b41194b, 0x27278323, 0x1c56c948, 0x08101235, 0x251f4341, 0x12350612, 0xa3821d55, + 0x68ff0928, 0xbd025f02, 0xcf464f00, 0x41312005, 0x2b6c0741, 0x09754c09, 0x420f794b, 0x1f44116b, 0x46172006, 0xf5330567, 0x10100c02, 0x21222111, + 0x24241817, 0x11111323, 0x1824490d, 0x822bcf81, 0x1222083d, 0x17232222, 0x98500d26, 0x1a142672, 0x38351d1a, 0x37252537, 0x1a1d3538, 0x2018141a, + 0x44422420, 0x81182e44, 0x13271fd2, 0x341b191a, 0x43233636, 0x30260583, 0x4d027aff, 0xef870e02, 0xc308096d, 0x05ea24ef, 0x421e1403, 0x1e3807d9, + 0x0e0f0f1d, 0x1b24470a, 0x15272829, 0x0d0e1313, 0x23141111, 0x44182525, 0x28096067, 0x0e1a1b1c, 0x450a0c0d, 0x067c6722, 0x1c120d32, 0x0d0e1b1b, + 0x12340a0d, 0x2264864a, 0x2626271a, 0x0b6b9a19, 0x32332133, 0x17181a31, 0x15161112, 0x2e2e2d18, 0x2323171f, 0xab9a1922, 0x22173513, 0x11122123, + 0x37a50c10, 0x50000100, 0x2d020000, 0x5700be02, 0x41105770, 0x332306bd, 0x19323732, 0x210de530, 0xe8181615, 0x4555199f, 0x1415310f, 0x4c502215, + 0x0b0b0919, 0x0303060c, 0x0d0c090c, 0x0e2af582, 0x0304060e, 0x1212150c, 0xcc820f10, 0x00830220, 0x1601013a, 0x194c0a0a, 0x0e0e0607, 0x0c1d1615, + 0x0c0b0d0c, 0x060b0b0b, 0x03040505, 0x083d0182, 0x04050607, 0x024c0302, 0x6bd5af0f, 0x07080709, 0x06020103, 0x03040305, 0x01010203, 0x220a8202, + 0x82090707, 0x390d8345, 0x29281a01, 0x953baf36, 0x1b1a244a, 0x08081010, 0x02030101, 0x02050304, 0x02820303, 0x0904042b, 0x10100d0d, 0x92141112, + 0x20fb8231, 0x22fb8261, 0x18db020d, 0x21087188, 0xea181514, 0x61272031, 0x29191745, 0x18563a2a, 0x24127ffe, 0xbdb72402, 0x77fe185f, 0x0001221a, + 0x206f8264, 0x05234603, 0x82183320, 0x6420161f, 0x0c5a5418, 0x0f365418, 0x00020023, 0x26438207, 0x00660361, 0x57630013, 0x33250f13, 0x37363732, + 0x086f5f32, 0x50250550, 0x48182055, 0x45201587, 0x18211850, 0x1824fb4a, 0x500fb748, 0x4b181f23, 0x0221260b, 0x054f7500, 0x1300f424, 0x27416f00, + 0x0fb74420, 0x41406575, 0x052a0b33, 0x2a2b1819, 0x2c071918, 0x4a505cfe, 0x247b752d, 0x44f4022e, 0x22212122, 0x12112444, 0xfd241112, 0x75085f75, + 0x452a4c8b, 0x5c023fff, 0x4700bd02, 0xf3530000, 0x1dd94c14, 0x21083d44, 0x57531415, 0x1513300a, 0x1818220a, 0x07070e0d, 0x393e1f1f, 0x4d0f2c13, + 0x503a0b81, 0x19191327, 0x3536331c, 0x2d040924, 0x1d1c2525, 0x0d0c0e0e, 0x2a291a1a, 0x13541c39, 0x0f2d210e, 0x2e0e914d, 0x1b191912, 0x23353434, + 0x1b1c0d0e, 0x5438292a, 0x6c240c23, 0x2c0237ff, 0x54085352, 0x06211d23, 0x54d5a607, 0x0b201435, 0x310b3554, 0x05020201, 0x0d080804, 0x1611120b, + 0x0604254a, 0xd54d0405, 0x301f2d0d, 0x16192d2f, 0x0a131116, 0x151a1b20, 0x20054854, 0x26485409, 0x06060323, 0x0ef94d03, 0x2a2a1c27, 0x14141529, + 0x1a5a540f, 0x0001002b, 0x023fff45, 0x00bd0224, 0x10d3412b, 0x0d6f4018, 0x32353422, 0x0965c018, 0x01222332, 0x210b1425, 0x0e0e1818, 0x45cf0607, + 0x194c194c, 0x1a250582, 0x1a1a0c0d, 0x0caf552a, 0x4e47d621, 0x4e36092e, 0x2e2e40da, 0x0f0e1d1c, 0x01000000, 0x37ff6600, 0x0e021202, 0x778d2f00, + 0x37363724, 0x6b5e3536, 0x0e934e06, 0x53461420, 0x3e7b8205, 0x131d3905, 0x0a0a0d0e, 0x04040607, 0x3cb70202, 0x17461746, 0x17453db6, 0x14150a0a, + 0x552e2021, 0xb9210e70, 0x095e4e3e, 0x55b29b21, 0x41240b57, 0x1f0268ff, 0x2005f346, 0x20df8305, 0x77471834, 0x236d840b, 0x07222322, 0x180a1b62, + 0x18114b45, 0x180c4745, 0x390bc589, 0x23221510, 0x01221514, 0x071a504f, 0x060e0b0b, 0x090b0303, 0x100f0c0d, 0x0b830e0e, 0x280c2908, 0x05161f1f, + 0x09030303, 0x06050808, 0x1a4c0203, 0x0d0e0606, 0x0a1d1615, 0x0d0d0c0c, 0x0b0c0c0b, 0x07060808, 0x05050607, 0x4c2a1b83, 0xae98501a, 0x0956ac3a, + 0xf1460808, 0x03042405, 0x82010403, 0x090a2300, 0x0b820514, 0x100f0d33, 0x18191313, 0x8936a41c, 0x1b1b2444, 0x09081010, 0x05ee4602, 0x0506053e, + 0x0c0c0907, 0x13121011, 0xfd2c8515, 0x2672b0f2, 0x57000100, 0x03027aff, 0x39000f02, 0x8e067b41, 0x182320f7, 0x842055c8, 0x494622d9, 0x2ed98219, + 0x0201020f, 0x15080505, 0x551c1919, 0x5f462b2b, 0x172c0f5c, 0x864a1744, 0x3c7837a5, 0x090a0a0c, 0x032cb182, 0x050c0502, 0x6a353506, 0x2a541f5f, + 0x0d2e8318, 0xfe184926, 0x21658475, 0xe3289f82, 0x3f010000, 0x0700e002, 0x2e068b48, 0xe3221510, 0x02451745, 0xd8fdb828, 0x4b0300b8, 0x032705d3, + 0x00130066, 0x45450033, 0xf14c1ed5, 0x05e14609, 0x06232227, 0x22070607, 0x087b5a13, 0xd1492720, 0x0edf4606, 0x18292b23, 0x832d1918, 0x67561835, + 0x5d93180e, 0x3923290f, 0x39222239, 0x03012339, 0x0fb09f18, 0x0000002f, 0xff480003, 0x023402f3, 0x001700e8, 0x832d1999, 0x15142370, 0x03821516, + 0x0f5f7518, 0x1b481720, 0x26352308, 0x23432627, 0x54272007, 0x35210cb1, 0x71721822, 0x18037a0f, 0x17522b08, 0x2c1f1b1b, 0x0c192222, 0x0707090a, + 0x100f0303, 0x2f2e1f1f, 0x091f5d3c, 0x1a111009, 0x1818251b, 0x17191817, 0x0c0a1617, 0x00830d0b, 0x18306782, 0x191e1e22, 0x0b0a0b0b, 0x0709090b, + 0x03040405, 0x01260082, 0x01030204, 0x01890201, 0x21053e4a, 0x1b821f3e, 0x01020422, 0x2b080082, 0x090a0702, 0x0c0b0c0b, 0x0c0c0b95, 0x1f1e250f, + 0x0b0a1715, 0x1e28274d, 0x0a15151e, 0x1007070a, 0x02090a06, 0x222143e8, 0x10432122, 0x2306767a, 0x21fd2311, 0x92864218, 0x42040021, 0x172608f3, + 0x4f002f00, 0x6b186100, 0x0f4a3111, 0x28114308, 0x1ff36a18, 0x4651fe21, 0x52290762, 0x292a1c29, 0x14131629, 0x627d190f, 0x189d200c, 0x1810cea2, + 0x4323235f, 0x04202b30, 0x25062f43, 0x001700d9, 0x5919002f, 0x49438927, 0x1f87414c, 0x50435120, 0xd639198b, 0x438e2021, 0x02219260, 0x2a008200, + 0xbd024e02, 0x35002700, 0x47310000, 0x372006c9, 0x62091b5e, 0x078307c9, 0x46353421, 0x10200945, 0x06250b86, 0x26190607, 0x637f1925, 0x00032e4b, + 0x02f3ff14, 0x001b0258, 0x00770061, 0x0def6b97, 0x0f4d4818, 0x07222323, 0x05a37306, 0x17323324, 0x46181716, 0xa74f0e43, 0x19142008, 0x6c0b0f57, + 0x232009e5, 0x2206e348, 0x5f333213, 0xcf450823, 0x45072009, 0x9f490ae9, 0x5f781808, 0x0155080a, 0x2122143a, 0x1e1e2631, 0x0a0a1414, 0x18190d0d, + 0x2c302425, 0x3118180e, 0x211f1f1d, 0x1e212226, 0x121f1f2d, 0x0f0c0c08, 0x1a141510, 0x1117171d, 0x080d0d10, 0xa4040407, 0x07060152, 0x16150c0c, + 0x1f20271d, 0x21211c19, 0x17171b25, 0x0d0d1312, 0x05297b20, 0x06d67504, 0x09107808, 0xe5050609, 0x14100f0b, 0x09111018, 0x02030305, 0x10010103, + 0x1c1c2908, 0x09080f10, 0x253d0606, 0x0a0a1213, 0x1d1d1414, 0x201f2a25, 0x0a0b1514, 0x1d3b0d1c, 0x130a0a1d, 0x08101a35, 0x1e0f0f08, 0x080b0b0d, + 0x06040409, 0x140c0c06, 0x271b1c14, 0x0a202f26, 0x05030404, 0x1d28060d, 0x0911111c, 0x170c0d09, 0x0a141b35, 0x0a050409, 0x010e0e0a, 0x23081009, + 0x820f1a1a, 0x08082b3c, 0x1a1b1010, 0x0ce90f25, 0x0b820605, 0x1e830820, 0x18131323, 0x2b918219, 0x12120a0a, 0x12111818, 0x02000000, 0x084b6918, + 0x2b001322, 0x6e168d48, 0x202105e7, 0x09535423, 0x14332026, 0xda012015, 0x13f15e18, 0x69189720, 0x51480f21, 0x0d69180e, 0x00032e0e, 0x02f3ff3e, + 0x00e8022c, 0x004f0017, 0x5d818f6b, 0x322008e9, 0x20548571, 0x67c189d8, 0x1127051b, 0x18182b17, 0x71172c07, 0xa5474b7d, 0x71152011, 0x00203f6d, + 0x0a8b9b18, 0x49003722, 0x210f5d43, 0x09432035, 0x15037711, 0x83652520, 0x1425080d, 0xf1011617, 0x402f301f, 0x1f2e2f3f, 0x01100f1f, 0x08096327, + 0x1d1d1111, 0x14141328, 0x14141516, 0x13141412, 0x3e078215, 0x2f304015, 0x0f101f20, 0xbafe100f, 0x251b1c11, 0x101a1b25, 0x0309090f, 0x09085fbf, + 0x82162e4d, 0x2d230800, 0x5c45452c, 0x01030a1d, 0x212c2d39, 0x04101021, 0x0b080704, 0x21400d0b, 0x0507070a, 0x17030304, 0x822d2c17, 0x445c2321, + 0x68820344, 0x1e0f0f2a, 0x3c2d2d1e, 0x002c2d3a, 0x4728db83, 0x3502f3ff, 0x3b001b02, 0x210ff177, 0xdb903435, 0x19e35b18, 0x06070622, 0xb927df92, + 0x2722221d, 0x822b2c37, 0x0f2008df, 0x0c642a01, 0x2218180b, 0x312c2b21, 0x191b3631, 0x1817181a, 0x252b1818, 0x181f1e26, 0x08111018, 0x57080082, + 0x16171011, 0x1a12f2fe, 0x1c22211a, 0x0d15161b, 0x65ca050c, 0x1014090a, 0x10110809, 0x2f2f2222, 0x020b1f3b, 0x21212b01, 0x0c0b1818, 0x391b0d0d, + 0x08070a1d, 0x02020605, 0x11110808, 0x1f1e1818, 0x2a2a2525, 0x201f2524, 0x143e1918, 0x0a0b0a0a, 0x1d1d1414, 0x1d1e2626, 0x0422e782, 0xe7823a00, + 0x66032e23, 0x059b7400, 0x17497920, 0x18132031, 0x410cf987, 0x1d82101b, 0x4727f741, 0x30201fa7, 0x493f1642, 0xfd21213d, 0x3d394246, 0x42000421, + 0x4f490537, 0x006b2205, 0x19bf6f7d, 0x4125eb75, 0x6b42104f, 0x3000212f, 0x2905cd75, 0x08183007, 0x04030304, 0x831930bc, 0x12200d2b, 0x20438b42, + 0x21b54802, 0xae429920, 0x03002143, 0x2408b755, 0x002f0017, 0x31ad427f, 0x424fd555, 0xfe211fb3, 0x47e05546, 0x222ccb18, 0x61183320, 0x03204400, + 0x7306f355, 0x8b20055f, 0x563c6341, 0x6f415011, 0x565d2020, 0xd273531c, 0x93fd2120, 0x872b8c66, 0x1bdc662b, 0x03000028, 0xf3ff4500, 0x9b451c02, + 0x41952006, 0x99453187, 0xcb551808, 0x2b216510, 0x0c994618, 0x6007a165, 0xee200a9f, 0x0ec0b718, 0x182fbc24, 0x00820407, 0x17300723, 0x21068208, + 0x62181d04, 0xcc4556da, 0x18222022, 0x2758fd62, 0xff550003, 0x021402f6, 0x2005e745, 0x3f9b418d, 0x64183320, 0x2320103d, 0x210c136c, 0x71792627, + 0x3534210c, 0x12d34818, 0x200bc168, 0x0f9341ef, 0x0e308919, 0x4d181520, 0xff454eaa, 0x16a62122, 0x4fcd4d18, 0x0d000128, 0x5b02f3ff, 0x5718bd02, + 0x35220fe9, 0x8a183332, 0x40180adf, 0x23200d79, 0x20083f47, 0xd9ce1837, 0x10bd6c0f, 0x06072708, 0x37260e02, 0x37474836, 0x13262636, 0x0c224313, + 0x2518190d, 0x24302f24, 0x0c181925, 0x170b0c0d, 0x28212117, 0x7c5f1542, 0x233a0805, 0x5decfe16, 0x17796c01, 0x12212223, 0x1a0d1010, 0x1d1d1c1c, + 0x0b141819, 0x05050708, 0x13130202, 0x0e0e1c2b, 0x1c1c0f0e, 0x22342829, 0x11121a1a, 0x09080809, 0x1a191211, 0x48752021, 0x1a343d05, 0x1412120d, + 0x1a262624, 0x1a34143b, 0x2426261a, 0x0d121214, 0x0c0c0706, 0x0d191212, 0x0e273b82, 0x33110f0f, 0x82002828, 0x00012a00, 0x0233ff49, 0x000e0234, + 0x0eb37b4d, 0x70190969, 0x34240913, 0x14332035, 0x8a086b64, 0x152108f7, 0x01060714, 0x353526e7, 0x18181844, 0x1a1b1819, 0x31312b1c, 0x24243037, + 0x0d0d1819, 0x17170c0c, 0x2def8320, 0x2627281a, 0x0e131215, 0x480153fb, 0xa784196d, 0x190e1124, 0xee821b1b, 0x14151a38, 0x13130a0b, 0x0e0e1d94, + 0x04030302, 0x3d090707, 0x0c0b171e, 0xc2820809, 0x21211924, 0xf6831818, 0x1a352308, 0x2a2b2b1d, 0x10141416, 0x1b341133, 0x2829291b, 0x0f131415, + 0x0c0b0505, 0x191a1313, 0x33211d1d, 0xe3822728, 0x09fb6518, 0x82000721, 0x5c13200f, 0x2221054d, 0xef651803, 0xe09f241e, 0x18a3e14b, 0x2617dd65, + 0x34113421, 0x18dffc11, 0x181cd565, 0x2107c34f, 0x779100b2, 0x18151421, 0x570d6766, 0x222009f9, 0x88207783, 0x2017b175, 0x2177836d, 0x4f1893fd, + 0x00231a91, 0x18000300, 0x5407b76e, 0x002205a3, 0x49582213, 0x37342406, 0x74323336, 0x15230503, 0x4a060714, 0x01201739, 0x471e1941, 0x8520203b, + 0x48173641, 0x5241227b, 0x60db821c, 0x53480523, 0x454f2005, 0x4177312f, 0x20dba01f, 0x179a41a0, 0x21398018, 0xb6419220, 0x4d00201c, 0x4b220d43, + 0xddb16b00, 0x18141321, 0x20112d43, 0x06974333, 0x27580120, 0x0d09460c, 0x17141523, 0x20f99f16, 0xd6aa186d, 0x5e661818, 0x215d471b, 0x1857fe21, + 0x191007cf, 0x2625f008, 0xff450004, 0x472402f3, 0x4f22063b, 0x2f415f00, 0x0c734e32, 0x0d5da518, 0x13ef5918, 0x241f2341, 0x2c2d1e25, 0x3509193b, + 0x21e94c25, 0x8118be20, 0x8c192879, 0x02250807, 0x001b00cb, 0x937e1831, 0x05b74ac6, 0xcb762420, 0x510520ec, 0x4b240c47, 0x73006100, 0x4432d542, + 0xbb781a05, 0x18072011, 0x42148f80, 0x0d441fe9, 0xae801819, 0x3a194427, 0x21d08018, 0x1b440520, 0x0053220c, 0x33e34f65, 0x790d9152, 0x5341413b, + 0x063d441f, 0x1f1f2c23, 0x7900820f, 0x4a4b3e5a, 0x79be2022, 0x0028437d, 0x59000300, 0x2c02f3ff, 0x20065f4e, 0x32af4275, 0x4e078545, 0x3721105f, + 0x20018236, 0x69821822, 0x2b64180b, 0x4cf02019, 0x172810ab, 0x04040308, 0x182f0803, 0x222a0784, 0x47383728, 0x262a2a2c, 0x64181413, 0x162d084a, + 0x0b0f1015, 0x0106060b, 0x69d14fed, 0x4b641806, 0x262b2e0c, 0x2c2a2a26, 0x28373847, 0x13131428, 0x21ad4214, 0x304bfd22, 0x386e6418, 0x00030027, + 0x02f3ff6c, 0x06cb461d, 0x43417d20, 0x0b535831, 0x0ddb7e18, 0x334b4e18, 0xdc53ec20, 0x0c8b4f0e, 0x04030323, 0x6a4e181a, 0x13142e09, 0x2d27261f, + 0x1521222d, 0x020d0c16, 0x6a4e18cb, 0x130e2508, 0x1e191812, 0x1b6a4e18, 0xa2421820, 0x18982022, 0x2c428d4e, 0x003e0002, 0x034b0200, 0x00070066, + 0x73ed1851, 0x18032009, 0x2646a740, 0xe0a92223, 0x188ee04b, 0x2046016d, 0x06594c03, 0x79183d20, 0xf2823f15, 0xff340027, 0x02410237, 0x20f782b2, + 0x6cf7d161, 0x232a0f59, 0x4be09f22, 0x12248de1, 0x5719090c, 0xe0183167, 0x6d2521fb, 0x11341134, 0xf05419fc, 0xf8561831, 0x42032021, 0x1724081f, + 0x79002f00, 0x18316957, 0x18074147, 0x700ce977, 0x611823d9, 0x07240ce3, 0x01222306, 0x211f6557, 0x67429bfe, 0x228a4d47, 0x20428342, 0x06834203, + 0x1700c826, 0x89002f00, 0x4131d744, 0xad42475b, 0x1f8d4711, 0x3ee15719, 0x18020321, 0x2518c6e3, 0x07040468, 0xdc54162c, 0x21079405, 0x4418cffc, + 0x00225064, 0xe7420000, 0x000b2709, 0x00610017, 0xa5181300, 0x2220094b, 0x0b351219, 0x25477341, 0x13b62223, 0x1c191f1e, 0x8c2d07f2, 0x121f2012, + 0x2416203e, 0xfe3b1524, 0x46c642fe, 0x094ce318, 0x89181820, 0xb6420863, 0x42002042, 0x032506b7, 0x000b0006, 0x59e61815, 0x0706290a, 0x33220706, + 0x33323736, 0x29410984, 0x119d4247, 0x0cc5ec18, 0x3c194d2a, 0x2727171d, 0xfffe3217, 0x24575e45, 0x37372156, 0x21038321, 0x05832c84, 0x42e1fc21, + 0x03265181, 0x00003f00, 0x274a1d02, 0x446f2006, 0x0320310b, 0x18082553, 0x21355771, 0xba5c2ff1, 0x58082005, 0xbc200659, 0x0eb7ca18, 0x161a053b, + 0x15131316, 0x14141714, 0x10121314, 0x0b0e0e10, 0x0408080b, 0x03194d05, 0x76711804, 0x0c0d210a, 0x0a767118, 0x2121174a, 0x7118f9fc, 0x002f399a, + 0x00530003, 0x02ff0100, 0x001700cd, 0x4167002f, 0x5b183b33, 0xfb202d4f, 0x200ee957, 0x0e2b41bb, 0x07032322, 0x126e5b18, 0x08040436, 0x0d0b0b09, + 0x100f100e, 0x0d111112, 0x100e0f0e, 0x02451745, 0x20071a53, 0x06f84404, 0x075c9318, 0xfd210f88, 0x925b1892, 0x01003031, 0x68ff6c00, 0xbd023902, + 0x00001300, 0x18353417, 0x7909e744, 0xd128069b, 0x5a01194c, 0x5af2fe73, 0x2205327d, 0x79af0e02, 0x92260adb, 0x0a027aff, 0x3b8e0e02, 0x737d4382, + 0xee210805, 0x1a011745, 0x4947d55e, 0x64864a19, 0x838b0122, 0xf7fe1640, 0x0037a559, 0x00050000, 0x02000029, 0x06c7423f, 0x59005124, 0x33486f00, + 0x07037d32, 0x180e3557, 0x1809cd4e, 0x221d135b, 0x5b30ff00, 0x1822071e, 0x00820308, 0xb24bbb20, 0xfe35080e, 0x1e194c60, 0x1d1d210f, 0x14151919, + 0x07070f0f, 0x0f0f0708, 0x19191514, 0x6d211c1d, 0x194c8c01, 0x1e9bfe4c, 0x16161a0f, 0x08091110, 0x100f0707, 0x211e1716, 0x23ce420c, 0x318d7218, + 0x05000029, 0x00003400, 0x55023402, 0x492205b7, 0xcb425100, 0x06bb5533, 0x410abf72, 0x2321052d, 0x1d2b4122, 0x2020e947, 0x605c1873, 0x5a97182b, + 0x18932022, 0x2129845c, 0x80180000, 0x9b7e1627, 0x8b37200a, 0x0ab15b0b, 0x11435518, 0x0f4d5318, 0x1289b418, 0x4b083f82, 0x1c021437, 0x33343435, + 0x2330313e, 0x09111222, 0x1c13140a, 0x2143251c, 0x0f070822, 0x1b15150e, 0x241f1f1b, 0x18161513, 0x1e1b1b17, 0x1819191b, 0x13151618, 0x131b1a24, + 0x0a090912, 0x1c131309, 0x1439241b, 0x1e261934, 0x0b16161f, 0x16320082, 0x2a202116, 0x18191818, 0x1a191919, 0x08091216, 0x4e820d0d, 0x2431262e, + 0x17171d1d, 0x10091111, 0x1d3b2526, 0x112e4483, 0x060c0b11, 0x03030206, 0x08050604, 0x3d651d3a, 0x07022105, 0x14357482, 0x141b1a15, 0x070e0f15, + 0x09133b07, 0x18121209, 0x18212019, 0x289a8219, 0x06030208, 0x0d0a0906, 0x836a1847, 0x27ac100c, 0x02381101, 0x5bff3a00, 0xcb025902, 0x65004500, + 0x26050000, 0x26312627, 0x30232207, 0x9d18018a, 0x352108e5, 0x09b56a34, 0x76096370, 0x0d19070b, 0x222008a5, 0x361f3158, 0x301de301, 0x0405024b, + 0x080a0903, 0x02050607, 0x302a1b02, 0x82101f1e, 0x1f250800, 0x3e2f2f1f, 0x181b1b1f, 0x10141418, 0x080f0e20, 0x0b081109, 0x0f0d0d0b, 0x332d120f, + 0xfe582233, 0x1c1c11c5, 0xc50b1a25, 0xa5320816, 0x024b2f1d, 0x2d181501, 0x5742432d, 0x455c0305, 0x162d2d45, 0x0b050617, 0x1711110b, 0x5c454131, + 0x2a383844, 0x10111215, 0x090b0c0f, 0x2031312c, 0xcf182701, 0x02311c01, 0x36ff4200, 0x1a020d02, 0x33002300, 0x34050000, 0x17f55735, 0x24050f4b, + 0x01221510, 0x65a41814, 0x0125080d, 0x252617b0, 0x27283234, 0x0e0f1d1d, 0x1d1d0f0e, 0x34322827, 0x02172625, 0x3f010303, 0xddfe4615, 0x44432122, + 0x08008221, 0x2143442b, 0x5ab2ca22, 0x12141429, 0x33252511, 0x32414033, 0x13252533, 0x28141413, 0x0c131211, 0x01b6e0fd, 0x343365cf, 0x65653334, + 0x22008233, 0x82000100, 0x68022700, 0x4900bd02, 0xa8180000, 0x40181aa7, 0x317a1b2f, 0x25db820d, 0x0e702207, 0xf3181514, 0x5522459d, 0xf3188181, + 0x00203d89, 0x0e20e388, 0x8320e3cd, 0x485df318, 0xf3184020, 0xe3833f49, 0xe3ff3b28, 0xbd022d02, 0xc16a5f00, 0x7f072005, 0x8e190a97, 0x03190ce5, + 0x332110b9, 0x039e1932, 0x8236200a, 0x0613630b, 0x0b831720, 0x36353623, 0x18318635, 0x26095773, 0x05082d02, 0x830b1204, 0x0a500800, 0x231c0c0b, + 0x2b382a23, 0x0b101e2b, 0x0408070c, 0x021a4c05, 0x09050502, 0x150e0f0a, 0x10121d15, 0x0e0f0d11, 0x0a0b0c0d, 0x0911070a, 0x08072308, 0x0c0a0a09, + 0x02030e0c, 0x01010102, 0x0201194c, 0x07070405, 0x10100e08, 0x0a0a122e, 0x06050525, 0x07370082, 0x07081006, 0x0e1c0d0e, 0x15161212, 0x011d191a, + 0xa8fe796d, 0x820e0dac, 0x0c0c2d00, 0x0505090a, 0x0d050203, 0x0c0c0d0c, 0x0b250382, 0x0c150605, 0x8289850c, 0x82082048, 0x07230803, 0xfe818301, + 0x1415a2bc, 0x0f111114, 0x07080d10, 0x00000008, 0x003f0001, 0x02280200, 0x004300cb, 0x44103300, 0x1364077f, 0x18152011, 0x620ae98e, 0x06270cab, + 0x14150607, 0x82332015, 0x14233003, 0x053f2215, 0x0c080804, 0x2a1e0f0c, 0x8239382b, 0x0c0f21fd, 0x3207aa4b, 0x09050403, 0x150f0f09, 0x151c1c16, + 0x090f0f15, 0x8205050a, 0x61222fed, 0x4c61defe, 0x1ea24501, 0x15161918, 0xde821212, 0x0e0f0f2f, 0x12120d1c, 0x18191615, 0x4513381e, 0x21df8223, + 0xfc180e0d, 0x0e200bb2, 0xa825f383, 0x9f143c38, 0x27c28235, 0x2b000200, 0x3e020000, 0x3327c382, 0x00005f00, 0x45353421, 0x5c180851, 0xdb6414e1, + 0x05514a08, 0x0320b583, 0x910ad76f, 0x0def75dd, 0x5a9b0127, 0x2b2a372d, 0x32d9821e, 0x04040809, 0x1f1e0f0f, 0x1c372b2c, 0x15161819, 0x86101213, + 0x0f2f3215, 0xa04c102e, 0x02032265, 0x0a090506, 0x15160e0f, 0x36f5831d, 0x040a090e, 0x02030205, 0x04030201, 0x0a070705, 0x110d0d0a, 0x82359f12, + 0x13103f43, 0x1d181813, 0x3042231c, 0x0e1e1d2f, 0x0704040f, 0x100b0b06, 0x1713130f, 0x221d1d18, 0xec832b81, 0x89240133, 0x10111145, 0x0d0d1010, + 0x05060a0a, 0x0a0b0605, 0x25378210, 0x13191717, 0x15821211, 0x0c0b0e31, 0x06060909, 0x00000303, 0x001b0001, 0x414e0200, 0x212105d7, 0x070f6610, + 0xd741db91, 0x11435905, 0x22061171, 0x82143332, 0x22038221, 0x42038b01, 0x1c3509be, 0x0e0f1516, 0x0405090a, 0x194c0203, 0x08080404, 0x1e0f0c0b, + 0x05f0412b, 0x2805ee42, 0x47184604, 0x58014c17, 0x15bc41ac, 0x321a4e23, 0x15f04119, 0x83319221, 0x2bbf82e9, 0x02f3ff3f, 0x00bd0228, 0x21000047, + 0x830a1746, 0x4b3520c1, 0x734205a3, 0x060b6407, 0x0f1b5318, 0x4f623520, 0x06157b05, 0x43820720, 0x168c012c, 0x381b1819, 0x0f1e2a2b, 0x404e0c0c, + 0x22012605, 0x61defe61, 0x26da8202, 0x0f0f090a, 0x831c1515, 0x090f22da, 0x05577a09, 0xda850520, 0x12130f25, 0x43030307, 0x83250d79, 0xae143c2c, + 0x0a7c4357, 0x09050626, 0x0e0c0c09, 0x0d300082, 0x19331b4f, 0x151a191d, 0x0e121216, 0x000a0a0f, 0x012d0082, 0x00003000, 0xcb023802, 0x00006b00, + 0x4d5a1833, 0x0c995408, 0xa5413620, 0x937c180b, 0x1da5410d, 0x860fa550, 0x33323f0f, 0x46201514, 0x0911194c, 0x1e1d1c1a, 0x0e0f0e10, 0x0b0c0c0d, + 0x020c0b17, 0x07050402, 0xae840b07, 0x16111236, 0x141e1d29, 0x4d090913, 0x11080919, 0x1d171711, 0x2521211d, 0x1733be82, 0x11151417, 0x02131328, + 0x06050502, 0x09080806, 0x820b0a0a, 0x0c5f0800, 0x0b0a0b0b, 0x87090a0a, 0x7598fe2d, 0x0b133927, 0x0d0b160c, 0x11100f0d, 0x2f281311, 0x1616362e, + 0x12141416, 0x090d0f11, 0x02060609, 0x180c0c03, 0x3c292a19, 0x03060207, 0x202b2b36, 0x0e171820, 0x0507070f, 0x0d070804, 0x3726120c, 0x16194837, + 0x14151516, 0x10111313, 0x0d100f10, 0x480c0d0d, 0x032a05b3, 0x0100143c, 0x00003c00, 0x474e2c02, 0x41332005, 0x474e0bf3, 0x3c203705, 0x27011a4c, + 0x62d8fe63, 0xc0fe51f4, 0x83af0e02, 0xfe143c2c, 0x3a825cee, 0x2c08d744, 0x004900cc, 0x37343300, 0x35343534, 0x17dd4436, 0x2008fd73, 0x18274334, + 0xe1441020, 0x013f2305, 0xdf440301, 0x181b2709, 0x12171619, 0xe3440f13, 0x3b922a22, 0x2e57595a, 0x1e202a2a, 0x08e64419, 0x07040426, 0x0f0a0b06, + 0x2005ea44, 0x06ea4419, 0x0e0d0f36, 0x0a090b0c, 0x04050505, 0x0c0c0a09, 0x0e0f0d0e, 0x6db9fe0e, 0x022cd383, 0xf3ff2500, 0xcb026202, 0x93006700, + 0x20121543, 0x054d4234, 0xcb443320, 0x10f3430e, 0x22151023, 0x08e94523, 0x0bb14418, 0x7d731520, 0x0a354309, 0x740bc77a, 0x07200fdd, 0x14202783, + 0x096f5f18, 0xbb014e08, 0x1212110f, 0x12151517, 0x0b0f0f13, 0x0c05060a, 0x1d18180b, 0x1134241e, 0x04040201, 0x09080606, 0x0f0f0c0b, 0x1f181313, + 0x11101818, 0x06070c0c, 0x18490404, 0x21211111, 0x3c3c2f2f, 0x10212e2f, 0x09080d0d, 0x10310504, 0x03031031, 0x232f8407, 0x076f0d0e, 0x08350082, + 0x06070808, 0x09050506, 0x172e0404, 0x080a0b0d, 0x03060508, 0x08008201, 0x0904042a, 0x07050604, 0x05050303, 0x11100b0b, 0x1e1e1717, 0x29293725, + 0x0e0d1b1a, 0x191e0407, 0x10141418, 0x090d0d11, 0x0206060a, 0x0a212283, 0x2e228211, 0xfe261e1f, 0x25016bc0, 0x34334592, 0x82112323, 0x122333b3, + 0x1a1a1515, 0x11241e1f, 0x5a143f06, 0x15161a2c, 0x37821314, 0x0a0a0e3a, 0x0201033e, 0x03030202, 0x10080506, 0x64251919, 0x07040422, 0x130e0d07, + 0x093a9382, 0x0a090908, 0x0f1a1a26, 0x00060508, 0x23000200, 0x3602f3ff, 0x2f00bd02, 0x9f415b00, 0x0d79420d, 0x4508ff43, 0x6b41055b, 0x1c674106, + 0x4e069158, 0x44080747, 0x18167001, 0x2c391a19, 0x101e1f2b, 0x0805040f, 0x0f0b0b09, 0x352b2b1f, 0x194c2166, 0x0f2f0f2f, 0x0f200f10, 0x0fcf1312, + 0x1c1d1616, 0x0f0e1515, 0x06050a09, 0x2d5a0202, 0x0d111115, 0x070a0a0d, 0x03050506, 0x08d68202, 0x0504032b, 0x03070909, 0x22101103, 0x42323122, + 0x1a1e1e22, 0x11161519, 0x84111122, 0x3c2c832b, 0x41468b14, 0x0f202f30, 0x0d530b0c, 0x08348207, 0x0e0a0a2e, 0x1110100d, 0x3cb61111, 0x08080403, + 0x0d0d0b0a, 0x11110e0f, 0x19151213, 0x16151818, 0x01001212, 0x00005d00, 0xbd023202, 0x00003b00, 0x4f06b343, 0x7b470b19, 0x1d4f4809, 0x4c5d2228, + 0x23221c1a, 0x57851a28, 0x82821020, 0x04070827, 0x03194b04, 0x26b28203, 0x150f0e0a, 0x831d1c16, 0x0a0a2cd9, 0x02020504, 0xaf0e024c, 0x82124387, + 0x0704320c, 0x0e0b0a07, 0x1512110e, 0x1d1a1916, 0x23461339, 0x0520490e, 0x050a0929, 0x0a040504, 0x840c0c09, 0x54fd2110, 0x5c20ab82, 0x2a20ab82, + 0x0b20ab82, 0x2c08477f, 0x15143320, 0x1a4c5c20, 0xfe5a0e01, 0x2e5482a6, 0x3c9b2efe, 0x00000014, 0xff2e0001, 0x823a02f3, 0x694b202b, 0x4f4a0e8f, + 0x34352106, 0x08bfb118, 0x43823220, 0xa36a0383, 0x3637230e, 0x93463635, 0x10e83612, 0x1b1b1515, 0x10111616, 0x0a090d0c, 0x04030706, 0x17450202, + 0x08018246, 0x042e8b21, 0x10080804, 0x10171710, 0x0204070f, 0x01020103, 0x02021746, 0x06060303, 0x0c0c0a09, 0x82030601, 0x07072100, 0x0d2c0b82, + 0x14141010, 0xb71d1818, 0x6fb3fe3d, 0x8329b582, 0x2371e12c, 0x0e0e1818, 0x20008207, 0x2c21830e, 0x110f0f0c, 0x6dd954fe, 0x1418181d, 0x05404814, + 0x0002002d, 0x02f3ff1b, 0x00cb024d, 0x97c30073, 0x055344d5, 0x2406ab5e, 0x33321514, 0x09b34636, 0x500b3b44, 0xaf6c11f3, 0xf7431807, 0x11a74609, + 0x830ff342, 0x3635235b, 0x01823435, 0x18065741, 0x200d45bb, 0x05577a23, 0x06070624, 0x01821415, 0x14151623, 0x0afd4717, 0x0116172e, 0x18171598, + 0x2021271b, 0x1414191a, 0x20058144, 0x3d008203, 0x09090605, 0x4511340b, 0x19081117, 0x10211c1d, 0x12131212, 0x18181516, 0x0b151717, 0x00830a09, + 0x191b0b23, 0x3f0d8219, 0x15171516, 0x10121315, 0x252a0e11, 0x1a1f1e25, 0x1015151a, 0x050c0b11, 0x03010106, 0x06050503, 0x0a234783, 0x820f0c0d, + 0x0eb63441, 0x1c151211, 0x11101616, 0x08090c0d, 0x03030606, 0x82010201, 0x36278302, 0x090a0707, 0x10100c0c, 0x17171414, 0x04211d1c, 0x08080b02, + 0x82020504, 0x0203221f, 0x20478304, 0x278f8207, 0x0305030c, 0x0b060602, 0x15382782, 0x1c181814, 0x1f1d1c1c, 0x1b1e1d21, 0x19191a1a, 0x1c563091, + 0x1118171e, 0x05235782, 0x83030204, 0x2e058235, 0x04040303, 0x0b102144, 0x0306070b, 0x82030304, 0x0c0a2a65, 0x0a060501, 0x120f0e0a, 0x27f78213, + 0x2722221c, 0x11131314, 0x102cbf82, 0x0e0f0f11, 0x0a0b0c0e, 0x4608090a, 0x04217982, 0x056d4a04, 0x100e0e25, 0x820c0d0c, 0x090c2519, 0x0f101011, + 0x0d220082, 0x25830b0d, 0x08080937, 0x04050605, 0x19170202, 0x1d1c1b19, 0x060b1e1d, 0x0c0c0c0d, 0x8202820b, 0x0b0b2f07, 0x07080908, 0x01000607, + 0x00004a00, 0xdf431f02, 0x4f891805, 0x07e34215, 0x1807f741, 0x210a9ba4, 0x01433736, 0x15103605, 0x0db90122, 0x10100f0f, 0x35171414, 0x0f1f2a29, + 0x08080c0c, 0x0bde4303, 0x1d1c1525, 0x490e1615, 0x4c260889, 0x07094487, 0xc9820507, 0x1b0e0e2f, 0x1611120e, 0x1d1a1a15, 0x70e04ce7, 0x08fe4c0e, + 0x05040424, 0xdb830909, 0x79221182, 0x7118fe28, 0x242407d7, 0x3102e6ff, 0x5723af82, 0x42050000, 0x99451253, 0x8237200b, 0x1837209f, 0x5e09e76c, + 0xbd420e05, 0x42152007, 0xe5820c71, 0x31021431, 0x2622231a, 0x314a4a47, 0x0f16161d, 0x83060709, 0x06062ba7, 0x16170d0d, 0x1f1e1b1d, 0x53822424, + 0x1a162008, 0x284f111a, 0x14222214, 0x191a1a1c, 0x1618171a, 0x14141516, 0x0e101013, 0x080a0b0e, 0x42040408, 0x0335053b, 0x0e0b0b08, 0x42636357, + 0x0d0d0a1a, 0x1b1c1a0f, 0x0b0b0b13, 0x2f7a820c, 0x08090708, 0x11100f0a, 0x16161212, 0x16151518, 0x152b0082, 0x2a292513, 0x3737211b, 0x8a0d0c21, + 0x0c0c2e00, 0x0b0a0c0b, 0x08070908, 0x03030306, 0x36028302, 0x05060606, 0x19262622, 0x00020049, 0x02e9ff2f, 0x00cb0239, 0x4f9d0085, 0x8b581111, + 0x0b3b4d0b, 0x180c0f4e, 0x4308c545, 0x21410f9b, 0x7e152005, 0x8d480501, 0x8c398306, 0x0801463d, 0x1809374f, 0x180c67b4, 0x080a499d, 0x13390224, + 0x08280a0a, 0x0a090809, 0x16090908, 0x1a191818, 0x111c1c1b, 0x0f0e1010, 0x160c0d0d, 0x02030c0b, 0x1c820607, 0x1c1d1631, 0x19191a26, 0x17171817, + 0x0a0b0d17, 0x82040607, 0x050422f6, 0x201a8207, 0x06994a0d, 0x141d1d32, 0x4d090913, 0x0a06051a, 0x110e0d0a, 0x18151411, 0x20084e82, 0x1a1a1c1b, + 0x15151718, 0x0e0e1211, 0x05050b0b, 0x0c0b0706, 0x19141010, 0x70fe1716, 0x11221211, 0x32018412, 0x22222410, 0x0d0d1121, 0x04050909, 0x06060d1a, + 0x4f0b0e18, 0x1422055a, 0x35830f10, 0x0502012d, 0x0a060704, 0x211a1a12, 0x820f0f11, 0x090b2499, 0x42090a13, 0x0f35058d, 0x1b1a1a19, 0x201e1e1b, + 0x1518181b, 0x0d111116, 0x0609090e, 0x08174b05, 0x06020831, 0x22222904, 0x17161c1c, 0x0d0d1211, 0x82040807, 0x07082600, 0x11110d0d, 0x35d58216, + 0x2a272222, 0x23242728, 0x181d2120, 0x20451c1d, 0x04051010, 0x1d820809, 0x0f0f1e23, 0x20098403, 0x4d008200, 0x3f2209eb, 0xeb4d0000, 0x05534b38, + 0xe74d2220, 0x4d922031, 0xfe2432e5, 0x143c66cf, 0xbb4fba82, 0x023d2606, 0x004300cb, 0x20bd8265, 0x11415c20, 0x43096f46, 0x83420a9b, 0x14332206, + 0x06677f15, 0x20086d46, 0x35611814, 0xb9461809, 0x0fb94307, 0xfe3a0226, 0x0d0e82fd, 0x43080082, 0x090a0b0b, 0x05060708, 0x04050203, 0x11110a0a, + 0x17171816, 0x29292517, 0x13264c1b, 0x23131d1e, 0x23232423, 0x1a262425, 0x1e1e1d1d, 0x26211f1f, 0x15272a2b, 0xfe0f1313, 0x17468bbc, 0x11202221, + 0x070c1010, 0x2f059c4a, 0x0c0c1007, 0x03040808, 0x0c0c0606, 0x01021212, 0x08050646, 0x0a08083c, 0x110d0d0a, 0x19161614, 0x251e1f18, 0x1f232326, + 0x2d43433c, 0x1e31311e, 0x171f2029, 0x380c0b16, 0x150b0a1b, 0x29201f16, 0x4045463f, 0x191f1f22, 0x37243f3a, 0x1a1c3537, 0x9c821419, 0x0b0b0b3f, + 0x171b0c0c, 0x0f131217, 0x0b100d0f, 0x0306060b, 0x00010003, 0x02f3ff2b, 0x00bd025d, 0x0d654a43, 0x20081b4f, 0x0ba34410, 0xa2183320, 0x394f0aa1, + 0x23222106, 0x8d472182, 0x78013a09, 0x1a191916, 0x1e2b2b39, 0x080c0b0f, 0x4c040507, 0x05020319, 0x0e090a04, 0x05b7500f, 0x0a0f0e34, 0x0206040a, + 0x46309202, 0x07050417, 0x0f0b0c08, 0x134f1210, 0x0d8d5211, 0x270a104f, 0x3b818301, 0x88f1fe14, 0x220d144f, 0x82200001, 0x024924c7, 0x7e9500cb, + 0xc7840d5d, 0x4608e373, 0xc78c0747, 0x0921a318, 0x18122d66, 0x25082bea, 0x15060706, 0x89442322, 0x0cb1480a, 0x4507eb76, 0x994407e7, 0x3317820f, + 0x1d17bb01, 0x242d211e, 0x141c1d24, 0x060d0d15, 0x02234507, 0x0805f672, 0x0b0c0840, 0x11120e0e, 0x11111416, 0x0b0c0f0e, 0x08091209, 0x1414090a, + 0xde241c1c, 0x1063c54a, 0x0c0c0e0e, 0x07080a09, 0x03030505, 0x1e1f0202, 0x16161e3d, 0x0707100f, 0x07082446, 0x14140e0e, 0x57821919, 0x17171928, + 0x12111515, 0x3f820e10, 0x04050838, 0x04040102, 0x0d070505, 0x22171213, 0x0f0f1919, 0x04040809, 0x47480707, 0x09042105, 0x2d080b82, 0x14100f08, + 0x1b1a1915, 0x0f0f1e1c, 0x0c0d0d0e, 0x08090a0c, 0x03060607, 0x06030304, 0x0a070705, 0x1f181813, 0x1118181e, 0x3c090911, 0x42540214, 0x4f092005, + 0x0c3305b6, 0x071a1b36, 0x150d0d07, 0x181d1e14, 0x10151619, 0x830c0b11, 0x06072e39, 0x0c0c0909, 0x11110f0e, 0x0d171313, 0x30b5820d, 0x140a0b0b, + 0x08070e0e, 0x17181010, 0x151e1b1b, 0x25008214, 0x0f101312, 0x6b440d0c, 0xf3ff2306, 0x7b424e02, 0x05136a18, 0x51197f42, 0xc5331193, 0x1b191817, + 0x1e2b2a38, 0x080c0c0f, 0x47040407, 0x4b309217, 0x054808e4, 0x040a2d07, 0x4c020206, 0x0804051a, 0x100b0c07, 0x23118f51, 0x143b6631, 0x51187d42, + 0x01220f8e, 0xc3823000, 0xc3823820, 0x77427d20, 0x0eb74612, 0xb7183720, 0x711819bf, 0x654f0c2d, 0xff59180f, 0x12fd4b13, 0x19189d2f, 0x21241b19, + 0x181e1e21, 0x09121218, 0x05a14c09, 0x100e0f24, 0x00831110, 0x06050c2f, 0x0e0d0f16, 0x0b0c0d0e, 0x2905110a, 0x200a8214, 0x2a198311, 0x30464740, + 0x17262617, 0x82090906, 0x0c44081a, 0x1d1c250a, 0x05050615, 0x03020404, 0x03020603, 0x12140a09, 0x29291e1e, 0x13121e1d, 0x194c0909, 0x0a0a0504, + 0x11100f0e, 0x08021514, 0x07070403, 0x17180f0e, 0x2b2b2021, 0x21222635, 0x17181c1d, 0x0e0d1213, 0x2b087b82, 0x03040105, 0x04060903, 0x01030203, + 0x01143b01, 0x05030302, 0x1c1a0704, 0x2242131c, 0x090f1009, 0x03020303, 0x12010102, 0x0a092311, 0x23080082, 0x170c0a0b, 0x3a1e1b1b, 0x19192a2a, + 0x0c0c0d0c, 0x2a2b1819, 0x0703073c, 0x22232903, 0x17171b1c, 0x0c0d1112, 0x4a053342, 0xcc220533, 0x63563f00, 0x1617241b, 0x50151617, 0x1919069b, + 0x072311a5, 0x83060706, 0x044a331d, 0x0c080803, 0x2b1e0f0c, 0x191b382a, 0x12161718, 0x61570f13, 0x0a04210b, 0x220a6d55, 0x8205090a, 0x014b23d1, + 0x7651a245, 0x93fe2719, 0xac58017a, 0x78510e0e, 0x817d2114, 0x012ac082, 0xe4ff3000, 0xcb023802, 0x434a7500, 0x08136d0a, 0x780f7754, 0x65450d8f, + 0x2e174909, 0x21069544, 0x5f821623, 0x01142608, 0x47482ee6, 0x21212544, 0x2525171a, 0x0a0a0816, 0x0b0b0c0b, 0x1112130a, 0x0d0d0e0f, 0x07070a0a, + 0x03030507, 0x22108209, 0x442a1e1f, 0x0c300591, 0x090a120a, 0x0505194d, 0x0e0e0a0a, 0x14141111, 0x260def48, 0x0b0b0e0f, 0x82040504, 0x0c0c341d, + 0x1010100f, 0x10101111, 0x21201d0f, 0x1c131c15, 0x820f1b1d, 0x42260854, 0x0f0f0921, 0x03030309, 0x01010202, 0x09090504, 0x11100e0d, 0x17181514, + 0x39201a1b, 0x181a292a, 0x03030c0d, 0x17820605, 0x2a2a1923, 0x14c8483b, 0x08092608, 0x11120c0d, 0x1c1c1717, 0x27282222, 0x1d1c2223, 0x12131817, + 0x08090d0e, 0x0d0c0405, 0x004b080d, 0x17000100, 0x05bb5700, 0xbb484520, 0x2627210f, 0x0f420182, 0x0a894b05, 0x52114541, 0x2f820cc1, 0x01df0126, + 0x05020201, 0x24065e57, 0x47161212, 0x084a4c17, 0x02024808, 0x07061748, 0x17160e0e, 0x28281f1e, 0x29293332, 0x15151e1e, 0x06070d0d, 0x901f0147, + 0x12121113, 0x0e101011, 0x090b0c0e, 0x0206050a, 0x0167cbfe, 0x09048913, 0x110e0e08, 0x19151612, 0x050e1c18, 0x24290911, 0x431f2023, 0x092e05ad, + 0x18121209, 0x241f1f18, 0xb8fe2924, 0x0082006e, 0xe7550220, 0x00752208, 0x15e955bd, 0x4c0c6354, 0x27211291, 0x09075e26, 0x200afb48, 0x1c454b36, + 0x0c610a19, 0x8f183720, 0x6d8c0a25, 0x12538f18, 0x0fcf4e18, 0x0be7c618, 0x4c462a08, 0x1e060e19, 0x031e1d1e, 0x02010203, 0x05060101, 0x0a0a080c, + 0x090a0b0c, 0x0f100f09, 0x0e0f1010, 0x0807090e, 0x04040605, 0x211d8203, 0xd6580101, 0x06062305, 0x25820708, 0x0e0e0c3e, 0x13131110, 0x261a1616, + 0x1918201f, 0x0f0f1414, 0x07070b0c, 0x05040303, 0x0b0a0908, 0x102d1d82, 0x13121213, 0xfe2d8612, 0x0201ca99, 0x05d35812, 0xde500220, 0x1f123605, + 0x0e102d1f, 0x0a0c0b0f, 0x0809080a, 0x05050607, 0x04060304, 0x055e4f03, 0x82080621, 0x0b0a2285, 0x2b43840d, 0x130d0e0e, 0x27750909, 0x0b0a1339, + 0x2c05f15a, 0x180a0b0a, 0x090d1314, 0x03020605, 0x2a008301, 0x04050302, 0x07070509, 0x83080708, 0x0707274c, 0x05070607, 0xfd4e1111, 0x0e0f2805, + 0x0b0c0d0d, 0x830a090b, 0x030327c8, 0x0c0c0706, 0xe6420f10, 0x192c0805, 0x1e211a1a, 0x181b1b1f, 0x15161519, 0x0d111114, 0x143c080d, 0x090a0aee, + 0x1a1b180a, 0x1f201b1b, 0x13141325, 0x12111414, 0x0f0f1e0e, 0x2005bc47, 0x82658206, 0x08092863, 0x15131312, 0x82080808, 0x0406276a, 0x02040406, + 0x02820101, 0x04040131, 0x15100909, 0x00001c1d, 0x00310001, 0x5b630200, 0x81592277, 0x59232008, 0x102619c5, 0x04312215, 0xbb830804, 0x2b2a1e36, + 0x2b2c3838, 0x0b0c0f1e, 0x04050708, 0x17461746, 0x0203194c, 0x53050146, 0x09250734, 0x0305040a, 0x19755b02, 0x4b058459, 0xfe2318d7, 0x8200817d, + 0x00012a00, 0x02f3ff4a, 0x00bd021f, 0x34874a3f, 0x200d834a, 0x0b074896, 0x481c0b50, 0x0f5d1805, 0x0d814a0f, 0xa2bcfe22, 0x240f7f4a, 0x02000010, + 0x68bf8657, 0xcb5014c3, 0x33323224, 0x01221514, 0x0e0f0e80, 0x13131110, 0x2a2a3517, 0x0b91461f, 0x09090528, 0x15160e0f, 0x345b1c1d, 0x02052706, + 0x56194c02, 0xd150a11c, 0x21632313, 0xd150356c, 0x54fc2115, 0x2b078a54, 0x34000100, 0x3302f3ff, 0xaf00cb02, 0x7f12bf48, 0xfe18101b, 0x6347179d, + 0x057a1809, 0x0f634409, 0x23221522, 0x5308694b, 0x05510dbd, 0xb15e1810, 0x95951809, 0x67b6180e, 0xa680080e, 0x1e1b1b17, 0x1d232428, 0x1017171d, + 0x47080810, 0x170b0b23, 0x221c1d15, 0x141b1b22, 0x06070809, 0x04030305, 0x0b080704, 0x100d0f0b, 0x1111110f, 0x12131212, 0x0f101012, 0x0b0d0e0f, + 0x0408090b, 0x0c060604, 0x1812120d, 0x26201f19, 0x19212027, 0x0c13121a, 0x4607060c, 0x0f070723, 0x2018180e, 0x0b0e0e10, 0x0809090c, 0x04060608, + 0x03020203, 0x07050602, 0x0c090808, 0x0c0d0c0b, 0x080d0d0d, 0x03224182, 0x17830103, 0x0d0e0d2a, 0x0d0d0f0f, 0x0b0a0d0b, 0x05292f83, 0x0f020305, + 0x14102010, 0x05254913, 0x140e0d29, 0x1d1a1914, 0x8223211d, 0x09132899, 0x1109090a, 0x820a0a09, 0x100e2643, 0x0c0e0f11, 0x2610820b, 0x05070608, + 0x82060606, 0x07072103, 0x10576482, 0x12132b05, 0x17171a17, 0x11111516, 0x16820d0d, 0x0d0d073f, 0x16151111, 0x191a1717, 0x100f1414, 0x02020807, + 0x06050404, 0x08090707, 0x0b0a0a0a, 0x24d5820a, 0x0707090a, 0x24f98206, 0x05050405, 0x21b48204, 0xb7440201, 0x24588405, 0x0a070806, 0x29268209, + 0x110e0f0c, 0x26301211, 0x7b821d25, 0x512f5749, 0x57490693, 0x05b95f6a, 0x20175549, 0x08fb4d02, 0xbf007f22, 0x6107c542, 0x34200c8f, 0x09e54118, + 0x761d6149, 0xcd530b85, 0xfd69180f, 0x07062210, 0x47431806, 0x07d3420b, 0x837d0320, 0x162f430a, 0x08bf5518, 0x830f4d50, 0xbb01349d, 0x211d1d18, + 0x22290205, 0x151c1c22, 0x050f0c18, 0x45234505, 0x3a080691, 0x1b161610, 0x0e121215, 0x080c0c0f, 0x04060609, 0x0a020204, 0x1c131409, 0x4adf251b, + 0x0c102e5b, 0x0409080d, 0x08030404, 0x0f0b0c07, 0x1411110e, 0x1c181915, 0x1e2a2a35, 0x4e0f0e1e, 0x34081511, 0x10100c0b, 0x0cc71414, 0x17120f0e, + 0x0d0d1212, 0x06050a0a, 0x01020303, 0x05040203, 0x0a090807, 0x0707050b, 0x08090607, 0x0f0f1309, 0x0a090b0c, 0x05040607, 0x291f8203, 0x02020201, + 0x07060605, 0x4d4e090a, 0x14113006, 0x191d1816, 0x05031917, 0x11121214, 0x820e0d11, 0x04052949, 0x08060603, 0x0c0a0a08, 0x2d055454, 0x1017171d, + 0x3c090910, 0x0c0d0714, 0x26821111, 0x29821320, 0x0f0f1131, 0x0a090c0e, 0x04040706, 0x1b1a0d0d, 0x472b2121, 0x0b220545, 0x3a4e130a, 0x18192c05, + 0x151d1a1b, 0x14141514, 0x82101112, 0x980138e2, 0x03020205, 0x0b080804, 0x0f0d0d0b, 0x0a0a0f0e, 0x090b0a0b, 0x82080808, 0x051b4742, 0xbc820220, + 0x82060621, 0x0a092111, 0x0d280082, 0x0b0b0b0a, 0x08090a0a, 0x002bc982, 0x004e0001, 0x022f0200, 0x5a0f00bd, 0x22080853, 0x15143320, 0x15102320, + 0x194c4e22, 0xfe5f1d01, 0x024c5fe3, 0x2c83af0e, 0xb3fe153d, 0x0000006f, 0x82230003, 0x82452033, 0x00432433, 0x187f0061, 0x590ce365, 0x5d4908b1, + 0x3534220e, 0x18558232, 0x4d2877a2, 0x17200be1, 0xa2183582, 0x2720197b, 0x012a7182, 0x1c1b2103, 0x11121615, 0x5d600c0d, 0x02032505, 0x09080505, + 0x2b051b44, 0x48221b1c, 0x23222d18, 0x11121819, 0x05311d83, 0x11090905, 0x23191812, 0x18482d22, 0x0c0f0f12, 0x079f480d, 0x02020139, 0x06030301, + 0x180e0805, 0x13198419, 0x090e0e13, 0x0405050a, 0x52020103, 0x0a3f0570, 0x0f0d0c0a, 0x0119320f, 0x0a0a0506, 0x11140e0e, 0x18191515, 0x21231e1e, + 0x1a1a1e1e, 0x82121616, 0x0a260830, 0x0106050a, 0x13260e2b, 0x110a0a01, 0x1f191811, 0x2c252520, 0x1f26252b, 0x11191820, 0x010a0912, 0x01941238, + 0x66828b16, 0x0c2a8683, 0x1310100c, 0x1c181714, 0x395a181c, 0x0d182a05, 0xfe9f010c, 0x06018bea, 0x086e5d06, 0x17181d27, 0x10101314, 0x20da850c, + 0x3ff11803, 0x02472908, 0x004900cb, 0x33000079, 0x09b56518, 0x4b0e5f4f, 0x755e0cbd, 0x0c89560a, 0x180a5f64, 0x560cd175, 0x21082089, 0x48721617, + 0x03184818, 0x0b070703, 0x120f0f0a, 0x1a161712, 0x212a1e1a, 0x131a1a21, 0x070c0c13, 0x19820406, 0x5f0a0a21, 0x18360583, 0x14161d18, 0x10161115, + 0x10010a10, 0x5bf0fe5b, 0x1b0f6b4b, 0xd882261b, 0x090c0d26, 0x0507070a, 0x08064543, 0x05030341, 0x0a080705, 0x100e0d0a, 0x1b271310, 0x070e0e1a, + 0x56070807, 0xcf153d1d, 0x14151668, 0x11111213, 0x0b0b0f0d, 0x04040807, 0x0e0e0707, 0x17181312, 0x171e1a1b, 0x13121515, 0x0d0e1110, 0x82090b0a, + 0x03032219, 0x32428206, 0x3e26730c, 0x011d5614, 0x0a09139d, 0x05050203, 0x82080706, 0x0c0d2715, 0x0f100d0d, 0xc7570e0e, 0x07062705, 0x02030405, + 0xbc820909, 0x1e1c1724, 0x51181818, 0x1b210a97, 0x23ed1800, 0x000330df, 0x02f3ff24, 0x00bd0245, 0x0081006f, 0x1800009b, 0x480b5b91, 0xc7180dc1, + 0x3323134f, 0x85223510, 0x0b194625, 0xe7433320, 0x5417200e, 0x6f4e0f09, 0x06232408, 0x18353403, 0x830ac955, 0x10172129, 0x17d1ca18, 0x69014708, + 0x0c0c0b0c, 0x151a1a1e, 0x10111215, 0x0b111016, 0x0407070c, 0x48020104, 0x02010218, 0x07040303, 0x0c0a0906, 0x1511110d, 0x16242431, 0x020b0b17, + 0x09050503, 0x25180d08, 0x16453225, 0x151b1b23, 0x0c111015, 0xba4c0a0f, 0x03023c06, 0x05060304, 0x0a0a0908, 0x0e100d0d, 0x0b141212, 0x18730b0b, + 0x090a1111, 0x82050506, 0x11112c49, 0x14141c78, 0x08090e0e, 0x82020505, 0x82052000, 0x0e0e3d2b, 0x010c1414, 0x03030101, 0x0a070405, 0x12130e0e, + 0x17181615, 0x071a1919, 0x19030602, 0x22085f82, 0x0b0e0e10, 0x0709090d, 0x01040307, 0x08088001, 0x1718100f, 0x0d0e1121, 0x0a0a0c0d, 0x07080f08, + 0x83013b74, 0x0c0c3347, 0x1515120e, 0x1e1e1a1a, 0x13131522, 0x11111213, 0x24831010, 0xd3540b20, 0x023b0805, 0x421a0201, 0x05020221, 0x110a0b04, + 0x030a0a10, 0x50030204, 0x068000ff, 0x100b0b05, 0x1a161510, 0x1b21201b, 0x1015161b, 0x050a0a0f, 0x00000005, 0x01f00001, 0x027901d9, 0x822b00db, + 0x1514210c, 0x0c4f8218, 0x57098745, 0x5f4a09cf, 0x79012107, 0x10227c82, 0xb3820c0f, 0x59040521, 0x10290653, 0x10131211, 0x0b0a0e0d, 0x37008206, + 0x0d0e0a0b, 0x14261302, 0x09080405, 0x0e0f0c0c, 0x12121010, 0x0e0f1110, 0x2d055355, 0x06051326, 0x0d0d0a0a, 0x0c0d0e0f, 0x8a840b0b, 0xea248b82, + 0x7e01e001, 0x21054f46, 0x7d823613, 0x3a05f945, 0x07060706, 0x0d08ea22, 0x1a50070e, 0x0f1a1b0f, 0x1de00130, 0x361d2e2e, 0x83182f11, 0x29378207, + 0x015402bd, 0x000503ac, 0xa3770013, 0x09a77705, 0xbd333b84, 0x0d0c0c0a, 0x111a1a19, 0x1e142141, 0x0e0f1d1d, 0x18390b0e, 0x82119985, 0x02712847, + 0x03f80153, 0x8247005b, 0x0c9f5647, 0x36218b82, 0x0aaf5737, 0x65820f84, 0x33323522, 0x4b0e1b45, 0x072b0d8d, 0x1932bc06, 0x05050302, 0x470a0707, + 0x0e2606b9, 0x1a0e0e01, 0xf8840e0e, 0x03040930, 0x02020204, 0x091a3301, 0x0c09120a, 0x00820c0b, 0x10110d25, 0x82101011, 0x0b0d2ea3, 0x0304080c, + 0x01030202, 0x0e530202, 0x3600820d, 0x0c0a0b0c, 0x07070908, 0x03030605, 0x04030504, 0x08060604, 0x82050908, 0x07062c00, 0x181c0807, 0x090c1518, + 0x82060609, 0x0405221e, 0x21228204, 0x77830404, 0x05050422, 0x00202783, 0xbc28df82, 0xac015102, 0x13000203, 0x162d7f18, 0x1e145f2b, 0x0e101d1d, + 0x21430b0e, 0x06324109, 0x51023a22, 0x14230319, 0x02590029, 0x030f024e, 0x186d0054, 0x470ab757, 0x272006c1, 0x0c938a18, 0x18071f58, 0x210c0b88, + 0xcb433122, 0x0d075806, 0x8220955c, 0xc4012835, 0x100e0d0d, 0x820a0b0a, 0x092f0800, 0x0708080a, 0x05050707, 0x021b3804, 0x06070304, 0x0d080807, + 0x06060a0a, 0x06070202, 0x11120d0e, 0x0c0c0d16, 0x1920010b, 0x08100f18, 0x5f1a3508, 0x0d28059c, 0x120f0f0e, 0x14131411, 0x2f066153, 0x0f0f1011, + 0x0b0a0d0d, 0x04040808, 0x04050202, 0x09304682, 0x57020a0b, 0x01020205, 0x04020202, 0x07060604, 0x0c225882, 0x69820d0b, 0x02040323, 0x3d228303, + 0x130a0908, 0x0a0b0e0f, 0x02010405, 0x0f0f0803, 0x1d1e1717, 0x18181c25, 0x12121515, 0xfd53100f, 0x82052005, 0x8202201b, 0x07072c3f, 0x0b0b0909, + 0x11100e0e, 0x820c0e12, 0x0809269f, 0x06060807, 0x2a008200, 0x025e0001, 0x020a0253, 0x7e0b00db, 0x20340871, 0x20151433, 0x0112345e, 0xbffe590d, + 0x22665302, 0x0e2b143b, 0x332c2b84, 0x3402f4ff, 0x71000e02, 0x06370000, 0x09b94818, 0x39492720, 0x0f6b4508, 0x0de56318, 0xe7623520, 0x15036008, + 0x37363725, 0x82343534, 0x15102343, 0xf56f2322, 0x8227200c, 0x0def266d, 0x0f151110, 0x05c44d0e, 0x0606072a, 0x02020303, 0x0101153f, 0x042afe82, + 0x0b0c0405, 0x08090b12, 0x0a820706, 0x82030421, 0x830120f6, 0x8202201a, 0x06042522, 0x0a130d0d, 0x41081a82, 0x03050405, 0x01030305, 0x153e0102, + 0x1911153e, 0x0f112019, 0x0a0e0d0f, 0x0a09060b, 0x0408030b, 0x05030203, 0x0e090a05, 0x1511110d, 0x251d1d16, 0x65c84ce5, 0x1117171b, 0x0a0e0e11, + 0x0306050a, 0x1f820402, 0x0b080737, 0x1710100c, 0x4be21d16, 0x182365c8, 0x0a0f0f18, 0x070d060a, 0x241d8307, 0x09060506, 0x303d820c, 0xe21a1516, + 0x8476fe4b, 0x0e1d0f1e, 0x0803040e, 0x30148308, 0x01000c0c, 0x37ff6000, 0x1b021102, 0x00003300, 0x099c1817, 0x098b4c08, 0x574ff584, 0x4815200e, + 0x223505e3, 0x22151423, 0x19174560, 0x2b3a2a29, 0x15142120, 0x17450a0b, 0x6ae71807, 0x0133080c, 0x56ff5500, 0x2202c945, 0x2f1b34b5, 0x0d0d1716, + 0x28281a1b, 0x4c1d5635, 0x191a2327, 0x09081111, 0x16150b0a, 0xad291f1e, 0x97113339, 0x00000032, 0x82250002, 0x0244278f, 0x002f001a, 0x67710043, + 0x7427200e, 0xa1840ac3, 0x5e05d344, 0x2320060d, 0x73718d82, 0x0607300f, 0x93010607, 0x34262517, 0x14161719, 0x83111114, 0x0f0e30fe, 0x27281d1d, + 0x25263432, 0x02020317, 0x83153f02, 0xfe462d01, 0x432122dc, 0x21212244, 0x18224422, 0xc9329b84, 0x142959b2, 0x09050414, 0x110f0e09, 0x40323225, + 0x87713341, 0x13132508, 0x72a8fe0d, 0x0121b483, 0x088b71ce, 0x190d0d29, 0x0026251a, 0x825c0001, 0x025224c3, 0x8235001b, 0x080953c1, 0x09835d18, + 0xe8181520, 0xd54710b9, 0x53152005, 0x012a083f, 0x0d0706ab, 0x1d15140d, 0x8a841921, 0x37174527, 0x0303021c, 0x056a4101, 0x1515202d, 0x13370a0b, + 0xc9461337, 0x41b06001, 0xe0280d49, 0x838b014a, 0x0f19190e, 0x21096e41, 0x5c4140c3, 0x26978305, 0x022102f3, 0x513300db, 0xa36c0d8b, 0x09a34415, + 0x97853520, 0xab013422, 0x0a2a7f88, 0x0117450a, 0xf1fe5a0f, 0xa882075a, 0x15152208, 0x1819211c, 0x08091111, 0x17461746, 0x17172e4f, 0x1a1a0d0d, + 0x01362928, 0x3499858e, 0x56ad1132, 0x82161924, 0x1b53320c, 0x003b54fe, 0xff330002, 0x02530237, 0x002b001a, 0x2deb413f, 0x3c14e741, 0x252517a2, + 0x17161935, 0x11111414, 0x0f0e1e0e, 0x1d1e0e0f, 0x35322728, 0x02172525, 0x05e74103, 0xc8fe8527, 0x43432121, 0x27008222, 0x19192243, 0x07081111, + 0x231fe541, 0x1134a513, 0x2813e341, 0x02000072, 0x00db020a, 0x08e74d13, 0x42052541, 0x2037058d, 0xed174572, 0xce4fed4f, 0x02edfe44, 0x3499b724, + 0xdcfe1132, 0x44113561, 0x5b2005df, 0x0c24f782, 0x31001b02, 0x22067343, 0x19161716, 0x1810f1b6, 0x6b11bb5f, 0x5b2006d7, 0x2c0a0a42, 0x15152021, + 0x17450a0a, 0x0d0d0707, 0x05871814, 0x00012808, 0xc9bbfe55, 0x42b52202, 0xf5230d07, 0x426dda52, 0xfe280d2c, 0x11336cbd, 0x35000200, 0x5b208f82, + 0x5b228f82, 0x918d8100, 0x200f6353, 0x4ae38517, 0x6f450873, 0x0eb34a09, 0x6e067d45, 0x10210c19, 0x0c0d7615, 0x37205b83, 0x490ca950, 0x6c080747, + 0x021b3835, 0x11010303, 0x13151312, 0x1e1c1818, 0x14151918, 0x1f0e1213, 0x26031011, 0x0411230c, 0x0e0e0809, 0x14131111, 0x23151515, 0x16151d1c, + 0x06050a0a, 0x0e0e0c0b, 0x13141112, 0x01224314, 0x06060303, 0x160a0708, 0x242a2020, 0x13141c1c, 0x01450a0a, 0x08080602, 0x1011140a, 0x0506060c, + 0x03030405, 0x0e204202, 0x050a0c0c, 0x340b8304, 0x08040401, 0xc9060504, 0x0fb52202, 0x1b101819, 0x090b1212, 0x33008205, 0x0d0e0a0a, 0x32312612, + 0x29103340, 0x17171f20, 0x09091011, 0x092a2a82, 0x18191112, 0x14141820, 0x83601010, 0x1a200805, 0x13121616, 0x1b0d0f0f, 0x0a0b0e0e, 0x23221414, + 0x7b8ffe2f, 0x01030101, 0x10090802, 0x0e0b0b09, 0x1429ae82, 0x04090505, 0x07060707, 0x35138209, 0x05090c0c, 0x00000403, 0x2e000200, 0x4e02f3ff, + 0x3b00db02, 0x95435b00, 0x09c1460d, 0x4109734a, 0x936b058f, 0x34352121, 0x12c36718, 0x201a9632, 0x1a1e2821, 0x1215161a, 0x0a0e0e12, 0x0306070a, + 0x3608fd82, 0x0a0a0706, 0x11120e0d, 0x1a1b1516, 0x4623681e, 0x3f153f17, 0x0d060615, 0xff13130c, 0x221a1911, 0x121a1a21, 0x5c080810, 0x17181d2e, + 0x09091213, 0x03040202, 0x82130607, 0x05053712, 0x0e0f0a0a, 0x16161313, 0x1b1a191a, 0x1a191d1c, 0x15151718, 0x9f641312, 0x9a2a0805, 0x32349933, + 0x25499411, 0x1d1c2020, 0x1b4e1616, 0x0e0f0e0e, 0x25251a1b, 0x0d319330, 0x241b1a0d, 0x14163025, 0x11121314, 0x00820010, 0x5e00012a, 0x0a0237ff, + 0x2b00db02, 0x232a8746, 0x5e221510, 0x280c7f46, 0x06061746, 0x15140d0e, 0x05dc431c, 0xc9450927, 0xbde9bb02, 0x090b455f, 0x21120343, 0x7f847d8a, + 0x37ffcc28, 0x0e02ed01, 0x7f860b00, 0x2e05c743, 0x1745cc22, 0xc9d93293, 0xfeb52202, 0x4333a512, 0x342006bf, 0x3420ab82, 0x6f20ab82, 0xcb45ab93, + 0x0a796706, 0x48147148, 0x2620114f, 0x54054d5b, 0x072015f7, 0x3306535e, 0x12153e34, 0x20221819, 0x060e1717, 0x02020504, 0x01010102, 0x33115248, + 0x02010302, 0x3f153f01, 0x19191115, 0x16172021, 0x0505060e, 0x8206f75a, 0x07032c2c, 0x0b120d0d, 0x05050908, 0x50030405, 0x01370528, 0xbb02c93e, + 0x1d54a6e9, 0x0d0d0e0f, 0x0f0e0d1a, 0x15141212, 0x48284f18, 0x0d30234e, 0x0f0d190d, 0x15121110, 0x274f1814, 0x0e191823, 0x27067f48, 0x04040202, + 0x08060605, 0x32053752, 0x7e88fe1a, 0x00020000, 0x02f3ff45, 0x00e60224, 0x428d0053, 0x262322ef, 0x18272627, 0x200b6bab, 0x06814416, 0x210cb757, + 0x777a1415, 0x14a76b0b, 0x18273421, 0x200cc3b5, 0x14774427, 0xa1013608, 0x201b1c17, 0x161b1b1f, 0x0f111217, 0x070b0b0f, 0x06030407, 0x120d0d07, + 0x18161611, 0x26221b17, 0x21131926, 0x170e1320, 0x100a0e17, 0x28780a10, 0x0f1e2266, 0x22258207, 0x41030405, 0x2008055e, 0x07060403, 0x0e100b0b, + 0x11f31212, 0x13251c1c, 0x0e0e1111, 0x08090c0b, 0x04030605, 0x01010302, 0x05b14902, 0x0909072a, 0x1a19330c, 0x10101515, 0x1b826583, 0x04040123, + 0x203a8206, 0x05754404, 0x12110e30, 0x18171515, 0x2a1d1b1b, 0x1d1c2423, 0x27821615, 0x15040a36, 0x1a101718, 0x08192b2a, 0x0d090e0f, 0x4a0d1617, + 0x0b143c19, 0x2205fa54, 0x820c0d0d, 0x09093400, 0x1d1d2005, 0x15151819, 0x0e0e1012, 0x0f0e1d63, 0x82080404, 0x0c0d228f, 0x2691820f, 0x061a1615, + 0x840d0a09, 0x232c8200, 0x0a0a0b0d, 0x1220dc84, 0x1828dc82, 0x1313131b, 0x0f0e1212, 0x200f8b43, 0x0cf34a05, 0x0daf3719, 0x2a0c2148, 0x01221510, + 0x292919ad, 0x46202b3b, 0x19480a94, 0xbbc9220c, 0x0c1a485d, 0xb19efe22, 0x290d1748, 0xdffd4ae0, 0x000100b6, 0x5b47005e, 0x519b1805, 0x06976f09, + 0x1807515f, 0x440f7954, 0x56250807, 0x17452a2a, 0x06034407, 0x11191826, 0x45090911, 0x1fc37518, 0x5300022c, 0x1002f2ff, 0x6b00db02, 0x5b6ea500, + 0x08d94611, 0x210f8b55, 0xe9703332, 0x0ce7430e, 0x85151421, 0x0ca9421d, 0x86161721, 0x201b85c1, 0x15ab4206, 0x8407154e, 0x572986e5, 0x3a080fc9, + 0x0e0d4801, 0x1a1d100f, 0x0f151519, 0x060a0c10, 0x180d0c06, 0x2e232219, 0x0e16151c, 0x0407070d, 0x08060805, 0x21420507, 0x06080905, 0x05040507, + 0x0c090a05, 0x0907100c, 0x84070808, 0x07082400, 0x8205070f, 0x13162600, 0x0c0f1012, 0x3225820c, 0x02040406, 0x0a174501, 0x0a141010, 0x0f860b0c, + 0x771e1617, 0x0b2205a8, 0x0a580808, 0x02033905, 0x09090505, 0x12130d0d, 0x0d0e0f1a, 0x0b0b0b0c, 0x07070909, 0x03030506, 0x20050a5f, 0x21408207, + 0x1f820706, 0x1818132f, 0x2e201b1b, 0x292a2c2b, 0x03252627, 0x3353820a, 0x10131212, 0x090d0e0e, 0x08070a0b, 0x0b080c0c, 0x0d0b0b0c, 0x05283f83, + 0x03010104, 0x04040504, 0x04250282, 0x0409153f, 0x22008203, 0x820f0e0c, 0x111022dc, 0x37358211, 0x15151414, 0x1b363cb5, 0x0d111116, 0x6b040506, + 0x040b0b15, 0x09060604, 0x0c354982, 0x100e0f0c, 0x0d1b110f, 0x13131210, 0x12131213, 0x0c0f0f12, 0x2265820d, 0x82100f0e, 0x333e8200, 0x0f141213, + 0x0e0d0f0f, 0x00000d0c, 0x61000100, 0x570237ff, 0x20057749, 0x29974b05, 0x22060946, 0x4c06b001, 0xba4c06db, 0x17452105, 0x4c05a648, 0x38220afe, + 0x914b7d12, 0xa7fe3224, 0x00113373, 0xff4d0002, 0x021702f3, 0x006300db, 0x1e0b4591, 0x34232223, 0x0ecf7035, 0x17323325, 0x82163316, 0x18322005, + 0x5a124bcf, 0x15220c3b, 0x051a2322, 0xaf51120f, 0x08694a08, 0x4907836a, 0x01310787, 0x191a147b, 0x14151720, 0x0e0d1110, 0x09090b0c, 0x05ef5c06, + 0x0a0b0634, 0x4612370e, 0x14131123, 0x1a191616, 0x1e1e1b1a, 0x71820720, 0x82020321, 0x27048200, 0x0f0d0c0b, 0x0d0e0d0f, 0x28080082, 0x0c0c0d0b, + 0x0b0b0b0c, 0x30303c0a, 0x12112323, 0x03021b38, 0x100b0203, 0x1510b010, 0x11131a15, 0x0a0d0d10, 0x0707080a, 0x08158206, 0x0c0b013d, 0x27261818, + 0x090a0d36, 0x04030707, 0x04050203, 0x0d0c0707, 0x03040606, 0x0a0a0808, 0x10100d0d, 0x15161211, 0x20211c1b, 0x21222425, 0x1e113221, 0x17171a1b, + 0x0d0e1212, 0x83010706, 0x182f2a00, 0x03030205, 0x06050603, 0x21308207, 0x86820d0b, 0x12041036, 0x2a212012, 0x46d3352b, 0x0f19180f, 0x43111015, + 0x0408080f, 0x09225982, 0x9d820c09, 0x0e0f2908, 0x2c0e0e0f, 0x1d1e2416, 0x0e0d1718, 0x1f1f1d03, 0x1f1f2121, 0x1314191c, 0x0a0b0d0d, 0x48000100, + 0x4802f3ff, 0x3100db02, 0x5f0da141, 0x09450d6d, 0x05414f08, 0x10232222, 0x28057341, 0x2a199801, 0x202b3a2a, 0x091c4f20, 0x1b151523, 0x05404221, + 0x3f2c8425, 0x821b3815, 0x0a304db0, 0xd951f523, 0x0d13456d, 0x7e790127, 0x0dfe1032, 0x33bd82a6, 0x01000000, 0x37ff6d00, 0x0e029801, 0x00001700, + 0x32353417, 0xdd7d7983, 0x2323080d, 0x274d6d22, 0x4616162e, 0x160b0b17, 0x29202017, 0x1238c960, 0x013b1d1e, 0x9bfe8691, 0x24242eb2, 0x690c1819, + 0x0c20061f, 0x0c20db82, 0x6c19db92, 0xd15c0c17, 0x87f5840b, 0x18af22db, 0x08ed452a, 0x84153f23, 0x0f094e2c, 0x011c3824, 0xdb8a0303, 0x755c0124, + 0xf3451131, 0x76fe2212, 0x2ddc8484, 0xff540001, 0x020f0237, 0x0089001c, 0x177d0500, 0x087f4508, 0x420acd73, 0x2d4909bb, 0x07374816, 0x5414cf75, + 0x0f910f8f, 0x08070143, 0x3332335e, 0xd9f60114, 0x1011156d, 0x06060d0d, 0x0c0d0607, 0x14141010, 0x11161615, 0x0f101011, 0x0d0c0f0e, 0x07070a0a, + 0x01020403, 0x07070505, 0x1a1a140b, 0x0b0a0c20, 0x08090909, 0x100f1208, 0x0809110a, 0x16151222, 0x1e1f1919, 0x17161923, 0x13121615, 0x0c0c1010, + 0x04040808, 0x07070403, 0x2405a15f, 0x0f0e100f, 0x840d8210, 0x0d0e2235, 0x0527530c, 0x02040432, 0x08040502, 0x44ca0d08, 0x0c0706c9, 0x110e0e0b, + 0x12260084, 0x14131212, 0x33831413, 0x0f0f0f23, 0x08008310, 0x10110f2e, 0x0b0c0c11, 0x0a0a0c0b, 0x08091008, 0x02020101, 0x0a030404, 0x0c100d0c, + 0x16170606, 0x0c0c1211, 0x03030607, 0x090a0607, 0x0f0f0d0e, 0x132a4082, 0x13121415, 0x11121011, 0xc8841212, 0x050e0f24, 0xb3820606, 0x0d060823, + 0x3049820c, 0x090a0a0a, 0x04060807, 0x07070605, 0x00330403, 0x08934700, 0xc4181b20, 0xb34e085b, 0x1a95470a, 0x47092245, 0xaa501399, 0x35352209, + 0x0a9a4b6a, 0x150b0b28, 0x291e1e16, 0x77824ae0, 0x37ff7928, 0x2602ef01, 0x13428300, 0x0b09520b, 0x84070b42, 0xdf771807, 0x211d8a10, 0x4b471716, + 0x0d13620a, 0x33163322, 0x83075d45, 0x167347d7, 0x14282382, 0x60c1ef01, 0x0d0e0f12, 0x2f05a75e, 0x07040402, 0x0c0a0a08, 0x100e0e0d, 0x0e0c0c0d, + 0x06820782, 0x0e0e0c22, 0x0d3a0582, 0x08070b0a, 0x03030404, 0x0a0a0607, 0x0d0d0c0d, 0x0314290a, 0x0c030405, 0x17850a09, 0x06050628, 0x09090707, + 0x00830a09, 0x0809083c, 0x07080708, 0x03040805, 0x1a1a1b10, 0x14141818, 0x0e0d1211, 0x05050a09, 0x27820303, 0xae0a0829, 0x0506c93a, 0x8207050a, + 0x090a260c, 0x1413120b, 0x2eaa8216, 0x17161818, 0x0f101015, 0x0e0d0f10, 0x8201020c, 0x08062d8e, 0x0d0a0b08, 0x110f0f0d, 0x0f0e0e0e, 0x0d350382, + 0x090c0d0b, 0x05031124, 0x0b0a0304, 0x0c0b0c0a, 0x080a0b0b, 0x05c16107, 0x02030326, 0x02010103, 0x02240282, 0x1a07070d, 0x1a215082, 0x37008319, + 0x17171817, 0x0b0f1212, 0x07080909, 0x00330404, 0x31000100, 0x320237ff, 0x4a056755, 0x35460d13, 0x110d7107, 0x201d7955, 0x20795537, 0x21853520, + 0x22151037, 0x1811de01, 0x0f112118, 0x0a0d0e0f, 0x0b09060b, 0x100d0c0b, 0x05785510, 0x070a0a28, 0x04050507, 0x78550104, 0x04032407, 0x550c0c05, + 0x03200a78, 0x7955df83, 0x07032e07, 0x0a130d0d, 0x06050809, 0x04030504, 0x251b8303, 0xc93f153f, 0x165552a4, 0x5509200c, 0xfd314f79, 0x0000b6df, + 0xff540002, 0x02140237, 0x008d001c, 0x1fe144cd, 0x83343521, 0x0db574fd, 0x79690d8d, 0x1b9f5e11, 0x2111e344, 0xe5440607, 0x1403210b, 0x36202182, + 0x4a092d43, 0xb9540b83, 0x5d421809, 0x4a15200d, 0x01290adb, 0x136ddafc, 0x0d0d1010, 0x37478207, 0x0d0c0d0d, 0x0505050d, 0x04040504, 0x01010203, + 0x03010201, 0x09070703, 0x26058059, 0x08090404, 0x82060608, 0x0220081f, 0x02020102, 0x09080504, 0x0e100c0c, 0x14141111, 0x15181516, 0x16151514, + 0x21121313, 0x04031011, 0x0a2a3382, 0x0e0d0c0c, 0x0f100f0f, 0xb0680710, 0x13082d05, 0x0a0a0e0e, 0x07070909, 0x04040304, 0x06274983, 0x07e344ca, + 0x82150c06, 0x12152438, 0x830e0f11, 0x0a142435, 0x820d0b0b, 0x1b0f2700, 0x13101615, 0x81830a09, 0x08050522, 0x04223283, 0xa3820302, 0x04060638, + 0x02040305, 0x0506c902, 0x0d0e0b0b, 0x12111312, 0x0e0f1010, 0x0083060e, 0x0a080822, 0xa3846d82, 0x0d0d0f27, 0x0c0c0b0c, 0x22ce850c, 0x820b0405, + 0x0908257b, 0x05040a0a, 0x4782c182, 0x6e5c1120, 0x82918206, 0x2ae18252, 0x08090607, 0x2222190e, 0x8214142b, 0x11122153, 0x11205782, 0x0f235982, + 0x8208060f, 0x08072553, 0x0d0d1106, 0x09292c82, 0x08070a0a, 0x06070a07, 0x28848204, 0x135c0133, 0x13121413, 0x27fc8214, 0x16161615, 0x1d181818, + 0x0820b782, 0x01285183, 0x0d060602, 0x1412110e, 0x08262e82, 0x0b090808, 0xba820505, 0x02030227, 0x09090908, 0x2c04820a, 0x000a0a0a, 0x005b0001, + 0x023f0200, 0xf383181b, 0x0e535408, 0x1914375e, 0x640ee915, 0xfb41134d, 0x22152109, 0x36077954, 0x223a2928, 0x14151c1b, 0x09090f10, 0x02020505, + 0x05050303, 0x82090707, 0x0b0c2dd1, 0xc0256f0e, 0x17172041, 0x0505070f, 0x0120d983, 0xa4631d83, 0x0d240805, 0x21110f0f, 0x10101818, 0x01450808, + 0x190f838b, 0x172f1019, 0x0f060718, 0x1914130f, 0x211c1d18, 0x11121212, 0x30080082, 0x0e0f0f10, 0x0e0d0e0e, 0x2a11330d, 0x191a1914, 0x0f0e0e1c, + 0x12121010, 0x0f101015, 0x0d0d100f, 0x090a0b0d, 0x03030607, 0x17170b0c, 0xe6211b1c, 0x059f464d, 0x02f3ff27, 0x000d020a, 0x09a74929, 0x5916a349, + 0x262a07cd, 0xae012627, 0x3b292a18, 0x48192b54, 0x4f2217e9, 0x4819172e, 0x012a21b3, 0x37ff5b00, 0xdb025d02, 0xc5562f00, 0x2181960f, 0x8d183510, + 0xab200997, 0x5506214a, 0x334f09c8, 0x45092508, 0x85154117, 0x4a0c354f, 0xfd31141f, 0x1134d879, 0x00010000, 0x02f4ff34, 0x001b0234, 0x110b5b77, + 0x994a3520, 0x1f955205, 0x08536618, 0x520c4b44, 0x055a05ab, 0x0c3d7206, 0x06071426, 0x14150607, 0x2d09d54e, 0x0e0e0cdf, 0x17182010, 0x0405060d, + 0x94450203, 0x0b9f5205, 0x04060526, 0x02050305, 0x29057845, 0x0c0b0b09, 0x110e0e0d, 0x2f821720, 0x2405cd52, 0x0101153f, 0x2d008202, 0x0d0e0703, + 0x0b0c1113, 0x03030605, 0x00820103, 0x09153f36, 0x07010a0b, 0x0d0c0303, 0x0f0f0d19, 0x15151312, 0x55010118, 0x2b1df15a, 0x0b100f1e, 0x0307070a, + 0x1a0c0d04, 0x123a3483, 0xff191515, 0x64c95600, 0x0f181822, 0x060a0a10, 0x0507070d, 0x0d0a0a06, 0xe268100d, 0xed0d2706, 0x0f0f1e4f, 0x53420b0b, + 0x02372606, 0x001b020a, 0x0d15572d, 0x231e1d5b, 0x5e221510, 0x54101a4e, 0x9f571299, 0x7d8a2122, 0x02268782, 0x31ff4a00, 0x87821602, 0x5f004326, + 0x14250000, 0x18067557, 0x2010e95e, 0x0cab5135, 0x5b0f2349, 0x05210b31, 0x09e97c16, 0x3e0c8176, 0x02161714, 0x763a3b16, 0x2b292926, 0x1416151a, + 0x12131314, 0x111b1b24, 0x15080910, 0x19362526, 0x340e898a, 0x19181413, 0x34221d1c, 0x03162626, 0x3f020202, 0x11b8fe15, 0x898a191a, 0x111a290d, + 0x09090812, 0x3c792208, 0x50768a19, 0x9b000126, 0x09020000, 0x2005b355, 0x09534333, 0x459b202d, 0xfe44ce17, 0x838b01ed, 0x5572a8fe, 0x77200fb3, + 0x6507a343, 0x26220cb5, 0x21432627, 0x081f5d22, 0x200f1759, 0x21214315, 0x01202182, 0x43051b6b, 0xc9265720, 0x0b0f52a4, 0x2243070b, 0x7c01242c, + 0x4354a67e, 0xfe353023, 0x0000827d, 0x28000200, 0x390237ff, 0x37001b02, 0x00004b00, 0x07376717, 0x1aebb618, 0x67087341, 0x14200b25, 0x08118b42, + 0x0f2c632f, 0x1c380f2c, 0x02030302, 0x34252517, 0x1d282832, 0x0e0e0e1d, 0x100f1c0f, 0x17141411, 0x25331a17, 0x1a011725, 0x5ee6fe5e, 0x21214646, + 0x06265d45, 0x4222222e, 0xc9212145, 0x11330b24, 0x0c99cb01, 0x0a11b718, 0x41332608, 0x25323240, 0x090f0e11, 0x14040509, 0x26732814, 0x0c231133, + 0x3365d001, 0x1a0d0d34, 0x33262718, 0x33333266, 0x089f5632, 0x8b7fb818, 0x0c00032a, 0x4d0237ff, 0x4f00db02, 0x21051f6a, 0x29663417, 0x08114a07, + 0x4d183620, 0x16220af3, 0x4b661617, 0x32332411, 0x18151433, 0x4a08b79b, 0x2323090d, 0x66221514, 0x2b821237, 0x180c574d, 0x2a0cef49, 0x121314f1, + 0x0e0f0f0f, 0x490e0e0d, 0x4708051b, 0x1f080710, 0x0a080908, 0x0a090909, 0x1b181715, 0x1c272632, 0x0e0e0e1c, 0x281c1c0f, 0x16423327, 0x1d313145, + 0x070f0f1e, 0x150c0c07, 0x251c1d14, 0x17452e25, 0x0e171620, 0x0707080f, 0x160f1008, 0x13187a17, 0x0c101014, 0x2306f951, 0x03040302, 0x0d362b82, + 0x191a1112, 0x024285c9, 0x05040401, 0x08060704, 0x0a0a0908, 0x6c820c0a, 0x0b1e3e08, 0x09080a09, 0x0d060807, 0xff000607, 0x140a0a7f, 0x201a1a14, + 0x121b1a21, 0x8a090813, 0x21101045, 0x3d2f2f21, 0x1f232428, 0x1118181f, 0x95090812, 0x5ed50232, 0x0905052f, 0x100d0c09, 0x05407811, 0x7fff4d22, + 0x2f05e56b, 0x10100e0e, 0x14151312, 0x18181c17, 0x0f0f1414, 0x27060666, 0x38000100, 0x5802f3ff, 0x1905d747, 0x570b012e, 0x53491c05, 0x87012106, + 0x21071d51, 0xa05d0b14, 0x14152506, 0x1919211c, 0x2305255f, 0x349d1d57, 0x510d275f, 0xa82f1318, 0x3b113372, 0x00010200, 0x69010000, 0x19008f01, + 0x201cdf9c, 0xa16d1803, 0x5a012c16, 0x04071a32, 0x07040303, 0x83081933, 0x8e082007, 0x1901260f, 0x3d070303, 0x8223851e, 0x03032407, 0x8504e7fe, + 0x04042811, 0x1f3c0704, 0x82040307, 0x01002981, 0xc600b200, 0x2e01b601, 0x00218782, 0xdb6f1837, 0x1437220c, 0x067b6315, 0x201fb226, 0x11102020, + 0x102f0082, 0x22221110, 0x20202022, 0x1a33e11f, 0x5807070e, 0x0b8206fa, 0x07070623, 0x37508206, 0xff5c0005, 0x02300273, 0x003100db, 0x004b0039, + 0x00650053, 0x35340500, 0x6c051d61, 0xdf590ce1, 0x06714c08, 0x14250f88, 0x32032215, 0x20338333, 0x6b838214, 0x19990e63, 0x18013008, 0x2f8d2f8d, + 0x262c0d25, 0x0e1d1c25, 0x1008090f, 0x1e171810, 0x141c1b24, 0x0f0a0a14, 0x2b1e1e0f, 0x6626372a, 0x17431743, 0x1313178c, 0x82070f10, 0x0e0d2400, + 0x84a51414, 0x21360812, 0x10101919, 0x08090809, 0x19181212, 0x01236a8d, 0x1d5999cc, 0x0b02284e, 0x1d12130a, 0x161d271c, 0x09111016, 0x0d050409, + 0x1b15160d, 0x1e29221b, 0x0b15151e, 0x2882020b, 0x2f8bf52f, 0x3e7a8a8b, 0x0a060602, 0x1a12120a, 0x39278318, 0x26fe0506, 0xa7a838a8, 0x07014a95, + 0x140d0c06, 0x151f1c14, 0x070d0d16, 0x00820007, 0x5000012a, 0x1a020000, 0x4b001b02, 0x430f7f54, 0x8558069f, 0x0c455818, 0x2b773220, 0x152c080b, + 0x01060714, 0x2c2c1ddf, 0x292a383a, 0x0e0e1c1d, 0x04040102, 0x3f0c0908, 0x08080d20, 0x02030405, 0x11110909, 0x22221919, 0x11111a1a, 0x05221182, + 0xac820b0b, 0x25492408, 0x1e3d0124, 0x1f100f01, 0x15232231, 0x0f0b0b14, 0x0f1d3b0f, 0x1b0d0e0f, 0x3126261b, 0x0b0e0d0e, 0x820d0c0c, 0x0c2e080e, + 0x0b0c0a0a, 0x1b1a210f, 0x090a1413, 0x13140a09, 0x1b241c1c, 0x11111616, 0x180a0d0d, 0x26412d2d, 0x110d1819, 0x191a1516, 0x332a2121, 0xde822828, + 0xdc24e386, 0x5d004100, 0x4c18e596, 0x195f0ced, 0x083f7408, 0x83091978, 0xe57c18db, 0x0b61670b, 0x1714153f, 0x1ce10116, 0x39392b2b, 0x1d1d2c2b, + 0x0b0c0e0e, 0x25241919, 0x06030330, 0x0a080806, 0x08ae8209, 0x0d0d1233, 0x04050809, 0x10101e3c, 0x1414281f, 0x1722232e, 0x0e0b0b16, 0x11d1fe0e, + 0x22221a1a, 0x10111919, 0x08080809, 0x191a1111, 0x22224423, 0x21410909, 0x08008210, 0x2e20215d, 0x2a363c2f, 0x141d1d2b, 0x152b0a14, 0x07090a0d, + 0x04040507, 0x03020303, 0x0c080804, 0x1711120b, 0x060e0d15, 0x2c1c1d0d, 0x1610162d, 0x281e1d16, 0x2e3b3328, 0x0c18132d, 0x180c0b0b, 0x2d222218, + 0x1522222d, 0x2c0b0a16, 0x232d582b, 0x00020023, 0x0238ff37, 0x00ec0130, 0x5a810059, 0xb14f1a93, 0x51661912, 0x07062308, 0x31650706, 0x1415210e, + 0x14201382, 0x4107b74f, 0xe14b172b, 0x3045820c, 0x16171415, 0x2c21f101, 0x252d392c, 0x161d1d26, 0x05456e16, 0x0f0f4f08, 0x1e1e1615, 0x0c2e2726, + 0x07080a0a, 0x06060404, 0x15150c0d, 0x17162c1e, 0x10030202, 0x0c220909, 0x0b0b0605, 0x21221615, 0x3030612f, 0x251e0f0f, 0x13121c1d, 0x100f0909, + 0x1f15a8fe, 0x1e29281f, 0x0a15151e, 0x0c06060a, 0x1210100b, 0x00821412, 0x14131331, 0x0c0f0f13, 0x0a07060c, 0x0d1c910b, 0x8208080e, 0x19142164, + 0x1b280082, 0x1a1a1b1c, 0x10161519, 0x01255882, 0x0f0b0c08, 0x0800820e, 0x0e0f1045, 0x06060d0c, 0x0a211110, 0x0a0b0a0a, 0x11130504, 0x20191616, + 0x0f101718, 0x23230908, 0x1d1d2745, 0x0d030713, 0x1a191313, 0x36292121, 0x131a2929, 0x090a0a09, 0x1b1b1213, 0x17171c21, 0x0c0d1211, 0x82040809, + 0x09083c00, 0x11120d0d, 0x211c1617, 0x02001b1b, 0x38ff1c00, 0xe6014d02, 0x85006b00, 0x18050000, 0x4f081b57, 0x0726070b, 0x37362726, 0x515e3736, + 0x07a15608, 0x2108334d, 0xaf5c3332, 0x06ad4b09, 0x084ba318, 0x2f4d2220, 0x0d495105, 0x03200d87, 0x4b0c0b49, 0xcf410599, 0xea012e05, 0x0f0d2242, + 0x13131210, 0x0f101414, 0x2df9820f, 0x070e0d0e, 0x150f0f0a, 0x121b1b25, 0xd7820911, 0x15165008, 0x0f271e1e, 0x0a0a0d0c, 0x060d0b0b, 0x1c1d0f04, + 0x2d2d592b, 0x56562a2b, 0x09092b2c, 0x20080e12, 0x04051010, 0x0e0e0a0a, 0x15151112, 0x17171a18, 0x10101213, 0x0d0d0f0e, 0x2e161798, 0x0a0f0e14, + 0x1305050a, 0x0c182513, 0xc80e0f1e, 0x82100f17, 0x0420080f, 0x05050302, 0x210a0607, 0x07070a11, 0x21010404, 0x2c2c2626, 0x38322e2f, 0x1b1b2928, + 0x02020d0e, 0x20085082, 0x0c170e09, 0x6f37360b, 0x3c770306, 0x7b3e3f3c, 0x0b15254a, 0x4b25250b, 0x21281122, 0x14191921, 0x08ac8215, 0x0c0a0d31, + 0x09090b0b, 0x0d0c0b0c, 0x8c011011, 0x07212042, 0x170e0f07, 0x21432016, 0x151c1c39, 0x00582b15, 0x50000100, 0x1a0238ff, 0x5b00ec01, 0x18050000, + 0x20127f6e, 0x14eb4437, 0x52075941, 0xad4106cf, 0x07954108, 0x0810ab4b, 0x1a021438, 0x3a703738, 0x1d1d2d2c, 0x04040f0f, 0x0e0d0807, 0x12203e15, + 0x090a0d0e, 0x090a0504, 0x1b1b1212, 0x21224224, 0x3b3c1e1f, 0x07081d1c, 0x081d3b10, 0x03030605, 0xb2830201, 0x17121329, 0x1a171817, 0x481a191a, + 0x3b08052c, 0x5d0f0808, 0x0d0c2e2e, 0x21221817, 0x1011132b, 0x0e0f0e0e, 0x0e0f0d0f, 0x11100e0e, 0x15161c13, 0x0807100f, 0xd3391d1c, 0x201f3f6a, + 0x1b34191a, 0x09181919, 0x0d0d0b0b, 0x1e0d0c0d, 0x13264182, 0x0a0a0f0e, 0x8b6e0605, 0xeb212d09, 0x4f000100, 0x190238ff, 0x8700ec01, 0x880df943, + 0x140741d1, 0x4205bd51, 0x195a0633, 0x0fd15106, 0x2110c953, 0x21442322, 0x0c27520e, 0xed181420, 0x31080911, 0x2a1cdf01, 0x2c3a3829, 0x0f1d1d2c, + 0x0503020e, 0x100b0b05, 0x0b112040, 0x0305060b, 0x11090903, 0x241a1a11, 0x11191920, 0x1d090811, 0x091c3b1e, 0x895e0d18, 0x02530806, 0x0a060603, + 0x120e0e09, 0x151a1712, 0x09101116, 0x03020108, 0x05050403, 0x070f1b36, 0x1b0e0d07, 0x3227271b, 0x1a282837, 0x070e0e1a, 0x160e0e07, 0x1d3b1e15, + 0x9c0e0f1e, 0x0c0b0b16, 0x2118170d, 0x0d0f2a21, 0x0f0a0b0d, 0x0e12100e, 0x0d0a0a0e, 0x411b0d0c, 0x072d0556, 0x130d0e06, 0x0f1f1a13, 0x311d1d39, + 0x25838211, 0x16141412, 0x00820d0e, 0x790a0a21, 0x0b3e067b, 0x09181112, 0x0d0d0a0b, 0x140f0e0e, 0x281d1919, 0x14141e1f, 0x0b0c0b0a, 0x21201617, + 0xe7611d2a, 0x03062b06, 0x3d23240a, 0x222c0d19, 0x00820021, 0x5b00032f, 0x26020000, 0x2700db02, 0x6f004700, 0x08714f00, 0x43343521, 0x33230ff5, + 0x45161732, 0x77460953, 0x05235117, 0x74161721, 0x9d470b0f, 0x0857440b, 0x08066b45, 0x3a26023b, 0x3972733a, 0x311a1939, 0x0b13141a, 0x2b06050c, + 0x2b55552a, 0x170c0c2b, 0xfe292a51, 0x10110ba1, 0x11101717, 0x05050b0b, 0x0e0d0707, 0x11110f10, 0x0e0e0f10, 0x06060707, 0x06b26520, 0x08111126, + 0x0a050509, 0x3708f982, 0x11100f0f, 0x11111110, 0x0d0d0f0f, 0x05050a0a, 0x77ee0809, 0x3b3b3b3c, 0x2f304d77, 0x08030612, 0x11110c0c, 0x4f1b1717, + 0x25252726, 0x1c1d264a, 0x0b030615, 0x0d973737, 0x062b8b82, 0x12130d0d, 0x15141d16, 0x82060c0c, 0x0c32080e, 0x1b14150c, 0xfe111217, 0x0a0a1679, + 0x15160b0a, 0x20261e1e, 0x14141a1a, 0x09090e0e, 0x06050506, 0x0e0f0909, 0x1a1a1414, 0x1e1e2620, 0x02000000, 0x04821700, 0xe6014826, 0x67004900, + 0x230fd747, 0x36373435, 0x430d2f45, 0xd1630ba7, 0x23222406, 0x45363736, 0x07200f39, 0x8b083561, 0x05634119, 0x14153a08, 0x46011617, 0x291e1e14, + 0x1722222c, 0x2e0b0c18, 0x10125e2f, 0x0c0e0d11, 0x03040a0c, 0x0c0b0c0a, 0x0f0e0d0b, 0x141e1d26, 0x1e0a0a14, 0x1b363c1d, 0x101a1a35, 0x050c2110, + 0x2dd28215, 0x100bd00a, 0x14291610, 0x11080915, 0xe9820e1d, 0x0a0b5a08, 0x04050506, 0x0e0f1b38, 0x1f1e100f, 0x093d2d2e, 0x39397205, 0x05060202, + 0x0d0d0909, 0x06050909, 0x0e0d0202, 0x28281a1a, 0x520a1535, 0x29273d3d, 0x254c3a3a, 0x21214212, 0x452b1515, 0x2c2c3b23, 0x07081010, 0x72391c1c, + 0x11112238, 0x0f0f0908, 0x3c211818, 0x1a1a231d, 0x08db4900, 0xec011927, 0x00003b00, 0x0cb74421, 0x20085742, 0xa3371906, 0x37362108, 0x430c834d, + 0x012d0bc9, 0x1f193110, 0x0e0d1717, 0x3a390707, 0x08a18272, 0x0e080756, 0x1e17170f, 0x12191831, 0x060d0d13, 0x07030306, 0x0f0b0b07, 0x1913130f, + 0x12191920, 0x19090912, 0x1c1d1919, 0x24242021, 0x3b3a7428, 0x29733a3b, 0x21202524, 0x1e191c1c, 0x23232120, 0x16202222, 0x12121415, 0x0b0a0e0e, + 0x0a0a0506, 0x1e1f1515, 0x4140432a, 0x4f28b384, 0x1a0239ff, 0x6300e201, 0x2033a345, 0x12974423, 0x777d1383, 0x4807200d, 0x02250aa1, 0x7037381a, + 0x05ab453b, 0x0603032b, 0x100b0b06, 0x090c1c3a, 0x08d4830a, 0x12090945, 0x231b1a12, 0x1e202141, 0x08183b1e, 0x161c0b15, 0x080d0e16, 0x190d0d07, + 0x37282819, 0x2638384c, 0x07131325, 0x1a0f0e08, 0x1a23251a, 0x0912131a, 0x2f5c0e09, 0x1a0c0d2e, 0x2d242319, 0x0d111012, 0x840e0f0e, 0x100d3400, + 0x171f1210, 0x08111117, 0x3b1e1d08, 0x2040080f, 0x82123620, 0x0c26086d, 0x1c161010, 0x0e0e1516, 0x18300706, 0x17170b0b, 0x192a2121, 0x0f101414, + 0x06070b0b, 0x0d0e0503, 0x1b1c1414, 0xbb461124, 0x01192206, 0x06a75cec, 0xa1642620, 0x5e07200d, 0x3321088f, 0x890e1936, 0x0949540b, 0x230d9f59, + 0x14171415, 0x16250382, 0x26232215, 0x69611827, 0x0bf55e08, 0x480bff41, 0x4308134b, 0x203fdc01, 0x140e0d06, 0x17151615, 0x0c0d0d0d, 0x080a0b0b, + 0x1305050a, 0x1c16160f, 0x03020101, 0x0f181720, 0x39080710, 0x2b3b7138, 0x0e1d1c2c, 0x0402020e, 0x07050603, 0x03040404, 0x01020204, 0x1a350101, + 0x03240583, 0x03030302, 0x2c05ca4a, 0x45222201, 0x101a1a22, 0x06080910, 0x05526606, 0x11114908, 0x12121311, 0x0e0e1211, 0x06060a0b, 0x14141bc8, + 0x07070d0d, 0x05040302, 0x0b090706, 0x16160606, 0x02030c0c, 0x231f0301, 0x28262722, 0x386f2928, 0x1c0e0e38, 0x3228281b, 0x090f0e14, 0x0c0a0a09, + 0x0a080707, 0x100c0c09, 0x05327782, 0x05050405, 0x0a0a0a0c, 0x070b0b0e, 0x06070808, 0x21820a0a, 0x110e0e38, 0x0a26274d, 0x1f14140a, 0x22272a1e, + 0x181c1c23, 0x10141418, 0xba410c11, 0x0e0d2806, 0x00000d0d, 0x82490002, 0x02142604, 0x004300dc, 0x0eb1456b, 0x69443620, 0x0c494c0c, 0x220d7945, + 0x82232215, 0x212d851d, 0x23551415, 0x13154b0f, 0x16172908, 0x14021617, 0x75703838, 0x0f0e3b3b, 0x2a2a1d1d, 0x16151a37, 0x0c0d1010, 0x04020809, + 0x0d0b0b05, 0x1110100d, 0x0e0f1110, 0x33080082, 0x09080b0b, 0x17460504, 0x74683334, 0xd2fe3a3a, 0x19151511, 0x1117171e, 0x09080710, 0x19101109, + 0x14182018, 0x0c0f1013, 0x0307080b, 0x07040404, 0xe80c0c08, 0x47082882, 0x3d7c3d3e, 0x1f1f2d2e, 0x0404100f, 0x0a0b0707, 0x13285110, 0x0d0c1010, + 0x06050909, 0x02020304, 0x07060405, 0x0a090808, 0x1408160b, 0x2223450a, 0xf1592d2c, 0x06060ddb, 0x14150a0a, 0x2e2b2120, 0x18182322, 0x07060c0b, + 0x14398a83, 0x16151614, 0x15151616, 0x00111115, 0x00500002, 0x02190200, 0x003100d0, 0x099f4541, 0x83343521, 0x36372201, 0x05c95033, 0x2105af4a, + 0x694c3332, 0x0bb14206, 0x070b5118, 0x4e057348, 0x65080553, 0x38703a2d, 0x54292937, 0x50a039ad, 0x0b121124, 0x0c0c0906, 0x1414100f, 0x2a2a371b, + 0x0e0e1d1c, 0xadfe0e0f, 0x46432222, 0x22222323, 0x23224545, 0x100f203f, 0xd973393a, 0x4f02016d, 0x11332929, 0x672a1514, 0x0c0c0f23, 0x04040707, + 0x1e1e0f0f, 0x3d3d2e2d, 0x59972e2f, 0x2d2d2c2d, 0x2c2b575c, 0x01002c2d, 0xb7821c00, 0xe6014d28, 0x00005900, 0xc1482233, 0x15834b05, 0x4b215346, + 0xf941055d, 0x26272305, 0x0f862223, 0x16171439, 0x322041e0, 0x0c0b1819, 0x21211818, 0x0e0d122a, 0x0a0a0b0b, 0x8303060b, 0x0d0a2906, 0x212a100c, + 0x0c181922, 0x21081d82, 0x2c1d3c2e, 0x12131716, 0x13010224, 0x08081013, 0x0809143c, 0x250c1a10, 0x19191213, 0x38363734, 0xfa83101f, 0x0e1c3908, + 0x0602030d, 0x0d0a0a05, 0x040b0a0f, 0x0d020205, 0x2a1c1c0e, 0x1121382a, 0x33363537, 0x302f2f2d, 0x1a322c58, 0x30181919, 0x2c562062, 0x1b191830, + 0x2952361a, 0x002f3032, 0x5020ef82, 0x1a22ef82, 0x4547d902, 0x21df8211, 0x35483332, 0x0da76306, 0x080d0e19, 0x35443220, 0x0b6f4805, 0x0dad4018, + 0x19141521, 0x5108a122, 0x01360a5d, 0x2a2b1ce1, 0x2b2a373b, 0x0f0e1e1e, 0x3b190d0c, 0x0c0b171d, 0xd4830909, 0x19232124, 0xe882101a, 0x23222b08, + 0x1c081845, 0x14131b0d, 0x07080e0e, 0x11110809, 0x49241a1b, 0x1c3a2425, 0x2b3c1d1e, 0x16152120, 0x06060b0a, 0x12120b0a, 0x334e1e18, 0x0e0e2505, + 0x0e0e1b37, 0x5f084d82, 0x3226261a, 0x1521212c, 0x2420211d, 0x111a1922, 0x09080711, 0x1d131209, 0x284f261d, 0x06102f27, 0x0e0b0c06, 0x10100f0e, + 0x090f100f, 0x1b0d050a, 0x0d11291b, 0x0b050a0d, 0x1812110b, 0x13172018, 0x0c101013, 0x0307070b, 0x1512130d, 0x241d1c16, 0x00282834, 0x50000100, + 0x1a0239ff, 0x4900f901, 0x83099b46, 0x301522eb, 0x06574d15, 0x35103523, 0x0b5d4606, 0x2320f985, 0x08abe618, 0x21082541, 0xef423534, 0x377b0806, + 0x3b1a0210, 0x3870753b, 0x201f3e37, 0x24494023, 0x1c37a325, 0x0e0d1515, 0x0f100707, 0x32312120, 0x23223244, 0x0a0a1414, 0x17170c0b, 0x1e2c2121, + 0x512c2727, 0x08385554, 0x2b30305f, 0x0102562b, 0x1b192d06, 0x013f201f, 0x06126e49, 0x0f0a0913, 0x1614130f, 0x1c251a17, 0x0913121c, 0x041b3409, + 0x0f090904, 0x1618150f, 0x0e141417, 0x1429080e, 0x06050604, 0x080b0b0a, 0x82007ffe, 0x06eb4200, 0x00dc0223, 0x11eb4265, 0x2108a155, 0xdb621716, + 0x33322205, 0x20138232, 0x200d8232, 0x07f94216, 0x201a4949, 0x22f78222, 0x4e303534, 0x9f080b65, 0x16171415, 0x342347ee, 0x05051a1a, 0x11100a0a, + 0x1e1d1717, 0x2d2d2524, 0x02020335, 0x49485b06, 0x01040837, 0x2a070e15, 0x06111e1e, 0x1d1a1501, 0x28284f27, 0x4235191a, 0x1c1b3621, 0x1d211111, + 0x0808100f, 0x0808143c, 0x1a152914, 0x1d1c0c0d, 0x42393a31, 0x201d1120, 0x2022211f, 0x1c202121, 0x141a1a1d, 0x08120e15, 0x33142209, 0x090e5333, + 0x170c0b05, 0x0b180202, 0x6634330b, 0x353a172d, 0x2f2b3135, 0x1f3d3330, 0x13232345, 0x25702714, 0x120c4847, 0x13120c05, 0x34452222, 0x33333b1a, + 0x22080b43, 0x4a5500cb, 0x65180e51, 0x8b670813, 0x0aaf5c08, 0x410c0b5b, 0x3743072d, 0xf759180a, 0x0126080b, 0x2a2b1ce0, 0x2b2a393a, 0x0e0f1d1d, + 0x22231744, 0x19192345, 0x08081111, 0x07070403, 0x0c130e0d, 0x0b0b0b0c, 0x0b820605, 0x12130d2e, 0x06060a1a, 0x0e0d1416, 0x04040809, 0x0c2e1183, + 0x10150c0d, 0x0409080f, 0x3c0e0f04, 0x00820f1e, 0x1e1e3108, 0x013d2d2e, 0xc4fe7762, 0x2b2b579d, 0x15160b0a, 0x18271e1f, 0x0f0e1313, 0x080b0e0d, + 0x0a090809, 0x10110e0d, 0x10101111, 0x0f0e100f, 0x071d0807, 0x9a820082, 0x0a072208, 0x0a0a0a0b, 0x0d080808, 0x1312100f, 0x381d1717, 0x00002c2b, + 0xff170002, 0x02520239, 0x0035004f, 0x121d4e5f, 0xe9822620, 0x69333221, 0xd98b0afd, 0x2205ed42, 0x50010607, 0xa9480c65, 0x16272105, 0x22222982, + 0xf7423623, 0x82418306, 0x01220803, 0x22221bb1, 0x33334127, 0x11122525, 0x017e3f3f, 0x38020202, 0x0203011b, 0x1c1b1f02, 0x14131717, 0x01731110, + 0x04052105, 0x3a064251, 0x30a8fe17, 0x24316030, 0x0c181924, 0x13090a0c, 0x2a1e1f13, 0x01030202, 0x85011c37, 0x282e0800, 0x14131e1e, 0x0eac0a09, + 0x15150706, 0x3f3e2a29, 0x54549453, 0x23221e14, 0x26261716, 0x0b0a0517, 0x14141010, 0x1b1a1818, 0x1d1d1e1d, 0x04821e1e, 0x1a1a1c22, 0x34086a82, + 0x85220112, 0x11114242, 0x32322221, 0x2f2e3a41, 0x19182423, 0x48483f0e, 0x1616102f, 0x2f2e2d18, 0x18190d1f, 0x2f2f2324, 0x00010000, 0x0239ff1c, + 0x00e70125, 0x31a34a95, 0x57182720, 0x15260ad3, 0x15060706, 0x11822322, 0x82342721, 0x0e156617, 0x82222321, 0x59362013, 0xfd6d0977, 0x0d73480c, + 0x2a0f3b47, 0x37250210, 0x2d3b6e37, 0x501e1d2e, 0x0f360581, 0x1e3b150e, 0x070e0e13, 0x0a040308, 0x1b131209, 0x2041251b, 0x0b820521, 0x0c0b0a2f, + 0x0b0c0c0d, 0x0206050b, 0x162d0201, 0x25008201, 0x0a1b0e0e, 0x5d630706, 0x05043506, 0x0a090804, 0x14141312, 0x0c030306, 0x06080709, 0x07070606, + 0x04200482, 0x6b080082, 0x06050503, 0x07070505, 0x0c0d0d09, 0x0b0b0a0b, 0x0b04060a, 0x0d0d0c0b, 0x20141010, 0x13131b1a, 0x5a14090a, 0x0c0d2d2c, + 0x2223191a, 0x1211152d, 0x0d0e0f0e, 0x0f10110d, 0x100f0e0e, 0x16171d11, 0x08091111, 0xea391c1c, 0x11111575, 0x06050c0b, 0x0f0f0808, 0x17211818, + 0x1111191a, 0x3f111d1c, 0x0101201f, 0x04030202, 0x05080606, 0x06200082, 0x0b288182, 0x0a0b1616, 0x09090c2a, 0x0320b082, 0x04211b83, 0x08198204, + 0x0303042a, 0x05050102, 0x11110909, 0x12111a19, 0x04050808, 0x13140a09, 0xfe271d1d, 0x000200f8, 0x0238ff17, 0x00e6014a, 0x0091007b, 0x2906f969, + 0x14333235, 0x32331617, 0x014e3233, 0x063d4c0a, 0x710bf74d, 0x47180dfb, 0x34200e95, 0x4e052145, 0x734b0d67, 0x0be55010, 0x718a7384, 0x07222d08, + 0x01141506, 0x6c091263, 0x1f3c3536, 0x0f3f1f1f, 0x22234508, 0x1e0e0706, 0x0e0d1b0a, 0x0c0c0606, 0x0e0e1b1a, 0x07070708, 0x11100d0d, 0x50088c82, + 0x15141715, 0x10141314, 0x060c0c10, 0x180c0b05, 0x2c222217, 0x0d0f1012, 0x0a0b0b0d, 0x1e170306, 0x1b24231e, 0x0912131b, 0x0a050509, 0x140f0e0a, + 0x3a151428, 0x159ffe39, 0x13282c16, 0x170c0c14, 0x14290c1a, 0x2d2ec814, 0x1d1c3b5c, 0x20341a1a, 0x3816820f, 0x12111236, 0x2f1d3923, 0x0e0e1818, + 0x26203f1e, 0x191a1f20, 0x0d0c1213, 0x31008206, 0x10100b0a, 0x1a1a1616, 0x3014291f, 0x18182424, 0x9e4e0c0c, 0x0c173006, 0x180c0c0b, 0x2d222118, + 0x131a1a20, 0x820f0f14, 0x1c153a7e, 0x1120221b, 0x012b2b55, 0x232346b9, 0x4f3d1e1f, 0x13142728, 0x2a3d1f1f, 0x2a008200, 0xff420001, 0x02090238, + 0x447d00cb, 0x40181259, 0x15210c3f, 0x05574414, 0x4a096b45, 0x3f470535, 0x109d4c07, 0x7e0cdd4e, 0x322410d1, 0x36353433, 0x32304184, 0x14151033, + 0xd3010607, 0x392a291b, 0x1e2b2b3a, 0x3b052043, 0x130d0d07, 0x0c121d3b, 0x0307070c, 0x13090803, 0x231a1a12, 0x10191a24, 0x09080711, 0x1d280d82, + 0x1017281d, 0x060b0c10, 0x3c081d82, 0x07080506, 0x091e3c0a, 0x04040607, 0x05040202, 0x0c0d0a0a, 0x11111010, 0x1a191a13, 0x13131918, 0x0103050e, + 0x0d0d1541, 0x0e0e1d8f, 0x1a1b0d0d, 0x132b2322, 0x0d0d0f10, 0x110f0d0e, 0x3e07830f, 0x161d100e, 0x09111116, 0x140b0a09, 0x2a1f1f14, 0x1f0e0d1a, + 0x110e0d0b, 0x1f2f2f41, 0x47100f20, 0x0f200618, 0x10285382, 0x0d090e0e, 0x10110f0f, 0x1a220082, 0x81821516, 0x22089f82, 0x06070404, 0x11100c0c, + 0x393a2614, 0x1b1a1e38, 0xe338fe15, 0x002c2c3b, 0x00010000, 0x0237ff1c, 0x6ce7014d, 0x272005df, 0x4c081341, 0x254e0885, 0x34332206, 0x18098235, + 0x2112616f, 0x57443332, 0x08d9470a, 0x25510620, 0x23222212, 0x0fd74734, 0x8313254e, 0xe8013013, 0x330d0d19, 0x140c0b04, 0x18171614, 0x820c0d0d, + 0x0b0c3402, 0x10030409, 0x100f0f0e, 0x0b25264c, 0x1f16170a, 0x83132a1f, 0x081882df, 0x12020671, 0x28261d1c, 0x15151e1e, 0x15150b0a, 0x0809122a, + 0x100f1e24, 0x21221111, 0x08070f10, 0x0808143c, 0x260c1a10, 0x04041213, 0x0a0a0807, 0x0e0e0c0c, 0x0e0d0f0e, 0x17161a0e, 0x10101313, 0x0b0c0e0d, + 0x121601c9, 0x070e0e12, 0x05020207, 0x0a070704, 0x1605050b, 0x070a0a14, 0x41423d03, 0x3a0d1945, 0x1d1d2b2c, 0x03030e0f, 0x09090606, 0x820c190d, + 0x1b340891, 0x3528271b, 0x313a0b15, 0x27012a31, 0x442a2828, 0x1c1d3822, 0x6d291514, 0x29316024, 0x1f1f1415, 0x1d162b3d, 0x15151919, 0x0e0f1211, + 0x0a0a0c0c, 0x0e060908, 0x0b32c882, 0x0f0f0d0d, 0x01001413, 0x39ff4f00, 0xdd011902, 0x1b4a5100, 0x057b600d, 0x35343525, 0x47062322, 0x4344051f, + 0x116d5507, 0x42056352, 0x323c10f9, 0x19021033, 0x75703738, 0x1f3f3b3b, 0x43462423, 0x04062121, 0x100d0e0b, 0x18141410, 0x0806615b, 0x1108084c, + 0x261a1a10, 0x161d2548, 0x0d111017, 0x0407080c, 0x11090904, 0x241c1b11, 0x1218191e, 0x43090911, 0x2c581717, 0x5e2f2f2c, 0x1c1e1e3e, 0x1c56391c, + 0x0609090b, 0x0f030305, 0x271e1d0e, 0x1e243227, 0x1719191e, 0x12121517, 0x01821011, 0x12122408, 0x22161313, 0x14131a1a, 0x07070a09, 0x15150e0d, + 0xfe3db81b, 0x0002008c, 0x0200001c, 0x00db021a, 0x4999007d, 0x355b0d21, 0x06154508, 0x220b1b4d, 0x42333217, 0x0721062f, 0x16cd6d06, 0x5a182220, + 0x4d45079b, 0x82458b0d, 0x87142039, 0x14172203, 0x6d981807, 0x10875b0c, 0x271ae62a, 0x1c213327, 0x1318181c, 0x3e06f44e, 0x06060404, 0x13120e0d, + 0x201f1a19, 0x14141725, 0x0d0d1111, 0x11020808, 0x12232312, 0x54143b12, 0x5e0806ce, 0x050a0a0e, 0x33030306, 0x0e06071a, 0x1c16150e, 0x10121216, + 0x080c0c10, 0x0b080307, 0x140e0d0b, 0x1a241914, 0x0911121b, 0x0c0d010a, 0x1b13d2fe, 0x1821221b, 0x080f1018, 0x11090807, 0x231a1a12, 0x09212143, + 0x0f1c390a, 0x0b06050e, 0x120e0e0a, 0x17141412, 0x17171616, 0x1c1d1d1f, 0x8217171b, 0x09260839, 0x08080404, 0x5b0f0c0b, 0x1a19322d, 0x0b311a19, + 0x19050b04, 0x0c0c1312, 0x06060706, 0x15150b0c, 0x20212c1e, 0x87831515, 0x0b0a2508, 0x18171112, 0x0a0b1111, 0x0a0a0506, 0x1c1c1313, 0x1c1d2f24, + 0x13130f25, 0x22221a18, 0x2a2a362d, 0x0b0b171c, 0x3206894f, 0x1723242f, 0x2b0c0b17, 0x232f562b, 0x00000022, 0x824f0002, 0x021a2d04, 0x005300db, + 0x3300006f, 0x37343534, 0xc94e0382, 0x1415220f, 0x074e1807, 0x23222111, 0x2612f95b, 0x26272627, 0x4e232223, 0x222109c5, 0x07314413, 0x82173221, + 0x4835202f, 0x30080bdb, 0x0b014f14, 0x2317170c, 0x242e2f24, 0x10181c22, 0x190b0b13, 0x0e16151e, 0x0907070e, 0x1a121109, 0x1e3b2419, 0x0f131217, + 0x080b0b0f, 0x04030408, 0x964a1804, 0x02162107, 0x05300082, 0x20204103, 0x050a4343, 0x32201f0d, 0x0d0e0d0c, 0x07243682, 0x1a351f1e, 0x08059746, + 0x6969455d, 0x31313666, 0x1e1e2925, 0x0a0a1414, 0x11140809, 0x1522221c, 0x0c271d1c, 0x1d1d1515, 0x2a252121, 0x1d1e2424, 0x0f161b1b, 0x15161213, + 0x18181617, 0x15161716, 0x12131414, 0x0b0b0e0f, 0x23010605, 0x45ce4624, 0x0c19af01, 0x2002010c, 0x2d101919, 0x06061716, 0x14130c0c, 0x8200641a, + 0x00012800, 0x0239ff2b, 0x5df3013d, 0x35450f1d, 0x06e34b06, 0xc9181520, 0x074f0a5d, 0x1fbb180d, 0x0c616d15, 0x45085d5e, 0x15200b39, 0x08152d4f, + 0x3020fca8, 0x34453f2f, 0x11222135, 0x341a1a11, 0x24090913, 0x0c151529, 0x2117160b, 0x1e272e22, 0x0a17161e, 0x0b05050b, 0x1911110b, 0x1d3b1745, + 0x0a100f15, 0x0505050a, 0x100a0a04, 0x0707140f, 0x07080908, 0x03060607, 0x1f3d0103, 0x08080404, 0x07100c0c, 0x0a0a0909, 0x07070908, 0x06060404, + 0x10100b0a, 0x13141c15, 0x05060b0c, 0x1e8b1110, 0x15140f0f, 0x3f3f2928, 0x4c0f1f54, 0x0a545050, 0x3c120404, 0x32434040, 0x32334319, 0x10102121, + 0x16160b0b, 0x1c2b2021, 0x0d0d1515, 0x10300707, 0x0a0b0605, 0x12121010, 0x51820d0d, 0x02070831, 0x05040403, 0x0a0a0807, 0x10130f0f, 0x83090d0c, + 0x0303237d, 0x13840504, 0x0d0c2608, 0x11111311, 0x0d0c0e0d, 0x1003060a, 0x12111211, 0x321b1716, 0x02002829, 0x00004500, 0xcb020f02, 0x2b001700, + 0x0c155900, 0x1732332b, 0x33321716, 0x33323534, 0x07375310, 0x5b057f46, 0x02260595, 0x733a390f, 0x00823972, 0x36723b08, 0x080c2120, 0xfe164302, + 0x191910b4, 0x22234523, 0x44442222, 0x07082221, 0x3d3c7af3, 0x7c7a3c3c, 0x0e0e3f3f, 0xfe46d01b, 0x0a16fa9e, 0x592b2c0a, 0x2d2d2c5a, 0x212d5a2e, + 0x00820021, 0x5100022c, 0x4e020000, 0x7300db02, 0xdf44a300, 0x172f470d, 0x180ca144, 0x44102354, 0xf95109ed, 0x10e95206, 0x230c115b, 0x35060706, + 0x46168957, 0x8b510b1d, 0x0151080b, 0x1b1b1793, 0x2827341f, 0x0e0e1b1c, 0x12130909, 0x19221b1b, 0x0e0e1314, 0x07080b0b, 0x0b0c0803, 0x1313100f, + 0x15151d15, 0x07070e0e, 0x03031a33, 0x0a090605, 0x0d0c100e, 0x05060a0a, 0x1211143b, 0x12112423, 0x0d090307, 0x1411100d, 0x1f261714, 0x4654181f, + 0x05934307, 0x130e1026, 0x04050913, 0x26051e45, 0x10111010, 0x820f1012, 0x0d0c2501, 0x05050a09, 0x2106dc6a, 0x604e1110, 0x0d0f3605, 0x060b160d, + 0x1e101005, 0x3e2e2f1f, 0x1d256fde, 0x0913121d, 0x273b8209, 0x1911110b, 0x0c111116, 0x0a2a1d82, 0x2015150a, 0x151e2c21, 0xf7590b15, 0x13260806, + 0x040c1912, 0x1a31050a, 0x32191a19, 0x0c0f2266, 0x0408080b, 0x11090904, 0x1b171712, 0x1f1d1e1c, 0x16161717, 0xab821417, 0x720e0e2e, 0x1e191914, + 0x1419191e, 0x0a0f0f14, 0x052a5982, 0x0e090804, 0x1812130d, 0x15821d18, 0x10161523, 0x28638310, 0x0a0a0504, 0x00000e0f, 0x05b35102, 0x00cb0225, + 0x4a93006f, 0xcb431675, 0x09874308, 0x135f6118, 0x0706272c, 0x27220706, 0x37343526, 0x33833336, 0x32353423, 0x05db4b33, 0x22220783, 0x1f821423, + 0xfd511420, 0x8201200d, 0x594b9327, 0xe1380c5d, 0x3a2b2b1c, 0x1d2b2b39, 0x020e0f1c, 0x08050502, 0x09110b08, 0x050a2509, 0x0a260082, 0x100c0d09, + 0x5f41100f, 0x05615b06, 0x2c161622, 0x48082982, 0x06050b01, 0x27264e16, 0x0a502828, 0x3b070b0b, 0x0c0b1814, 0x1f3f1745, 0x01150a0a, 0x2b161501, + 0x0e121124, 0x0bd1fe0e, 0x1515100f, 0x050a1010, 0x02020304, 0x06060102, 0x0f0e0d0d, 0x0e0f0f10, 0x07060d0d, 0x17980505, 0x2900820c, 0x22221817, + 0x0d0e102b, 0x0c820b0c, 0x07060c31, 0x0d0d0918, 0x10101411, 0x0a090d0d, 0x82030707, 0x07073b00, 0x0e0e0a0a, 0x26141111, 0x1b181f1f, 0x02181818, + 0x26040101, 0x274f4c27, 0x00820127, 0x339a3208, 0x130e50a0, 0x12391914, 0x0d121319, 0x11050409, 0x1914140f, 0x32232417, 0x0123232e, 0x06060ca0, + 0x060d0506, 0x09080808, 0x190a0909, 0x0c0c1112, 0x2d118205, 0x12120c0c, 0x1110151a, 0x02000000, 0x04825900, 0xcb022426, 0x2f001f00, 0x230afb43, + 0x33323510, 0x0a696b18, 0x41323321, 0x052005a3, 0x3508474d, 0x22232627, 0x24020607, 0x72733939, 0x15413a3a, 0x0d0a070e, 0x7d82100d, 0x2935182e, + 0x0e1d1c29, 0x2392fe0f, 0x22444422, 0x05820082, 0x7bf6232c, 0x3d3e3d3e, 0x755f017c, 0x858247d6, 0x0431dc82, 0x1f1f0f10, 0x593c2e2e, 0x2d2c2c2d, + 0x2d2c5959, 0x054b4b2d, 0x39ff5028, 0x47021a02, 0x35427100, 0x1795431d, 0x280f195f, 0x26353435, 0x34272627, 0x0c394235, 0x2005597b, 0x08454627, + 0x08070b44, 0x1de00122, 0x393a2b2c, 0x1c1d2a2a, 0x03020e0e, 0x0a0b0606, 0x0909120f, 0x07060a24, 0x02010303, 0x090a0505, 0x1022e582, 0x77430f10, + 0x0d0d3305, 0x04050a0a, 0x0b0b0605, 0x2b1a1313, 0x331f1515, 0x03831f33, 0x1f123736, 0x20203435, 0x1b1f3534, 0x131a351b, 0x050b0b12, 0x8f0f0e06, + 0x67085382, 0x1b1c0d0e, 0x152f2626, 0x0e0f1111, 0x0a131111, 0x0f150506, 0x09090d0d, 0x170a0a0a, 0x10111313, 0x08090c0c, 0x05040405, 0x0c0d0908, + 0x14131110, 0x15141617, 0x14131312, 0x24242914, 0x0b19321f, 0x380b1211, 0x12130c1d, 0x551c520c, 0x12120c2a, 0x0c1c370c, 0x270c1314, 0x1f1f1014, + 0x1617192b, 0x18181516, 0x26262f1c, 0x28054b47, 0x02000046, 0x00db0211, 0x0951459e, 0x35343528, 0x15303332, 0x1e431614, 0x14c85b15, 0x15932220, + 0x200c5247, 0x560d8526, 0x984c0d80, 0x09505f0f, 0x0811ae64, 0x1cd80128, 0x74392a2b, 0x18463a3a, 0x141a4442, 0x0b0f0f14, 0x0307070b, 0x08030403, + 0x0c0a0a08, 0x2a531f5e, 0x060a0a0c, 0x00820306, 0x85060621, 0x0b292811, 0x06060909, 0x45020302, 0x0e240559, 0x071a1413, 0x0a2c2d83, 0x08090a09, + 0x03070608, 0x051b3804, 0x0d252b83, 0x11111010, 0x221b8610, 0x82080a09, 0x03042635, 0x27251112, 0x37008213, 0x100f1524, 0x04050909, 0x152b0f0e, + 0x31310b0b, 0x330c2362, 0x0404403e, 0x0c2f7784, 0x0f0c0d0d, 0x0c0b0d0d, 0x11350606, 0x82090405, 0x0b0a218b, 0x05235e83, 0x82123504, 0x09092123, + 0x07240e82, 0x04050607, 0x01210085, 0x2f8e8202, 0x06050504, 0x0b0b0808, 0x0c120d0e, 0x07070909, 0x03251c83, 0x02010202, 0x82aa8201, 0x0707381c, + 0x0d0c090a, 0x17162210, 0x0c03060b, 0x1e201617, 0x060e1516, 0x820d0e03, 0x10103200, 0x1d1d2614, 0x00010000, 0x0239ff45, 0x00db0224, 0x16eb52d7, + 0x17623620, 0x834e1809, 0x14152209, 0x52018307, 0x29490ad1, 0xc3661809, 0x09b94b0f, 0x9507de41, 0x19514911, 0x4115ee41, 0x8b830ee6, 0x580af75d, + 0x022b0b93, 0x6d363724, 0x1d333248, 0x740f0f1d, 0x0322066d, 0x01830201, 0x0704052a, 0x1f3d0806, 0x0108070e, 0x02260082, 0x02040404, 0x1b840202, + 0x03032208, 0x0a080506, 0x11120d0d, 0x1f1d1717, 0x0f0f1717, 0x04050707, 0x0c0d0809, 0x2d103311, 0x11112216, 0x270d8304, 0x1133100d, 0x1121172d, + 0x22200082, 0x2a081783, 0x080d0d10, 0x06050409, 0x110b0b06, 0x12251812, 0x071c3712, 0x110e0d07, 0x08051311, 0x08090a07, 0x04080709, 0x2c171704, + 0x8217172c, 0x110a2823, 0x11161711, 0x820c0b11, 0x0b052230, 0x826b820a, 0x47393317, 0x0f102423, 0x2f2e1e1e, 0x1c1c163f, 0x21202121, 0x00820921, + 0x0a085e08, 0x16150c0a, 0x18161715, 0x2c2a1917, 0x090a2f2c, 0x0b0a0a0a, 0x15130a0a, 0x17181814, 0x12171616, 0x11120e12, 0x0d101110, 0x0a0c0c0e, + 0x0307070a, 0x0a040503, 0x1611100a, 0x0c0f0f12, 0x3206060d, 0x21111110, 0x0a0d0d12, 0x3105050a, 0x23121210, 0x340f1020, 0x07040311, 0x0a080908, + 0x2649820b, 0x0507080a, 0x42191a07, 0x062305ee, 0x83020606, 0x07220841, 0x0d0a0a07, 0x1727100e, 0x03060818, 0x2618180a, 0x0e101113, 0x0308090d, + 0x08040407, 0x110d0e09, 0x5f821310, 0x090c0b3c, 0x03060608, 0x001f1f0e, 0x00020000, 0x0282ff50, 0x00ec011a, 0x00550035, 0x1d591700, 0x0a276405, + 0x200c394e, 0x06016316, 0x33240782, 0x15143332, 0x27242782, 0x37060706, 0x17200f82, 0x470e8f6b, 0x38080b55, 0x1c1d2664, 0x22214414, 0x11110908, + 0x1a1a1615, 0x1d1c1c1c, 0x1a1a1b1b, 0x11101616, 0x23240808, 0x1a1d1846, 0x42040221, 0x30263334, 0x10303434, 0x24241a1a, 0x10101a1a, 0x2a008208, + 0x1a1a1111, 0x19192223, 0x82091111, 0x417e330d, 0x140b0b20, 0x4c3a3a28, 0x1c222228, 0x0e15141c, 0x0082070e, 0x0e0e3508, 0x1b1b1415, 0x4c282222, + 0x17283b3b, 0x2041090a, 0x2d1f1f10, 0xeb1f1f2d, 0x0c111118, 0x1712110b, 0x27201f17, 0x1621212a, 0x0b0b0c16, 0x2116160c, 0x20272920, 0x0120ff83, + 0x20088766, 0x84fd8265, 0x0b1154d7, 0x220de444, 0x43353435, 0x54190745, 0x37200c03, 0x5406b54d, 0x46181a9f, 0xae300ad7, 0x43212201, 0x28212243, + 0x02024d26, 0x13261d1c, 0x0805d467, 0x1410083c, 0x2c2b1715, 0x16401e2c, 0x2a25261d, 0x3650514d, 0x46462222, 0x08092222, 0x15151111, 0x1b1c1a1b, + 0x1b1c1c1d, 0x15161a1a, 0x08091011, 0x03040404, 0x111c1c11, 0x09040302, 0x00821f3e, 0x050a3e3e, 0x39222445, 0x170a0b13, 0x231c2114, 0x1a090404, + 0x02010101, 0x01030302, 0x366e1849, 0x022b0b86, 0x2b4d4c6e, 0x402d2d1a, 0x8320050a, 0x0f102b4a, 0x06050b0b, 0x0b0b0506, 0x6483100f, 0x0e0d2024, + 0x33830a0f, 0x0e0e0823, 0x2a008200, 0xff4c0001, 0x02160238, 0x515d00dc, 0x3421164b, 0x8b2a1927, 0x41e38207, 0xcf7f061f, 0x18332010, 0x20080f6d, + 0x062d4815, 0x2d823720, 0x44143721, 0x3d080b17, 0x393a1602, 0x39397273, 0x2121203f, 0x21214443, 0x3a452222, 0x451a3414, 0x11102223, 0x12111110, + 0x2b3a1212, 0x0d1c1c2a, 0x1c0e0e0e, 0x3a2b2b1d, 0x141d1d27, 0x25090a13, 0x1f214b25, 0x00831c1f, 0x4d262728, 0x0927264d, 0x0082305f, 0x14415f20, + 0x112a0805, 0x1c1b3808, 0x32021337, 0x04046133, 0x01020204, 0x15150a0a, 0x2b2a2020, 0x17172221, 0x162d0c0c, 0x0f0e0807, 0x331b1414, 0xa64a1a1a, + 0x52143505, 0x3b3a5d29, 0x0f030719, 0x133b2324, 0x39000300, 0x31020000, 0x3b24ff82, 0x5b004b00, 0x180d094d, 0x8c08a14b, 0x097356ef, 0x08e34f18, + 0x2006934a, 0x0c795103, 0x6a161721, 0x35220701, 0x41823534, 0x06072608, 0x3738f901, 0x3938716f, 0x1c1d0e0e, 0x67392a2a, 0x392d5c22, 0x1d1c2a2a, + 0x39390e0e, 0x2a293871, 0x0e0f1a1b, 0x2201862a, 0x422267de, 0x20270546, 0x22214121, 0x82214343, 0x4242082c, 0x4f9e2021, 0x29282728, 0x1e1f2850, + 0x0b0b1516, 0x0b0b1338, 0x201f1615, 0x28295128, 0x13130a0a, 0x4c291e1e, 0x38123419, 0x40153f13, 0x21442501, 0x1817162f, 0x18313017, 0x30c9fe19, + 0x19181718, 0x04824532, 0x2508136b, 0x004f00ec, 0x1344006d, 0x52a38206, 0xab840735, 0x44054346, 0x8d4d0503, 0x54f78405, 0x0b4308b5, 0x08a75709, + 0x14232223, 0x3b981815, 0x0fdd570e, 0x16173a08, 0x13152fb4, 0x0c14090a, 0x1c190506, 0x100f0e0f, 0x27275020, 0x2e4c2626, 0x06111f1f, 0x1f1e1002, + 0x26264d2e, 0x1313090a, 0x11241c1c, 0x0a0a0d0e, 0x05040706, 0x2b2b0202, 0x05df4e6d, 0x070c2f08, 0x11040408, 0x0d1a2211, 0x05090912, 0x172dc805, + 0x062c181b, 0x29f77607, 0x16011516, 0x32642c16, 0x2e1a1a32, 0x2c2d0118, 0x5d254b59, 0x2a822f2f, 0x1111222e, 0x4c5d2f2f, 0x24242f27, 0x0c0b1818, + 0x35057864, 0x5c17300e, 0x25012e2d, 0x0406060c, 0x0f090905, 0x4184140f, 0x0082142a, 0x3c772731, 0x00131219, 0xff350001, 0x01330239, 0x4a8d00ec, + 0x7d5c0d93, 0xc542180c, 0x1031570e, 0x14151628, 0x06070617, 0x35822607, 0x180fbf58, 0x5716fb59, 0x754e078d, 0x2157840b, 0x31863736, 0xf0013108, + 0x3b2e2e22, 0x1c26262f, 0x0c15141d, 0x0a06070c, 0x1f14140a, 0x0e0d2a1f, 0x0d0e0d0e, 0x0a0c0d0d, 0x0407080a, 0x0a050504, 0x15100f0a, 0x0b0f1013, + 0x2708e482, 0x1a0f0101, 0x01010f1a, 0x0b0b0102, 0x20201616, 0x19181f29, 0x0e0e1413, 0x0504090a, 0x15160a0b, 0x1b2a1f20, 0x11111615, 0x47053247, + 0x2d08054e, 0x18171212, 0x1c1d251c, 0x0a0b1516, 0x33100808, 0x0c0d191a, 0x18961111, 0x07070d0c, 0x13120f0f, 0x19191718, 0x2021231b, 0x17171d1d, + 0x70820611, 0x82060421, 0x08082700, 0x0c0d0909, 0x5b82100f, 0x05050b31, 0x0a090405, 0x07130e0e, 0x02040707, 0x82020304, 0x250533ab, 0x12131b1c, + 0x05050a09, 0x0b0c0909, 0x10100f0f, 0x00831b12, 0x0f151522, 0x27081d82, 0x100f0e0e, 0x11121111, 0x0f101111, 0x0c0c0f10, 0x0405090a, 0x11120908, + 0x1d231a1a, 0x1d0d1415, 0x22211a0e, 0x25253129, 0x2805bb44, 0x0239ff59, 0x00f40124, 0x0abb4461, 0x5805c54c, 0x272010d3, 0x5b05ae4a, 0xfd510ae3, + 0x07062608, 0x31222306, 0x21218222, 0x1d4c2322, 0x0c2e4b0c, 0x02323c08, 0x72393923, 0x413a3a72, 0x120a0916, 0x1e191912, 0x111b1b25, 0x09090911, + 0x19101008, 0x0b152119, 0x1a212b0b, 0x0a12121a, 0x0c060609, 0x1912130b, 0x2720201a, 0x21212f01, 0x4f030716, 0x102007d0, 0x2906417e, 0x0a0a0d0d, + 0x0b460605, 0x00822f5e, 0x015d2308, 0x58b17b71, 0x0c101116, 0x0805060b, 0x19111109, 0x1d22221a, 0x1718191c, 0x03081518, 0x1e190f04, 0x0082231f, + 0x171a2130, 0x11151617, 0x060d0d10, 0x140b0b07, 0x0b822447, 0x480e0e21, 0x0321055d, 0x05344e03, 0x1511102f, 0x00020000, 0x0238ff32, 0x00f3012d, + 0x18fd595d, 0x0fff4a18, 0x510a8b58, 0x29570f23, 0x15142518, 0x01060714, 0x081e1b48, 0x17bf0147, 0x2d2b2221, 0x15162122, 0x07080b0b, 0x16160f0f, + 0x2627351e, 0x0d0c191a, 0x12120a09, 0x1d1d1818, 0x201f1e1f, 0x1d1d1f1e, 0x13121818, 0x0a0b0909, 0x23231516, 0x1d1c2a2f, 0x08081010, 0x0b0b0505, + 0x14161010, 0x2ff68410, 0x0c0c1742, 0x1e14e3fe, 0x1e2a281e, 0x0a12121e, 0x142a0082, 0x281e1d14, 0x141e1e28, 0x0d820914, 0x0811a723, 0x05496808, + 0x181d2428, 0x0f121317, 0x64820a0e, 0x20181925, 0x8222261f, 0x11172560, 0x060c0b11, 0x0c3a0082, 0x1711110b, 0x221c1c17, 0x1a1e1e21, 0x1517181a, + 0x110f1010, 0x14131210, 0x31820e13, 0x04050535, 0x0c090804, 0x091b100c, 0x18210c18, 0x115b0119, 0x82040b0b, 0x11122a89, 0x211f1819, 0x12111919, + 0x82678209, 0x2119240d, 0x42181921, 0x502c058b, 0x1a02c1ff, 0x5d00ec01, 0x30050000, 0x5a0d284d, 0x6d700f13, 0x07db4311, 0x355a0720, 0x0fc77b06, + 0xcd631720, 0x175c0806, 0x01060706, 0x05030378, 0x04050406, 0x0a070807, 0x0d0b0b09, 0x0c0f0e11, 0x080b0a0c, 0x21080810, 0x1e161711, 0x0e16161e, + 0x0f07080f, 0x2e1e1e0f, 0x366b3d2d, 0x24121237, 0x24090913, 0x200d0e1b, 0x1b244220, 0x0811111b, 0x0d060609, 0x1c14140c, 0x1f25262c, 0x3f0f0f0e, + 0x05060303, 0x0621f682, 0x08fa8206, 0x0302014c, 0x0b070703, 0x04080d0a, 0x0f181105, 0x0509060f, 0x1e191815, 0x2522221d, 0x19272735, 0x010d0c1a, + 0x4b292a09, 0x4336372b, 0x0e040407, 0x212e2e38, 0x091b1b36, 0x1c121208, 0x1c20271c, 0x171a191c, 0x160a1518, 0x0d0b2216, 0x0082000c, 0x91000336, + 0xd7011800, 0x1700d401, 0x47002f00, 0x22130000, 0x26272223, 0x22089966, 0x46161732, 0x1720054d, 0x07201796, 0xe2241796, 0x0408162b, 0x08200082, + 0xde220786, 0x9082152a, 0x07040422, 0xee220786, 0x1f86152b, 0x0308152d, 0x01030404, 0x07030481, 0x83071225, 0x2007850b, 0x201082ab, 0x84108624, + 0x03be2807, 0x12230704, 0x87030407, 0x30bf8207, 0x01cb0002, 0x029e0163, 0x003300db, 0x0100004f, 0x29551806, 0x3435210b, 0x210e5d67, 0x37513736, + 0x0b474306, 0x9b522720, 0x0fdb410a, 0x6e012208, 0x13100f0d, 0x0d131318, 0x1706060d, 0x1e582e17, 0x09122b56, 0x11142908, 0x0b0c0e0f, 0x06050909, + 0x2c008203, 0x090a0506, 0x0b0c0773, 0x0b0a0f10, 0x26cd8207, 0x111d0e0e, 0x84070c0b, 0x012d08cb, 0x05050a77, 0x11110809, 0x68211a19, 0x15162a34, + 0x09090a1c, 0x18123714, 0x0905040c, 0x0f0d0c09, 0x1110100f, 0x0f101010, 0x240c0c0f, 0x2cbe820f, 0x110c0c07, 0x162d1512, 0x0e070615, 0x821b820e, + 0x83e7841c, 0x03682604, 0x000b0066, 0x62e78255, 0xb982057f, 0x03221722, 0x1bbd9818, 0x47079b42, 0xb362070d, 0x5d668305, 0x77180815, 0x22240811, + 0x24152e01, 0x08191f19, 0x180ed121, 0x1847968a, 0x2409f795, 0x815516fd, 0xa28a1881, 0x0200223f, 0x050b4100, 0x13000624, 0x0b415d00, 0x090f4106, + 0x084f1341, 0x1d140e2e, 0x0e101d1e, 0x21420a0e, 0x0e0c0c09, 0x111a1a18, 0x18109f39, 0x0b0d1718, 0x1e3d090b, 0x0a080807, 0x0c111211, 0x0f0e0f0a, + 0x05070707, 0x302c7e19, 0x79191520, 0x7e190fc9, 0x2f42412c, 0x4268200a, 0x1320052f, 0x42095560, 0xee2c4a2f, 0x131e1f12, 0x24151f3e, 0x91391624, + 0x2a492e42, 0x272617ed, 0x26271717, 0x4213fd17, 0x2b42402e, 0x1207430f, 0x244a3f43, 0x1a1a110d, 0x0de71919, 0x9e39210d, 0x20a02b42, 0x064f4303, + 0x17006626, 0x79002f00, 0x20190346, 0x16eb4533, 0x81440120, 0x2ff62748, 0x04030818, 0x97180304, 0xfe2117f5, 0x486642af, 0x04070326, 0x162b0705, + 0x24054e46, 0x0507152c, 0x210f8f04, 0x7e42f9fc, 0x41002040, 0x0221065b, 0x825b41cc, 0x08183023, 0x24008203, 0x07183008, 0x20008204, 0x259818bc, + 0xc2fe210e, 0x1849a942, 0x21223bb3, 0x83196140, 0x00313e12, 0x00620002, 0x03270200, 0x004b0066, 0x13000063, 0x07536106, 0x180e8d66, 0x240e99f0, + 0x32313435, 0x065d5e33, 0x42081f4f, 0x262007c1, 0x2405996e, 0x20151401, 0x7fbc1823, 0xe7320812, 0x29030205, 0x0d060615, 0x1611110d, 0x0a090806, + 0x0d0a0a07, 0x0e040307, 0x0809090a, 0x06060608, 0x2a020305, 0x0d070614, 0x1511120d, 0x0a070806, 0x1f850b07, 0x05050422, 0x04292682, 0x06070804, + 0xacfe3b01, 0xadbc1871, 0x2303390b, 0x0a080906, 0x12180101, 0x060e0e13, 0x02010107, 0x06040501, 0x07010104, 0x2205725a, 0x1a080706, 0x210b8436, + 0x1c820402, 0x08020226, 0x02030302, 0xfd230382, 0x18143c27, 0x370adcbc, 0x03000000, 0xf3ff3e00, 0xd4022c02, 0x73003b00, 0x00008f00, 0x06072213, + 0x15200183, 0x48115b62, 0x37200afb, 0x20141541, 0x2b691813, 0x05f34a14, 0x15141523, 0x09954d20, 0xeb183320, 0x6b8308ff, 0x33320325, 0x86323336, + 0x0ea57301, 0x09fd2408, 0x04050607, 0x142a0303, 0x0c0d0606, 0x12181213, 0x06111111, 0x0b0e0404, 0x09070809, 0x04050707, 0x83010202, 0x0d0c221c, + 0x201c8312, 0x381c8412, 0x4e08090a, 0x24333441, 0x12121225, 0x15122411, 0x1a191816, 0x2b361d1b, 0x28e1192a, 0x2c213a0b, 0x3631302c, 0x1819191b, + 0xca181816, 0x1e191828, 0x150f100e, 0x261d1d16, 0x057b4c02, 0x1c212136, 0x0c16151c, 0x0599020d, 0x0e090904, 0x181f120e, 0x08121218, 0x0f277582, + 0x0d030306, 0x8205040a, 0x0e082317, 0xca19130e, 0x2f0810b7, 0x12125afd, 0x33332524, 0x32333f40, 0x0e0f1226, 0x05050909, 0x22221111, 0x203c2e2e, + 0x2b01020a, 0x17182122, 0x0d0e0c0c, 0x0a1c3a1b, 0x05050808, 0x4232c382, 0x1d1d2701, 0x0a0a1413, 0x15150a0b, 0x00001d1d, 0xc4180200, 0x0b220893, + 0xc7493500, 0x08e77c0e, 0x1cc7fa18, 0x49151421, 0x40320da7, 0x2a2c2c1d, 0x10151417, 0x22162448, 0x10112121, 0x07820c0f, 0x0f122026, 0x24490b10, + 0x2b201b82, 0x4c201b83, 0x210b8349, 0xd31869d2, 0xec211f65, 0x82aa824f, 0xff342aab, 0x03410237, 0x00130006, 0x16674975, 0x12697f18, 0x081d7d18, + 0x1b079518, 0x750ee36b, 0x0d890d95, 0x01222325, 0x491e1314, 0x19250b7f, 0x39111a19, 0x599f18cc, 0x06082d35, 0x04040306, 0x02010203, 0x02010101, + 0x03390682, 0x090b0402, 0x05060609, 0x03030405, 0x0e0b0204, 0x1412110e, 0x02371814, 0x0f954955, 0x32bc8519, 0x0e0f1226, 0x07070a0a, 0x03305b84, + 0x04050404, 0x1b0a0607, 0x0f0e1516, 0x07060c0b, 0x12227382, 0x7b820e0d, 0x13420520, 0x004b220b, 0x4dc74475, 0x2b571320, 0x1b9f4705, 0x26068941, + 0x020305dd, 0x4407152a, 0x092a06d9, 0x0a080a08, 0x04070c09, 0xd9440f03, 0x03022208, 0x241f8629, 0x09080615, 0x0bd94409, 0x03030429, 0x07060904, + 0x42194c84, 0xee44228c, 0x12fe233d, 0xc0424fec, 0x42002020, 0x022807bb, 0x004b00e1, 0x010000a9, 0x441c0145, 0x172105cd, 0x08535232, 0x50140945, + 0x03230737, 0x5b060706, 0x6f460d83, 0x41058205, 0xe9422267, 0x08337017, 0x0709023f, 0x03040507, 0x07142903, 0x120d0c06, 0x090a1612, 0x0a070808, + 0x03070a09, 0x04060e04, 0x211b8204, 0x23850404, 0x2a010228, 0x0c070714, 0x2482130c, 0x08090826, 0x090a0907, 0x05202483, 0x03350082, 0x130f0404, + 0x37161414, 0x14122413, 0x050c1010, 0x04070606, 0x283c8203, 0x23050405, 0x13242627, 0x4bff1911, 0x0605221d, 0x20028305, 0x27708205, 0x0b0a0c02, + 0x04040508, 0x03219382, 0x05347101, 0x02082c08, 0x090405a5, 0x130d0e09, 0x10191920, 0x02090911, 0x05030302, 0x03070706, 0x03050d04, 0x01030203, + 0x08080504, 0x1f130e0e, 0x83111919, 0x03012b1e, 0x08060603, 0x0d030306, 0x1f820405, 0xfc01012c, 0x050509a5, 0x06061237, 0x4782040b, 0x0807072f, + 0x0b0b0a0a, 0x5e5d550d, 0x29292e54, 0x9cd81822, 0x422b2b0f, 0x1f223f42, 0x0d0d171f, 0x03820d0c, 0x0b100c24, 0x7982060a, 0x080a1229, 0x05060708, + 0x430c0205, 0x002c05c4, 0x00010000, 0x01e100b2, 0x002e01b6, 0x15af5e1a, 0x47261fa1, 0x2202e700, 0x3f862a01, 0x1433202f, 0x01472015, 0x9bfe7764, + 0x321132e7, 0x82628211, 0x009b2463, 0x88ce01e7, 0x82322023, 0x9b222423, 0x86e74de6, 0x82012021, 0x02e72224, 0x221f8568, 0x84353435, 0xce012443, + 0x8532fe9a, 0x371f9f20, 0xff8e0002, 0x02d9011d, 0x000700df, 0x1700000f, 0x33323510, 0x33221510, 0x8e240786, 0xdf401541, 0xe3260382, 0xfdf0d202, + 0x0585f02e, 0x00297282, 0xff000002, 0xff68021d, 0x203785b3, 0x20798615, 0x20818b07, 0x2987849a, 0x1c091d73, 0x0a1c700a, 0xcf85091d, 0xc701e726, + 0xdb029701, 0x13226d83, 0x2b4e3534, 0x15143f09, 0x1f13e722, 0x1a33131e, 0x0a0f0f0a, 0x41c7015e, 0x37382220, 0x38372222, 0x00184922, 0x37870001, + 0x00000b26, 0x34373613, 0x1436a782, 0x22070615, 0x5e0d25e7, 0x39194a20, 0x2d87c701, 0x18481848, 0x2b822d87, 0x79ffca27, 0x8e007901, 0x202b8200, + 0x222b8a17, 0x820c25ca, 0x3a18272b, 0x492d8787, 0x2a834918, 0x0122578d, 0x57852726, 0x2217162b, 0x194a4a01, 0x0d251f5f, 0x82588a3a, 0x000222c0, + 0x20bf8269, 0x20bf84ff, 0x8e89821f, 0x8e3320c1, 0x1369230f, 0xd1861f1f, 0x12c75f2c, 0x33121f1f, 0x0f10091a, 0xdd8d5f09, 0x0021e98c, 0x20638500, + 0x226382fe, 0x8d17000b, 0x8a3320ed, 0x866920cd, 0x86d220f9, 0x41a889d5, 0x4b840809, 0x0179ff26, 0x008e00fe, 0x0d414b84, 0x414b9b0b, 0x29410821, + 0x41979109, 0x33200a2d, 0xcc200b8a, 0x26063841, 0x5e184ad2, 0x410c2520, 0x978a0a40, 0x51000128, 0x1802a4ff, 0xe183bd02, 0x5c180520, 0x7d41079b, + 0x32270805, 0x22151433, 0x22151023, 0x2e890801, 0x16422e89, 0x2e8a2e8a, 0x89015c42, 0x94123683, 0x36319431, 0x8377fe12, 0x89000000, 0x00272343, + 0x4e180500, 0x078907a9, 0x8305c564, 0x1514214b, 0x0b825385, 0x57895385, 0x93255b85, 0xbf123731, 0x825e8740, 0x93132209, 0x275f8231, 0x01da00a0, + 0x00f101c9, 0xed535f82, 0x0885450d, 0x396d3620, 0x07955908, 0x1a179d2a, 0x1a1f1f1a, 0x0a16151b, 0x16240082, 0x0e0c0b0a, 0x10360082, 0x161b1a20, + 0x06070809, 0x0c030307, 0x1403010b, 0x0a0b0b0a, 0x40671514, 0x09142b05, 0x06050807, 0x0a0a0302, 0x2f820a14, 0x0e0e0d26, 0x18181d10, 0xb5297f84, + 0x1702f101, 0x00001100, 0x05c56437, 0x17206582, 0x28064547, 0x3e3e29a0, 0x1d1d203c, 0x2e078616, 0x1676ecb5, 0x11202021, 0x150c0f0f, 0x821f2120, + 0x00002507, 0xf5000100, 0x73270482, 0x17008f00, 0x4f210000, 0x63221753, 0xae4d2040, 0x20078205, 0x23008304, 0x264d0703, 0x2d05ad4e, 0x0307274c, + 0x02000004, 0x00008000, 0x4784e801, 0x00002f22, 0x97179d4f, 0x40ef2317, 0x57830720, 0x07860720, 0x203fe323, 0x200f8308, 0x23078308, 0x04040303, + 0x0f8f708e, 0x00030023, 0x20848228, 0x207f863f, 0x9781b147, 0x8e972099, 0x41c52099, 0xc5200e0a, 0xa9a7a186, 0x002cb990, 0xe3000100, 0x85010e01, + 0x1f00ae01, 0x4e0f3556, 0x152c0d3d, 0x01060714, 0x0f0e0c6e, 0x0f0e1111, 0x2807a058, 0x11110e0f, 0x0b0c0e0f, 0x21008206, 0x06842501, 0x820b0b21, + 0x82122022, 0x820a2022, 0x0a062513, 0x120e0f0b, 0x00222282, 0x00820007, 0x02680230, 0x002f00a1, 0x0067004f, 0x00c30093, 0x738201eb, 0xa9561320, + 0x0fb75c0a, 0x200fbf42, 0x562b8207, 0x3f770fa5, 0x1714220c, 0xf9401816, 0x42bf8209, 0x67970a91, 0x05206393, 0x3520938a, 0x6206135d, 0x39570f83, + 0x8745180b, 0x13bd7f13, 0xfd690520, 0x0f13680e, 0x82088359, 0x07635d7f, 0x10d83b08, 0x10141312, 0x0d0d0e0e, 0x15090c0b, 0x0a0b0a0a, 0x0b0c0915, + 0x0e0e0d0d, 0x19191f0f, 0x07070915, 0x03030706, 0x09090605, 0x0c930d0d, 0x11110f0e, 0x0c0d0f0f, 0x06060506, 0xac410d0c, 0x0c0c2205, 0x38248206, + 0x06050425, 0x2d2d2204, 0x60605d32, 0x06060340, 0x60604004, 0x2d2d325d, 0x25258298, 0x0e0f0f0f, 0x5a820e0d, 0x820b1321, 0x14152460, 0x851e1919, + 0x090b2271, 0x82118215, 0x0c0b2371, 0x28822701, 0x72821020, 0x84821420, 0x05277082, 0x140a0708, 0x821e191a, 0x0d0d2c3b, 0x0a090b0c, 0x06050808, + 0x840a0202, 0x4bfe212c, 0x11252c82, 0x0c0f0e12, 0x2088820d, 0x24048306, 0x09080807, 0x3c9b8209, 0x0403050c, 0x02010404, 0x3f010606, 0x110f0f0c, + 0x08080909, 0x05060608, 0x03040407, 0x83168303, 0x8212822c, 0x8219822d, 0x820520b8, 0x01012c10, 0x05050303, 0x0409a401, 0x82020305, 0x09072b2b, + 0x1d181814, 0x1319181d, 0x3b820709, 0x03022308, 0x0913090a, 0x0c0c0b0a, 0x130f0e0e, 0x0f0f1211, 0x0b350c0d, 0x06060506, 0x0d0e0c0b, 0x0d0d1011, + 0x26820b0c, 0x2b080d82, 0x11100e0d, 0x09e40e0e, 0x0d080f0e, 0x23121111, 0x09182423, 0x18080e0e, 0x12232424, 0xf4fe1111, 0x02030305, 0x07060503, + 0x19130907, 0x18246083, 0x09091413, 0xed821182, 0x18130929, 0x181c1d17, 0x83091418, 0x03033394, 0x13140a0a, 0x0f1c1818, 0x0d0c0e0d, 0x14090a0a, + 0x27830a09, 0x0a07072a, 0x0d0b0a0a, 0x0d0d0d0c, 0x3f212b86, 0x2a87820c, 0x0e0b0c05, 0x0f10100e, 0x83050b0e, 0x020221e7, 0x04219a82, 0x82678206, + 0x0e1023e6, 0x23820b0e, 0x03010222, 0x13831a82, 0x08070624, 0x2b8a0707, 0x03231982, 0x82050405, 0x07112141, 0x35821a82, 0x4f430020, 0x01ff2810, + 0x013f011f, 0x4200005f, 0xbf4217e7, 0x07595e0f, 0x20374f43, 0x1f234317, 0x14173223, 0x0a7b6017, 0x220c6743, 0x8b161732, 0x4637201b, 0x054c10a9, + 0x0b975207, 0x27263524, 0xaf522726, 0x0d397506, 0x34201782, 0x9f07bd59, 0x10b360cf, 0x750ca372, 0x45180f6b, 0x15320d55, 0xd7161714, 0x14121210, + 0x10121214, 0x0a0d0d10, 0x00820509, 0x0d0a0924, 0x1584100d, 0x15841320, 0x0609092d, 0x09060505, 0x920e0d09, 0x430e0f0c, 0x12230d8f, 0x430e0e11, + 0x863c1d8f, 0x18151512, 0x1116151a, 0x04080911, 0x0b080704, 0x100e0d0b, 0x1618110f, 0x01021115, 0x02200083, 0x012d0685, 0x15161201, 0x0c0c101a, + 0x09080a09, 0x20138307, 0x05ce4f02, 0x08020331, 0x0a0b0a09, 0x110d0c0b, 0x0e0e0f0f, 0x46080a0b, 0x082f05cd, 0x0e0e0b0a, 0x0d110f0f, 0x0a090d0c, + 0x8608090a, 0x0101232e, 0x31830402, 0x0b0a0a28, 0x16190e0b, 0x658d1216, 0x48828620, 0x0d0e0f25, 0x820a0a0c, 0x0a052ae9, 0x0e0d0c0a, 0x0a0b0c0f, + 0x20e2830a, 0x850d85c6, 0x8206201b, 0x20ee821b, 0x230d850c, 0x0d0ac605, 0x378e0d82, 0x090a0d22, 0x01233783, 0x820409a4, 0x09092e4d, 0x0f0f0c0c, + 0x12131112, 0x100f1211, 0x24c8820b, 0x04040504, 0x8215820a, 0x121122ef, 0x05c74314, 0x060b3622, 0xcd820082, 0x10110d22, 0xc7438782, 0x0e0d220a, + 0x16c743e5, 0x0a14ef22, 0x132e0082, 0x1c191813, 0x10111113, 0x090c0c0f, 0x59820509, 0xf3831420, 0x00820220, 0x2505cc69, 0x0a091401, 0x5d820303, + 0x82080721, 0x03012110, 0x022d1882, 0x01040102, 0x0507070a, 0x04020305, 0x23a18405, 0x13111010, 0x0f21a282, 0x2ada8210, 0x02040409, 0x07060503, + 0x86010908, 0x82012042, 0x02042508, 0x06070809, 0x0a223182, 0x9d41140a, 0x068f4106, 0x43270221, 0x0e2c0afc, 0x060c0b0e, 0x0c060506, 0x100f0e0b, + 0x2006f443, 0x06184406, 0x00271bab, 0x02d60001, 0x1892010e, 0x5c0aa37b, 0x21080acd, 0x1b1c10d6, 0x09214410, 0x190e0d0c, 0x21121a1b, 0x37210e02, + 0x0f0b2136, 0x201f110f, 0x02001620, 0x3b828b00, 0x3b84dd20, 0x00001f22, 0x250a0f5b, 0x07060706, 0x757b3322, 0x2207220c, 0x244d838b, 0x0c0a2243, + 0x284d850c, 0x1c1b108b, 0x09224310, 0x210f830d, 0x5d8e111b, 0x0028698c, 0x3f000300, 0x28020e02, 0x2f206b86, 0x7d8f6da1, 0x1b113f24, 0x6d85111b, + 0x1b1a1a25, 0x8e8c2211, 0x8b8d82db, 0x8c8d9a1f, 0x0c3f4199, 0x220eb359, 0x82670122, 0x0e1a3874, 0x44090d0c, 0x1b1a1122, 0x0e022010, 0x1f202016, + 0x0b0f0f11, 0x74373621, 0x43410613, 0x20418f0c, 0x0dfd5033, 0x1c012225, 0x821a1b12, 0x0a0c2951, 0x1b102244, 0x8c21101b, 0x0f836189, 0x6d8d618e, + 0x8e114341, 0x8f6d8f5d, 0x12d1290f, 0x0e1a1b1a, 0x450a0c0d, 0x20217c84, 0x20de8e8b, 0x821f868b, 0x8c8c9eee, 0x00012d98, 0x01430080, 0x00f2016a, + 0x2500001d, 0x1dd76f1a, 0x2b1c6a2c, 0x14172a2b, 0x2c1c0f14, 0x0784292b, 0x1c2f2f23, 0x2a03821c, 0x24241843, 0x11101323, 0x840d190d, 0x11112809, + 0x181e3c0d, 0x83172827, 0x00432403, 0x82ff0001, 0x86e92063, 0x05bd4e63, 0x6d4c6983, 0x15142109, 0x21066f4c, 0x4f82ff00, 0x821d1d21, 0x140f2a53, + 0x2c291714, 0x2b1c1c2b, 0x266b832c, 0x171e3b43, 0x83182728, 0x1e3c2903, 0x1311110d, 0x18242423, 0x00346e88, 0x7a000400, 0x1102e3ff, 0x1700c102, + 0x4f002f00, 0x00006f00, 0x4d08b755, 0x618605f1, 0x41220721, 0x178e0859, 0x09470720, 0x097f6912, 0x47060721, 0x1f8b1329, 0x0402ae36, 0x07070403, + 0x21640507, 0x06060604, 0x03030204, 0x0303e62d, 0x04211384, 0x21138263, 0x0d820607, 0xad2d0228, 0x110f0f0b, 0x6e4b0e12, 0x490b2006, 0x0b2606eb, + 0x0606050c, 0x0d82e905, 0x8b111221, 0x1110231b, 0x984b0f0f, 0x12e43405, 0x2f191717, 0x9d213131, 0x21468c35, 0x192f3131, 0x93121717, 0x84ea2013, + 0x820c204a, 0x13122d66, 0x0a0b0f0e, 0x06050506, 0x0e0f0b0a, 0x4805b06d, 0x0f2105c5, 0x201b910f, 0x32008200, 0xff7a0003, 0x020802ee, 0x003f00cb, + 0x007d0059, 0x6b103700, 0x23200587, 0x21073f41, 0xc1410706, 0x0c517e05, 0x23150554, 0x22151415, 0x1809c54e, 0x210d874e, 0xe1481427, 0x139d4b0b, + 0x07141530, 0x0405f706, 0x04030405, 0x0b0b0304, 0x00830c0b, 0x18171822, 0x192f0082, 0x25263018, 0x0e0d1c1c, 0x09080404, 0x82181010, 0x0b173fe2, + 0x05060909, 0x01020404, 0x47470101, 0x04080704, 0x070a0a0e, 0x03040306, 0x07070603, 0x00820907, 0x0b060833, 0x0f0f0d0c, 0x0b0a0e0d, 0x05050605, + 0x0506040b, 0x26008207, 0x0d0d0f09, 0x82050b0b, 0x01bc2300, 0xf1459427, 0x82012005, 0x8206201b, 0x08210837, 0x0a0d1e3b, 0x0307060a, 0x160b0c04, + 0x251f1e17, 0x10111011, 0x15131310, 0x1405050a, 0x070a090b, 0x2f408208, 0x0a090807, 0x04f2143c, 0x0d040707, 0x0a0a0c0b, 0x0e246582, 0x09090c0b, + 0x90838382, 0x20fe9823, 0x2a07820a, 0x0d0a0a05, 0x0d10100d, 0x83040a0c, 0x02012294, 0x20118205, 0x3111830c, 0x0000000d, 0x02000001, 0x026802b1, + 0x000700d7, 0xe1521100, 0xb102250b, 0x0a1c091d, 0x002d2282, 0xffdeff01, 0xff8a021c, 0x002300c7, 0x08db4c00, 0x4c094543, 0x142e0b95, 0x06070615, + 0x2b2add01, 0x55532a2b, 0x06825855, 0x15162a29, 0x15151514, 0x832d1616, 0x2b2b330c, 0x2c2b2c2b, 0x07060ec9, 0x28371c1c, 0x13131914, 0xa482060b, + 0x0201032f, 0x0c0c0706, 0x28191213, 0x15161b14, 0x2a978200, 0x0256003f, 0x006d0329, 0x41000011, 0x372e0bcb, 0x07003332, 0x221a3f22, 0x302d2622, + 0x5c822b2f, 0x18471136, 0x4862d9fe, 0x44443456, 0x5f5f5c4b, 0x29292d55, 0xc6affd22, 0xe7284383, 0xbb0181ff, 0x1700db02, 0x5106fd53, 0x32210d2f, + 0x240f8233, 0x59359fe7, 0x2b01851e, 0x84027f9f, 0xf71032d6, 0xf5113352, 0x83820382, 0x3f82ad20, 0x3f868120, 0x32353423, 0x0f875133, 0x22151025, + 0x851e5aad, 0x359f2301, 0x38857f9f, 0x3153f638, 0xd77dfd11, 0x11000400, 0x5802eeff, 0x5300cb02, 0xcb00a700, 0xc982ef00, 0x101b4f18, 0x4d0bc34d, + 0xe94208bf, 0x5933200a, 0x714b08fd, 0x0bf34207, 0xc1821520, 0x53d22120, 0x4c139344, 0x8b830b01, 0x71080942, 0x23831669, 0x03025430, 0x09080605, + 0x0403080e, 0x07060a0f, 0x0f820403, 0x0b052108, 0x100e0d0b, 0x0b0d0d0d, 0x100d0d0c, 0x0f100f11, 0x1612130f, 0x03040103, 0x11181820, 0x03090911, + 0x0a383382, 0x04070f0a, 0x070b0f03, 0x01030308, 0x18014902, 0x06050203, 0x080e0809, 0x48821482, 0x82030421, 0x23488b0f, 0x10100f0e, 0x05214887, + 0x21488502, 0x488b0208, 0x04030722, 0xe2214882, 0x2373820a, 0x0b0c0d0f, 0x21058a43, 0xc5820505, 0x08080822, 0x0a218e82, 0x260c820b, 0x0b270105, + 0x43100c0d, 0x13830899, 0x07070722, 0x0c212082, 0x05d0440d, 0x31bc2808, 0x14131818, 0x11111010, 0x05060a14, 0x0c0d0d15, 0x0b0a0a0a, 0x0f0e130a, + 0x05050909, 0x07070403, 0x440f0b0b, 0x820a0e23, 0x03032ba5, 0x140c0c03, 0x261e1d15, 0x9d821112, 0x16131330, 0x1405050a, 0x0a0d0c11, 0x0f0c0c09, + 0x4aca143c, 0xea43bb20, 0x9e0a201e, 0x8200201f, 0x05af4200, 0xcb02122a, 0x6b005300, 0xb3008f00, 0x4755af42, 0x32220aed, 0x81471433, 0x22072107, + 0xa3234f42, 0x48734223, 0x58474120, 0x00ff2112, 0x301f4042, 0x0d0c0b36, 0x0d0d100f, 0x05060b0a, 0x040b0605, 0x0fec4505, 0x204af541, 0x13864728, + 0xea41e320, 0x200a421e, 0x53000422, 0x2708b744, 0x00870063, 0x250000ab, 0x20526344, 0x058b4925, 0x20070342, 0x13e74822, 0x21337344, 0x2b448401, + 0xd7fe3246, 0x03030203, 0x04021a4c, 0x493c0203, 0x0f0d0d0b, 0x06054410, 0x050a0528, 0x07070505, 0xc3470708, 0x05042505, 0x11010405, 0x2d6a3844, + 0x35342026, 0xcc4ce71f, 0x34351f67, 0xef41e120, 0x00012a3f, 0x02a4ff65, 0x00bd0233, 0x06274723, 0x2612dd6b, 0x22151007, 0x82351023, 0x15360803, + 0x4b966522, 0x1b1f1f24, 0x0f15151a, 0x0f07070f, 0x2a1e1e0e, 0x12353529, 0x5c351847, 0x06c65302, 0x120c0c06, 0x1a161711, 0x222b1e1b, 0x0e1b1a22, + 0xd6fe040f, 0xe9180263, 0x9f2f073f, 0xcb010e02, 0x0f00a603, 0x47002700, 0x18010000, 0x51086f5e, 0x072005c5, 0x550a897d, 0x1d420b03, 0x0b054b13, + 0xcb013c08, 0x4a4b2626, 0x26252526, 0x26264b4a, 0x2c1516ee, 0x0515162c, 0x100b0b05, 0x10161611, 0x050b0a11, 0x08067406, 0x08080907, 0x03060507, + 0x07020303, 0x08070706, 0x06080809, 0x82020306, 0x65da280e, 0x33343433, 0x82336665, 0x51662b00, 0x28292928, 0x1e1e2a51, 0x7f6f1414, 0x1e1e2305, + 0x25830542, 0x07040523, 0x28328306, 0x02030506, 0x06050302, 0x260d8306, 0x00000007, 0x82860002, 0x03c724d7, 0x821b0097, 0x010021d7, 0x69052948, + 0xa5590925, 0x3227220a, 0x08837733, 0x48014708, 0x21163191, 0x10112022, 0x143d0b10, 0x0f2c0f2c, 0x23679b33, 0x0d0c0c09, 0x02191a18, 0x2715420e, + 0x2d2e1e13, 0x1516172c, 0x283fbe11, 0x8c16410d, 0x110c4181, 0x24221311, 0x01000024, 0xfe01a000, 0x8d03be01, 0x7b573b00, 0xe764180a, 0x0cad730c, + 0x2305774c, 0x15142322, 0x080e434b, 0x1692016f, 0x25261e1e, 0x1b181e1f, 0x1b1e1d1d, 0x0e0d1414, 0x07080708, 0x13140e0f, 0x1818181b, 0x853bb017, + 0x0d0d0d2c, 0x1c1c240f, 0x0a0a1615, 0x21020b0a, 0x04090812, 0x12240804, 0x0606070d, 0x100b0c06, 0x10161511, 0x060b0c10, 0x0a040506, 0x0c213193, + 0x02042040, 0x12090902, 0x1f181911, 0x0019191f, 0x02a50002, 0x03d10106, 0x0031009e, 0x1a295849, 0x53151421, 0xa38f064f, 0x6e079753, 0x36081059, + 0x1a1b13ab, 0x1e1f2822, 0x09091312, 0x16160b0b, 0x172b2121, 0x14161716, 0x3d181516, 0x1a101e1e, 0x1a212319, 0x0a12121b, 0xbe0a0909, 0x1310100c, + 0x1414152a, 0x82132a15, 0x050c21ad, 0x0221ae82, 0x2dca8229, 0x19180d0c, 0x32352726, 0x1b1a2526, 0xd8820d0d, 0x0a112034, 0x26260505, 0x0d0e1c4b, + 0x11100909, 0x20211919, 0xbb6e1818, 0x172e2206, 0x27f28217, 0x1611110c, 0x00111115, 0x012a0082, 0x0e029f00, 0x9703c301, 0xa3501900, 0x37362506, + 0x23223736, 0x080ee74d, 0x1d14db3b, 0x0e101d1e, 0x37a70b0d, 0x0f0b49db, 0x1e1d100e, 0x0231141f, 0x40402b0e, 0x1e1e213e, 0x0f0b2216, 0x20201808, + 0x44454123, 0x0003002d, 0x0109029e, 0x00a003cb, 0x00470037, 0x12314163, 0x430edd72, 0x07210b0b, 0x5b018206, 0x9f7706b3, 0x26272509, 0x06072223, + 0x13d35d18, 0x3a081783, 0x16171415, 0x1c14a301, 0x1c23241b, 0x0a14141b, 0x3018180a, 0x0b111014, 0x0905060a, 0x1a121309, 0x1a20201a, 0x0a12131a, + 0x0b06060a, 0x1411100b, 0x0a191830, 0x1314d00a, 0x82132726, 0x26272700, 0x0b0d1413, 0x05421010, 0x82052006, 0x820c2024, 0x162c3f0d, 0x02060616, + 0x08070f27, 0x0f0f0708, 0x2b1a1514, 0x05091a1a, 0x0c0b0808, 0x17110e0e, 0xf97a1213, 0x13123507, 0x0e0e1117, 0x08080b0c, 0x191a0905, 0x14151b2b, + 0x1020ff00, 0x20270082, 0x10101121, 0x54f0fe11, 0x0e22063d, 0x3382120f, 0x0d820a20, 0x26131330, 0x000e0f12, 0x98000200, 0xc4010b02, 0x5742a303, + 0x0805430e, 0x5d4f3520, 0x7927201e, 0x2d430acb, 0x0132080b, 0x21211797, 0x1617162b, 0x16161517, 0x1e1e3d17, 0x2419190f, 0x121a1a23, 0x09090a11, + 0x1b13120a, 0x1d29231a, 0x0912131e, 0xd80b0c0a, 0x142a1615, 0x4a4f100f, 0x0b0c2a05, 0x2a140f10, 0x3f021516, 0x084a421a, 0x26260634, 0x0d0e1b4b, + 0x12110908, 0x20211819, 0x11111819, 0x74420909, 0x42c32009, 0x10370752, 0x11121517, 0x06050d0c, 0x00001717, 0x8e000100, 0xdb015801, 0x82006f02, + 0x0651440d, 0x85183220, 0x22280e4b, 0x23691a01, 0x0d282369, 0x01280584, 0x211d5858, 0x591e580b, 0x1d200583, 0x43844282, 0xdb01cd29, 0x0700f901, + 0x42130000, 0x222c0591, 0xf953fa8e, 0x0b21cd01, 0x02000b21, 0x97206382, 0x2f206382, 0x0f201f82, 0x07202189, 0x5420298a, 0x022b2d82, 0x220b2202, + 0x0c216b0b, 0x82000b22, 0x00ec2b53, 0x027d01f3, 0x001b00d3, 0x4f182500, 0x32201129, 0x07e15718, 0x227d0124, 0xd0821811, 0x82550b20, 0x12112605, + 0x2a112218, 0x25008215, 0x1e1f1ff3, 0x01821d1e, 0x1d250582, 0x201e1f1d, 0x8b00853c, 0x8413205b, 0x4f36205b, 0x322106bd, 0x06cf4233, 0x221f0124, + 0x42822911, 0x22291530, 0x18172f11, 0x3cf31718, 0x3b3b3c3d, 0x06823c3d, 0x3c210782, 0x2243833c, 0x821e008e, 0x003422f3, 0x5f438217, 0x37411533, + 0x571e2c0d, 0x580b221d, 0x211e571d, 0x821d570c, 0x008e26df, 0x00db0192, 0x0bfb62bf, 0x53fa8e2f, 0x0b2292f9, 0x00000c21, 0x008e0002, 0x201f825c, + 0x053341f5, 0x2006af61, 0x0f334122, 0x0b21c92a, 0x226d0b21, 0x000b220b, 0xff28d784, 0x017d01b9, 0x001b0099, 0x0aa16518, 0x41087f50, 0x47242133, + 0x1d1f1e20, 0x20053341, 0x4107821e, 0x3b200633, 0xec20ef84, 0x13205b86, 0x33415b84, 0x3d472f21, 0x3b3b3d3c, 0x3e3c3c3c, 0x3b3a3c3c, 0x9f833b3c, + 0xf5ff0528, 0xc6026602, 0x43824f00, 0x10af9d18, 0x0ce34b18, 0x2008a345, 0x0a675c07, 0x37323322, 0x2107bf61, 0xed462322, 0x33323409, 0x01221514, + 0x0f100f57, 0x12121110, 0x25252f13, 0x820e1b1c, 0x1b530800, 0x3025251c, 0x1d212126, 0x2620211c, 0x141b1b23, 0x09090a13, 0x1b14130a, 0x2026231b, + 0x42c81c21, 0x3296359c, 0x35a13296, 0x478d0bcb, 0x07090a0d, 0x14040307, 0x33262513, 0x33414133, 0x14252633, 0x1b0d0d13, 0x11211933, 0x1c0d0e11, + 0x3629291c, 0x83292936, 0x11220859, 0x3ebc2211, 0x28770f2e, 0x31930f2e, 0x03000f2f, 0xd6ff3d00, 0xed023102, 0x87006700, 0x00009f00, 0x5f663617, + 0x087d4109, 0x200dcd70, 0x065d5a16, 0x56183220, 0x40180897, 0xf1830825, 0x6b320721, 0x232109a1, 0x22018222, 0x82062326, 0x23222117, 0x0d845987, + 0x200cb350, 0x8d551826, 0x2061820e, 0x0adb5a27, 0x83183720, 0x4b080a97, 0x090a0581, 0x04040506, 0x15142804, 0x12110909, 0x1e1f1918, 0x02282424, + 0x2f010303, 0x04030218, 0x0f0f0e01, 0x0403040e, 0x04182f02, 0x0a040707, 0x0d080809, 0x180e0e0e, 0x0d171a1a, 0x050a0b0c, 0x30303603, 0x31312c2a, + 0x03050935, 0x02220082, 0x37830203, 0x02030422, 0x0d3c2482, 0x03050405, 0x0c149335, 0x08060f0c, 0x0e0b0a08, 0x0e0d120f, 0x0c13100f, 0x07070f0b, + 0x21080f82, 0x0b120e0d, 0x115c0e0e, 0x060c0a0a, 0x09080706, 0x210f0d0c, 0x1d141a1a, 0x0a090e0e, 0x2222142a, 0x40820414, 0x42312408, 0x30395442, + 0x1e272731, 0x0d15161f, 0x0a08030d, 0x0c07070a, 0x0302070b, 0x0e0d0503, 0x180f0a0d, 0x82060e19, 0x426c0800, 0x0c0b0e21, 0x5f60560a, 0x2a2a2f57, + 0x2d161623, 0x10222143, 0x08080111, 0x0c080509, 0x0505080d, 0x12110706, 0x48760c11, 0x18382c2c, 0x29251c1d, 0x04453534, 0x46020203, 0x18362a2b, + 0x27241b1c, 0x09433333, 0x3c580707, 0x152e2625, 0x221f1818, 0x073a2c2c, 0x251a1111, 0x37453635, 0x00002e2d, 0x2f000100, 0x2c02f3ff, 0x6900cb02, + 0x09074618, 0x18355018, 0x5b05c341, 0x172112ad, 0x18018216, 0x24082973, 0x32333233, 0x42018317, 0x15200ee5, 0x2d07af41, 0x2d2a0214, 0x2f383232, + 0x22232928, 0xa0791b1a, 0x12400805, 0x221a1b12, 0x2f292923, 0x2b323239, 0x18161715, 0x1e1a1b18, 0x1c292835, 0x060f0e1d, 0x100b0c05, 0x1613130f, + 0x12351815, 0x31232415, 0x05040405, 0x05050504, 0x100e0e0b, 0x1017171d, 0x16080711, 0x23088282, 0x16151616, 0x11102236, 0x16170a0b, 0x28291f1f, + 0x38383131, 0x28293131, 0x16162020, 0x11120b0b, 0x16214221, 0x3b081d82, 0x1205050c, 0x35252512, 0x262e4636, 0x161e1d25, 0x0a100f16, 0x3001040b, + 0x2b193165, 0x01011515, 0x071b3502, 0x0b0b0404, 0x1e1e1615, 0x013d7c29, 0x0a0a0606, 0x4b171011, 0x01000000, 0x00220382, 0xe74b2202, 0x08cb5205, + 0x43059d6f, 0x290810b3, 0x22151423, 0x581d5875, 0x6b42011d, 0x4ade52f7, 0x1f5d4ade, 0x6f4b1f5d, 0x01081824, 0x143b8288, 0x143c339c, 0x08182775, + 0x5782256e, 0x0000462b, 0xcb023602, 0x00004f00, 0x13275333, 0x5d083d4e, 0x8d4108c5, 0x69401812, 0x360f840f, 0x1d584620, 0x17481847, 0x184b194a, + 0x1a1a0e0e, 0x14372928, 0x82121314, 0x08058301, 0x12101045, 0x18241212, 0x070d0e19, 0x92319207, 0x95319631, 0xfe45d132, 0x72143c8c, 0x33113225, + 0x1e113211, 0x2d2d3c0e, 0x0f0e1e1d, 0x04030202, 0x39070506, 0x07070a1c, 0x02030405, 0x12130909, 0x19302322, 0x83103309, 0x26712427, 0x8200143c, + 0x00012f00, 0x02a7ff36, 0x00670237, 0x17000081, 0x5b183712, 0xa1530e93, 0x08b14308, 0x151b9118, 0x37361724, 0x3f443736, 0x0a6b4b05, 0x0b0bbb18, + 0xbf493520, 0x0d215e06, 0x82055145, 0x05814553, 0x42aa2225, 0x82010120, 0x03022cba, 0x05050503, 0x0b080806, 0x8209080b, 0x03042c09, 0x03020204, + 0x3f010102, 0x82193215, 0x1101331c, 0x12211919, 0x0b0b0e0e, 0x08060807, 0x2306090a, 0xe7820512, 0x0e0d0c39, 0x0e0d1110, 0x0a0a0c0d, 0x07070d07, + 0x0201153f, 0x04020301, 0x82040503, 0x0b07284b, 0x070d0e13, 0x82020305, 0x3f023d46, 0x0e0f0815, 0x01592709, 0x171f8306, 0x0b100f17, 0x0506070a, + 0x01040405, 0x04020202, 0x24082d82, 0x0a0b0706, 0x17170f10, 0x014be220, 0x0e08838b, 0x0f1d090e, 0x0704040e, 0x08080707, 0x1722221e, 0x111b1c10, + 0x29888207, 0x09060702, 0x2e180e08, 0xa21a452e, 0x0c21083d, 0x334a870c, 0x080f0707, 0x10100d0c, 0xe21c1616, 0x201c374b, 0x00203636, 0x05200082, + 0x002e0382, 0xbd026802, 0x4b004300, 0x5f005500, 0x9c186700, 0x494b0cd5, 0x35342105, 0x20080955, 0x0f054917, 0x20080167, 0x07554123, 0x14232227, + 0x32132215, 0x210f8333, 0x07851514, 0x39841382, 0x16232227, 0x34171617, 0x22078435, 0x85143d51, 0x2d5b2f01, 0x1214130d, 0x07090a0a, 0x194a1c56, + 0x0185143c, 0x0d2e5b27, 0x0a131313, 0x33158209, 0x1a4a4a1d, 0x0c0b080d, 0x051e3d08, 0x2f050909, 0x0f2fc410, 0x44200a84, 0x0c3f1682, 0x2c40c20c, + 0x2c11340e, 0x1f40c20e, 0x182e2f30, 0xc2111617, 0x2b41c140, 0x2b12330f, 0x8341c10f, 0x192c0813, 0xc1111616, 0x13bb0141, 0x49131d1e, 0x15160d97, + 0x3412330d, 0x16150d11, 0x121848a7, 0x02001e1e, 0xf3ff0500, 0xbd026602, 0xb700a100, 0x180ad144, 0x820a9943, 0x067942b3, 0xe1842320, 0x35102323, + 0x08534332, 0x1941d583, 0x2340180f, 0x57332008, 0x591808af, 0x7b420903, 0x26272105, 0x19083541, 0x4c12bdd8, 0x9d7d071b, 0x06057408, 0x07141524, + 0xe96d0106, 0x09394b08, 0x14234608, 0x15104802, 0x18171b14, 0x0f1e1b19, 0x0a12121a, 0x0d05060a, 0x08080106, 0x18180f0f, 0x25102f1f, 0x14264b0d, + 0x0d0d1111, 0x0707090a, 0x10030404, 0x470b2305, 0x03184617, 0x09050402, 0x0b220e0a, 0x0d0c0d0e, 0x2500820c, 0x090c0c10, 0x21820508, 0x0d080833, + 0x0304120d, 0x10150802, 0x0509090f, 0x0e070705, 0x3a61820e, 0x13161518, 0x16161513, 0x04111122, 0x0c060603, 0x0204130c, 0x12170702, 0x820b0b11, + 0xfd082723, 0x11152ae0, 0xed520d0e, 0x0e540808, 0x1d102f11, 0x080a0a16, 0x0a0a1008, 0x22221312, 0x2f47d632, 0x1a1a2424, 0x46d40d0d, 0x05af0e02, + 0x0e0b0b05, 0x1312110e, 0x25701514, 0x11322570, 0x15215fbe, 0x040a0815, 0x0e060b05, 0x06050a09, 0x06060403, 0x10100a0a, 0x0d0d1315, 0x09090708, + 0x04010208, 0x112a9983, 0x261e1818, 0x14141d1d, 0x99820a0a, 0x1b372208, 0x140a0a12, 0x0b0f2814, 0x0908080c, 0x02010808, 0x0e0a0301, 0x1911110d, + 0x1e281f18, 0x0936011e, 0x2a0b8308, 0x19181f21, 0x09081111, 0x410000c6, 0x642606f7, 0x9d00bd02, 0xf741ab00, 0x0bb96207, 0x27262726, 0x15163114, + 0x4108694b, 0x034208b7, 0x08235810, 0x0ae98018, 0x9f591720, 0x2b621806, 0x17ef4108, 0x17202782, 0x1808f546, 0x180ba343, 0x410b935f, 0x854f05f3, + 0x14232805, 0x1b143d02, 0x5a09221c, 0x0523068e, 0x82030403, 0x01042b00, 0x130b172f, 0x08080b13, 0xbf7f0708, 0x35400807, 0x61103111, 0x1e1f2931, + 0x0a0a1414, 0x0b0b0405, 0x0c14100f, 0x0a090a0b, 0x070a0909, 0x1f0f0404, 0x2b1f1f20, 0x05051615, 0x11100a0a, 0x03030518, 0x14141b0a, 0x06050d0c, + 0x11120809, 0x0f231a1b, 0x0e270082, 0x1a0c0d0d, 0x821d1b1b, 0x03043927, 0x10100708, 0x03020618, 0x16171e0a, 0x06060e0e, 0xf5fd0a09, 0x182f1b36, + 0x2f280082, 0x161d143d, 0x01020a0a, 0x2005a262, 0x26008601, 0x22383822, 0x61131217, 0x2f0805cc, 0x4adf0303, 0x0caf0e02, 0x25191a0c, 0x1d243124, + 0x1015161c, 0x0b06080f, 0x1811110b, 0x0a151d17, 0x0c192a0a, 0x2a15160d, 0x090d0d13, 0x07090808, 0x2611eb41, 0x03040202, 0x41070505, 0x0e2307ef, + 0x82090c0b, 0x05ef4129, 0x110e0d36, 0x1e191812, 0x011e1e28, 0x3e201f45, 0xbb1f1f3e, 0x06000000, 0xe7440382, 0x00672c05, 0x007d0073, 0x009b0089, + 0x5e0000ad, 0xe7440817, 0x27262305, 0x09892726, 0x2005f344, 0x06d96032, 0x4605e143, 0xf744095b, 0x07062305, 0x09890706, 0x180d937e, 0x2208255a, + 0x85032207, 0x23222145, 0x67834585, 0x17202b82, 0x0320158a, 0x8507e348, 0x20278223, 0x3b119005, 0x05060570, 0x0d0c0c07, 0x170b2108, 0x0303020b, + 0x0a061301, 0x04040304, 0x03204203, 0x65270082, 0x04050333, 0x82172e04, 0x61032605, 0x03040230, 0x82178202, 0x030b241d, 0x82020810, 0x08192d2d, + 0x0c080f1d, 0x06060c0d, 0x1f400406, 0x07f21219, 0x0c03043d, 0x0a121312, 0x48060908, 0x01264b0a, 0x56020303, 0x0202012b, 0x01050cb0, 0x82020203, + 0x4c4d250f, 0x01020126, 0x032d1583, 0x0b06ce03, 0x05050a0a, 0x1f3d0305, 0x24008203, 0x01060707, 0x29078219, 0x07070604, 0x071f3e04, 0x1c830b0a, + 0x24241c37, 0x4e4d4b28, 0x0a103333, 0x320a1212, 0x1d1d1110, 0x1d1d1010, 0x20078f11, 0x291f8532, 0x4d4e3311, 0x2424284b, 0x37821b1c, 0x4d4c4a27, + 0x4d4d3333, 0x220f8249, 0x83e8011b, 0x3103923f, 0x352492fe, 0x191b3335, 0x19131319, 0x35331b19, 0x07822535, 0x07821c20, 0x17832420, 0x19191c31, + 0x00020000, 0x02f3ff16, 0x00bd0254, 0x55470021, 0x37200559, 0x2008ad45, 0x35a81815, 0x2223270c, 0x22151023, 0xf5432221, 0x87811807, 0x4a33200f, + 0x2508059f, 0x15141506, 0x41271614, 0x27332741, 0x0e1b1b26, 0x0812380d, 0x1a101008, 0x22652419, 0x8b2b0237, 0x27273345, 0x16821a1b, 0x16821320, + 0x16820f20, 0x22672608, 0x0d011830, 0x01eddc01, 0x23221111, 0x81453534, 0x38366b2b, 0x19182929, 0x21fe0d0c, 0x2311119f, 0x44343324, 0x3a148982, + 0x579fdf01, 0x457e8483, 0x00003d3d, 0xff7b0003, 0x02a60258, 0x003300db, 0x4b4b0043, 0x114e0d63, 0x13634f0c, 0x2323cf82, 0x18262726, 0x200f7369, + 0x06595013, 0xea013f08, 0x34262617, 0x1d282732, 0x0e0e0f1d, 0x281d1d0f, 0x26343228, 0x26721725, 0x17452672, 0x18481848, 0x02021b38, 0x22effe03, + 0x22454322, 0x45222121, 0x01222243, 0x43e04be0, 0x12141428, 0xcc182413, 0x12260867, 0x28141412, 0x1b1a246d, 0xd1200d07, 0x3806cd55, 0x32333332, + 0x1234ebfd, 0x00001135, 0x12000100, 0x1202f3ff, 0x9700cb02, 0x05c75e00, 0x2a092d48, 0x37363736, 0x35343332, 0x85263534, 0x82372003, 0x2003830b, + 0x05d74d35, 0x43052543, 0x7147060d, 0x08c54a08, 0x490cad6b, 0x222505f7, 0x14151423, 0x5f5c1807, 0x83152008, 0x15162109, 0x9f451b87, 0x83631806, + 0x15143b0c, 0x01060706, 0x141413ca, 0x2e2d3b15, 0x16162120, 0x051d3a0e, 0x2c050708, 0x0082010e, 0x831c3721, 0x142a3a0b, 0x0b090907, 0x110e0e0c, + 0x382d2e21, 0x13141315, 0x11131312, 0x09080908, 0x8301820a, 0x1d242a3b, 0x0e15161d, 0x50a0060e, 0x333b8204, 0x010137a6, 0x07053c78, 0x32640508, + 0x150f0e05, 0x251d1d16, 0x0a223583, 0x33820a0a, 0x11080836, 0x05041213, 0x11010202, 0x32212010, 0x100a4532, 0x02040a10, 0x03290082, 0x05090906, + 0x050a0a06, 0x080c8201, 0x0901052b, 0x22091010, 0x1a191d1e, 0x22111514, 0x03031111, 0x07070504, 0x0620410a, 0x06050707, 0x07040505, 0x0d0c0404, + 0x24241918, 0x30298330, 0x03020306, 0x01060303, 0x040e050e, 0x04060103, 0x830f8202, 0x30270859, 0x19182424, 0x04050d0c, 0x05050408, 0x06060605, + 0x0a204107, 0x00000707, 0x16000100, 0x54020000, 0x3b00bd02, 0x71330000, 0x9d4f0d33, 0x09ed440d, 0x20064341, 0x09174717, 0x15145f08, 0x11335a22, + 0x15411133, 0x33343523, 0x1318191b, 0x1913244a, 0x36341b19, 0x30912335, 0x1b144080, 0x3a371e1b, 0x264c263a, 0x1d1b1a14, 0x26383836, 0x56040140, + 0x4be20d29, 0x372362c5, 0x1a1c3437, 0x1a131319, 0x37351d1a, 0x0e282538, 0x211e1d17, 0x2a40403d, 0x211d1d16, 0x293e3e3c, 0xa78354fe, 0xa7821820, + 0xa7825120, 0x00004723, 0x05a54b21, 0x18272621, 0x83075f77, 0x190d899b, 0x21097b0f, 0xc3831514, 0x2183af83, 0x22340d8f, 0x21130201, 0x0c071321, + 0x2c1b070c, 0x20141b2c, 0x0d071420, 0x2d340b83, 0x013ab01b, 0x3baf8eab, 0x15242416, 0x080c0c08, 0x1e30301d, 0x4c2b0b8b, 0x180e458b, 0x100a0e18, + 0x82130a0f, 0x152a3b35, 0x0f17180e, 0x0a10110a, 0x13201f13, 0x143b3192, 0x2a55143b, 0x0d19180d, 0x1382100a, 0x131f2025, 0x830f162b, 0x3a0d8421, + 0x45cd1420, 0x0f000500, 0x63022aff, 0x8100cb02, 0x0101c100, 0x45012d01, 0x55370000, 0xc5831733, 0x35513620, 0x099f630e, 0x41070621, 0x25430507, + 0x0a314a0f, 0x230faf63, 0x22272223, 0x0c474818, 0x30233422, 0x078d5118, 0x180c1b43, 0x840ec35a, 0x18798b33, 0x200e67ba, 0x07854113, 0x0ebd4c18, + 0x8d4d3720, 0x49918910, 0x4d180871, 0xa1610edf, 0x266f8414, 0x14150615, 0x49051617, 0x3720065f, 0x220e5b50, 0x6a0c0983, 0x042a08d0, 0x0c080904, + 0x09090f0b, 0x8d480a0a, 0x04062705, 0x02020504, 0x06820303, 0x00820620, 0x04052308, 0x03020404, 0x1f020202, 0x0505040f, 0x08080606, 0x14150f08, + 0x16161a19, 0x0f101414, 0x09090a0e, 0x1f820605, 0x03040126, 0x05090607, 0x062b2082, 0x14080807, 0x07171515, 0x84060707, 0x2504828b, 0x03040406, + 0x54820301, 0x07074f28, 0x0c0e0808, 0x37820a0c, 0x04060724, 0x59830305, 0x04040222, 0x09202982, 0x25055c6e, 0x0304060e, 0x2b820205, 0x82040421, + 0x01012358, 0x96820202, 0x02010234, 0x09090b05, 0x100f09e6, 0x08080509, 0x03040407, 0x8b820503, 0x09090726, 0x06060609, 0x05207683, 0x07265282, + 0x05070608, 0x1c820508, 0x83060621, 0x0c0c22d5, 0x206f820c, 0x2c218207, 0x09080804, 0x06060334, 0x08090908, 0x855c8206, 0x83042055, 0x03032311, + 0x01820504, 0x03205283, 0xfe226e83, 0x1282035a, 0x82050621, 0x20388214, 0x84a18206, 0x141a3180, 0x0807090a, 0x1313100f, 0x12121618, 0x09080f0f, + 0x0721f182, 0x2e268305, 0x20340605, 0x15112920, 0x271d1a15, 0x82033226, 0x820520cd, 0x08350839, 0x100c0b0a, 0x11121508, 0x0c0b0e0e, 0x08080f08, + 0x0f0f0708, 0x161a1314, 0x1d1d191a, 0x19201f20, 0x20211b1b, 0x0f1e1e1f, 0x0e0e0e0f, 0x190b0d0c, 0x03010c0c, 0x82f58202, 0x0727083c, 0x02050407, + 0x06090202, 0x03053407, 0x10090803, 0x17151411, 0x1b171817, 0x1618181a, 0x1518181b, 0x0f131316, 0x820f0e14, 0x020532fd, 0x29212136, 0x1b151612, + 0x3327271f, 0x0a0d0d10, 0x23e3820a, 0x06010203, 0xfe270982, 0x060604d3, 0x743e2a03, 0x242705b1, 0x17171d1e, 0x820c1011, 0x8203205c, 0x04032720, + 0x090a0707, 0x8782140c, 0x1a191d2b, 0x14131717, 0x07080e0f, 0x2e318203, 0x3e0c0909, 0x03014646, 0x0806050b, 0x82071008, 0x0d0d290e, 0x0e130f0d, + 0x050a0b0f, 0x37089782, 0x06060303, 0x0e0d0a0a, 0x0b0b0813, 0x0c0c0e0d, 0x0202031d, 0x080e0807, 0x01020404, 0x03030304, 0x05050504, 0x00020000, + 0x02f3ff17, 0x00cb0247, 0x00a50085, 0x35340500, 0x0f3f6f18, 0x84070621, 0x08dd4201, 0x200aa542, 0x0a254307, 0x420c454e, 0x362007d1, 0x47052b55, + 0xcd430ceb, 0x820f8f0f, 0x1803206d, 0x271f2f4d, 0x1b1a2255, 0x0a0b1415, 0x0c34e383, 0x1112120c, 0x0e100f10, 0x0f130e0e, 0x080b0b0f, 0x0c0e0508, + 0x07210683, 0x08f98209, 0x08120c20, 0x12142209, 0x10100f12, 0x0b0b1211, 0x0a0b0c0b, 0x090c090a, 0x0607070a, 0x05050506, 0x08820706, 0x38072108, + 0x0b0a1c1d, 0x1b1b1516, 0x12131420, 0x0f0e1111, 0x05050b0a, 0x06070403, 0x170d0a0a, 0x0b0b1111, 0x06382782, 0x14130d0d, 0x22221b1b, 0x0f0e0a18, + 0x07060813, 0x02020504, 0x07080404, 0x0d3c2382, 0x07070b0a, 0x05050403, 0x0819320d, 0x17101008, 0x0d0e1e16, 0x0e0a0b0d, 0x0c10100e, 0x09271a86, + 0x07070809, 0x82080810, 0x82082032, 0x060b384a, 0x161e1705, 0x060d0d16, 0x05020106, 0x0a070704, 0x0609090e, 0x82030307, 0x06033254, 0x342a0806, + 0x1e283c33, 0x0b15161e, 0x0a04050c, 0x2bdb8209, 0x1e181913, 0x18181817, 0x14161617, 0x17370084, 0x1a1b1b17, 0x12171719, 0x070d0d13, 0x10e80106, + 0x0c0e0f10, 0x82120e0f, 0x181131c1, 0x0d0c1213, 0x07060606, 0x10100d0d, 0x13121613, 0x21059f63, 0x3f4c0035, 0x00392605, 0x00510043, 0x0c29475b, + 0x23092551, 0x17161732, 0x22050f4c, 0x82141516, 0x0e1d4c01, 0x51053950, 0x0b84051b, 0x36333224, 0x01823435, 0x22272625, 0x4f151423, 0x098205d3, + 0x0c216224, 0x03830b22, 0x48924708, 0x183b3c61, 0x101f0f2d, 0x24010102, 0x0913260b, 0x1c1d1213, 0x57382a2a, 0x9e4c4c1d, 0x1e1e134f, 0xb01d572a, + 0x01010158, 0x264e41c6, 0x1320202c, 0x37013db6, 0x280e2868, 0x5c0e2a0d, 0x3e1f1e1f, 0x07070e2a, 0x02820607, 0x0d290624, 0xdc82181d, 0xd4090a38, + 0x17420246, 0x78230c0b, 0x07050606, 0x08070806, 0x0e0e7a28, 0xe783291b, 0x1b000228, 0x4502b2ff, 0xe3820a03, 0x00006323, 0xcf411805, 0x0e696609, + 0x19067959, 0x20103be2, 0x45ac1827, 0x07994a09, 0x67641420, 0x15142308, 0x3b192722, 0xe54e08a7, 0x23013b07, 0x1e212126, 0x1218181e, 0x08080911, + 0x17121109, 0x211e1e18, 0x11342622, 0x00821a1b, 0x18181924, 0x00821918, 0x1b1a1b2e, 0x11121214, 0x0f0f1011, 0x256d0f2e, 0x1c2c1982, 0x1e1d1c1c, + 0x1b221134, 0x0e1b141a, 0x75080082, 0x1b1a141b, 0x04172d4e, 0x15150d0d, 0x26271d1e, 0x39392f30, 0x26273030, 0x15141e1d, 0x32050d0d, 0x01152b11, + 0x07080405, 0x43100d0d, 0x11111621, 0x05060b0a, 0xbe83fe01, 0x04040203, 0x8e090706, 0xc9143a2f, 0x0f0f1464, 0x05050909, 0x95103101, 0x08bb7401, + 0x241a1010, 0x46483535, 0x19243636, 0x00001110, 0x00130003, 0x02550200, 0x005700bd, 0x006d0061, 0xa54d3300, 0x35342109, 0x4205a94a, 0x3949050d, + 0x07234109, 0x42061742, 0x09820921, 0x43491b83, 0x0a314e09, 0x20052342, 0x05714927, 0x8205974e, 0x0a13350b, 0x080e0f10, 0x32050707, 0x061d3910, + 0x5a070a0b, 0x052e5d1e, 0x0f251082, 0x460a0f0f, 0x201d8222, 0x080c820f, 0x2367052d, 0x0a06274f, 0x16400709, 0x0f0a162d, 0x08080e10, 0x20400507, + 0x0d0e0e0a, 0x05070608, 0x06064c9a, 0x0e0e0707, 0xd848090f, 0x83092040, 0x0f2608f0, 0x4181390f, 0x060a0907, 0x09062c58, 0x2d2d1e0a, 0x1515182b, + 0x130e2b10, 0x2c121e1e, 0x1515100f, 0x2d2d2b17, 0x17821d1d, 0x17821720, 0x120f2c27, 0x2b131e1e, 0x8727870e, 0x20278207, 0x23278218, 0x1cca011e, + 0x2005256e, 0x823f83b8, 0x00002c2b, 0xff000001, 0x026802f3, 0x6a7f00cb, 0x53420ac7, 0x0d314107, 0x2007c15f, 0x075b4120, 0x22073d51, 0x6c072223, + 0x91740689, 0x4f14200c, 0x35411083, 0x15142305, 0x255b2320, 0x1514210f, 0x6b081182, 0x1b1ab101, 0x2f3f1b1b, 0x10212130, 0x05020210, 0x2548143b, + 0x02030301, 0x0d0b0a07, 0x1110100d, 0x150137a6, 0x0202038b, 0x07070e02, 0x15140b0b, 0x2f231d1c, 0x342e2e2e, 0x252b302f, 0x1c1c2020, 0x100f1615, + 0x02030807, 0x4d133a05, 0x0f0e0d27, 0x16161213, 0x0506041a, 0xfe47d504, 0x060a8fe3, 0x150a0b06, 0x271e1e15, 0x38353532, 0x03326882, 0x0d020305, + 0x261a1a0d, 0x10133127, 0x0e2c0f11, 0x6b820402, 0x07080926, 0x05070708, 0x02280d82, 0x110d0301, 0x161c1511, 0x0e3c5684, 0x20401b0e, 0x07090a12, + 0x120d0d06, 0x1b171812, 0x0f121f1c, 0x0f2b0f10, 0x0809090b, 0x01393183, 0x2b010102, 0x12110e0f, 0x17171e16, 0x08081010, 0x44211111, 0x08080b21, + 0x2c008200, 0xff410002, 0x02280273, 0x005500db, 0x0fbf437b, 0x18262721, 0x5b071551, 0x34230c21, 0x18373235, 0x4d0b39b0, 0x23200859, 0x4309cb43, + 0x232008c3, 0x570cc343, 0x14230633, 0x18171617, 0x420a2d90, 0x012e05d7, 0x17161841, 0x15151617, 0x0f0f1213, 0xd2770b0b, 0x0f0f3005, 0x15141412, + 0x16161716, 0x0f100917, 0x8218170a, 0x820d8209, 0x22148205, 0x83191917, 0x82128430, 0x17173004, 0x180c2617, 0x15111313, 0x07070f0e, 0x82010403, + 0x032d0800, 0x08090606, 0x070d0a0b, 0x0a0b090a, 0x568d0a0b, 0x0707032c, 0x10100b0a, 0x17181313, 0x21201c1c, 0x26020625, 0x1d1c2121, 0x13141717, + 0x3476830e, 0x24470307, 0x01234701, 0x07080404, 0x42110d0d, 0x12111821, 0x3d8d820a, 0x06a3bafe, 0x110b0b05, 0x21431912, 0x090c0c11, 0x60050408, + 0x3e01d020, 0x0b0a06a0, 0x2046130f, 0x19290805, 0x09080909, 0x06070708, 0x12131416, 0x0b0e0e12, 0x05070707, 0x00040505, 0x08000300, 0x6802a1ff, + 0xb500cb02, 0x0901dd00, 0x177b1900, 0x33322109, 0x6309e363, 0x07230eeb, 0x84060714, 0x82062003, 0xef5c1807, 0x0c894b0e, 0x470a9f58, 0x37830cff, + 0x560ee94a, 0x574b131b, 0x053f4f08, 0x015d2220, 0x09255d06, 0x27204382, 0x22244b83, 0x36353437, 0x65846183, 0x36373422, 0x17590f85, 0x8216200e, + 0x35362163, 0x2d82af84, 0x7b180783, 0x93590817, 0x0714210e, 0x08202b82, 0x31060652, 0x0c0a1d04, 0x14110f0e, 0x0b030c0b, 0x0c140f10, 0xc4410909, + 0x05f34a07, 0x02026f08, 0x1c1c2202, 0x0d0c1a17, 0x060b0605, 0x0a0a0808, 0x0c120e0f, 0x181a0606, 0x0f101313, 0x0a0a0d0d, 0x05040706, 0x15150302, + 0x34352a29, 0x2e2d2a40, 0x02030431, 0x2c2b290a, 0x22222a2e, 0x0c0d1a19, 0x0c0c0606, 0x10201617, 0x291e0807, 0x13121e1e, 0x15140909, 0x3232252a, + 0x0302033c, 0x020f1d03, 0x11020304, 0x03101211, 0x1e020303, 0x4b82020e, 0x08090824, 0x02820708, 0x05050526, 0x01852103, 0x03828782, 0x02360282, + 0x04030302, 0x08090705, 0x04050507, 0x0f0f0504, 0x01027c0f, 0x1c850303, 0x03292582, 0x07050502, 0x0607080a, 0x824a8203, 0x8203202b, 0x10103e13, + 0x39255f11, 0x1a1e3739, 0x0810141b, 0x08070710, 0x09121209, 0x07030308, 0x0c090907, 0x282c8208, 0x03050604, 0x05080805, 0x2cc98206, 0x120a0a01, + 0x201a1a15, 0x0b0f1012, 0x05534b06, 0x03040525, 0x83070802, 0x09460800, 0x0b090908, 0x0d0b0b0a, 0x2a32100d, 0x1121212a, 0x120a0911, 0x300c0c18, + 0x090e0e1b, 0x1913130a, 0x0e121d18, 0x0a0a0a0e, 0x02050a09, 0x100c0902, 0x1a131210, 0x2a36211b, 0x101d202b, 0x17150310, 0x1a0f0f17, 0xc5821019, + 0x19191628, 0x1f1e1211, 0xa7820212, 0x02020328, 0x21211e04, 0x0c82b616, 0x0202012a, 0x07040102, 0x06040407, 0x0325c384, 0x03050507, 0x39e38204, + 0x0c080704, 0x0909110c, 0x05081e08, 0x06091004, 0x02040105, 0x05050802, 0x21860705, 0x82040421, 0x09062f0d, 0x0f0b0b08, 0x0b020305, 0x00030304, + 0x874f0002, 0x00072d07, 0x13000017, 0x33203534, 0x13201514, 0x83053950, 0x23222b0b, 0x18221510, 0xfe8eab01, 0x464f5c55, 0x024c3306, 0x3b143b6e, + 0x0192fd14, 0x143c796c, 0x94fe143c, 0x00820079, 0x3400012d, 0x38020000, 0x6500bd02, 0x42210000, 0xd5510af7, 0x34232205, 0x08e75835, 0xbf423720, + 0x054f5a05, 0x23202986, 0x20251385, 0x06070633, 0x05395507, 0x4e07e551, 0x27430e95, 0x01222c08, 0x1c1c1092, 0x0c0c0d11, 0x820b0b0b, 0x0e240804, + 0x1849100e, 0x1b242549, 0x0910111a, 0x59b20209, 0x06080806, 0x05024f9e, 0x0b080805, 0x130f0f0c, 0x29501814, 0x012e1383, 0x0905a246, 0x39730508, + 0x050e0e15, 0x0b833061, 0x264c3708, 0x130a0a02, 0x251c1c13, 0x090c0b0d, 0x0a0a0b0a, 0x0e0c0d0a, 0x131d1d19, 0x37382151, 0x13141921, 0x08080d0d, + 0x02030405, 0x0808143a, 0x14151011, 0x12130b17, 0x78820c0b, 0x57610b20, 0x0b270805, 0x0a0a1212, 0x120b1212, 0x0b1e1819, 0x1f0b1312, 0x16151b1a, + 0x03040d0c, 0x06060605, 0x0d0e0a0a, 0x2f1b1415, 0x4a243636, 0x04320583, 0x56020000, 0x1f00bd02, 0x67004300, 0x00006f00, 0x035d1013, 0x074b5f0a, + 0x2506fd53, 0x26272627, 0x814c1425, 0x0c514411, 0x07213382, 0x0d397b14, 0xef4f3720, 0x07df430a, 0x31551320, 0x5c322d05, 0x20411642, 0x0b0b0a08, + 0x0e161615, 0x0f310b83, 0x0c151615, 0xf2010a0a, 0x10100908, 0x0e1d1616, 0x08dc820d, 0x080a096c, 0x09090810, 0x16111008, 0x161d1b16, 0x09101016, + 0x0505c008, 0x0d0c0a09, 0x0c0b0f10, 0x06050807, 0x02010203, 0x090a0505, 0x10110d0d, 0x09090d0d, 0xa5b40505, 0x9301a537, 0x0265d2fe, 0x251daf0e, + 0x514e2b26, 0x4b013651, 0xaff2fd6e, 0x474a4a32, 0x83232227, 0x1a23232c, 0x040d0e1a, 0x09070703, 0x24190d09, 0x222c2d23, 0x11821b23, 0x1b0d0d2e, + 0x2c22231b, 0x13191a20, 0x06090912, 0x0805397e, 0x0f0f0b29, 0x19191f13, 0x09091313, 0x13130809, 0xedfe1a19, 0x0e2c0e2c, 0x02000000, 0xae010000, + 0xbd023302, 0x31000f00, 0x4a130000, 0x222109a7, 0x20e78223, 0x07ed5c33, 0x85059754, 0x070623f9, 0xa7490706, 0x080f8205, 0x143d5144, 0x143d37a4, + 0x1c39a62b, 0x0d16150d, 0x0b14140b, 0x0e2b1541, 0x0f18180f, 0x1a0f0a12, 0x012a101a, 0x2138abae, 0xaa0b210b, 0x1643cc39, 0x16162625, 0xcb162526, + 0x1a4b9744, 0x1b1b2c2c, 0xa91a2c2c, 0x84820039, 0x82250021, 0x0244248c, 0x195b00ae, 0x5115779f, 0x99181831, 0x1f490e8b, 0xa97a180c, 0x08af820f, + 0x2952255f, 0x0e16161e, 0x0807080e, 0x17101009, 0x231e1d18, 0x23282822, 0x171e1d24, 0x08101018, 0x0e070608, 0x1e17160e, 0x3aae1f5d, 0x1117171d, + 0x0b090911, 0x1f16160c, 0x1f26271e, 0x0b16171e, 0x0804040c, 0x0e0a0b07, 0x1412110e, 0x1f143dad, 0x22222020, 0x312d2726, 0x24252a2b, 0x13131c1b, + 0x2400820a, 0x1b1c1313, 0x4daf1924, 0x00003334, 0xff0d0003, 0x032d0281, 0x0019000b, 0x004b0031, 0xc7601300, 0x76c98205, 0x45180677, 0x354f0871, + 0x5337200b, 0x278207d3, 0x854b0120, 0x08ad480d, 0x22076508, 0x151a4d34, 0x16152323, 0x33162423, 0xd01a4d11, 0x0304035f, 0x62614103, 0x2e2d335e, + 0x05040223, 0x61624102, 0x2d2e335e, 0x1e140201, 0x0e0f1d1e, 0x38a60a0e, 0x1e1549db, 0x0f0f1e1e, 0x01310b0e, 0xbf0d2783, 0x06060460, 0x03132403, + 0xff030506, 0x960d2755, 0x09111009, 0x1617160f, 0x080b0b0b, 0x0a100f0a, 0x0c250b83, 0x8cfe0a0b, 0x054e6a2a, 0x0b21172f, 0x442d070f, 0x20234145, + 0x00001820, 0x20df8204, 0x22df887f, 0xb47b0063, 0x071754e1, 0x41405d69, 0xbf392811, 0x2b212216, 0x16171716, 0x17161714, 0x101e1f3c, 0x22241919, + 0x12111b1a, 0x24008209, 0x1b1b1213, 0x05754722, 0x0c0b0a2a, 0x2a1515d8, 0x0c0f1014, 0x26057771, 0x14100f0c, 0x4115152a, 0x45082c3b, 0x0d0c1abd, + 0x21070404, 0x05060910, 0x1b4c2526, 0x08090e0e, 0x19181212, 0x19182120, 0x09091111, 0x18190c0d, 0x32352627, 0x2ec42726, 0x07061717, 0x10110c0c, + 0x12111616, 0x06060c0c, 0x03001817, 0x7aff0d00, 0x43423202, 0x417f2006, 0x09454561, 0x4c232007, 0x3220059f, 0x4c09cd78, 0x23820989, 0xff6b3220, + 0x062b690c, 0x08286541, 0x2218c63f, 0x1d1c2c22, 0x1c221e1d, 0x1519171d, 0x070e0f14, 0x361c1b07, 0x0c190819, 0x06181730, 0x110c0b06, 0x1b181611, + 0x10101d1b, 0x0d0f0f10, 0x1d240d0d, 0x0b15161c, 0x2b15160a, 0x0b181830, 0x2c65410c, 0x0810a52b, 0x0a040508, 0x060d1327, 0x057e4507, 0x23102d08, + 0x0d271111, 0x0d1d0e0e, 0x07070b0b, 0x06050403, 0x0413250a, 0x03020303, 0x0e060701, 0x1713120e, 0x09161522, 0x2718190a, 0x0017171d, 0x2b086741, + 0x003d0013, 0x00a30055, 0x35341300, 0x46077b43, 0x337a0f37, 0x3332241d, 0x43221514, 0xed4218cf, 0x3b8b4110, 0x15203408, 0x1a152425, 0x0a0a1211, + 0x07070605, 0x10110c0c, 0x1d1c1815, 0x1010101f, 0x0f0f0f0e, 0x1d1c2310, 0x0a0b1615, 0x09090504, 0x1a1d1414, 0x99141d1e, 0x444dd633, 0xaf411727, + 0x23290841, 0x21211411, 0x13131714, 0x0c0d0e0e, 0x0c0c0e0d, 0x04040909, 0x28110908, 0x04050714, 0x01020303, 0x100f0807, 0x0e191514, 0x2801820d, + 0x181b1515, 0x28131b1b, 0x1875440e, 0x4546d341, 0x6d20077f, 0x5b4d3b43, 0x0171089d, 0x28294318, 0x1f16ba23, 0x0729711e, 0x1a1f2308, 0x0e0e1514, + 0x08070706, 0x13140f0e, 0x1718191a, 0x853baf17, 0x0e0d0d2c, 0x1c1c240e, 0x0a0b1516, 0x19430b0b, 0x12a9322c, 0x05040909, 0x0e122408, 0x06050606, + 0x10110c0b, 0x05557116, 0x55710520, 0x710b2005, 0x0b430f55, 0x032d2107, 0x20050b43, 0x710b4391, 0x42215b41, 0x7f414cf9, 0x4ee94231, 0x243ca341, + 0x0065004d, 0x1bab73a1, 0x2033e545, 0x0ac55705, 0x440c8f48, 0xb34118bf, 0x1e012121, 0x36091146, 0x141a171c, 0x070f0e14, 0x371c1b08, 0x0d180818, + 0x0618182f, 0x460b0c06, 0x1e260511, 0x0f101011, 0x11460e0e, 0x0b0a2106, 0x23051146, 0xe4fe0b0c, 0x4117bb44, 0x9c2030c1, 0x30122f46, 0x0d261112, + 0x0d1d0f0e, 0x07070a0b, 0x05050304, 0x072f460b, 0x46070621, 0x1826092f, 0x171d2719, 0x2949be17, 0x30c94117, 0x0500042e, 0x2d027aff, 0x1b000b03, + 0x3f002700, 0x21064349, 0x63462322, 0x4a372008, 0x23240823, 0x27221514, 0x200ae775, 0x52a34103, 0x3191c722, 0x27113a76, 0x181a1911, 0x2c0c0c0d, + 0x3e487d41, 0x26164283, 0x2e2d1f12, 0x1615172c, 0x273fbd10, 0x8c16420d, 0x23184181, 0x10132224, 0x41d1fe11, 0x0020485c, 0x2205a34a, 0x4935027a, + 0xa34a063f, 0x2726213f, 0x5317cd68, 0x59760e11, 0x28134617, 0x13d22708, 0x28221b1a, 0x12131e1e, 0x0b0b090a, 0x21201716, 0x1717172b, 0x16161416, + 0x1e1e3c18, 0x23191910, 0x121a1a22, 0x00820913, 0x100cbf26, 0x15291410, 0x29230082, 0x4a101014, 0x224605aa, 0x12a8262c, 0x0c0c0809, 0x05ad7619, + 0x1a1a262d, 0x04030c0d, 0x0a102108, 0x74250505, 0x112d0762, 0x20201919, 0x0c0d1919, 0x17170506, 0x055a742e, 0x10110d26, 0x11111616, 0x260b6341, + 0x0053003b, 0x449d0085, 0x27441b8d, 0x207b4421, 0x21408541, 0x9b781101, 0x0e13240d, 0x7807080e, 0xfe211b9b, 0x17fb42f2, 0x203fa741, 0x079e47a0, + 0x47070d21, 0x1120059e, 0x2507ee76, 0x920a0404, 0x9e472131, 0x43c4200f, 0xc441171c, 0x0005263e, 0x027aff0d, 0x0627432f, 0x79006924, 0x2f499500, + 0x07a3413c, 0x43525178, 0xca3e2843, 0x231c1b14, 0x141c1b24, 0x180a0a14, 0x10142f19, 0x050b0b10, 0x12090a06, 0x211a1913, 0x476c1a20, 0x062f0805, + 0x10100a0b, 0x18182f14, 0x13cf0a0a, 0x14262713, 0x26141313, 0x0c131327, 0x1510100c, 0x0b111015, 0x0606050c, 0x110b0c06, 0x162c1410, 0x43060616, + 0x3d082c59, 0x07080fa3, 0x0e0f0807, 0x2b1a1415, 0x05091a1b, 0x0b0c0807, 0x17110e0f, 0x0e0e1312, 0x06070706, 0x12130e0e, 0x0f0e1117, 0x07080c0b, + 0x191a0905, 0x15151a2c, 0x10200001, 0x20101111, 0x00821021, 0x8209a578, 0x0e0e2829, 0x04050a0a, 0x82261312, 0x8200203d, 0x07b34100, 0x4d00132a, + 0x9d006500, 0xc900ad00, 0x481b7943, 0xe7415407, 0x5a2f485a, 0x48551942, 0x45425754, 0x09f7435b, 0x53003b28, 0x9b008b00, 0x4342b700, 0x4abd451b, + 0x45521944, 0x21424ad7, 0x48ed4555, 0x205b1242, 0x150b4600, 0x50188954, 0x234420eb, 0x7e5a205a, 0x322113ff, 0x17ad4750, 0x3455d541, 0x40412a83, + 0x1e1d223d, 0x0f0b2117, 0x20201807, 0x44444223, 0x18d6502d, 0x255cba41, 0x0d000200, 0x9355ed00, 0x32715608, 0x56285d47, 0x00342a40, 0x00010000, + 0x02b10021, 0x00e80168, 0x3700001f, 0x27262726, 0x5605e14c, 0x202507eb, 0x20151433, 0x080d8623, 0x2e1bb235, 0x2d1b1b2d, 0x0e091b2e, 0x190f080e, + 0x63011018, 0x9ec5fe76, 0x0f191810, 0xb10e0e08, 0x192b2b19, 0x2a1a0d1a, 0x0e07192b, 0x180d080d, 0x143d0e17, 0x8217170d, 0x820d200a, 0x828e2067, + 0x02da226c, 0x20678305, 0x05936321, 0x7007274d, 0x6b5e05f7, 0x10272506, 0x0b012215, 0x52825c83, 0x2d1c0926, 0x0e1b1c2d, 0x0d837283, 0x3d2b1583, + 0x0e8a1401, 0x080e1818, 0x83080e0d, 0x20038370, 0x836e8208, 0xc9fe2213, 0x82d28267, 0x8200206b, 0x854820d3, 0x872520d3, 0x23202565, 0x33203534, + 0xff720d87, 0x21738205, 0x5983b601, 0xfe25c283, 0x3b01769d, 0x8363839e, 0x827983de, 0x08b12203, 0x82bf820d, 0x153c24c4, 0x8218170e, 0x070e270a, + 0x1a2a2b19, 0x77820d1a, 0xd78b6b85, 0x10245d8b, 0x10333235, 0x220c0b6c, 0x82200122, 0x831c2051, 0x216f835d, 0x0583143e, 0x1b280d83, 0x1f1b2d2e, + 0x192b2c19, 0x0720d482, 0x0124c883, 0xecfe6737, 0x0720e684, 0x1923da82, 0x85192c2b, 0x0021286b, 0x0148026c, 0x413700a4, 0xa95c14ab, 0x37362305, + 0xdd883736, 0x5c080344, 0xef8205ab, 0x2110c341, 0xf28e6edc, 0x10411c20, 0x6edc2107, 0x2006d941, 0x21ec826c, 0xf283191a, 0x0d081a24, 0xa183080d, + 0x27058241, 0x2b1a080d, 0x0c1a192b, 0xf3410583, 0x0e182105, 0x0d201982, 0xb082c782, 0x41000121, 0xaf82071b, 0x1b412120, 0x0d4b6d0b, 0x6d0dff41, + 0x33410d31, 0x1917420e, 0x21184b41, 0x2e4268cf, 0x41198517, 0x012a0961, 0x00005c00, 0x97010c02, 0x1b5e2300, 0x058f5b0a, 0x20099b5b, 0x05bd5c16, + 0x07061739, 0x15d30106, 0x371e1b1a, 0x30263939, 0x09080610, 0x4c349a06, 0x851b1426, 0x120a3411, 0x19191312, 0x3536341c, 0x811b5024, 0x08090541, + 0x850f2d06, 0x24362711, 0x0011110a, 0x6f8c0000, 0x18089942, 0x41094f44, 0x222105c5, 0x08a17f23, 0x120b9630, 0x39260b12, 0x1a1e373a, 0x1c55141b, + 0x9b784589, 0x39262605, 0x1b1d3839, 0x2a54821b, 0x3636240a, 0x19191c34, 0x820f2d13, 0x9105268f, 0x24244731, 0x82118435, 0x226f8d6e, 0x5e353421, + 0x781809d9, 0x17200a45, 0x82053755, 0x22072ddd, 0x254c2201, 0x37393a25, 0x151a1b1e, 0xdb827a83, 0x82381d21, 0x102f21ed, 0x9b227883, 0x6e870e2d, + 0x12110a24, 0xed83140a, 0x23363526, 0x40811a50, 0xdf937c83, 0xb1465b85, 0x06554407, 0x3d650720, 0x79222707, 0x06080906, 0xcf821030, 0x0a207287, + 0xed820b85, 0x059b1d22, 0x91261c82, 0x23234730, 0xe3833536, 0x120a1425, 0x84230a11, 0x131a23ef, 0xe0820f2c, 0x43000121, 0x3b20071f, 0x87161f43, + 0x0d4575e7, 0x43079942, 0xa1311923, 0x17170e51, 0x16170d0e, 0x1010090d, 0x651a4e09, 0x200f8433, 0x240f8216, 0x8109100f, 0x19274341, 0x25251638, + 0x0c0d0716, 0x19180f07, 0x16133a0f, 0x06162425, 0x0f060d0d, 0x27431919, 0x42b78f0c, 0xb18d0903, 0x4310bd44, 0xd3820adf, 0x170d9e23, 0x23a18417, + 0x32651a4d, 0x1727a185, 0x0f0f0a0d, 0x43408109, 0xa12117e3, 0x20338251, 0x8393876c, 0x43af89a1, 0xc78219e3, 0x00000030, 0x002c0001, 0x013c02b9, + 0x007f0097, 0x37463700, 0x09736805, 0x82072743, 0x0fdd6f07, 0x67070d66, 0x17200b55, 0x18070d42, 0x70129dcb, 0x0f830f49, 0x080be36c, 0x15142729, + 0x0a052c22, 0x349a0609, 0x03022d59, 0x0b050603, 0x06040f0a, 0x08070706, 0x0d0e0809, 0x02040c0d, 0x01020103, 0x83040301, 0x0b0c3111, 0x0c0c0d0e, + 0x0d0c100c, 0x0a0a0b0c, 0x04050508, 0x03270282, 0x07060d03, 0x8204011b, 0x07082435, 0x84070608, 0x82072003, 0x82062000, 0x0202213b, 0x05273c82, + 0x08090606, 0x820f0c0c, 0x0f0c253a, 0x0c0b0d0d, 0x0e253b82, 0x300a0f10, 0x07dd43b9, 0x04050128, 0x0a0b0707, 0x4c7d0510, 0x07072205, 0x0522790d, + 0x0a04042c, 0x0c0b0b0b, 0x06070909, 0x61830303, 0x09070723, 0x20c38206, 0x22008307, 0x83100404, 0x05082373, 0xa3820506, 0x03010223, 0x20458203, + 0x29268204, 0x03030404, 0x0c0a0a09, 0x37840a0d, 0x99840320, 0x11100926, 0x1b4f0c10, 0x230b7b41, 0x2500007b, 0x41082144, 0x4d411019, 0x0e337117, + 0x74108941, 0x694a13b3, 0x069d440d, 0x0afd0125, 0x820a1112, 0x0c0b2c00, 0x1a0e0d0d, 0x06141616, 0x82030505, 0x05022900, 0x05060405, 0x08050607, + 0x08379482, 0x06060809, 0x09050605, 0x0d020504, 0x051b0706, 0x0a0a0809, 0x820c0c0b, 0x1b0e2402, 0x82131716, 0x8233841b, 0x04042df3, 0x060a0707, + 0x09070707, 0x07070808, 0x0c284c82, 0x05060909, 0x01020304, 0x64390082, 0x05458921, 0x2f05090a, 0x0c2347b9, 0x0a0c1312, 0x06050808, 0x0b0b0303, + 0x20308215, 0x20628206, 0x38118405, 0x03030404, 0x02020201, 0x04050403, 0x07080806, 0x04040705, 0x0d0d0d10, 0x884b820b, 0x822e822f, 0x06082376, + 0x64820507, 0x82040621, 0x04012d2f, 0x05050504, 0x07090a0e, 0x02040406, 0x2d207083, 0x20064745, 0x335b4400, 0x440bd142, 0x3227195b, 0x26271819, + 0x490f0818, 0xcf230551, 0x445cb845, 0x0f27054d, 0x27261808, 0x44193218, 0x8f471d5b, 0x133a2107, 0x24067747, 0x25241607, 0x13834716, 0xc3743b20, + 0x0f85471e, 0x1420bd8b, 0x830b9349, 0x198747ae, 0x0e22cc84, 0x2183090e, 0x56ac3d2b, 0x0e18170e, 0x070e0d08, 0x21958217, 0x8947182f, 0x182f3017, + 0x17242516, 0x080d0e07, 0x0e17180e, 0x410041c1, 0xc3490d6f, 0x092b7b08, 0xe5483620, 0x1df34806, 0x06070624, 0xce481101, 0x45ce2307, 0x06455cb7, + 0x27182507, 0x19321727, 0x25171445, 0x27171932, 0xd0486c27, 0x133a2107, 0x0d25b685, 0x25251608, 0x1e144516, 0x2009f348, 0x0643483b, 0xd96ea987, + 0x690d8905, 0x372006b7, 0x48152976, 0x18230ef7, 0x4a182726, 0x15831137, 0x2118f748, 0xae831730, 0x23051f42, 0x40c20e17, 0x85078b41, 0x058b41c6, + 0x460bfb48, 0x35200783, 0x42223b47, 0xb52125d9, 0x2ba0835a, 0x090e0e08, 0x17252617, 0x17262517, 0x1825c283, 0xb5182627, 0x21d5425a, 0x2423162a, + 0x23241516, 0x0e0d0815, 0x8f10d342, 0x06bb72ab, 0x15422720, 0x834e2028, 0x83918389, 0x83a18399, 0x5ab421a9, 0x21171042, 0xb5825ab4, 0x0e076c2e, + 0x2315080d, 0x24161524, 0x0d081623, 0x42240e42, 0x27200ac7, 0x21145741, 0x13493320, 0x23222305, 0x23443534, 0x0d012819, 0x3e153d5a, 0x4178ef14, + 0x58251936, 0x584eea1e, 0x08f8431d, 0x82098742, 0x4b638477, 0x32271d73, 0x22151433, 0x431f5e8e, 0x5e2619d8, 0x133af91f, 0xc24371e0, 0x54fd2317, + 0x8349133a, 0x2077820c, 0x43db8537, 0x20211ba3, 0x24778223, 0xef153d21, 0x177b4177, 0x59f3fe24, 0xdb826c3e, 0x79431e20, 0x1d582119, 0x820a5f4e, + 0x0e6b4c77, 0x82053544, 0x496b8267, 0x63430b4f, 0x205d250e, 0x1f5e53f9, 0x83184f43, 0x143921e0, 0x43050041, 0xe34c0b37, 0x673f2007, 0xe5430a53, + 0x07062209, 0x08a34906, 0x490f6145, 0x9f820ddb, 0x29548e22, 0x410be843, 0xa487198b, 0x5e242d83, 0x133af91f, 0x210b3e45, 0xa34154a8, 0x45198217, + 0xaf410a8e, 0x00f2220c, 0x149f4253, 0x79090d6b, 0x23220e95, 0x54183534, 0xef831339, 0x23200382, 0x2f19cb42, 0x070861c2, 0x05060608, 0x040a0405, + 0x03010205, 0x04260082, 0x0d0c0b09, 0x02820d0e, 0x0c0c0c2c, 0x030b0b15, 0x08050602, 0x00820b08, 0x0a0d0c26, 0x68cf080b, 0x2219f642, 0x82020201, + 0x09032640, 0x070c0a0b, 0x37548207, 0x09030405, 0x1a330504, 0x04050203, 0x140a0808, 0x0d1c1818, 0x0d0d0d0c, 0x09264b82, 0x06050708, 0x22430302, + 0x089b4308, 0x5700f224, 0x63460000, 0x0da57a0a, 0x4a08595c, 0x8a1808b5, 0x8d70081b, 0x4a172005, 0x332008e9, 0x5012e942, 0xcf24095f, 0x0b0a0867, + 0x0b24e082, 0x08080d0b, 0x2207f577, 0x82090808, 0x0e0e2113, 0x0d24a282, 0x04090c0b, 0x0223cd83, 0x82050401, 0x820520c4, 0x0708235e, 0x184361c2, + 0x0897460e, 0x06020326, 0x0a070705, 0x0c205182, 0x0b213a82, 0x3144820f, 0x090b0b0c, 0x0408070a, 0x34030205, 0x09040519, 0x37770403, 0x0a0c2405, + 0x8203090b, 0x02022200, 0x10454301, 0x02000022, 0x2406374d, 0x005300f2, 0x16054273, 0x08d54918, 0x2013bb4b, 0x06f56b15, 0x2207a74b, 0x4f232223, + 0x05420535, 0x42372008, 0x44180847, 0x27230999, 0x85222326, 0x14152131, 0x31109550, 0x02022674, 0x08070605, 0x0b0c080b, 0x0e0f0d0d, 0xde821010, + 0x0a0b0d23, 0x091e420a, 0x0a28f884, 0x13380709, 0x3466143e, 0x28062242, 0x101225c0, 0x0a090c0c, 0x055f4204, 0x0606052c, 0x0c060506, 0x090a0b0b, + 0xc6500404, 0x13272112, 0x08057941, 0x080a0b26, 0x07060707, 0x03030302, 0x07070506, 0x18191408, 0x0c0d0d1d, 0x0c0b0c0d, 0x08070b0a, 0x03020405, + 0x194b194b, 0x2c063b42, 0x080405bb, 0x0c0a0b09, 0x080b0a0d, 0x2b328204, 0x05020102, 0x0b080904, 0x002b0d0b, 0x4f410082, 0x0a59420e, 0x42071541, + 0x894b1a61, 0x1815200f, 0x5107d148, 0x25200cd7, 0x123f3919, 0x420b8d42, 0x73290975, 0x32143d27, 0x0b0a0719, 0x2b00820c, 0x08080c0b, 0x02030505, + 0x09160a0b, 0x0d29ad82, 0x100f0e0e, 0x0e0d0e0f, 0x936b180b, 0x67012207, 0x0e6e4233, 0x2ae4fe26, 0x0905050e, 0x0525ee83, 0x07060606, 0x22e98205, + 0x82040405, 0x0c0d2111, 0x39088a42, 0x194b194b, 0x05040203, 0x0a0b0708, 0x0d0c0b0c, 0x1d0d0d0c, 0x08141918, 0x57180707, 0x0a200a7f, 0x0d247183, + 0x0f2b0e0d, 0x3b108342, 0x0d1328a9, 0x09080b0a, 0x01020504, 0x03030302, 0x0a0b0804, 0x0b0a0c0d, 0x05040809, 0x200b0b4a, 0x169d42c9, 0x0c014718, + 0x22066d4e, 0x42343734, 0xbf7213ab, 0x0c9b4e0f, 0x43373221, 0xbf4512c1, 0x23222108, 0x437e0182, 0x05634d12, 0x15251b86, 0x07141506, 0x08817806, + 0x590a5d7f, 0x194505a3, 0x01033d1a, 0x0507070a, 0x07060606, 0x03010204, 0x04050302, 0x01030305, 0x0a060101, 0x08060f0a, 0x2a06104d, 0x04040605, + 0x02030201, 0x82020102, 0x2106831a, 0x0e820202, 0x0404042b, 0x04050605, 0x08080303, 0x203b820c, 0x0ec54101, 0x2a08d353, 0x02040102, 0x02050103, + 0x82050506, 0x0a072d67, 0x0c0d0e10, 0x02040406, 0x05030302, 0x04204883, 0x58830082, 0x2206737d, 0x82080607, 0x07072400, 0x82060607, 0x23208231, + 0x02020402, 0x251c8d45, 0x05060404, 0x9b840409, 0x57830320, 0x02010126, 0x08100f14, 0x03223682, 0x00820502, 0xd6830720, 0xdb82d982, 0x2986c384, + 0x05050723, 0x20bd8204, 0x119f4401, 0x22064c56, 0x83020e18, 0x820620b5, 0x21e38237, 0x00820910, 0x82050621, 0x02012755, 0x01010502, 0x07820201, + 0x0909012b, 0x07080908, 0x03040306, 0x826c8202, 0x05072388, 0xef450202, 0x0262260d, 0x00ad0148, 0x0cef4553, 0x560bcd4a, 0x5f790dfd, 0xc1aa1805, + 0x1e7f5109, 0x0d2f012b, 0x050e1516, 0x4c050708, 0x06244127, 0x32570920, 0x2b582f0f, 0x050a0906, 0x0d17160d, 0x05080805, 0xa8412953, 0x2f5d2117, + 0x62282782, 0x03050503, 0x14242314, 0x0720c486, 0x2b118855, 0x18272818, 0x03040503, 0x15232315, 0x41105743, 0x182f083b, 0x00002827, 0x00390001, + 0x022f0200, 0x544900a0, 0x36200adf, 0x4f06494d, 0xc14707dd, 0x53072006, 0x1d930da5, 0x22061741, 0x4b078801, 0x8a08050c, 0x10100a17, 0x15140c0a, + 0x0605040c, 0x0b0b0b06, 0x41412b08, 0x1e1e223f, 0x0e0e0918, 0x0607070d, 0x191a0f05, 0x170f1e0f, 0x3e221e1f, 0x062b4141, 0x10090708, 0x110b1111, + 0x07111d1d, 0x1f070b0c, 0x02013434, 0x311e0102, 0x0b061e31, 0x1c10060c, 0x1d16101b, 0x3f3c211d, 0x25192a3f, 0x12132325, 0x4d330d11, 0x24284b4d, + 0x04031c24, 0x53a60305, 0x1311110d, 0x18252424, 0x312b2c21, 0x3e5e5d5a, 0x0c13130c, 0x090f0f09, 0x54232415, 0x0d2406eb, 0x23008902, 0x1020eb82, + 0x20095b4b, 0x11e35807, 0x10333228, 0xbb012215, 0x8b4150a1, 0x07b34107, 0x2507394e, 0x013d51f2, 0x5d417255, 0x2c192507, 0x0d19192b, 0xb04e0583, + 0x0e182505, 0x008572fe, 0x8608cf55, 0x10332173, 0x45065f55, 0x4b440cb7, 0x2273820a, 0x426bd75c, 0x1c230726, 0x821b2e2d, 0x591c2076, 0xb4250759, + 0x8f013d3c, 0x24728584, 0x2b19070e, 0x8272832c, 0x05cf4d05, 0xfe0e1824, 0xe38d72ab, 0xd7943320, 0x67828382, 0x2007bf59, 0x25d88fed, 0x143e3cb5, + 0xf6866cd7, 0x0e28d78b, 0x18170e08, 0x7155010d, 0x8485da82, 0xcf550d20, 0x4bdf8607, 0x22210863, 0x05e95823, 0x21123945, 0xce877b01, 0x3e51f125, + 0x8e50a014, 0x28cb87ec, 0xfe858e01, 0x180d71ab, 0x8a758217, 0x26df82eb, 0x0200005d, 0x5708020b, 0x4b41088f, 0x05f97507, 0x20115f59, 0x065f5951, + 0x180f0928, 0x38a70f19, 0xcd4b4ce5, 0x2d2d2208, 0x0c61591c, 0x54ff0027, 0xeafe133b, 0x4bdc838b, 0xe38309cd, 0x73822020, 0x94014922, 0x53417383, + 0x33202112, 0x5b05d34c, 0xb1200813, 0x270fe043, 0x3d5a0f01, 0x94d9fe15, 0x5541ec86, 0x349d2311, 0x534147d7, 0x0029280a, 0x013f02a2, 0x465700d5, + 0x3b4c06db, 0x0ae76e09, 0x21101548, 0x52182322, 0x15201aad, 0x210e4359, 0xfe821bba, 0x0e083e08, 0x190f080e, 0x04010f1a, 0x0b090805, 0x241e0e0b, + 0x14162b23, 0x10111214, 0x0b0f0e0f, 0x0408080b, 0x03193203, 0x06050602, 0x09070807, 0x0d0c0c08, 0x171a0f0d, 0x080b1317, 0x02030307, 0x0b8c4c01, + 0x19a21e29, 0x08192b2b, 0x84080e0d, 0x032408c7, 0x11141315, 0x0d100f12, 0x040e0d1b, 0x0a070704, 0x100d0d0a, 0x1211110f, 0x0c0d1411, 0x0a0b0c0c, + 0x0607090a, 0x03295782, 0x11090a03, 0x0c0b0c0a, 0x2102820d, 0x3b840407, 0x080d0e22, 0x00224b83, 0x07410001, 0x454f2007, 0x16240a9b, 0x34171617, + 0x210b314a, 0x354a2627, 0x2322210a, 0x2008e147, 0x15721837, 0x8e17200c, 0x850125ff, 0x1b2d2d1c, 0x2307415c, 0x03040202, 0x2608a482, 0x0b0a0a09, + 0x0e0c0c0b, 0x1118171b, 0x33090913, 0x0e070719, 0x1712120d, 0x1d191a17, 0x1d24242a, 0x080b0c0f, 0x82050408, 0x0f1922f8, 0x24ea8209, 0x1c2d2d1b, + 0x23f88e1f, 0x0a0d0e11, 0x0a25dd82, 0x04070708, 0x2ede8305, 0x15161312, 0x17181a1a, 0x11111516, 0x82060d0c, 0x0e1b2851, 0x11121010, 0x8e141313, + 0x000025f0, 0x19000200, 0x4f270482, 0x0700ee01, 0x78002b00, 0x6e1808d7, 0x795a0823, 0x0119271a, 0x57fe8ea8, 0x7f5a2d01, 0xc801271c, 0x091d0a1c, + 0x875a38fe, 0x0002221f, 0x26878221, 0x00460248, 0x844f0027, 0x0f9b5287, 0x54056379, 0x0d470f11, 0x23202107, 0x42074b5a, 0x418309bb, 0x2506b95a, + 0x1b153d21, 0xd9442d2d, 0x0d012208, 0x08c7505a, 0x2d1c0927, 0x013e1b2d, 0x08825d2f, 0x5059f321, 0x3d230d08, 0x82143e15, 0x0d012923, 0x2e5b4eeb, + 0x1a2a2b1a, 0x3207215d, 0x170e133a, 0x0e070e18, 0x2b1a080e, 0x23671a2b, 0x5c08f3fe, 0x39210699, 0x0b494414, 0xea226722, 0x19273982, 0x00002c2b, + 0x82000100, 0x3c022505, 0x6300de01, 0x0ddf4c18, 0x4705a77e, 0xcf760607, 0x0b1f4a0e, 0x410c8942, 0x9518179d, 0x012f0a07, 0x18181789, 0x18181a1a, + 0x14141717, 0x82132511, 0x0e253d00, 0x191e0708, 0x0c0c0c0d, 0x0d0d0c19, 0x1110100f, 0x1e1f2312, 0x09090b19, 0x03030707, 0x08056a78, 0x05040b21, + 0x102f0305, 0x06090905, 0x264b339b, 0x03040403, 0x090e0d13, 0x1305040a, 0x13122512, 0x82091214, 0x04270820, 0x0c0c0a09, 0x2b2a2211, 0x292a2f32, + 0x07070d24, 0x1b1c181b, 0x1d1d2221, 0x09080b17, 0x03030606, 0x0b170c0b, 0x820f0c0d, 0x82112000, 0x10102465, 0x83080d0c, 0x1b502949, 0x08054181, + 0x0f2d0509, 0x112e0d83, 0x16151314, 0x32171616, 0x11222a2b, 0x23410c0c, 0x7379181e, 0x2322230c, 0xd1503534, 0x09b17805, 0x18063b48, 0x7313f395, + 0xa353074f, 0x4e152007, 0x01380633, 0x181817a2, 0x18171b1a, 0x14141717, 0x0e0d1112, 0x05050a0a, 0x04251312, 0x3808f582, 0x458a1c56, 0x06090905, + 0x05031030, 0x090b0305, 0x04070709, 0x07030303, 0x0c090807, 0x231e1f18, 0x0f111013, 0x0b0d0e0f, 0x0c0c0c1a, 0x070f1a0d, 0x12251e08, 0x25121313, + 0x41498211, 0x10210923, 0x26e38213, 0x311a1617, 0x82232a29, 0x2d032b54, 0x0809050f, 0x47309205, 0x0e820324, 0x0c0d0825, 0x82111010, 0x820f2002, + 0x0d0c2600, 0x0b0c170b, 0x05f47f03, 0x1d1d172f, 0x1c1b2122, 0x07070e18, 0x2a29241a, 0x0a23412f, 0xe1002128, 0xa4014802, 0xf75a1300, 0x0c2f6108, + 0x23612120, 0x6e4b290c, 0x27e162fe, 0x2b2b1913, 0x20083d5f, 0x4c38823a, 0x2e2009d7, 0xbf474784, 0x116f6105, 0x8a9d0125, 0x4b93dafe, 0x2b210b73, + 0x08ed570e, 0x01010023, 0x0657610b, 0x21215282, 0x06914110, 0x210c4b61, 0x3f611529, 0x8184210d, 0x20143361, 0x2247828e, 0x8305025d, 0x109f618b, + 0x21109361, 0x87610f2e, 0x7cfe230f, 0x00820081, 0x41000121, 0x71610d1b, 0x2120240f, 0x4a932501, 0xfe220bf3, 0x6057e162, 0x2b1a2509, 0x0f2b192b, + 0x6c244787, 0x2e014802, 0xc3618f83, 0x1514210e, 0x270db761, 0x9d016eb6, 0x2d2d1c8a, 0x23088e4e, 0x1326133a, 0x47844a82, 0x61101f41, 0x0b200f93, + 0x230d8761, 0x8184012e, 0x24147b61, 0x010000a4, 0x061f4173, 0x2211e761, 0x41350122, 0x15210c65, 0x0fcf612e, 0x45051f41, 0x1c24076b, 0x3f001f00, + 0x620ae946, 0x0520169d, 0x4211d549, 0xe74f0c21, 0xb6fe2209, 0x0e59416e, 0x2d2d1c24, 0x9d48e0fe, 0x6e4b2110, 0x20094d42, 0x0a4d45e3, 0x0e18182c, + 0x080d0e07, 0x1a2b2b1a, 0x05820c19, 0xb848fd20, 0x08a74111, 0x00000025, 0x82160002, 0x02532204, 0x20c78505, 0x1ed16333, 0x2308dd60, 0x17161716, + 0x22121963, 0x47190f92, 0x1b210965, 0x47b5830e, 0x3d2107ae, 0x0d3463f2, 0x1b832983, 0x2e2e1b24, 0x0c641f1a, 0x0f82411d, 0x410e5263, 0xfd640e8b, + 0x6417201f, 0xc3521e49, 0x41012010, 0xfb200b6b, 0x4108e346, 0xe32013a8, 0x46087741, 0x93410be1, 0x46eb2005, 0x192615d9, 0x2c2b190d, 0xbb470100, + 0x001c2406, 0x4a000037, 0x37420aaf, 0x4207201e, 0xb9840c45, 0x1f1f1323, 0x44038313, 0x7b440fbb, 0x190f2305, 0xcf8c1018, 0x29051e42, 0x111e1d12, + 0x121e1e12, 0xc0830c19, 0x230d4e42, 0x0d18170e, 0x820b3242, 0x073342ab, 0x3142ab83, 0x05656313, 0x230b6748, 0x23221510, 0x0d822989, 0x230e2942, + 0x12202012, 0x1424b582, 0x2e1a0e1b, 0x23079766, 0x153d0f19, 0x2e66af83, 0x1d122313, 0x0383121d, 0x420e0245, 0x44660647, 0x0c574109, 0x4308eb4c, + 0x0d8d0da5, 0x23050f5f, 0x07060706, 0x41135b66, 0x102308f4, 0x430f1918, 0x142a11ab, 0x14141f1e, 0x1c141e1f, 0xed412d2d, 0x4191830d, 0x9d430544, + 0x1e122709, 0x1e11121e, 0x0142121d, 0x41002005, 0x9b440e57, 0x09354d11, 0x2010314d, 0x99451823, 0x4ba72008, 0x0d250522, 0x19190f09, 0x0512450f, + 0x4305a466, 0x1c290b6f, 0x1f1f140d, 0x20201213, 0x0c4c4d12, 0x6609ae66, 0x122315bc, 0x83111e1d, 0x00002fb0, 0x21000200, 0x48021f00, 0x1300f101, + 0xc1782700, 0x0c3d4708, 0x67430120, 0x1514240d, 0x47060706, 0x01211151, 0x0b50430c, 0x828a9d21, 0x2e0123be, 0x234a1327, 0xf1fe250d, 0x080d0e07, + 0x0d279482, 0x1327133a, 0x922b2b19, 0x10a1467f, 0x89471320, 0x11b54612, 0x2e1b0824, 0x9b471b2d, 0x2e01210c, 0x260aa841, 0x2b1a2b2a, 0x82f1fe0f, + 0x2c192b72, 0x0d14390e, 0x080e1818, 0x6b570e0d, 0x00a42409, 0x54550045, 0x175a16cd, 0x64232010, 0x27201eaf, 0x2005a752, 0x22278422, 0x44161716, + 0x07350c89, 0x8c080c0c, 0x0e0e0846, 0x0f0f0907, 0x08080509, 0x65205d05, 0x2d0f8233, 0x94319409, 0x0e0e074a, 0x0e0f0908, 0x1782060a, 0x08264c25, + 0x82070c0c, 0x792c2f19, 0x0d0e083d, 0x074b9709, 0x08080d0d, 0x38570d0d, 0x0c07270e, 0x180f070b, 0x33820f19, 0x0f0a063c, 0x0a1d0a10, 0x0f18170f, + 0x190e0a1d, 0x08050e18, 0x10090509, 0x0b070910, 0xf082060c, 0x180f6e28, 0x0c070f17, 0x8582070d, 0x58030021, 0xbb240667, 0x63005300, 0x8d186958, + 0x1e7153fd, 0x420a4f51, 0x0b410643, 0x4117200f, 0x4c18051b, 0x1b4108d1, 0x21413710, 0x04070704, 0x0d17160d, 0x04060604, 0x0b081934, 0x0e09080c, + 0x006a080e, 0x081c3806, 0x08090e0e, 0x4c080b0c, 0x05040326, 0x15160d03, 0x0404030e, 0x41152a03, 0x4b27072b, 0x05060325, 0x412b5603, 0xc12c062b, + 0x0d083060, 0x0c08080c, 0x2a55080d, 0x3b411982, 0x20132312, 0x4b831320, 0x1c1b1029, 0x0c0b0710, 0x690d0807, 0x06270f47, 0x0d070b0c, 0x830d1817, + 0x130b2369, 0x4d410a13, 0x07072b12, 0x07070c0c, 0x0f070c0d, 0x73581817, 0x0b57420a, 0x4b0d4566, 0x5d4105af, 0x4137202c, 0xb3200e3b, 0x3a064142, + 0x651f5e06, 0x0e0e0932, 0x94319308, 0x0e0d084a, 0x0e0f0908, 0x08080509, 0x41264c06, 0x8c27173d, 0x0e0e0746, 0x414b963d, 0x793a071b, 0x0e0d093c, + 0x0908056c, 0x0f100a05, 0x0f091e0a, 0x1d0f1718, 0x18180f0a, 0x4782060f, 0x41064142, 0x0e231619, 0x8b671919, 0x099b63fd, 0x51432d20, 0x05eb4614, + 0x46079945, 0xf14611f9, 0x26538207, 0x642c0108, 0x4193dafe, 0x072606cb, 0xfe6e4b01, 0xe94185f5, 0x12c94106, 0x420a1d21, 0x072006db, 0xf1420982, + 0x00002105, 0x820a8b5e, 0x5f33208f, 0xdd461b77, 0x07834505, 0xe2200d82, 0xf86c8383, 0x0b082511, 0x0a1f080c, 0x03839583, 0x7dfa1e26, 0x070b0c07, + 0x290f016d, 0x070c0b07, 0x015ee7fe, 0x94848a14, 0x0d820d20, 0x61070f6d, 0x8f82072f, 0x610e4b4b, 0xcb460739, 0x055f4a16, 0x0b0c0829, 0x64d5fe08, + 0x41932501, 0xfe2507be, 0x0a016eb6, 0x0eec4185, 0x0e076c25, 0x8206080d, 0x091e2199, 0x21079e41, 0xe0420a1d, 0x0e1f4110, 0x4a0cab5f, 0x16230519, + 0x83171617, 0x510d8397, 0x416d0fc9, 0x0c082908, 0x0a1f070c, 0x070d0d08, 0x09820383, 0x4b6da382, 0x307c8310, 0xfe5e1901, 0x0d068aec, 0x0c06060c, + 0x3701060d, 0x053d4167, 0x5b0af453, 0xa42407af, 0x4b003700, 0x54144142, 0x794412db, 0x08694418, 0x89450720, 0x52a62113, 0x440e3441, 0xa521085f, + 0x06674253, 0x6edc2c22, 0x21076641, 0x81456edc, 0x10584119, 0x7e411920, 0x072d4407, 0x20078441, 0x067f4507, 0x8f6d0220, 0x41e7820a, 0xa5420c79, + 0x0e83411b, 0x82363721, 0x05cd6401, 0x06070625, 0x82151407, 0x09d96ee7, 0xc442c483, 0x41082019, 0x0a240ba5, 0x070d0d08, 0x8207d442, 0x07ae4b0b, + 0x0722bf82, 0xe2424e9b, 0x41198517, 0x422607be, 0x060d0c06, 0xe28468cf, 0x070c0d28, 0x0d0668cf, 0x0082000c, 0x4e00012d, 0x1b02e4ff, 0x3b009701, + 0x5b050000, 0x262105a1, 0x17b35127, 0x41072f4f, 0xd18405bb, 0x4f461720, 0xa7013306, 0x1b181813, 0x23343332, 0x0905102f, 0x339b0509, 0x11871225, + 0x0f820620, 0x2107ef6d, 0x8b530f2b, 0x2b158207, 0x1617121c, 0x31312f1a, 0x810e2821, 0x2306fa6d, 0x19171711, 0x202c1182, 0x06080905, 0x1c191a13, + 0x23363634, 0x19204982, 0x15820985, 0x8c000021, 0x086d4cb3, 0x18056d41, 0x6909a953, 0x83510bb9, 0x86c22016, 0x371d2698, 0x26263939, 0x21988513, + 0xbe83263a, 0x3434222a, 0x18191a32, 0x890e2912, 0x83065a51, 0x181b2711, 0x08061c18, 0x29540509, 0x0e292107, 0x36210985, 0x27158324, 0x2f313120, + 0x11171719, 0x22070c69, 0x82211224, 0x161a2211, 0x05674117, 0x02000029, 0x00b2011b, 0x6e00003b, 0x32211853, 0xd7551833, 0x176b6e09, 0x12263022, + 0x19218a85, 0x21a88312, 0x776e3a26, 0x0e2b2905, 0x37393926, 0x141b1b1d, 0x062a1582, 0x1b181812, 0x22343432, 0xe2831030, 0x0e2d9a26, 0x2f303121, + 0x12218982, 0x6ebd8205, 0x2521070c, 0x24098213, 0x19191c33, 0x41158314, 0x27210778, 0x09976e0d, 0xb3894e20, 0x5406334d, 0x1f4707f1, 0x05dd420b, + 0x8f050347, 0x212f8317, 0x92826a22, 0x102f052a, 0x32333423, 0x1318181b, 0x06200d82, 0x2305af6e, 0x1327151a, 0xb6850985, 0xb6861320, 0x9a0e2922, + 0x2905c56e, 0x31201223, 0x17193031, 0x0f821117, 0x36240523, 0x21ae8336, 0x506f2a13, 0x27158308, 0x1a161712, 0x2131302f, 0x200edb6e, 0x10a1442b, + 0x4609df46, 0xb15509db, 0x0fef7105, 0x5a0f013b, 0x0b86f4fe, 0x010b1312, 0xccfe7459, 0x12130b99, 0x652d010b, 0x0e0878f1, 0x0ede460e, 0x0b0a1d27, + 0x1d0a1211, 0x25058209, 0x08091d0b, 0xaf520e0d, 0x00a42109, 0x25248382, 0x27262726, 0x23053546, 0x37363736, 0x56093f46, 0xf55a050d, 0x0545460c, + 0x5af2fe2f, 0x0c860b01, 0xfe0c1212, 0x330173a6, 0x2309849a, 0x78f064d3, 0x240a6d49, 0x0d0e076c, 0x25748208, 0x1c0b1112, 0x05820a0a, 0x490a1d21, + 0x00200c1d, 0x2009eb47, 0x10074151, 0x4605254b, 0x078f073d, 0x077b7a18, 0x8b076d47, 0x19ad6407, 0x05162b2c, 0x0d060909, 0x0e0e1818, 0x03821718, + 0x172c0782, 0x09050e18, 0x040d050a, 0x080f0e09, 0x0e23158b, 0x820d1818, 0x200922cb, 0x19215f10, 0x0a0a062b, 0x1a191006, 0x191a0f0f, 0x83078710, + 0x1a332713, 0x09101009, 0x19831a0f, 0x13830389, 0x730dbf5e, 0xfb8205ff, 0x4408c747, 0xd5930519, 0x0b574e18, 0x4b110d41, 0xa5411059, 0x23ba8305, + 0x0f081020, 0x2005db59, 0x23ec820e, 0x0d18190d, 0xee83e683, 0x06050b25, 0x84060909, 0x19182115, 0x9e821584, 0x82050e21, 0x152b2113, 0x530ec95e, + 0xd897088d, 0x41133a21, 0xc75e170c, 0x4c002010, 0xa426083b, 0x27001f00, 0xfb412f00, 0x15142116, 0x6808c941, 0x2220067b, 0x2006af5b, 0x0cf74b22, + 0x6123aa83, 0x412b5620, 0x942706a7, 0x84461746, 0x43461846, 0x7b4f0e02, 0x080d2608, 0x3a6e0e0d, 0x83018513, 0x07f3678b, 0x01208b86, 0x181d3d47, + 0x20082d74, 0x053b5c07, 0x231ddf76, 0x3d143e15, 0x01230383, 0x67295124, 0x5c2717c8, 0x1642931e, 0x83911642, 0x121b4104, 0x590a1b42, 0x14250f99, + 0x06070615, 0x41878625, 0xf941071b, 0x20612309, 0xc7412b56, 0x4ffe280e, 0x84471846, 0x6d461846, 0x1a201210, 0x2007fd75, 0x091d415c, 0x270b1f41, + 0x000f0007, 0x0100002f, 0xff876f86, 0x0b761120, 0x0f6d5a0d, 0x0b012222, 0x53060341, 0xcc5d0df9, 0x2d2e3008, 0xae011f1b, 0x16411641, 0x42164292, + 0x53e4fe16, 0x5c210be8, 0x0537411e, 0x6a13db6c, 0x9f440993, 0x07062307, 0xdd5a0706, 0x5a212014, 0x6c241fb5, 0x2d5c4eea, 0x610dd457, 0x67210ba5, + 0x0dfb6b22, 0x4a0c774b, 0x1d410d4f, 0x05e77506, 0x50640121, 0x0c5b08d7, 0x16874116, 0x2f05e95a, 0x002b2b1a, 0x000c0002, 0x01480258, 0x001900b7, + 0x48072d46, 0x14210b35, 0x05274615, 0x34271425, 0x82332035, 0x08798503, 0x17160725, 0x100dc716, 0x23211110, 0x23171722, 0x10112122, 0x20010d10, + 0x60dffe61, 0x61240127, 0x1361dcfe, 0x82131e1e, 0x0c583703, 0x1f100f0f, 0x16152021, 0x111f2120, 0x470b0f0f, 0x47287918, 0x0782213c, 0x110e1e29, + 0x11111d1d, 0x82001d1c, 0x00022800, 0x0100007a, 0x851902ef, 0x10332487, 0x62232235, 0x6f820b55, 0x23221727, 0x27221510, 0x082d6132, 0x2b05c345, + 0x2143de10, 0x1210100c, 0x16232221, 0x20212282, 0x27898212, 0x0881194c, 0x101f194d, 0x13298082, 0x121f1e12, 0x0f010b23, 0x2789825a, 0x20201f11, + 0x20201616, 0x0c278983, 0x215af1fe, 0x185b1201, 0x2107f969, 0x8785eefe, 0x58002124, 0x0f415c02, 0x85252007, 0x66f983f1, 0xb75a0737, 0x83372006, + 0x2726279d, 0x15142726, 0x03822320, 0x01143323, 0x26fd82a2, 0x16602101, 0x82212223, 0x860c2084, 0x831b2007, 0x1f123280, 0xdcfe121e, 0x62230161, + 0x79184758, 0x151f4028, 0x2b848521, 0x1f212015, 0x480f0f10, 0x111c1d11, 0x11258982, 0x18470b21, 0x110f4121, 0x087d5618, 0x1023fd85, 0x86333215, + 0x83272087, 0x817f1887, 0x82232008, 0x340121a5, 0x37070e41, 0x2b81194b, 0x100d2243, 0x23201210, 0x1e131722, 0x0c23131e, 0x0f1f1a4c, 0x0c318d82, + 0x1f100f0f, 0x01152120, 0xf0fe5b0f, 0x0f0f0b5a, 0x200d8211, 0x2985831a, 0xfe5c1201, 0x1c115cee, 0x9341001d, 0x00212809, 0x3300003b, 0x82323534, + 0x13974103, 0x8f821420, 0x20151423, 0x441f8527, 0x89520747, 0x7a142309, 0xa541194b, 0x194c2813, 0xe33ae8fe, 0x411a4b4c, 0x4b250baa, 0xac216319, + 0x0fad4139, 0x6339ac28, 0x10312121, 0xaf414be1, 0x4be12607, 0x00000031, 0x08374203, 0x2b002124, 0xa5a34700, 0x09bd5e18, 0xaf8d0320, 0x25051d47, + 0x15143332, 0xb19b2322, 0x18303926, 0x070b0b07, 0x7a200382, 0x072bbb85, 0x50070c0c, 0x0b0c0728, 0x990b2307, 0xc90125bd, 0x060a0a06, 0xfe210382, + 0x27c78352, 0x060b0c06, 0x060c0b06, 0x3122c791, 0xc7a34100, 0x59322721, 0xb1860649, 0xcd8d1720, 0x73411020, 0x2264251b, 0x0f191810, 0xa926ad83, + 0x1a4b2264, 0x0e83101f, 0x26187641, 0x0e932501, 0x820e1817, 0x831020a9, 0x180e25b9, 0xb6fe0e17, 0x240b7b41, 0x00390025, 0x42b3844b, 0x2342051d, + 0x05c14313, 0x18151421, 0x18076f6e, 0x200c6d6e, 0x44bb8313, 0x354205e9, 0x43de2606, 0x20201221, 0x11354212, 0x1322432f, 0x4c141f1f, 0x21368119, + 0x0f0f0911, 0x21038308, 0xe9431122, 0x431c2006, 0xc8250df5, 0x1e1d1243, 0x0f4a4211, 0x1d1e112f, 0x0143c812, 0x0e0d098e, 0x0d0e0808, 0x06514209, + 0xcb82fe2d, 0x1c1d1144, 0x1d1c1111, 0x4200cb11, 0x2d220c5b, 0x57184100, 0x34200807, 0x9b069944, 0x333225e3, 0x03201514, 0x8c050d4c, 0x0e7142e7, + 0x9d0f2143, 0x194c24f1, 0x9204e8fe, 0x434820f4, 0x65211341, 0x23fa9722, 0x21632265, 0x3123fc92, 0x87339b10, 0x349a22fe, 0x21ff8231, 0x0b450002, + 0x00212507, 0x3700003b, 0x20056351, 0x31741832, 0x44172009, 0x07280683, 0x23223534, 0x35221514, 0x5005c541, 0x1b450503, 0x05ab7205, 0x69211425, + 0x453db823, 0x0c270e18, 0x35693db8, 0x4550ef11, 0xef29071f, 0x58113550, 0x47580701, 0x101e4518, 0x18470c29, 0x47211847, 0x450f1d18, 0x48220927, + 0xa384d718, 0x0000232f, 0x02024602, 0x2f000b00, 0x10330000, 0x05af4635, 0x22151022, 0x4f083345, 0x232c1ac9, 0xfe899a01, 0x011c7f81, 0x1a1b14df, + 0x20059d7d, 0x05b94f0f, 0x26264c34, 0x1e37393a, 0x0b151b1a, 0x82011213, 0xfe091980, 0x1d637898, 0x07474e11, 0x11110a25, 0x87000200, 0x8323208b, + 0x4537208b, 0xc1480707, 0x05a5640b, 0x22075f4c, 0x82340722, 0x351027af, 0x15103332, 0x7282e820, 0x3839392a, 0x141b1b1d, 0x0b12120b, 0x2206894f, + 0x82102f25, 0x9a062c90, 0x807e01f9, 0x66fe0a1b, 0x840f2c6c, 0x191a2273, 0x20738213, 0x29918e0a, 0x091a6c05, 0xfe786701, 0x4346817f, 0x002b230c, + 0x5c180047, 0xc54509c1, 0x0d55461b, 0x4611c945, 0x9e430e5f, 0x194c2111, 0x450f7146, 0x7b460bdb, 0x2e8c210c, 0x210f9943, 0x89462f8b, 0x41c3210b, + 0x20069943, 0x21098211, 0xd74b1d1c, 0x005b240a, 0x6b870073, 0x07190c97, 0x272012c9, 0x09317318, 0x201a1d67, 0x099f4317, 0x200c874e, 0x058d4425, + 0x2008137b, 0x067f7023, 0x07357518, 0x53853720, 0x82232221, 0x09134b3f, 0x284f3f08, 0x08060503, 0x0e0c0b09, 0x1411110e, 0x0d111113, 0x070b0b0e, + 0x03060608, 0x12230d28, 0x09050603, 0x0e0b0b08, 0x1311110d, 0x0c0e0e0f, 0x090c0b0d, 0x04030405, 0x04030304, 0x01010102, 0x4f4b284f, 0x6fc0240f, + 0x83020425, 0x06063700, 0x09070707, 0x0e120909, 0x04050c0f, 0x0e0b0c03, 0x1011120e, 0x666d0e0f, 0x31622405, 0x49030305, 0x0a2f08eb, 0x0a0b0b0a, + 0x06070909, 0x04040405, 0x84090706, 0x3a0a220f, 0x21158213, 0x17820b0b, 0x6d820820, 0x05050330, 0x030a0807, 0x05050405, 0x02080606, 0x62670303, + 0x0b5d5805, 0x0306a930, 0x02020103, 0x03050406, 0x06010203, 0x4d820c06, 0x820b6321, 0x0c05212e, 0x02211682, 0x5f198307, 0x515c10db, 0x07062419, + 0x5f220706, 0x595c1ffb, 0x0e092912, 0x2d1b080e, 0xd31f1b2e, 0x5d0de374, 0xbd5f0cc3, 0x1df95f1d, 0x0001002c, 0x0288ff21, 0x00870248, 0xff53004f, + 0x0da55005, 0xcd5d0d9f, 0x2bd75d12, 0x5d1de55d, 0x78200aed, 0x250ac07b, 0x0d0e1817, 0xdc631818, 0x0e0e2105, 0x39200d82, 0x6c08797a, 0x12290500, + 0x12121d1d, 0x1a111e1e, 0x2005830c, 0x06025e12, 0x77002b21, 0x1b4f0c77, 0x05654c17, 0x093d7b18, 0x2b1b6f78, 0x143e2b83, 0x2e8b2e8b, 0x3a74153d, + 0x4f06234f, 0x5827121b, 0x3a1e581e, 0x781d5813, 0xf34c0a76, 0x1887830a, 0x500f2b74, 0x45571073, 0x15142b0a, 0x2e8ad922, 0x143e2e8a, 0x32433a74, + 0x08bd700e, 0x3d2c8225, 0x821d586c, 0x50798273, 0x192a1024, 0x080d0e07, 0x0e18180d, 0xab521d58, 0x5047200b, 0x9b78162b, 0x10c57421, 0x23104350, + 0x143e1f5d, 0x241ac26f, 0x52153d1f, 0x1d3f412a, 0x5741c59b, 0x9e3f2015, 0x13e741cf, 0x940e8d75, 0x0f2b2bc7, 0x1847143e, 0x143e1847, 0xb7a10f2b, + 0x4109fb41, 0xa78317ff, 0x410fff41, 0xb3822b73, 0x17477f28, 0x153d1846, 0x65410e2c, 0x4221821f, 0x99830817, 0x421d5541, 0x776d0d1f, 0x0ff97107, + 0xb3aeab87, 0x291cc77b, 0x1132153f, 0x11320715, 0xe1421c38, 0x153f2317, 0x21851033, 0xa31d3742, 0x0b3f42e5, 0x200b1350, 0x06414223, 0x5d171350, + 0x0b500629, 0x17055017, 0x3a226727, 0x7a326713, 0x0801503d, 0x21096b4a, 0x73820019, 0x4f23774f, 0x1721076f, 0x056f4f22, 0x6f4f0786, 0x83582008, + 0x2d5c2164, 0x2417694f, 0x00030089, 0x06eb4f0c, 0x35002b23, 0x072b4300, 0xed4ae98d, 0x53272018, 0x162305c7, 0x50051617, 0x05410809, 0x37a42110, + 0x0c239c8e, 0x412736a5, 0x01210613, 0x07f84a3c, 0x21102351, 0xb6902267, 0x22670c22, 0x200a2f41, 0x07064b11, 0x18008921, 0x2609f3b0, 0x1f00bd02, + 0x65003100, 0xc58305d9, 0x4c05716b, 0x2f500585, 0x18072008, 0x18090199, 0x0808cd7b, 0x140ff765, 0x2a291514, 0x23461c2a, 0x0a11110a, 0x120a57ae, + 0x23450a12, 0x282a2a1c, 0x0f131416, 0x09071e5c, 0x13130a0a, 0x478e0d14, 0x1314130d, 0x2e09090a, 0x7d433c3c, 0x22558181, 0x23233839, 0x55223938, + 0x437d8181, 0x542e3c3c, 0x221e1f18, 0x2c414240, 0x4042412c, 0x001f1e22, 0xff3a0001, 0x022e02f3, 0x6d5700cb, 0x75181647, 0x17200e79, 0x0d756e18, + 0x1806c36f, 0x180c59c5, 0x080d4b9e, 0x0607063a, 0x1916a601, 0x313f1f1a, 0x0d112130, 0x0408070d, 0x21101105, 0x40313021, 0x161a1a20, 0x0e111115, + 0x080b0b0d, 0x04050607, 0x05052144, 0x0c080706, 0x110f0f0c, 0x274e1512, 0x4e270082, 0x0f111215, 0x830c0c0f, 0x4305241f, 0x82060422, 0x0b26081f, + 0x110e0d0b, 0x050a0612, 0x2f171704, 0x221c1d18, 0x2c262721, 0x2f444459, 0x0518182e, 0x0d0a0a06, 0x1010100d, 0x01821211, 0x0e121024, 0x5f820d0f, + 0x04090a39, 0x91484805, 0x05494890, 0x0e090905, 0x0f0d110d, 0x12111110, 0x82131212, 0x0c0f2f29, 0x0200000d, 0xf5ff5f00, 0x6f020b02, 0x621a8700, + 0x65181fe9, 0x17200f59, 0x6a18ef83, 0x342107e3, 0x0ce37037, 0x0ee36a18, 0x77180620, 0x67180b37, 0x4f8f074b, 0x20074d6d, 0xf5a61807, 0x05377116, + 0x78262321, 0xa36d09bd, 0x74012507, 0x1b191917, 0x102ff783, 0x190d0f0f, 0x04030d0c, 0x0a0b0607, 0x82100e0e, 0x121327eb, 0x14141813, 0x00830710, + 0x06050625, 0x82010202, 0x85012002, 0x02022a00, 0x09050304, 0x09110e0e, 0x261e8208, 0x08090908, 0x83060808, 0x03022400, 0x82040503, 0x05300801, + 0x02020303, 0x07060505, 0x16151109, 0x23242d1b, 0x0a0a0d1b, 0x03030707, 0x0a0a0504, 0x11100d0d, 0x0bb91414, 0x1c140f0f, 0x12101717, 0x02010809, + 0x05215182, 0x08118305, 0x0a04042c, 0x0f0b140f, 0x09080c0b, 0x01010304, 0x04040304, 0x07060d0f, 0x06060303, 0x190c0a0a, 0x15292021, 0x14141413, + 0x10101211, 0x51830c0b, 0xb5823682, 0x0a080823, 0x2062820b, 0x2200850a, 0x830a0909, 0x0d102b99, 0x0b0b0c0e, 0x080f090a, 0x99830207, 0x06070526, + 0x04040505, 0x0229c784, 0x06060401, 0x07060707, 0x08058308, 0x050c0527, 0x24121306, 0x18161512, 0x201d1d19, 0x21242427, 0x181c1d21, 0x0f141418, + 0x1007070f, 0x271e1e0f, 0x0e102d26, 0x214c820d, 0x1182060a, 0x07022208, 0x140e0c09, 0x1b191914, 0x0d111d1b, 0x090b0b0d, 0x01000008, 0x00005900, + 0xbd020e02, 0x00001700, 0x095f5533, 0x2b076755, 0x15103320, 0x04015920, 0x57fdfe56, 0x48270586, 0x3cb8fe6d, 0x833aad14, 0x143b2403, 0x50aff2fd, + 0x592205a7, 0x4782d4ff, 0x3b00ea29, 0x57004900, 0x63170000, 0x0d9b0dcd, 0x20051744, 0x52698232, 0x222105fd, 0x051d4e13, 0xfd410620, 0x06af5005, + 0x79390d86, 0x02050402, 0x172e0b22, 0x0c0d0d08, 0x04060607, 0x366c2367, 0x0d0c0d08, 0x310b8206, 0x55aa3aac, 0x02040502, 0x05021a34, 0x1a4f0205, + 0x078369d1, 0x50bd3a31, 0x040d191a, 0x0c070606, 0x95650d0c, 0x832c5732, 0x0606313b, 0x0e082c06, 0x143c080e, 0x292b2a1c, 0x0f141416, 0x2b210982, + 0x2409822a, 0x143b1013, 0x82198209, 0x8209201d, 0x2f0682de, 0xadb30108, 0x1413103a, 0x2b2a2916, 0x3aadadfe, 0xf8823186, 0x2500032e, 0x45022e00, + 0x4b002d02, 0xb3007f00, 0x180a1375, 0x20169754, 0x0bc95717, 0x129f7618, 0x08274a18, 0x7018ef82, 0x054e0c85, 0x09517408, 0x21051f41, 0xbf700607, + 0x0e1b4e0b, 0x7505b743, 0xa54e0b7b, 0x8607200a, 0x562f087f, 0x090f1009, 0x0b12120b, 0x09090a0b, 0x14040408, 0x2f282714, 0x181c372f, 0x11141417, + 0x110f0f11, 0x0f0a0a11, 0x130b0a0f, 0x090c0b13, 0x8409080a, 0x15132a21, 0x1a181716, 0x171b1d1b, 0x3d258318, 0x11110e0e, 0x16162531, 0x0f0e0c1c, + 0x1a1b1412, 0x04040523, 0x06050405, 0x13121205, 0x00821314, 0x10101230, 0x0b0b0f0f, 0x03030707, 0x02070403, 0x07820202, 0x12590324, 0x1d821213, + 0x12121426, 0x0e0f1011, 0x06211d82, 0x20008204, 0x211d8606, 0x4f832403, 0x130e0f26, 0x221b1a14, 0x05204e82, 0x2e3f0082, 0x080f0f09, 0x0a11120a, + 0x1310100e, 0x19171613, 0x252d2d34, 0x04131226, 0x09090804, 0x820e0a09, 0x820820a7, 0x820b2021, 0x110d24b3, 0x86121310, 0x0d122521, 0x050a0a0d, + 0x08349382, 0x0a0a0907, 0x8b10100d, 0x1a151521, 0x110e0d0c, 0x21191913, 0x02268a82, 0x02020302, 0x9b830407, 0x20820720, 0x45100e21, 0x9882053c, + 0xc7831120, 0x46203982, 0x03251d83, 0x0b0a0707, 0x281d820d, 0x12121110, 0x12121312, 0x82e68410, 0x89222022, 0x0420224f, 0x264d8303, 0x00000002, + 0x82fdff02, 0x026d2804, 0x0013009d, 0x58000025, 0x1747084f, 0x17162505, 0x27201716, 0x4109e54f, 0x032b069b, 0x2e30301f, 0x11161619, 0x84202246, + 0x17350809, 0x1d2cfe11, 0x22177bf6, 0x10122022, 0x22160c10, 0x10112122, 0x7b7b5110, 0x3a394077, 0x7b7b522c, 0x393a4076, 0x5a3c512c, 0x2b2e585b, + 0x5b3b202a, 0x2a2f575b, 0x8c7e822b, 0x5119207f, 0x20200a7f, 0x2907bb57, 0x12372207, 0x12232037, 0x74870001, 0xd0a00132, 0x19161711, 0x2030302e, + 0x2f8a1a4e, 0x8a5cebfe, 0x2c2d6987, 0x7740393a, 0x60517b7b, 0xfe7b7101, 0x2a5f838f, 0x00410001, 0x02280200, 0x824500b0, 0x2382185d, 0x0c797308, + 0x36373622, 0x09ffea18, 0x2109d145, 0xd7590607, 0x0a0d7f06, 0x022d2783, 0x224f9d28, 0x1c1d2020, 0x11101817, 0x37008208, 0x17171111, 0x201f1e1d, + 0x9d3bb121, 0x1516174f, 0x0f0e1314, 0x0302040a, 0x37080082, 0x642b0102, 0x0185f6fe, 0x0c080606, 0x13120f10, 0xb1161415, 0x170c0c3b, 0x271f2017, + 0x2e2b2b27, 0x272b2b30, 0x181f2027, 0x3c0b0c17, 0x14090914, 0x1c171813, 0x0c0b0b0a, 0x3c290083, 0x17161814, 0x18192117, 0x20658211, 0x31cc823c, + 0xff410003, 0x032802ad, 0x00570003, 0x007d006b, 0x87491700, 0x0ecb4307, 0x2005cd46, 0x0d9b6833, 0x62151421, 0xb54e09f3, 0x616f1805, 0x16332108, + 0x2722ff87, 0x15822726, 0x45069555, 0xd3510513, 0x85132006, 0x0a0b410d, 0x1910f12e, 0x0a060f19, 0x181e070a, 0x09111117, 0x3e0b0841, 0x08061c39, + 0x1a0f0508, 0x06040f1a, 0x0f2f0406, 0x0d091d3b, 0x06070d0d, 0x28770506, 0x82053d7c, 0x200e8262, 0x2e1b8209, 0x9d3bb106, 0x0c0b0c4f, 0x0908070b, + 0x8732655e, 0x14273b25, 0x1924242e, 0x43060608, 0x0b10100f, 0x02012a54, 0x03020302, 0x0c090503, 0x3d82530c, 0x13054808, 0x17132121, 0x28281f20, + 0x2f2f2b2c, 0x28282a2b, 0x17171f20, 0x1b0f0b0c, 0x07050f1a, 0x120c0407, 0x143c0c12, 0x272a291b, 0x0f131316, 0x140e143c, 0x29271513, 0x01011b29, + 0x0102143c, 0x19191603, 0x2a1bc201, 0x82152829, 0x21212c1d, 0x17171742, 0x312ce9fe, 0x820e2132, 0x820b2088, 0x151a2300, 0x00820015, 0x4100012d, + 0x27024e00, 0x45000d02, 0x42250000, 0x3f420c3b, 0x05635522, 0x3a0f3b42, 0x214f9d27, 0x1d1e1f20, 0x08101717, 0x04040607, 0x08080202, 0x17171111, + 0x42201d1c, 0xb182053f, 0x0d111025, 0x820a0a0e, 0x27013f1d, 0x83fafe62, 0x0a070604, 0x110d0d0a, 0x16141310, 0x074e3bb1, 0x150e0f08, 0x0e0e1a14, + 0x00830e0d, 0x1d1d1f36, 0x14141a1a, 0x07080e0f, 0x0304143c, 0x0a0b0809, 0x0b0c0c0c, 0x0b20ff82, 0x0c200782, 0x21053045, 0x0743003c, 0x3433210c, + 0x0a957118, 0xc5453620, 0x09716206, 0x18064d42, 0x1807475d, 0x4909e141, 0x25080b15, 0x9d412223, 0x1515184f, 0x0f101212, 0x0304030a, 0x02010303, + 0x63d4fe01, 0x02850a01, 0x0a0a0606, 0x13120e0e, 0xb0821515, 0x224f9d25, 0x831d201f, 0x081123f0, 0xec820909, 0x1d171632, 0x221f201d, 0x09143cb1, + 0x18121309, 0x0a091d18, 0x2708aa82, 0x3c0d0c0d, 0x19191814, 0x17171a1a, 0x08091211, 0x0c0b143c, 0x201f1717, 0x2c2b2727, 0x2b2a302e, 0x201f2828, + 0x0c0b1717, 0x220e0743, 0x43810065, 0x78180a07, 0x0d8d0d87, 0x22272622, 0xe546d18a, 0x06232320, 0x055b0607, 0x060b6206, 0x45180320, 0xf7460873, + 0x08514308, 0x1a0fbc2c, 0x07041019, 0x0f2f0406, 0x07821d3a, 0x0e0d0731, 0x2878090d, 0x06053e7b, 0x0d0d0706, 0x8205090e, 0x09eb4208, 0x0f06082d, + 0x06101919, 0x1e060a0b, 0x41111718, 0x393c0d17, 0x0808051d, 0x02295392, 0x08090506, 0x0e0f0b0c, 0x286e0f10, 0x15141714, 0x100f1313, 0x21086941, + 0x65843364, 0x530d0d34, 0x05070705, 0x0c12120b, 0x130f143c, 0x29271613, 0x09841b2a, 0x0808f042, 0x0302013a, 0x11191916, 0x04070605, 0x13212114, + 0x28201f18, 0x302a2b28, 0x282b2b2f, 0x171f1f28, 0x0f0c0b17, 0xc4011b1a, 0x18171818, 0x10141518, 0xfe32312c, 0x120909af, 0x1e181911, 0x86079841, + 0x0d134358, 0x00004123, 0x0f474237, 0x32334342, 0x10141416, 0x0a0d0d10, 0x0407070a, 0x0162d9fe, 0x7c048306, 0x102206f2, 0x3f421414, 0x10163a0a, + 0x08090811, 0x17101009, 0x201c1e16, 0x4eb12220, 0x0404143c, 0x0a090908, 0x2400820c, 0x0c143c0b, 0x3707820b, 0x09080b0a, 0x143c0403, 0x0f0e0807, + 0x1a1a1415, 0x1e1e1c1c, 0x1a1b1b1c, 0x07266483, 0x01000007, 0x04827d00, 0x5b02ec23, 0x330c8200, 0x20351033, 0x20151033, 0x5c13017d, 0xc401edfe, + 0x973cfe97, 0x012de482, 0x33ff4c00, 0xca021d02, 0x00000f00, 0x5e238517, 0x4c36083d, 0x3b755c01, 0x3b4de813, 0xe6b102cd, 0x02e64ffd, 0x7efdd682, + 0x338f00d6, 0x57823220, 0x2907875e, 0x143a4c20, 0x143a4de8, 0x3384a3fe, 0x02d67d24, 0x3982d782, 0x48203382, 0x1f206782, 0x2f206782, 0x2f516782, + 0x61951805, 0x3427210a, 0x81639d82, 0x063d6907, 0x5f610720, 0x48202907, 0x31323321, 0x1218171a, 0x18270784, 0x59011217, 0x477af473, 0x0784078e, + 0x16173008, 0x5e1b0111, 0x1dcd9efe, 0x504f350e, 0x2525294d, 0x4a49311c, 0x23222646, 0x320c211a, 0x46452e11, 0x20212442, 0x4c4b3219, 0x23232749, + 0x8410311b, 0x012c29fb, 0x013c0206, 0x00070056, 0x2b08417d, 0x848c012c, 0x060174fe, 0x143c143c, 0x02282382, 0x00002c00, 0x26023c02, 0x1f202382, + 0x73182589, 0x31530887, 0x2d3d850e, 0xa738a65a, 0xa7153f37, 0x3f38a637, 0x4983d601, 0x742afe2d, 0x75133c27, 0x3b277527, 0x84277414, 0xff33267b, + 0x021c02a7, 0x085782bd, 0x00170026, 0x00333237, 0x01332207, 0x18486227, 0x4763d9fe, 0xc5510259, 0x00c6b0fd, 0x53000100, 0x16025200, 0x3b000902, + 0x08ab5318, 0x7d0b0947, 0xe9430d35, 0x079b6a0f, 0x2215143e, 0x34201801, 0x09061f35, 0x38220509, 0x37222237, 0x09052238, 0x351f0609, 0x0e2b2034, + 0x0d830583, 0x38382223, 0x83038322, 0x3d2d8325, 0x3b76522b, 0x121d1e12, 0x090e0f08, 0x111d1d11, 0x111c1d11, 0x080f0e09, 0x121e1e11, 0x1b832c85, + 0x84111e21, 0x831c201b, 0x841d201b, 0x1d12211b, 0x002d1b83, 0x00960002, 0x01d3019a, 0x002f00c5, 0x19e94f4f, 0x23178b4e, 0x16171627, 0x20073d7d, + 0x06314b35, 0x09f14918, 0x01161731, 0x15141283, 0x14141616, 0x0e0f1112, 0x82050a0a, 0x0b0b3d00, 0x13110e0e, 0x21161414, 0x0c171c1d, 0x05060809, + 0x06050303, 0x0e0f0a0b, 0x10110da5, 0x2305164b, 0x07060707, 0x12272582, 0x11111314, 0x82070e0d, 0x0aad3000, 0x05040405, 0x0c0d0a0a, 0x13131111, + 0x84131615, 0x26518219, 0x160b0c06, 0x820d0c0c, 0x0f0e2200, 0x312f8415, 0x070d380d, 0x0d070606, 0x1210100d, 0x0d101013, 0x0082060d, 0x5b820d20, + 0x10121322, 0x2e06777a, 0x010701f5, 0x00970173, 0x01000017, 0x18222322, 0x2113d7cd, 0xb7186301, 0x01280e5c, 0x06040307, 0x0407264e, 0x07260082, + 0x0406274d, 0x00820003, 0x1e00012b, 0x5002eeff, 0x33001d03, 0x05fb4800, 0x6b0ba567, 0x7f180b07, 0xf54809bb, 0x2264080b, 0x16170ffc, 0x0b0a0c16, + 0x19180f08, 0x0606040f, 0x2d2d1b04, 0x14140e1c, 0x09090b13, 0x2b2b1c08, 0x14141729, 0x1013370f, 0x16161008, 0x2f2e2d18, 0x2f122f1f, 0x25444847, + 0x051a2122, 0x0b050808, 0x090a1313, 0x2a090f0e, 0x213d3f40, 0x55171e1d, 0x437a7f7f, 0x2e2e3b3b, 0x41413110, 0x8b8a8648, 0x0200005b, 0x8224a386, + 0x8d005900, 0x0a616218, 0x0c3bad18, 0x2011c541, 0x06494523, 0x440cd741, 0x72180811, 0x0320139f, 0x2006a547, 0x07cf4227, 0x0132ffa2, 0x21211851, + 0x1010102a, 0x0f0f0d0e, 0x1010120f, 0x01820e0d, 0x13182408, 0x080e0f13, 0x0d070607, 0x1b15150e, 0x0d180819, 0x0718192f, 0x100b0c06, 0x1c191510, + 0x10111e1c, 0x820e0f10, 0x1c232200, 0xb772181c, 0x0b0c2209, 0x304c416d, 0x1009022d, 0x01020807, 0x03040203, 0x5b132505, 0x04200633, 0x08050c52, + 0x0d0c1132, 0x0404090a, 0x0e0e0d26, 0x0a0b0d1d, 0x04040807, 0x270b0606, 0x03030413, 0x01010202, 0x0d0e0807, 0x22171213, 0x0a091516, 0x1c28191a, + 0xd5fd1616, 0x212f9a41, 0x9b410300, 0x007a2606, 0x0027001b, 0x3978185b, 0x0b2d4208, 0x1808cf59, 0x200b816c, 0x326b4113, 0x3191fa3c, 0x20212216, + 0x0c101011, 0x0f2b143d, 0x9a340f2b, 0x19112267, 0x0c0d1919, 0x3a41820b, 0xf2013f30, 0x13261641, 0x2c2d2e1e, 0x11151518, 0x0d273fbe, 0x818b1542, + 0x23241740, 0x10111223, 0x0b4164fd, 0x00022c30, 0x0276005d, 0x00da010b, 0x446f004b, 0x4518198b, 0x23410827, 0x18332006, 0x4a09ab4f, 0x15820bd9, + 0x23412720, 0x0e2f5305, 0x08cfaf18, 0x0b674418, 0x16171425, 0x44103b01, 0x10330559, 0x090d0e10, 0x0a05040a, 0x1b141409, 0x1417211b, 0x82111014, + 0x0b2e0813, 0x13120f0f, 0x0e171514, 0x0d0d0d0e, 0x080b0d0c, 0x06070707, 0x0c050605, 0x140e0d0d, 0x11101212, 0x10131211, 0x0a9c1010, 0x11110f0e, + 0x23820f10, 0x23830c20, 0x00820620, 0x0f2c2383, 0x0c0e0f12, 0x0505060b, 0x060d8f05, 0x0b233782, 0x8210100c, 0x1831084d, 0x1f1f271b, 0x0c0c1919, + 0x0d0e0707, 0x1c1e1616, 0x0f0e1615, 0x162c0708, 0x0e0e0607, 0x131d1615, 0x0a0a0e0e, 0x0c050808, 0x162b0606, 0x0c0b0606, 0x2c238315, 0x080f3a15, + 0x0f070808, 0x1c15150f, 0x20218211, 0x2c21830b, 0x08080605, 0x1515100f, 0x1413191a, 0x2e008200, 0x00140003, 0x01540276, 0x005b00da, 0x18af0087, + 0x4c0d078c, 0xe1450f2d, 0x6c17200f, 0x6d41064d, 0x0e775108, 0x540b7351, 0x61410f91, 0xb94e1813, 0x4625200b, 0x7c180a35, 0x63511319, 0xcd220807, + 0x0a0a0a09, 0x10131315, 0x090d0d10, 0x03060509, 0x07040503, 0x0b0a0a07, 0x0f0e0d0b, 0x0b0c1110, 0x0083090c, 0x00820820, 0x08080733, 0x24231807, + 0x0f0e102f, 0x0c0b0d0d, 0x0807090a, 0x362f8206, 0x14140a0b, 0x151f1a1a, 0x10101213, 0x10131212, 0x09101011, 0x82570a09, 0x1009222d, 0x8229820f, + 0x0707212b, 0x063c9a83, 0x0d0d0b05, 0x0f0f120f, 0x0404050c, 0x01020303, 0x050a0605, 0x16010506, 0x100d0d0c, 0x072b5f84, 0x060b0507, 0x0b050405, + 0x820e0e0b, 0x233c8246, 0x080c0c0c, 0x06253c82, 0x037b0606, 0x41308201, 0x173206d1, 0x1212121a, 0x0e0e1111, 0x090a0b0c, 0x03040606, 0xb8820202, + 0x06070625, 0x820a0809, 0x3a112a64, 0x03041c1d, 0x09090707, 0x2a5b830c, 0x15131310, 0x18202027, 0x410c0c19, 0x1d2706dd, 0x070d1415, 0x82410505, + 0x07082685, 0x15150e0e, 0x0de1411e, 0x47820720, 0x0c0c0a2a, 0x1514190e, 0x0606070f, 0x60823783, 0x0606042e, 0x15151008, 0x13141919, 0x08070f10, + 0x24063d42, 0x0a0d0e12, 0x05b3540a, 0x87003f29, 0x54022a02, 0x64000b00, 0x10200511, 0x34054950, 0x0115403f, 0x90fe6531, 0x735a0187, 0x3c5fe2fe, + 0x01000014, 0x202b8700, 0x442b8211, 0x02350989, 0x14333207, 0x1b3f2015, 0x46262221, 0x3f314849, 0xfe52f616, 0x273a8254, 0x2c28271f, 0x38555551, + 0x01353f87, 0x011dff09, 0x00df025f, 0x05000007, 0x33323510, 0x01221510, 0x9ac31809, 0x83002009, 0x00522863, 0x02160200, 0x1825002d, 0x510aef86, + 0x222109e1, 0x0bdf4423, 0x07062108, 0x52220706, 0x100f0e0b, 0x151e1f1d, 0x1f14284f, 0x0e101d1e, 0x20400b0f, 0x0c0c0b08, 0x10181817, 0x07a2cd18, + 0x24472008, 0x63353030, 0x44446667, 0x35636766, 0x1d243030, 0x4e2a2626, 0x36365151, 0x2a4e5151, 0x901d2626, 0x3fb5187b, 0x06f5420d, 0xab583720, + 0xf922210d, 0x1f237b85, 0x82203f14, 0x0c182469, 0x82080c0b, 0x0c172f07, 0x40080b0c, 0x0e0f0b20, 0x1f1e1d10, 0x7b875914, 0x07876b87, 0x66221784, + 0x7b8c4467, 0xf7826720, 0x34353422, 0x09c15018, 0x1fc95018, 0x94181520, 0x4a180961, 0xf9570e17, 0x0c255205, 0x08a54518, 0x52223583, 0x00820201, + 0x06032608, 0x100f0b0b, 0x16171312, 0x1b191718, 0x16171919, 0x070e1212, 0x05060606, 0x03040405, 0x02010202, 0x15400101, 0x82008301, 0x310d8309, + 0x0c060101, 0x1412120d, 0x12131413, 0x0d111213, 0x1a58070d, 0x01013109, 0x1d5ab641, 0x12131717, 0x190c100f, 0x0e0e1312, 0x0806f857, 0x07070321, + 0x060d0a0a, 0x09090808, 0x0a0d0b0b, 0x12110e0e, 0xcc211919, 0x0769d344, 0x0c0b0908, 0x82080a0a, 0x03042171, 0x0d207182, 0x08200b82, 0x04220882, + 0x29820707, 0x84820420, 0x0405042e, 0x0b0b0a05, 0x08080b0c, 0x004fec05, 0x180c2f41, 0x4512cf47, 0x352105df, 0x5d951826, 0x0fd35507, 0x11838018, + 0x23076341, 0x36373635, 0x37413587, 0x06072a0b, 0x18169401, 0x19181a18, 0x25da8418, 0x060b0c0e, 0x00820203, 0x16410123, 0x31008901, 0x0d070102, + 0x1312110d, 0x13161312, 0x0c121214, 0x3541050c, 0x3f01210c, 0x022e2c82, 0x03030201, 0x100a0b07, 0x0d12120f, 0xe7820307, 0x0a070737, 0x130e0e0a, + 0x0f0c1813, 0x1713120f, 0x44cc1d17, 0x080569d2, 0x25ef8208, 0x05070a0b, 0x00830306, 0x0b0a0d25, 0x82040707, 0x09082400, 0x820b0a0a, 0x05043b43, + 0x08070605, 0x0b0c0a0a, 0xed070809, 0x225ab64f, 0x11111a19, 0x190a0d0d, 0x05821313, 0x00000b30, 0xff410001, 0x02260252, 0x008900d8, 0x52180500, + 0x4d5a0e8d, 0x0ac74507, 0x08558718, 0x08f74818, 0x34373423, 0x50018435, 0xdd5b0845, 0x0765510e, 0x2408f545, 0x27263526, 0x05194a26, 0x07222329, + 0x15140706, 0x82141506, 0x17531825, 0x2c01260a, 0x2f242418, 0x31ab8215, 0x03040506, 0x04010203, 0x0c080904, 0x08080f0b, 0x11820608, 0x45190420, + 0x03220806, 0xff820d04, 0x1182f482, 0x0708023d, 0x10100a0b, 0x1b1b1615, 0x08090a21, 0x0807090a, 0x06060d06, 0x08070504, 0x820e0b0b, 0x07072411, + 0x41030605, 0x03250589, 0x0f1a0403, 0x310c8410, 0x07040502, 0x4d090907, 0x05181930, 0x05060a04, 0x00830706, 0x0a0a0c25, 0x84040708, 0x82052079, + 0x82042035, 0x05052204, 0x27108205, 0x2a291515, 0x0a4f3c3c, 0x0e224c82, 0x39820407, 0x41424f37, 0x24233232, 0x0b0c1717, 0x02020101, 0x0a050404, + 0x0c100d0d, 0x223f8309, 0x82030204, 0x0806247e, 0x84030402, 0x04083900, 0x91494905, 0x0d080804, 0x0f0e0d0c, 0x0d0d0e0f, 0x2732313c, 0x001f1f27, + 0x022f0082, 0x4aff2000, 0x4d034902, 0xb1005d00, 0x41170000, 0x0d4b0b8d, 0x096d4b0a, 0x21057741, 0x07833635, 0x12a9c518, 0x4d0ab578, 0x10220857, + 0xb3421415, 0x205da005, 0x07fd4110, 0x9c0cdd47, 0x0dbf2753, 0x0a141110, 0xbe480b0b, 0x04043405, 0x07070611, 0x05060606, 0x08070906, 0x03020605, + 0x42030301, 0x102105c7, 0x27268310, 0x0c0b0d0e, 0x0304090c, 0x05242685, 0x08090506, 0x03212e82, 0x05615c03, 0x110ecb22, 0x0c202582, 0x05204c87, + 0x25824c8f, 0x25053858, 0x0c0a1311, 0x4b850d0c, 0xa1827282, 0x09317383, 0x05050808, 0x04040303, 0x0a0a0607, 0x05050ba1, 0x05dd5b01, 0x08070f3f, + 0x0203041e, 0x01010203, 0x09090504, 0x6116100f, 0x204b3c3b, 0x36322627, 0x0f5d4647, 0x26008210, 0x0b0a0e0d, 0x85020606, 0x080e232f, 0x92821e08, + 0x02020222, 0x08202f82, 0x172b2f82, 0x0ff614fe, 0x11100f10, 0x9b0b0e0d, 0xec012156, 0x4dab2682, 0x0003002f, 0x0256ff1b, 0x003f034f, 0x0097004b, + 0x140142e3, 0x16173223, 0x06b75317, 0x35363525, 0x41341110, 0x332005f7, 0x4107fd46, 0x2321089f, 0x05f34126, 0x15141527, 0x07141510, 0x15ef4106, + 0x32203782, 0x4ba34185, 0xd1060721, 0xa82b084b, 0x1c13140c, 0x07080808, 0x09080707, 0x09020204, 0x07050504, 0x03040406, 0x02030405, 0x07060103, + 0x14140c0c, 0x0808071b, 0x82090706, 0x02032720, 0x05050509, 0x20840506, 0x03020429, 0x0d970607, 0x841b1413, 0x07082340, 0x4083050a, 0x20820620, + 0x03050424, 0x4e820305, 0x06010128, 0x130c0d05, 0x41821c14, 0x08236182, 0x84010509, 0x82062062, 0x06032542, 0x02030302, 0x06242182, 0x13140d96, + 0x21824386, 0x0a010223, 0x20628204, 0x8a648205, 0x86858243, 0x820920a5, 0x030a2165, 0x43846482, 0x30054b42, 0x13850606, 0x02010909, 0x02020201, + 0x08091103, 0x31578221, 0x02010101, 0x08070404, 0x00fe010b, 0x16161aff, 0x21851213, 0x20840320, 0x82052447, 0x0804252d, 0x01fe0b07, 0x17212082, + 0x84424012, 0x0003002f, 0x023f005d, 0x0020020c, 0x002f0017, 0x19e75047, 0xff500320, 0x96212016, 0x05175117, 0x03040427, 0x08204008, 0x20078203, + 0x2007829e, 0x82008204, 0x0407260f, 0x01040303, 0x2110892a, 0x00820308, 0x04900127, 0x264d0703, 0x20238207, 0x23078304, 0xaffe0403, 0x27211183, + 0x252e8306, 0x07264e06, 0x0f8f0403, 0x5e20bf82, 0x0a20bf82, 0x1320bf89, 0xa7978f96, 0xcd20d797, 0xae84b686, 0x01219282, 0x20ae8e28, 0x8420899f, + 0xa1be91df, 0x000028ce, 0x00f40002, 0x8674013f, 0x186552bf, 0x6541a597, 0xa0062010, 0x11544195, 0x00820020, 0x07420420, 0x5f82190e, 0x1749411a, + 0x97172153, 0x2061412f, 0x42c9fe21, 0x73413132, 0x10424221, 0x0002002d, 0x0206012c, 0x0020023c, 0x431f0017, 0x05201901, 0x2205d356, 0x53640120, + 0xfe210ef1, 0x056356c0, 0x2d10bf42, 0x3c143c8a, 0x03000014, 0x3f002500, 0x5f864402, 0x61a13720, 0xc3420520, 0x34022916, 0x0408203f, 0x08040303, + 0x042b0783, 0xe9fd0404, 0xfe5e1701, 0x8eb101e8, 0x118b4217, 0xc7208a84, 0x0522fb91, 0x9b822b00, 0x9b843e20, 0x37002f25, 0x19004f00, 0x411a7773, + 0x194117c9, 0xcbe21807, 0x22379717, 0x4320409b, 0x078605ed, 0x868b0121, 0x82df84d7, 0xf7fd28e7, 0xfe848c01, 0x86411574, 0x21078627, 0xef8b8d01, + 0xef912782, 0x950f0742, 0x110f41ff, 0x2c000324, 0x0b423f00, 0x00572206, 0x1cab416f, 0x200efb4a, 0x07ad5017, 0x18151421, 0x4e107b99, 0xa94708a5, + 0x06072106, 0x4217e341, 0x3608125d, 0x27262626, 0x0f0c0d0c, 0x110f100e, 0x08020304, 0x181a1a1c, 0x24232322, 0x11121310, 0x15131312, 0x0b0c0c0e, + 0x0f0d0d0c, 0x09020204, 0x0c0f0e11, 0x0f0e0e0c, 0x83131214, 0x2501211b, 0x3e200f44, 0x1b1b37a7, 0x01020e0e, 0x05050302, 0x01010108, 0x07060d04, + 0x381e0e0f, 0x090a0d1b, 0x82040707, 0x03033554, 0x02060504, 0x05070301, 0x01040405, 0x06030402, 0xbb0b0b07, 0x2f113b41, 0x002c0001, 0x013c02e9, + 0x003f0072, 0x35343700, 0x203c1f41, 0x20f5ba2c, 0x20d2b5e9, 0x89008200, 0x534320c3, 0x34210e07, 0x0e8d5235, 0x18082b4b, 0x2009b394, 0x09234e22, + 0x49303121, 0x28080593, 0x0d0c0df3, 0x1313120f, 0x13121211, 0x23232512, 0x1a1a1821, 0x0202041d, 0x0f101108, 0x0d0d0e0f, 0x2626270c, 0x12121325, + 0x2e238211, 0x0e0e0f14, 0x0f0e0d0c, 0x03030511, 0x82030101, 0xf138080b, 0x04030203, 0x0a060604, 0x1c370e0a, 0x070f0e1e, 0x01010d06, 0x05080401, + 0x01020305, 0x1b0e0e02, 0x0b101c36, 0x0406070b, 0x04010204, 0x07050504, 0x02010102, 0x00040505, 0x5226c783, 0x03023c02, 0x47734d00, 0x4f26200a, + 0xe5640509, 0x0da14106, 0x210e6b5a, 0xdf823233, 0x3211c942, 0x01060706, 0x15150d24, 0x0e0d090d, 0x03040408, 0x82040803, 0x260e28c3, 0x26232524, + 0x83272625, 0x0a0b27d0, 0x0a0a070a, 0x2583080b, 0x0d0e0727, 0x15141608, 0x08ae4212, 0x1413122a, 0x0b0c0b0c, 0x0d0c0b0b, 0x52210682, 0x23428203, + 0x223a3922, 0x2505164f, 0x0f020103, 0xbc411e0e, 0x03033108, 0x2e2e2803, 0x0405031e, 0x36352103, 0x05040820, 0x290c9742, 0x04020301, 0x302b0503, + 0x00820030, 0x2c00022a, 0x3c028f00, 0x0700b501, 0x1320f183, 0x2006ab45, 0x4ce38407, 0x32210cd5, 0x0cd76031, 0x4560e594, 0x05cf4108, 0x2105055c, + 0x00821384, 0x12131225, 0x820e0d14, 0x0f0f2b00, 0x05030110, 0x0d0f0306, 0x00830c0e, 0x24232324, 0xc6411124, 0x19132b05, 0x041b1a1a, 0x14090202, + 0x1d831111, 0x14130a23, 0x311a8213, 0x3c650112, 0xd6143c14, 0x0a0f1b37, 0x0406060b, 0xe0820204, 0x0705042a, 0x01020202, 0x03050507, 0x0f22fd83, + 0x1969381e, 0x04042905, 0x010c0606, 0x09040101, 0x022b6382, 0x04030201, 0x0b0c0607, 0x82020000, 0x82a620e7, 0x00c527e7, 0x0047003f, 0xc3411300, + 0x3316210d, 0xbb41db84, 0x44262016, 0x07201185, 0x43062741, 0x13273b6d, 0xfe848c01, 0x413c0174, 0x032e06b7, 0x08050502, 0x0d040102, 0x0e0e0606, + 0xce87371e, 0x46441182, 0x0203310a, 0x07030402, 0xa70b0b06, 0x143d143d, 0x01000000, 0x2e24d782, 0x46023d02, 0x080b4e18, 0x570dd568, 0x07200a83, + 0x141d9919, 0x91531720, 0x076d5e07, 0x109dc418, 0x09916618, 0x2009ef57, 0x084d6407, 0x0bad4c08, 0x080a1212, 0x58090e0e, 0x0e38711d, 0x170e1716, + 0x13191818, 0x09101211, 0x0b0b090a, 0x15080909, 0x15151415, 0x0d101312, 0x0b0c0c0c, 0x05110f0e, 0x12050a01, 0x0b12201f, 0x0f0a1211, 0x09101a1a, + 0x14080808, 0x12121313, 0x820e100f, 0x0e400831, 0x0f0e0e0d, 0x0b0d0c0f, 0x08070808, 0x0c090908, 0x0a100f0e, 0x6cd845d0, 0x2e17170f, 0x080f0f09, + 0x0e16170e, 0x2115143d, 0x050a1422, 0x07030405, 0x06050503, 0x07070606, 0x0c111b36, 0x0206050b, 0x2806ec6a, 0x05010206, 0x33331e02, 0x0833831e, + 0x2a2a1a3c, 0x0101011a, 0x07080405, 0x380d0b0a, 0x0707091b, 0x05050606, 0x02020403, 0x02010102, 0x15040302, 0x3d0f1817, 0x26261614, 0x03000000, + 0x5a002c00, 0x25023c02, 0x4f004700, 0x2d425700, 0x0c0d4307, 0x54280b43, 0x5d430c3b, 0x33202609, 0x2c201514, 0x22f88315, 0x82141314, 0x0d0d31f7, + 0x04151110, 0x0f080203, 0x0c0c0e0d, 0x230c0c0d, 0x4225a946, 0x84200545, 0x30054b42, 0x0f1c369d, 0x06070a0a, 0x01020303, 0x05050302, 0x20f48209, + 0x27e88303, 0x0f020203, 0x1c371d0f, 0x20059b46, 0x231c8203, 0x06040403, 0x0320fb82, 0x2c059c46, 0x06030301, 0xa80b0c06, 0x143d143d, 0x065a42ab, + 0x00020025, 0x4117002c, 0x7b200607, 0x20490541, 0x2b761813, 0x35342509, 0x37363332, 0x13554f18, 0x22151423, 0x879f1823, 0x4329410a, 0x0b8c2c08, + 0x040b1211, 0x5e040708, 0x352e8c1f, 0xd440c011, 0x10110a69, 0x11120a0a, 0x0707040b, 0x8b1f5c03, 0xc012342f, 0x0a6ad340, 0x41011010, 0xfe373f49, + 0x0d0d066a, 0x09090606, 0x44143d05, 0x0c143d16, 0x070d1516, 0x85070c0d, 0x17432111, 0x00201184, 0x2605bf43, 0x023c0200, 0x70790070, 0xbf4306a1, + 0x071b410d, 0x57272621, 0x901808b1, 0x36200cc7, 0x670c3f5a, 0x17210cfd, 0x0fcf4416, 0x27262323, 0x779d1806, 0x08c5430c, 0x0ee93008, 0x040e1919, + 0x66040908, 0x06386f22, 0x97060b0b, 0x193aae32, 0x0102020c, 0x10101302, 0x0c0c0d0d, 0x2525280c, 0x12131323, 0x14141213, 0x820c0c17, 0x10102311, + 0xdf820712, 0x0e0d0834, 0x18170f08, 0x0c0c080f, 0x03030108, 0x23232204, 0x45491224, 0x08132c05, 0x07090808, 0x9c050808, 0x83509f34, 0x44cd2755, + 0x0a0766ca, 0x1282050b, 0x140c2208, 0x143d0c14, 0x111c1c11, 0x2042143d, 0x05080102, 0x01030306, 0x1d0e0e01, 0x0b0d1c36, 0x0306070a, 0x05c34204, + 0x53820820, 0x23150237, 0x09051524, 0x21140508, 0x01011321, 0x371d0f0f, 0x0b0a0e1c, 0x24328306, 0x15141302, 0x8249870e, 0x05eb454f, 0x3c028f28, + 0x5f00c501, 0xb742b900, 0x0901590e, 0x82171621, 0x16332301, 0xeb663031, 0x08af5509, 0x4611bf47, 0xd1430a03, 0x0c53450c, 0x47082144, 0x697b112b, + 0x9237200a, 0x0659455d, 0x07822620, 0x22272222, 0x0807537b, 0x13142c2a, 0x15111213, 0x04041a14, 0x07050405, 0x07080907, 0x08060707, 0x02050a09, + 0x04020301, 0x0e0d0d0b, 0x0d0e0d0e, 0x11121111, 0x32080382, 0x12131112, 0x13131212, 0x0d0d0e13, 0x0d0d0c0b, 0x0202040d, 0x09090c09, 0x08070606, + 0x0c0d0d07, 0x1314140d, 0x09080810, 0x0a0a0909, 0x13121509, 0x820a0712, 0x0a0a2609, 0x1d1c190a, 0x0b934720, 0x17820d20, 0x08202782, 0x09240383, + 0x0a0a0908, 0x11205582, 0x13210382, 0x069f4718, 0x0a251882, 0x0608070a, 0x825a8205, 0x86072090, 0x3c012d1f, 0x0b0f1b37, 0x0406060a, 0x02010103, + 0x2205e751, 0x82030301, 0x260b82ac, 0x04040406, 0x47020203, 0x0f28058f, 0x0b0d1b37, 0x0307070a, 0x2006cb47, 0x21cf8205, 0xa06c0305, 0x01032405, + 0x82040402, 0x05042a19, 0xb5070805, 0x0a101b37, 0x05cf440a, 0x07020128, 0x02020d07, 0xd0440102, 0x01012f06, 0x02020302, 0x05040304, 0x07070505, + 0x52873809, 0x22060048, 0x82030403, 0x06505900, 0x6f437685, 0x02172606, 0x003d023c, 0x0ddf4983, 0x20077341, 0x0d194807, 0x36373622, 0x43076d5d, + 0xff491677, 0x22232118, 0x2005596b, 0x0cdf4c07, 0x0c737918, 0x07062008, 0x0d020106, 0x0a0d1615, 0x0d0a0f0f, 0x130c0c0c, 0x12111312, 0x26121312, + 0x08272525, 0x82070909, 0x07082c03, 0x0e0e0303, 0x0c0b0d0c, 0x820d0b0c, 0x13232117, 0x15202083, 0x35078443, 0x0d0c140f, 0x160d080d, 0x0f090d15, + 0x0e0e090f, 0x23220c0d, 0x00822423, 0x1211262c, 0x03061212, 0x191d0d03, 0x1385161a, 0x82252521, 0x830d202b, 0x05042f00, 0x0f090304, 0x06031710, + 0x301d0406, 0x29491e30, 0x37103408, 0x0e0e1c1b, 0x02010101, 0x15030102, 0x06290b0b, 0x82030304, 0x0e0f361d, 0x0e1b371e, 0x07070a0a, 0x01010403, + 0x05040304, 0x29292508, 0x233f831b, 0x1d30301c, 0x0e202282, 0x2d06814a, 0x15060403, 0x0d290a0a, 0x0f0f0706, 0x234d381e, 0x252f8205, 0x03010604, + 0x2b820103, 0x26095f47, 0x003f0026, 0x498d0085, 0x575a118d, 0x1c2b430a, 0x470db341, 0x81430c9f, 0x8a499811, 0x05954745, 0x203a414d, 0x3feb4a13, + 0xc8471220, 0x369f2a05, 0x0d0d1b1c, 0x03020102, 0x075c4e04, 0x0e0e0623, 0x06154a1d, 0xc0470320, 0x0404240d, 0x47020104, 0xbe2305c0, 0x450e1c36, + 0x032c073c, 0x07050503, 0x02020201, 0x03040507, 0x2e090048, 0x0407070a, 0x0c060603, 0x03010102, 0x82060609, 0x0401271f, 0x0c070703, 0xf747a60b, + 0x00032707, 0x0246002c, 0x9f41023c, 0x41cb2005, 0x45458a9f, 0x08f34606, 0x4b32e541, 0xdd413cb1, 0x2040bf40, 0x73184201, 0x5442ba20, 0x4b00203a, + 0x4b240c4f, 0x5b005300, 0x0e33db18, 0x200e1f50, 0x08294733, 0x5008e541, 0x894d1c27, 0x50078707, 0x223c0f37, 0x0c0c0c0d, 0x100d0d0d, 0x08020204, + 0x0d111116, 0x090b0a0d, 0x13131314, 0x14141412, 0x25183f50, 0x848c01d3, 0x554b74fe, 0x03a33206, 0x03030102, 0x0a0b0606, 0x1d1c370e, 0x02030f0f, + 0x06924d03, 0x05050922, 0x0e821b82, 0x0a07062e, 0x1b370f0a, 0x070b0b0f, 0x01030307, 0x25075350, 0x05050202, 0x544ba104, 0x00022b0b, 0x0267002b, + 0x00f4013c, 0xe2180013, 0x342b0b49, 0x16171635, 0x36373217, 0x46011437, 0xf9850981, 0x06072239, 0x42513c02, 0x42323243, 0x42575243, 0x432f2e42, + 0xf0fd5442, 0x82424252, 0x52422211, 0x25118356, 0xa0014242, 0x00821225, 0x1c38252c, 0x01141325, 0x3f271313, 0x0b83b2fe, 0x13121222, 0x1b491388, + 0x02202b05, 0x003a023c, 0x00910049, 0x814b1300, 0x08734105, 0x4a05e75a, 0x234a0c53, 0x0e116105, 0xa9532320, 0x08b75106, 0x5f012221, 0x27210e17, + 0x4a018226, 0x2b4d05bd, 0x0f09760a, 0x95723520, 0x2d43820d, 0x041c552c, 0x06050202, 0x0b0c0807, 0x00830910, 0x0b0a0a3c, 0x13141414, 0x090f0f13, + 0x03040406, 0x39721c54, 0x06060404, 0x050a0908, 0x02820606, 0x0e060623, 0x2300820b, 0x02060808, 0x01350082, 0x80010102, 0x13132b01, 0x110f1414, + 0x11141411, 0x03040c10, 0x22158203, 0x82550102, 0x04012239, 0x235a8203, 0x05050b08, 0x072f3984, 0x0a0b0b0d, 0x0609090b, 0x81030405, 0x82254b2a, + 0x03032c27, 0x08080506, 0x66010b0b, 0x8211133c, 0x0c0a2664, 0x0a0b0c0b, 0x30208205, 0x05010203, 0x0f0c0b06, 0x0c0a130f, 0x143b100c, 0x25938217, + 0x080c0b10, 0x6b5f0305, 0x04042b05, 0x0c0d0809, 0x08090711, 0xb4820809, 0x0bd1fe22, 0x05279f82, 0x10100909, 0x82060717, 0x06073000, 0x16143b07, + 0x10101313, 0x03080c0c, 0x82020303, 0x84052096, 0x0d122a33, 0x3b171212, 0x07070414, 0x2400820a, 0x0a0a0b0c, 0x20008200, 0x05b35002, 0x003a0225, + 0x41510049, 0xbd504bab, 0x436b4108, 0x8c012b25, 0x4174fe84, 0xc020402d, 0x2c07f357, 0x02a6002c, 0x0065023c, 0x001f0017, 0x1c475627, 0x14332024, + 0xcb872015, 0x4312ff55, 0xd6200bc3, 0x0f8be318, 0x6f837120, 0x143dbf2a, 0x0700143d, 0xf5ff2c00, 0x07227384, 0x77860f00, 0x47002f34, 0x32130000, + 0x06072233, 0x14373415, 0x26273415, 0x6b823223, 0x1617142d, 0x22332233, 0x36373223, 0x84051435, 0x34232281, 0x06d74f15, 0x33321722, 0x08b7fa18, + 0x8b582320, 0x09f6370a, 0x03030805, 0x0804047e, 0x03037a0c, 0x0b7b0b08, 0x04040805, 0xa08ab8fe, 0x6f565420, 0x6502310e, 0x0b070403, 0x07050903, + 0x0a8f0304, 0x04030704, 0x0a21c082, 0x20b48225, 0x28b383fb, 0x07030322, 0x0407274d, 0x82258203, 0x03032107, 0x22058b5a, 0x41f7ff2c, 0x3f200a3b, + 0x1159c182, 0x0f354516, 0x58175557, 0x76200f69, 0x0121b28a, 0x0e75587d, 0x64410120, 0x83af201a, 0x07895ca8, 0xb8822620, 0x0422b082, 0xaf8f2b00, + 0x59170b5b, 0x69410829, 0x17315906, 0x8e2d0221, 0x06095993, 0x5905c945, 0xb0ad100f, 0x2500042f, 0x44028e00, 0x1700cd01, 0x37001f00, 0x1a5f4100, + 0xa79e3720, 0x8c221f87, 0xc9591e3a, 0x1d3b2d05, 0x04040308, 0x22012d03, 0x95ddfe61, 0x01261594, 0x0703044d, 0x2f852142, 0x03270782, 0x143c1804, + 0x82d7143c, 0x21432315, 0x00820307, 0x07830720, 0x3d180422, 0x20051a54, 0x41af9200, 0x2520175f, 0x0742af86, 0x241f8717, 0x1e3a3402, 0x21698208, + 0xb0820803, 0x495b0420, 0x22b18205, 0x96ae01de, 0x44b3af17, 0x012c06f3, 0x002b00b5, 0x37000043, 0x33323534, 0x0b71ae18, 0x73332021, 0x1521081d, + 0x050f6516, 0x2106d150, 0x5a183720, 0x35270865, 0x27262734, 0x7c062322, 0x2c310585, 0x0306356a, 0x07030404, 0x8c012878, 0x03346784, 0x06f55303, + 0x04020237, 0x74fe2675, 0x06183062, 0x03040505, 0x06070201, 0x0d18300d, 0x23008206, 0x0e143ca6, 0x0f3b0082, 0x3c0d0e0e, 0x03143b13, 0x08080405, + 0x08090908, 0x06070706, 0x3c090708, 0x82055014, 0x08072e76, 0x0f100807, 0x0e0b0c0e, 0x0e11110e, 0x0683430e, 0x02a60028, 0x00dc023c, 0xed48002b, + 0x0f194706, 0x64133364, 0xef710771, 0x0fb7431f, 0x7d012408, 0x15121310, 0x11121215, 0x090d0d10, 0x05040509, 0x0d0a0a04, 0x1211100c, 0x19201413, + 0x0b14141a, 0x8205050b, 0x960d3011, 0x12100f0c, 0x0d0f0f13, 0x0606070c, 0x820d0c07, 0x1012230d, 0xec840c0f, 0xd443be20, 0x08e72e0b, 0x05040405, + 0x0b0b0908, 0x11110f0e, 0x82598212, 0x830c20e0, 0x0a0a275a, 0x17181213, 0xea82121b, 0x0c0c0f23, 0x69e11831, 0x06062a10, 0x0e0e0b0c, 0x0e0e1010, + 0x095b45c7, 0xc3460320, 0x007d2606, 0x001b0013, 0x0c4b4c23, 0x5105dd48, 0xcb450541, 0x345b2c0c, 0x3a393637, 0x35323636, 0x82373636, 0x8b662002, + 0x38e223a0, 0x9782241c, 0x82241121, 0x13122607, 0x13120102, 0x206e89a2, 0x266f8700, 0x001d00f2, 0x822d0025, 0x095f6b6f, 0x0dffba18, 0x22207783, + 0x3e0f4f41, 0x0b0a0797, 0x1615150b, 0x0e1b360e, 0x0b151516, 0x30080a0a, 0x1b1b1018, 0x1a1a0f10, 0x8b7d3810, 0x13d73487, 0x321b1818, 0x23233434, + 0x1b323434, 0x26131818, 0x83263e3e, 0x8a722003, 0x188f918e, 0x52089972, 0x076b0589, 0x248f8f0e, 0x0b070c01, 0x2590840a, 0x1a101931, 0x8a830f1a, + 0x87183021, 0xf53c219a, 0x88879094, 0x908b9887, 0x27061f41, 0x23002003, 0x33002b00, 0x23061f41, 0x27262726, 0x0b955118, 0x06070627, 0x16171607, + 0x41178317, 0xc73b129f, 0x080d0e07, 0x15212215, 0x0d082c5a, 0x0e08070e, 0x2c5a070e, 0x15222214, 0x820e0e07, 0x15232517, 0xaf222215, 0xe42c9a8b, + 0x16262617, 0x0e17170e, 0x17262616, 0x0e270b8b, 0x0e0e1718, 0x418d1817, 0x00210b32, 0x05334204, 0x00240323, 0x1bc54113, 0x53183720, 0x57570917, + 0x6c99200e, 0x223007b5, 0x18181011, 0x0b0b0c17, 0x6503ea09, 0x18180e32, 0xcb206c83, 0xed28998b, 0x1e1a1b14, 0x26393a37, 0x07128e18, 0x39223428, + 0x3a22223a, 0x9289de39, 0x23000736, 0x4602a600, 0x2b00df02, 0x81005700, 0xb300a100, 0xc300bb00, 0x430dc74c, 0x3b4b07d5, 0x35342108, 0x2309394b, + 0x05060706, 0x09c74918, 0x654b3420, 0x14332207, 0x08eb5315, 0x15141522, 0x4b098772, 0x578f0a4b, 0x22212782, 0x08515223, 0x740be96f, 0xfb440c47, + 0x32372306, 0xb0183433, 0x2b410e19, 0x099b260e, 0x130a0809, 0x06a81810, 0x0a13210a, 0x0805e944, 0x081a0555, 0x01010b14, 0x06070501, 0x08174201, + 0x04040817, 0x0d0d0708, 0x16081711, 0x0606090a, 0x02010404, 0x0e290d2a, 0x13124518, 0x14181313, 0x080d0e13, 0x0d070707, 0x1612110e, 0x0c111015, + 0x6606060b, 0x13120232, 0x13121122, 0x08abfe12, 0x0d0d0b0a, 0x46080a0a, 0x0825053d, 0x0d0d0a0a, 0x2e0d820b, 0x04030304, 0x04274fcd, 0x0b070704, + 0x840e0e0a, 0xee052112, 0x080ba141, 0x0204db33, 0x0e070702, 0x1612120d, 0x0e121217, 0x0207060e, 0x07030402, 0x194d0807, 0x090542c5, 0x06090609, + 0x297c0707, 0x05080712, 0x070c0b10, 0x13030407, 0x2e218306, 0x0c080706, 0x7c061304, 0x03070929, 0x83060604, 0x86182040, 0x06063240, 0x11110c0c, + 0x21040b16, 0x05041010, 0x0a181608, 0x82008205, 0x83bb8292, 0x05042ca4, 0x0a0a0405, 0x11110d0e, 0x833d0d0e, 0x040721b4, 0x07200082, 0xf020b482, + 0x2013db43, 0x07e945db, 0x35341328, 0x17143332, 0xa7501716, 0x0ad15f0f, 0x6a09656e, 0x776e086f, 0x44118b08, 0x29080f09, 0x020e1a6f, 0x09070101, + 0x0d0b0a09, 0x0d0e0f0c, 0x070b0b0c, 0x17100608, 0x10161f18, 0x050c0b11, 0x0f0b2106, 0x0e101d0e, 0xcc820a0d, 0x0e0b2227, 0x0d111d0e, 0x210b830e, + 0x4d414e21, 0xd328080b, 0x0c0841c1, 0x080c080c, 0x03060609, 0x07030302, 0x0e0b0a07, 0x070e0e1b, 0x150d0e07, 0x27751a14, 0x12243467, 0x0b050512, + 0x14224d82, 0x0d8d256d, 0xfd896e20, 0x2007a343, 0x27fb8238, 0x006b0063, 0x01000073, 0x10df8218, 0x55107b72, 0xf3460c5b, 0x0d576f07, 0x15061526, + 0x17221514, 0x4a16b74a, 0x01210f07, 0x050c420f, 0x02060b37, 0x05060c03, 0x02040405, 0x08040401, 0x0d0b0a08, 0x19171614, 0x21008318, 0xde831213, + 0x05020322, 0x06281783, 0x070b0303, 0x02010504, 0x01260082, 0x060e1624, 0x00820408, 0x070d0822, 0xfe210784, 0x0a2b41f3, 0x1931022f, 0x0a0a0d0c, + 0x09080707, 0x0303050a, 0x285e820a, 0x06060506, 0x08090b07, 0x26468206, 0x1d100807, 0x82070d0f, 0x05124e12, 0x82090821, 0x0a092728, 0x0a020206, + 0x2f820406, 0x71820320, 0x0b080829, 0x045e0716, 0x82150703, 0x03032274, 0x21078304, 0x46410403, 0x01002e0a, 0x11002c00, 0x49023c02, 0x00003500, + 0x0f195b37, 0x18091b5b, 0x21093f7f, 0x59181514, 0x3a080b8f, 0x7d060706, 0x0c14130c, 0x0f1a1910, 0x376e194b, 0x111d1d11, 0x51f340c1, 0x140c2852, + 0x1a0f0c13, 0x194c0f1a, 0x1e11376f, 0x40c3111d, 0x27176cd7, 0x0f0a1127, 0x1f120a0f, 0x833d131f, 0x3c143748, 0x0a316314, 0x13090e0e, 0x3c131f20, + 0x22231414, 0x1c143d15, 0x035d2f2e, 0x00002108, 0x7c05134d, 0x97420817, 0x06e35f0f, 0x220a3741, 0x823cb001, 0x50ab2056, 0xe38309f5, 0xe3820520, + 0x45005722, 0x1950e388, 0x15eb5a05, 0x8f373621, 0x051945ed, 0x320a0f5c, 0x17160dcf, 0x5a07150d, 0x08356a1e, 0x98090d0e, 0x8351a233, 0xd7280807, + 0x076dd948, 0x0d080d0e, 0x050d1616, 0x58050809, 0x2227741d, 0xb332960b, 0xd50b223c, 0x086cd847, 0x05050c0d, 0x2906090a, 0x330b305a, 0x10143c11, + 0x05101b1c, 0x0a060a0a, 0x3c0b1112, 0x3d174314, 0x10240384, 0x04001b1a, 0x2006f77c, 0x06074151, 0x410afb7c, 0x554f0f09, 0x0a0b4108, 0x8505774c, + 0x01022105, 0x5d0d1741, 0x2b320a67, 0x3b020000, 0x1900ff01, 0x00002100, 0x34272425, 0x255a2435, 0x48072009, 0x142007b7, 0x2107fd42, 0x9b523b02, + 0x4a302905, 0x2226474a, 0x49311a23, 0x23240782, 0xf0fd1a22, 0x792a7a84, 0x133c2675, 0x1d3a2775, 0xe67a130e, 0x140d2905, 0x090a1414, 0x8e40070a, + 0x00208183, 0x8706cb7d, 0x3437216f, 0x080dac18, 0x2b462620, 0x247f8205, 0x15141704, 0x2fd18804, 0x2722231a, 0x31494a47, 0x2623221a, 0x314a4a47, + 0x7926e18a, 0x09071d38, 0x61820a0a, 0x09080d30, 0x14130b09, 0x16410e13, 0x143b2775, 0x6c84a074, 0x0000002b, 0xff2b0003, 0x023b02af, 0x20df842c, + 0x87e1a329, 0x41e99e79, 0xa6200558, 0xef826e82, 0x0d1d3929, 0x0a131415, 0x8d08090a, 0x567e20ef, 0x878e09d7, 0x8787f9a1, 0x62412b20, 0x05014107, + 0x01414920, 0x2184860b, 0x76841c39, 0x07090a2c, 0x0a0a0908, 0x0d151413, 0x98841541, 0x143ca024, 0x8487143c, 0x2b000224, 0x0b4164ff, 0x414b2006, + 0x01201b09, 0x43050b44, 0x235f0727, 0x0937530f, 0x2b410988, 0xfe2a0817, 0x13130b7e, 0x4c040f0b, 0x222e8a19, 0xcf39ac0b, 0x17180f67, 0x13130c0f, + 0x4b05100c, 0x083d7819, 0xab090e0f, 0x0e68ce38, 0x49411718, 0xfe230819, 0x11110ba9, 0x3d050e0b, 0x3c0b2214, 0x18180e14, 0x12120a0e, 0x3c050f0a, + 0x0f0e0814, 0x0e143d08, 0x8e001817, 0x195d41db, 0xdbb01320, 0x20157f41, 0x41d8a90a, 0xfe21189d, 0x2dd8a197, 0x01000000, 0x00002b00, 0x5b023c02, + 0xa75f4f00, 0x10fd5d0a, 0xd9833720, 0xf1663420, 0x8b471805, 0x6536200c, 0x07260b2f, 0x17161716, 0x2b821514, 0x23222322, 0x2b084382, 0x18180fc3, + 0x14140c0e, 0x23231e0c, 0x1a191c26, 0x16161817, 0x06050d13, 0x3c3c3019, 0x40445947, 0x18060433, 0x0e131b1b, 0x0d0f1818, 0x1f2b2582, 0x35262322, + 0x0c292f30, 0x82180706, 0x5a462321, 0x21853f43, 0x0b072608, 0x2617070b, 0x0e0a1726, 0x1c38110e, 0x080a0a0d, 0x04060609, 0x2d0c0b17, 0x21111105, + 0x12291c38, 0x32322d11, 0x25268422, 0x0a182525, 0x26820d0e, 0x0f101923, 0x20228509, 0x20228212, 0x2122822a, 0xea823233, 0xff2c0023, 0x22ef82f3, + 0x18430068, 0x210cfd57, 0x2d442726, 0x0bf95c09, 0xe388df91, 0x454c2720, 0x83272006, 0x06594c23, 0x01019a08, 0x0f17170f, 0x0c12120c, 0x33233194, + 0x181b3134, 0x120a1318, 0x170f0b12, 0x0c070f18, 0x301c070c, 0x39221c2f, 0x0f092339, 0x140f0910, 0x2a2a1614, 0x16101c2b, 0x302d1916, 0x130a202f, + 0x0a060412, 0x2e1c0609, 0x25161c2e, 0x07040d25, 0x38220407, 0x12382139, 0x140c1a34, 0x090a1313, 0x35210609, 0x07042035, 0x22160506, 0x110b1623, + 0x1c3a0b12, 0x0c14140d, 0x1d30301c, 0x08070705, 0x0a0f0f0e, 0x08061c3a, 0x12110908, 0x37210c11, 0x1c12f136, 0x100a111d, 0x0c080a10, 0x25fb8b0c, + 0x004b003f, 0xad421700, 0x37362105, 0x230ded41, 0x35342726, 0x5e079945, 0x17200e03, 0x20086b5c, 0x20338207, 0x07435e37, 0xea240b82, 0x0e18180e, + 0x1d3de083, 0x231c302f, 0x0a223939, 0xb00a100f, 0x2f2f203a, 0x1616192d, 0x13120b11, 0x18170f0a, 0x3107820e, 0x3e3d250b, 0x33342224, 0x18191a32, + 0x12120b12, 0xee831b4d, 0x16252425, 0x84090906, 0x23162af2, 0x110b1622, 0x1d390a12, 0x21da860c, 0x0b82153d, 0x11111226, 0x06090809, 0x212cd482, + 0x05060704, 0x21393922, 0x0e16170e, 0x200c1a41, 0x24ea86e7, 0x1c1c1208, 0x28ef8500, 0x023c028d, 0x0053005d, 0x44ef8a5f, 0xf5410973, 0x08ab5929, + 0x200d6962, 0x0afb4113, 0x190fe33a, 0x09071019, 0x2264060a, 0x0e09366c, 0x349d090f, 0x33353523, 0x1319191b, 0x0b20cf82, 0x0f2c1d82, 0x070c0c07, + 0x1a2c2c1b, 0x21363720, 0x50080b82, 0x42432808, 0x2c2c1c28, 0x1515162b, 0x0b0c080f, 0xcb45d008, 0x0c0d0766, 0x0708032b, 0x28281804, 0x21211418, + 0x08080573, 0x1c1b1105, 0x19143c11, 0x2e192b2a, 0x0b1a350f, 0x080f100f, 0x1f050807, 0x041f3334, 0x15040808, 0x08152323, 0x3a080d0d, 0x2a75821d, + 0x23231608, 0x12120b16, 0x821c390b, 0x070c3a13, 0x14040606, 0x3c152223, 0x24231614, 0x130c7c01, 0x0b060c14, 0x0905070b, 0x0b1f4109, 0x65005922, + 0x42141f41, 0x47470f19, 0x261f4205, 0x20094b67, 0x0a294213, 0x2541b720, 0x06092505, 0x274f1643, 0x4b088682, 0x2d2e1b05, 0x3738221c, 0x0c0c0722, + 0x28281a07, 0x13131427, 0x2d2c1e0e, 0x1515172b, 0x12130a10, 0x191a0f0b, 0x13120b0f, 0x4040260a, 0x34342226, 0x18191b32, 0x0b0c0812, 0xe850f108, + 0x0c0d0775, 0x27261783, 0x21201317, 0x07060413, 0x3a0a2b41, 0x101a1b0f, 0x080d0d09, 0x0f091d38, 0x22150910, 0x0a071523, 0x05050b0b, 0x183a0405, + 0x3c08bf4b, 0x1f343320, 0x04080804, 0x1e34341f, 0x0c13120c, 0x0f0a1b34, 0x07080f0f, 0x23160507, 0x06314124, 0x0a06772c, 0x0906060b, 0x140b0509, + 0x00820014, 0x2b000224, 0xd348ecff, 0x46612006, 0x05201be7, 0x5a11696a, 0xc1640a2f, 0x0a27630f, 0x460e6b6a, 0xfd2817fd, 0x131415f0, 0x14131213, + 0x6a186467, 0x0e6e067d, 0x0d0d2310, 0x3882100e, 0x13121123, 0x19514913, 0x1b36a22a, 0x060a0a10, 0x01030207, 0x250c7167, 0x02010304, 0xb05f0f0e, + 0x0b07221e, 0x122b410b, 0x62193747, 0xe760059b, 0x342b410c, 0x4a084d47, 0xcf490740, 0x43284105, 0x491d3821, 0x0e270705, 0x0a141314, 0x4a070a09, + 0xb420060d, 0x2c412841, 0xff2b0002, 0x023b028d, 0x0083005d, 0x0b87438d, 0x41060721, 0x33210519, 0x43018232, 0xa5460543, 0x0daf4427, 0x7006076c, + 0x27241b91, 0x23262726, 0x07820182, 0x06070623, 0x08d74413, 0x190fe32a, 0x0d091019, 0x2526080e, 0x3105d26d, 0x03070309, 0x060a0a09, 0x1913349d, + 0x35341b19, 0xdd442335, 0x2c1a3c0b, 0x36201a2c, 0x0d072135, 0x4228080c, 0x2c1d2842, 0x14172b2b, 0x0b060f15, 0x8303060a, 0x04042200, 0x07af7004, + 0x4d671220, 0x0f410806, 0x0b0a0d0d, 0x040e0d0d, 0x01090202, 0x02020201, 0x0b0a0606, 0x04290d0e, 0x19050607, 0x50192827, 0x08080573, 0x27271805, + 0x1d0e0e18, 0x0e1b1b36, 0x1c1c190d, 0x350f2e13, 0x0807061a, 0x100f0f08, 0x0909450a, 0x08152223, 0x0f09450c, 0x081c3a2d, 0x070d0d0d, 0x12040606, + 0x82131e1e, 0x29638261, 0x07060d01, 0x371d0f0e, 0x98820e1b, 0x012b9982, 0x04030302, 0x01020505, 0x82010301, 0x04033021, 0x01262722, 0x14140c78, + 0x0b0b070c, 0x41001507, 0x912209a3, 0x3b479b00, 0x1565180e, 0x0b6f5e09, 0x673e3b45, 0xb54109bd, 0x0c67650d, 0x0aeb4018, 0x29096345, 0x19190fb7, + 0x0e0e0810, 0x00840407, 0x12030322, 0x24080082, 0x10121213, 0x0f0e0f10, 0x03040505, 0x1c2e2f1b, 0x22373822, 0x080b0c08, 0x2628291a, 0x0e131315, + 0x2b2c2d1e, 0x10714518, 0x22263f30, 0x1b313434, 0x06121918, 0x03050a09, 0x20530606, 0x72032005, 0x24270973, 0x0d262425, 0x720b0d0c, 0x0d20076f, + 0x053a2182, 0x0d0b0908, 0x17810e0e, 0x13172625, 0x0f13201f, 0x08080573, 0x26261705, 0x00820117, 0x03820220, 0x0b0b0736, 0x0e1b360f, 0x06050a0a, + 0x0c020403, 0x09090e0e, 0x39080e0d, 0x2424ab45, 0x120c1e35, 0x0aab4512, 0x1b1b1126, 0x03020211, 0x2105fc58, 0xd7410401, 0x0d1b2307, 0x1582010d, + 0x06040422, 0x03207082, 0x01206683, 0x25392582, 0x7201292a, 0x060a0a06, 0x05090906, 0x0000002e, 0xff2b0002, 0x023b02aa, 0x73831845, 0x2726220a, + 0x17a94e26, 0x4805c360, 0x298508f9, 0x17490420, 0x3b022c09, 0x5d626140, 0x232d2d33, 0x4e848c01, 0x6d4d11c6, 0x0a9f4407, 0x2d2e223d, 0x62615d33, + 0x1d1d13bd, 0x0e0d0f1c, 0x75143b0a, 0x0e1d3a27, 0x0a131414, 0x4d070a09, 0x402207f9, 0x064ed7fe, 0x2c1c840c, 0x26751641, 0x0d0b1a35, 0x1d1c0f0d, + 0x45cb911d, 0xaf42186f, 0x42012006, 0x954f073d, 0x1a2b2816, 0x47262223, 0x4e304a4a, 0xad860a1b, 0x8ad00121, 0x871e87e6, 0x3abd22dc, 0x07294e1c, + 0x090a0727, 0x1414130a, 0x24a9820e, 0x0a1a3527, 0x21a9840e, 0xeb85dafe, 0x3b0b0d24, 0xeb827414, 0x0d202486, 0x0b20f383, 0x4120f382, 0x002dca82, + 0xff2b0003, 0x023b0244, 0x007500ad, 0x0c154581, 0x48115743, 0xd3890b8f, 0x510b8b43, 0xcd4b0777, 0x0b25450f, 0x75088d50, 0x072007ad, 0x210c0745, + 0x61431617, 0x06073c09, 0x1a1a0fd3, 0x0d0c070f, 0x27281707, 0x2f301d17, 0x0c0d071e, 0x3d3c2508, 0x48291a24, 0x330805c1, 0x2a1c0408, 0x1416292a, + 0x39250f14, 0x1a1d3739, 0x110a141b, 0x190f0a12, 0x0d060f1a, 0x2617060d, 0x301c1726, 0x0c081c30, 0x3090080c, 0x1513120e, 0x1b282826, 0x13203386, + 0x38213382, 0x08338638, 0x054c112b, 0x1d050807, 0x181c2f2f, 0x1c152727, 0x171c2e2f, 0x04182727, 0x04bc0808, 0x16040707, 0x07162524, 0x39070b0c, + 0x0d0d081d, 0x08198208, 0x100a1727, 0x1d3a0a10, 0x0c0b0c08, 0x04060506, 0x0d080d18, 0x06070c0c, 0x1a350406, 0x1011110b, 0x06080808, 0x1f353520, + 0x273b8205, 0x16242417, 0x070b0b07, 0x0d202d82, 0x272bc782, 0x0e281727, 0x05051d39, 0x820b0606, 0x0c192195, 0x06203983, 0x09303988, 0x20050808, + 0xfb013534, 0x0e18180e, 0x080d0c08, 0xfe222582, 0x758207e1, 0x0b0a0628, 0x18180d06, 0xb3410000, 0x007b240a, 0x18930087, 0x460ed355, 0x2d4507b9, + 0x09b74115, 0x20217b4c, 0x0a435236, 0x2006774d, 0x10954d17, 0x200bad41, 0x08cd4603, 0x16174d08, 0x1a1a0fd3, 0x14140c0f, 0x2f2f1c0c, 0x03468b1c, + 0x0e030404, 0x27151314, 0x111c2929, 0x2d181615, 0x051f2f2e, 0x21040707, 0x1a313333, 0x14121818, 0x351d1a19, 0x0c243837, 0x0f0c1413, 0x0b0f1a19, + 0x1c0b1514, 0x271b2e2e, 0x04274040, 0xa6293b82, 0x2e2e1e37, 0x1615182d, 0x2b358210, 0x18171205, 0x3332311a, 0x191a1321, 0x373e3582, 0x14130b25, + 0x101109aa, 0x0d0e0709, 0x03030108, 0x030202b3, 0x10100a01, 0x0e0e080a, 0x658204bc, 0x3d3c243a, 0x0d0e0824, 0x28143b09, 0x0f0e0815, 0x06060408, + 0x0d0c0c06, 0x051c3a08, 0x0d3c0983, 0x170e080d, 0x0e090e18, 0x06070e0d, 0x1d3a0507, 0x09070806, 0x0b10100f, 0x243c3c24, 0x04216f82, 0x2e3f8525, + 0x0b1a3508, 0x090b1314, 0x31080e0e, 0x411d3a10, 0x0e2407b9, 0x050e1718, 0x0e243882, 0x39090e0e, 0x11203b85, 0x29083b83, 0x020c023b, 0x02020504, + 0x04020404, 0xe9fe0908, 0x05080905, 0x02050502, 0x00030403, 0xff2b0001, 0x023b02ea, 0x00150070, 0x1f432500, 0x05b94105, 0x0805fb4d, 0x1617162a, + 0x84513b02, 0x84b8b784, 0x5e515084, 0x5e6a695d, 0x264b5b5e, 0x2347476b, 0x47231a34, 0x264b6b47, 0x15343455, 0x00353417, 0x2c204b82, 0x3c204b82, + 0x11824b85, 0x4e05c148, 0x4f84075f, 0x5d502c28, 0x5e696b5e, 0x5283515e, 0x8584b62d, 0x52254c16, 0x15173435, 0x8a553434, 0x06db4454, 0x97828920, + 0x1d00ad24, 0x99884100, 0x43057f45, 0xa18807e9, 0xd7431320, 0x07574209, 0x0cb34e18, 0xc5841720, 0x38382e3c, 0x4c4c4242, 0x4d4d5856, 0x37374141, + 0x5657482e, 0x56576566, 0x12110e49, 0x00821514, 0x14165908, 0x1e1c1214, 0x2b22221e, 0x363d352b, 0x2a2f2f36, 0x2426262a, 0x264ad424, 0x21272830, + 0x0e171721, 0x170f1a34, 0x28212017, 0x264b3028, 0x132d2d47, 0xfe2e2d15, 0x10284fe8, 0x11121112, 0x11101111, 0x110c0e0d, 0x0c0c0f0e, 0x3e080a0a, + 0x0e0d081f, 0x16161212, 0x1e1e1b1b, 0x4522cf8e, 0xab450000, 0x85a58d06, 0x070623cf, 0xf5490306, 0x0c854f0d, 0x080b6558, 0x57492b2e, 0x57656457, + 0x382e4857, 0x4d414137, 0x4c56584c, 0x3842424c, 0x24222e38, 0x2a262524, 0x362f2f2a, 0x1e233d36, 0x171b1a1e, 0x13141517, 0xe6830182, 0x14152708, + 0x11111414, 0x44254b64, 0x13152d2e, 0x4c472d2d, 0x28283025, 0x17172021, 0x0e1a340f, 0x21211717, 0xf5fe2827, 0x3882284f, 0x161b1b27, 0x0e121216, + 0x20ce820d, 0x2b788305, 0x0a090808, 0x0d0c0a0a, 0x10110d0e, 0x1222f182, 0xda821111, 0x00020025, 0x41cbff2b, 0x5d2006ab, 0x471fab41, 0x99670551, + 0x08055c0c, 0x4d11377b, 0x23210927, 0x21f98522, 0xc7413b02, 0x39fe2116, 0x4d17ef6c, 0xe4412218, 0x36b3271e, 0x0d0d1b1c, 0xc66c0201, 0x03012318, + 0x79480503, 0x05072105, 0x200ac66c, 0x0f1b4100, 0x6f1df741, 0xa7180eb3, 0xf56d0b77, 0x26272118, 0x09b35e18, 0x26110f42, 0x42424c4b, 0x412f3838, + 0x27423a19, 0x170d2716, 0x28212117, 0x1841c928, 0x00022c37, 0x02b2ff2b, 0x00a8023b, 0x46550045, 0x33440a39, 0x73981809, 0x0706210d, 0x460dcb47, + 0x07460755, 0x0bbd4709, 0x08062546, 0x1a0ffe45, 0x100a0f1a, 0x07080f0f, 0x36300508, 0x48523a35, 0x16143d48, 0x1a0f1016, 0x110a1019, 0x21270a10, + 0x14141a22, 0x15151615, 0x04081716, 0x04030a04, 0x353b0604, 0x3b2c3035, 0x16144a3c, 0x03030b17, 0x830c0802, 0x0c0d2c00, 0x1515140d, 0x0707054e, + 0x52301f05, 0x122d05e3, 0x340b0f0f, 0x17170f1a, 0x46463e1e, 0x0819832f, 0x32321e37, 0x20201c1e, 0x15264b24, 0x11111312, 0x180d0f0e, 0x0a1d0d0d, + 0x1c100c0d, 0x4b322727, 0x302f3b26, 0x46463d25, 0x060c3701, 0x04051907, 0x03030304, 0x05050204, 0x07434306, 0x48130f41, 0x13410dfd, 0x09374407, + 0x180bb153, 0x200c6f8a, 0x200d8207, 0xebcf1813, 0x8237200a, 0x10cd2633, 0x0a0f1a19, 0x25f78310, 0x15141b21, 0xf9821614, 0x052df782, 0x04050309, + 0x36353a05, 0x3b3b2d30, 0x24f7824b, 0x1919100f, 0x061b510f, 0x3531063c, 0x48523935, 0x17143c48, 0x02047316, 0x0c0d0803, 0x0c0c0d0b, 0x15150d0d, + 0xf5854e14, 0x1c1d3327, 0x4c251f20, 0x24f58425, 0x190d0e0f, 0x25f58d0c, 0x453e252f, 0x2b832e45, 0x412f1f21, 0x1020063b, 0x29053b41, 0x473e1e16, + 0x0d630146, 0x0f410606, 0x41032006, 0x012a070f, 0x4d002c00, 0x0e023c02, 0x5c183b00, 0x77640fbf, 0x0b7b600d, 0x0b3b5018, 0x2f05454d, 0x3c021433, + 0x1e2260c1, 0x161b1b1e, 0x08101015, 0x102e0082, 0x1b161510, 0x211f1e1b, 0x60c148d9, 0xb4821517, 0x0f0f4308, 0x05060a0b, 0x0b0a0606, 0x12130e0f, + 0xd9171515, 0x07074d48, 0x1414100f, 0x1d1c1a19, 0x1c1c201f, 0x1414191a, 0x07080f10, 0x05061135, 0x0d0e0b0b, 0x12131212, 0x13141516, 0x0e0f1112, + 0x05050a0a, 0xaf8c0035, 0x0f5b5a18, 0x756c3520, 0x995c180a, 0xc12c221f, 0x82598461, 0x060b2294, 0x2a6e8306, 0x13120f0f, 0xda171514, 0x8461c148, + 0x161521c8, 0x0726c882, 0x10100807, 0xc8821516, 0xda221e23, 0x2497834d, 0x0e0e0a0a, 0x20298311, 0x2a9c8216, 0x0a0e0e12, 0x3506050b, 0x86080711, + 0x201c23c7, 0xc7861d1f, 0x54070721, 0xe326050b, 0x77023c02, 0x2b554500, 0xfdd1180c, 0x36372312, 0x8f503637, 0x0fcf5c06, 0x59058543, 0x272008b9, + 0x0c755f18, 0x340b8d41, 0x191910ec, 0x0b0a070f, 0x0a0a0b06, 0x0909090a, 0x12112307, 0x41c18208, 0x293d068a, 0x0c0c0715, 0x1a190f07, 0x0908060f, + 0x6c226706, 0x14140e36, 0x0a090b14, 0xc744cd07, 0x261b8264, 0x1e1e1b1d, 0x410c1813, 0x58080aae, 0x0b180c0c, 0x051d0b0b, 0x12050808, 0x05121e1e, + 0x06060605, 0x21070707, 0x202d2728, 0x1a1a1d1d, 0x0f101314, 0x21140708, 0x08051420, 0x190f0507, 0x11351018, 0x37393826, 0x151a1b1d, 0x21141135, + 0x5349aa21, 0x05063853, 0x0e0e0a0a, 0x14131212, 0x1b1b1f16, 0x08090a16, 0x191b4100, 0x0d935d18, 0x640fc95a, 0x52180569, 0x07230efd, 0x59060706, + 0x3720051b, 0x0c815d18, 0x82081142, 0x0fe9331f, 0x050f1919, 0x67050909, 0x0d366d22, 0x0a141415, 0xf787090a, 0x1b820720, 0x0b071025, 0x820c070a, + 0x09092614, 0x12220809, 0x0af94111, 0x152a2008, 0x390c0c07, 0x15170c19, 0x0f121314, 0x060b0b0e, 0x170d0c06, 0x0e0b0b0b, 0x1d1e1e1a, 0x87080805, + 0x383921f8, 0x1041f888, 0x05334105, 0x06070538, 0x21070707, 0x202d2827, 0x1a1b1c1d, 0x0f101414, 0x21140707, 0x17419c21, 0x12112f05, 0x20161414, + 0x0a171b1a, 0x49050807, 0x1b415253, 0x00002905, 0x59023c02, 0x43003b00, 0x5e3d9943, 0xa1430805, 0x06235e34, 0xa8439920, 0x201c3c08, 0x191c1c1f, + 0x0f15141a, 0x34070710, 0x0b050512, 0x110e0e0b, 0x15131312, 0x18131316, 0x21073ef6, 0x5c18aa35, 0x5a200e07, 0xb143c785, 0x085d5e3b, 0x0832b943, + 0x8c01482a, 0x9974fe84, 0x06051135, 0x0d0d0a0a, 0x14131212, 0x13141516, 0x0e0e1112, 0x05050b0a, 0x07081235, 0x14150f10, 0x1c1c191a, 0x22098744, + 0x84990707, 0x00022cc5, 0x029dff2c, 0x00be023c, 0x47770059, 0x99420a43, 0x3ccd4309, 0x650ecf57, 0x654508e1, 0x42d2200f, 0x083405bf, 0x5e1c5606, + 0x0909062f, 0x13141205, 0x11101414, 0x06070e0d, 0x310ae343, 0x0a071e3b, 0x190e070b, 0x09040e1a, 0x1c540409, 0x61552e5c, 0x3eb93507, 0x07055bb6, + 0x4ae00508, 0x0b076dd9, 0x1f1a150b, 0x152a141f, 0x340aeb43, 0x09090504, 0x0e0e0b0c, 0x04630e0d, 0x0e040808, 0x3c0e1718, 0x23758214, 0x090a0410, + 0x34055065, 0x201e1b1a, 0x1b1a1c1c, 0x100f1414, 0x1f130807, 0x0804131f, 0x2e288409, 0x39251235, 0x1b1d3738, 0x1135141b, 0x8216170e, 0x20122a38, + 0x4c35011f, 0x05385556, 0x05334506, 0x1514142b, 0x0f121215, 0x090c0d0f, 0x071b4509, 0x22055741, 0x4179005b, 0x09441457, 0x9d61180e, 0x32332209, + 0x09914717, 0x41180b44, 0x15440a59, 0x55262015, 0x59410595, 0x09083f05, 0x5e1c5505, 0x0808052f, 0x802a7d05, 0x14140d41, 0x0a090a14, 0x03030207, + 0xc148da04, 0x0c820861, 0x0a0a092d, 0x1a190e07, 0x0e0c180e, 0x440d0d0d, 0x17210d23, 0x2939830c, 0x6dda4ae1, 0x6b0a0b07, 0x5d460406, 0x03032d0a, + 0x09090607, 0x0606060b, 0x1c1d1907, 0x080a5b41, 0x17160e26, 0x2611350e, 0x1e363938, 0x01141a1a, 0x1a021135, 0x04131d1d, 0x44040908, 0x090a0723, + 0x2828210b, 0x1d1d202d, 0x21051647, 0x57410707, 0x42302009, 0x142b07c7, 0x0f101614, 0x0c0e0e0e, 0x82050a0d, 0x4f472d00, 0x01000050, 0x9fff2c00, + 0x5a023c02, 0x63067146, 0xa7180f35, 0xe3470a09, 0x2215212d, 0x07d5a018, 0x30095941, 0x08162cf5, 0x84080c0d, 0x0b51a32c, 0x2d0b1414, 0x31044816, + 0x06376f26, 0x07060a09, 0x2b324583, 0x1a1051a2, 0x1120611b, 0x090f0f09, 0x160e143c, 0x78440e17, 0x1f1d2108, 0x21097844, 0x78443508, 0x05112717, + 0x09050808, 0x3d820e0f, 0x1e1f1222, 0x240a0b41, 0x17000061, 0x06394726, 0x2107c574, 0x01832322, 0x0ea16218, 0x20294548, 0x10a74707, 0x250e0d41, + 0x02060206, 0xaf4448da, 0x050c2109, 0x2e1a6948, 0x0e0e0706, 0x15151111, 0x0b141414, 0x41070c0c, 0xc344170f, 0x1414361d, 0x1d1d191b, 0x1a1a1f1f, + 0x13131617, 0x09090e0d, 0x0a090804, 0x09104106, 0x0000002f, 0xff420002, 0x022702f3, 0x003b005b, 0xd75b1853, 0x35102412, 0x18143332, 0x86184f9c, + 0x0607211d, 0x27200183, 0x08167767, 0x1bc10133, 0x2c2b2324, 0x1b1b2322, 0x0c0c1413, 0x16400606, 0x08090304, 0x12110c0d, 0x1c1b1716, 0x11111617, + 0x08080d0d, 0x16400404, 0x0c0d0606, 0x32821413, 0x059d721a, 0x19332108, 0x03030408, 0x060b0904, 0x0b060505, 0x1b13130c, 0x2e24251b, 0xe95d1601, + 0x1d1e2674, 0x0e0e1515, 0x04323683, 0x0e080804, 0x1d15150e, 0x0601261e, 0x2e7cf757, 0x69822524, 0x03bd1326, 0x1a350703, 0x2105db70, 0x07821b34, + 0x916bebcc, 0x87ca1809, 0x2bebb00c, 0x3f1540c0, 0x400d2616, 0x27154015, 0x8a3fe7b5, 0x0c23153c, 0x143c143c, 0x143d0b24, 0x2c000100, 0x3c023800, + 0x0f002302, 0x10370000, 0x18332035, 0x36084b83, 0x012c2015, 0xb4fe848c, 0x6e4d016f, 0x013874fe, 0x143c7b70, 0x8f3c53f8, 0x82342033, 0x20038233, + 0x21038223, 0x33831033, 0x33822d82, 0x74213982, 0x24308538, 0x007b90fe, 0x20678202, 0x20678206, 0x20678254, 0x66699117, 0x71860ccf, 0x2a05eb64, + 0x70520192, 0x49d9143c, 0x838c143c, 0x820020b4, 0x8e4b8f00, 0x894b8981, 0x284b8689, 0x48da143c, 0xaffe143c, 0x284b8871, 0x002f0001, 0x02390200, + 0x2197825b, 0xff833300, 0x22151023, 0x20078223, 0x36078223, 0x8288012f, 0xf8fe163f, 0xc4014058, 0x973cfe97, 0xfe838801, 0x8f008378, 0x83322033, + 0x843b82f7, 0x402f2907, 0x58080115, 0x79fe1540, 0x78213383, 0x31338383, 0x0300973c, 0x32002800, 0x2c024102, 0x83003f00, 0x39439b00, 0x26272111, + 0x0913cb18, 0x434e3720, 0x0f815106, 0x710bc56a, 0x59180bbd, 0xc34c0809, 0x0795510a, 0x0f9d7218, 0x200b9b43, 0x17954237, 0x199f2c08, 0x1c1d1a1b, + 0x19181b1a, 0x13111615, 0x0a0a0f0f, 0x04050504, 0x0f0f0a0a, 0x16161313, 0x19191819, 0x1b1b1d1a, 0x15161819, 0x820e1312, 0x05d26c1d, 0x0e0e2808, + 0x15151214, 0x131312cf, 0x13131414, 0x10111212, 0x0a0b0d0e, 0x04040807, 0x07060403, 0x07100b0c, 0x09080808, 0x18080708, 0x3e0c126f, 0x07070b0a, + 0x04030304, 0x0b0a0808, 0x10100e0e, 0x6823673a, 0x68113522, 0x34236722, 0x6d060a47, 0x1524082c, 0x18171715, 0x17247a82, 0x15171718, 0x0d237782, + 0x87090a0e, 0x82112077, 0x821d8277, 0x8518201e, 0x2079821d, 0xcc6e1831, 0x0f0d2409, 0x8211110e, 0x11122195, 0x0f2a0082, 0x06080e0f, 0x05040506, + 0x21890304, 0x100f0e28, 0x11121111, 0xb5821413, 0x0f0e112e, 0x0a0a0d0d, 0x31206103, 0x62216111, 0x60210582, 0x0ebf4121, 0xbf418b20, 0x6f272085, + 0x0120065f, 0x257baf41, 0x56040150, 0xa941fdfe, 0x3184267b, 0x00113111, 0x0ea34100, 0xa341b320, 0x39681886, 0x097f4a13, 0x1805914e, 0x82072558, + 0x7ccb4107, 0x1009032c, 0x1e120910, 0x1f12121f, 0x0b84121f, 0x121e1f2a, 0x131e1e13, 0x0a0f1009, 0x13270783, 0x0a131d1e, 0x83090f0f, 0x1e12220b, + 0x7bf5411e, 0x82081b21, 0x1d112b87, 0x1d11111c, 0x0e09111d, 0x0783080f, 0x17840383, 0x111d1c23, 0x21038211, 0x17820f09, 0x27820782, 0x450f1f42, + 0x27208683, 0x177dd218, 0x307bd343, 0x10100903, 0x15151009, 0x2d2d2b17, 0x0f10091e, 0x230b820a, 0x2d2c2b18, 0x2b80ef41, 0x1613140f, 0x1c2a2a29, + 0x090f0f08, 0xd7410b86, 0x869b450f, 0x35343727, 0x15143332, 0x7ccf4322, 0x205e1e23, 0x7bb3415f, 0x246c5826, 0x0400246c, 0x220cfb48, 0x45cb00ab, + 0x37238599, 0x63060706, 0xcb4e07b9, 0x1617210d, 0x277b0183, 0x7ce14127, 0x1010a03c, 0x181c1311, 0x0a131317, 0x0a040409, 0x100b0c09, 0x1211110f, + 0x1218181d, 0x11820914, 0x0d09092a, 0x0c09820c, 0x0c0e0e0c, 0x08e71d19, 0x0d820b20, 0x0d830b20, 0x05040422, 0x337b1d42, 0x0504093a, 0x12120909, + 0x121a1616, 0x0e0f1010, 0x08090b0c, 0x1322c383, 0x11841512, 0x0a0f0e2a, 0x0508370b, 0x09040404, 0x0d26d782, 0x090a0b0d, 0x00820509, 0x0b090923, + 0x210d820b, 0x0082000c, 0x5b420720, 0x00512a0a, 0x00750065, 0x00970085, 0x416142a9, 0x35340322, 0x0f297a18, 0x5307f75a, 0x142109b1, 0x79138707, + 0x16200703, 0x21059177, 0x1d523435, 0x85072005, 0x0a396945, 0x15143722, 0x820b0563, 0x3c3f424b, 0x0d0d9f3d, 0x0e0e0f0d, 0x02070f0e, 0x24200206, + 0x28185124, 0x02061828, 0x02020103, 0x820e0f0f, 0x0c0d3e19, 0x262722d4, 0x2b2b1a1a, 0x0303071a, 0x1aec0403, 0x061b2a2b, 0x04030404, 0x27272306, + 0x242e8264, 0x05020617, 0x24438403, 0x0c460d0d, 0x824b820d, 0x8207204f, 0x23202213, 0x3b1e4224, 0x6007012b, 0x0404012f, 0x0a0b0505, 0x089d830d, + 0x14141327, 0x17160e0e, 0x0203050e, 0x0d020203, 0x05050b0a, 0x6b010404, 0x14141295, 0x17160d0d, 0x1212100d, 0x11121313, 0x210b8336, 0x0b831111, + 0x82101221, 0x5ec5261b, 0x16160e2f, 0x86a4830e, 0x5e8c2133, 0x06205788, 0x2382f582, 0x63440020, 0x008b220e, 0x41014293, 0x2043614d, 0x49951827, + 0x3ceb410e, 0x223f594d, 0x844fee41, 0x3bd44101, 0x253f554d, 0x240c24c6, 0x0483730c, 0x4196b747, 0xa94107b1, 0x9607237c, 0xa5419733, 0x05514d7b, + 0x2800032e, 0x42023100, 0x07002b02, 0x27000f00, 0x2b06b551, 0x27201510, 0x35103320, 0x17102320, 0x08163f50, 0x9301282c, 0x406cfe87, 0xfe632901, + 0x74a363d7, 0x35277427, 0x75277511, 0x01313427, 0x85fe7e7c, 0x1801427f, 0x55e8fe5d, 0x1131246e, 0x0585246e, 0x00820020, 0x25526f8d, 0x206f8a07, + 0x06ef4e37, 0x19255f8c, 0xfe560401, 0x20598cfd, 0x05104e3d, 0x3f204f8d, 0x9b4dbf92, 0x35778c2e, 0x100f0942, 0x29291909, 0x2a291919, 0x0f100919, + 0x2a2a1909, 0x0b821a19, 0x0f0f0a27, 0x292a1a0a, 0x2117821a, 0x0b820918, 0x292a1826, 0x2a2a1819, 0x4e34a18c, 0x080f1008, 0x17272717, 0x18272718, + 0x080f0f08, 0x18272618, 0x10210b85, 0x83078308, 0x0f08231b, 0x0783090e, 0x28271723, 0x41cb8d00, 0x3224151b, 0x22151433, 0x8723a38c, 0x8c5f205e, + 0x6c112577, 0x00246c24, 0x01200082, 0x52066b7a, 0x3b8307f7, 0x3f822020, 0x82232021, 0x3f2c3243, 0x6f4d0115, 0x3f6fb3fe, 0xc497c401, 0xc4143c41, + 0x20339042, 0x95971821, 0x33322609, 0x01221510, 0x822f82e8, 0x153f2335, 0x3183c53f, 0x3cfe4123, 0x21678f97, 0x5f1a1021, 0x33830a47, 0x38a60a32, + 0xa6848c01, 0x88013f38, 0x3c143c83, 0x8378fe14, 0x02203382, 0x43289b82, 0x1a023c02, 0x19000700, 0x2008cf71, 0x064b4710, 0x210a5d68, 0x9b7a3c02, + 0x542a0805, 0x3d3e3f29, 0x171d1e20, 0x211d1d17, 0x433f3f3c, 0x133b3193, 0x9efe3293, 0x0f50a002, 0x0b161616, 0x08080a0b, 0x160b0a0a, 0x5e821615, + 0x5f8e0020, 0x35103727, 0x15141704, 0xf50d1904, 0x27262108, 0x14210185, 0x3c9c822c, 0x163074fe, 0x3d201d1e, 0x29293f3f, 0x203d3f3f, 0x43161e1d, + 0x94766101, 0x93143a31, 0x24548242, 0x1616150c, 0x2264870e, 0x410300b4, 0x01210557, 0x7bbb84ff, 0x10210961, 0x05094827, 0x0520bd8a, 0x8806cd42, + 0x3a2630c5, 0x1b1e383b, 0x3b26151b, 0x1c1e383a, 0x7b58fe1b, 0xfe2c0b61, 0x39730bdb, 0x0f10100a, 0x06070808, 0xeb200786, 0x09c74a18, 0x3c020022, + 0xd1997389, 0x73860320, 0x2720d986, 0x1c2a7184, 0x1b1c1414, 0x3a3b381e, 0x71855427, 0x62240129, 0x143b2775, 0x830b4574, 0x08072d6f, 0x08070605, + 0x10100f08, 0xf0fe810a, 0x2a089b5d, 0x02a9000e, 0x00b5015a, 0x47550035, 0x7d5b126b, 0x9340180d, 0x2b594b0a, 0x16023808, 0x15121211, 0x0f111114, + 0x090b0b0e, 0x03050608, 0x67ce4ee8, 0x09060603, 0x0e0c0b09, 0x1310110f, 0x10121214, 0x0a0c0d11, 0x04040509, 0x0c0a0905, 0x0b0a8a0c, 0x820e0f0c, + 0x830a2011, 0x820a2011, 0x05ec6711, 0x05050625, 0x8208ba06, 0x07042213, 0x263d8208, 0x0a0a0a0b, 0x830b143b, 0x09092400, 0x83030808, 0x0d092f3d, + 0x11100f0c, 0x11121311, 0x0c0f1011, 0x53853e0b, 0x0b0c092c, 0x0c0c0d0d, 0x05050909, 0x39820506, 0x794a0c20, 0x00012c05, 0x0233ff42, 0x00d70227, + 0x1a00003b, 0x2019dd81, 0x054d5615, 0x550a9755, 0x1d830b8f, 0x06423b08, 0x140c0c06, 0x231b1b13, 0x232c2c22, 0x141a1b23, 0x060d0c13, 0x04154106, + 0x0c090804, 0x1611120d, 0x171b1c16, 0x0c111117, 0x0408080d, 0x01cd4104, 0x252ee4ca, 0x131b1b25, 0xe7580c13, 0x2e252c0b, 0x01acfefd, 0x1d26debb, + 0x5814151e, 0x142a0be8, 0x261d1e15, 0x00a60dfe, 0xb3820100, 0xb3822620, 0xb383ca20, 0xfd4c0520, 0x2627290a, 0x10352627, 0x10333235, 0x821cb959, + 0x05b9591d, 0x2030b558, 0x08a98ac4, 0x2f252427, 0xfeac0202, 0x1e26de45, 0x0f14151d, 0x0308080e, 0x08030404, 0x140f0e08, 0x261e1d15, 0xfea6f301, + 0x252fe436, 0x2ce18324, 0x00020000, 0x023d0034, 0x001e0233, 0xc5a2181f, 0x0f315108, 0x8207495b, 0x362722d1, 0x05975d37, 0x01211382, 0x06c57934, + 0x16111f3e, 0x2f2d1816, 0x2f1f1f2f, 0x16192d30, 0x2f1f1016, 0x16182d2f, 0x2d5a1116, 0x1a2a2b19, 0x2b2b0583, 0x1515103d, 0x2d2c2a17, 0x8314101d, + 0x1e2c2a07, 0x2b2c2c1e, 0x10151417, 0x2607851d, 0x182a5561, 0x84182828, 0x82002005, 0x00012100, 0x4b777a18, 0xc200842b, 0xfb01e401, 0x00002300, + 0x07514c37, 0x1a234718, 0x0d07c82e, 0x2314080d, 0x2c5a1422, 0x070e0d08, 0x5a330383, 0x2222142c, 0x0d0e0714, 0x22221508, 0x22211515, 0x182516c2, + 0x21080647, 0x47181616, 0x25280812, 0x17170d16, 0x17170e0e, 0x4a18c382, 0xc52707ff, 0x4b004300, 0x42130000, 0x53180b11, 0x51180e29, 0xc76b0aab, + 0x0bc94208, 0x07496318, 0x18077b59, 0x180f1953, 0x372d5163, 0x848c01d3, 0x440174fe, 0x04020303, 0x0a060604, 0x1c360e0b, 0x060e0e1e, 0x08586318, + 0x01030222, 0x07586318, 0x07060c28, 0x02020304, 0x63180403, 0xa1200958, 0x3306847f, 0x00fcff01, 0x026a0200, 0x0015005b, 0x23222100, 0x27262734, + 0x0e094918, 0x375d013c, 0x8744431c, 0x305c2850, 0x2f050430, 0x27505b30, 0xd2434387, 0x465c9796, 0x02834645, 0x975c4624, 0x00820096, 0x332e4b8c, + 0x37362322, 0x33323536, 0x17161714, 0x71422322, 0x74062c05, 0x44872850, 0x431b3843, 0x844f8743, 0x3104224f, 0x203d8230, 0x224d84d2, 0x82474646, + 0x2e8e8201, 0xfdff2d00, 0x5e023b02, 0x77004300, 0x18050000, 0x651cf583, 0x142006d5, 0x09b94718, 0x200fd761, 0x20838233, 0x50438c35, 0x47180dc9, + 0xd7500df5, 0x31338305, 0x43873b02, 0x1d1f2022, 0x171a1a1d, 0x0c111216, 0x0082060d, 0x110c0d33, 0x19171611, 0x1f1d1e1a, 0x33982220, 0x1f214387, + 0x1093671e, 0x98221e3b, 0x16438732, 0x12111413, 0x0a0a0d0e, 0x06050506, 0x0e0e0a0a, 0x13141111, 0x23198316, 0x090c0c0f, 0x26081585, 0x0f0c0c09, + 0x06033298, 0x110c0b06, 0x18151510, 0x1e1c1b19, 0x1d201f1e, 0x191b1c1d, 0x10151518, 0x060b0c11, 0x66143c06, 0x1f2009fd, 0x3606fd66, 0x0708100f, + 0x05048c3c, 0x0d0d0a0a, 0x13131010, 0x13121414, 0x820d1010, 0x0405236d, 0x8545143b, 0x0b0e2806, 0x0509090c, 0x41003c05, 0x17201053, 0x462c935f, + 0xdd440b8f, 0x06072405, 0x8a272223, 0x34352343, 0xc16b2627, 0x84232005, 0xaf841815, 0x872d2217, 0x15fb6744, 0x82339821, 0x28f88319, 0x16161a1a, + 0x0c0c1212, 0x2d008206, 0x12120c0c, 0x191a1616, 0x1f201d1d, 0x21829922, 0x210bb446, 0x33830e0d, 0x20076464, 0x08e65a0a, 0x14141131, 0x3c039815, + 0x10080714, 0x1914140f, 0x411d1c1a, 0x10250733, 0x3c07070f, 0x086b4114, 0x1c1c1723, 0x2158821e, 0x6b411e1e, 0x3ca0290b, 0x09050514, 0x0d0c0c09, + 0x21063c41, 0x6441143b, 0x14122308, 0x64411314, 0x00003308, 0x2c000300, 0x3c022eff, 0x1f00dc02, 0x3b002700, 0x99740000, 0x07cd481f, 0x200a176f, + 0xdb431824, 0x3c022107, 0x251c8175, 0xfe848c01, 0x43188474, 0xfe2207f7, 0x108464d3, 0x74550121, 0x0d200d92, 0x0a23a182, 0x7407090a, 0x8d280892, + 0x143c143c, 0x1d3951fe, 0x2906ac74, 0x401b530e, 0x3c267515, 0xbf937513, 0x44181320, 0x06201779, 0x4906f541, 0x01200619, 0x2424b583, 0x04151437, + 0x090b4518, 0x46752c20, 0x11237607, 0xab854020, 0x884a8c20, 0xf5fe2205, 0x21c68786, 0x1c765501, 0x76ba820e, 0x8b200c1c, 0x7529be85, 0x74143b27, + 0x49154027, 0xd2441825, 0x82402007, 0x020022be, 0xa7451800, 0x00072207, 0x03831821, 0x6d9d8809, 0x16250b5b, 0x14171617, 0x75888c2b, 0x01210fff, + 0x2e6d88af, 0x39277513, 0x090a071c, 0x1415130b, 0x76140e0d, 0x738605d3, 0x4a002c21, 0x1b200747, 0xd1417389, 0x053f4a13, 0x8611b341, 0x0e934166, + 0x133b2723, 0x0c5f7175, 0x45002722, 0x09535f84, 0xb560180b, 0x82072014, 0x460120e7, 0x42180871, 0x57720a0f, 0x232b2908, 0x1a1a1e1f, 0x15151717, + 0x1424ca82, 0x15161414, 0x11260983, 0x24210e11, 0x5f712624, 0xd3012806, 0x4137372e, 0x714d4d41, 0x3d08087c, 0x65575649, 0x01575666, 0x061f3e2e, + 0x07070606, 0x090a0708, 0x0c0c0b0a, 0x10100e0e, 0x12111111, 0x4f101111, 0x1f1e2228, 0x16161a1b, 0x0d0e1113, 0x264bc3fe, 0x20292830, 0x0e181720, + 0x586f1a34, 0x4a303a06, 0x2d2d4426, 0x2d2e1216, 0x00020000, 0x0289ff2b, 0x00ad023b, 0x00410023, 0x72b38a00, 0x09540d3f, 0x4201200a, 0x1f8d0591, + 0xf582d785, 0x723b0221, 0x252b07df, 0x0f222424, 0x14151111, 0x82161515, 0x11360804, 0x211f1e1c, 0xfe2b2b22, 0x57574825, 0x57576465, 0x38382d49, + 0x4c4c4343, 0x4d4c5855, 0x38374141, 0x1f3e8b01, 0x110e0d09, 0x1a171612, 0x221e1f1b, 0x1110284f, 0xd5821212, 0x10102a08, 0x110b0e0e, 0x0c0c0f0f, + 0xf6fd0a0a, 0x2d47264b, 0x2d16122e, 0x254b442d, 0x21282830, 0x0d171721, 0x180e1a34, 0x29202017, 0x20cf8428, 0x22cf8251, 0x777d00e5, 0xfb6f0ce9, + 0x0b137609, 0x700df373, 0x11702115, 0x3207220c, 0x090b7d31, 0x70112574, 0x73860b33, 0x190fd828, 0x08061019, 0xd4820908, 0x280b2c08, 0x1f352e2e, + 0x1b1b1d1e, 0x06161818, 0x350d0403, 0x2d443b3c, 0x28282a2a, 0x06181f1f, 0x0d050807, 0x100d1616, 0x070f1919, 0x82070d0c, 0x1f143423, 0x08272323, + 0x03090504, 0x33050504, 0x2a292e2d, 0x82403534, 0x042a0827, 0x1d010101, 0x1f201e1e, 0x14191c1c, 0x1e1e191a, 0x09242121, 0x01020605, 0x16040203, + 0x054c191a, 0x1a090202, 0x0c1a1a19, 0x01820b0a, 0x05af0a37, 0x13040807, 0x301b1817, 0x0f223333, 0x3e070b0c, 0x0506041f, 0x08948206, 0x0a130830, + 0x10152709, 0x1a340a10, 0x0c0a0a07, 0x0c0c0d0c, 0x02040403, 0x27414128, 0x04080804, 0x16232416, 0x15151514, 0x1b1f264b, 0x0d18151b, 0x23821d0c, + 0x20181033, 0x264a2620, 0x2226262c, 0x0e151613, 0x14140f01, 0x26008218, 0x17284f1a, 0x82181819, 0x05173d02, 0x01010304, 0x43020201, 0xee014b4b, + 0x1a06060c, 0x05070609, 0x03020302, 0x00040303, 0x02230082, 0x41ff2b00, 0x6f2205af, 0x0b7d7b00, 0x0567420e, 0x45076f77, 0xa7790d07, 0x13e37709, + 0x710fad70, 0xa14115df, 0x37322905, 0x27222726, 0xb9141506, 0x08059d7e, 0x1d080d28, 0x23161a1b, 0x0a2b2627, 0x3b140504, 0x33263130, 0x06403a3a, + 0x470a0202, 0x16373e3f, 0x1f1e1a1b, 0x05212020, 0x00840605, 0x3b0ad170, 0x0707080e, 0x2b2a2706, 0x3939402e, 0x340b1733, 0x2f4f4242, 0x2425292a, + 0x031c2020, 0x0a3ff082, 0x080e0f0e, 0x03b70706, 0x03030505, 0x01030404, 0x080705af, 0x29281904, 0x18191919, 0x83284f19, 0x0f1d3f27, 0x24213b0e, + 0x254b2824, 0x19242430, 0x1e08080f, 0x35272618, 0x1718254c, 0x12161517, 0x38411013, 0x02390805, 0x44453c02, 0x0808042d, 0x2e2d1e04, 0x1516172c, + 0x090a0c10, 0x0a1a3408, 0x44130f0f, 0x12121821, 0x071f3e0b, 0x0c0c0a09, 0x0211100f, 0x1e010202, 0x172a2d2c, 0x24021415, 0x30008501, 0x00000102, + 0xff2c0002, 0x023c02b2, 0x003100a8, 0x0c876a3f, 0x4b351021, 0x671809c1, 0x0d8c0d09, 0x25852720, 0x2e056769, 0x190fc114, 0x0e080e19, 0x1c56090d, + 0x820a6cd7, 0x180f3d81, 0x0d090f19, 0x1c55080e, 0x1a113162, 0x0c0e191a, 0x48d8090c, 0x120b6bd7, 0x162a4a12, 0x070bb11a, 0x4e339933, 0x06090906, + 0x13212113, 0x197b7001, 0x05192a29, 0x3c0e820a, 0x3c132120, 0x3d3d2814, 0x1c1d1f3b, 0x19143c16, 0x29bc292a, 0x203b3c3d, 0xf8161c1c, 0x18bb9b00, + 0x6f0ba95d, 0x32251143, 0x22151033, 0x20c58223, 0xa7941837, 0x21bb8a0c, 0x99873263, 0x8f48d921, 0x24bb84c7, 0x29339851, 0x88cf8615, 0x143c21ba, + 0xab829d87, 0xfe22c38a, 0xba837b90, 0x8653f821, 0x2bba82ca, 0x2c000100, 0x3c02a5ff, 0x35005402, 0x870c7541, 0x232221b9, 0x6a0dcb66, 0x0d25137d, + 0x080c1514, 0x057f6a0d, 0x10100a25, 0x664ade0a, 0x643f08ef, 0x04050332, 0x0d0d0703, 0xa22c8408, 0x1b1a1051, 0x1010095b, 0x0e0f0909, 0x0c143c09, + 0x660b1312, 0x02230894, 0x6a020404, 0x1222056f, 0x98821f1e, 0xad6697a1, 0x6697a60d, 0x979f07c9, 0x9108e066, 0xff2b2897, 0x013b027f, 0x186b00ff, + 0x180a5fa1, 0x7b1d6b70, 0x4e1809ff, 0x15201421, 0x1806f74c, 0x710d7366, 0x6d18054d, 0x013009bd, 0x14150d2d, 0x0b0a070e, 0x03040406, 0x0d040803, + 0x26390082, 0x26232524, 0x0f272626, 0x0b0c0c0d, 0x1007090a, 0x17171108, 0x31313019, 0x12a17f20, 0x3d3d2432, 0x08080525, 0x15141605, 0x23232212, + 0x12121124, 0x70180282, 0x082409a2, 0x03810909, 0x1a265b82, 0x011b2b2b, 0x01820201, 0x01010322, 0x07944218, 0x032e0e82, 0x42030302, 0x06070521, + 0x0f0e0e08, 0x4e183c09, 0x3a2c14ac, 0x12120b1c, 0x2020140b, 0x05040814, 0x0c4a4518, 0x0203012d, 0x20050304, 0x00002424, 0x41000100, 0x75200743, + 0x21284341, 0xa9493736, 0x0d774507, 0x10a54018, 0x79080f6c, 0x49821969, 0x2b234d41, 0x04070706, 0x2f313120, 0x1216171a, 0x2f12b84a, 0x2829291b, + 0x0f131415, 0x060b0c06, 0x060a0a06, 0x233b5741, 0x131c1c19, 0x21068f45, 0x45183905, 0x3431148d, 0x0c0d071b, 0x0606060c, 0x02020204, 0x28281901, + 0x19614118, 0x2b00022c, 0x3b0232ff, 0x1d00ad02, 0xa37a6b00, 0x5703201f, 0x0b830bbb, 0x69182620, 0x37690933, 0x0e676508, 0x16e14718, 0x06070622, + 0x2118b17a, 0x73180dcf, 0x0d210e47, 0x4773180d, 0x0fa44223, 0x0c0c0b22, 0x2b1ebe7a, 0x0405031a, 0x39392104, 0x01020122, 0x7a09c342, 0x023307d2, + 0x2e270302, 0x04031e2d, 0x37200304, 0x04082036, 0x180e0e03, 0x290af047, 0x04020201, 0x302b0404, 0x43410030, 0x1dcb7a0e, 0x43411320, 0x17d97a4c, + 0x4241c920, 0x1de77a48, 0x419efe21, 0x00294542, 0x00280003, 0x013f02e6, 0x6f7d1876, 0x6e372007, 0x451916a9, 0x179717db, 0x18409721, 0x200d4b79, + 0xa47a18c5, 0xf345190e, 0x04e6270f, 0x264c0704, 0x00820407, 0x002c07a5, 0x49000100, 0x1f0281ff, 0x2300c900, 0x0a47bb18, 0x09896e18, 0x20079b4b, + 0xff981832, 0x01440807, 0x15140f34, 0x2c2b2a16, 0x121c361c, 0x0f1b1d1c, 0x130a0d0d, 0x0e1c1c1c, 0x360a0d0e, 0x2b2b1d1b, 0x1414162a, 0x1c1c167f, + 0x3c3d3a1f, 0x27281a28, 0x12121526, 0x27271a0e, 0x13121427, 0x3d3c280e, 0x1c1c1f3a, 0x26087783, 0x0181ffe7, 0x00db02bb, 0x1700000b, 0x33323510, + 0x23221514, 0xe7221510, 0x1e59359f, 0x84027f46, 0xfd1032d6, 0x8200c6ae, 0x00012200, 0x202b82ad, 0x202b8581, 0x05135a05, 0x82333221, 0x25012f2b, + 0x359f1e5a, 0x52027f45, 0xfd1131c6, 0x2b84d77d, 0x1021578f, 0x255b8415, 0x591746e7, 0x57839f1e, 0xc5affd24, 0x57901133, 0x82341721, 0x82878383, + 0x5aad2b57, 0x9f17451e, 0x0211337f, 0x5685c551, 0x00010029, 0x02ae002c, 0x8396013c, 0x343722af, 0x09fb5a35, 0x848c012d, 0x3f6fb3fe, 0x3d3aaeae, + 0x84267114, 0x00012d57, 0x26020fff, 0x45007d03, 0x10050000, 0x0fe78718, 0x0c3d8f18, 0x240f5557, 0x27342734, 0x44038426, 0x1423059f, 0x82070607, + 0x01250891, 0x02010100, 0x07060404, 0x180b090a, 0x16312524, 0x0d0c1111, 0x05040606, 0x0b0b0807, 0x09090a0f, 0x05060606, 0x05664a03, 0x02020122, + 0x30080282, 0x040f0f1a, 0x4a010102, 0xca9401f1, 0x1e131408, 0x2b34343e, 0x1a22222b, 0x051a1a35, 0x0c0a0a05, 0x0a0d100d, 0x0307070a, 0x04030204, + 0x09050605, 0x82098203, 0x0603230a, 0x36820303, 0x4949012b, 0x29282391, 0xa318fe1a, 0x28fb8200, 0x011cff3e, 0x008a0363, 0x8acf823d, 0xff5b18b1, + 0x07e9520f, 0x37323328, 0x35363736, 0x4f413736, 0x15142205, 0x06335114, 0x2c010627, 0x31242418, 0x20bd8217, 0x27bd820c, 0x0a080804, 0x090c0e0b, + 0x04218782, 0x82b58205, 0x030222e3, 0x82b98304, 0x194a2dc9, 0x04050101, 0x09090707, 0x1a1a347c, 0x20057852, 0x24b3840f, 0x02030404, 0x33b38206, + 0x06060507, 0x04040808, 0x23924849, 0x011b2828, 0x6cfea3e8, 0x1424eb82, 0x35343d1e, 0x0020eb83, 0x012d0082, 0x08ff8c00, 0x8903dc01, 0x00002b00, + 0x055a1817, 0x08d74211, 0x0ce95918, 0x15145108, 0x06068c22, 0x0f100c0c, 0x15141413, 0x16161716, 0x1a1a3614, 0x14141717, 0x0d0e1110, 0x08090c0c, + 0x04040706, 0xf8490202, 0x606b2549, 0x4a535460, 0x353f3f4a, 0x262d2e36, 0x2f311e25, 0x2c2d2c30, 0x2f2d2d2d, 0x37323230, 0x433b3b37, 0x1c524944, + 0x0d268b87, 0x8a03ee00, 0x8b820700, 0x32111036, 0x22111033, 0x4919498c, 0x015e03f3, 0xfea3fc1f, 0x010000e0, 0x1920af82, 0x8a20af82, 0x9119af83, + 0x272109fd, 0x18018526, 0x5407b788, 0x09870953, 0xdc014a08, 0x181a1b35, 0x15171719, 0x0e121214, 0x050a0a0e, 0x02194905, 0x08060603, 0x0d0a0b08, + 0x120e0f0d, 0x13121111, 0x2c26e713, 0x3831312c, 0x473e3e38, 0x574e4f46, 0x1b526057, 0x48512449, 0x3a404048, 0x2f33343a, 0x292b2b30, 0x206a8229, + 0x41af8727, 0x0520083b, 0x0cc3a218, 0x08c34118, 0x77092944, 0x153a0819, 0x027b0122, 0x07040402, 0x0c080906, 0x100e0e0c, 0x17141411, 0x1a361a17, + 0x00821615, 0x15153308, 0x0f101313, 0x05060c0d, 0x2549f849, 0x3b434449, 0x3236373b, 0x2e2f3032, 0x2d2c2d2d, 0x312f302c, 0x2d26251e, 0x3f35362e, + 0x534a4a3f, 0x6b606054, 0x8c821c52, 0x7b010126, 0xdc010dff, 0x20053b41, 0x063b4105, 0x497b0123, 0x0a3c4118, 0x200c3b41, 0xebb11817, 0x0a295209, + 0x41073f41, 0x07240bed, 0x1b35dc06, 0x12249582, 0x0f111012, 0x0b3a9982, 0x0608080b, 0x49030306, 0x0a040518, 0x120e0f0a, 0x18141511, 0xe7191817, + 0xf6822726, 0x29292208, 0x2f302b2b, 0x3a3a3433, 0x48484040, 0x491b5251, 0x57576024, 0x47464f4e, 0x38383e3e, 0x2c2c3131, 0x83878300, 0x447e20ab, + 0x112105db, 0x05db4432, 0x8c221126, 0x3bb354fc, 0x5529b082, 0x17451c01, 0xfbfef0fc, 0x422b8500, 0x0b202813, 0x84083742, 0x498c2753, 0xfc3bb319, + 0x4f8203e7, 0x45214d83, 0x224f8617, 0x8403dc01, 0x1005227b, 0x058d4d11, 0x01250782, 0xfc3cb37b, 0x227c8254, 0x82050110, 0xfeab237c, 0x534100e4, + 0x00832407, 0x41000007, 0x59260e53, 0xa8fc1d01, 0x8f42e2fe, 0x84832008, 0x353423cb, 0x7b413332, 0xb38c3006, 0xfc18493c, 0x031745e7, 0xfc04010a, + 0x82e6feb0, 0x0601257b, 0x600205ff, 0x1f207b82, 0x34204f84, 0x0bd38818, 0x080c5958, 0x22151037, 0x07070601, 0x13120d0d, 0x1b1b1817, 0x5d22671f, + 0x1515192f, 0x08080f0f, 0x5602fb46, 0x20232b01, 0x161c1c1f, 0x09101016, 0x0b153e09, 0x1d16160c, 0x5cfd241d, 0x296382e1, 0x0dff0800, 0x89036301, + 0x63824f00, 0x22159342, 0x57262322, 0x7f890579, 0xfb410983, 0x06af420e, 0x21073f43, 0x93831415, 0x02023108, 0x06050303, 0x0a0a0708, 0x100f0e0d, + 0x16171313, 0x0809081a, 0x200a1506, 0x16151b1b, 0x0d0c1211, 0x05050909, 0x17460303, 0x09190d0d, 0x08100c0c, 0x073fc682, 0x0c040505, 0x06060a0a, + 0xf3460304, 0x222a52a5, 0x151a1a22, 0x0b0f0e15, 0x0507070a, 0x83010204, 0x16422200, 0x375a8201, 0x0d0d0908, 0x1c1d1515, 0xba332828, 0x6754a83d, + 0x0d244546, 0x04080b0b, 0x3106d550, 0x221a1912, 0x362c2d21, 0x01003fbd, 0x19ff0601, 0xe7826002, 0xf5591f20, 0x05795d0f, 0x59141121, 0x34080a9d, + 0x1f2e5b60, 0x17181b1b, 0x0d0e1212, 0x17460707, 0x0f0f0808, 0x69191515, 0x0808e723, 0x16171010, 0x20201c1b, 0xde9b0223, 0xd6feadfd, 0x161d1d24, + 0x3f0a0b17, 0x24638400, 0x03630109, 0x0cff418c, 0x17460634, 0x6303f746, 0x9efc2001, 0x0100dffe, 0x05ff0800, 0xd3416201, 0x18db5809, 0x22151024, + 0xda7c0501, 0x23693406, 0x1c1f2d5c, 0x1218181b, 0x070d0d12, 0x02fb4606, 0x832c0159, 0x0c162678, 0x08153e0b, 0x27938309, 0x201f1c1c, 0xe05ffd23, + 0x05228783, 0xeb840dff, 0x4106d341, 0x714e0ab7, 0x26272108, 0x2715fb44, 0x14333233, 0x22072215, 0x10f56d18, 0x06070623, 0x08198215, 0x0405013c, + 0x09070603, 0x0c0b0c0a, 0x08070e0d, 0x06060607, 0x0d190505, 0x0317460d, 0x09050603, 0x110d0c09, 0x1a161512, 0x0717211b, 0x050a0a05, 0x1416161b, + 0x0d100f13, 0x080a0a0d, 0x3b820508, 0x46020233, 0x3654a8f3, 0x22212d2c, 0x0e12191a, 0x04070b0c, 0x05ae4105, 0x46452439, 0xa43fbd67, 0x28283353, + 0x15151d1c, 0x08090d0d, 0x01020303, 0x83011d3b, 0x04023900, 0x0a070705, 0x150e0f0b, 0x221a1b15, 0x3eb92a21, 0x08000100, 0x620119ff, 0x2005d341, + 0x0b315a17, 0x32351025, 0x47111033, 0x07260825, 0x08222306, 0xf77e2e5e, 0x08340805, 0x07061746, 0x12130d0d, 0x1b1b1818, 0x3ee7671f, 0x170b0a15, + 0x241d1d16, 0xfddf9e02, 0x23d7feb0, 0x1b1c2020, 0x10101716, 0x00000808, 0x00010100, 0x63010fff, 0x3b0e2745, 0x4a194a00, 0x015d03f1, 0xfea4fc1e, + 0xff0100e1, 0x022301f6, 0x00740173, 0x03000007, 0x2b06cb48, 0xa0dd010a, 0x230122fe, 0x143d153c, 0xff234783, 0x82fa00f6, 0x839c2023, 0x8c272023, + 0x79fa2423, 0x82287a29, 0x266b8222, 0x0107ff0c, 0x4294035c, 0x0c2c0c3f, 0xf93c143c, 0x23016a03, 0xddfe96fc, 0xe420f382, 0x84202382, 0x17202385, + 0x23063b44, 0x782878e4, 0x00232289, 0x821e0003, 0x844b208f, 0x000f238f, 0x34190017, 0x332708db, 0x33323534, 0x87221514, 0x6d1e2407, 0x82aa6d24, + 0x6da92303, 0xa9856d25, 0xb184ad83, 0xaf824382, 0x83014b21, 0x204384af, 0x933b8e37, 0x83c98443, 0x24d185cd, 0xff0c0103, 0x20cf8243, 0x84cf8253, + 0x86012043, 0x8e032043, 0x83012007, 0x821420e3, 0x320383e7, 0x49d93102, 0x88fe49d9, 0x49da49da, 0x48da8afe, 0x820048da, 0x00032200, 0x214b82e4, + 0x4b880384, 0x438e1320, 0xe4225387, 0x01882878, 0x04204a92, 0x200e1b41, 0x191d411f, 0x462ee188, 0x46834718, 0x47824618, 0x47834717, 0x29414818, + 0x413c200d, 0x578205df, 0x820c2f41, 0x17314157, 0x3d415797, 0x0541410c, 0x04000022, 0x820e4341, 0x17454157, 0x41070141, 0x142e0c4d, 0x023c143c, + 0x9431948e, 0x93e7fe31, 0x05829331, 0x00200b89, 0x04200082, 0x410e5741, 0xa5410a0f, 0x1361410f, 0x28782823, 0x205e9878, 0x29bb8201, 0x01730207, + 0x000b0074, 0x0f540500, 0x23223605, 0x01221510, 0x5a0d010c, 0xf93c46d1, 0x3d9bd201, 0x876bfe14, 0x05fb4200, 0x9c202b82, 0xf0262b99, 0xfe287aa5, + 0x2b827d8a, 0x5788b382, 0x578a1720, 0x2b01e426, 0x783cb364, 0x2f43568a, 0x94578705, 0x2756882b, 0xf6ff0100, 0x5c0107ff, 0x2220af88, 0x8206537b, + 0x45d124af, 0x82590d01, 0x879526af, 0x2efe153c, 0x8683829b, 0x92af872b, 0x7d76262b, 0x10fe2979, 0x202b87a5, 0x82578584, 0x252b8883, 0x013bb3e4, + 0xaf82632b, 0x83865688, 0x84018421, 0x882b9457, 0x01002b56, 0x23010c01, 0x94037302, 0x64820b00, 0x32351023, 0x059b4d33, 0x0c012032, 0x46d1143c, + 0x2301f3fe, 0xfe9cd501, 0x143d8868, 0x00212b83, 0x202b87fa, 0x282b9225, 0xa6f401fa, 0x7a7e86fe, 0x214a8228, 0x5789e400, 0x2b8a1320, 0x2878e426, + 0xd5fe3cb3, 0x0023568a, 0x89e40001, 0x91372057, 0x45568a2b, 0x01210527, 0x20af855c, 0x091f4e03, 0xd10a2025, 0x83143c45, 0x153c27ae, 0xfe889801, + 0x83829c2b, 0x00f6ff23, 0x202b87fa, 0x292b9127, 0x012979fa, 0x0dfe7e7a, 0x2b8400a7, 0x84209282, 0xb3235792, 0x8328783b, 0x86578faf, 0x85578c2b, + 0x42578c2b, 0x578205bf, 0x49000f21, 0xfb4e06cf, 0x05c34205, 0xd1143c25, 0x4546d146, 0xfe22059b, 0xc8428868, 0x06f34205, 0x862133a4, 0x05d0427e, + 0xcf420120, 0x20338205, 0x22678313, 0x41232235, 0x2f430947, 0x0a1e2506, 0x3cb32878, 0x01226d83, 0xd4418795, 0x6bfe2207, 0x07df4287, 0x17203b85, + 0x07423784, 0x223b8408, 0x830a1ee4, 0x061643a8, 0x88980122, 0x3b8aaa88, 0x4b46df82, 0x20df8905, 0x837083e4, 0x6a032335, 0x33932301, 0x7621aba3, + 0x0755427d, 0x7d8afe22, 0xf025abad, 0x7e7a01a5, 0x072241fe, 0x3389abab, 0x4105a343, 0x3520078b, 0x2d06bb4b, 0x10333235, 0x0c012211, 0x45d145d1, + 0xd443143c, 0x98012206, 0x055f4788, 0x762333a6, 0x8229797d, 0x20338aa0, 0x0abf4184, 0x2309af42, 0x15102322, 0xb3256b84, 0x1e28783b, 0x256d890a, + 0xfe9c2bfe, 0xef43876b, 0x08bf4107, 0x1520a38a, 0x1524a782, 0x3bb3e422, 0x1e21a683, 0x0626440a, 0x4405c141, 0x77830a83, 0x00000f22, 0x82062b44, + 0x82df8533, 0x89728337, 0x8daa8435, 0x09fb516f, 0x2f523383, 0x0c012305, 0xab8845d1, 0xfe25e586, 0x8afea70d, 0x8d3b8d7d, 0x87ab916f, 0x7e86213a, + 0x410b0345, 0x3b8d058b, 0xe3831120, 0x5641ab86, 0x246f850b, 0x74017302, 0x86df8200, 0x332021ab, 0x8306d752, 0xdd0122a7, 0x061243a0, 0x43153c21, + 0x3388057e, 0x42009c21, 0x6b49079f, 0x080f5305, 0x0d213784, 0x05ba4359, 0x6f830120, 0x9a0a1e21, 0x3332213b, 0xc7413f85, 0x45d12108, 0x2507bb46, + 0x153c8795, 0xc2430a1e, 0x9e778a05, 0x8e7183ab, 0x45df8433, 0xdf8608eb, 0x3bb3e422, 0xb321de82, 0x06c0413c, 0xdf8da286, 0xdf88338a, 0x21055346, + 0x39843cb3, 0x3b94de8c, 0x3b82df8c, 0x43477582, 0x8dde8c06, 0x8aab9adf, 0x463383de, 0x0f220647, 0xef450000, 0x45ab830a, 0xd12105f3, 0x05224b46, + 0x2205d442, 0x8300143d, 0x064f4633, 0x00001322, 0x850a9f45, 0x151421df, 0xd1233787, 0x45f3fe46, 0x682506ab, 0x1f143d88, 0x0507460a, 0x25203b89, + 0x46071b71, 0xf3430ceb, 0x213c8405, 0x15460a1f, 0x06f34605, 0x42059f4b, 0x778e059f, 0x7186ab89, 0xdf9e3285, 0x783bb325, 0xb13cb328, 0x823785df, + 0x9cd52039, 0x3b4218df, 0x22df8a08, 0x853bb3e4, 0xd5fe223d, 0x41de8dfa, 0x0f200a57, 0x21105741, 0x35860a20, 0xdf902220, 0x0207ff29, 0x00940373, + 0x44000017, 0x4f430e2b, 0x45d1210c, 0x22070b47, 0x41879501, 0x0f470555, 0xf6ff2108, 0x044443b0, 0x08744606, 0x43b20120, 0x63478787, 0x4443b208, + 0xb04309c2, 0x4187a805, 0x9a44054e, 0x0b744708, 0x0745438c, 0x0a7b470d, 0x2105f345, 0xfe4346d1, 0x0db74708, 0x439acb8b, 0x439f8685, 0xdb411b20, + 0x0a674516, 0x1e244887, 0x01f93c0a, 0x210b9d41, 0x17460a1f, 0x73022408, 0x89009403, 0x0dc7464b, 0x1e214b88, 0x07a2420a, 0x8446d121, 0x0ba6424b, + 0xdb924b90, 0x47087742, 0xea440817, 0x0531480a, 0x850fcf45, 0x474b8897, 0x4b8b099b, 0x493bb321, 0xfa440a27, 0x0d7f4805, 0x41273f42, 0x3f420afb, + 0x22db921c, 0x47102322, 0xfb4108ef, 0x45428f06, 0x93430787, 0x41439a05, 0x4e430afb, 0x4343b30f, 0x43b30f4e, 0x0220cb90, 0x500c8b4f, 0x1e2410a5, + 0xf7ba3eba, 0x6f4f0382, 0x00002509, 0x1e000200, 0x200a674f, 0x0f634f00, 0x4b4f3387, 0x2d328208, 0x0c010200, 0x5c0169ff, 0x07002d03, 0x294d0f00, + 0x03222108, 0x20053945, 0x082f4f22, 0x019c0129, 0xd3fe642d, 0x83cdfd64, 0x65d42107, 0x00213b84, 0x203b82e4, 0x4d3b8784, 0x3b88060d, 0x6b50e420, + 0x283a9006, 0x00f6ff02, 0x017302d2, 0x207385c5, 0x05454803, 0x08c17e18, 0x20051d52, 0x0523529f, 0x153c7425, 0x6fa2143d, 0x02280534, 0x07ffbc00, + 0x9403ac01, 0x954b3785, 0x22112105, 0x24072556, 0x3c143cbc, 0x0b10528c, 0x82081852, 0x067b4cac, 0x13207382, 0x180a6f4f, 0x4f076b76, 0xfb480977, + 0x0e022205, 0x277283b0, 0xa8fe143d, 0x01000073, 0xaf827783, 0x82007421, 0x0b274f3b, 0x35102324, 0x3b822322, 0x4901bc25, 0x8232956e, 0x4f14207a, + 0x012609b6, 0x6bfe8795, 0xb3840087, 0x0b24eb84, 0x00001700, 0x20203d86, 0x33203583, 0x830a895c, 0xf3fe2641, 0xd18c3c5a, 0x20488246, 0x227f84f9, + 0x829b2efe, 0x4b838744, 0xbf88057b, 0x47054344, 0x202105c7, 0x21bf8433, 0x018345d1, 0x2a058b4f, 0x143d7358, 0x153c153c, 0x82b0f2fd, 0x213b84bf, + 0xbf8701ac, 0x8808634f, 0x319524bf, 0x866e4801, 0x066f4fbf, 0x3b86bf87, 0x8400c521, 0x100523bf, 0xf94f2035, 0x203d8407, 0x051d4b34, 0xfe5c0124, + 0x438359f3, 0x3195b429, 0xf93c45d1, 0x849bd201, 0x8301207c, 0x6bfe2a88, 0x01010087, 0x02d2000c, 0x05cb4b73, 0x210a634f, 0x83412322, 0x06974f05, + 0xd146d12c, 0xd2f3fe46, 0xfeb01202, 0x824174a5, 0x21bf8205, 0x2b49bc00, 0x00132206, 0x06654200, 0x2606cb4b, 0x14333215, 0x84bc2015, 0x951424ba, + 0x4fb7fe32, 0x3549077f, 0x00002409, 0x86bc0002, 0x4fc3847b, 0x20200689, 0x954f3983, 0x8222200a, 0x0d012645, 0x32b7fe5a, 0x2049823c, 0x248384d1, + 0x143d9c2b, 0x834a83a2, 0x0100278c, 0xd200f6ff, 0xc3855c01, 0x42192720, 0x2d430baf, 0x0a202105, 0x21058241, 0xc282143c, 0x26057f41, 0xfd735c01, + 0x8200b1ef, 0xf6ff21c3, 0xac209a82, 0xef493b85, 0x213b870c, 0xc5853195, 0x2748c383, 0x07f14f07, 0x7b84c382, 0xc3843f83, 0x20217d82, 0x49398633, + 0x22240a91, 0x590d010a, 0xb7217e82, 0x264d836d, 0x143dd2d1, 0x829cd501, 0x82a22080, 0x735c2450, 0x528868fe, 0x2345074b, 0x05875905, 0xeb451520, + 0x0c0b4305, 0x4f05b348, 0x8d410ac3, 0xa8fe2307, 0xd3420073, 0x20438206, 0x05d34207, 0x43055d5c, 0xa9470587, 0x068f4309, 0x95329523, 0x09a45532, + 0x220d314f, 0x43030000, 0x4b84055b, 0x1f001322, 0x2008735a, 0x08e74122, 0x44151421, 0x27470551, 0x83558806, 0x21598b9c, 0xa8416d02, 0x93fd2107, + 0x49103743, 0xff4a0ea7, 0x07ef4e0c, 0x4308f34e, 0x0128073c, 0x96fc735c, 0x0200ddfe, 0x82050343, 0x850f2043, 0x0d2d4fef, 0x23087f44, 0x31953195, + 0x49078344, 0x408307ec, 0x200b8744, 0x214b8803, 0xef84000b, 0x210a0b42, 0xb3560122, 0x0b594306, 0x53830a20, 0x2101d122, 0x5b435882, 0x74012105, + 0x2107cc41, 0x598793fd, 0x85086643, 0x450220ab, 0x1720055b, 0x20097157, 0x0edd7a13, 0x22056345, 0x4e45d177, 0x53830526, 0xfd143d23, 0x44478493, + 0x00200671, 0x2008d74c, 0x4ef58a74, 0x3b440863, 0xa0dd210b, 0x2108fd44, 0x6e4e8795, 0x063f4406, 0x8f86ef84, 0x4383ef87, 0x07712919, 0x10333224, + 0x09452215, 0x2499850b, 0xd1319527, 0x060d4545, 0xfe229c8c, 0xdc41876b, 0x06474608, 0x43079741, 0x85180c55, 0x0a200a11, 0x2105824b, 0x524622fe, + 0x5c012509, 0x74a5fe73, 0x58075846, 0x234206a3, 0x4c458c05, 0x0a210a3f, 0x069f4395, 0x4c329521, 0x67440bb7, 0x44eb820b, 0x1f200a67, 0x210cd74d, + 0x4b892122, 0x46052221, 0xdb4106f1, 0x32952409, 0x4654fed1, 0x9e8308f1, 0x42886821, 0xfd4607ce, 0x088f4106, 0x2720a782, 0x420a974a, 0xcb430ccb, + 0x05944413, 0x21050441, 0xd34346d1, 0x42012005, 0x69450ae3, 0xa8fe2208, 0x07f34173, 0x43496385, 0x0e7b5310, 0x410a0342, 0x0a42091d, 0x051e410c, + 0x420aa14b, 0x00210616, 0x08334a04, 0x17000b26, 0x2f002300, 0x20192d41, 0x0a856303, 0x430c2942, 0x95230819, 0x42e6d132, 0x42410e30, 0x06d9420d, + 0x480b3c42, 0x74200a13, 0x5e069b4b, 0x2f081443, 0x22151015, 0x05050c01, 0x0f0e0909, 0x18181312, 0x7e2f8e1c, 0x17162d3f, 0x1901f93c, 0x18181a8d, + 0x12121717, 0x08070e0e, 0x1e1e143d, 0x6ac4fe3a, 0xdb835783, 0x015c0122, 0x27215788, 0xb55d1826, 0x31578412, 0x8d2d1716, 0x1c3f7d2f, 0x14131717, + 0x0a0a0e0e, 0x57840504, 0x1e1e3a2f, 0x0707153c, 0x12130e0e, 0x19181617, 0x2357881a, 0x5c012301, 0x2005b34b, 0x06d35b03, 0x6205a15d, 0x2f0809f5, + 0x22230607, 0x2d3f7d0a, 0x143c1617, 0x0a0a0405, 0x12140e0e, 0x8d1c1718, 0x153c2301, 0x013a1d1d, 0xe3fe6b41, 0x19181a8f, 0x13121616, 0x07070d0e, + 0x47050741, 0x1b23065f, 0x77010000, 0x797b0db1, 0x32332c08, 0x73021433, 0x181b3f7e, 0x82131318, 0x05092eaa, 0x17143c05, 0x2f8e2d16, 0x07072301, + 0x24a9820d, 0x18191616, 0x235f851a, 0x3d1d1d3a, 0xff284a82, 0x0207ffd5, 0x008f0394, 0x07205782, 0x200a1961, 0x0d096337, 0x2b223508, 0x2320201a, + 0x474a4a42, 0x2835353a, 0x35281d3c, 0x4b473a35, 0x2023424a, 0xf9421a20, 0x433c3b32, 0x868c8c7c, 0x4c63646f, 0x6f64634c, 0x7c8c8c86, 0x323b3c43, + 0x05205f8e, 0x200abd5d, 0x0d296227, 0x3b02222b, 0x24201f1a, 0x464b4a41, 0x2160823b, 0x6e851d3b, 0x6e844b20, 0x3121608d, 0x256c853c, 0x4c64646e, + 0xbf880100, 0x00004722, 0x6787bf88, 0x751ab766, 0x9618089d, 0x272008ab, 0x3f07696b, 0x39252b22, 0x1b1d3738, 0x1a14141a, 0x39361d1b, 0x1d3b2539, + 0x1a161711, 0x2030312e, 0x19171711, 0x3c210783, 0x2723821d, 0x1b1a1e36, 0x39382614, 0x1a2b0782, 0x201e3b14, 0x192e3130, 0x83111717, 0x161a3d07, + 0xf9421117, 0x676a6b47, 0x26323237, 0x37323226, 0x476a6b67, 0x302b2b20, 0x3d5b5c58, 0x47220787, 0x1f846b6a, 0x3d272787, 0x30585c5c, 0x87212b2a, + 0x51002007, 0x012105a3, 0x089b5d34, 0x14333228, 0xef0a2215, 0x554cef4f, 0x01002605, 0x4b010c01, 0x06735d01, 0x114c0120, 0x2416820b, 0x49fe92b7, + 0x82438292, 0x08df5d3f, 0x23077d5b, 0x50ef3401, 0x5f424487, 0x07ff2505, 0x4b015c01, 0x0ca7af18, 0x143c0c2a, 0xb301f93c, 0x914dfe91, 0xff232383, + 0x82fa00f6, 0x839c204b, 0x4a252023, 0x142005dd, 0x4f2a4782, 0x79fa4fef, 0x01007a29, 0x7482e400, 0x94038422, 0x1b481f83, 0xe4222406, 0x89782878, + 0x0100238a, 0x475e3401, 0x5d252009, 0x8b840603, 0x28204283, 0x21052757, 0x87858401, 0xcf861720, 0x86894383, 0x5e010021, 0x0f22088b, 0x27530000, + 0x2a4b8708, 0xf652f63e, 0xe74de852, 0x540a1ffa, 0x735e05df, 0x0567560a, 0x2a09974a, 0xe4221510, 0x143c0a1e, 0x83780a1e, 0xb701255f, 0x9249fe92, + 0x638cec84, 0x5b852720, 0x14333225, 0x82232215, 0x840a2003, 0xf64e2160, 0x1e21b282, 0x05bc530a, 0xd75efb82, 0x073f5506, 0x3f57bb86, 0x57608205, + 0xb321053d, 0x26648991, 0x01000001, 0x4168024b, 0x112c052f, 0x33203510, 0x01201510, 0x32fe9ace, 0x82093041, 0x0fff2a23, 0xa5ff6802, 0x00000700, + 0x06934615, 0xf1242384, 0x26702670, 0x0020db82, 0x00211f83, 0x231f9132, 0x49da49da, 0xbe201f88, 0x638b1f84, 0x4401f127, 0x6cbdfe6b, 0x20848200, + 0x41438400, 0x15200573, 0xad24238d, 0x8f53fe8f, 0xd820238a, 0x02254791, 0xeafdb217, 0x212389b3, 0x23926402, 0xfdd58024, 0x238ad681, 0x2392f120, + 0xfdf9e924, 0x2389f917, 0x24051741, 0x20111015, 0x85038233, 0x640327f3, 0x9dfc2101, 0xd786defe, 0x238e2320, 0xfe899a24, 0x238df166, 0x8ed30121, + 0x755e2323, 0x238fa2fe, 0x238e8320, 0xfe612223, 0x20238fde, 0x20238834, 0x238f8232, 0xe74de722, 0x43412189, 0xe4002106, 0xab22238d, 0x2391ab39, + 0x238d9620, 0x71267022, 0x45202391, 0x3322238d, 0x238c3412, 0xff340123, 0x0737420f, 0x23051f4c, 0x34012211, 0x1029918c, 0x19ff0000, 0x7e031c02, + 0x278e1800, 0x0037350b, 0x0047003f, 0x0057004f, 0x0067005f, 0x0077006f, 0x1100007f, 0x2105dd42, 0x07862122, 0x0f8e0720, 0x0f8e0520, 0x3a241fcf, + 0x21013a13, 0xac2a0482, 0x01391339, 0x3a143921, 0x12b61efe, 0x4e160323, 0x2001851a, 0x21089192, 0x01851a4f, 0x4f231a89, 0x831b4e1a, 0x20118803, + 0x2a358791, 0x00180000, 0x0219ff00, 0x417d0368, 0x3f220c3f, 0x3b414700, 0x00773a06, 0x0087007f, 0x009f008f, 0x00af00a7, 0x00bf00b7, 0x00d700cf, + 0x00ef00df, 0x072f4100, 0x37412320, 0x1425220e, 0x05334515, 0x05201786, 0x14200d85, 0x44060352, 0x3423055d, 0x86272235, 0x44172017, 0x17830b75, + 0x1f850f85, 0x14333022, 0x278b1f98, 0x14333222, 0x8906f145, 0x881f875f, 0x84312007, 0x8677871b, 0x612f98bf, 0x1f8806ff, 0x31030234, 0x33ff3232, + 0xfffe3232, 0x01333333, 0x33333468, 0x0d823135, 0x0d823220, 0x33013322, 0x4d220e82, 0x05823419, 0x69333323, 0x82138233, 0x339b2202, 0x23108334, + 0x3233cf66, 0x35250882, 0x32339832, 0x21138432, 0x40821a4c, 0x34333524, 0x25823232, 0x3f829920, 0x19899920, 0x01194d23, 0x203e8536, 0x20198732, + 0x8255829a, 0xe7332212, 0x24008a38, 0x393938e1, 0x22038338, 0x821b5571, 0x25198307, 0x71373939, 0x23841c54, 0x1b823720, 0x84703821, 0x2011821e, + 0x250882a9, 0x37363739, 0x1c837137, 0x1b827020, 0x55713929, 0xe7fe391c, 0x83381c53, 0x85392029, 0x272e8412, 0x6f37386f, 0xfc551c55, 0x37215e88, + 0x23118238, 0x1c553938, 0x53241183, 0x0038371c, 0x0a200082, 0x37063742, 0x003b007e, 0x004b0043, 0x005b0053, 0x006b0063, 0x007b0073, 0x15000083, + 0x4c0b9150, 0x07890715, 0x14333225, 0x83333215, 0x05a96923, 0x42232221, 0x07840533, 0x2d771320, 0x05142105, 0x07200786, 0x17a7078e, 0x07bae318, + 0xad290785, 0xae133a3a, 0x3b133939, 0x21098313, 0x15837474, 0x3a340126, 0x9a133b14, 0x04840a83, 0xe7260f9a, 0x1a4e246d, 0x03892f8d, 0x4e1a4e27, + 0xfeb4fc1a, 0x074a43e7, 0x866b0321, 0x82ac2009, 0x43ac2007, 0x4f200582, 0x4e250b86, 0x4e1a4f1b, 0x261782ad, 0x00010000, 0x47f10200, 0xe746080b, + 0xf102260b, 0x297a287b, 0x22008200, 0x44230201, 0x022311f7, 0x45113423, 0x47820a1d, 0x010fff23, 0x08cb4634, 0x10333229, 0x4de72215, 0x4601f1e7, + 0x012005c9, 0x48053b45, 0x34200ee7, 0x0020218a, 0x01228b83, 0xef45014b, 0x47112006, 0x218206c7, 0x84099547, 0x208b8223, 0x05b36169, 0x11101522, + 0x03836783, 0x4de72031, 0x31fe4de8, 0x016403f1, 0x9249fe21, 0x878f53fe, 0x8266202b, 0x000f272b, 0x11020500, 0x53842722, 0x3b059151, 0x98013301, + 0x994de79a, 0x01f19a99, 0x011e011d, 0xfe92b701, 0xfedafedc, 0x00e3fee2, 0x89080b47, 0x83202067, 0x822320cf, 0xcf0124d3, 0x464ee79a, 0x678d0582, + 0x05222b86, 0xc3783510, 0x46102005, 0x2f83051b, 0xad01f123, 0x235f828f, 0xdefe9dfc, 0x01245b84, 0x024b0134, 0x07202f83, 0x24095556, 0x4de83401, + 0x25e989e7, 0xff000002, 0xbb83020f, 0x82000721, 0x101524bd, 0x82053035, 0x84132051, 0x261128f1, 0xe7e73401, 0x84999999, 0x25b28358, 0x24013d02, + 0xc0822401, 0x4101db21, 0x4f711023, 0x41112007, 0x8d8b0723, 0x03000129, 0x6502dbff, 0x82001902, 0x4817208b, 0x032f0683, 0xfe98ca01, 0xae012537, + 0x8f51fe90, 0x8a020000, 0xf9c41823, 0x4d4e1809, 0x262d8508, 0x7c740160, 0x867c8cfe, 0x01362634, 0xa3fe745e, 0x253b8b00, 0x002f0017, 0x91730500, + 0x32252c16, 0x36373233, 0x34353435, 0x82232627, 0x06072d23, 0x14151415, 0xba011617, 0x2b555ab2, 0x32080082, 0x5659b355, 0x2a2b2b2a, 0x59b39efe, + 0x1c1c1d39, 0x5ab2391d, 0x1d1d1c39, 0x2828251c, 0x5054a851, 0x29282829, 0x5154a850, 0x1b362828, 0x54a8361a, 0x871b1a36, 0x03002107, 0x1721bf8c, + 0x05695600, 0x0a9f4e18, 0xc986f78d, 0x2a013225, 0x8cd6fe63, 0x014726cf, 0xe9fe5d18, 0x21d6825e, 0x538e0600, 0x27001f22, 0x4988df83, 0x34332027, + 0x14232035, 0x41079e15, 0x41410c3b, 0x86059105, 0xd6012983, 0x74250c26, 0x75260d25, 0x27220787, 0x8ba2270d, 0x33322728, 0x23223510, 0x079e1710, + 0x28298b86, 0x6e0d280d, 0x0e280d29, 0x8409846f, 0x0e292304, 0x09410e29, 0x0175250c, 0xa3fe745e, 0x00210591, 0x1417411a, 0x2413ff48, 0x008f0087, + 0x0ac74797, 0xcf00c722, 0x20099941, 0x06634503, 0x3420b382, 0x1420bb82, 0x7b450797, 0x871f9707, 0x45152017, 0xc3450eb3, 0x870f870f, 0xa74f9f27, + 0x1e534177, 0x4147fe21, 0x2924176d, 0x6e0e290e, 0x23088041, 0x280d296f, 0x2f970e85, 0x3d424999, 0x260d230b, 0x038b250c, 0x0d8c7420, 0x75201985, + 0x1583238e, 0x27212794, 0x2201900d, 0x41080000, 0x1f2c0aff, 0x43003300, 0x61004b00, 0x79007100, 0x2409db41, 0x34333225, 0x07295035, 0x18232221, + 0x200805f2, 0x70158b37, 0x13860615, 0x82056d7d, 0x840f8213, 0x3203240b, 0x18333237, 0x2008ef4f, 0x202d8615, 0x86138e07, 0x4114200f, 0x012f0585, + 0x38091c6b, 0x2c515454, 0x1c1e2827, 0x8255380a, 0x282c0809, 0x1a144327, 0x37361c1a, 0x19332537, 0x4346452e, 0x19202123, 0x1d2f301c, 0x130e172d, + 0x29271513, 0x182f1b28, 0xb316170d, 0x0e17180d, 0x243e1f83, 0x25192120, 0x1d363838, 0x2e821a1a, 0x29291b17, 0x13131528, 0x302f1e0f, 0x0e18317d, + 0x24431716, 0x0b182a08, 0x4d4f4f35, 0x1c252529, 0x21098217, 0x09824c50, 0x2f532908, 0x18191218, 0x3435321b, 0x41412b22, 0x1f1e223f, 0x1b162c7b, + 0x0d1b2c2c, 0x25141212, 0x32742626, 0x15150c10, 0x2c0163fe, 0x20081d83, 0x2f181e1f, 0x35342318, 0x19181c32, 0x27261a12, 0x12121425, 0x1b162b0d, + 0x0d1b2d2d, 0x330d1516, 0x41008200, 0x17240b6b, 0x33001f00, 0x20116b41, 0x07595203, 0x2105976f, 0x0f833514, 0x14232223, 0x27178d11, 0x07060706, + 0x33321514, 0x34211587, 0x842f8535, 0x89172017, 0x07a95115, 0x16333223, 0x182d8537, 0x22081d51, 0x84333217, 0x056b410b, 0x1b602a08, 0x15272829, + 0x2e0f1313, 0x2f301c17, 0x16170d1d, 0x2e12350d, 0x24434546, 0x32192020, 0x38372519, 0x1a1a1d35, 0x380c1914, 0x05904155, 0x410d1921, 0x2726059a, + 0x3825c11f, 0x1c843637, 0x2421203d, 0x2e464543, 0x5f17180e, 0x2f1e162e, 0x140e1d30, 0x29271513, 0x12377a29, 0x4217160e, 0x383507d7, 0x2526261a, + 0x0d121214, 0x1b2c2c1b, 0x150c7d31, 0xfe320c15, 0x066241d0, 0x3422172a, 0x191b3235, 0x82351218, 0x30069041, 0x34081a1d, 0x294c504f, 0x1a1c2625, + 0x3435230a, 0x081d8233, 0x182f1321, 0x221f1e18, 0x2c41413f, 0x2d1b0101, 0x162b1b2d, 0x1412120d, 0x1a262725, 0x150d172e, 0x44000016, 0x30080cd7, + 0x00270015, 0x00470039, 0x00670057, 0x00870077, 0x00a70097, 0x00c900b9, 0x00e900d9, 0x010d01fb, 0x012d011d, 0x014d013d, 0x016d015d, 0x018f017d, + 0x09fb42a1, 0x45180320, 0x22250787, 0x16151423, 0x250d8917, 0x07060706, 0x11951716, 0x82078d41, 0xb75a181f, 0x8f2f830b, 0x8705200f, 0x8f4f8651, + 0x8671881f, 0x822f8c1f, 0x430f8491, 0x41960587, 0xb18b318c, 0x51822f93, 0x91161721, 0x8243ac53, 0x8f2f8f63, 0x420720d5, 0x4018058b, 0xa94b07d7, + 0xe5401805, 0x8d05200a, 0x2051821f, 0x42119017, 0x4f2c05b7, 0x070c0c07, 0x03050603, 0x9d0d0a1c, 0x02310b83, 0x1d020504, 0x0505030e, 0x0b0b0603, + 0x0c0b06a2, 0x260b8206, 0x020e1c04, 0x82020505, 0x0ca1241f, 0x820d1904, 0x82032011, 0x82e1200b, 0x8a072003, 0x06952403, 0x82060d0d, 0x26138235, + 0x0b06070b, 0x8240010a, 0x0706220c, 0x210c820c, 0x07820b0c, 0x8ae40c21, 0x0606242c, 0x8ea30c0c, 0xcffe2140, 0x0b2d1084, 0x0503070a, 0x010a0306, + 0x040403d8, 0x838a8403, 0x0c0b223f, 0x821e8447, 0x2707844f, 0xd0fe0c0b, 0x060c0d06, 0x64837583, 0xa2201482, 0xdf20508e, 0x8d848582, 0x05040328, + 0x06060303, 0x5883d001, 0x95845583, 0xfe0a0b23, 0x82929ed2, 0x820b2041, 0x060d23aa, 0xc2840b07, 0x83380121, 0x84062030, 0x22d782cf, 0x88930b0b, + 0x0c0b2140, 0xf1226a83, 0x68820c19, 0x5f830320, 0x01260783, 0x03091ccb, 0x0f850506, 0xfe060528, 0x030d1ad2, 0x0e820405, 0x06070c22, 0x22825182, + 0x0d199926, 0x03060604, 0x0c215285, 0x431d8207, 0xd52007e8, 0x0f837382, 0x081a0324, 0x0b83010d, 0x04040223, 0x21c98302, 0x93820a06, 0x060a0b22, + 0x03202b82, 0x1b821383, 0x050c0a24, 0x1b83081a, 0x4e200b82, 0x07200382, 0x0620038f, 0x13832f82, 0x0a0a0626, 0x0a0a0707, 0x0720cf83, 0x13824783, + 0x0a074f22, 0x2205a241, 0x820c0b06, 0x8e1f8317, 0x820b200f, 0x8209200f, 0x0504256f, 0x0a0a1d03, 0x05217382, 0x22c78502, 0x82090a06, 0x510b2131, + 0x0f946d8f, 0x07216582, 0x235d820b, 0x074d0b0b, 0xd1844d82, 0x84040521, 0x03052b49, 0x03050503, 0x04020d1a, 0xa5850205, 0x850a0921, 0x070a212b, + 0x3b869584, 0x0b0c0623, 0x82ad8306, 0x824d2003, 0x86ad84c9, 0x20f18483, 0x20578306, 0x22ad820a, 0x82090a0a, 0x221f8247, 0x8306060b, 0x0b0b26bd, + 0x0506033b, 0x20378203, 0x27078307, 0x0b18091a, 0x03060503, 0x12426383, 0x21278208, 0xe5820a07, 0x23831782, 0x840a0621, 0x030734ab, 0x00000404, + 0x6e000100, 0xfb013f00, 0x0700b401, 0x4c370000, 0x6e260637, 0xfe632a01, 0x254b3fd6, 0x8a022007, 0x890f2023, 0x49272025, 0x2d85068b, 0x47d42a24, + 0x328647d4, 0x43c73623, 0x265b84c8, 0x02710003, 0x84830165, 0x06934e5b, 0x24059f43, 0xce45cd71, 0x22228244, 0x89000200, 0x865b8323, 0x4b272025, + 0x574b066f, 0x2334840c, 0x7e2a7e35, 0xa2245b84, 0xc601dbff, 0x2808ef4c, 0x15103332, 0x49dba222, 0x08ed4cdb, 0x5b820020, 0xb9562389, 0x22152108, + 0x8307474b, 0x8610242d, 0x4b2d852c, 0xb78c0c11, 0xed821320, 0x18073547, 0x2c09b1d8, 0x1c130320, 0x0d0f1b1c, 0x30010a0e, 0x300a8598, 0xa9fe0a0d, + 0x32332171, 0x17181a31, 0x33332112, 0x82078330, 0x22df8a4a, 0x951b0013, 0x24eb824d, 0x23203736, 0x29559506, 0x5501011b, 0x00ff1747, 0x5f904656, + 0x20060a41, 0x09fb4d00, 0x00001122, 0x4908e547, 0x172b064b, 0x38250320, 0x1a1d3738, 0x4826141a, 0x143305f0, 0x462537fe, 0x36666a69, 0x46263132, + 0x3766696a, 0x4e263131, 0x11220a1b, 0x45932300, 0x8718a582, 0x07230a59, 0x92060706, 0x01443257, 0x130e9226, 0x28271513, 0x281b1b29, 0x13142828, + 0x2e6a9013, 0x24231c36, 0x4c4c4927, 0x4c4c3232, 0x82242749, 0x0983426c, 0xab78bf82, 0x08bf8808, 0x110c6e23, 0x25231312, 0x25181824, 0x11132325, + 0xd6fe0d11, 0x2020193f, 0x45444224, 0x44452d2d, 0x20202442, 0x42bf8219, 0xbf8407c7, 0xda184591, 0x579211e5, 0x4c960e31, 0x1414150e, 0x08090a0b, + 0x1415150e, 0x900a0a0a, 0x1a363169, 0x14262727, 0x1a0e1213, 0x15252827, 0x00001212, 0x280a7f41, 0x17000005, 0x17043510, 0x09794f04, 0xd748d722, + 0x4f060742, 0x0520069f, 0x82066960, 0xf15a1825, 0x85102010, 0x1d603437, 0x4e2a2626, 0x36365150, 0x2a4e5051, 0x251d2626, 0x8290ae01, 0x0d082148, + 0x2a05624a, 0x26261919, 0x12111425, 0x83c9fe0e, 0x0d3f415b, 0x09514c18, 0x0806e549, 0x221a6e21, 0x49462622, 0x49313149, 0x22264649, 0x7cf93f22, + 0x1210100c, 0x17222221, 0x21222217, 0x82101012, 0x09e34344, 0x9f831120, 0x45903720, 0x37363725, 0x8f142726, 0xa91f244b, 0x9138a938, 0x50432550, + 0x9f1a501b, 0x032a9b85, 0x65023f00, 0x1100b401, 0x55910000, 0x714a032f, 0x353a6c70, 0x34282834, 0x706c3a35, 0x864a8271, 0x0d0c2793, 0x21111010, + 0x9b842322, 0x0f824389, 0x47414591, 0x8f142010, 0x32113057, 0x28494b4c, 0x321b2323, 0x27494c4b, 0x911b2423, 0x0d392d68, 0x0b131314, 0x0d070909, + 0x0a131413, 0xbf870782, 0x8206b741, 0x430520bf, 0x0b440701, 0x34012c08, 0x36383825, 0x141a1a1e, 0x4ccb9701, 0x1b200550, 0x430ff142, 0x45910f5b, + 0x2021bf88, 0x06f54223, 0x14325793, 0x1411120d, 0x18262524, 0x0e87f2fe, 0x23141111, 0x6a8f2526, 0x21195f2f, 0x46432421, 0x20192e46, 0x46442421, + 0x0bdf4545, 0x2520bf82, 0x0d2abf92, 0x23131111, 0x01182425, 0x0a858508, 0xf2422520, 0x43182008, 0x5b430564, 0x8845910f, 0x08df4dbf, 0x91340121, + 0x43182057, 0x9726075a, 0x15140e4b, 0x5c430b14, 0x2869860a, 0x27271a3e, 0x12121525, 0x4307860e, 0x05340f5b, 0x37242724, 0xfe650210, 0xca019937, + 0x48d72598, 0x51fe48d7, 0x240b9b52, 0x00170005, 0x22258500, 0x18351007, 0x870ea353, 0x35392f37, 0x2a4e5151, 0x1d1d2526, 0x4e2a2625, 0x47865151, + 0x14013f32, 0x2726198a, 0x12121424, 0x12110e0d, 0x26262514, 0x410c1f47, 0x13460b3f, 0x01102207, 0x065443fb, 0x64431a20, 0x173f2807, 0x11212223, + 0x430d1010, 0xfe210763, 0x414682e9, 0x49881843, 0x115d5f18, 0x392f5b91, 0x272a2a1c, 0x0f131416, 0x1614130f, 0x922a2a27, 0x8e0e216b, 0x079ee618, + 0x0907072b, 0x14120b09, 0x01000014, 0x093f4300, 0xbd410020, 0x29798808, 0x704a6502, 0x343a6c71, 0x8c432835, 0x43578807, 0xc387078b, 0x910c8743, + 0x91c39149, 0x4339205b, 0x91430781, 0x8a6b9206, 0x140d26c3, 0x090a1313, 0x0b63450a, 0x47181f20, 0xc3870a57, 0x20063543, 0x06f14117, 0x46093d43, + 0xa2430ffa, 0x35232d07, 0x181c3334, 0x34231319, 0x191b3335, 0x35200782, 0x18210783, 0x42178613, 0x1f220b53, 0x71a13f00, 0x42108144, 0x91a00e7b, + 0x271a1433, 0x12142626, 0x261a0e12, 0x13142527, 0x27190e12, 0x270f8427, 0x1412120e, 0x25272726, 0x4530b19e, 0x24242518, 0x0d111113, 0x23252418, + 0x0d121113, 0x27072c47, 0x1311110d, 0x00252424, 0x03200082, 0x8308d351, 0xc15f20d3, 0x443720d5, 0x8741074f, 0x1c142837, 0x16282a2b, 0x880f1414, + 0x2a2a2707, 0x13141629, 0x07861c0f, 0x2122162f, 0x10101121, 0x10100c0c, 0x22212111, 0x27078316, 0x16212220, 0x11100f0c, 0x15410782, 0x1a35281f, + 0x15262728, 0x870e1312, 0x271b2707, 0x13152528, 0x07860e12, 0x1f151d30, 0x0f101f20, 0x0f0b0b0f, 0x1f1f100f, 0x078e1520, 0x03000033, 0xd8ff0300, + 0x1c026502, 0x7f003f00, 0x0000af00, 0xaf471805, 0x4546180a, 0x19431809, 0x3776180d, 0x3376183f, 0x187f8e1c, 0x180d6f5c, 0x33111b5b, 0x13147f01, + 0x13111212, 0x14131413, 0x1c241314, 0x0a14141c, 0x14240082, 0x241c1c14, 0x14251183, 0x12111313, 0x22098512, 0x871b1c25, 0x1c1b221d, 0x32318225, + 0x0f0f109b, 0x0e0e0f0e, 0x100f1011, 0x17171e0f, 0x8208100f, 0x0f102400, 0x821e1717, 0x11102210, 0x231c820e, 0x10100f0f, 0x1d2d1e82, 0x10101616, + 0x08090908, 0x16161010, 0x2610821d, 0x19181bb0, 0x82191818, 0x13132400, 0x82060c0c, 0x0c0c2300, 0x0e821313, 0x18271583, 0x1212171b, 0x82070d0d, + 0x0d410800, 0x1e12120d, 0x02020305, 0x07060503, 0x1a120a08, 0x2421201a, 0x25292925, 0x19212024, 0x070a1419, 0x02060508, 0x06020303, 0x0a070805, + 0x20191914, 0x2a25251f, 0x2025252a, 0x131a191f, 0x3307080a, 0x3a1d8304, 0x06070304, 0x15151008, 0x1d1e1919, 0x1d1d2020, 0x1415191a, 0x06060811, + 0x82020404, 0x04042200, 0x291d8206, 0x1a191414, 0x22221d1d, 0x57821e1d, 0x0810142a, 0x0d3a0706, 0x06070706, 0x112b8182, 0x17181415, 0x17171a1a, + 0x82111515, 0x20158597, 0x354f820f, 0x1c1c1818, 0x15141818, 0x00001110, 0xff3a0002, 0x032e0220, 0x13440009, 0x16102a46, 0x2e2c1815, 0x15111f2e, + 0x28078316, 0x2e2e1f1e, 0x1615182c, 0x2b178710, 0x22242318, 0x0d101112, 0x23232318, 0x0c380783, 0x22121111, 0x17172423, 0x13222324, 0x21e01110, + 0x59302b2b, 0x203e5c5d, 0x28061665, 0x585c5b3d, 0x202b2b30, 0x38178522, 0x48473035, 0x21222544, 0x46472e1a, 0x21212445, 0x21211a1a, 0x47464524, + 0x2017862e, 0x20008200, 0x0cdf4202, 0x4280dd42, 0x814278ad, 0x55002077, 0x634406ff, 0x00153005, 0x0045002d, 0x0075005d, 0x00a1008b, 0x180000b9, + 0x2c072150, 0x16173233, 0x26070617, 0x22232627, 0x46078407, 0x63180871, 0x25200a7d, 0x08edce18, 0x84262721, 0x0617471f, 0x17860520, 0x37343522, + 0x086fa318, 0x17141524, 0x4f820516, 0x35212783, 0x232f8934, 0x06071415, 0xd9452f82, 0x8545870b, 0x19362053, 0x180dfb93, 0x86086f54, 0x32332117, + 0xf8281f85, 0x08020104, 0x12131313, 0x0a210383, 0x062a4405, 0x0c9e2b08, 0x0b1a0607, 0x0d0d0b0c, 0x070e0d0e, 0x0b0f0404, 0x0a0a0b0b, 0xbd010909, + 0x1907060c, 0x0a090a08, 0x0c0a0b0a, 0x10030408, 0x00820d0e, 0xfe0b0b27, 0x08070f22, 0x05c4431e, 0x032a0983, 0x02030302, 0x080e1902, 0x07821e07, + 0x03020222, 0x1e840983, 0x1459fe23, 0x2154820a, 0x5e830d0d, 0x09214c82, 0x264c8309, 0x151e010b, 0x820a0c0a, 0x0a0a2262, 0x217c820a, 0x00830c19, + 0x5c0c0d22, 0x9b829784, 0x01020423, 0x07e54408, 0x01275182, 0x07070eda, 0x8203051b, 0x24052200, 0x281c8213, 0x085f0201, 0x0e110404, 0x3844840b, + 0x07060d08, 0x06070718, 0x0a090808, 0x04030916, 0x090a0b11, 0x07060808, 0x83be8407, 0x0b0c2271, 0x288e82ec, 0x12111007, 0x12111414, 0x270b8310, + 0x100e0e0c, 0x1b0e0e10, 0x0c200b8a, 0x12282384, 0x12141411, 0x10219011, 0x0a284e83, 0x080e0c0b, 0x0c110405, 0x07245183, 0x10213707, 0x18825682, + 0x090d0928, 0x0f100404, 0xd0820c0d, 0x04280822, 0x03219882, 0x20f48204, 0x05f6441c, 0x00210982, 0x0ac34306, 0x6d005328, 0x97008d00, 0xa946a100, + 0x17322c42, 0x37323316, 0x35103332, 0x83222326, 0x10072401, 0x47151013, 0x312106eb, 0x0afd5936, 0x26272623, 0x096f4b03, 0x2207062b, 0x14070607, + 0x16171615, 0x46438217, 0x01210593, 0x2d398314, 0x26273435, 0x06353401, 0x14150607, 0xed431617, 0x067a233c, 0x66820707, 0x82060721, 0x270a8407, + 0x0a0a096e, 0x0201050a, 0x04310282, 0x05070503, 0x04040306, 0x0504ad04, 0x070c0406, 0x28008e02, 0x0604060d, 0x1a190105, 0x2600820d, 0x0c1962fe, + 0x440c0d0d, 0x2c213b01, 0x34008201, 0x01019934, 0x4b01a7fe, 0x0390e0fe, 0x03050504, 0xfe030101, 0x2c77827f, 0x02030303, 0x02020102, 0x1f0153fe, + 0x260f8290, 0x02030602, 0x82010101, 0x7ffc2112, 0x08830782, 0x22821182, 0x60c06638, 0x2b24231e, 0xff24242b, 0x1c5ebc00, 0x2a292424, 0x00002423, + 0xa3450400, 0x00af220c, 0x42db41d7, 0x0bf9c518, 0x1806d141, 0x200b3b83, 0x07694427, 0x4107c74a, 0xcb4106b1, 0x16172105, 0x0bbb7518, 0x0f397f18, + 0x180bfd48, 0x2013c375, 0x8a6f8237, 0x3387186b, 0x40114208, 0x2d3bad48, 0x100f0f8a, 0x08070710, 0x09080807, 0x0b821e07, 0x071e0f24, 0x0e820809, + 0x1007072b, 0x0d0f0f10, 0x08090b0b, 0x2b008204, 0x0b0b0908, 0x0909096d, 0x04040507, 0x04270282, 0x09081104, 0x82110809, 0x210e8319, 0x1a820705, + 0x37821020, 0x4d420920, 0x3bd1483b, 0x04097933, 0x02010104, 0x05030203, 0x22191810, 0x10191822, 0x340d8305, 0x04040101, 0x090a0709, 0x0f0f0c0d, + 0x0e0f1212, 0x0b0a0c0d, 0x20198227, 0x2c2c8201, 0x09020102, 0x12120e0d, 0x02090e0d, 0x200c8202, 0x833c8201, 0x0d132410, 0x4201000d, 0x1d480a7b, + 0x3cef4340, 0x213b5141, 0xe7480000, 0x4361200b, 0x0323413f, 0x4b321510, 0x3d430df3, 0x20ebbc0f, 0x1c734b5f, 0x263b0941, 0xccfef901, 0x4b02039b, + 0x2b411b2e, 0x4159200c, 0x2723412b, 0x18223510, 0x20091f52, 0x31db1815, 0x3eff4508, 0x1f1e5f22, 0x162b0182, 0x080f1017, 0x0f080909, 0x84161710, + 0x3a494c10, 0x35012a39, 0x1008089a, 0x18151411, 0x221d1d19, 0x191d1d22, 0x10151518, 0x42080811, 0x55200d3f, 0x21411341, 0xb1182001, 0x062210ab, + 0x33420607, 0xacfe2b3c, 0x1fa34701, 0x1e1f3e1e, 0x1a411f1e, 0x3c2c420a, 0x32421226, 0x08102231, 0x15410082, 0x4c002007, 0x4b430e33, 0x46272042, + 0x2021138b, 0x47274223, 0x22131546, 0x4ea4bafe, 0x214109a8, 0x12aa453b, 0x410a5e4e, 0x73200e2b, 0x41413742, 0x2222142b, 0x61433423, 0xa36c180b, + 0x3c55420f, 0x22133d41, 0x4f0e3db8, 0x4b4117f4, 0x4d9a234e, 0xbb4f0202, 0x0d934317, 0x5b414f20, 0x32012241, 0x0c474133, 0x233c3741, 0x3db8acfe, + 0x21488543, 0x96444d9a, 0x00002d09, 0x9c000100, 0xcd01d8ff, 0x21001c02, 0x10220c82, 0x58182215, 0x2620083d, 0x250f8b49, 0x36373637, 0xdf51cd01, + 0x1c1d2c08, 0x0a091413, 0x1314090a, 0x52251d1c, 0x12250511, 0x7dfe1c02, 0x067c51c1, 0x1a1a142e, 0x24232120, 0x24242929, 0x1a192120, 0x8c077c51, + 0x00192573, 0x35101700, 0x2108d74b, 0xe3491617, 0x06073507, 0x259c0607, 0x27262627, 0x12121e1d, 0x0a09090a, 0x1d1d1312, 0x28270f83, 0x0ac28201, + 0x8216140b, 0x241f3f5d, 0x242a2923, 0x1a1d1e25, 0x0b151619, 0xff02000b, 0x02f7fff6, 0x00e40273, 0x00370007, 0x815e0700, 0x44372006, 0x5d470e13, + 0x0b1d530b, 0x7b074d46, 0x20080551, 0x12131153, 0x13131515, 0x0d0d1111, 0x06050a0a, 0x0a0a0505, 0x11110e0d, 0x15151313, 0x10111312, 0x2115830e, + 0x15840404, 0x3202092a, 0xbbcefdbb, 0x05040af6, 0x09302682, 0x10100d0c, 0x14131112, 0x10101111, 0x09090c0d, 0x05211482, 0x23158609, 0x12111314, + 0x00201583, 0x03200082, 0x0f20af82, 0x4722af86, 0xb1998700, 0x200ee54a, 0x2f514b26, 0x5413c941, 0x01411b57, 0x53542005, 0x14201cce, 0x201c0a54, + 0x1cce539a, 0x0a541020, 0x02f1271c, 0x21fdf5e0, 0x7d47d3f6, 0x1a132409, 0x53201f19, 0x1f2105a9, 0x13c75320, 0x53202121, 0x212405e5, 0x121a1a20, + 0x2e0ec753, 0x19191414, 0x22221d1e, 0x191a1d1d, 0x53101414, 0x112e0dc7, 0x1a191514, 0x20201d1d, 0x19191e1d, 0x1d821515, 0x00000723, 0x05d37602, + 0x00e40228, 0x004b0029, 0x47422700, 0x23222205, 0x0d1b4334, 0x24105955, 0x23202122, 0x0dc94934, 0x290f6541, 0xa0dd010a, 0x0a0a0509, 0x14551414, + 0x14454105, 0xfe30022e, 0x0807a2ba, 0x17171010, 0x100f101b, 0x29132d41, 0x7a7001fa, 0x2a7a90fe, 0x10412525, 0x1e22211a, 0x0f20f284, 0x0020f294, + 0xff30e784, 0x0073020f, 0x001d00fa, 0x0700002f, 0x33323510, 0x200a2947, 0x06954a33, 0x10231582, 0x56012015, 0x352f0a2b, 0x07143320, 0x04090a06, + 0x144c2726, 0x82131312, 0x27122d03, 0x4d262726, 0x040a2625, 0x190122fe, 0x08073748, 0x201f3c24, 0x1fa34701, 0x7001f11e, 0x3d3e537b, 0x08080b2a, + 0x03030405, 0x2a150a0b, 0xfe533e3d, 0x24017b90, 0x00820811, 0x32211138, 0x32424232, 0x01000032, 0xfa009c00, 0x1c02cd01, 0x00001700, 0x4f412237, + 0x14332207, 0x0af74915, 0x1429d929, 0x264c2626, 0x83272626, 0x171d3a68, 0x08101016, 0x3e53fa08, 0x0b142a3e, 0x0814270a, 0x14111008, 0x1d191814, + 0x234f8b1e, 0x2500001b, 0x2108c341, 0x75443423, 0x16172e0b, 0xcd011617, 0x1f1e1529, 0x1e1f203c, 0x05c0561d, 0x24111229, 0x14141c1d, 0x48fa0a0a, + 0x272806b8, 0x06030314, 0x09070805, 0x20235a82, 0x4525251f, 0x0021073b, 0x20ab83fa, 0x41518217, 0x352205fb, 0x58183332, 0x9c300a2d, 0x201f1e1d, + 0x291e1f3c, 0x13090a15, 0x271c1d13, 0x2824b582, 0x08081327, 0x2a2af384, 0x1e1e2525, 0x15151919, 0x8b450b0b, 0x204f8508, 0x42f18225, 0x9541056f, + 0xcd01210d, 0xfc834182, 0xe7832920, 0x17161028, 0x1e1e1f1d, 0xf8822612, 0x3d2a153b, 0x1d23533e, 0x1518191d, 0x08111014, 0x00010008, 0x02fa0003, + 0x001c0265, 0x0b4b412b, 0x9742a583, 0x41152007, 0x5f410911, 0x283f220a, 0x11d94114, 0x4a142821, 0xfa321110, 0x2a3e3e53, 0x0408080a, 0x0a030305, + 0x3e2a140b, 0xe549533e, 0x06f74d12, 0x3723d782, 0x42250000, 0xdf830a47, 0xc718dd8d, 0xab830fe7, 0x22054f41, 0x8226cd01, 0x1312242e, 0x82131412, + 0x274c2403, 0x49142826, 0x22430976, 0x2fc38213, 0x0a150225, 0x0403030b, 0x0b080805, 0x533e3d2a, 0x200a4e49, 0x11e95703, 0x3d3e5322, 0x240f7f61, + 0x15103700, 0x0ef97020, 0x1023238f, 0xa1170035, 0x33202223, 0x61478b00, 0x05240de7, 0x33202700, 0x34098b5e, 0xfe90ae01, 0x00000051, 0x00a00002, + 0x01c901da, 0x002f00f1, 0x12394157, 0x590c7f7f, 0xdf4911ad, 0x13f7460f, 0x17141525, 0x467f0116, 0x102014d4, 0x080e0047, 0x0a05062c, 0xb10d0d0a, + 0x18161511, 0x0e0f1010, 0x080b0b0d, 0x04040408, 0x0b080705, 0x0f0e0d0b, 0x1618110f, 0x08111115, 0xee080909, 0x0082050a, 0x0c090a23, 0x0607470c, + 0x07471220, 0x1111210f, 0x27070747, 0x08071120, 0x08080303, 0x0e375b83, 0x0e100f0e, 0x0a0c0d0e, 0x0407070a, 0x10090804, 0x17141410, 0x62131417, + 0x07210df3, 0x057f6500, 0x1033202b, 0x32372015, 0x22351033, 0x06eb6223, 0x3eba9824, 0x81653eba, 0x7002200d, 0xe5710c7b, 0x20378c09, 0x18379d60, + 0x8207c548, 0x8227206f, 0x070b6075, 0x26094f66, 0x585b5c3c, 0x882a2b2f, 0x9b372879, 0x52565539, 0x7328282d, 0x478b0d27, 0x87080966, 0x3d6022bb, + 0x2144835b, 0x3073202b, 0x5639210a, 0x1e224584, 0xaf72a3fe, 0x20c9861a, 0x29d18d05, 0x37a537a5, 0x37a41501, 0x0f4137a4, 0x0175210c, 0x5d068373, + 0x112409bf, 0x43002300, 0x5325a565, 0x64180ba9, 0x15210f5f, 0x27c56514, 0x0c0afc2e, 0x0c0e0e0c, 0x0509090c, 0x0a050405, 0x0b230d85, 0x82050a0a, + 0x0f846200, 0xe1652620, 0x09512c0f, 0x05040405, 0x0b0b0909, 0x820b0d0d, 0x18042042, 0x20095188, 0x0d27420b, 0x1d001122, 0x2370d593, 0x6610200a, + 0x98241275, 0x130e4993, 0x99057466, 0xcbfe218b, 0x940c8763, 0x32272267, 0x08c55633, 0x44226792, 0xd46637a5, 0x14012218, 0x08cf6689, 0xf6ff022c, + 0x7302cdff, 0x37002802, 0x974c7700, 0x074f4b31, 0x0befc118, 0x2105a546, 0x0f443637, 0x1f514a0b, 0x27d3012a, 0x13292828, 0x14141413, 0x27250382, + 0x15141e1e, 0x2400820a, 0x1e1e1415, 0x08128427, 0x1313142f, 0x27282829, 0x151d1e27, 0x0a0a0b14, 0x1d15140b, 0x10fdfe1e, 0x100e100f, 0x11111010, + 0x1e0f100f, 0x11101817, 0x09080809, 0x17181011, 0x2110821e, 0x1a821111, 0x22820e20, 0x51081f82, 0x17181d11, 0x09081111, 0x11110909, 0x111d1717, + 0x16091111, 0x02020a0a, 0x08080505, 0x1a1b150c, 0x26252120, 0x26262c2d, 0x1a1a2120, 0x08080b16, 0x02030506, 0x16150b0b, 0x20211a1a, 0x2d2c2626, + 0x20212526, 0x03041b1a, 0x03020203, 0x06060504, 0x1b831008, 0x231f1f30, 0x1a1f1f23, 0x1016151a, 0x04060707, 0x1f820205, 0x0604042d, 0x15100906, + 0x1f1a1a15, 0x8524241f, 0x090f231d, 0xd3600607, 0x0007240c, 0x741b000f, 0x11281179, 0x35103320, 0x15142322, 0xfd430382, 0x37a52a06, 0x740137a5, + 0xcf37a47c, 0x06684346, 0x9c39012c, 0xc9fe9b33, 0xc3745e01, 0xb7439a41, 0x8b13200c, 0x32372153, 0x20204b82, 0x32214b82, 0x059b6e33, 0xb5295388, + 0x8cfe37a4, 0xfe45d07c, 0x435c83eb, 0x9b250abe, 0x9b41c234, 0x24539a33, 0x34333227, 0x23038335, 0x05102320, 0x53880783, 0x37a56024, 0x558245cf, + 0x260d1244, 0x339c40c3, 0x9d75a3fe, 0x82202053, 0x23222253, 0x21f78234, 0x538d2510, 0xcf21f782, 0x0f664445, 0xc3339b29, 0x8ea3fe41, 0x609b339c, + 0x67210cef, 0x4eb15000, 0x210cbd42, 0x2d661514, 0x16172408, 0x72271617, 0x07200677, 0x083f0753, 0x1114a42d, 0x1e1e1011, 0x1e3e1f1e, 0x3e1e1f1f, + 0x0b0c0c0c, 0x0c0b0b0c, 0x08035ab5, 0x100d0d08, 0x13121310, 0x36a09914, 0x17181718, 0x501e1f36, 0x36223bb0, 0x53820306, 0x074b1120, 0x31200805, + 0x05050622, 0x03030404, 0x1b40c101, 0x13131819, 0x0d0c1010, 0x88f10908, 0x07080344, 0x2b2b1e0d, 0x220d4b62, 0x447f0073, 0x7d183119, 0x03210f2b, + 0x078d5b14, 0x22271f44, 0x19133207, 0x2007c712, 0x3e7f5516, 0x0c0b4222, 0x0b2c0083, 0x16161c0b, 0x08091111, 0x0f100708, 0x3d052444, 0x0f0e1110, + 0x1111100f, 0x13141414, 0x100f1312, 0x07080d0d, 0x8f0bcb03, 0x1f1e0547, 0x23821736, 0x383aa355, 0x56aa2c01, 0x05020302, 0x05050504, 0x1913140f, + 0x231e1d19, 0x1b1c1d20, 0x09ee611a, 0x05030339, 0x0c090905, 0x1410100c, 0x1c171814, 0x329900ff, 0x1e2b2b38, 0x4407070d, 0x6b5f062f, 0x003f2105, + 0x2145df42, 0xad763534, 0x4b262009, 0xa15005fd, 0x778e1813, 0x5222200a, 0x2d083c59, 0x025bb47b, 0x0d0d0809, 0x13121010, 0x14141313, 0x0e101312, + 0x100f0e0e, 0x3c10100f, 0x1f20201f, 0x1718173c, 0x17171751, 0x1f1e3718, 0xdf42a105, 0xc02c293b, 0x18181c40, 0x100f1414, 0x3e05f847, 0x02010303, + 0x07060404, 0x32312208, 0x32324242, 0x07070d21, 0x044487c7, 0x1d0d0707, 0x44382b2c, 0x6f220c3b, 0xdf427b00, 0x0f0d4b41, 0x82363721, 0x23222201, + 0x07cd4934, 0x480fe954, 0x14200a27, 0x083c6341, 0x0f109b36, 0x11100e0f, 0x13141411, 0x10121313, 0x090d0d10, 0x43cc0308, 0x19171817, 0x1016171d, + 0x0809080f, 0x16100f08, 0x0f101e17, 0x478f6910, 0x371e1f05, 0x17171718, 0x383b6c41, 0x03020433, 0x05060303, 0x0c0d0809, 0x13131010, 0xac1b1918, + 0x07080355, 0x068e580d, 0x1d202125, 0x501a1a1d, 0xf62905ee, 0x1e2b2b39, 0x0308070d, 0x0ad34899, 0x11000522, 0x1806fd46, 0x2009c749, 0x08a94a20, + 0x24231b2a, 0x4c4b4927, 0x67ccfe32, 0x2a059d46, 0x21221909, 0x47474425, 0x49dffe2f, 0x47840d83, 0x27000528, 0x07103320, 0x916c3510, 0x083d6b08, + 0x89eefe29, 0x484c4c32, 0x86232328, 0x22012948, 0x47472f60, 0x22212544, 0x02204882, 0x8408bb4b, 0x10172547, 0x20170035, 0x4b0a3b70, 0x602206f5, + 0x45821201, 0x27494b25, 0x851b2324, 0x368f2346, 0x4483482f, 0x84192121, 0x00022b90, 0x02060030, 0x00ee0137, 0x73720007, 0x8295820b, 0x30103a93, + 0xfe818601, 0x3101497b, 0x66d0fe65, 0x7a6e0106, 0x357a92fe, 0xfe5f1e01, 0x208382e3, 0x213b8a01, 0x09523700, 0x85202005, 0x2a2a8631, 0x00020000, + 0x022b0057, 0x8eca0110, 0x062d475f, 0x4b015735, 0x35b5fe6e, 0x52f552f5, 0x6837012b, 0x3568c9fe, 0x84e64ce7, 0x8837895b, 0x862d855b, 0x0d8f6c28, + 0x00001123, 0x21278217, 0x854c2015, 0x010b2911, 0x4c326734, 0x2427494b, 0x24064941, 0x0201368f, 0x054a4180, 0x6a822120, 0x0001002e, 0x028aff1b, + 0x00bd024e, 0x01000059, 0x29068563, 0x06070615, 0x26353407, 0x7b7b2627, 0x27262208, 0x5fc91810, 0x5795180f, 0x0f455407, 0x2708db52, 0x35363736, + 0x33323510, 0x022d5582, 0x0d0c130e, 0x04030607, 0x22080911, 0x08008201, 0x07020221, 0x110a0a07, 0x03041710, 0x090a0706, 0x11100f0e, 0x18191414, + 0x1616181e, 0x11101414, 0x82060c0c, 0x0c0b2200, 0x08758210, 0x1817164d, 0x13151516, 0x0c100f13, 0x2d010204, 0x1a1a2017, 0x20214402, 0x231e2120, + 0x03072723, 0x0f100e04, 0x0c0e0e0f, 0x18160b0b, 0x1d1e1a18, 0xc0fe1e1e, 0x1c1d23a0, 0x13121617, 0x0b0a0f0e, 0x03040706, 0x07080404, 0x0d0d0c0b, + 0x82100f0f, 0x0e0d262c, 0x08070b0b, 0x24168204, 0x09090607, 0x2315820c, 0x8fb0010f, 0x00363882, 0x00040000, 0x02fdff16, 0x00180253, 0x001f000f, + 0x003f002f, 0xc1640100, 0x45c81806, 0x640f8e08, 0x1f9707e1, 0x18350129, 0x19192829, 0x83182928, 0x200b8203, 0x200786b6, 0x21178619, 0x108e2101, + 0x308eb420, 0x1724012b, 0x17172625, 0x17172726, 0x23078327, 0x2617aa25, 0x03880783, 0x17851820, 0x27200f87, 0x2b821f82, 0x27212387, 0x2cc48226, + 0xd1ff7800, 0x9702f101, 0x00003700, 0x08435205, 0x230fbb41, 0x36373637, 0x440d5353, 0x67080bff, 0x434df101, 0x151a3843, 0x070e0f14, 0x0d080707, + 0x1a15150e, 0x21201f1c, 0x26232422, 0x14151517, 0x11121314, 0x080d0c11, 0x11040409, 0x28222110, 0x060b1e28, 0x1a35191a, 0x1f201b1c, 0x25252223, + 0x201f2222, 0x1a191d1c, 0x0d0d1414, 0x060d0707, 0x0d0c0506, 0x1a191312, 0x1e1e1b1b, 0x4623201f, 0x32313c3b, 0x01001919, 0x4722ab88, 0x3f530000, + 0x13ed5609, 0x2720bf83, 0x4210b353, 0xc3830fa9, 0x2f782108, 0x10212828, 0x08090c0d, 0x05040304, 0x0c0c0908, 0x0c0c0b0f, 0x0e0e0d0e, 0x0e0f0f0c, + 0x2425250e, 0x1e249d82, 0x15161c1b, 0x08399b83, 0x140f0f07, 0x14121915, 0x16171714, 0x19181515, 0x060c2f19, 0x18321819, 0x08aa831c, 0x23211f28, + 0x21202222, 0x0e151b1a, 0x09090c0b, 0x07070708, 0x0c040605, 0x0e060706, 0x1914140e, 0x211c1d1b, 0x21212020, 0x00822324, 0x0d255182, 0x0a0a0c0d, + 0x21258208, 0xdb820506, 0xc7ffb32a, 0x8002b501, 0x00001700, 0x092b7218, 0x82343521, 0x333221dd, 0x39060163, 0x2e5bb501, 0x0f17161e, 0x1e08080f, + 0x2d5c3d1e, 0x1b1b1a36, 0x2c2d391a, 0x00832b2d, 0x57575524, 0x00825759, 0x57585823, 0x204f8200, 0x224f82b7, 0x866a02b1, 0x4d36204f, 0x322206bf, + 0x35591633, 0x3b013a09, 0x19352c58, 0x35191a1a, 0x1d3c2c58, 0x0f07071d, 0x3916170e, 0x56545554, 0x2a008254, 0x52545456, 0x292a292b, 0x832c2b2a, + 0xffa2274f, 0x02c701c3, 0x76180082, 0x76180b5b, 0x4f181051, 0x01290999, 0x10100c5c, 0x23222112, 0x29078716, 0x23172447, 0x10122122, 0x07870d10, + 0x173d5029, 0x3e221e1e, 0x842b4140, 0x41412d07, 0x41412b2b, 0x1e1e223e, 0x40412b17, 0xc7820784, 0x5f76778a, 0x23501808, 0x5f062011, 0x222106e5, + 0x073770a2, 0x2322162a, 0x10101121, 0x1723460c, 0x76820982, 0x07870c20, 0x2a3d502f, 0x213f4041, 0x2b171f1e, 0x213f4140, 0x8e6e831f, 0x26778276, + 0x01b0ff69, 0xa87002ff, 0x1d5a3fef, 0x172a2c2d, 0x1e101515, 0x172b2c2c, 0x6e101514, 0x15151037, 0x2d2d2b18, 0x2d2d1e1e, 0x1982182b, 0x87507c21, + 0x22e786d7, 0x821f1718, 0x20f783ff, 0x8d808540, 0x24efa377, 0x15151169, 0x82648717, 0x6e11227e, 0x82808737, 0x182a2107, 0x7b218882, 0x055e4150, + 0x5e414020, 0x41f78206, 0x18200566, 0x6641ff82, 0x26778205, 0x02a7ff67, 0xa8bb0201, 0x193835ef, 0x14252627, 0x0e0e1212, 0x25141212, 0x86192726, + 0x27271943, 0x1a211184, 0x3d078526, 0x49305997, 0x22264648, 0x221a1a21, 0x49462522, 0x492f3048, 0x22254748, 0x48301a22, 0x07834649, 0xbc207788, + 0x410cf977, 0x67201adf, 0x0d215c86, 0x21648619, 0x80874386, 0x96209087, 0x30207688, 0x21057576, 0x85761919, 0x83302005, 0x21262476, 0x82001a22, + 0xffe42b77, 0x0284017c, 0x001b0091, 0x6f830500, 0x6a351021, 0x103a0b5d, 0x16171615, 0x06070617, 0x25155801, 0x24161624, 0x0d091525, 0x1f12080e, + 0x0383121f, 0x0d0e082a, 0x22211584, 0xbf7e0114, 0x07320683, 0x10080d0d, 0xfe111d1e, 0x1d11afa3, 0x0c08111d, 0x0082000c, 0xe4000124, 0x63827eff, + 0x63889320, 0x10216183, 0x0b274635, 0x83151021, 0x82102063, 0x1309284f, 0x13131e1f, 0x83131f1e, 0x826f8367, 0x08822477, 0x83080d0c, 0x5e012251, + 0x2b0682ae, 0x0d0d0810, 0x21221407, 0xbf82fe15, 0x63850682, 0x65ff8c28, 0x8502dc01, 0xc7826900, 0x0d5b5418, 0xf34e3420, 0x22232507, 0x32353423, + 0x82089f59, 0x18372017, 0x22082d54, 0x18333233, 0x4510638c, 0xf7470827, 0xd5a91807, 0x3336080e, 0x32dc0114, 0x17161e1a, 0x0c0b1010, 0x03030606, + 0x0a0a0505, 0x11191111, 0x19080f06, 0x0a091112, 0x03030505, 0x0b0b0606, 0x17171010, 0x1013391e, 0x0d0d1108, 0x29830809, 0x04010224, 0xed820904, + 0x0d141429, 0x0409080e, 0x83020104, 0x08230829, 0x110d0d09, 0x049b0612, 0x0b070703, 0x1811110c, 0x21441f18, 0x0c161521, 0x2d06060d, 0x0c06070f, + 0x8216160c, 0x191f2411, 0x82111118, 0x03072471, 0x820f2d03, 0x82042038, 0x0f0a2f2d, 0x23451410, 0x0e181822, 0x050b0a0f, 0x0f820a06, 0x21181726, + 0x0f142346, 0x07340f82, 0x02040407, 0x00002e02, 0x7d000100, 0xec0162ff, 0x69008b02, 0x41053b46, 0x3724070d, 0x35363736, 0x18091141, 0x5b099b77, + 0x56180abd, 0x1141125d, 0x0d3f4108, 0x17821520, 0x2c096f64, 0x127d2223, 0x0e0d1209, 0x06070a0a, 0x2fea8203, 0x08080504, 0x15151010, 0x09090f0f, + 0x01020405, 0x2c06e348, 0x0714120e, 0x19201c37, 0x0c121119, 0x08b2830c, 0x0b040522, 0x1c13130b, 0x08100612, 0x0b13131c, 0x0405040b, 0x0c070704, + 0x1911120c, 0x9e3e2019, 0x0202102e, 0x0b201083, 0x1439eb82, 0x18212447, 0x0a0f1018, 0x0a05060a, 0x190f100a, 0x24462218, 0x0b0f1013, 0x2648820b, + 0x2e020303, 0x8303030f, 0x1124083a, 0x1f181811, 0x161f2345, 0x060c0c17, 0x070f2e06, 0x160c0d06, 0x22442116, 0x1118191f, 0x070b0c11, 0x00040307, + 0x012f0082, 0x8e002a00, 0xd5013e02, 0x00001f00, 0x19373625, 0x21092f4a, 0x0d423332, 0x07e97406, 0x0122073a, 0xfe216220, 0x7efb5ee5, 0x18292919, + 0x2015254c, 0x0e111f20, 0x1f150b0f, 0x0c320784, 0x1f5c8e55, 0x2717143c, 0x1e141727, 0x0e101d1e, 0x07820b0e, 0x07831c20, 0x0100002c, 0x45003a00, + 0x1c022e02, 0x67822900, 0x890bf16d, 0x9586180b, 0x210f820f, 0x43182e02, 0x240808f6, 0x29192b2b, 0x203b3d3d, 0x32161d1d, 0x1a1a1418, 0x3837361d, + 0x1d1d1225, 0x02030211, 0x06050603, 0x06050345, 0x080b8205, 0x1c100221, 0x3423101c, 0x181c3235, 0x182e1318, 0x1e1b1b15, 0x273a3938, 0x18272818, + 0x1b181912, 0x82343532, 0x228f82f6, 0x82c5002a, 0x84e920f7, 0x2f87188f, 0x05ef4a07, 0x99838787, 0x350e0341, 0x07058001, 0x20180507, 0x4341231f, + 0x442c2c44, 0x1f234143, 0x13831820, 0x10100d3d, 0x23232113, 0x23231717, 0x10101321, 0x262617c5, 0x01010117, 0x03030302, 0x841b3502, 0x830e8206, + 0x0d092f15, 0x1b1a0e0c, 0x1b12121b, 0x0c0e1a1b, 0x8b82000d, 0x5b003a26, 0x31022e02, 0x37208b83, 0x4409f96e, 0x9d8b0737, 0xfb461383, 0x31842d06, + 0x3d3e2919, 0x1d1c203b, 0x2b2b1916, 0x081f4518, 0x6b820220, 0x06052508, 0x1d110405, 0x3725121d, 0x1a1d3638, 0x172f5b1a, 0x33343522, 0x1219181b, + 0x101b1b11, 0x06050504, 0x02020302, 0x2b060e41, 0x28281722, 0x3a392617, 0x1b1b1e37, 0x172b8b82, 0x5202c400, 0x1500d301, 0x18370000, 0x410911b0, + 0x7b82070b, 0x10e12608, 0xc80d1112, 0x0d59b142, 0x420d1313, 0x76765d5c, 0x1cc45c5d, 0x21152020, 0x2323160b, 0x22222d16, 0x22231616, 0x28d78300, + 0x028c0025, 0x00fe0144, 0x0d9d5a49, 0x995a3520, 0x08bf4407, 0x20092d58, 0x0c576233, 0x440d1f5f, 0x012405a7, 0x080807a0, 0x2f054849, 0x03040403, + 0x14131207, 0x0970e00d, 0x07070809, 0x08270f84, 0xfc080908, 0x85172f54, 0x0807220d, 0x24008209, 0x32640708, 0x22f28204, 0x82010101, 0x99712331, + 0x00820307, 0x08060731, 0x070a0907, 0x13100708, 0x04030d12, 0x82070606, 0x07072256, 0x22388206, 0x8207162b, 0x82092046, 0x2129851b, 0x2f822f5f, + 0x05030429, 0x08090504, 0x836a0707, 0x002a28db, 0x013e02ce, 0x821100f3, 0xb53019db, 0x0620080d, 0xa3010607, 0x015ee5fe, 0x311d5e1b, 0x301d1d30, + 0x2164ce31, 0x2d580714, 0x1c2d2e1c, 0x002e2e1b, 0x012a0082, 0xb1001700, 0xea015202, 0x3f901900, 0x82068946, 0x062d0888, 0xd1feab01, 0x652f0165, + 0x100f0e0b, 0x151e1f1d, 0x1d1f1e15, 0xb10e0f10, 0x143b1d58, 0x0d0a274e, 0x1d1b0f0e, 0x1d13131d, 0x0d0f1c1d, 0x2956820e, 0x1b000400, 0x4e02af00, + 0x5782e401, 0x29002124, 0x57183100, 0xcd420c75, 0x3425240e, 0x18333235, 0x200aa375, 0x080f8633, 0x71a9012f, 0x0b267126, 0x1d100e0e, 0x14141f1e, + 0x101d1e1f, 0x67fe0e0e, 0x30110511, 0x40220b22, 0xaf441743, 0x236a153f, 0x0d0a1c38, 0x1c1c0f0d, 0x2180821c, 0x80821b1c, 0x236a4a22, 0x00200189, + 0x2a288b82, 0x3e02c200, 0x1100e601, 0x58188d86, 0xe5860b01, 0x83970520, 0x6ba32908, 0x21246b24, 0x2d2d2726, 0x66fe2627, 0x2c100510, 0x3d200b20, + 0xc2401540, 0x32960c22, 0x25330f1f, 0x25161525, 0x32960524, 0x97410189, 0x82b72005, 0x41db2073, 0xb72e2497, 0x2164143b, 0x2d1c1a36, 0x2d1c1b2e, + 0x0082002d, 0x3000022b, 0x3802af00, 0x1f00ed01, 0x20108200, 0x07374737, 0x85272621, 0x0e414101, 0x820a0552, 0x30670819, 0x100e0f0b, 0x14201f1e, + 0x1e1f2014, 0x0b0f0e10, 0x312d2d22, 0x3f605f5d, 0x5d5f603f, 0xb42d2d31, 0x3a26478d, 0x1b1d3839, 0x1f13151b, 0x0d0baf20, 0x1d1c0f0e, 0x1d13141d, + 0x0d0f1c1e, 0x0e0b0b0e, 0x1e1c0f0d, 0x1d14131d, 0x0e0f1c1d, 0x120b940d, 0x09091111, 0x1e120608, 0x0002001e, 0x02c6003d, 0x00f3012b, 0x43250017, + 0x9f440699, 0x29af8812, 0x07062322, 0x321e3d06, 0x03831e32, 0x2a212d08, 0x5b57302a, 0x2b203c5b, 0x5b582f2a, 0x37242f5b, 0x1a1c3537, 0x43871419, + 0xc61e1f11, 0x1c2f2f1c, 0x1d2f2e1d, 0x0e0d0d0a, 0x131b1c1b, 0x1b2f0784, 0x110b291c, 0x07091011, 0x1c110608, 0x8201001d, 0x0287267f, 0x0039022b, + 0x187d861f, 0x92073548, 0x083d2a85, 0x160c0b0b, 0x080f1717, 0x2907830a, 0x5b3c0f18, 0x2a2f585b, 0x7f86202b, 0x130e8728, 0x28271413, 0x07821a28, + 0x82261521, 0x281a2a07, 0x13152628, 0x130e0e13, 0x2d0f8312, 0x01000000, 0xba001b00, 0xfe014e02, 0xc1422900, 0x41222006, 0x35220581, 0x83623534, + 0x32332206, 0x39401833, 0xa9013310, 0x0f1266ce, 0x060e0e10, 0x0e060707, 0x120f100e, 0xc7424de7, 0x35ba350e, 0x0d060611, 0x110f0f0d, 0x0f113871, + 0x060d0d0e, 0x0b182f07, 0x1b2a1082, 0x13131c1d, 0x0f1b1d1c, 0x7f850d0d, 0x7f87b920, 0x2f483720, 0x22739308, 0x70353407, 0x1b200857, 0x0b207597, + 0xb9219788, 0x2d768272, 0x060c0d0f, 0x0a182f06, 0x1b0f0d0e, 0x76821d1c, 0x821c1c21, 0x340a2876, 0x0c060611, 0x830f100d, 0x00a8267f, 0x02c1017b, + 0x061f444b, 0x59232221, 0x7f4205b9, 0x0128080e, 0x68226832, 0x0c0c0a22, 0x1a1a190e, 0x1a1a1212, 0x0c0c0e19, 0x9f205e7b, 0x102a5435, 0x29161314, + 0x1c1d2a2b, 0x16292b2b, 0x22059b7d, 0x82ac001b, 0x43e120d3, 0x713b161b, 0x0155fffe, 0x371b5600, 0x38535338, 0x0e2aac37, 0x12263194, 0x17272735, + 0x43272717, 0x3226051b, 0x3602ab00, 0x0f64f101, 0xcd5b1805, 0x22978e0c, 0x42372207, 0x1422071f, 0xc55a2215, 0x01210805, 0xbe3fbe2f, 0x0b1e3b3f, + 0x1f110f0f, 0x15152020, 0x111f2020, 0x430b0f0f, 0x2e2d1b07, 0x2d2e1b1b, 0x081f831b, 0x143bab2b, 0x143b2a7e, 0x100e0e0b, 0x141e1e1c, 0x1d1e1e14, + 0x0b0e0e0f, 0x2a2b191b, 0x2b2b191a, 0x55143c19, 0x00003b1d, 0x00320002, 0x208b828e, 0x238bbdd5, 0x100f0f0c, 0x93838b83, 0x20211e2c, 0x1b3c4315, + 0x1a1a2e2e, 0x8b842e2e, 0x143c8e25, 0x843c2a7d, 0x821d208b, 0x2093828b, 0x8207830f, 0x192b218b, 0x3b248b83, 0x3c1c5514, 0x1b2f8b83, 0x4e025600, + 0x2300df01, 0x00003f00, 0x47353425, 0x36230737, 0x83333237, 0x054b490b, 0x47151421, 0x1d4106b9, 0x07214106, 0x22211583, 0x21058323, 0x05823332, + 0x16013508, 0x02020201, 0x1a4c40c2, 0x100964c7, 0x0c18090f, 0x0f18170f, 0x2e303020, 0x11161619, 0x2a1c2227, 0x1316292a, 0x130c0f14, 0x0f0a0b13, + 0x64c70a0e, 0x0d16160d, 0x42082b84, 0x02172d56, 0x32020404, 0x0f2a7e10, 0x200e1919, 0x2d203635, 0x1c1d1316, 0x0d0e0f1b, 0x19115e0a, 0x0c0d1819, + 0x2b1a080c, 0x190f1a2a, 0x23160e1a, 0x180f1623, 0x00020019, 0x02650030, 0x00b90138, 0x82410025, 0x272625bf, 0x23222726, 0x6f580583, 0x41078307, + 0xc58507e1, 0x4309df41, 0x615b07ff, 0x08e98405, 0x09d10183, 0xb8080f0e, 0x1e1e115c, 0x02509f12, 0x21010302, 0x2c2c1d11, 0x1515162b, 0x16170d0f, + 0x0b05180d, 0x0f0b1211, 0x25141212, 0x08192727, 0xb8090e0e, 0x14140c5c, 0x095cb70d, 0x0d650e0e, 0x1b0d1516, 0x2c1b2d2d, 0x0303020f, 0x100e2c02, + 0x0d181819, 0x26090c0b, 0x2f2e1c13, 0x2516171c, 0x0b071724, 0x16150b0a, 0x150d0e16, 0x1f130d15, 0x150e121f, 0x00000015, 0x003f0002, 0x022a0267, + 0x00270005, 0x8bc79039, 0x0a6147c3, 0x27220722, 0x2f11a942, 0x0a09064a, 0x07438505, 0xac070c0b, 0x160e1b39, 0x0806197e, 0x0c0c0726, 0x10100c07, + 0x22212111, 0x1c121f16, 0x1c1c3130, 0xac1c3031, 0x673aab39, 0x0b11110b, 0x0d16160d, 0x0e293aaf, 0x8207e87d, 0x0b0e36c8, 0x1e110e0f, 0x63152020, + 0x1b2d2c1b, 0x1a2e2d1b, 0x2c830e2a, 0x26ab832a, 0x023d002b, 0x82fe013e, 0x824120ab, 0x353423ab, 0x37422322, 0x0b314205, 0x0622a78b, 0x37420607, + 0x2726230e, 0x5d432726, 0x23450809, 0x0c083eba, 0x4890080c, 0x060a0a06, 0x24180f1e, 0x12132325, 0x0d070c11, 0x2518070d, 0x11132324, 0x15220d11, + 0x1e1e1f14, 0x0b0e0e10, 0x100e0e0b, 0x141f1e1e, 0x3eba3eba, 0xa80f2e3d, 0x18180e54, 0x12120b0f, 0x074d510c, 0x18170f23, 0x290b860e, 0x1d131f0d, + 0x0d0f1c1c, 0x6f480a0e, 0x2d122506, 0x2e2f8f0f, 0x1a2ac383, 0x4f029d00, 0x2f001902, 0xc3824700, 0x42053142, 0x53410539, 0x33322107, 0x44187741, + 0xe9870c21, 0x33322208, 0x046f0114, 0xcb040506, 0x06050465, 0x11120a03, 0x12110b0b, 0x1b50f20a, 0x2221170e, 0x0f101220, 0x411d830c, 0x31080885, + 0x30311c01, 0x31301c1c, 0x0765cb1c, 0x08080d0e, 0xe4070e0d, 0x0b069d4c, 0x0510060b, 0x070b0b07, 0x16252515, 0x15252415, 0x20150f2a, 0x0e111e20, + 0x15830b0f, 0x0f0e0c36, 0x1f201e11, 0x2d1b3f15, 0x2d1a1b2e, 0x0d2a1b2d, 0x101c1b11, 0x11210382, 0x26d7832a, 0x02770016, 0x86f80154, 0x353423d7, + 0xcf872322, 0x4105cd43, 0xf54407a9, 0x09a3410f, 0x8b079b41, 0xda5d22d7, 0x20cf876d, 0x27e18203, 0x05044de8, 0x0e1c0406, 0x122dcb82, 0x17222221, + 0x03060604, 0x1110100d, 0x390b8222, 0x301d151f, 0x301e1e30, 0x67cf1d30, 0x090d0d08, 0x080d0d09, 0x2b774ee8, 0xcf82160e, 0x27050143, 0x070f060b, + 0x070b0a07, 0x8407c244, 0x0f0f2cd7, 0x20211f10, 0x2e1c1c15, 0x821c1c2d, 0x0e2b25db, 0x111b1c11, 0x2b2d0383, 0x00010000, 0x02590049, 0x00320220, + 0x0d8f4b3b, 0x33322722, 0x4809dd5d, 0x594205e7, 0x08355005, 0x68363721, 0x14350811, 0xd6010607, 0x342d2c24, 0x262c2c33, 0x080a0b0d, 0x0f0d3cb7, + 0xe2471810, 0x0d0f250a, 0x0c0751a3, 0x1332d582, 0x18171713, 0x2c321918, 0x1225262d, 0x9f121313, 0x00821124, 0x0d0c2426, 0x14290e0d, 0x20060546, + 0x06054616, 0x0f2e0c38, 0x100e0f0d, 0x090c0c0f, 0x11040409, 0x2a232311, 0x2930312a, 0x00820029, 0x2c00093b, 0x3c029d00, 0x29007301, 0x41003500, + 0x59004d00, 0x71006500, 0x89007d00, 0x05a34c00, 0x83353421, 0x333225b5, 0x17161716, 0x210f1548, 0x5b453534, 0x49222005, 0xa74406ab, 0x05e54407, + 0x0b943185, 0x89430720, 0x823d8405, 0x05d34555, 0x06070622, 0x2c2a0b97, 0x0d15150c, 0x0c15150d, 0x09824080, 0x22690c23, 0x82008310, 0x212225f1, + 0x2f5c2020, 0x902d1383, 0x0b080e28, 0x0e0b1212, 0x12110b07, 0x200b8335, 0x210b8411, 0x17853611, 0x0b070d23, 0x220b8211, 0x85120b07, 0xae122117, + 0x2f822982, 0x11830f20, 0x35842020, 0x0b820b20, 0x20111123, 0x2011820d, 0x200b8512, 0x8217851f, 0x11122a05, 0x1d1e119d, 0x11091212, 0x3f05821d, + 0x3e111d1d, 0x0f0f101f, 0x0c0c0d0d, 0x1b1b150b, 0x1217461f, 0x79111e1d, 0x0f19180f, 0x0f18190f, 0x7b260796, 0x0f1a190f, 0x23831a0f, 0x003e0794, + 0x3a000300, 0x2e025700, 0x22002d02, 0x44003400, 0x14250000, 0x26171617, 0x22232627, 0x51180623, 0x3e220867, 0x51183701, 0x062607ea, 0x2e271407, + 0x1f442701, 0x26148305, 0x1417011e, 0x82232207, 0x21028213, 0x0e823332, 0x011e7b08, 0x03041d02, 0x1f1e1c0a, 0x0e0d0e23, 0x1314120e, 0x2220140e, + 0x050d0511, 0x13212013, 0x0d17160d, 0x15ac0102, 0x0e111e40, 0x0f0b0b0f, 0x401e110e, 0x1d561715, 0x1f101e0b, 0x264d1540, 0x101f4015, 0x1e1fcd1e, + 0x04082316, 0x11020104, 0x120c1413, 0x040e211f, 0x1e13040f, 0x150d131e, 0x0d0d0c16, 0x3c13450d, 0x0e0e0f1d, 0x0b24480b, 0x1c100e0d, 0x3151143c, + 0x1d0f1c0b, 0x1783133c, 0x83001c21, 0x002a2ad7, 0x013e02da, 0x0011009c, 0x08774a1d, 0x23097749, 0x25060706, 0x20096742, 0x21e98422, 0x15823332, + 0x01220736, 0x602060c7, 0x1e1e1b20, 0x1e1e2020, 0x170d8ffe, 0x478e0d16, 0xa021b583, 0x8205837c, 0x3011820b, 0x153fdaa0, 0x1c380713, 0x11181820, + 0x4e181811, 0x2c97820c, 0x0c15160c, 0x15150d5e, 0x15150c0c, 0x2d83840d, 0x023d003a, 0x0013022e, 0x00350025, 0x755a0046, 0x06674709, 0x37323324, + 0x73823736, 0x15141523, 0x23028216, 0x27012e17, 0x05230d82, 0x8237013e, 0x33322402, 0x8207010e, 0x17222302, 0x0e823534, 0x2a823620, 0x84151421, + 0x012b0812, 0x05070571, 0x20211205, 0x16160e14, 0x0d0e0e0d, 0x1f1f230d, 0x0405081c, 0x11010101, 0x21130d2a, 0x15b6fe20, 0x1e101f40, 0x41264d0b, + 0x56210555, 0x2207836e, 0x84152020, 0x4c012916, 0x06050704, 0x131e1e12, 0x3482b583, 0x05042c08, 0x1e1e1a07, 0x0707061f, 0x0707070c, 0x120c2612, + 0x149f1e1f, 0x1c0f1d3c, 0x0f1c0a0a, 0x82143c1d, 0x1c0a2448, 0x1e1d1d10, 0x41244814, 0x012a0561, 0x57002800, 0x51024102, 0x33427300, 0x4fac8212, + 0x272005fb, 0x0da99418, 0x0ef74518, 0x20078744, 0x43bb1817, 0x0e834507, 0x190bf377, 0x51088302, 0x022a0641, 0x0a04042f, 0x2422221f, 0x34620e0e, + 0x09270805, 0x18040707, 0x091e0d0e, 0x06110d0d, 0x07080807, 0x13080809, 0x220d0f0f, 0x0e291213, 0x08171212, 0x09090908, 0x820b0a0a, 0x0a0a2d03, + 0x0f070809, 0x08070708, 0x1312230f, 0x072d1d84, 0x02030505, 0x01020201, 0x05050303, 0x08478706, 0x02010120, 0x0c0c0804, 0x01010110, 0x201f21d4, + 0x0405081d, 0x0b0f0201, 0x0204080b, 0x0d0c1703, 0x1b82091b, 0x05040623, 0x303a8203, 0x200c0606, 0x0d261112, 0x07161111, 0x04040506, 0x343b8302, + 0x07050604, 0x1411110f, 0x0f111215, 0x27121121, 0x1610110d, 0x20008407, 0x83008308, 0x17062409, 0x831c0c0d, 0x07033847, 0x11130907, 0x0f0e0e10, + 0x0000000e, 0x00160001, 0x015302b9, 0x82470089, 0x0706230c, 0x67510706, 0x820d820a, 0x22152211, 0x0b156c23, 0x220acd73, 0x4d333235, 0x73410957, + 0x16352c06, 0x53021617, 0x1d202123, 0x82070304, 0x6e0437b0, 0x0d0e1036, 0x05060b0c, 0x06064c99, 0x0708060e, 0x08090809, 0x04820a0a, 0x08070922, + 0x062b1082, 0x06054d98, 0x0e0d0c0b, 0x82376d10, 0x083482ee, 0x201d0433, 0x13210121, 0x13221a19, 0x070f1211, 0x05030505, 0x0c0a0b05, 0x0f120f0d, + 0x04060c0f, 0x02030405, 0x04020102, 0x05050404, 0x120f100d, 0x0a0d0c10, 0x2824830b, 0x110f0706, 0x1a221212, 0x2dd7841a, 0x0253003a, 0x0028022e, + 0x25000061, 0xca84010e, 0x8207fe41, 0x0e0723d4, 0xc9832301, 0x85373621, 0x09cf7301, 0x1622df87, 0x37433233, 0x8717200b, 0x200782df, 0x5c408535, + 0x1e3a06de, 0x01161701, 0x26222171, 0x1511100d, 0x0707070f, 0x07050c06, 0x1209030e, 0x8e411409, 0x35188405, 0x110f0e0c, 0x0c0f0e10, 0x07052952, + 0x10130806, 0x0e0e0e10, 0x50430e0d, 0x0f022407, 0x82070b0b, 0x010128d4, 0x0c0c1801, 0x8218091b, 0x064908e8, 0x05060102, 0x201ff504, 0x10100b24, + 0x11100d14, 0x0d0f1413, 0x0603050c, 0x07040401, 0x111e0d07, 0x0f0c2410, 0x050b1410, 0x0b050606, 0x0203264e, 0x0b0a0703, 0x0403020d, 0x1e1d1a08, + 0x0d0d0c20, 0x100f0e0e, 0x04030410, 0x081a8203, 0x0b160228, 0x16081a0c, 0x0e0d0b0f, 0x0807070f, 0x0007060e, 0x1b000300, 0x4e028c00, 0x2300d701, + 0x77004f00, 0x16010000, 0xe7871617, 0x0f3b4818, 0x18074343, 0x531b5f48, 0x06230c79, 0x18170607, 0x50123b90, 0x1b82086d, 0x03860720, 0x16cb0133, + 0x232b2121, 0x19191e1e, 0x0b111516, 0x02050807, 0x28e48201, 0x0a0a0809, 0x0a0a0a0c, 0x21c18209, 0x2b82bafe, 0x08070925, 0x82070707, 0x050526ee, + 0x02030204, 0x20f78201, 0x82e5820c, 0x21083012, 0x39392d2e, 0xa8524645, 0x05ed7373, 0x82050506, 0x09082237, 0x30008204, 0x05050309, 0x18191705, + 0x1b1b1a19, 0x21212a1c, 0x05945317, 0xb701052b, 0x1521222d, 0x08090809, 0x2c558208, 0x0a070704, 0x05050406, 0x08090a0b, 0x2d358207, 0x04030704, + 0x0103cd04, 0x03020202, 0x42820403, 0x82050621, 0x070738ac, 0x0a0c0b10, 0x0206050b, 0x090d0201, 0x0609080a, 0x110a0506, 0x83017810, 0x070828ad, + 0x0b0c0a09, 0x82070909, 0x080322ad, 0x82ab8208, 0x211526ac, 0x04052d21, 0x32428205, 0x02000003, 0xac000e00, 0xbb015a02, 0x4f001700, 0x82010000, + 0x420720d1, 0x07870792, 0x16171622, 0x18136141, 0x42084d45, 0x594905ad, 0x4b172008, 0x02270aed, 0x2324335a, 0x82071014, 0x851020d0, 0x23142905, + 0x0a92fe24, 0x0a0b0b0b, 0x07240083, 0x05060407, 0x0a260282, 0x0a0d0e0a, 0x7d82060a, 0xb5820382, 0x83080921, 0x0c0b2122, 0x21272682, 0x52523939, + 0x82213939, 0x34013f0c, 0x2e222315, 0x1411110f, 0x0f111112, 0x13111010, 0x0e111113, 0x6f22212e, 0x02020104, 0xd5820403, 0x82060521, 0x0a0b21e6, + 0x0928e982, 0x090c0b08, 0x04050509, 0x90440082, 0x05052205, 0x272f8206, 0x11120e0f, 0x05050713, 0x002cec82, 0x02d20013, 0x00b70156, 0x250000b9, + 0x4b0bc355, 0x05820517, 0x27343522, 0x82059349, 0x0adb5505, 0x180ac977, 0x4308018d, 0x36250599, 0x30353637, 0x05974335, 0x30273422, 0x4209a159, + 0x16200c87, 0x23059568, 0x14311423, 0x85076f42, 0x52232007, 0x3120081d, 0x59417d83, 0x0b0f5b05, 0x2f8d2220, 0x23060733, 0xa61c0122, 0x03030353, + 0x01010302, 0x06060c01, 0x21058317, 0x0c821805, 0x03211482, 0x821b8502, 0x09012e0d, 0x01130404, 0x02040202, 0x4d010102, 0x201c8226, 0x2c098302, + 0x01010301, 0x01010105, 0x03040302, 0x27458302, 0x160a0a12, 0x0c0a0907, 0x02841382, 0x0b120228, 0x0908150a, 0x1e850c09, 0x82030421, 0x2134883e, + 0x47820202, 0x02264d25, 0x85040203, 0x12052162, 0x22825582, 0x82d20221, 0x821c8352, 0x16012471, 0x822b0b0b, 0x0102216b, 0x15230182, 0x832c0b0b, + 0x844d8207, 0x2483847f, 0x09081102, 0x830e8223, 0x2734835a, 0x03010203, 0x14040509, 0xa9848084, 0x02280983, 0x14090911, 0x0b090907, 0x5f822684, + 0x03281982, 0x15090911, 0x0c090807, 0x6b821383, 0x1d841282, 0x13223d82, 0x46820103, 0x62839a82, 0x01250384, 0x23080911, 0x2d0a8303, 0x13000100, + 0x5602a800, 0xbf00da01, 0xab730000, 0x22232605, 0x26232627, 0x05f54227, 0x21050142, 0x7b413536, 0x44312012, 0x07240621, 0x23220730, 0x210a3542, + 0x935b3635, 0x0ab36b07, 0x20143742, 0xf78f1815, 0x32332108, 0x5b06d145, 0x7d8306cd, 0x33892720, 0x36373222, 0xf3721f83, 0x21098509, 0x39421415, + 0xae01210d, 0x45059759, 0xf68305ac, 0x05040a27, 0x01010111, 0x21178303, 0x06820d19, 0x0d23f483, 0x41180606, 0x0324059d, 0x040359b3, 0x22821582, + 0x1426012c, 0x060c0101, 0x06050e06, 0x34420806, 0x5ab32c07, 0x01030304, 0x0e020101, 0x831a0706, 0x82022045, 0x4247820c, 0x09260665, 0x01120504, + 0x21840102, 0x7c840782, 0x10101f27, 0x0f100c24, 0x08364215, 0xac201086, 0x14823a83, 0x25050b42, 0x0b150201, 0xa782290b, 0x8a820e82, 0x01201782, + 0x02259982, 0x2e0b0b17, 0x820f8304, 0x82032019, 0x22548200, 0x82244a01, 0x05324239, 0x1b0c0c26, 0x0e0c0b08, 0x03203685, 0x37823082, 0x19231c84, + 0x42320d0c, 0x02200736, 0x01255284, 0x0b0b1402, 0x2029822a, 0x06094201, 0x1a272a83, 0x0a1f0d0e, 0x84110d0d, 0x20d5824d, 0x22fa8204, 0x830e0d1a, + 0x82002013, 0x00033100, 0x027e0019, 0x00bc0150, 0x004d001b, 0x13000069, 0x180b9f6a, 0x200d3372, 0xc1b41920, 0x18362008, 0x4b0cbddd, 0xc749094f, + 0x2207220e, 0x05754f23, 0x4609835a, 0x192c0a65, 0x060866cc, 0x04050606, 0x0d1a0404, 0xce82d584, 0x100f0b2d, 0x01e6fe14, 0x1001030c, 0x821e1716, + 0x05062c1a, 0x0e070506, 0x1e060b0a, 0x82101617, 0x1b013a25, 0x14140e0e, 0x0909081b, 0x0c0c0a0a, 0x17181a0d, 0x11111615, 0x1a461f0e, 0x202d820d, + 0x28508205, 0xfb4ce608, 0x0f10147d, 0x0554410b, 0x4201012e, 0x0b0d0819, 0x0b0c0b0b, 0x03030a0a, 0x26082482, 0x18030303, 0xc4171818, 0x1e210305, + 0x04031b1e, 0x05040403, 0x08090504, 0x1e1b0607, 0x0203211e, 0x1b1a0102, 0x8307191a, 0x06062b00, 0x11100d07, 0x18181313, 0x95450b1c, 0x190c2205, + 0x843c8309, 0x03032235, 0x97b31800, 0x3534240d, 0x83103332, 0x32153903, 0x20151433, 0x3f37a72c, 0xfe37a715, 0x01143c74, 0x78fe8388, 0x00143c83, + 0x01350082, 0x63ff9b00, 0xe302cd01, 0x00006500, 0x22232205, 0x26232623, 0x08c74927, 0x1808595b, 0x6c0e6747, 0x535c0825, 0x0bd14f0a, 0x4b071d45, + 0x37240b3d, 0x33363332, 0x01258b82, 0x050a15cd, 0x29cd8206, 0x3c080708, 0x1a192b2b, 0xd9820d0c, 0x110d2308, 0x11151410, 0x060c0b10, 0x06030306, + 0x08080807, 0x0608080a, 0x06060706, 0x22080911, 0x140d0e06, 0x00821514, 0x1013132c, 0x15080810, 0x10152a15, 0x2b820c10, 0x10080832, 0x241b1b10, + 0x090f0e14, 0x04030405, 0x019d0308, 0x093a0082, 0x19191211, 0x1e251f20, 0x28282223, 0x38362f2e, 0x22222d2e, 0x0a0c1817, 0x25820707, 0x03030227, + 0x0d0d0707, 0x08688213, 0x13190c28, 0x060d0d14, 0x0b060605, 0x1912130c, 0x704a4a24, 0x252d2d36, 0x181e1e25, 0x0e14141a, 0x090b0b0e, 0x01030305, + 0x2b413201, 0xff9c2605, 0x02ce0163, 0x090360e3, 0x37441720, 0x1937200a, 0x74102f36, 0x17200fb3, 0x13711d19, 0x4406254b, 0x5b650551, 0x06072c09, + 0x22070623, 0x22232207, 0x8204089c, 0x050424d9, 0x82080506, 0x250a3b00, 0x10101a1a, 0x06060809, 0x10100c0d, 0x15152a14, 0x10110708, 0x16141313, + 0xb1821415, 0x11070d2d, 0x07220809, 0x06060707, 0x820a0708, 0x820620ef, 0x060536e5, 0x10110b0b, 0x11101417, 0x06070d0d, 0x1b1a0d0d, 0x083b2a2a, + 0x08258308, 0x17060527, 0x0111329d, 0x02030102, 0x0b0b0902, 0x14140e0e, 0x1f1e181a, 0x2d2e2424, 0x4a4a7036, 0x13121924, 0x06060b0c, 0x28358205, + 0x05191314, 0x130c0304, 0x0843820c, 0x02040421, 0x07050403, 0x160d0a08, 0x2e202016, 0x2f363b2f, 0x2228282f, 0x1f261d23, 0x11191920, 0x82010911, + 0x82002000, 0x00022100, 0x0cebb318, 0xf5493720, 0x0f23680a, 0x250c9947, 0x15143332, 0xa1432322, 0x4b272006, 0x45740981, 0x07814208, 0x17141529, + 0x110ee016, 0x6c141311, 0x092106ec, 0x08008205, 0x0c090923, 0x1310100d, 0x11141512, 0x0b0e0e11, 0x0509080c, 0x4de80306, 0x060367cd, 0x0c080906, + 0x0b0a830b, 0xbedc190c, 0x0e0c260c, 0x0a0c0c0f, 0x2c3a820a, 0x0407b705, 0x09040403, 0x100c0c0a, 0x0857820f, 0x11111320, 0x0b0c0f10, 0x04050809, + 0x08080304, 0x0b0b0909, 0x3c0a0a0a, 0x0a0b0a14, 0x090a0b0c, 0x20760943, 0x0c0c2505, 0x0b0c0d0d, 0x0864be18, 0x0c200d83, 0x0320ff82, 0x0a775118, + 0x43003122, 0x21b75418, 0x916f0320, 0x21fd8609, 0x59423613, 0x72372005, 0x01210873, 0x7d511834, 0xf0d3261e, 0x21211678, 0x27b88320, 0x120f0f0c, + 0x9e212120, 0x0782cc83, 0x19881620, 0x1f815118, 0xd4012108, 0x4041422c, 0x181e1f22, 0x221f1e18, 0xfe424140, 0x1f1f1835, 0x43424023, 0x42432c2c, + 0x1f1f2340, 0x2a05df41, 0x0181ff94, 0x00db02d5, 0x1817000f, 0x220cbd9d, 0x18143332, 0x3d09af5e, 0x5b50f194, 0xf01e5b1e, 0x4b194b1e, 0x84027f19, + 0xfd0c23d6, 0x0c23bfc3, 0xbf3d022f, 0x4882c3fd, 0x83000221, 0x88d42047, 0x05bd4447, 0x3305a55a, 0x37221510, 0x35103332, 0x94102322, 0x1e5a1e5a, + 0x5af050f0, 0x23214784, 0x823e820c, 0xd77d2149, 0x01224788, 0x8f82c400, 0xda02a522, 0x2d288766, 0x1a1a1150, 0x0c0c0d19, 0x1a191109, 0x07820e19, + 0x871c3921, 0x0c093411, 0x1a190d0c, 0x7f40111a, 0x4c4f4f34, 0x1c252529, 0x8c4e4f34, 0x251c2807, 0x4f4c2925, 0x8c00344f, 0x23776777, 0x6e87c420, + 0x38216c87, 0x99118f1d, 0x288e8776, 0x00020000, 0x0281ff5f, 0x22ef8404, 0x4d000047, 0x596908a1, 0x0815511a, 0xec20239a, 0x0e2e9583, 0x09090c0c, + 0x190d0d0c, 0x38111a1a, 0x0c410a1d, 0x22af8606, 0x41ae400a, 0x38410f26, 0x251c271b, 0x4e4c2925, 0x0787344f, 0x41095041, 0x17890558, 0x41056041, + 0x00200858, 0x0920e387, 0xb787e388, 0x201ae567, 0x2123a233, 0xe65c095f, 0x87112005, 0x20bf88d9, 0x2111870a, 0x1c42b440, 0x191a2108, 0x84061c42, + 0x1a192335, 0x11861111, 0x877f4021, 0x42c397ab, 0x03410f3c, 0x2ee2820f, 0xceff0100, 0x9b026c00, 0x1f00a401, 0x18370000, 0x200913ad, 0x05456816, + 0x33200726, 0x23201514, 0x5f200d86, 0x3507e05c, 0x080e0e09, 0x1018190f, 0xfe98c701, 0x1810ca6b, 0x0e080f19, 0x76196c0e, 0x3a281138, 0x18180e13, + 0x0e0d080d, 0x2520678d, 0x0d7d6519, 0x260b5768, 0x07061514, 0x82090206, 0x8309204e, 0x39fe2556, 0xca940197, 0x0ec84419, 0x08b04a19, 0x0e2a5e84, + 0x080d0d08, 0x192b2b1a, 0x05820c1a, 0x3720d38d, 0x7190d396, 0x08234819, 0x4b21eb9a, 0x20878ea5, 0x21a5881c, 0x0341a6b6, 0x180e2219, 0x25a28d18, + 0x0d0e0719, 0x15820d08, 0x31081b41, 0x3e029a00, 0xb3021001, 0x00000f00, 0x26272213, 0xa7583435, 0x14152605, 0x19d50607, 0x2a008211, 0x12111819, + 0x3e021112, 0x87181111, 0x00112a0f, 0x019a0001, 0x01100182, 0x29379ff7, 0x11108201, 0x11121819, 0x3d821211, 0x02001022, 0x6f843785, 0x71911f20, + 0x819a0720, 0x8d907d88, 0x628cbc20, 0x00219b83, 0x209b82c5, 0x209b833b, 0x21519a37, 0x9a8211c5, 0x5a83dc83, 0x9b830020, 0x9b973783, 0x499a0320, + 0xfe219b99, 0x22648c87, 0x849a0002, 0x82f7209b, 0x41ffba9b, 0xbd200d55, 0x0021628c, 0x86638503, 0x412f20c7, 0x75412165, 0x41e59927, 0x8e8e0c81, + 0x01010027, 0x013e0257, 0x218f84cc, 0x45410100, 0x9101240e, 0x41101119, 0x644207bf, 0x0000250e, 0x9a000200, 0x2f413b88, 0x8e332012, 0x0bb1424d, + 0xad42a420, 0x11122306, 0x588d1211, 0x840cc942, 0x82012163, 0x63829f86, 0x1d41a18f, 0x21b1830f, 0xd4421111, 0x43d42006, 0x12411822, 0x0300230c, + 0x638a9a00, 0x8f129341, 0x97758fc9, 0x8b8099d9, 0x418c8de5, 0x00210557, 0x42f399c5, 0xf3a60feb, 0x820eec42, 0x058b4267, 0x2105fb41, 0xf7a2001f, + 0xf7bd798f, 0x8f909090, 0x411fed41, 0x09410f87, 0x351c4318, 0x9a000422, 0x220a8741, 0x433f002f, 0x194211ad, 0x41a18f1f, 0xac992331, 0x43183542, + 0x01260dd5, 0x82015701, 0xff45cc01, 0x0f434105, 0x440cd343, 0x00200daa, 0x43057b42, 0x75460a0b, 0x43172010, 0xe14234d3, 0x4302200e, 0x9f84056f, + 0x8d3a3744, 0x0d6646bc, 0x4121d343, 0xc9410f99, 0x0ba9410f, 0x440b9141, 0xe58c19b9, 0xbf468e8e, 0x05934106, 0x8d3bc744, 0x0df741f4, 0x48103f43, + 0xbd410f33, 0x0f03410f, 0x45239d42, 0xf38c0dad, 0x00208d8d, 0x8706eb46, 0x225f44f3, 0x10418fb3, 0x0b76410d, 0x00208e8f, 0x8f22cf43, 0x0f154281, + 0x25421f8f, 0x19054623, 0x990c3d41, 0x430220ba, 0x022105cf, 0x059748b3, 0x8f0fd143, 0x0ce14393, 0xc1471820, 0x437c8c18, 0x0941212f, 0x0b23432b, + 0x47073b43, 0x8c8d1de9, 0x91000021, 0x8ff59f8f, 0x180b469f, 0x2035c043, 0x0e234804, 0x8f320b46, 0x236d43a1, 0x0b46ac99, 0x0d794418, 0x41101344, + 0x4d421f47, 0x08514913, 0x420bcc41, 0x854326d6, 0x2283430e, 0x8f0f2741, 0x410f8f91, 0xaca51747, 0x8d184741, 0x41b792b8, 0xc79f1f49, 0x4124a142, + 0x3c442665, 0x00002319, 0xc7480500, 0x484f2010, 0xcd9f31c9, 0x8b178541, 0x0bcd42c0, 0x9141d899, 0x2de49b18, 0x00570101, 0x01cc01c5, 0x000f003b, + 0xa5482500, 0x0c11450e, 0x4d0d584e, 0x034b05f3, 0x10ef4807, 0x970f4147, 0x0d1547e5, 0x860ed94a, 0x17ef4863, 0x970f9547, 0x0de94663, 0x470d9e42, + 0x574e076b, 0x48759b29, 0x8e8e32ef, 0x2008ef48, 0x05b3463b, 0x420fe94f, 0xf3970f4d, 0x4f0cac41, 0x5f480d49, 0x4cf39908, 0x759b0faf, 0xd941f3a5, + 0x45908e0d, 0xe741066b, 0x12ef4806, 0xb30fb944, 0x1a05428f, 0xef488e8e, 0x41a1b733, 0xe547253d, 0x0c31420c, 0x0220ba8c, 0x4805cb43, 0xd54117ef, + 0x0cdd430f, 0x4119ef48, 0x00200dba, 0x485bff4e, 0x909025f3, 0x4330ab47, 0x51460fc3, 0x0daa4424, 0x20199241, 0x233f4200, 0x420fc142, 0xa18f0f3f, + 0x4617e743, 0xac8d1725, 0x42181946, 0x0b450c4b, 0x0fa94711, 0x8f0f4142, 0x324741c5, 0x420dcc41, 0x47410cce, 0x41a19f33, 0xb89a4947, 0x4132f348, + 0x59410fff, 0x4c404428, 0x9f47f348, 0x238541cd, 0xd942d8a5, 0x0d564225, 0x27450020, 0x066f4606, 0x8f10bd55, 0x182745bd, 0x431a5246, 0x1149114b, + 0x0fe1430f, 0x2341758f, 0x19234517, 0x501b9244, 0x8f8b5953, 0x4a0d1041, 0xdb431b76, 0x0f114123, 0x8f0f1343, 0x2353501f, 0x99263d41, 0x10ab48ba, + 0x8f0f2345, 0x45b58f95, 0x48412423, 0x0ca5450d, 0x440ecb42, 0x6942126b, 0x42a18f2f, 0x6b461779, 0x19854225, 0xb786b98c, 0x5008f349, 0x64417217, + 0x18f2410d, 0x134eb68c, 0x1f034225, 0xc9421f9f, 0x328d4123, 0x0021e2a6, 0x0c474a03, 0x45002f21, 0xcf8f2021, 0x4a183145, 0x36421965, 0x444f4919, + 0xe342a18f, 0x0b1f4417, 0x46192b44, 0xe3442575, 0x2f2d4413, 0x3d44b78f, 0x41b89924, 0x0e420c65, 0x48002018, 0x59444707, 0x41cd8f0f, 0xdb421785, + 0x41d89917, 0xe49b1891, 0x41123b45, 0xc18f1f9f, 0x9f41e18f, 0x1748530c, 0x41199c54, 0xf6450c9f, 0x2587441b, 0xbd8f9d8f, 0x2f8f0f8f, 0xb1179f41, + 0x189f41d8, 0x7f53e49b, 0x1fa14114, 0xe39fc38f, 0x420cb141, 0x17971778, 0x410d664d, 0x78420cbd, 0x0d4f4618, 0x63540620, 0x545f2012, 0x15415165, + 0x17d9410f, 0x1797e897, 0x410d0041, 0x0c4118e5, 0x00012825, 0x0109009a, 0x627f0010, 0x09201fe3, 0x12296884, 0x18191112, 0x00001111, 0x62378502, + 0xfd214de3, 0x86648ccb, 0x178b5463, 0x470f774e, 0x734817c1, 0x87fe210d, 0x0320638c, 0x0753c78c, 0x5f75a722, 0xb2421919, 0x418e8e0c, 0x01200757, + 0x43168b54, 0xf3970f59, 0x200c8b54, 0x21f18cbc, 0xf3a00000, 0x75a7e38f, 0xb94ff399, 0x86908e0d, 0x298b548f, 0x05428fb3, 0x0c02450d, 0x00218e8e, + 0x0e134204, 0x8f12274b, 0x410f9f81, 0x314117a7, 0x193d410b, 0x9c0c3142, 0x063f42ba, 0x45082358, 0xd9410fb9, 0x1889450f, 0x430d6444, 0x00200e98, + 0x63074342, 0x9090788f, 0x8a054342, 0x41f98f8f, 0x09410fa1, 0x26964128, 0x420ec843, 0x8f890543, 0x46124342, 0xa19f0f1f, 0x99233f46, 0x182746ac, + 0xdb41b88e, 0x0f4b4113, 0x8f0f3b41, 0x185542b9, 0x20449e99, 0x324b411b, 0x4b41a19f, 0x20b89b49, 0x05474d00, 0x1f670920, 0x002f2208, 0x31d94d3f, + 0x41345d41, 0x4c441969, 0x00052329, 0xbb8d009a, 0x8f328b5d, 0x410f8fbd, 0xd8992f89, 0x4518e142, 0x63481b31, 0x18eb6405, 0x420f4742, 0x5e4618d9, + 0x2253430d, 0x8f1f3152, 0x23274179, 0x410db445, 0x918f0ce8, 0x47062f45, 0x9d441973, 0x418fb30f, 0x904a0d14, 0x478e8f0b, 0x2f450673, 0x0f39421c, + 0xd956a1ab, 0x19d95f17, 0x9c0c3d41, 0x064f49ba, 0x450a3b66, 0xb98f0f2f, 0x55420f8f, 0x41b68b18, 0xd3420d4c, 0x222f451b, 0x8f1f0957, 0x237d42a1, + 0x41199943, 0xb99b0c4b, 0x54082f45, 0xbbbf3ba3, 0x4d0d6841, 0x354a1846, 0x242b450d, 0xc142998f, 0x8f1f8f0f, 0x17454a0f, 0x4117ab62, 0xe2a62691, + 0x6007e742, 0xe74209c3, 0x0f33441f, 0x500ce742, 0xc44417d0, 0x22e74229, 0x8f1f6141, 0x17e742a1, 0x8146aca5, 0x10ee4418, 0x4113ef44, 0xcb8f1f4d, + 0x5d41bb8f, 0x173c500c, 0x4243f044, 0xad8f24eb, 0x8f0fcb42, 0x41cd8f1f, 0xd8b11789, 0x45189541, 0x5b421bd5, 0x1f9f4112, 0x0f8fe18f, 0x420c9f41, + 0xb2431750, 0x1c444526, 0x8f449f41, 0x410f8fbd, 0xd8b1179f, 0x9b189f41, 0x41e394e4, 0x73421fa1, 0x8fd38f0f, 0x0cb1410f, 0x41237842, 0x704526bd, + 0x4b062026, 0xa754127f, 0x41f58f52, 0x004117d9, 0x18e5413d, 0x20260c41, 0x07735400, 0x20053769, 0x1139691f, 0xbd41c78f, 0x1b1c5318, 0x4b104750, + 0x0f8f0fa7, 0x3d41758f, 0x0de24623, 0x4b1c414e, 0xc94920a7, 0x488fa31f, 0x76430df1, 0x13b7461b, 0xab1f1141, 0x3ea74ba1, 0xa74bba9c, 0x055b5508, + 0x00002f22, 0x411fe969, 0x5c4233db, 0x0b77580c, 0x460d2f4a, 0x4741125f, 0x0f11470f, 0x4a1fbd44, 0x85422f1d, 0x50b8991b, 0xa34b09d3, 0x0f39411b, + 0xb142bbcf, 0x46ba991a, 0x75411433, 0x8fb98f0f, 0x42c9b70f, 0xe2994bd9, 0x4221a34b, 0xdf8f0f55, 0x470c3545, 0x3a4217cc, 0x30e7421b, 0x9f0f5141, + 0x17d144a1, 0x8746aca5, 0x1c79450b, 0x4434bb53, 0x5d411feb, 0x2350470c, 0x4f0d6941, 0xeb422948, 0x0f794124, 0x9f0f0b42, 0x178941cd, 0x1d48d8b1, + 0x1bd14518, 0x4a124345, 0x4b420f01, 0x41f19f0f, 0x50423e9f, 0x1aa6430d, 0x9f410020, 0x41cdaf34, 0xe4a8559f, 0xa141e394, 0x0f73420f, 0xb1410f8f, + 0x65704538, 0xaf46a34b, 0x23d941f5, 0x43310041, 0xd6422585, 0x4e0b551b, 0x4717d245, 0x7e461afe, 0x23af4a0d, 0x411fe544, 0x7b410f9b, 0x45ac9717, + 0xbb8737c2, 0x431b6749, 0xbbbf1f1d, 0x4d0d6841, 0xf74326aa, 0x1f674914, 0xe942c9bb, 0x32914117, 0x9b41e2a6, 0x1fd94413, 0x7b46e19f, 0x0d9c4130, + 0x430c2947, 0x9f411ca3, 0x1f154324, 0x2543cd9f, 0x311b4817, 0x9a19f448, 0x43e386e5, 0xbb5c0a3b, 0x41e3db32, 0x76420dbc, 0x20e29a18, 0x267b4600, + 0x9f0f0344, 0x4e1f9fd5, 0x9d582f67, 0x1a174517, 0x45340e41, 0x934313eb, 0x0f1b411f, 0x93430f8f, 0x17a86c0c, 0x43265357, 0xa6460ca0, 0x350f4a0e, + 0x0f9fad8f, 0xb1179343, 0x252948d8, 0x7744e48e, 0x1fa14114, 0x8f1f8d42, 0x0cb141f3, 0x46176c44, 0x93435918, 0x9fd59f26, 0x41f58f1f, 0x004117d9, + 0x18e5413d, 0x41189f43, 0x00200ef1, 0x4115d742, 0xdd8f1ff3, 0x411f0d41, 0xdb410cf3, 0x32864417, 0x450cb143, 0xf3411989, 0x41f5af46, 0x004117f3, + 0x18f3413d, 0x21260c41, 0x97460000, 0x1ff54117, 0x9f1fe541, 0x0c05421f, 0xa317f842, 0x4f984617, 0xc7590720, 0x6e6f2014, 0x51426171, 0x1731420f, + 0x43231441, 0x3d42253e, 0x18314418, 0x27195643, 0x57010100, 0xcc010900, 0x18059b6e, 0x6e1c2743, 0xd3650d9c, 0x179b6e06, 0x410f894c, 0x06421715, + 0x0e716a0d, 0x8f0e3766, 0x970f8f53, 0x0d054a63, 0x5a0e2660, 0xdf41208b, 0x4d759b0f, 0xe58d1723, 0x8e0c6b4b, 0x075b6c8e, 0x4c179b6e, 0xf3970f31, + 0x460c2159, 0xf3a00f30, 0x9b0f0353, 0x52f3a575, 0x908e0dcf, 0x41207f5b, 0x8fb30f83, 0x450d0542, 0x8e8e0c68, 0x4113e34a, 0x918f0ff5, 0xa1a70f8f, + 0x42253d41, 0xba9c0c31, 0x43020021, 0x431805cf, 0x98434e2b, 0x13bf6c0e, 0x460f2141, 0x53420f49, 0x17b9420f, 0x90250b77, 0x10d34290, 0x8f1f0947, + 0x24d946af, 0x5729c843, 0x718f1237, 0x420f2141, 0x2f8f0f43, 0x46173141, 0xac8d1759, 0x44183546, 0x77700f81, 0x0f4b4112, 0x420fcb41, 0x4b410fed, + 0x1b204432, 0x9f324b41, 0x494b41a1, 0x9b6eb89b, 0x285d4145, 0x4e4f4c44, 0x9542144b, 0x1fc5420f, 0x8f0fd542, 0x238941cd, 0xe142d8a5, 0x1b314518, + 0x18062f45, 0x42173343, 0x017e0f47, 0x0d5e4618, 0x41225343, 0x17410f47, 0x41798f0f, 0x2f451727, 0x0c354619, 0x7347918f, 0x0fd74120, 0x14418fb3, + 0x1b0a680d, 0xab337347, 0x174142a1, 0x9c263d41, 0x318f59ba, 0x450feb41, 0x4c41242f, 0x1bd3420d, 0x8f222f45, 0x43a54381, 0x4933fe7d, 0xf3570f7a, + 0x0f294313, 0xcf0ff741, 0x0d6841bb, 0x8d18544d, 0x242b45ba, 0xc9bba98f, 0x4817d142, 0x1b44250d, 0x21e2a60c, 0x5b4a0300, 0x3f43180c, 0x0f334422, + 0x18183d45, 0x44263f43, 0xe7420ec4, 0x1f614122, 0x6545a18f, 0x19334423, 0x8e188146, 0x351748b8, 0xbb8fcb8f, 0x99244544, 0x181242bc, 0xeb42bc90, + 0x42ad8f24, 0xcd8f1ffb, 0x42178941, 0xd89917df, 0x45189541, 0x5b421bd5, 0x0f054b12, 0x0f8fd18f, 0x410f6345, 0x40540c9f, 0x0dc04b23, 0x450c9f41, + 0x0f561bfe, 0x2f454515, 0x9f41cd9f, 0x41d8b117, 0xe49b189f, 0x41148342, 0x93421fa1, 0x1cb1411f, 0x97177842, 0x1abd4117, 0x56267045, 0xf5af46f3, + 0x9717d941, 0x411797e8, 0xe5410d00, 0x260c4118, 0x50000021, 0x1b5307db, 0x0fad5407, 0x460fb142, 0x1c53186d, 0x1047501b, 0x8f0f3743, 0x41758f0f, + 0x9f44173d, 0x1c414e19, 0x4220a74b, 0x8fb30fb3, 0x430df148, 0xa74b1b76, 0x48a1ab33, 0x3d4117d5, 0x29164519, 0x8b599b6e, 0x0c5c429d, 0x46197857, + 0x5942125f, 0x0f11470f, 0x601fc743, 0x47412333, 0x0d854219, 0x9b6eb899, 0x91511879, 0x0cb14219, 0x3346ba99, 0x0f754114, 0x8f0f3f43, 0x3785410f, + 0x994bd942, 0x21a34be2, 0x8f0f5542, 0x183545df, 0x4219a34b, 0x174d0d3a, 0x22e7420d, 0x9f0f5141, 0x236145a1, 0x6e19e742, 0xbc99a29b, 0x4229ec44, + 0x794124eb, 0x0f0b420f, 0x5c2bb945, 0x631817bb, 0xda433efb, 0x0d5a420c, 0x4a138b46, 0x4b420f01, 0x4bf19f0f, 0xd8480ca3, 0x199f4117, 0x430d0943, + 0xa34b1aa6, 0x43cdaf35, 0xd8b11729, 0x9a193543, 0x148342e4, 0x420fa141, 0x0f8f0f73, 0x4538b141, 0xa34b6570, 0x41f5af46, 0x004123d9, 0x18a34b31, + 0x410c8543, 0x00201af1, 0x6a077f46, 0x55180813, 0xb04a5563, 0x227f4629, 0x411fe544, 0x7b410f9b, 0x17e16717, 0x450d074d, 0x0b5529c2, 0x41bbbf43, + 0xaa4d0d68, 0x14f74326, 0x431f6749, 0xc99b1fe7, 0x4523e942, 0x914119b4, 0x41e2a60c, 0xd944139b, 0x46e19f1f, 0x9c41307b, 0x29a3430d, 0x43249f41, + 0xcd9f1f15, 0x46172543, 0x9f41317b, 0x6ee5a70c, 0xc14c949b, 0x18764219, 0x461b6c45, 0x3943267b, 0x1fb9410f, 0x674e1f9f, 0x3ee54123, 0x21340e41, + 0x9f580400, 0x074e180e, 0xf1761846, 0x0b014d08, 0xec450b97, 0x24934337, 0x411f9941, 0x0f8f0fe9, 0x46179343, 0x334517b9, 0x25294819, 0x940eaf4b, + 0x3f3545e3, 0x4545e38f, 0x44e49930, 0x92420c78, 0x43e48d18, 0xc9412693, 0x8f1f9f1f, 0x17d941f5, 0x41238743, 0xe5411900, 0x260c4118, 0x9b6e0020, + 0x41f29997, 0x6c460cf3, 0x46f34126, 0x420fd341, 0xf3411f03, 0x23815917, 0x41190041, 0x0c4118f3, 0xb69b6e26, 0x42191041, 0xf8420c11, 0x1ba74718, + 0x41d09b6e, 0x3d42192c, 0x33384118, 0x2106ff6d, 0x70187f00, 0xb86e3d33, 0xa65b180c, 0xcb43180e, 0x0fa74c11, 0x491f7351, 0x1448230d, 0x0dbb6a0d, + 0xef59908e, 0x4c8fc320, 0xdf5f0d38, 0x4f8f8e0d, 0xb744223f, 0x4da1b70f, 0x3d4117c5, 0x0c8e430d, 0xef59ba9c, 0x45b98f21, 0xdb410f71, 0x0cef5923, + 0x410c0b48, 0x47410c49, 0x0f374122, 0x47419db7, 0x0daa5425, 0xef59b899, 0x42bbcf35, 0x8a460db1, 0x4aba990c, 0xdf43146f, 0x9fa98f0f, 0x2723420f, + 0x17755e18, 0x42402567, 0xbf440c56, 0x0f4f4b11, 0x8f0f5542, 0x242f4bbf, 0x440d8243, 0xe7421bc0, 0x9f818f22, 0x17e748a1, 0x8d17db4a, 0x0b9146ac, + 0xb792b89a, 0x420f4941, 0xb79f0f19, 0x43185941, 0xe84425a0, 0x24e74229, 0xaf0f7541, 0x238541cd, 0x2348d8a5, 0x1bcd4518, 0x41229f41, 0xe18f0f8f, + 0x410f0141, 0x40453e9f, 0x349f4129, 0x9f41cdaf, 0x94e4a855, 0x1f4143e3, 0x8f0fa141, 0x34b1410f, 0x43258442, 0x4f460c5d, 0x56e74d26, 0xd941f59f, + 0x2500412f, 0x41188543, 0x0376260c, 0x19eb5909, 0x410fc342, 0x244728cf, 0x0dfa470b, 0x472e2344, 0xd5560fed, 0x41a19f0f, 0xd147237b, 0x18b99b26, + 0xcf34935d, 0x0d6841bb, 0x48191c6b, 0xf7430c80, 0x0f754114, 0xab1fe142, 0x17dd42c9, 0x43250d48, 0xe2a60cf6, 0x9f33eb59, 0x307b46f1, 0x430d9c41, + 0x9f4129a3, 0x0f154324, 0x0f8fbd8f, 0x430fc743, 0xb7412325, 0x0dad4917, 0xa70c9f41, 0x44eb59e5, 0xbc41e3db, 0x180a510d, 0x1819c94c, 0x4318ef41, + 0xe58f2f69, 0xd9410f8f, 0x17c1411b, 0x970b7943, 0x1ae54123, 0x63340e41, 0xdb8f23fb, 0x431f6544, 0x44550c93, 0x45d49a23, 0x93431cec, 0x0f894124, + 0x9343cdaf, 0x48d8b117, 0xe49b1829, 0x0f4ae394, 0x41f38f1f, 0x00462cb1, 0x41179717, 0x18461abd, 0x460f4a26, 0xd941f5af, 0x97e89717, 0x0d004117, + 0x4118e541, 0xeb59260c, 0x0fe74247, 0x430f1d41, 0x864424a5, 0x266c4632, 0x8f46f341, 0x8f0f8fe5, 0x17f341f5, 0x4117cd43, 0xf3412500, 0x260c4118, + 0x4159eb59, 0x05421f0f, 0x17e0420c, 0x59739846, 0x214168eb, 0x1731421f, 0x42492c41, 0xd147183d, 0x07f75833, 0x08376018, 0x431fdd73, 0x11420f21, + 0x26ac5724, 0x1809f356, 0x18088769, 0x49125b72, 0x91412f7b, 0x0d9f452f, 0x4e288951, 0xf14b244b, 0x0f5d411f, 0xf14abbaf, 0x264e440d, 0x41143348, + 0xc9bb1f65, 0x43172545, 0x91411723, 0x34ab4c0d, 0x7606c754, 0x2f2206c3, 0x63183f00, 0x9b413121, 0x0c04433f, 0x4f18b75e, 0xc7610ce5, 0x0f9b4116, + 0x441faf49, 0x9b412bb3, 0x0d2d433d, 0x474ee4a6, 0x9fc39f24, 0x23535c1f, 0x43177f42, 0xe2a61a55, 0x17375018, 0x8f0fc941, 0x420f8fc5, 0x1f9f0f83, + 0xe541f597, 0x1981433d, 0x4e270e41, 0xd5422347, 0x46eb9f0f, 0xa0490c89, 0x19345417, 0x500dba42, 0x2f451b13, 0x0fa94124, 0xf945cdaf, 0x72d8b117, + 0xe49a1943, 0x474ee394, 0x2f13461f, 0x430cb141, 0x1797177c, 0x4c411446, 0xf5af4653, 0x9717d941, 0x411797e8, 0x154a0d00, 0x26044818, 0x4227474e, + 0xe7420fc7, 0x2ca5430f, 0x1797da97, 0xb143f28d, 0x257a440d, 0xbf36f341, 0x61f341f5, 0x4e330c41, 0xe5413947, 0x431f9f1f, 0x984618f9, 0x48474e7f, + 0x9f1f0141, 0x2331421f, 0x443d2c41, 0x56432531, 0x60ab5925, 0x4923f646, 0xe9461aa6, 0x26634b1a, 0x411fe545, 0xd8a337cf, 0x490df644, 0xe59a197d, + 0x4524634b, 0xe3db1fcb, 0x500dbc41, 0x634b33ca, 0x43f5cb37, 0xe5411791, 0x340e413e, 0x1807eb7c, 0x490d2764, 0x0d411fc3, 0x451f8f1f, 0x987e18c9, + 0x0df44123, 0x440ca948, 0xcf472677, 0x1fbd4326, 0xe942d58f, 0x17b84837, 0xd9431797, 0x260d4127, 0x4108af5c, 0x77180cf3, 0x2f415257, 0x23ad460f, + 0x42311042, 0x0e4118f6, 0x28cb4725, 0xbf1fed41, 0x17854f1f, 0x42231141, 0x36413239, 0x2341183e, 0x1f374415, 0x8f0f2341, 0x0f31420f, 0x770c3744, + 0xfcb21708, 0x470c4444, 0x37441910, 0x8fb58f26, 0x8f0f9fd5, 0x1727433f, 0x493d0041, 0x0c4125c9, 0x39074c19, 0x0f41df8f, 0x0c05422f, 0x4717ed41, + 0x3b44733c, 0x1f014128, 0x31411f9f, 0x422f8f0f, 0x2c411731, 0x183d4249, 0x42184744, 0x57431a49, 0x2f3d4416, 0x410f0541, 0x47421f25, 0x232f420c, + 0x47173e41, 0x47424f90, 0x1f014148, 0x47421f9f, 0x492c4117, 0x45184742, 0xba470c92, 0x41002025, 0x49421837, 0x2f39421f, 0x421f3741, 0x35420c59, + 0x4217af17, 0x74431a65, 0x25384118, 0x67180820, 0x7f20168f, 0x71916718, 0x420f8941, 0x3c411781, 0x412f972f, 0x8d420d54, 0x3e604118, 0x00000034, + 0xff960002, 0x02d30181, 0x002100da, 0x01000043, 0xce181110, 0x27200849, 0x0c55de18, 0x85363721, 0x18032001, 0x180881f5, 0x0813ffc2, 0x1716175e, + 0x2ad30116, 0x1e1e2424, 0x13131919, 0x09090e0e, 0x05040405, 0x0e0e0909, 0x19191312, 0x25251d1e, 0x12111208, 0x0f0e1010, 0x0a0a0c0c, 0x03040707, + 0x07070403, 0x0c0c0a0a, 0x10100e0f, 0xda021112, 0xe2fec5fd, 0x150f1009, 0x1d191916, 0x2320201d, 0x24232422, 0x21232323, 0x1d1f2022, 0x16395482, + 0xfd0f0f15, 0xe5ca0105, 0x100a0b04, 0x18151410, 0x1c1a1a18, 0x1e1d1d1d, 0x2a04821e, 0x181b1a1c, 0x10141418, 0x910a0b10, 0x101722db, 0x0bc71811, + 0x18a78308, 0x850b87c2, 0x3d0d19cb, 0xaff11809, 0x29963717, 0x1e1e2524, 0x13131818, 0x090a0e0f, 0x04050504, 0x0e0d0a09, 0xda821213, 0x24251e2b, + 0x11121108, 0x0e0f1010, 0x21da830d, 0x00820406, 0xda830620, 0x0f0e0d2d, 0x12111010, 0x013b027f, 0x840f091e, 0x841e20d9, 0x842320d9, 0x832220d9, + 0x191d22d9, 0x28d98219, 0xfefb0210, 0x0a05e536, 0x20d9820b, 0x23d98214, 0x1c1d1c1b, 0x1b23d986, 0x8319181a, 0x0b0a2dd9, 0xc8000100, 0xec0168ff, + 0x2100f402, 0x0a6bc118, 0x18351021, 0x240acbcd, 0x10070617, 0x2ced8315, 0x01060706, 0x2c2d1db9, 0x1415172b, 0x38078710, 0x0a100f0a, 0x2c1a2369, + 0x100a1b2b, 0x2a1c980f, 0x14162829, 0x2f010f13, 0x300a8797, 0x090e0e0a, 0x90fe2063, 0x292819b7, 0x0f0e0a18, 0x20738200, 0x2073827d, 0x207385a1, + 0xd3bc1817, 0x35102307, 0x75832726, 0x20075741, 0xadd91810, 0x09af2407, 0x82091010, 0x5d1a2260, 0x2109832e, 0x80832c1e, 0x10152508, 0x2a2d2c1e, + 0x98151418, 0x0a0e0f0a, 0x19282918, 0x578a9d01, 0x0e0e092c, 0x2a291c0a, 0x14131628, 0x97d1fe0f, 0x00200a86, 0x13197383, 0x002109cf, 0xd3d01805, + 0x1837200e, 0x180efbc6, 0x18202fc2, 0x831f0bc2, 0x002c336f, 0x023c0235, 0x00270026, 0x35343700, 0x35342322, 0x03833332, 0x89151421, 0x15142207, + 0xb5301922, 0x5ca62e0b, 0x3f1f5b1e, 0x3f1d5715, 0x5c1e5c15, 0x2609841e, 0x3c349d35, 0x85349c14, 0x143c2301, 0x0183349d, 0x37205f8b, 0x6f875f9a, + 0x8b82678e, 0x65287784, 0x0e2b0e2b, 0x143d153f, 0x0d890385, 0x3f153c22, 0x7d83778c, 0x7f857b87, 0x2800032d, 0x410226ff, 0x0f00d702, 0x82001f00, + 0x14252483, 0x18230607, 0x300ad7ae, 0x16171405, 0x36373233, 0x26273435, 0x06072223, 0x452e1913, 0x41023416, 0x85874343, 0x44434344, 0x43438785, + 0x32312dfe, 0x82326363, 0x21058200, 0x6119f531, 0xfe3f0eb3, 0x767675ed, 0x77eced75, 0xec777676, 0x666665cc, 0x66cbcc65, 0xfe666767, 0x060403e8, + 0x1907264e, 0x2d0a62f0, 0x004b0001, 0x021e0252, 0x004f0009, 0xc7183700, 0x18190a75, 0xf7410cc7, 0x0ded4207, 0x83070621, 0x0b134201, 0x0e0d2119, + 0x130b8638, 0x20150b12, 0x0f102020, 0x20160c0f, 0x0f111f20, 0x120b0b0f, 0x0b870b12, 0x0f0f0c27, 0x20201f11, 0x88278315, 0x0f0f221f, 0x84328210, + 0x830b2013, 0x201f221f, 0x2d078416, 0x0b522020, 0x140b1011, 0x0f1e1e1e, 0x07820e0e, 0x101d1f22, 0x0a230782, 0x830a1112, 0x2eda1813, 0x141e2409, + 0x8212110a, 0x231f8513, 0x0f0e0e0b, 0x14243282, 0x0b11100b, 0x0762df18, 0x1f340784, 0x0000001e, 0x002c0002, 0x023c02e9, 0x00170020, 0x01000057, + 0x22167d41, 0x82353405, 0x49c618fb, 0x1367190c, 0x2fd71919, 0x9dc51912, 0x26262712, 0x0d0c2726, 0xdb190f0c, 0x9021339d, 0xf1e01904, 0x8cdb190e, + 0x00002136, 0x68b7dc19, 0x17d1ba19, 0x3fdc0129, 0x03040820, 0x83080403, 0x04042407, 0x4148fe04, 0xad223a19, 0xde192040, 0x29410d19, 0x19bb2047, + 0x2411b6dc, 0x2a000100, 0xc3e31800, 0x083b4308, 0x20151423, 0x3f038233, 0x1ec61423, 0x1d1d3130, 0x011e3031, 0xe6fe5e1a, 0x2d1cb75e, 0x2e1b1c2d, + 0x143c1c2d, 0x003b2164, 0x22080082, 0x00990001, 0x02d0014f, 0x00110044, 0x35103700, 0x37362322, 0x17163736, 0x23221716, 0xed221510, 0x841d1c38, + 0x1d312d41, 0x4f6c153f, 0x1c580a01, 0x1c1c2e2d, 0xfe224182, 0x3f9058f6, 0x27262525, 0x18322726, 0x240899cb, 0x01060706, 0x827c8234, 0x246b213a, + 0x312c4882, 0x2e1b4f31, 0x0a011b2e, 0x59f6fe59, 0x3f850982, 0x68004626, 0xfa01f101, 0x081bc418, 0x0bddc418, 0xc5823220, 0x0ac5e718, 0x13aa3b08, + 0x20131f1f, 0x192f3231, 0x0c121717, 0xa60c1312, 0x12120c37, 0x1717110c, 0x32312f1a, 0x1e1e1268, 0x2e2e1e12, 0x1516182c, 0x11120a11, 0x0b458a0b, + 0x100a1211, 0x2d181516, 0xeb842e2e, 0x68007824, 0x6b852302, 0x5b87ab84, 0x32353423, 0x0e474433, 0x82be0121, 0x30192a56, 0x0b213131, 0x930b1312, + 0x246e8249, 0x3131200b, 0x827a8330, 0x11682886, 0x2c181615, 0x831e2e2f, 0x349b2168, 0x1a196883, 0x12260725, 0x00001e1e, 0x6b8b0001, 0x0bffe318, + 0x830b3747, 0x1514240b, 0x83470122, 0x21c68563, 0x5d822031, 0x31211328, 0x171a2f31, 0xde831117, 0x0b68a522, 0xc686cc82, 0x1e111f24, 0x6982121d, + 0x15182d24, 0x75831016, 0x82349b21, 0x0b43416b, 0x18353421, 0x87074ada, 0xf31e1969, 0x4622210b, 0x12256a83, 0x2f1a1716, 0x206a8432, 0x416a8314, + 0x1225054f, 0x8a68a50c, 0x87d08345, 0x1d12236c, 0x6c8a111e, 0xe6180b20, 0x1b200b33, 0x470aab45, 0x77480527, 0x34072306, 0x79422235, 0x37a62b0a, + 0x1d30311d, 0x1d31301d, 0x7f4237a6, 0x49e6180a, 0x3b1c2308, 0x57833b14, 0x82078742, 0x42252057, 0xde180547, 0x8d42074b, 0x42638305, 0x98420a51, + 0x095b420b, 0x42349c21, 0x9c26079f, 0x2e2e1b34, 0xf6180000, 0x1f2209f7, 0x35493100, 0x191f190a, 0x6fd41816, 0x07454608, 0x20191020, 0x1c202121, + 0x0e2b1f19, 0x30fc1e19, 0xb1bdfe21, 0x098d4ba7, 0x10992419, 0x28192520, 0x0f820e56, 0x1a1d3626, 0x2a1c141b, 0x0cc31f19, 0x0123a6a0, 0x191b8f1f, + 0x180d961f, 0x410c47f8, 0x25192d4f, 0xa7981241, 0x22064f41, 0x8699cefe, 0x26aaa0b2, 0x2627281a, 0x19131215, 0xb1073e20, 0x200321a7, 0x0839ca18, + 0x27ab2219, 0x3201f923, 0x08fa4199, 0x9f055a41, 0x0c0121a7, 0x0c20a890, 0x0897f918, 0x13000b39, 0x27001b00, 0x37002f00, 0x47003f00, 0x5f005300, + 0x6f006700, 0x4a130000, 0x22250519, 0x22151423, 0x01ea1837, 0x4a17200e, 0x1b8207ad, 0x1b860520, 0x07862120, 0x32210f96, 0x842b8233, 0x4a2f8e23, + 0x223b06f1, 0x20194b03, 0x44a32b0b, 0x41904316, 0x22bb4116, 0x2b194d0b, 0x0e2bc9fd, 0x821b022b, 0x2b098d04, 0x014b0a21, 0x2b0b22e3, 0x9bfe4c0e, + 0x012a3086, 0x281847ba, 0x290b1e0e, 0x01850e28, 0x0a1f2929, 0x18470e28, 0x85153f9b, 0x3d9b2201, 0x2e018514, 0x1f1848a9, 0x290e280b, 0x480a200d, + 0x830d2918, 0x0e283509, 0x03000000, 0x44ff6000, 0x1a02ef01, 0x63002300, 0x00007900, 0x0c2f0b19, 0x12a90719, 0x07141524, 0xd9181306, 0xed431b73, + 0x35342105, 0x1021f183, 0x200d8515, 0x07eb4d32, 0x15143722, 0x84193b82, 0x19190a87, 0x012f0a53, 0x0d0d0b78, 0x0d0c100f, 0x05060a0b, 0x820a0505, + 0x07270803, 0x09080707, 0x0b0d0d0f, 0x0505040b, 0x19170c04, 0x25301918, 0x0e1c1b26, 0x0904040e, 0x18101008, 0x1606050b, 0x8209090c, 0x0104282a, + 0x18480102, 0x82040504, 0x03200800, 0x0b0c0b03, 0x0c0c0c0b, 0x1818180d, 0x07080395, 0x0a0a0f04, 0x03040606, 0x0d0d0606, 0x9f010c0d, 0x052d5b83, + 0x0d0d0a0a, 0x0c0d1010, 0x0303040a, 0x823e8203, 0x0c0a2172, 0x0d221183, 0x2b82a8fd, 0x170b0b2e, 0x251f1e16, 0x0f111012, 0x1613140f, 0x14243282, + 0x08090a0a, 0x072b9282, 0x09090907, 0xd9fe143c, 0x82010193, 0x02012175, 0x20089c82, 0x07080606, 0x0e1e3b08, 0x873f0a0a, 0x07060443, 0x0c0c0d04, + 0x0c0b0a09, 0x100f160d, 0x06070a0a, 0x2f008200, 0x002c0002, 0x013c023f, 0x003f0072, 0x37000047, 0x273e634a, 0x32353417, 0x22151433, 0x3be1d519, + 0x205eb62e, 0x1b37e95f, 0x020e0e1b, 0x05030201, 0x2cd8e519, 0x6b246b29, 0x00010024, 0x198401e7, 0x2107736d, 0x91851013, 0x95822320, 0x359fe725, + 0x82461e59, 0x5601251b, 0x45d01032, 0x2b82fe82, 0x0f82ad20, 0xdb028127, 0x00000b00, 0x074d4301, 0x22151032, 0x1e5a2501, 0x0145359f, 0x3146cf84, + 0x56fffe11, 0x57822c82, 0x0181ff25, 0x83d800bb, 0x8517202b, 0x31ed8457, 0x591746e7, 0x017f9f1e, 0x44cf5601, 0x01001133, 0x2782ad00, 0x27868120, + 0x82074b4e, 0x6f6d1953, 0x45ce2208, 0x335182fe, 0xff6d0002, 0x02fc01ee, 0x005700cb, 0x2500007b, 0x35343534, 0x0b3dfc18, 0x180c9151, 0x210c6fd3, + 0x00191514, 0xd4180ed1, 0xe3500b8b, 0x20058505, 0x18f58215, 0x18178ddc, 0x080ca5e4, 0x01011f25, 0x02010201, 0x05060303, 0x0a0c0808, 0x16170506, + 0x0909100f, 0x0e0e0505, 0x26261c1c, 0x3130332e, 0x8217192d, 0x15330854, 0x161a1416, 0x09101015, 0x07030308, 0x0e090a07, 0x1606050c, 0x070c0c0f, + 0x03060508, 0x48020103, 0x0d0c0b4b, 0x0d0d100f, 0x05060b0a, 0x040b0505, 0x82070506, 0x05314300, 0x052a1082, 0x0c1427bc, 0x07070a09, 0x1a820706, + 0x07070636, 0x0a0b0908, 0x14140505, 0x100f1212, 0x25131212, 0x17171e1d, 0x0e3f4282, 0x111e3b1a, 0x08090b0b, 0x07060404, 0x11100d0d, 0x0b0c0d15, + 0x0b0c0a0a, 0x06050b0d, 0x820c0e14, 0x0b0c2d0c, 0x0e0e0b0c, 0xbb133610, 0x0404050a, 0x200b3b43, 0x43898304, 0x002f093b, 0x00020000, 0x0282ff8b, + 0x0046032c, 0x19550009, 0x2308c951, 0x03060706, 0x08afec18, 0x0d6d1019, 0x35363722, 0x180f7f48, 0x180e47db, 0x080d25db, 0x1514152c, 0x1f5c8b22, + 0x17272617, 0x0d120809, 0x11191213, 0x0a210909, 0x07070809, 0x08040606, 0x1f3d0404, 0x19282819, 0x18282818, 0xd8421745, 0x05062f05, 0x0a090708, + 0x170b0a0a, 0x0b0a0d0b, 0x27820908, 0x01043008, 0x25015c02, 0xfe899801, 0x180e9cc6, 0x864ffe17, 0x1e1f2543, 0x11101118, 0x05050a0e, 0x07070615, + 0x08080708, 0x16151106, 0x1b23671b, 0x831b2c2c, 0x356b2b03, 0x10111113, 0x0c0e0d0f, 0x70820a0b, 0x07080924, 0x0482070e, 0x0a08092a, 0x100b0c0a, + 0x3297120f, 0x8524ff83, 0xf30182ff, 0x0b26ff82, 0x00003700, 0x60192201, 0x172409cb, 0x23221510, 0x24064f42, 0x16171627, 0x84c98217, 0xdbf3181d, + 0x081f820b, 0x35343527, 0xd09a0132, 0x90153f45, 0x1e3c5931, 0x18181911, 0x090c0b0d, 0x02030402, 0x1e3b1540, 0x18191910, 0x090b0c0d, 0x08008202, + 0x0101013c, 0x017a0140, 0xd9fe7359, 0xfe3b3263, 0x372473a6, 0x1a1c3637, 0x3d261419, 0x194b263e, 0x25735a01, 0x1d353737, 0x1a131a1a, 0x15272829, + 0x3d0e1313, 0x03000014, 0x82ff3100, 0xa3823802, 0x47003122, 0x07b3d718, 0x35262728, 0x37343510, 0xa7413336, 0xcb1e190c, 0x32152a0d, 0x10151617, + 0x06071415, 0x18a78203, 0x21093dd5, 0x35833215, 0x03262725, 0x19363534, 0x8909a309, 0x08eb841f, 0xdd013257, 0x172c71e2, 0x26141416, 0x07070304, + 0x1a0c0a0a, 0x27262020, 0x0d192120, 0x07070a09, 0x14270304, 0x91171713, 0x1511120d, 0x0d121115, 0x8e06060d, 0x2e07062f, 0x060b0a16, 0x0e0d0a06, + 0x0e10100e, 0x060c0c0e, 0x150b0c06, 0x16167e36, 0x8a14012a, 0x7a17172d, 0x0850823d, 0x0f11113e, 0x0c1b0d0e, 0x1b0c0d0d, 0x110f0e0d, 0x16141411, + 0x17173d7a, 0x8aecfe2d, 0x0316162a, 0x08080f58, 0x0f0f0908, 0x891a1414, 0x1a3d7a2e, 0x45fd1514, 0x110a4182, 0x0d101810, 0x050b0b0d, 0x0b3a0082, + 0x100e0d0c, 0x0a111016, 0x00003192, 0xffd8ff01, 0x03680219, 0x00150083, 0xf6180300, 0x2b081273, 0x35281023, 0x3231261b, 0x6a6a6637, 0x6a6a4646, + 0x31323766, 0x03143c26, 0x31312683, 0x69696536, 0x66674546, 0x30303663, 0x004f0324, 0x01240082, 0xe3fec8ff, 0xb8264f82, 0x00002f00, 0xcf420601, + 0x1f83510a, 0x1617163f, 0x43306802, 0x28274942, 0x353a2727, 0x110b2935, 0x67440a12, 0x31356467, 0x67452530, 0x35648367, 0x11120a25, 0x4342310b, + 0x28272749, 0x35353b26, 0x42314801, 0x0c834842, 0x34353a26, 0x11110a29, 0x8d843082, 0x68462528, 0x31366669, 0xf9822631, 0x43310a33, 0x28274a44, + 0x363c2629, 0x00010035, 0x0219ff00, 0x21ef8590, 0x9f433611, 0x33322306, 0xaf421110, 0x29e48208, 0x32313767, 0x35143b26, 0xf085471a, 0x46480125, + 0x83656969, 0xb0fc234f, 0x9482e6fe, 0xf1826220, 0xeb824b83, 0x8403a121, 0x772519eb, 0x3de51807, 0x4d5b8708, 0xeb831331, 0xdf82a120, 0xef8b0b20, + 0x282cd78a, 0x0a12120a, 0x36303025, 0x44676763, 0x20060341, 0x8bde83e7, 0x24d68aee, 0x11100a29, 0x0890410a, 0x63676626, 0x00313035, 0x1c220082, + 0xa5835601, 0x00240982, 0x20018f00, 0x01240b86, 0xd6011200, 0x02240b86, 0xf9010700, 0x03240b86, 0x27021200, 0x04200b86, 0x60200b82, 0x05240b86, + 0x7f020500, 0x06200b86, 0xab201782, 0x07230b86, 0x87033000, 0x00092453, 0x8671030f, 0x000a2417, 0x86e90333, 0x000b240b, 0x866d0427, 0x820c200b, + 0x86e5200b, 0x0f0d240b, 0x86732332, 0x000e2e0b, 0x00ee3223, 0x04010003, 0x01000009, 0x85ad821e, 0x0001240b, 0x86b00124, 0x00022417, 0x86e9010e, + 0x0003240b, 0x86010224, 0x8204200b, 0x863a200b, 0x0005240b, 0x8673020a, 0x8206200b, 0x86852017, 0x0007240b, 0x86be0260, 0x0009240b, 0x8651031e, + 0x000a240b, 0x86810366, 0x000b240b, 0x861d044e, 0x820c200b, 0x8695200b, 0x1e0d240b, 0x860d0564, 0x000e3e0b, 0x00a63246, 0x006f0043, 0x00790070, + 0x00690072, 0x00680067, 0x00200074, 0x00630028, 0x28078229, 0x00300032, 0x00390031, 0x220b862c, 0x82330032, 0x84542009, 0x8273202b, 0x00612229, + 0x200f826e, 0x240f8447, 0x006d006d, 0x20098265, 0x2051a20a, 0x20358238, 0x20778253, 0x202f8275, 0x22358263, 0x84460020, 0x006e220d, 0x20118264, + 0x221d8279, 0x82750041, 0x8268205f, 0x00722315, 0x53a10073, 0x99843020, 0xc7826220, 0x42002022, 0x7420c982, 0x74203582, 0x65224b82, 0x97826100, + 0x4920bf83, 0x6322ab82, 0x5b842e00, 0x6c006c22, 0x52200782, 0x7320f188, 0x65200d84, 0xc1833382, 0x91827620, 0x29826420, 0x77820a20, 0x6f430033, + 0x69727970, 0x20746867, 0x20296328, 0x39313032, 0x3205822c, 0x54203332, 0x74736972, 0x47206e61, 0x6d6d6972, 0x900a7265, 0x20383728, 0x72756f53, + 0x46206563, 0x646e756f, 0x41207972, 0x6f687475, 0x29907372, 0x2033303a, 0x42207962, 0x74737469, 0x6d616572, 0x6e49202c, 0x41202e63, 0x52206c6c, + 0x732f7883, 0x73655220, 0x65767265, 0x0a0a2e64, 0x82500000, 0x006f22d5, 0x22018267, 0x82560079, 0x006324a9, 0x826f0074, 0x82442013, 0x82742005, + 0x0065220b, 0x2f248264, 0x67676f72, 0x63655679, 0x44726f74, 0x6574746f, 0x52201382, 0x67222c82, 0xfa827500, 0x2e826120, 0x65520027, 0x616c7567, + 0xb850ba72, 0x00312389, 0x0383002e, 0x00003726, 0x2e312e31, 0x4ab80682, 0x2211eb41, 0x82560020, 0x007228e8, 0x00200061, 0x82730069, 0x20098305, + 0x22f28274, 0x82640061, 0x826d2019, 0x00722219, 0x2217826b, 0x8266006f, 0x42419105, 0x00200b2d, 0x36089641, 0x72655620, 0x73692061, 0x74206120, + 0x65646172, 0x6b72616d, 0x41666f20, 0x00210fb7, 0x1d1e4300, 0x37420020, 0x0000220e, 0x20848241, 0x0ac84176, 0xb4822f20, 0xa4826320, 0x03826c20, + 0x6c006222, 0x20211982, 0x201f8300, 0x24178272, 0x006f0069, 0x22ba886e, 0x84680074, 0x0b3d411d, 0x43002022, 0x9a433384, 0x84662005, 0x0074222f, + 0x2f66822e, 0x63657620, 0x2f726f74, 0x6c616373, 0x656c6261, 0x72240f82, 0x6e6f6973, 0x7434c483, 0x50206568, 0x67676f72, 0x6c432079, 0x206e6165, + 0x746e6f66, 0x68223482, 0x01827400, 0x79827020, 0x2f003a22, 0x67220182, 0x0f826900, 0x75006824, 0x53826200, 0x5d826320, 0x15826d20, 0x71826220, + 0x89827520, 0x83007321, 0x826e20b7, 0x42702011, 0x83870aa4, 0x00007339, 0x70747468, 0x2f2f3a73, 0x68746967, 0x632e6275, 0x622f6d6f, 0x8265756c, + 0x2f6e2291, 0x837e8470, 0xf6288377, 0x41542077, 0x77200651, 0x2442d982, 0x00692405, 0x8420006e, 0x826520f3, 0x17a74207, 0x85002021, 0x416a20f1, + 0x7a4206c7, 0x135c4507, 0x22335445, 0x82610020, 0x82642087, 0x006c2481, 0x82630069, 0x006e2265, 0x83058273, 0x84752011, 0x00652219, 0x24a78a72, + 0x0049004d, 0x200f8254, 0x232d8c4c, 0x000a000a, 0x4820e19f, 0x63226982, 0x3b826b00, 0xd445d1af, 0x24d3e92f, 0x00650044, 0x22d7826a, 0x92750056, + 0x827720d7, 0x82732019, 0x05cd4217, 0x69006d24, 0x46457400, 0x82202006, 0x416f2007, 0x70200a55, 0x62213f82, 0x05814100, 0x64002026, 0x6d006f00, + 0x69223b82, 0x2c466e00, 0x114a4406, 0x200b8c44, 0x212b8253, 0x6983006e, 0x39824d20, 0x03826e20, 0x2a472020, 0x00322214, 0x20018230, 0x149a4433, + 0x49002022, 0x4208c646, 0x9b9d2d11, 0x230d2742, 0x00770020, 0x2305e743, 0x00520020, 0x470d1647, 0x6e2205aa, 0x9f827400, 0xd1824e20, 0x1f846d20, + 0x22002022, 0x20127647, 0x87238222, 0x452220a5, 0x22220896, 0x01820a00, 0x2809a142, 0x00430049, 0x004e0045, 0x83058253, 0x13334319, 0x22919048, + 0x8250000a, 0x007226f9, 0x0069006d, 0x0a994573, 0x20220d83, 0x1b846800, 0x48006521, 0x67260590, 0x61007200, 0x55426e00, 0x002c2406, 0x82660020, + 0x82652011, 0x00202123, 0x20058446, 0x20318263, 0x20138261, 0x83138267, 0x8274201f, 0x051f4317, 0x2d827920, 0x4d847020, 0xfb457320, 0x82622008, + 0x82612049, 0x846e2077, 0x82672003, 0x42612021, 0x702106bf, 0x852f8300, 0x82742053, 0x838d8553, 0x82662039, 0x82772033, 0x84722085, 0x07954175, + 0xbb846120, 0x63006f24, 0x1b826900, 0x1b827420, 0x49826420, 0x69826420, 0x75006322, 0x6520db82, 0x6120b584, 0x69203b82, 0x66207d86, 0x6c202982, + 0x73202782, 0x28202782, 0x22081745, 0x82530022, 0x23638b1f, 0x00290022, 0x6420c989, 0x61223182, 0x33826c00, 0x8f0d4f45, 0x09794235, 0x7f826f20, + 0x2f827420, 0x7320af83, 0x72206782, 0x63207782, 0x59838788, 0x9b826920, 0x53826320, 0x64007522, 0x42080741, 0x3d8707b7, 0x19826c20, 0x8b05d143, + 0x007421c3, 0x4a053747, 0xcd8309f2, 0x22057341, 0x41730075, 0x63200683, 0x8306184b, 0x826d206b, 0x2265830b, 0x84790066, 0x826d20d5, 0x00722123, + 0x4407ad41, 0x73200917, 0x2f835982, 0x73202b83, 0x6220b586, 0x6520c984, 0x73203784, 0x200a4144, 0x87bf8265, 0x8261206b, 0x0064220b, 0x2065822f, + 0x83f38272, 0x05a24a15, 0x69208385, 0x41066f41, 0x652009d7, 0x4106404b, 0x77830b71, 0x20204785, 0x4206b744, 0xff850537, 0x42002021, 0xef890b45, + 0xb1827720, 0x6d006f22, 0x410ae544, 0x45421193, 0x82662005, 0x827220bb, 0x200d83a7, 0x20918268, 0x20338464, 0x2005826f, 0x22b78264, 0x82730020, + 0x85838305, 0x090947e3, 0x20055741, 0x06734174, 0x25826620, 0x6f22db83, 0xb5417700, 0x22e58308, 0x8264006e, 0x8274200f, 0x826f2003, 0x00732363, + 0xad46003a, 0x0061220b, 0x20378262, 0x21758276, 0x13410020, 0x0db04c05, 0x1d826e20, 0x63203b83, 0x830cdd42, 0x41bb8573, 0xab430909, 0x20358d0b, + 0x21a18273, 0x77410061, 0x84622005, 0x0b614247, 0x9f826520, 0xb1842020, 0x87002021, 0x0f9d4125, 0x2005bb41, 0x22ab8275, 0x82740073, 0x826e2025, + 0x84692005, 0x0020222d, 0x20a18270, 0x08bf4272, 0xc3497320, 0x0f754110, 0xff862e20, 0x45004822, 0x532c2b82, 0x46004f00, 0x57005400, 0x52004100, + 0x49221184, 0x17825300, 0x0d825020, 0x56004f26, 0x44004900, 0x44201582, 0x22201182, 0x19832182, 0x22221f83, 0x11822c00, 0x1d825720, 0x48005422, + 0x55204182, 0x20204182, 0x52204386, 0x4e202782, 0x59200f82, 0x5b832182, 0x0f842020, 0x4b200d83, 0x4e202f82, 0x3b834f82, 0x58004524, 0x71845000, + 0x6f845320, 0x0b824f20, 0x1f822020, 0x15824d20, 0x07824c20, 0x27864520, 0x4e004928, 0x4c004300, 0x0f825500, 0x47200b83, 0x42205582, 0x54200d82, + 0x4e200782, 0x07837982, 0xf5452f83, 0x20358305, 0x207b8220, 0x201d824f, 0x20998254, 0x83a58445, 0x209587d9, 0x83cd8249, 0x209985c5, 0x200d824d, + 0x205f8252, 0x20a38448, 0x20058254, 0x207b8242, 0x20d7844c, 0x20e38459, 0x200b8446, 0x8335844e, 0x82462037, 0x82522073, 0x82412055, 0x82502003, + 0x8252202f, 0x8249206d, 0x82552041, 0x844120a3, 0x825020c3, 0x0052229d, 0x20278250, 0x85358253, 0x864420fd, 0x004e22ad, 0x20cf8249, 0x85278246, + 0x004521cb, 0x4e248183, 0x2e005400, 0x13832182, 0x1f822020, 0x4522bd83, 0x3d825600, 0x20221983, 0xc9825300, 0x5f824120, 0xd58a4c20, 0x65824120, + 0x20057b41, 0x0a3f4152, 0x75824320, 0x59005022, 0x47205f84, 0x54203582, 0x48203182, 0x4c221382, 0xe9844400, 0x4220c183, 0x4c209584, 0x41228982, + 0x55824200, 0x23824520, 0x4e20d589, 0x20223d82, 0x17824300, 0x21824120, 0x2c004d22, 0x44201d82, 0x4d20e782, 0x47200382, 0x20083b41, 0x21158252, + 0x7f83004f, 0xf3844520, 0x49214d87, 0x0b3b4100, 0x81825720, 0x258a4520, 0x4122df85, 0x3d824e00, 0x63824120, 0x49005422, 0x0d839b82, 0x83058d41, + 0x824e20bd, 0x8252202f, 0x8243206b, 0x207b8307, 0x20218254, 0x200b8252, 0x83078420, 0x20758705, 0x203d8257, 0x83918253, 0x84412025, 0x825320f1, + 0x004e2211, 0x205d8247, 0x210f8246, 0xbd85004f, 0x42004f21, 0x6385059d, 0x83076742, 0x206f8575, 0x8343824e, 0x428b876d, 0x202007d5, 0x2021b986, + 0x11234300, 0x89854585, 0x5f822020, 0x8505e941, 0x0b174115, 0x5b824420, 0x4c004122, 0x3d439786, 0x21798305, 0x7d430054, 0x059b4315, 0x2f824220, + 0x75825420, 0xc5825420, 0x41004522, 0x2022c782, 0x49825600, 0x0b825220, 0x4d842020, 0x502dd748, 0x0c5153c2, 0x4d204f13, 0x49000a21, 0x6523a509, + 0x4e002000, 0x20240989, 0x63006100, 0x6f240182, 0x70006d00, 0x6e220b82, 0x8d467900, 0x09354608, 0x2e0d6b4d, 0x00280020, 0x00460022, 0x006e006f, + 0x82730074, 0x4a29200b, 0x49490adf, 0x20618749, 0x1e534920, 0x65007222, 0x2206754e, 0x82750064, 0x47e183cb, 0x7f4807ff, 0x49202013, 0x619908ad, + 0x20715749, 0x0af54a65, 0x49294749, 0xf59d332f, 0x99433949, 0x00202161, 0x41a14349, 0x72210901, 0x0f2a5300, 0x530b2949, 0x6e210552, 0x05ff4900, + 0xd9866820, 0x28656149, 0x00200066, 0x006e006f, 0x20078465, 0x20058272, 0x4c0f826d, 0x1d4b05d3, 0x1b8b410d, 0x79007424, 0x43827000, 0xe7826620, + 0x07826320, 0xbf4f7320, 0x4a542006, 0x3b9b06a3, 0x33826d20, 0x77827920, 0x83846220, 0x2009174c, 0x220f8269, 0x822c0064, 0x00612419, 0x8274006c, + 0x8872200d, 0x006f2111, 0x6122a983, 0x01826400, 0x2005474a, 0x062b4b74, 0xcb826120, 0x154d6420, 0x82702008, 0x8272205b, 0x0069223b, 0x08a75563, + 0x2009b543, 0x22a98464, 0x82670069, 0x093f4a33, 0x6d826720, 0x6821cd83, 0x83138500, 0x074d4e69, 0x47826120, 0x1b838985, 0x440d794d, 0x202109c7, + 0x51d39d00, 0xc18509a7, 0xc54a6920, 0x82612008, 0x8220207b, 0x006c218f, 0x678d81a5, 0x440f0f41, 0x7323119f, 0x41002c00, 0x618305ef, 0x69002024, + 0x0f826600, 0x450b494c, 0xa1830589, 0x83050342, 0x506e2005, 0x9f4c0695, 0x20118709, 0x423d8273, 0x202305c9, 0x45006300, 0x474f05c7, 0x8265200d, + 0x535f8563, 0x0d540b4d, 0x00642105, 0xe7503f83, 0x05e34117, 0x20213b85, 0x21318700, 0xf7500020, 0x0537480b, 0x974f5420, 0x0f755108, 0x65006222, + 0x53519784, 0x006e2207, 0x068f4c75, 0x20072742, 0x20b58276, 0x06794369, 0x240b9952, 0x00780065, 0x513d8274, 0x61220597, 0x01827000, 0x2105bd46, + 0x43560061, 0x82742007, 0x09bd513b, 0x42092d42, 0xcf831bed, 0x59826120, 0xb3822020, 0xff846120, 0x65826220, 0x6e006525, 0x42002000, 0x20200ffb, + 0x2008a354, 0x46298469, 0xaf541383, 0x13554117, 0x2009a748, 0x416d8222, 0x454109c3, 0x82652009, 0x42bd9b17, 0x73200d6f, 0x6c21ff82, 0x20818300, + 0x209f8461, 0x20af8270, 0x44db8472, 0x61200539, 0x6c204d82, 0x67201384, 0x7220e382, 0x37510d82, 0x22338311, 0x826b0063, 0x24238325, 0x00620020, + 0x53418475, 0x0f4e05cd, 0x09815105, 0x4353a944, 0xd5890fad, 0x20056b52, 0x208f8269, 0x22bf8273, 0x4466006c, 0xc54a08d5, 0x00462605, 0x004e004f, + 0xdc4d4e54, 0xe1824120, 0x4d4e5920, 0x002021a8, 0x4e09514d, 0x2c200d0f, 0x5026c382, 0x54004100, 0xd1824500, 0x83005421, 0x0054220f, 0x20118252, + 0x20118244, 0x2207824d, 0x844b0052, 0x11cd4c15, 0x49005223, 0x05554e00, 0x4c27ad4e, 0x3b4d13c9, 0x8247200d, 0x004f2285, 0x227b824d, 0x82460020, + 0x825520b5, 0x8444200f, 0x078f4d9f, 0x5069af4e, 0xf741136b, 0x82472007, 0x4d4e20a1, 0x4c280683, 0x20002c00, 0x50005300, 0x43220f82, 0xad824900, + 0x3f831185, 0x0f824420, 0x17845220, 0x85055b41, 0x00492253, 0x203f8444, 0x412b8854, 0x814e0505, 0x82532005, 0x0051221b, 0x85218655, 0x8220204f, + 0x00412231, 0x08754f4d, 0x4f4f7183, 0x15034f93, 0x4121f583, 0x0b4b5100, 0x54002025, 0x4f004f00, 0x3787092b, 0x411b3b44, 0xcb4f0523, 0x0bfb4f07, + 0x4f002021, 0x57991f59, 0x2a05e545, 0x00780045, 0x00650063, 0x82740070, 0x05b74595, 0x530db947, 0xb94d0b97, 0x0baf4a09, 0x33482c20, 0x0945460a, + 0x45002021, 0x472105f5, 0x202b8300, 0x06f3556d, 0x65204183, 0x15892f82, 0x560b9a60, 0x6b550943, 0x1359590b, 0x8307a559, 0x0b575427, 0x20219785, + 0x053d4a00, 0x5b007521, 0x692007c3, 0x20258582, 0x64006100, 0x05e95d00, 0x69007422, 0x69201b82, 0x67201582, 0x2008e94a, 0x06bf4d6f, 0x77007222, + 0x65201d84, 0x22087f55, 0x82720070, 0x826d20cd, 0x82742003, 0x094749c7, 0x51827320, 0xd9866c20, 0xf5836b85, 0x37827220, 0x20204b89, 0x65207382, + 0x6d852784, 0x550d294a, 0x6347053d, 0x0f71571b, 0x69208b83, 0x65838982, 0x97827720, 0xb5826920, 0x6e209583, 0x61207582, 0x220ad461, 0x827a0069, + 0x5ee78375, 0x662005d1, 0xbd89c386, 0x871f8341, 0x1f7f41cb, 0x65007226, 0x70007300, 0x63200582, 0x69228b82, 0x09827600, 0x79006c24, 0x91822e00, + 0xa983d983, 0x4905db56, 0x692409f9, 0x66006e00, 0x6d20c584, 0x2c20a58a, 0x7d423182, 0x204d8309, 0x1055503a, 0x11827420, 0x53426720, 0x00202408, + 0x826f0064, 0x20ab8575, 0x2e738267, 0x5400000a, 0x77206568, 0x206b726f, 0x5f206e69, 0xac610978, 0x70202b05, 0x656a6f72, 0x69207463, 0x51622073, + 0x19766209, 0x6e612032, 0x696c2064, 0x736e6563, 0x75206465, 0x7265646e, 0x4d245384, 0x4c205449, 0x0a211685, 0x23708f0a, 0x6b636148, 0xb6626898, + 0x2569b417, 0x616a6544, 0x6b887556, 0x7361772a, 0x6d6f6320, 0x7474696d, 0x7421ad82, 0x22aa846f, 0x82627570, 0x642029c0, 0x69616d6f, 0x0a0a2e6e, + 0x280e7161, 0x736e6153, 0x6e6f4d20, 0x0c0f416f, 0x61333021, 0x2f630978, 0x16084105, 0x13414d8e, 0x77202406, 0x63687469, 0x202c0857, 0x746e6f46, + 0x6d614e20, 0x22207365, 0x22203088, 0x2233f184, 0x61726556, 0x4d0a0a22, 0x4c205449, 0x4e454349, 0x630a4553, 0x146410c1, 0x0a300842, 0x6d726550, + 0x69737369, 0x69206e6f, 0x65682073, 0x79626572, 0x61726720, 0x6465746e, 0x7266202c, 0x6f206565, 0x68632066, 0x65677261, 0x6f74202c, 0x79259d82, + 0x72657020, 0x2f308273, 0x6174626f, 0x6e696e69, 0x20612067, 0x79706f63, 0x8205d261, 0x6f732746, 0x61777466, 0xca846572, 0x73736135, 0x6169636f, + 0x20646574, 0x75636f64, 0x746e656d, 0x82697461, 0x6966223e, 0x26f9826c, 0x65687428, 0x86532220, 0x29222131, 0x64236484, 0x426c6165, 0x1a8707a7, + 0x6977202f, 0x756f6874, 0x65722074, 0x69727473, 0x20438363, 0x2324822c, 0x64756c63, 0x1e878383, 0x6d696c23, 0x83618669, 0x6472205a, 0xb98205cc, + 0x82737521, 0x826320c1, 0x202c27a7, 0x69646f6d, 0x07827966, 0xd6846520, 0x6275702a, 0x6873696c, 0x6964202c, 0x62225a83, 0x29827475, 0x14837320, + 0x6e656322, 0x612a3583, 0x6f2f646e, 0x65732072, 0xe9836c6c, 0xb7826920, 0x20666f22, 0x9d875e83, 0xeb842c20, 0x70226582, 0x7f827265, 0x21062241, + 0x11822073, 0x6f687723, 0x272b8c6d, 0x20736920, 0x6e727566, 0x8f427282, 0x6f642605, 0x2c6f7320, 0x23718220, 0x7463656a, 0x5a833383, 0x6c6f6625, + 0x83776f6c, 0x6f632ada, 0x7469646e, 0x736e6f69, 0x0556433a, 0x6f626124, 0x89836576, 0x24062466, 0x69746f6e, 0x056e4163, 0x82687421, 0x4184845d, + 0x1a8605d5, 0x61687322, 0x6221bb82, 0x06304165, 0x69227782, 0x1283206e, 0x706f6322, 0xdd82ce84, 0x7362752d, 0x746e6174, 0x206c6169, 0x84726f70, + 0x05d2416f, 0x87206521, 0x822e20e6, 0x45483a7f, 0x464f5320, 0x52415754, 0x53492045, 0x4f525020, 0x45444956, 0x41222044, 0x2a0f8253, 0x57202c22, + 0x4f485449, 0x82205455, 0x52230821, 0x59544e41, 0x20464f20, 0x20594e41, 0x444e494b, 0x5845202c, 0x53455250, 0x524f2053, 0x504d4920, 0x8245494c, + 0x4e492a13, 0x44554c43, 0x20474e49, 0x28378242, 0x20544f4e, 0x494d494c, 0x23548254, 0x54204f54, 0x4a867082, 0x82454921, 0x20462637, 0x4352454d, + 0x2c598248, 0x4c494241, 0x2c595449, 0x54494620, 0x2053834e, 0x33548246, 0x41502041, 0x43495452, 0x52414c55, 0x52555020, 0x45534f50, 0x44287e82, + 0x4e4f4e20, 0x52464e49, 0x45286582, 0x544e454d, 0x4e49202e, 0x20221382, 0x0c825645, 0x48532025, 0x844c4c41, 0x5541216a, 0x5220bd82, 0x432e9f84, + 0x5259504f, 0x54484749, 0x4c4f4820, 0x14824544, 0x82454221, 0x42412499, 0x8420454c, 0x2bd4826a, 0x49414c43, 0x44202c4d, 0x47414d41, 0x52229d83, + 0xb0824f20, 0x26845220, 0x57229d86, 0x12844548, 0x41316f82, 0x4341204e, 0x4e4f4954, 0x20464f20, 0x544e4f43, 0x260e8252, 0x4f54202c, 0x82205452, + 0x293a84bb, 0x45534957, 0x5241202c, 0xaa825349, 0x52462023, 0x215e824f, 0x1f82554f, 0x22834620, 0x37824482, 0x85454e21, 0x49572345, 0xb5844854, + 0x82089141, 0x216c8245, 0xf4825520, 0x20245087, 0x4c414544, 0x53204b82, 0x1c83f183, 0x2e302c87, 0x49420a0a, 0x52545354, 0x204d4145, 0x41524556, + 0x68196b44, 0x2145292d, 0x25bb660a, 0x84440a20, 0x20653852, 0x746e6f66, 0x63612073, 0x706d6f63, 0x69796e61, 0x7420676e, 0x46736968, 0x202307b5, + 0x83462228, 0x29222121, 0x8329a444, 0x08094330, 0x2606a944, 0x72706572, 0x4375646f, 0x3f44067c, 0x206c8209, 0x05e04565, 0x44073a43, 0xa34438ab, + 0x1997441a, 0x9c44ab8c, 0x44308c23, 0xa98251a1, 0x440ac068, 0x73210594, 0x44158420, 0x662b36b0, 0x656e6f20, 0x20726f20, 0x82726f6d, 0x058e4507, + 0x7429c58d, 0x66657079, 0x73656361, 0x0536452e, 0x6d251d8d, 0x62207961, 0x050b4665, 0x64656929, 0x6c61202c, 0x83726574, 0x27548208, 0x65646461, + 0x6f742064, 0x2b053a41, 0x70206e69, 0x69747261, 0x616c7563, 0x2f05e948, 0x69736564, 0x20736e67, 0x6720666f, 0x6870796c, 0x72270982, 0x61686320, + 0x82636172, 0x46732044, 0x718307bc, 0x8e207321, 0x82f68469, 0x74692660, 0x616e6f69, 0x8640956c, 0x42878733, 0x7321084f, 0x23f7822c, 0x6920796c, + 0xe642f085, 0x65722706, 0x6e657220, 0xb3846d61, 0x08832020, 0x6e207328, 0x6320746f, 0xa3476e6f, 0x69652307, 0xa6496874, 0x6f772306, 0x73486472, + 0x82f1820d, 0x8320201d, 0x48202018, 0x2e26057b, 0x68540a0a, 0xce497369, 0x62202607, 0x6d6f6365, 0x22558265, 0x846c6c75, 0x6f7623c0, 0xaa466469, + 0x78653007, 0x746e6574, 0x70706120, 0x6163696c, 0x83656c62, 0x82fb8518, 0x0d764159, 0x61687427, 0x61682074, 0x21518273, 0x7d416e65, 0x82528408, + 0x0941436e, 0x490b574a, 0x2025091e, 0x61726556, 0x41e18522, 0x73241bd5, 0x20646c6f, 0x702d6482, 0x20747261, 0x6120666f, 0x72616c20, 0x48ff8267, + 0x702d089b, 0x616b6361, 0x62206567, 0x6e207475, 0x08c0486f, 0x41295442, 0x6a8407d6, 0x20796228, 0x65737469, 0x2147666c, 0x4f462306, 0x2647544e, + 0x4e41226d, 0x07714759, 0x464b2647, 0x074705a8, 0x202c3306, 0x45544150, 0x202c544e, 0x44415254, 0x52414d45, 0xb7462c4b, 0x52202408, 0x47484749, + 0x64461456, 0x069d4609, 0x4f4e4730, 0x4620454d, 0x444e554f, 0x4f495441, 0x5747204e, 0x09354834, 0x472dfb83, 0x52454e45, 0x202c4c41, 0x43455053, + 0x26088349, 0x49444e49, 0x82434552, 0x212982ad, 0xb7824449, 0x82821583, 0x4e4f4326, 0x55514553, 0x27821082, 0x2107ba47, 0xa747202c, 0x0a814749, + 0x484e4921, 0x202706a5, 0x55204f54, 0x83204553, 0x0d1d421b, 0x46239182, 0x484d4f52, 0xac470638, 0x2c2b8c0f, 0x450a0a2e, 0x70656378, 0x73612074, + 0x06dc4320, 0x2405cb49, 0x73696874, 0x05574520, 0x74202c24, 0x22436568, 0x6f202805, 0x6e472066, 0x85656d6f, 0x700a8413, 0x61200519, 0x22053f4b, + 0x47646e61, 0x49250ab0, 0x2c2e636e, 0x052b4a20, 0x20254b82, 0x75206562, 0x2f5f8573, 0x65766461, 0x73697472, 0x20676e69, 0x6f20726f, 0x722e6282, + 0x65736977, 0x206f7420, 0x6d6f7270, 0x0a82746f, 0x73227682, 0x6c826c61, 0x25883582, 0x65642024, 0x36826c61, 0x82061445, 0x0d1044a6, 0x2207b84b, + 0x82697270, 0x72772f58, 0x65747469, 0x7561206e, 0x726f6874, 0xa7847a69, 0x82662021, 0x8fd58461, 0x4d6583c1, 0x2020083b, 0x722cbf85, 0x65707365, + 0x76697463, 0x2e796c65, 0x7224ed82, 0x72756620, 0x2026af83, 0x6f666e69, 0x52846d72, 0x3e412c20, 0x74632205, 0x072a483a, 0x6720742a, 0x656d6f6e, + 0x746f6420, 0x67245582, 0x00000a2e, 0x300f886e, 0x0070006f, 0x006e0065, 0x006f0073, 0x00720075, 0x200d8263, 0x240b822e, 0x00670072, 0x06a26b2f, + 0x65201f85, 0x2f262382, 0x49004d00, 0x46825400, 0x2e06806e, 0x6e65706f, 0x72756f73, 0x6f2e6563, 0x4f2f6772, 0x73230640, 0x82494d2f, 0x00022124, + 0xff230084, 0x8223009b, 0x82012008, 0x21028c03, 0x15840d07, 0x00024008, 0x00040003, 0x00060005, 0x00080007, 0x000a0009, 0x000c000b, 0x000e000d, + 0x0010000f, 0x00120011, 0x00140013, 0x00160015, 0x00180017, 0x001a0019, 0x001c001b, 0x001e001d, 0x0020001f, 0x82220021, 0x0024345d, 0x00260025, + 0x00280027, 0x002a0029, 0x002c002b, 0x822e002d, 0x303008bf, 0x32003100, 0x34003300, 0x36003500, 0x38003700, 0x3a003900, 0x3c003b00, 0x3e003d00, + 0x40003f00, 0x42004100, 0x44004300, 0x46004500, 0x48004700, 0x4a24dd82, 0x4c004b00, 0x4e2ae782, 0x50004f00, 0x52005100, 0xf1825300, 0x55760d07, + 0x57005600, 0x59005800, 0x5b005a00, 0x5d005c00, 0x5f005e00, 0x61006000, 0xa300ac00, 0x85008400, 0x9600bd00, 0x8600e800, 0x8b008e00, 0xa9009d00, + 0x0201a400, 0xda008a00, 0x93008300, 0xf300f200, 0x97008d00, 0xc3008800, 0xf100de00, 0xaa009e00, 0xf400f500, 0xa200f600, 0xc900ad00, 0xae00c700, + 0x63006200, 0x64009000, 0x6500cb00, 0xca00c800, 0xcc00cf00, 0xce00cd00, 0x6600e900, 0xd000d300, 0xaf00d100, 0xf0006700, 0xd6009100, 0xd500d400, + 0xeb006800, 0x8900ed00, 0x69006a00, 0x6d006b00, 0x6e006c00, 0x6f00a000, 0x70007100, 0x73007200, 0x74007500, 0x77007600, 0x7800ea00, 0x79007a00, + 0x7d007b00, 0xb8007c00, 0x7f00a100, 0x80007e00, 0xec008100, 0xba00ee00, 0x04010301, 0x06010501, 0x08010701, 0xfe00fd00, 0x0a010901, 0x0c010b01, + 0x0001ff00, 0x0e010d01, 0x01010f01, 0x11011001, 0x13011201, 0x15011401, 0x17011601, 0x19011801, 0x1b011a01, 0xf900f800, 0x1d011c01, 0x1f011e01, + 0x21012001, 0x23012201, 0x25012401, 0x27012601, 0x29012801, 0x2b012a01, 0xd700fa00, 0x2d012c01, 0x2f012e01, 0x31013001, 0x33013201, 0x35013401, + 0x37013601, 0x39013801, 0xe2003a01, 0x3b01e300, 0x3d013c01, 0x3f013e01, 0x41014001, 0x43014201, 0x45014401, 0x47014601, 0x49014801, 0xb100b000, + 0x4b014a01, 0x4d014c01, 0x4f014e01, 0x51015001, 0x53015201, 0xfc00fb00, 0xe500e400, 0x55015401, 0x57015601, 0x59015801, 0x5b015a01, 0x5d015c01, + 0x5f015e01, 0x61016001, 0x63016201, 0x65016401, 0x67016601, 0x69016801, 0x6a01bb00, 0x6c016b01, 0xe6006d01, 0x6e01e700, 0x6f01a600, 0x71017001, + 0x73017201, 0x75017401, 0x77017601, 0x79017801, 0x7b017a01, 0xe100d800, 0xdc00db00, 0xe000dd00, 0xdf00d900, 0x7d017c01, 0x7f017e01, 0x81018001, + 0x83018201, 0x85018401, 0x87018601, 0x89018801, 0x8b018a01, 0x8d018c01, 0x8f018e01, 0x91019001, 0x93019201, 0x95019401, 0x97019601, 0x99019801, + 0x9b019a01, 0x9d019c01, 0x9f019e01, 0xa101a001, 0xa301a201, 0xa501a401, 0xa701a601, 0xa901a801, 0xab01aa01, 0xad01ac01, 0xaf01ae01, 0xb101b001, + 0xb301b201, 0xb501b401, 0xb701b601, 0x9b00b801, 0xba01b901, 0xbc01bb01, 0xbe01bd01, 0xc001bf01, 0xc201c101, 0xc401c301, 0xc601c501, 0xc801c701, + 0xca01c901, 0xcc01cb01, 0xce01cd01, 0xd001cf01, 0xd201d101, 0xd401d301, 0xd601d501, 0xd801d701, 0xda01d901, 0xdc01db01, 0xde01dd01, 0xe001df01, + 0xe201e101, 0xe401e301, 0xe601e501, 0xe801e701, 0xea01e901, 0xec01eb01, 0xee01ed01, 0xf001ef01, 0xf201f101, 0xf401f301, 0xf601f501, 0xf801f701, + 0xfa01f901, 0xfc01fb01, 0xfe01fd01, 0x0002ff01, 0x02020102, 0x04020302, 0x06020502, 0x08020702, 0x0a020902, 0x0c020b02, 0x0e020d02, 0x10020f02, + 0x12021102, 0x14021302, 0x16021502, 0x18021702, 0x1a021902, 0x1c021b02, 0x1e021d02, 0x20021f02, 0x22022102, 0x24022302, 0x26022502, 0x28022702, + 0x2a022902, 0x2c022b02, 0x2e022d02, 0x30022f02, 0x32023102, 0x34023302, 0x36023502, 0x38023702, 0x3a023902, 0x3c023b02, 0x3e023d02, 0x40023f02, + 0x42024102, 0x44024302, 0x46024502, 0x48024702, 0x4a024902, 0x4c024b02, 0x4e024d02, 0x50024f02, 0x52025102, 0x54025302, 0x56025502, 0x58025702, + 0x5a025902, 0x5c025b02, 0x5e025d02, 0x60025f02, 0x62026102, 0x64026302, 0x66026502, 0x68026702, 0x6a026902, 0x6c026b02, 0x6e026d02, 0x70026f02, + 0x72027102, 0x74027302, 0x76027502, 0x78027702, 0x7a027902, 0x7c027b02, 0x7e027d02, 0x80027f02, 0x82028102, 0x84028302, 0x86028502, 0x88028702, + 0x8a028902, 0x8c028b02, 0x8e028d02, 0x90028f02, 0x92029102, 0x94029302, 0x96029502, 0x98029702, 0x9a029902, 0x9c029b02, 0x9e029d02, 0xa0029f02, + 0xa202a102, 0xa402a302, 0xa602a502, 0xa802a702, 0xaa02a902, 0xac02ab02, 0xae02ad02, 0xb002af02, 0xb202b102, 0xb402b302, 0xb602b502, 0xb802b702, + 0xba02b902, 0xbc02bb02, 0xbe02bd02, 0xc002bf02, 0xc202c102, 0xc402c302, 0xc602c502, 0xc802c702, 0xca02c902, 0xcc02cb02, 0xce02cd02, 0xd002cf02, + 0xd202d102, 0xd402d302, 0xd602d502, 0xd802d702, 0xda02d902, 0xdc02db02, 0xde02dd02, 0xe002df02, 0xe202e102, 0xe402e302, 0xe602e502, 0xe802e702, + 0xea02e902, 0xec02eb02, 0xee02ed02, 0xf002ef02, 0xf202f102, 0xf402f302, 0xf602f502, 0xf802f702, 0xfa02f902, 0xfc02fb02, 0xfe02fd02, 0x0003ff02, + 0x02030103, 0x04030303, 0x06030503, 0x08030703, 0x0a030903, 0x0c030b03, 0x0e030d03, 0x10030f03, 0x12031103, 0x14031303, 0x16031503, 0x18031703, + 0x1a031903, 0x1c031b03, 0x1e031d03, 0x20031f03, 0xb300b200, 0x22032103, 0xb6002303, 0xc400b700, 0xb4002403, 0xc500b500, 0x82002503, 0x8700c200, + 0x27032603, 0xab002803, 0x2a032903, 0x2b03c600, 0x2d032c03, 0x2f032e03, 0x31033003, 0xbf00be00, 0x33033203, 0x35033403, 0x3603bc00, 0x38033703, + 0x3a033903, 0x3c033b03, 0x3e033d03, 0x40033f03, 0x42034103, 0x44034303, 0x46034503, 0x48034703, 0x4a034903, 0x4c034b03, 0x4e034d03, 0x50034f03, + 0x5103f700, 0x53035203, 0x55035403, 0x57035603, 0x59035803, 0x5b035a03, 0x5d035c03, 0x5f035e03, 0x61036003, 0x63036203, 0x65036403, 0x8c006603, + 0x67039f00, 0x69036803, 0x6b036a03, 0x6d036c03, 0x6f036e03, 0x71037003, 0x73037203, 0x75037403, 0x77037603, 0x79037803, 0x7b037a03, 0x7d037c03, + 0x7f037e03, 0x81038003, 0x83038203, 0x85038403, 0x87038603, 0x89038803, 0x8b038a03, 0x8d038c03, 0x8f038e03, 0x91039003, 0x93039203, 0x95039403, + 0x97039603, 0x99039803, 0x9b039a03, 0x9d039c03, 0x9f039e03, 0xa103a003, 0xa303a203, 0xa503a403, 0xa703a603, 0xa903a803, 0xab03aa03, 0xad03ac03, + 0xaf03ae03, 0xb103b003, 0xb303b203, 0xb503b403, 0xb703b603, 0xb903b803, 0xbb03ba03, 0xbd03bc03, 0xbf03be03, 0xc103c003, 0xc303c203, 0xc503c403, + 0xc703c603, 0xc903c803, 0xcb03ca03, 0xcd03cc03, 0xcf03ce03, 0xd103d003, 0xd303d203, 0xd503d403, 0xd703d603, 0xd903d803, 0xdb03da03, 0xdd03dc03, + 0xdf03de03, 0xe103e003, 0xe303e203, 0x9800e403, 0xe603e503, 0xa800e703, 0xe903e803, 0xeb03ea03, 0xed03ec03, 0xef03ee03, 0xf0039a00, 0xef009900, + 0xf203f103, 0xf403f303, 0xa500f503, 0xf703f603, 0x9200f803, 0xfa03f903, 0xfc03fb03, 0xfe03fd03, 0x9c00ff03, 0x01040004, 0x03040204, 0x05040404, + 0x07040604, 0x09040804, 0x0b040a04, 0x0d040c04, 0x0f040e04, 0x11041004, 0xa7001204, 0x14041304, 0x16041504, 0x18041704, 0x1a041904, 0x1c041b04, + 0x1e041d04, 0x20041f04, 0x22042104, 0x24042304, 0x26042504, 0x28042704, 0x8f002904, 0x2b042a04, 0x94002c04, 0x2d049500, 0x2f042e04, 0x31043004, + 0x33043204, 0x35043404, 0x37043604, 0x39043804, 0x3b043a04, 0x3d043c04, 0x3f043e04, 0x41044004, 0x43044204, 0x45044404, 0x47044604, 0x49044804, + 0x4b044a04, 0x4d044c04, 0x4f044e04, 0x51045004, 0x53045204, 0x55045404, 0x57045604, 0x59045804, 0x5b045a04, 0x5d045c04, 0x5f045e04, 0x61046004, + 0x63046204, 0x65046404, 0x67046604, 0x69046804, 0x6b046a04, 0x6d046c04, 0x6f046e04, 0x71047004, 0x73047204, 0x75047404, 0x77047604, 0x79047804, + 0x7b047a04, 0x7d047c04, 0x7f047e04, 0x81048004, 0x83048204, 0x85048404, 0x87048604, 0x89048804, 0x8b048a04, 0x8d048c04, 0x8f048e04, 0x91049004, + 0x93049204, 0x95049404, 0x97049604, 0x99049804, 0x9b049a04, 0x9d049c04, 0x9f049e04, 0xa104a004, 0xa304a204, 0xa504a404, 0xa704a604, 0xa904a804, + 0xab04aa04, 0xad04ac04, 0xaf04ae04, 0xb104b004, 0xb304b204, 0xb504b404, 0xb704b604, 0xb904b804, 0xbb04ba04, 0xbd04bc04, 0xbf04be04, 0xc104c004, + 0xc304c204, 0xc504c404, 0xc704c604, 0xc904c804, 0xcb04ca04, 0xcd04cc04, 0xcf04ce04, 0xd104d004, 0xd304d204, 0xd504d404, 0xd704d604, 0xd904d804, + 0xdb04da04, 0xdd04dc04, 0xdf04de04, 0xe104e004, 0xe304e204, 0xe504e404, 0xe704e604, 0xe904e804, 0xeb04ea04, 0xed04ec04, 0xef04ee04, 0xf104f004, + 0xf304f204, 0xf504f404, 0xf704f604, 0xf904f804, 0xfb04fa04, 0xfd04fc04, 0xff04fe04, 0x01050005, 0x03050205, 0x05050405, 0x07050605, 0x09050805, + 0x0b050a05, 0x0d050c05, 0x0f050e05, 0x11051005, 0x13051205, 0x15051405, 0x17051605, 0x19051805, 0x1b051a05, 0x1d051c05, 0x1f051e05, 0x21052005, + 0x23052205, 0x25052405, 0x27052605, 0x29052805, 0x2b052a05, 0x2d052c05, 0x2f052e05, 0x31053005, 0x33053205, 0x35053405, 0x37053605, 0x39053805, + 0x3b053a05, 0x3d053c05, 0x3f053e05, 0x41054005, 0x43054205, 0x45054405, 0x47054605, 0x49054805, 0x4b054a05, 0x4d054c05, 0x4f054e05, 0x51055005, + 0x53055205, 0x55055405, 0x57055605, 0x59055805, 0x5b055a05, 0x5d055c05, 0x5f055e05, 0x61056005, 0x63056205, 0x65056405, 0x67056605, 0x69056805, + 0x6b056a05, 0x6d056c05, 0x6e05b900, 0x70056f05, 0x72057105, 0x74057305, 0x76057505, 0x78057705, 0x7a057905, 0x7c057b05, 0x7e057d05, 0x80057f05, + 0x82058105, 0x84058305, 0x86058505, 0x88058705, 0x8a058905, 0x8c058b05, 0x8e058d05, 0x90058f05, 0x92059105, 0x94059305, 0x96059505, 0x98059705, + 0x9a059905, 0x9c059b05, 0x9e059d05, 0xa0059f05, 0xa205a105, 0xa405a305, 0xa605a505, 0xa805a705, 0xaa05a905, 0xac05ab05, 0xae05ad05, 0xb005af05, + 0xb205b105, 0xb405b305, 0xb605b505, 0xb805b705, 0xba05b905, 0xbc05bb05, 0xbe05bd05, 0xc005bf05, 0xc205c105, 0xc405c305, 0xc605c505, 0xc805c705, + 0xca05c905, 0xcc05cb05, 0xce05cd05, 0xd005cf05, 0xd205d105, 0xd405d305, 0xd605d505, 0xd805d705, 0xda05d905, 0xdc05db05, 0xde05dd05, 0xe005df05, + 0xe205e105, 0xe405e305, 0xe605e505, 0xe805e705, 0xea05e905, 0xec05eb05, 0xee05ed05, 0xf005ef05, 0xf205f105, 0xf405f305, 0xf605f505, 0xf805f705, + 0xfa05f905, 0xfc05fb05, 0xfe05fd05, 0x0006ff05, 0x02060106, 0x04060306, 0x06060506, 0x08060706, 0x0a060906, 0x0c060b06, 0x0e060d06, 0x10060f06, + 0x12061106, 0x14061306, 0x16061506, 0x18061706, 0x1a061906, 0x1c061b06, 0x1e061d06, 0x20061f06, 0x22062106, 0x24062306, 0x26062506, 0x28062706, + 0x2a062906, 0x2c062b06, 0x2e062d06, 0x30062f06, 0x32063106, 0x34063306, 0x36063506, 0x38063706, 0x3a063906, 0x3c063b06, 0x3e063d06, 0x40063f06, + 0x42064106, 0x44064306, 0x46064506, 0x48064706, 0x4a064906, 0x4c064b06, 0x4e064d06, 0x50064f06, 0x52065106, 0x54065306, 0x56065506, 0x58065706, + 0x5a065906, 0x5c065b06, 0x5e065d06, 0x60065f06, 0x62066106, 0x64066306, 0x66066506, 0x68066706, 0x6a066906, 0x6c066b06, 0x6e066d06, 0x70066f06, + 0x72067106, 0x74067306, 0x76067506, 0x78067706, 0x7a067906, 0x7c067b06, 0x7e067d06, 0x80067f06, 0x82068106, 0x84068306, 0x86068506, 0x88068706, + 0x8a068906, 0x8c068b06, 0x8e068d06, 0x90068f06, 0x92069106, 0x94069306, 0x96069506, 0x98069706, 0x9a069906, 0x9c069b06, 0x9e069d06, 0xa0069f06, + 0xa206a106, 0xa406a306, 0xa606a506, 0xa806a706, 0xaa06a906, 0xac06ab06, 0xae06ad06, 0xb006af06, 0xb206b106, 0xb406b306, 0xb606b506, 0xb806b706, + 0xba06b906, 0xbc06bb06, 0xbe06bd06, 0xc006bf06, 0xc206c106, 0xc406c306, 0xc606c506, 0xc806c706, 0xca06c906, 0xcc06cb06, 0xce06cd06, 0xd006cf06, + 0xd206d106, 0xd406d306, 0xd606d506, 0xd806d706, 0xda06d906, 0xdc06db06, 0xde06dd06, 0xe006df06, 0xe206e106, 0xe406e306, 0xe606e506, 0xe806e706, + 0xea06e906, 0xec06eb06, 0xee06ed06, 0xf006ef06, 0xf206f106, 0xf406f306, 0xf606f506, 0xf806f706, 0xfa06f906, 0xfc06fb06, 0xfe06fd06, 0x0007ff06, + 0x02070107, 0x04070307, 0x06070507, 0x08070707, 0x0a070907, 0x0c070b07, 0x0e070d07, 0x75070f07, 0x3030696e, 0x07846461, 0x30303122, 0x31200786, + 0x32200786, 0x33200786, 0x34200786, 0x35200786, 0x38200786, 0x39200786, 0x61200786, 0x62200786, 0x65200786, 0x66200786, 0x31210785, 0x86078630, + 0x86312057, 0x86312057, 0x86312057, 0x36312157, 0x37202786, 0x67860786, 0x67863120, 0x67863120, 0x67863120, 0x86633121, 0x21c78627, 0x0f853032, + 0x86313221, 0x206f8607, 0x206f8632, 0x206f8632, 0x206f8632, 0x206f8632, 0x206f8632, 0x206f8632, 0x206f8632, 0x206f8632, 0x206f8632, 0x206f8632, + 0x866f8732, 0x863220e7, 0x863320e7, 0x8633206f, 0x8633206f, 0x8633206f, 0x8633206f, 0x8633206f, 0x8633206f, 0x8633206f, 0x8633206f, 0x8633206f, + 0x8633206f, 0x8633206f, 0x8633206f, 0x8633206f, 0x3034216f, 0x3420e785, 0x34206f86, 0x34206f86, 0x34206f86, 0x34206f86, 0x34206f86, 0x34206f86, + 0x34206f86, 0x34206f86, 0x34206f86, 0x34206f86, 0x34206f86, 0x34206f86, 0x35206f86, 0x35216f86, 0x20778531, 0x206f8635, 0x206f8635, 0x206f8635, + 0x206f8635, 0x206f8635, 0x206f8635, 0x206f8635, 0x206f8635, 0x206f8635, 0x206f8635, 0x063f4136, 0xcf863620, 0x5f863620, 0x5f863620, 0x5f863620, + 0x5f863620, 0x5f863620, 0x5f863620, 0x5f863620, 0x5f863620, 0x5f863620, 0x5f873620, 0x3620cf86, 0x3721cf86, 0x21c78530, 0x07863137, 0x37207f86, + 0x37207f86, 0x37207f86, 0x37207f86, 0x37207f86, 0x37207f86, 0x37207786, 0x37207786, 0x37207786, 0x37207786, 0x61206786, 0x61216786, 0x20678531, + 0x20578661, 0x201f8661, 0x201f8662, 0x205f8665, 0x205f8665, 0x20af8666, 0x21278566, 0xef853132, 0x0f433220, 0x43322006, 0x3220060f, 0x20060f43, + 0x06c74333, 0x85303321, 0x30332167, 0x3321c785, 0x20a78530, 0x06074333, 0x85383321, 0x3833217f, 0x3321d785, 0x21778538, 0x5f853833, 0x86383321, + 0x8538202f, 0x383321d7, 0x3321cf85, 0x218f8538, 0x8f853833, 0x85393321, 0x393322b7, 0x21d78431, 0x3f413933, 0x39332105, 0x39207786, 0x39206786, + 0x39206786, 0x39206786, 0x3321df85, 0x206f8639, 0x206f8639, 0x206f8639, 0x05474139, 0x86393321, 0x41392077, 0x332105bf, 0x207f8639, 0x417f8639, + 0x33200657, 0x21065741, 0x77866133, 0x21065f41, 0x77866133, 0x77866120, 0x77866120, 0x77866120, 0x77866120, 0x77866120, 0x77866120, 0x77866120, + 0x21061f45, 0x77866133, 0x2006af41, 0x06af4133, 0x31623322, 0x6220f785, 0x6220f786, 0x62207f86, 0x6220f786, 0x62207f86, 0x62207f86, 0x62207f86, + 0x62207f86, 0x62207f86, 0x62207f86, 0x62207f86, 0x62207f86, 0x6220f786, 0x62207f86, 0x6321f786, 0x20778531, 0x20778663, 0x20778663, 0x20778663, + 0x20778663, 0x20778663, 0x20778663, 0x20778663, 0x20778663, 0x20778663, 0x20778663, 0x20778663, 0x20778663, 0x20778663, 0x20578666, 0x204f8566, + 0x06674234, 0x67423420, 0x30342106, 0x34208785, 0x21066f42, 0x2f853034, 0x85303421, 0x30342187, 0x87853787, 0x85303421, 0x42342087, 0x34210697, + 0x21878530, 0x87853034, 0x85303421, 0x30342187, 0x34218785, 0x21878530, 0xff853034, 0x4f463420, 0x31342906, 0x6e750731, 0x31343069, 0x31207f86, + 0x21050741, 0x7f863134, 0x7f863120, 0x7f863120, 0x7f863120, 0x20064743, 0x06474334, 0x47433420, 0x43342006, 0x34210647, 0x207f8631, 0x207f8631, + 0x217f8631, 0x6f856631, 0x20066746, 0x06674634, 0x86323421, 0x065f437f, 0x67463420, 0x46342006, 0x34210667, 0x467f8632, 0x34200667, 0x20066746, + 0x06674634, 0x67463420, 0x46342006, 0x34200667, 0x20066746, 0x06674634, 0x86323421, 0x0667467f, 0x30333422, 0x33208785, 0x7746ff86, 0x46342006, + 0x34200677, 0x20067746, 0x06774634, 0x77463420, 0x46342006, 0x34200677, 0x20067746, 0x06774634, 0x77463420, 0x33342106, 0x46067f41, 0x34200677, + 0x20067746, 0x06774634, 0x77463420, 0x46342006, 0x34210677, 0x207f8634, 0x46ff8634, 0x34200687, 0x20068746, 0x06874634, 0x87463420, 0x34342106, + 0x46067f41, 0x34200687, 0x20068746, 0x06874634, 0x87463420, 0x46342006, 0x34200687, 0x20068746, 0x06874634, 0x87463420, 0x46342006, 0x34200687, + 0x21068746, 0x7f863534, 0xff413520, 0x06974606, 0x97463420, 0x46342006, 0x34200697, 0x20069746, 0x06974634, 0x97463420, 0x46342006, 0x34200697, + 0x20069746, 0x06974634, 0x97463420, 0x35342106, 0x20067f41, 0x06ff4135, 0x2006a746, 0x06a74634, 0x86373421, 0x0637467f, 0x17453420, 0x45342006, + 0x34200617, 0x20061745, 0x06174534, 0x17453420, 0x45342006, 0x34200617, 0x20061745, 0x06174534, 0x17453420, 0x45342006, 0x34200617, 0x20061745, + 0x06174534, 0x86613421, 0x06ef446f, 0xef443420, 0x44342006, 0x342106ef, 0x064f4361, 0x2006cf44, 0x06cf4434, 0xcf443420, 0x44342006, 0x342006cf, + 0x2006cf44, 0x06cf4434, 0xcf443420, 0x44342006, 0x342006cf, 0x2006cf44, 0x069f4434, 0x9f443420, 0x63342106, 0x44067f42, 0x34200687, 0x20068744, + 0x06874434, 0x87443420, 0x44342006, 0x34200677, 0x20067744, 0x06674434, 0x67443420, 0x63342106, 0x20064f41, 0x204f8664, 0x064f4264, 0xdf866420, + 0xcf416420, 0x43642006, 0x642006cf, 0x2006cf43, 0x064f4364, 0x4f426420, 0x44642006, 0x6420064f, 0x2105d744, 0xff866434, 0xcf426420, 0x43642006, + 0x642006cf, 0x2006cf43, 0x06cf4164, 0x7f866420, 0x43306521, 0x6521054f, 0x86078631, 0x8665207f, 0x8665207f, 0x8665207f, 0x06a7477f, 0xa7473420, + 0x65342106, 0x65207f86, 0x65207f86, 0x65207f86, 0x65207f86, 0x65207f86, 0x65207f86, 0x65207f86, 0x66217f86, 0x21778530, 0x07863166, 0x66207f86, + 0x7f457f86, 0x66342106, 0x87457f86, 0x86662007, 0x866620ff, 0x8566207f, 0x4b35207f, 0x3522066f, 0x4f843131, 0x85313521, 0x3135218f, 0x35208f85, + 0x2006df44, 0x06df4435, 0x47443520, 0x44352006, 0x35200647, 0x20064744, 0x06474435, 0x47443520, 0x44352006, 0x35200647, 0x20064744, 0x06474435, + 0x47443520, 0x33352106, 0x47446786, 0x44352006, 0x35200647, 0x20064744, 0x06474435, 0x47443520, 0x44352006, 0x35200647, 0x20064744, 0x06474435, + 0x47443520, 0x44352006, 0x35200647, 0x20064744, 0x06474435, 0x47443520, 0x44352006, 0x35200647, 0x20064744, 0x06474435, 0x47443520, 0x44352006, + 0x35200647, 0x20064744, 0x06474435, 0x47443520, 0x44352006, 0x35200647, 0x20064744, 0x06474435, 0x47443520, 0x44352006, 0x35200647, 0x20064744, + 0x06474435, 0x37443520, 0x44352006, 0x35200637, 0x20063744, 0x06374435, 0x37443520, 0x44352006, 0x35200637, 0x21063744, 0x8f413635, 0x063f4406, + 0x3f443520, 0x36352106, 0x20055f42, 0x06e74a35, 0xe74a3520, 0x4a352006, 0x352006e7, 0x2006e74a, 0x06e74a35, 0x41363521, 0xe74a0667, 0x4a352006, + 0x352006e7, 0x2106e74a, 0x5f423635, 0x4a352005, 0x352006e7, 0x2006e74a, 0x06e74a35, 0xaf443520, 0x44352006, 0x352006af, 0x2006e74a, 0x06e74a35, + 0xe74a3520, 0x4a352006, 0x352106e7, 0x055f4237, 0xef4a3520, 0x4a352006, 0x352006ef, 0x2006ef4a, 0x06ef4a35, 0x42373521, 0x352105df, 0x4a7f8637, + 0x352206ff, 0x87423038, 0x86382005, 0x423820ff, 0x352105df, 0x05df4238, 0x8f4a3520, 0x4a352006, 0x3520068f, 0x21068f4a, 0xdf423835, 0x4a352005, + 0x3520068f, 0x20068f4a, 0x053f4265, 0x44303121, 0x07820537, 0x07825784, 0x07825784, 0x07825784, 0x77833420, 0x35200782, 0x36200786, 0x57840786, + 0xd7841782, 0x39200782, 0x61201786, 0x62200786, 0x63200786, 0xd7840786, 0xd7842782, 0x66200782, 0x37441785, 0x30312105, 0x82053744, 0x447f8607, + 0x0f820537, 0x37447f86, 0x860f8205, 0x0537447f, 0x7f860f82, 0x82053744, 0x447f860f, 0x0f820537, 0x37447f86, 0x860f8205, 0x0537447f, 0x44303121, + 0x07820537, 0x8f853120, 0x7f866620, 0x82053744, 0x447f8617, 0x0f820537, 0x37447f86, 0x860f8205, 0x0537447f, 0x7f860f82, 0xff866620, 0x7f856620, + 0xbf416520, 0x65312105, 0x8205bf41, 0x20678507, 0x05bf4165, 0x67850f82, 0xbf416520, 0x65312105, 0x8205bf4a, 0x05374107, 0x97866520, 0x97866520, + 0xaf446520, 0x65312105, 0x32237785, 0x83303030, 0x303222bf, 0x82c78430, 0x825f8407, 0x86332007, 0x825f8417, 0x8635200f, 0x82c7840f, 0x8637200f, + 0x82c7840f, 0x8639200f, 0x21c7840f, 0x07453032, 0x20078205, 0x20178531, 0x20578631, 0x20478631, 0x20478631, 0x45478631, 0x2f82051f, 0x2f856620, + 0x2105cf49, 0xcf493032, 0x86078205, 0x05c74937, 0x27860f82, 0x21053f45, 0x3f453032, 0x86078205, 0x053f45b7, 0x37860f82, 0x82053f45, 0x456f860f, + 0x0f82051f, 0x6f856420, 0x82051f45, 0x4457860f, 0x322105f7, 0x05f74430, 0x37860782, 0x8205f744, 0x44ef860f, 0x322105ef, 0x05674430, 0x43303221, + 0x078205ef, 0x43063741, 0x0f8205d7, 0xd743ef86, 0x410f8205, 0xd7430637, 0x410f8205, 0xd7430637, 0x200f8205, 0x43978563, 0x0f8205d7, 0x0f856520, + 0x23058743, 0x62383032, 0x27860f86, 0xc7863820, 0x2105274e, 0x9f4d3032, 0x20078205, 0x48278531, 0x0f8205b7, 0xaf489786, 0x860f8205, 0x059f4d97, + 0x97860f82, 0x82059f4d, 0x4897860f, 0x0f8205cf, 0xcf486f86, 0x860f8205, 0x05cf4897, 0x48303221, 0x078205cf, 0xcf487786, 0x410f8205, 0x9f4d0697, + 0x410f8205, 0x974d0697, 0x860f8205, 0x05974d77, 0x42313221, 0x3120061f, 0x21052746, 0x27463132, 0x85078205, 0x46312047, 0x0f82051f, 0x31204785, + 0x82051f46, 0x05a7410f, 0x674a3120, 0x410f8205, 0x312005a7, 0x82052f46, 0x0537410f, 0x2f463120, 0x410f8205, 0x31200537, 0x82052f46, 0x05ff410f, + 0x474a3120, 0x31322105, 0x8205474a, 0x05bf4207, 0x474a3120, 0x410f8205, 0x31200547, 0x8205474a, 0x0547410f, 0x474a3120, 0x850f8205, 0x4a3120cf, + 0x0f820547, 0x20054741, 0x05474a31, 0x47410f82, 0x4f312005, 0x0f82055f, 0x20054741, 0x055f4f31, 0x41313221, 0x312006bf, 0x82055f4f, 0x4a7f860f, + 0x0f820577, 0xc7417f86, 0x4f312006, 0x17820567, 0x674fff86, 0x860f8205, 0x05974aff, 0xff860f82, 0x8205974a, 0x4aff860f, 0x0f820597, 0xc741ff86, + 0x4a312006, 0x32210597, 0x06c74131, 0x974a3120, 0x860f8205, 0x05674f7f, 0xff860f82, 0x2006cf41, 0x05674f31, 0x7f861782, 0x8205c74a, 0x447f860f, + 0x0f8205a7, 0x674f7f86, 0x860f8205, 0x05e74a7f, 0x63313227, 0x6e750731, 0x86078269, 0x05e74aff, 0x7f860f82, 0x82056f4f, 0x4a7f860f, 0x0f8205f7, + 0x20067f41, 0x4f7f8663, 0x1782056f, 0x074b7f86, 0x860f8205, 0x056f4f7f, 0x7f860f82, 0x2105df46, 0x174b3132, 0x86078205, 0x05174b7f, 0x7f860f82, + 0x8205174b, 0x4b7f860f, 0x0f820517, 0x174b7f86, 0x410f8205, 0x174b06ff, 0x410f8205, 0x174b06ff, 0x31322105, 0x8205cf46, 0x20ef8607, 0x466f8665, + 0x178205cf, 0xcf466f86, 0x860f8205, 0x05cf466f, 0x6f860f82, 0x8205cf46, 0x4ae7860f, 0x0f8205ff, 0xff4ae786, 0x860f8205, 0x05c746e7, 0x4a313221, + 0x078205ff, 0x2f467786, 0x860f8205, 0x05c74677, 0x77860f82, 0x8205c746, 0x4677860f, 0x3121064f, 0x46e78666, 0x1f8205c7, 0x6620e786, 0x57537f86, + 0x85178205, 0x4632207f, 0x3220067f, 0x21067f46, 0xdf433032, 0x30322105, 0x32217785, 0x05df4330, 0x42303221, 0x322005d7, 0x2205bf50, 0x41303232, + 0x322105d7, 0x216f8530, 0xef853032, 0xbf503220, 0x851f8205, 0x3032216f, 0x20055743, 0x068f4632, 0x86313221, 0x0687465f, 0x7f463220, 0x06df5306, + 0xdf533220, 0x86078206, 0x05af4b4f, 0x4f860f82, 0xb7863120, 0x21058750, 0xa7463232, 0x32322106, 0x5f509f86, 0x86178205, 0x055f509f, 0x07410f82, + 0x50322005, 0x36820557, 0xdf4bdf86, 0x410f8205, 0x32200557, 0x8205df4b, 0x0557410f, 0xdf4b3220, 0x860f8205, 0x05df4be7, 0x4f860f82, 0x2105df4b, + 0xc74b3232, 0x41078205, 0x322005bf, 0x8205c74b, 0x4667860f, 0x322006cf, 0x2006cf46, 0x05c74b32, 0xa7861f82, 0x8205bf4b, 0x4bf7860f, 0x0f8205bf, + 0xbf4bf786, 0x860f8205, 0x069745ff, 0x97453220, 0x4b322006, 0x322105bf, 0x05bf4b32, 0x77860782, 0x8205bf4b, 0x50df860f, 0x0f820507, 0xcf4bdf86, + 0x860f8205, 0x05cf4bdf, 0xdf860f82, 0x7f863520, 0x20069f45, 0x06674732, 0xcf4b3220, 0x32322105, 0x8205cf4b, 0x06d74107, 0x8205bf4b, 0x068f410f, + 0x8205bf4b, 0x4be7860f, 0x0f8205a7, 0x4b061742, 0x322105a7, 0x06b74732, 0xa74b3220, 0x410f8205, 0xa74b0647, 0x860f8205, 0x06cf47cf, 0xa74b3220, + 0x86178205, 0x05a74b67, 0x67860f82, 0x8205a74b, 0x064f410f, 0x8205a74b, 0x4bcf860f, 0x0f8205a7, 0x49064f41, 0x322105e7, 0x05e74932, 0x7f860782, + 0x8205e749, 0x497f860f, 0x0f8205e7, 0x4b064f41, 0x0f8205a7, 0x4b064f41, 0x0f8205af, 0x20064f41, 0x487f8638, 0x3220061f, 0x20061f48, 0x05475632, + 0x46323221, 0x322006e7, 0x2006e746, 0x052f5132, 0x4f411782, 0x052f5106, 0x87430f82, 0x052f5106, 0xf7860f82, 0x82052f51, 0x51f7860f, 0x0f82052f, + 0x47567786, 0x860f8205, 0x054756f7, 0xf7860f82, 0x2006e746, 0x06e74632, 0xa7483220, 0x46322006, 0x322006e7, 0x21055f51, 0x7f463232, 0x46322006, + 0x3220067f, 0x20064748, 0x067f4632, 0x6f463220, 0x51322006, 0x3221050f, 0x06274632, 0x0f513220, 0x860f8205, 0x059755bf, 0x8f860f82, 0x2106f745, + 0x8f866332, 0x2006f745, 0x06f74532, 0xcf503220, 0x32322105, 0x2006b745, 0x05cf5032, 0x3f860f82, 0x8205cf50, 0x453f860f, 0x322006c7, 0x2105974c, + 0xc7453232, 0x45322006, 0x322006c7, 0x8205cf50, 0x508f8617, 0x0f8205cf, 0x50064f41, 0x0f8205cf, 0x4c064f41, 0x3221056f, 0x060f4533, 0xff443320, + 0x06575806, 0xe7411782, 0x44332005, 0x332006ff, 0x2006e744, 0x069f4433, 0x27553320, 0x33322105, 0x57067748, 0x0f8206d7, 0xd757bf85, 0x850f8206, + 0x413320bf, 0x3320068f, 0x20068f41, 0x068f4133, 0x2106df57, 0x8f413332, 0x06df5706, 0x87420f82, 0x4a332005, 0x3320063f, 0x20067748, 0x063f4a33, + 0x77483320, 0x4a332006, 0x3320063f, 0x20067748, 0x063f4a33, 0x2706df57, 0x30303532, 0x696e7507, 0x31200782, 0xff420786, 0x30352105, 0x20058742, + 0x20ff8635, 0x060f4635, 0x85303521, 0x30352177, 0x20053741, 0x06174135, 0x17463520, 0x46352006, 0x35200617, 0x20061741, 0x06174635, 0x85303521, + 0x463520f7, 0x35210617, 0x51f78530, 0x322006b7, 0x8206b751, 0x467f8607, 0x3521062f, 0x057f4331, 0x37463520, 0x4a352006, 0x3521069f, 0x207f8631, + 0x057f4331, 0x41313521, 0xf75105b7, 0x43478206, 0xf7510507, 0x860f8206, 0x4431207f, 0x3520057f, 0x20064f46, 0x06af4135, 0xaf413520, 0x56352006, + 0x322105d7, 0x065f4635, 0x074d3520, 0x56352006, 0x178205d7, 0x7746ff86, 0x46352006, 0x35200677, 0x8205d756, 0x0517421f, 0xd7563520, 0x450f8205, + 0x3520054f, 0x21067f46, 0x7f863235, 0xff863220, 0x41303321, 0x4f4d0577, 0x068f5206, 0x8f523220, 0x86078206, 0x06af46ff, 0x82068f52, 0x52ff8617, + 0x0f82058f, 0x8f52ff86, 0x860f8205, 0x066f4dff, 0xaf463520, 0x068f5206, 0x7f861f82, 0x20058f52, 0x068f5232, 0x7f410782, 0x06c74606, 0x82068f52, + 0x05374317, 0x82068f52, 0x527f860f, 0x0f82058f, 0xcf467f86, 0x068f5206, 0xff861782, 0x82058f52, 0x52ff860f, 0x3221058f, 0x06cf4635, 0x82068f52, + 0x467f860f, 0x8f5206cf, 0x86178206, 0x066f4c7f, 0xcf463520, 0x4c352006, 0x3520066f, 0x2006cf46, 0x066f4c35, 0xcf463520, 0x4c352006, 0x3520066f, + 0x5206cf46, 0x4f82069f, 0x3620ff86, 0x46067f41, 0x352006d7, 0x5206d746, 0x322006a7, 0x8206a752, 0x467f8607, 0xa75206e7, 0x42178206, 0xa752067f, + 0x410f8205, 0xa75206ff, 0x860f8205, 0x06ff46ff, 0x8206a752, 0x467f8617, 0xa75206ff, 0x52322006, 0x078206a7, 0x52067f43, 0x0f8205a7, 0xff467f86, + 0x06a75206, 0x7f861782, 0x5206cf4e, 0x178206a7, 0x4606ff41, 0xa75206ff, 0x41178206, 0xa752067f, 0x52322005, 0x078206a7, 0x87423120, 0x05a75205, + 0x7f860f82, 0x8205a752, 0x527f860f, 0x0f8205a7, 0x5d06ff41, 0x0f82053f, 0x4f06ff41, 0x35200627, 0x2106ff46, 0xff863835, 0x20060747, 0x06074735, + 0x07473520, 0x47352006, 0x35200607, 0x20060747, 0x06074735, 0xef4d3520, 0x47352006, 0x35200607, 0x2006ef4d, 0x06074735, 0xef4d3520, 0x47352006, + 0x35200607, 0x2006ef4d, 0x06074735, 0x77453520, 0x47352006, 0x35200607, 0x2006ef4d, 0x06074735, 0xef4d3520, 0x45352006, 0x35200677, 0x20067745, + 0x06774535, 0x07473520, 0x45352006, 0x35200677, 0x2006ef4d, 0x06ef4d35, 0x77453520, 0x45352006, 0x35200677, 0x20067745, 0x06774535, 0x77453520, + 0x45352006, 0x35200677, 0x20067745, 0x06ef4d35, 0xb74f3520, 0x4d352006, 0x352006ef, 0x2006ef4d, 0x066f4735, 0x6f473520, 0x47352006, 0x3520066f, + 0x20066f47, 0x05575d35, 0x4d353221, 0x352006ef, 0x20067f47, 0x06bf4f35, 0xef4d3520, 0x58352006, 0x278205b7, 0x5d067f41, 0x0f820557, 0x5d06ff41, + 0x32210557, 0x06ef4d35, 0x31633522, 0x4705ff41, 0x352006c7, 0x2006c747, 0x06c74735, 0x41633521, 0xc74706ff, 0x4d352006, 0x352006ef, 0x8205e758, + 0x06ff4147, 0x8205ef58, 0x5d77860f, 0x0f820557, 0xef477786, 0x47352006, 0x352006ef, 0x2106ef47, 0xf7436435, 0x06e74d06, 0xff583520, 0x35322105, + 0x2106e74d, 0x77456435, 0x06e74d06, 0xff583520, 0x861f8205, 0x062f4877, 0x2f483520, 0x48352006, 0x3520062f, 0x2006e74d, 0x062f4835, 0xff583520, + 0x35322105, 0x20062f48, 0x062f4835, 0x2f483520, 0x48352006, 0x3520062f, 0x20062f48, 0x06f74d35, 0x2f483520, 0x4d352006, 0x352006f7, 0x20062f48, + 0x06f74d35, 0xff583520, 0x43578205, 0xff4d0677, 0x54352006, 0x178205c7, 0x5748ff86, 0x4d352006, 0x352006ff, 0x2006ff4d, 0x052f5435, 0x4d353221, + 0x352006ff, 0x8205ff58, 0x0677410f, 0x8205ff58, 0x0677430f, 0x82054f54, 0x4dff860f, 0x352006ff, 0x2006ff4d, 0x05c75435, 0x64201f82, 0x4d05d741, + 0x352006ff, 0x21055761, 0x4f573632, 0x37322105, 0x20064f45, 0x06af4b37, 0xc7443720, 0x87372006, 0x06c7441f, 0x6f573720, 0x37322105, 0x2106c744, + 0xcf853637, 0xc74b3720, 0x44372006, 0x372006c7, 0x2006c74b, 0x056f5737, 0x4b373221, 0x372006c7, 0x2006c744, 0x06c74b37, 0xd7433720, 0x43372006, + 0x372006bf, 0x2006bf43, 0x06bf4337, 0xbf433720, 0x43372006, 0x372006bf, 0x2006bf43, 0x06bf4337, 0xbf433720, 0x43372006, 0x372006bf, 0x2006bf43, + 0x06bf4337, 0xbf433720, 0x43372006, 0x372006bf, 0x2006bf43, 0x06bf4337, 0xbf433720, 0x43372006, 0x372006bf, 0x2006bf43, 0x06bf4337, 0xbf433720, + 0x43372006, 0x372006bf, 0x2006bf43, 0x06bf4337, 0xbf433720, 0x43372006, 0x372006b7, 0x2006b743, 0x06b74337, 0xb7433720, 0x43372006, 0x372006b7, + 0x2006b743, 0x06b74337, 0xb7433720, 0x43372006, 0x372006b7, 0x2006b743, 0x06b74337, 0xa7513720, 0x43372006, 0x372006b7, 0x2006a751, 0x069f4337, + 0x8f433720, 0x43372006, 0x3720068f, 0x2006ef42, 0x06d74237, 0xaf423720, 0x42372006, 0x372006af, 0x2006af42, 0x06af4237, 0xaf423720, 0x57372006, + 0x32210577, 0x06675037, 0x67423720, 0x50372006, 0x38200667, 0x21061f4a, 0x1f443038, 0x30382105, 0x2005a743, 0x061f4a38, 0x48303821, 0x3820059f, + 0x20061f4a, 0x061f4a38, 0x1f4a3820, 0x30382106, 0x20059f46, 0x061f4a38, 0x1f4a3820, 0x30382106, 0x20052743, 0x061f4a38, 0x42303821, 0x382105a7, + 0x05574230, 0x47303821, 0x3829051f, 0x75073031, 0x3832696e, 0x567f8631, 0x382006cf, 0x20061f4a, 0x061f4a38, 0x43313821, 0x38200527, 0x20061f4a, + 0x061f4a38, 0x86313821, 0x061f4a7f, 0x47313821, 0x3821059f, 0x207f8631, 0x05a74431, 0x86313821, 0x061f4a7f, 0x86313821, 0x061f4a7f, 0x1f4a3820, + 0x4a382006, 0x3820061f, 0x20061f4a, 0x061f4a38, 0x1f4a3820, 0x60382006, 0x322105f7, 0x061f4a38, 0x86323821, 0x061f4a7f, 0x97503820, 0x4a382006, + 0x3820061f, 0x8205f760, 0x4a7f862f, 0x3820061f, 0x20061f4a, 0x061f4a38, 0x1f4a3820, 0x57382006, 0x3820066f, 0x2105af5c, 0x6f573832, 0x4a382006, + 0x3820061f, 0x20066f57, 0x06cf5038, 0x1f4a3820, 0x33382106, 0x20052744, 0x061f4a38, 0xcf503820, 0x4a382006, 0x3820061f, 0x20061f4a, 0x068f5738, + 0x86333821, 0x061f4aff, 0xe7503820, 0x5c382006, 0x322105af, 0x061f4a38, 0xaf5c3820, 0x410f8205, 0xe750067f, 0x50382006, 0x382006e7, 0x21061f4a, + 0x7f863438, 0x20061f4a, 0x06bf5738, 0xef503820, 0x4a382006, 0x3821061f, 0x06ff4134, 0x7f863420, 0x20061f4a, 0x06ef5038, 0xef503820, 0x4a382006, + 0x3820061f, 0x20068f56, 0x06ef5038, 0xcf443820, 0x4a382006, 0x3820061f, 0x20061f4a, 0x061f4a38, 0x1f4a3820, 0x4a382006, 0x3820061f, 0x20061f4a, + 0x061f4a38, 0xef503820, 0x50382006, 0x382006ef, 0x20061f4a, 0x061f4a38, 0x1f4a3820, 0x5c382006, 0x322105c7, 0x05c75c38, 0xff860782, 0x20061f4a, + 0x05c75c38, 0xff411782, 0x06574506, 0x57453820, 0x45382006, 0x38200657, 0x20065745, 0x06574538, 0x57453820, 0x45382006, 0x38210657, 0x06ff4237, + 0x20065745, 0x06574538, 0x57453820, 0x37382106, 0x45067f43, 0x38200657, 0x20061f4a, 0x06ef5838, 0x1f513820, 0x4a382006, 0x3820061f, 0x20061f51, + 0x06ef5838, 0x1f4a3820, 0x58382006, 0x382106ef, 0x067f4137, 0x7f413720, 0x061f5106, 0x1f513820, 0x4a382006, 0x3820061f, 0x20061f51, 0x061f4a38, + 0x1f513820, 0x4a382006, 0x3820061f, 0x20061f51, 0x061f4a38, 0x1f513820, 0x4a382006, 0x3821061f, 0x067f4338, 0x7f433820, 0x061f4a06, 0x1f4a3820, + 0x38382106, 0x1f4a7f86, 0x4a382006, 0x3820061f, 0x20061f4a, 0x061f4a38, 0x47463820, 0x4a382006, 0x3820061f, 0x20061f4a, 0x061f4a38, 0x5f463820, + 0x46382006, 0x3820065f, 0x20065f46, 0x065f4638, 0x5f463820, 0x46382006, 0x3820065f, 0x21065f46, 0x7f863938, 0x20065f46, 0x065f4638, 0x5f463820, + 0x46382006, 0x3820065f, 0x20065f46, 0x065f4638, 0x5f463820, 0x46382006, 0x3820065f, 0x20065f46, 0x065f4638, 0x5f463820, 0x46382006, 0x3820065f, + 0x20065f46, 0x065f4638, 0x5f463820, 0x46382006, 0x3820065f, 0x20061f4a, 0x06674638, 0x67463820, 0x46382006, 0x38200667, 0x20066746, 0x06674638, + 0x67463820, 0x46382006, 0x38200667, 0x20066746, 0x06674638, 0x67463820, 0x46382006, 0x38200667, 0x20066746, 0x06674638, 0x67463820, 0x4a382006, + 0x3820061f, 0x21061f4a, 0x7f456338, 0x067f4606, 0x1f4a3820, 0x4a382006, 0x3821061f, 0x06ff4263, 0x20068f46, 0x061f4a38, 0x1f4a3820, 0x63382106, + 0x2006ff43, 0x067f4563, 0x2006274a, 0x060f5838, 0x274a3820, 0x52382006, 0x38200617, 0x2006274a, 0x06274a38, 0x274a3820, 0x4a382006, 0x38200627, + 0x2006274a, 0x06274a38, 0x274a3820, 0x4a382006, 0x38200627, 0x2006274a, 0x06274a38, 0x0f583820, 0x64382106, 0x274a7f86, 0x47382006, 0x38200637, + 0x2006274a, 0x06274a38, 0x274a3820, 0x47382006, 0x3820064f, 0x2006274a, 0x06274a38, 0x274a3820, 0x4a382006, 0x38200627, 0x2006274a, 0x06774738, + 0x77473820, 0x47382006, 0x38200677, 0x20067747, 0x06774738, 0x77473820, 0x4a382006, 0x38200627, 0x2006274a, 0x06275838, 0x274a3820, 0x4a382006, + 0x38200627, 0x2006274a, 0x06274a38, 0x274a3820, 0x66382106, 0x4706ff43, 0x382006bf, 0x2106bf47, 0x274a6638, 0x4a382005, 0x38200627, 0x20062758, + 0x06274a38, 0x274a3820, 0x4a382006, 0x38200627, 0x20062758, 0x06274a38, 0x42663821, 0x392005ff, 0x2006c743, 0x06c74339, 0x57433920, 0x43392006, + 0x39200657, 0x3920c786, 0x39205786, 0x61215786, 0x05b74430, 0xc7466120, 0x44612006, 0x612006f7, 0x2106f744, 0x2f423062, 0x30622105, 0x2105d74b, + 0xaf853062, 0x45306221, 0x6221052f, 0x052f4230, 0x41306221, 0x622105af, 0x052f4430, 0x44306221, 0x6220052f, 0x21062f48, 0x3f863162, 0x3f863120, + 0x3f863120, 0x3f863120, 0x3f853120, 0x17866520, 0x85316521, 0x476520d7, 0x652006c7, 0x2006c747, 0x06c74765, 0xc7476520, 0x47652006, 0x65200587, + 0x8206cf5d, 0x07312407, 0x82696e75, 0x85322007, 0x05974307, 0x43306521, 0x07820597, 0x33201787, 0x662c1f83, 0x00666665, 0xff010000, 0x000200ff, + 0x03820782, 0xd6df0024, 0x078331cb, 0x4751e12b, 0x000000f1, 0xd451e100, 0x02fa0534, 0x00369a2b, +}; + diff --git a/neo/sys/sys_imgui.cpp b/neo/sys/sys_imgui.cpp index f0438c085..99429bd0c 100644 --- a/neo/sys/sys_imgui.cpp +++ b/neo/sys/sys_imgui.cpp @@ -79,7 +79,7 @@ extern ImGuiTextBuffer WriteImGuiStyleToCode( const ImGuiStyle& style, const ImG namespace D3 { namespace ImGuiHooks { -#include "proggyvector_font_base85.h" +#include "proggyvector_font.h" static SDL_Window* sdlWindow = NULL; ImGuiContext* imguiCtx = NULL; @@ -255,6 +255,7 @@ bool Init(void* _sdlWindow, void* sdlGlContext) // Setup Dear ImGui context IMGUI_CHECKVERSION(); imguiCtx = ImGui::CreateContext(); + if ( imguiCtx == NULL ) { common->Warning( "Failed to create ImGui Context!\n" ); return false; @@ -270,14 +271,13 @@ bool Init(void* _sdlWindow, void* sdlGlContext) SetImGuiStyle( Style::Dhewm3 ); userStyle = ImGui::GetStyle(); // set dhewm3 style as default, in case the user style is missing values + if ( DG::ReadImGuiStyle( userStyle, GetUserStyleFilename() ) && imgui_style.GetInteger() == 2 ) { ImGui::GetStyle() = userStyle; } else if ( imgui_style.GetInteger() == 1 ) { ImGui::GetStyle() = ImGuiStyle(); ImGui::StyleColorsDark(); } - - imgui_scale.SetModified(); // so NewFrame() will load the scaled font // Setup Platform/Renderer backends @@ -365,7 +365,7 @@ void NewFrame() strcpy( fontCfg.Name, "ProggyVector" ); float fontSize = 18.0f * GetScale(); float fontSizeInt = roundf( fontSize ); // font sizes are supposed to be rounded to integers - io.Fonts->AddFontFromMemoryCompressedBase85TTF(ProggyVector_compressed_data_base85, fontSizeInt, &fontCfg); + ImFont* font = io.Fonts->AddFontFromMemoryCompressedTTF(ProggyVector_compressed_data, ProggyVector_compressed_size, fontSizeInt, nullptr); } // Start the Dear ImGui frame diff --git a/neo/sys/sys_local.cpp b/neo/sys/sys_local.cpp index d9073705c..0b2d1876f 100644 --- a/neo/sys/sys_local.cpp +++ b/neo/sys/sys_local.cpp @@ -122,10 +122,9 @@ const char *Sys_TimeStampToStr( ID_TIME_T timeStamp ) { static char timeString[MAX_STRING_CHARS]; timeString[0] = '\0'; - tm* time = localtime( &timeStamp ); - idStr out; - - idStr lang = cvarSystem->GetCVarString( "sys_lang" ); + tm *time = localtime( &timeStamp ); + idStr out; + idStr lang = cvarSystem->GetCVarString( "sys_lang" ); if ( lang.Icmp( "english" ) == 0 ) { // english gets "month/day/year hour:min" + "am" or "pm" out = va( "%02d", time->tm_mon + 1 ); @@ -134,6 +133,7 @@ const char *Sys_TimeStampToStr( ID_TIME_T timeStamp ) { out += "/"; out += va( "%d", time->tm_year + 1900 ); out += "\t"; + if ( time->tm_hour > 12 ) { out += va( "%02d", time->tm_hour - 12 ); } else if ( time->tm_hour == 0 ) { @@ -143,6 +143,7 @@ const char *Sys_TimeStampToStr( ID_TIME_T timeStamp ) { } out += ":"; out +=va( "%02d", time->tm_min ); + if ( time->tm_hour >= 12 ) { out += "pm"; } else { diff --git a/neo/sys/sys_public.h b/neo/sys/sys_public.h index dbff09dfd..82306418f 100644 --- a/neo/sys/sys_public.h +++ b/neo/sys/sys_public.h @@ -1,449 +1,454 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#ifndef __SYS_PUBLIC__ -#define __SYS_PUBLIC__ - -class idStr; - -typedef enum { - CPUID_NONE = 0x00000, - CPUID_UNSUPPORTED = 0x00001, // unsupported (386/486) - CPUID_GENERIC = 0x00002, // unrecognized processor - CPUID_MMX = 0x00010, // Multi Media Extensions - CPUID_3DNOW = 0x00020, // 3DNow! - CPUID_SSE = 0x00040, // Streaming SIMD Extensions - CPUID_SSE2 = 0x00080, // Streaming SIMD Extensions 2 - CPUID_SSE3 = 0x00100, // Streaming SIMD Extentions 3 aka Prescott's New Instructions - CPUID_ALTIVEC = 0x00200, // AltiVec -} cpuidSimd_t; - -typedef enum { - AXIS_LEFT_X, - AXIS_LEFT_Y, - AXIS_RIGHT_X, - AXIS_RIGHT_Y, - AXIS_LEFT_TRIG, - AXIS_RIGHT_TRIG, - MAX_JOYSTICK_AXIS -} joystickAxis_t; - -typedef enum { - SE_NONE, // evTime is still valid - SE_KEY, // evValue is a key code, evValue2 is the down flag - SE_CHAR, // evValue is a "High ASCII" (ISO-8859-1) char - SE_MOUSE, // evValue and evValue2 are relative signed x / y moves - SE_MOUSE_ABS, // evValue and evValue2 are absolute x / y coordinates in the window - SE_JOYSTICK, // evValue is an axis number and evValue2 is the current state (-127 to 127) - SE_CONSOLE // evPtr is a char*, from typing something at a non-game console -} sysEventType_t; - -typedef enum { - M_ACTION1, - M_ACTION2, - M_ACTION3, - M_ACTION4, - M_ACTION5, - M_ACTION6, - M_ACTION7, - M_ACTION8, - M_DELTAX, - M_DELTAY, - M_DELTAZ -} sys_mEvents; - -typedef enum { - J_ACTION_FIRST, - // these names are similar to the SDL3 SDL_GamepadButton names - J_BTN_SOUTH = J_ACTION_FIRST, // bottom face button, like Xbox A - J_BTN_EAST, // right face button, like Xbox B - J_BTN_WEST, // left face button, like Xbox X - J_BTN_NORTH, // top face button, like Xbox Y - J_BTN_BACK, - J_BTN_GUIDE, // Note: this one should probably not be used? - J_BTN_START, - J_BTN_LSTICK, // press left stick - J_BTN_RSTICK, // press right stick - J_BTN_LSHOULDER, - J_BTN_RSHOULDER, - - J_DPAD_UP, - J_DPAD_DOWN, - J_DPAD_LEFT, - J_DPAD_RIGHT, - - J_BTN_MISC1, // Additional button (e.g. Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button) - J_BTN_RPADDLE1, // Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1) - J_BTN_LPADDLE1, // Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3) - J_BTN_RPADDLE2, // Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2) - J_BTN_LPADDLE2, // Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4) - - J_ACTION_MAX = J_BTN_LPADDLE2, - // leaving some space here for about 12 additional J_ACTIONs, if needed - - J_AXIS_MIN = 32, - J_AXIS_LEFT_X = J_AXIS_MIN + AXIS_LEFT_X, - J_AXIS_LEFT_Y = J_AXIS_MIN + AXIS_LEFT_Y, - J_AXIS_RIGHT_X = J_AXIS_MIN + AXIS_RIGHT_X, - J_AXIS_RIGHT_Y = J_AXIS_MIN + AXIS_RIGHT_Y, - J_AXIS_LEFT_TRIG = J_AXIS_MIN + AXIS_LEFT_TRIG, - J_AXIS_RIGHT_TRIG = J_AXIS_MIN + AXIS_RIGHT_TRIG, - - J_AXIS_MAX = J_AXIS_MIN + MAX_JOYSTICK_AXIS - 1, - - MAX_JOY_EVENT -} sys_jEvents; - -struct sysEvent_t { - sysEventType_t evType; - int evValue; // for keys: K_* or ASCII code; for joystick: axis; for mouse: mouseX - int evValue2; // for keys: 0/1 for up/down; for axis: value; for mouse: mouseY - int evPtrLength; // bytes of data pointed to by evPtr, for journaling - void * evPtr; // this must be manually freed if not NULL -}; - -enum sysPath_t { - PATH_BASE, - PATH_CONFIG, - PATH_SAVE, - PATH_EXE -}; - -template class idList; // for Sys_ListFiles - - -void Sys_Init( void ); -void Sys_Shutdown( void ); -void Sys_Error( const char *error, ...); -void Sys_Quit( void ); - -// note that this isn't journaled... -char * Sys_GetClipboardData( void ); -void Sys_FreeClipboardData( char* data ); -void Sys_SetClipboardData( const char *string ); - -// will go to the various text consoles -// NOT thread safe - never use in the async paths -void Sys_Printf( const char *msg, ... )id_attribute((format(printf,1,2))); - -// guaranteed to be thread-safe -void Sys_DebugPrintf( const char *fmt, ... )id_attribute((format(printf,1,2))); -void Sys_DebugVPrintf( const char *fmt, va_list arg ); - -// allow game to yield CPU time -// NOTE: due to SDL_TIMESLICE this is very bad portability karma, and should be completely removed -void Sys_Sleep( int msec ); - -// Sys_Milliseconds should only be used for profiling purposes, -// any game related timing information should come from event timestamps -unsigned int Sys_Milliseconds( void ); - -// returns a selection of the CPUID_* flags -int Sys_GetProcessorId( void ); - -// sets the FPU precision -void Sys_FPU_SetPrecision(); - -// sets Flush-To-Zero mode -void Sys_FPU_SetFTZ( bool enable ); - -// sets Denormals-Are-Zero mode -void Sys_FPU_SetDAZ( bool enable ); - -// returns amount of system ram -int Sys_GetSystemRam( void ); - -// returns amount of drive space in path -int Sys_GetDriveFreeSpace( const char *path ); - -// lock and unlock memory -bool Sys_LockMemory( void *ptr, int bytes ); -bool Sys_UnlockMemory( void *ptr, int bytes ); - -// set amount of physical work memory -void Sys_SetPhysicalWorkMemory( int minBytes, int maxBytes ); - -// DLL loading, the path should be a fully qualified OS path to the DLL file to be loaded -uintptr_t Sys_DLL_Load( const char *dllName ); -void * Sys_DLL_GetProcAddress( uintptr_t dllHandle, const char *procName ); -void Sys_DLL_Unload( uintptr_t dllHandle ); - -// event generation -void Sys_GenerateEvents( void ); -sysEvent_t Sys_GetEvent( void ); -void Sys_ClearEvents( void ); -char *Sys_ConsoleInput( void ); - -// input is tied to windows, so it needs to be started up and shut down whenever -// the main window is recreated -void Sys_InitInput( void ); -void Sys_ShutdownInput( void ); -void Sys_InitScanTable( void ); -unsigned char Sys_GetConsoleKey( bool shifted ); -// map a scancode key to a char -// does nothing on win32, as SE_KEY == SE_CHAR there -// on other OSes, consider the keyboard mapping -unsigned char Sys_MapCharForKey( int key ); -// for keynums between K_FIRST_SCANCODE and K_LAST_SCANCODE -// returns e.g. "SC_A" for K_SC_A -const char* Sys_GetScancodeName( int key ); -// returns localized name of the key (between K_FIRST_SCANCODE and K_LAST_SCANCODE), -// regarding the current keyboard layout - if that name is in ASCII or corresponds -// to a "High-ASCII" char supported by Doom3. -// Otherwise return same name as Sys_GetScancodeName() -// !! Returned string is only valid until next call to this function !! -const char* Sys_GetLocalizedScancodeName( int key ); -// the same, but using UTF-8 instead of "High-ASCII" -const char* Sys_GetLocalizedScancodeNameUTF8( int key ); -// returns keyNum_t (K_SC_* constant) for given scancode name (like "SC_A") -int Sys_GetKeynumForScancodeName( const char* name ); - -// returns display name of the key (between K_FIRST_JOY and K_LAST_JOY) -// With SDL2 it'll return the name in the SDL_GameController standard layout -// (which is based on XBox/XInput => on Nintendo gamepads, A/B and X/Y will be flipped), -// with SDL3 it will return the "real" button name -const char* Sys_GetLocalizedJoyKeyName( int key ); - -// keyboard input polling -int Sys_PollKeyboardInputEvents( void ); -int Sys_ReturnKeyboardInputEvent( const int n, int &ch, bool &state ); -void Sys_EndKeyboardInputEvents( void ); - -// mouse input polling -int Sys_PollMouseInputEvents( void ); -int Sys_ReturnMouseInputEvent( const int n, int &action, int &value ); -void Sys_EndMouseInputEvents( void ); - -// joystick input polling -void Sys_SetRumble( int device, int low, int hi ); -int Sys_PollJoystickInputEvents( int deviceNum ); -int Sys_ReturnJoystickInputEvent( const int n, int &action, int &value ); -void Sys_EndJoystickInputEvents(); - -// when the console is down, or the game is about to perform a lengthy -// operation like map loading, the system can release the mouse cursor -// when in windowed mode -void Sys_GrabMouseCursor( bool grabIt ); - -// DG: added this for an ungodly hack for gamepad support -// active = true means "currently a GUI with a cursor is active/focused" -// active = false means "that GUI is not active anymore" -// ui == NULL means "clear all currently remembered GUIs" -class idUserInterface; -void Sys_SetInteractiveIngameGuiActive( bool active, idUserInterface* ui ); - -void Sys_ShowWindow( bool show ); -bool Sys_IsWindowVisible( void ); -void Sys_ShowConsole( int visLevel, bool quitOnClose ); - - -void Sys_Mkdir( const char *path ); -ID_TIME_T Sys_FileTimeStamp( FILE *fp ); -// NOTE: do we need to guarantee the same output on all platforms? -const char * Sys_TimeStampToStr( ID_TIME_T timeStamp ); - -bool Sys_GetPath(sysPath_t type, idStr &path); - -// use fs_debug to verbose Sys_ListFiles -// returns -1 if directory was not found (the list is cleared) -int Sys_ListFiles( const char *directory, const char *extension, idList &list ); - -/* -============================================================== - - Networking - -============================================================== -*/ - -typedef enum { - NA_BAD, // an address lookup failed - NA_LOOPBACK, - NA_BROADCAST, - NA_IP -} netadrtype_t; - -typedef struct { - netadrtype_t type; - unsigned char ip[4]; - unsigned short port; -} netadr_t; - -#define PORT_ANY -1 - -class idPort { -public: - idPort(); // this just zeros netSocket and port - virtual ~idPort(); - - // if the InitForPort fails, the idPort.port field will remain 0 - bool InitForPort( int portNumber ); - int GetPort( void ) const { return bound_to.port; } - netadr_t GetAdr( void ) const { return bound_to; } - void Close(); - - bool GetPacket( netadr_t &from, void *data, int &size, int maxSize ); - bool GetPacketBlocking( netadr_t &from, void *data, int &size, int maxSize, int timeout ); - void SendPacket( const netadr_t to, const void *data, int size ); - - int packetsRead; - int bytesRead; - - int packetsWritten; - int bytesWritten; - -private: - netadr_t bound_to; // interface and port - int netSocket; // OS specific socket -}; - -class idTCP { -public: - idTCP(); - virtual ~idTCP(); - - // if host is host:port, the value of port is ignored - bool Init( const char *host, short port ); - void Close(); - - // returns -1 on failure (and closes socket) - // those are non blocking, can be used for polling - // there is no buffering, you are not guaranteed to Read or Write everything in a single call - // (specially on win32, see recv and send documentation) - int Read( void *data, int size ); - int Write( void *data, int size ); - -private: - netadr_t address; // remote address - int fd; // OS specific socket -}; - - // parses the port number - // can also do DNS resolve if you ask for it. - // NOTE: DNS resolve is a slow/blocking call, think before you use - // ( could be exploited for server DoS ) -bool Sys_StringToNetAdr( const char *s, netadr_t *a, bool doDNSResolve ); -const char * Sys_NetAdrToString( const netadr_t a ); -bool Sys_IsLANAddress( const netadr_t a ); -bool Sys_CompareNetAdrBase( const netadr_t a, const netadr_t b ); - -void Sys_InitNetworking( void ); -void Sys_ShutdownNetworking( void ); - - -/* -============================================================== - - Multi-threading - -============================================================== -*/ - -struct SDL_Thread; - -typedef int (*xthread_t)( void * ); - -typedef struct { - const char *name; - SDL_Thread *threadHandle; - unsigned long threadId; -} xthreadInfo; - -void Sys_CreateThread( xthread_t function, void *parms, xthreadInfo &info, const char *name ); -void Sys_DestroyThread( xthreadInfo& info ); // sets threadHandle back to 0 - -// find the name of the calling thread -// if index != NULL, set the index in threads array (use -1 for "main" thread) -const char * Sys_GetThreadName( int *index = 0 ); - -extern void Sys_InitThreads(); -extern void Sys_ShutdownThreads(); - -bool Sys_IsMainThread(); - -const int MAX_CRITICAL_SECTIONS = 5; - -enum { - CRITICAL_SECTION_ZERO = 0, - CRITICAL_SECTION_ONE, - CRITICAL_SECTION_TWO, - CRITICAL_SECTION_THREE, - CRITICAL_SECTION_SYS -}; - -void Sys_EnterCriticalSection( int index = CRITICAL_SECTION_ZERO ); -void Sys_LeaveCriticalSection( int index = CRITICAL_SECTION_ZERO ); - -const int MAX_TRIGGER_EVENTS = 4; - -enum { - TRIGGER_EVENT_ZERO = 0, - TRIGGER_EVENT_ONE, - TRIGGER_EVENT_TWO, - TRIGGER_EVENT_THREE -}; - -void Sys_WaitForEvent( int index = TRIGGER_EVENT_ZERO ); -void Sys_TriggerEvent( int index = TRIGGER_EVENT_ZERO ); - -/* -============================================================== - - idSys - -============================================================== -*/ - -class idSys { -public: - virtual void DebugPrintf( const char *fmt, ... )id_attribute((format(printf,2,3))) = 0; - virtual void DebugVPrintf( const char *fmt, va_list arg ) = 0; - - virtual unsigned int GetMilliseconds( void ) = 0; - virtual int GetProcessorId( void ) = 0; - virtual void FPU_SetFTZ( bool enable ) = 0; - virtual void FPU_SetDAZ( bool enable ) = 0; - - virtual bool LockMemory( void *ptr, int bytes ) = 0; - virtual bool UnlockMemory( void *ptr, int bytes ) = 0; - - virtual uintptr_t DLL_Load( const char *dllName ) = 0; - virtual void * DLL_GetProcAddress( uintptr_t dllHandle, const char *procName ) = 0; - virtual void DLL_Unload( uintptr_t dllHandle ) = 0; - virtual void DLL_GetFileName( const char *baseName, char *dllName, int maxLength ) = 0; - - virtual sysEvent_t GenerateMouseButtonEvent( int button, bool down ) = 0; - virtual sysEvent_t GenerateMouseMoveEvent( int deltax, int deltay ) = 0; - - virtual void OpenURL( const char *url, bool quit ) = 0; - virtual void StartProcess( const char *exePath, bool quit ) = 0; -}; - -extern idSys * sys; - -#endif /* !__SYS_PUBLIC__ */ +/* +=========================================================================== + +Doom 3 GPL Source Code +Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. + +This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). + +Doom 3 Source Code is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Doom 3 Source Code is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Doom 3 Source Code. If not, see . + +In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ + +#ifndef __SYS_PUBLIC__ +#define __SYS_PUBLIC__ + +class idStr; + +typedef enum { + CPUID_NONE = 0x00000, // unsupported (386/486) + CPUID_GENERIC = 0x00001, // unrecognized processor + CPUID_INTEL = 0x00002, // Intel + CPUID_AMD = 0x00004, // AMD + CPUID_MMX = 0x00008, // Multi Media Extensions + CPUID_3DNOW = 0x00010, // 3DNow! + CPUID_SSE = 0x00020, // Streaming SIMD Extensions + CPUID_SSE2 = 0x00040, // Streaming SIMD Extensions 2 + CPUID_SSE3 = 0x00080, // Streaming SIMD Extentions 3 aka Prescott's New Instructions + CPUID_SSE41 = 0x00100, // Streaming SIMD Extentions 4.1 (Penryn) + CPUID_AVX = 0x00200, // AVX extenstions (SandyBridge) + CPUID_AVX2 = 0x00400, // AVX2 extenstions (Haswell) + CPUID_FMA3 = 0x00800, // FMA3 instruction (Haswell) + CPUID_DAZ = 0x01000, // Denormals-Are-Zero mode (denormal source operands are set to zero) + CPUID_ALTIVEC = 0x02000, // AltiVec +} cpuidSimd_t; + +typedef enum { + AXIS_LEFT_X, + AXIS_LEFT_Y, + AXIS_RIGHT_X, + AXIS_RIGHT_Y, + AXIS_LEFT_TRIG, + AXIS_RIGHT_TRIG, + MAX_JOYSTICK_AXIS +} joystickAxis_t; + +typedef enum { + SE_NONE, // evTime is still valid + SE_KEY, // evValue is a key code, evValue2 is the down flag + SE_CHAR, // evValue is a "High ASCII" (ISO-8859-1) char + SE_MOUSE, // evValue and evValue2 are relative signed x / y moves + SE_MOUSE_ABS, // evValue and evValue2 are absolute x / y coordinates in the window + SE_JOYSTICK, // evValue is an axis number and evValue2 is the current state (-127 to 127) + SE_CONSOLE // evPtr is a char*, from typing something at a non-game console +} sysEventType_t; + +typedef enum { + M_ACTION1, + M_ACTION2, + M_ACTION3, + M_ACTION4, + M_ACTION5, + M_ACTION6, + M_ACTION7, + M_ACTION8, + M_DELTAX, + M_DELTAY, + M_DELTAZ +} sys_mEvents; + +typedef enum { + J_ACTION_FIRST, + // these names are similar to the SDL3 SDL_GamepadButton names + J_BTN_SOUTH = J_ACTION_FIRST, // bottom face button, like Xbox A + J_BTN_EAST, // right face button, like Xbox B + J_BTN_WEST, // left face button, like Xbox X + J_BTN_NORTH, // top face button, like Xbox Y + J_BTN_BACK, + J_BTN_GUIDE, // Note: this one should probably not be used? + J_BTN_START, + J_BTN_LSTICK, // press left stick + J_BTN_RSTICK, // press right stick + J_BTN_LSHOULDER, + J_BTN_RSHOULDER, + + J_DPAD_UP, + J_DPAD_DOWN, + J_DPAD_LEFT, + J_DPAD_RIGHT, + + J_BTN_MISC1, // Additional button (e.g. Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button) + J_BTN_RPADDLE1, // Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1) + J_BTN_LPADDLE1, // Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3) + J_BTN_RPADDLE2, // Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2) + J_BTN_LPADDLE2, // Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4) + + J_ACTION_MAX = J_BTN_LPADDLE2, + // leaving some space here for about 12 additional J_ACTIONs, if needed + + J_AXIS_MIN = 32, + J_AXIS_LEFT_X = J_AXIS_MIN + AXIS_LEFT_X, + J_AXIS_LEFT_Y = J_AXIS_MIN + AXIS_LEFT_Y, + J_AXIS_RIGHT_X = J_AXIS_MIN + AXIS_RIGHT_X, + J_AXIS_RIGHT_Y = J_AXIS_MIN + AXIS_RIGHT_Y, + J_AXIS_LEFT_TRIG = J_AXIS_MIN + AXIS_LEFT_TRIG, + J_AXIS_RIGHT_TRIG = J_AXIS_MIN + AXIS_RIGHT_TRIG, + + J_AXIS_MAX = J_AXIS_MIN + MAX_JOYSTICK_AXIS - 1, + + MAX_JOY_EVENT +} sys_jEvents; + +struct sysEvent_t { + sysEventType_t evType; + int evValue; // for keys: K_* or ASCII code; for joystick: axis; for mouse: mouseX + int evValue2; // for keys: 0/1 for up/down; for axis: value; for mouse: mouseY + int evPtrLength; // bytes of data pointed to by evPtr, for journaling + void * evPtr; // this must be manually freed if not NULL +}; + +enum sysPath_t { + PATH_BASE, + PATH_CONFIG, + PATH_SAVE, + PATH_EXE +}; + +template class idList; // for Sys_ListFiles + +void Sys_Init( void ); +void Sys_Shutdown( void ); +void Sys_Error( const char *error, ...); +void Sys_Quit( void ); + +// note that this isn't journaled... +char * Sys_GetClipboardData( void ); +void Sys_FreeClipboardData( char* data ); +void Sys_SetClipboardData( const char *string ); + +// will go to the various text consoles +// NOT thread safe - never use in the async paths +void Sys_Printf( const char *msg, ... )id_attribute((format(printf,1,2))); + +// guaranteed to be thread-safe +void Sys_DebugPrintf( const char *fmt, ... )id_attribute((format(printf,1,2))); +void Sys_DebugVPrintf( const char *fmt, va_list arg ); + +// allow game to yield CPU time +// NOTE: due to SDL_TIMESLICE this is very bad portability karma, and should be completely removed +void Sys_Sleep( int msec ); + +// Sys_Milliseconds should only be used for profiling purposes, +// any game related timing information should come from event timestamps +unsigned int Sys_Milliseconds( void ); + +// returns a selection of the CPUID_* flags +int Sys_GetProcessorId( void ); + +// sets the FPU precision +void Sys_FPU_SetPrecision(); + +// sets Flush-To-Zero mode +void Sys_FPU_SetFTZ( bool enable = false ); + +// sets Denormals-Are-Zero mode +void Sys_FPU_SetDAZ( bool enable = false ); + +// returns amount of system ram +int Sys_GetSystemRam( void ); + +// returns amount of drive space in path +int Sys_GetDriveFreeSpace( const char *path ); + +// lock and unlock memory +bool Sys_LockMemory( void *ptr, int bytes ); +bool Sys_UnlockMemory( void *ptr, int bytes ); + +// set amount of physical work memory +void Sys_SetPhysicalWorkMemory( int minBytes, int maxBytes ); + +// DLL loading, the path should be a fully qualified OS path to the DLL file to be loaded +uintptr_t Sys_DLL_Load( const char *dllName ); +void * Sys_DLL_GetProcAddress( uintptr_t dllHandle, const char *procName ); +void Sys_DLL_Unload( uintptr_t dllHandle ); + +// event generation +void Sys_GenerateEvents( void ); +sysEvent_t Sys_GetEvent( void ); +void Sys_ClearEvents( void ); +char *Sys_ConsoleInput( void ); + +// input is tied to windows, so it needs to be started up and shut down whenever +// the main window is recreated +void Sys_InitInput( void ); +void Sys_ShutdownInput( void ); +void Sys_InitScanTable( void ); +unsigned char Sys_GetConsoleKey( bool shifted ); +// map a scancode key to a char +// does nothing on win32, as SE_KEY == SE_CHAR there +// on other OSes, consider the keyboard mapping +unsigned char Sys_MapCharForKey( int key ); +// for keynums between K_FIRST_SCANCODE and K_LAST_SCANCODE +// returns e.g. "SC_A" for K_SC_A +const char* Sys_GetScancodeName( int key ); +// returns localized name of the key (between K_FIRST_SCANCODE and K_LAST_SCANCODE), +// regarding the current keyboard layout - if that name is in ASCII or corresponds +// to a "High-ASCII" char supported by Doom3. +// Otherwise return same name as Sys_GetScancodeName() +// !! Returned string is only valid until next call to this function !! +const char* Sys_GetLocalizedScancodeName( int key ); +// the same, but using UTF-8 instead of "High-ASCII" +const char* Sys_GetLocalizedScancodeNameUTF8( int key ); +// returns keyNum_t (K_SC_* constant) for given scancode name (like "SC_A") +int Sys_GetKeynumForScancodeName( const char* name ); + +// returns display name of the key (between K_FIRST_JOY and K_LAST_JOY) +// With SDL2 it'll return the name in the SDL_GameController standard layout +// (which is based on XBox/XInput => on Nintendo gamepads, A/B and X/Y will be flipped), +// with SDL3 it will return the "real" button name +const char* Sys_GetLocalizedJoyKeyName( int key ); + +// keyboard input polling +int Sys_PollKeyboardInputEvents( void ); +int Sys_ReturnKeyboardInputEvent( const int n, int &ch, bool &state ); +void Sys_EndKeyboardInputEvents( void ); + +// mouse input polling +int Sys_PollMouseInputEvents( void ); +int Sys_ReturnMouseInputEvent( const int n, int &action, int &value ); +void Sys_EndMouseInputEvents( void ); + +// joystick input polling +void Sys_SetRumble( int device, int low, int hi ); +int Sys_PollJoystickInputEvents( int deviceNum ); +int Sys_ReturnJoystickInputEvent( const int n, int &action, int &value ); +void Sys_EndJoystickInputEvents(); + +// when the console is down, or the game is about to perform a lengthy +// operation like map loading, the system can release the mouse cursor +// when in windowed mode +void Sys_GrabMouseCursor( bool grabIt ); + +// DG: added this for an ungodly hack for gamepad support +// active = true means "currently a GUI with a cursor is active/focused" +// active = false means "that GUI is not active anymore" +// ui == NULL means "clear all currently remembered GUIs" +class idUserInterface; +void Sys_SetInteractiveIngameGuiActive( bool active, idUserInterface* ui ); + +void Sys_ShowWindow( bool show ); +bool Sys_IsWindowVisible( void ); +void Sys_ShowConsole( int visLevel, bool quitOnClose ); + + +void Sys_Mkdir( const char *path ); +ID_TIME_T Sys_FileTimeStamp( FILE *fp ); +// NOTE: do we need to guarantee the same output on all platforms? +const char * Sys_TimeStampToStr( ID_TIME_T timeStamp ); + +bool Sys_GetPath(sysPath_t type, idStr &path); + +// use fs_debug to verbose Sys_ListFiles +// returns -1 if directory was not found (the list is cleared) +int Sys_ListFiles( const char *directory, const char *extension, idList &list ); + +/* +============================================================== + + Networking + +============================================================== +*/ + +typedef enum { + NA_BAD, // an address lookup failed + NA_LOOPBACK, + NA_BROADCAST, + NA_IP +} netadrtype_t; + +typedef struct { + netadrtype_t type; + unsigned char ip[4]; + unsigned short port; +} netadr_t; + +#define PORT_ANY -1 + +class idPort { +public: + idPort(); // this just zeros netSocket and port + virtual ~idPort(); + + // if the InitForPort fails, the idPort.port field will remain 0 + bool InitForPort( int portNumber ); + int GetPort( void ) const { return bound_to.port; } + netadr_t GetAdr( void ) const { return bound_to; } + void Close(); + + bool GetPacket( netadr_t &from, void *data, int &size, int maxSize ); + bool GetPacketBlocking( netadr_t &from, void *data, int &size, int maxSize, int timeout ); + void SendPacket( const netadr_t to, const void *data, int size ); + + int packetsRead; + int bytesRead; + + int packetsWritten; + int bytesWritten; + +private: + netadr_t bound_to; // interface and port + int netSocket; // OS specific socket +}; + +class idTCP { +public: + idTCP(); + virtual ~idTCP(); + + // if host is host:port, the value of port is ignored + bool Init( const char *host, short port ); + void Close(); + + // returns -1 on failure (and closes socket) + // those are non blocking, can be used for polling + // there is no buffering, you are not guaranteed to Read or Write everything in a single call + // (specially on win32, see recv and send documentation) + int Read( void *data, int size ); + int Write( void *data, int size ); + +private: + netadr_t address; // remote address + int fd; // OS specific socket +}; + + // parses the port number + // can also do DNS resolve if you ask for it. + // NOTE: DNS resolve is a slow/blocking call, think before you use + // ( could be exploited for server DoS ) +bool Sys_StringToNetAdr( const char *s, netadr_t *a, bool doDNSResolve ); +const char * Sys_NetAdrToString( const netadr_t a ); +bool Sys_IsLANAddress( const netadr_t a ); +bool Sys_CompareNetAdrBase( const netadr_t a, const netadr_t b ); + +void Sys_InitNetworking( void ); +void Sys_ShutdownNetworking( void ); + + +/* +============================================================== + + Multi-threading + +============================================================== +*/ + +struct SDL_Thread; + +typedef int (*xthread_t)( void * ); + +typedef struct { + const char *name; + SDL_Thread *threadHandle; + unsigned long threadId; +} xthreadInfo; + +void Sys_CreateThread( xthread_t function, void *parms, xthreadInfo &info, const char *name ); +void Sys_DestroyThread( xthreadInfo& info ); // sets threadHandle back to 0 + +// find the name of the calling thread +// if index != NULL, set the index in threads array (use -1 for "main" thread) +const char * Sys_GetThreadName( int *index = 0 ); + +extern void Sys_InitThreads(); +extern void Sys_ShutdownThreads(); + +bool Sys_IsMainThread(); + +const int MAX_CRITICAL_SECTIONS = 5; + +enum { + CRITICAL_SECTION_ZERO = 0, + CRITICAL_SECTION_ONE, + CRITICAL_SECTION_TWO, + CRITICAL_SECTION_THREE, + CRITICAL_SECTION_SYS +}; + +void Sys_EnterCriticalSection( int index = CRITICAL_SECTION_ZERO ); +void Sys_LeaveCriticalSection( int index = CRITICAL_SECTION_ZERO ); + +const int MAX_TRIGGER_EVENTS = 4; + +enum { + TRIGGER_EVENT_ZERO = 0, + TRIGGER_EVENT_ONE, + TRIGGER_EVENT_TWO, + TRIGGER_EVENT_THREE +}; + +void Sys_WaitForEvent( int index = TRIGGER_EVENT_ZERO ); +void Sys_TriggerEvent( int index = TRIGGER_EVENT_ZERO ); + +/* +============================================================== + + idSys + +============================================================== +*/ + +class idSys { +public: + virtual void DebugPrintf( const char *fmt, ... )id_attribute((format(printf,2,3))) = 0; + virtual void DebugVPrintf( const char *fmt, va_list arg ) = 0; + + virtual unsigned int GetMilliseconds( void ) = 0; + virtual int GetProcessorId( void ) = 0; + virtual void FPU_SetFTZ( bool enable ) = 0; + virtual void FPU_SetDAZ( bool enable ) = 0; + + virtual bool LockMemory( void *ptr, int bytes ) = 0; + virtual bool UnlockMemory( void *ptr, int bytes ) = 0; + + virtual uintptr_t DLL_Load( const char *dllName ) = 0; + virtual void * DLL_GetProcAddress( uintptr_t dllHandle, const char *procName ) = 0; + virtual void DLL_Unload( uintptr_t dllHandle ) = 0; + virtual void DLL_GetFileName( const char *baseName, char *dllName, int maxLength ) = 0; + + virtual sysEvent_t GenerateMouseButtonEvent( int button, bool down ) = 0; + virtual sysEvent_t GenerateMouseMoveEvent( int deltax, int deltay ) = 0; + + virtual void OpenURL( const char *url, bool quit ) = 0; + virtual void StartProcess( const char *exePath, bool quit ) = 0; +}; + +extern idSys * sys; + +#endif /* !__SYS_PUBLIC__ */ diff --git a/neo/sys/threads.cpp b/neo/sys/threads.cpp index d2a07cfb3..e8eca6fe8 100644 --- a/neo/sys/threads.cpp +++ b/neo/sys/threads.cpp @@ -29,10 +29,10 @@ If you have questions concerning this license or the applicable additional terms #include "sys/sys_sdl.h" #if 0 // TODO: was there a reason not to include full SDL.h? - #include - #include - #include - #include +#include +#include +#include +#include #endif #include "sys/platform.h" @@ -41,24 +41,24 @@ If you have questions concerning this license or the applicable additional terms #include "sys/sys_public.h" #if SDL_MAJOR_VERSION < 2 - // SDL1.2 doesn't have SDL_threadID but uses Uint32. - // this typedef helps using the same code for SDL1.2 and SDL2 - typedef Uint32 SDL_threadID; +// SDL1.2 doesn't have SDL_threadID but uses Uint32. +// this typedef helps using the same code for SDL1.2 and SDL2 +typedef Uint32 SDL_threadID; #elif SDL_MAJOR_VERSION >= 3 - // backwards-compat with SDL2 - #define SDL_mutex SDL_Mutex - #define SDL_cond SDL_Condition - #define SDL_threadID SDL_ThreadID - #define SDL_CreateCond SDL_CreateCondition - #define SDL_DestroyCond SDL_DestroyCondition - #define SDL_CondWait SDL_WaitCondition - #define SDL_CondSignal SDL_SignalCondition +// backwards-compat with SDL2 +#define SDL_mutex SDL_Mutex +#define SDL_cond SDL_Condition +#define SDL_threadID SDL_ThreadID +#define SDL_CreateCond SDL_CreateCondition +#define SDL_DestroyCond SDL_DestroyCondition +#define SDL_CondWait SDL_WaitCondition +#define SDL_CondSignal SDL_SignalCondition #endif #if __cplusplus >= 201103 - // xthreadinfo::threadId doesn't use SDL_threadID directly so we don't drag SDL headers into sys_public.h - // but we should still make sure that the type fits (in SDL1.2 it's Uint32, in SDL2 it's unsigned long) - static_assert( sizeof(SDL_threadID) <= sizeof(xthreadInfo::threadId), "xthreadInfo::threadId has unsuitable type!" ); +// xthreadinfo::threadId doesn't use SDL_threadID directly so we don't drag SDL headers into sys_public.h +// but we should still make sure that the type fits (in SDL1.2 it's Uint32, in SDL2 it's unsigned long) +static_assert( sizeof( SDL_threadID ) <= sizeof( xthreadInfo::threadId ), "xthreadInfo::threadId has unsuitable type!" ); #endif static SDL_mutex *mutex[MAX_CRITICAL_SECTIONS] = { }; @@ -77,8 +77,8 @@ static SDL_threadID mainThreadID = -1; Sys_Sleep ============== */ -void Sys_Sleep(int msec) { - SDL_Delay(msec); +void Sys_Sleep( int msec ) { + SDL_Delay( msec ); } /* @@ -100,32 +100,31 @@ void Sys_InitThreads() { mainThreadIDset = true; // critical sections - for (int i = 0; i < MAX_CRITICAL_SECTIONS; i++) { + for ( int i = 0; i < MAX_CRITICAL_SECTIONS; i++ ) { mutex[i] = SDL_CreateMutex(); - if (!mutex[i]) { - Sys_Printf("ERROR: SDL_CreateMutex failed\n"); + if ( !mutex[i] ) { + Sys_Printf( "ERROR: SDL_CreateMutex failed\n" ); return; } } // events - for (int i = 0; i < MAX_TRIGGER_EVENTS; i++) { + for ( int i = 0; i < MAX_TRIGGER_EVENTS; i++ ) { cond[i] = SDL_CreateCond(); - if (!cond[i]) { - Sys_Printf("ERROR: SDL_CreateCond failed\n"); + if ( !cond[i] ) { + Sys_Printf( "ERROR: SDL_CreateCond failed\n" ); return; } - signaled[i] = false; waiting[i] = false; } // threads - for (int i = 0; i < MAX_THREADS; i++) + for ( int i = 0; i < MAX_THREADS; i++ ) { thread[i] = NULL; - + } thread_count = 0; } @@ -136,30 +135,30 @@ Sys_ShutdownThreads */ void Sys_ShutdownThreads() { // threads - for (int i = 0; i < MAX_THREADS; i++) { - if (!thread[i]) + for ( int i = 0; i < MAX_THREADS; i++ ) { + if ( !thread[i] ) { continue; - - Sys_Printf("WARNING: Thread '%s' still running\n", thread[i]->name); + } + Sys_Printf( "WARNING: Thread '%s' still running\n", thread[i]->name ); #if SDL_VERSION_ATLEAST(2, 0, 0) - // TODO no equivalent in SDL2 +// TODO no equivalent in SDL2 #else - SDL_KillThread(thread[i]->threadHandle); + SDL_KillThread( thread[i]->threadHandle ); #endif thread[i] = NULL; } // events - for (int i = 0; i < MAX_TRIGGER_EVENTS; i++) { - SDL_DestroyCond(cond[i]); + for ( int i = 0; i < MAX_TRIGGER_EVENTS; i++ ) { + SDL_DestroyCond( cond[i] ); cond[i] = NULL; signaled[i] = false; waiting[i] = false; } // critical sections - for (int i = 0; i < MAX_CRITICAL_SECTIONS; i++) { - SDL_DestroyMutex(mutex[i]); + for ( int i = 0; i < MAX_CRITICAL_SECTIONS; i++ ) { + SDL_DestroyMutex( mutex[i] ); mutex[i] = NULL; } } @@ -169,14 +168,15 @@ void Sys_ShutdownThreads() { Sys_EnterCriticalSection ================== */ -void Sys_EnterCriticalSection(int index) { - assert(index >= 0 && index < MAX_CRITICAL_SECTIONS); +void Sys_EnterCriticalSection( int index ) { + assert( index >= 0 && index < MAX_CRITICAL_SECTIONS ); #if SDL_VERSION_ATLEAST(3, 0, 0) - SDL_LockMutex(mutex[index]); // in SDL3, this returns void and can't fail + SDL_LockMutex( mutex[index] ); // in SDL3, this returns void and can't fail #else // SDL2 and SDL1.2 - if (SDL_LockMutex(mutex[index]) != 0) - common->Error("ERROR: SDL_LockMutex failed\n"); + if ( SDL_LockMutex( mutex[index] ) != 0 ) { + common->Error( "ERROR: SDL_LockMutex failed\n" ); + } #endif } @@ -185,14 +185,15 @@ void Sys_EnterCriticalSection(int index) { Sys_LeaveCriticalSection ================== */ -void Sys_LeaveCriticalSection(int index) { - assert(index >= 0 && index < MAX_CRITICAL_SECTIONS); +void Sys_LeaveCriticalSection( int index ) { + assert( index >= 0 && index < MAX_CRITICAL_SECTIONS ); #if SDL_VERSION_ATLEAST(3, 0, 0) - SDL_UnlockMutex(mutex[index]); // in SDL3, this returns void and can't fail + SDL_UnlockMutex( mutex[index] ); // in SDL3, this returns void and can't fail #else // SDL2 and SDL1.2 - if (SDL_UnlockMutex(mutex[index]) != 0) - common->Error("ERROR: SDL_UnlockMutex failed\n"); + if ( SDL_UnlockMutex( mutex[index] ) != 0 ) { + common->Error( "ERROR: SDL_UnlockMutex failed\n" ); + } #endif } @@ -214,27 +215,26 @@ the potential for time wasting lock waits is very low Sys_WaitForEvent ================== */ -void Sys_WaitForEvent(int index) { - assert(index >= 0 && index < MAX_TRIGGER_EVENTS); - - Sys_EnterCriticalSection(CRITICAL_SECTION_SYS); +void Sys_WaitForEvent( int index ) { + assert( index >= 0 && index < MAX_TRIGGER_EVENTS ); + Sys_EnterCriticalSection( CRITICAL_SECTION_SYS ); + assert( !waiting[index] ); // WaitForEvent from multiple threads? that wouldn't be good - assert(!waiting[index]); // WaitForEvent from multiple threads? that wouldn't be good - if (signaled[index]) { + if ( signaled[index] ) { // emulate windows behaviour: signal has been raised already. clear and keep going signaled[index] = false; } else { waiting[index] = true; #if SDL_VERSION_ATLEAST(3, 0, 0) - SDL_CondWait(cond[index], mutex[CRITICAL_SECTION_SYS]); // in SDL3, this returns void and can't fail + SDL_CondWait( cond[index], mutex[CRITICAL_SECTION_SYS] ); // in SDL3, this returns void and can't fail #else // SDL2 and SDL1.2 - if (SDL_CondWait(cond[index], mutex[CRITICAL_SECTION_SYS]) != 0) - common->Error("ERROR: SDL_CondWait failed\n"); + if ( SDL_CondWait( cond[index], mutex[CRITICAL_SECTION_SYS] ) != 0 ) { + common->Error( "ERROR: SDL_CondWait failed\n" ); + } #endif waiting[index] = false; } - - Sys_LeaveCriticalSection(CRITICAL_SECTION_SYS); + Sys_LeaveCriticalSection( CRITICAL_SECTION_SYS ); } /* @@ -242,24 +242,24 @@ void Sys_WaitForEvent(int index) { Sys_TriggerEvent ================== */ -void Sys_TriggerEvent(int index) { - assert(index >= 0 && index < MAX_TRIGGER_EVENTS); +void Sys_TriggerEvent( int index ) { + assert( index >= 0 && index < MAX_TRIGGER_EVENTS ); - Sys_EnterCriticalSection(CRITICAL_SECTION_SYS); + Sys_EnterCriticalSection( CRITICAL_SECTION_SYS ); - if (waiting[index]) { + if ( waiting[index] ) { #if SDL_VERSION_ATLEAST(3, 0, 0) - SDL_CondSignal(cond[index]); // in SDL3, this returns void and can't fail + SDL_CondSignal( cond[index] ); // in SDL3, this returns void and can't fail #else // SDL2 and SDL1.2 - if (SDL_CondSignal(cond[index]) != 0) - common->Error("ERROR: SDL_CondSignal failed\n"); + if ( SDL_CondSignal( cond[index] ) != 0 ) { + common->Error( "ERROR: SDL_CondSignal failed\n" ); + } #endif } else { // emulate windows behaviour: if no thread is waiting, leave the signal on so next wait keeps going signaled[index] = true; } - - Sys_LeaveCriticalSection(CRITICAL_SECTION_SYS); + Sys_LeaveCriticalSection( CRITICAL_SECTION_SYS ); } /* @@ -267,30 +267,29 @@ void Sys_TriggerEvent(int index) { Sys_CreateThread ================== */ -void Sys_CreateThread(xthread_t function, void *parms, xthreadInfo& info, const char *name) { +void Sys_CreateThread( xthread_t function, void *parms, xthreadInfo &info, const char *name ) { Sys_EnterCriticalSection(); #if SDL_VERSION_ATLEAST(2, 0, 0) - SDL_Thread *t = SDL_CreateThread(function, name, parms); + SDL_Thread *t = SDL_CreateThread( function, name, parms ); #else - SDL_Thread *t = SDL_CreateThread(function, parms); + SDL_Thread *t = SDL_CreateThread( function, parms ); #endif - if (!t) { - common->Error("ERROR: SDL_thread for '%s' failed\n", name); + if ( !t ) { + common->Error( "ERROR: SDL_thread for '%s' failed\n", name ); Sys_LeaveCriticalSection(); return; } - info.name = name; info.threadHandle = t; - info.threadId = SDL_GetThreadID(t); + info.threadId = SDL_GetThreadID( t ); - if (thread_count < MAX_THREADS) + if ( thread_count < MAX_THREADS ) { thread[thread_count++] = &info; - else - common->DPrintf("WARNING: MAX_THREADS reached\n"); - + } else { + common->DPrintf( "WARNING: MAX_THREADS reached\n" ); + } Sys_LeaveCriticalSection(); } @@ -299,10 +298,10 @@ void Sys_CreateThread(xthread_t function, void *parms, xthreadInfo& info, const Sys_DestroyThread ================== */ -void Sys_DestroyThread(xthreadInfo& info) { - assert(info.threadHandle); +void Sys_DestroyThread( xthreadInfo &info ) { + assert( info.threadHandle ); - SDL_WaitThread(info.threadHandle, NULL); + SDL_WaitThread( info.threadHandle, NULL ); info.name = NULL; info.threadHandle = NULL; @@ -310,21 +309,20 @@ void Sys_DestroyThread(xthreadInfo& info) { Sys_EnterCriticalSection(); - for (int i = 0; i < thread_count; i++) { - if (&info == thread[i]) { + int i, j; + for ( i = 0; i < static_cast( thread_count ); i++ ) { + if ( &info == thread[i] ) { thread[i] = NULL; - int j; - for (j = i + 1; j < thread_count; j++) + for ( j = i + 1; j < static_cast( thread_count ); j++ ) { thread[j - 1] = thread[j]; - + } thread[j - 1] = NULL; thread_count--; break; } } - Sys_LeaveCriticalSection( ); } @@ -334,18 +332,18 @@ Sys_GetThreadName find the name of the calling thread ================== */ -const char *Sys_GetThreadName(int *index) { +const char *Sys_GetThreadName( int *index ) { const char *name; Sys_EnterCriticalSection(); SDL_threadID id = SDL_ThreadID(); - for (int i = 0; i < thread_count; i++) { - if (id == thread[i]->threadId) { - if (index) + for ( int i = 0; i < static_cast( thread_count ); i++ ) { + if ( id == thread[i]->threadId ) { + if ( index ) { *index = i; - + } name = thread[i]->name; Sys_LeaveCriticalSection(); @@ -354,9 +352,9 @@ const char *Sys_GetThreadName(int *index) { } } - if (index) + if ( index ) { *index = -1; - + } Sys_LeaveCriticalSection(); return "main"; @@ -370,8 +368,10 @@ returns true if the current thread is the main thread ================== */ bool Sys_IsMainThread() { - if ( mainThreadIDset ) + if ( mainThreadIDset ) { return SDL_ThreadID() == mainThreadID; + } + // if this is called before mainThreadID is set, we haven't created // any threads yet so it should be the main thread return true;