/* Copyright (c) Mark J. Kilgard, 1999. */ /* This program is freely distributable without licensing fees and is provided without guarantee or warrantee expressed or implied. This program is -not- in the public domain. */ /* nvshadow.c - this example demonstrates stenciled shadow volume shadows, shadow volume visualization, soft shadows through stenciled shadow volumes, planar projected shadows, and a hybrid combination of shadow volumes and planar projected shadows. Graphics hardware with a hardware stencil is DEFINITELY NEEDED for good performance. Try it in 32-bit mode on your RIVA TNT! */ #include #include #include #include #include #include /* Some files do not define M_PI... */ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #ifndef _WIN32 #define CALLBACK /* compensate for Microsoft's stupidity */ #endif /* This "fastTeapot" routine is faster than glutSolidTeapot. */ static void fastTeapot(GLint grid, GLdouble scale); /* 2D points for the complex polygons making up the NVIDIA logo. */ GLdouble nvlogo0[][3] = { { -0.474465, -1.259490, 0 }, { 0.115919, -1.113297, 0 }, { 0.588227, -0.899634, 0 }, { 0.942455, -0.652235, 0 }, { 1.296687, -0.348609, 0 }, { 1.690275, -0.033738, 0 }, { 1.926431, 0.269888, 0 }, { 2.123226, 0.494796, 0 }, { 1.847713, 0.832160, 0 }, { 1.532842, 1.124540, 0 }, { 1.178611, 1.394430, 0 }, { 0.706303, 1.709300, 0 }, { 0.076562, 1.967940, 0 }, { -0.395747, 2.080400, 0 }, { -1.064784, 2.058940, 0 }, { -1.064847, 2.811350, 0 }, { 3.973113, 2.811350, 0 }, { 3.973113, -2.811350, 0 }, { -1.025490, -2.811350, 0 }, { -1.025490, -2.159120, 0 }, { -0.474465, -2.159120, 0 }, { 0.155277, -2.102890, 0 }, { 0.706303, -1.979190, 0 }, { 1.178611, -1.833000, 0 }, { 1.690275, -1.653080, 0 }, { 2.201941, -1.450660, 0 }, { 2.674248, -1.214510, 0 }, { 3.107212, -0.955861, 0 }, { 3.343357, -0.719707, 0 }, { 2.438097, -0.179928, 0 }, { 2.005147, -0.517290, 0 }, { 1.690275, -0.820916, 0 }, { 1.296687, -1.079560, 0 }, { 0.863740, -1.338200, 0 }, { 0.273356, -1.585600, 0 }, { -0.198952, -1.709300, 0 }, { -1.025490, -1.731790, 0 }, { -1.025490, -1.248240, 0 }, }; GLdouble nvlogo1[][3] = { { -0.493508, 0.560265, 0 }, { -0.233835, 0.218981, 0 }, { -0.078033, -0.107463, 0 }, { 0.545180, 0.441557, 0 }, { 0.285509, 0.753164, 0 }, { -0.129966, 1.005420, 0 }, { -0.545442, 1.153800, 0 }, { -1.034999, 1.167860, 0 }, { -1.064784, 1.658310, 0 }, { -0.233835, 1.598950, 0 }, { 0.233576, 1.361540, 0 }, { 0.649050, 1.094450, 0 }, { 1.012591, 0.753164, 0 }, { 1.324197, 0.426719, 0 }, { 1.064524, 0.189305, 0 }, { 0.804852, -0.166817, 0 }, { 0.389378, -0.508100, 0 }, { -0.078033, -0.745515, 0 }, { -0.441573, -0.879060, 0 }, { -1.013530, -0.889070, 0 }, { -1.012851, 0.723487, 0 }, }; GLdouble nvlogo2[][3] = { { -1.025490, -2.159120, 0 }, { -1.843800, -1.962260, 0 }, { -2.415081, -1.635820, 0 }, { -2.934425, -1.205510, 0 }, { -3.297966, -0.760353, 0 }, { -3.609571, -0.315201, 0 }, { -3.869244, 0.204143, 0 }, { -3.973113, 0.545426, 0 }, { -3.505702, 0.960900, 0 }, { -2.830556, 1.435730, 0 }, { -2.051539, 1.851210, 0 }, { -1.064784, 2.058940, 0 }, { -1.064784, 1.658310, 0 }, { -1.791868, 1.495080, 0 }, { -2.363145, 1.183480, 0 }, { -2.830556, 0.842190, 0 }, { -3.194097, 0.471234, 0 }, { -3.090228, 0.055759, 0 }, { -2.830556, -0.315201, 0 }, { -2.570884, -0.760353, 0 }, { -2.103473, -1.220340, 0 }, { -1.584129, -1.531950, 0 }, { -1.025490, -1.731790, 0 }, }; GLdouble nvlogo3[][3] = { { -1.025490, -1.248240, 0 }, { -1.472016, -1.099371, 0 }, { -1.794030, -0.875934, 0 }, { -2.047038, -0.606495, 0 }, { -2.254046, -0.337056, 0 }, { -2.415053, -0.047902, 0 }, { -2.530060, 0.260968, 0 }, { -2.392054, 0.536978, 0 }, { -2.047038, 0.806418, 0 }, { -1.633023, 1.016710, 0 }, { -1.034999, 1.167860, 0 }, { -1.012851, 0.723487, 0 }, { -1.380012, 0.681555, 0 }, { -1.610022, 0.530407, 0 }, { -1.863033, 0.326685, 0 }, { -1.909033, 0.076960, 0 }, { -1.748027, -0.159620, 0 }, { -1.541019, -0.448774, 0 }, { -1.311010, -0.685355, 0 }, { -1.013530, -0.889070, 0 }, }; GLdouble base[][3] = { { -5, -5, 0 }, { -5, 5, 0 }, { 5, 5, 0 }, { 5, -5, 0 } }; #define SIZE(a) (sizeof(a)/sizeof(a[0])) enum { DL_BOGUS = 0, DL_CUT_OUT, DL_CUT_OUT_VOLUME, DL_TEAPOT, DL_SPHERE }; enum { M_ANIMATE, M_VOLUME_SHADOWS, M_SOFT_SHADOWS, M_NO_SHADOWS, M_SHADOW_VOLUME, M_PLANAR_SHADOWS, M_HYBRID_SHADOWS, M_BENCHMARK }; enum { X, Y, Z, W /* Used to make code involving coordinates more readable. */ }; int doubleBuffer = 1; int useTextures = 1; int forceStencilHack = 0; int fullscreen = 0, smallFullscreen = 0; int moving = 0, beginx, beginy; int windowWidth, windowHeight; int teapotAngle = 0; float time1 = 0.0; float time2 = 0.0; int animate = 0; int animateMode = 1; int logoAngle = 0; int oneFrame = 0; int displayMode = M_HYBRID_SHADOWS; int numLightSamples = 4; int useMipmaps = 1; int linearFiltering = 1; GLUtesselator *tess; double L[4] = { 3,4,2, 1 }; /* Light location. */ double O[3] = { 3,2,2 }; /* Cut-out origin. */ double M[3], N[3]; /* Vectors to orient the cut-out. */ double Pbg[4]; /* Plane below the true ground plane. */ double Pg[4]; /* Plane at the actual ground plane. */ /* Three vertices just below the ground plane. */ double Sbg[3] = { 0, -1.5, 0 }; double Tbg[3] = { 0, -1.5, 1 }; double Rbg[3] = { 1, -1.5, 0 }; /* Three vertices on the ground plane. */ double Sg[3] = { 0, -1, 0 }; double Tg[3] = { 0, -1, 1 }; double Rg[3] = { 1, -1, 0 }; /* Nice floor texture tiling pattern. */ static char *circles[] = { "....xxxx........", "..xxxxxxxx......", ".xxxxxxxxxx.....", ".xxx....xxx.....", "xxx......xxx....", "xxx......xxx....", "xxx......xxx....", "xxx......xxx....", ".xxx....xxx.....", ".xxxxxxxxxx.....", "..xxxxxxxx......", "....xxxx........", "................", "................", "................", "................", }; static void makeFloorTexture(void) { GLubyte floorTexture[16][16][3]; GLubyte *loc; int s, t; /* Setup RGB image for the texture. */ loc = (GLubyte*) floorTexture; for (t = 0; t < 16; t++) { for (s = 0; s < 16; s++) { if (circles[t][s] == 'x') { /* Nice green. */ loc[0] = 0x1f; loc[1] = 0x8f; loc[2] = 0x1f; } else { /* Light gray. */ loc[0] = 0xaa; loc[1] = 0xaa; loc[2] = 0xaa; } loc += 3; } } glPixelStorei(GL_UNPACK_ALIGNMENT, 1); if (useMipmaps) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 16, 16, GL_RGB, GL_UNSIGNED_BYTE, floorTexture); } else { if (linearFiltering) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } glTexImage2D(GL_TEXTURE_2D, 0, 3, 16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, floorTexture); } } /* Create a matrix that will project the desired shadow. */ void shadowMatrix(GLfloat shadowMat[4][4], GLdouble groundplane[4], GLfloat lightpos[4]) { GLfloat dot; /* Find dot product between light position vector and ground plane normal. */ dot = groundplane[X] * lightpos[X] + groundplane[Y] * lightpos[Y] + groundplane[Z] * lightpos[Z] + groundplane[W] * lightpos[W]; shadowMat[0][0] = dot - lightpos[X] * groundplane[X]; shadowMat[1][0] = 0.f - lightpos[X] * groundplane[Y]; shadowMat[2][0] = 0.f - lightpos[X] * groundplane[Z]; shadowMat[3][0] = 0.f - lightpos[X] * groundplane[W]; shadowMat[X][1] = 0.f - lightpos[Y] * groundplane[X]; shadowMat[1][1] = dot - lightpos[Y] * groundplane[Y]; shadowMat[2][1] = 0.f - lightpos[Y] * groundplane[Z]; shadowMat[3][1] = 0.f - lightpos[Y] * groundplane[W]; shadowMat[X][2] = 0.f - lightpos[Z] * groundplane[X]; shadowMat[1][2] = 0.f - lightpos[Z] * groundplane[Y]; shadowMat[2][2] = dot - lightpos[Z] * groundplane[Z]; shadowMat[3][2] = 0.f - lightpos[Z] * groundplane[W]; shadowMat[X][3] = 0.f - lightpos[W] * groundplane[X]; shadowMat[1][3] = 0.f - lightpos[W] * groundplane[Y]; shadowMat[2][3] = 0.f - lightpos[W] * groundplane[Z]; shadowMat[3][3] = dot - lightpos[W] * groundplane[W]; } /* x86 generates tighter double-precision code. */ typedef GLdouble FPvalue; #define constructShadowVolumeMatrix constructShadowVolumeMatrixd #if ( _MSC_VER >= 800 ) /* Assume no aliasing in the constructShadowVolumeMatrix. */ # pragma optimize("a", on) /* Visual C++ 5.0 does poor common subexpression folding. Define to ENABLE common expression folding. */ # define CEF #endif /* PERFORMANCE RESULTS on 350 Mhz Pentium II "/Ox -DCEF" -- 160,500 calls/sec "/O1 -DCEF" -- 124,000 calls/sec "/Ox " -- 109,500 calls/sec "/O1 " -- 76,000 calls/sec */ /* Construct a shadow volume matrix. The code below was generated by Maple. The code implements an inlined 15x15 matrix inverse for the special case we are interested in. No guarantees if this code is numerically stable, but it is good enough for nvshadow and pretty fast. Consult the "Reconstruction" chapter of Michael Penna and Richard Patterson's book _Projective Geometry and its Applications to Computer Graphics_ (Prentice-Hall, 1986) for more details. */ void constructShadowVolumeMatrix(FPvalue P[5][3], FPvalue M[4][4]) { #ifndef CEF /* Common sub-expressions NOT folded together via temporary variables (except for "r"). */ FPvalue r; const FPvalue two = (FPvalue) 2.0; const FPvalue three = (FPvalue) 3.0; assert( (((char*)M) < ((char*)P)) || (((char*)M) >= (((char*)P)+sizeof(P))) ); assert( (((char*)P) < ((char*)M)) || (((char*)P) >= (((char*)M)+sizeof(M))) ); r = 1/(-P[4][2]*P[1][1]*P[2][0]+P[2][0]*P[1][1]*P[3][2]+P[4][1]*P[1][2]*P[2][0]-P[2][0]* P[3][1]*P[1][2]-P[2][0]*P[4][1]*P[3][2]+P[2][0]*P[3][1]*P[4][2]+P[2][2]*P[1][1]*P[4][0]+P[1][1]*P[4][2]*P[3][0]-P[1][1]*P[2][2]*P[3][0]-P[1][1]*P[3][2]*P[4][0]+P[2][1]*P[4][0]*P[3][2]+P[4][1]*P[1][0]*P[3][2]+ P[2][1]*P[3][0]*P[1][2]+P[4][2]*P[2][1]*P[1][0]+P[3][1]*P[1][2]*P[4][0]+P[4][1]*P[2][2]*P[3][0]-P[2][2]*P[4][1]*P[1][0]-P[4][1]*P[3][0]*P[1][2]-P[3][1]*P[2][2]*P[4][0]+P[3][1]*P[2][2]*P[1][0]-P[2][1]*P[1][0]* P[3][2]-P[3][1]*P[4][2]*P[1][0]-P[2][1]*P[3][0]*P[4][2]-P[2][1]*P[1][2]*P[4][0]); M[0][0] = (-two*P[0][2]*P[2][0]*P[1][1]*P[3][0]+two*P[0][2]*P[2][0]*P[1][1]*P[4][0]-two*P[0][2]*P[2][0]*P[4][1]*P[1][0]-two*P[0][2]*P[2][0]*P[3][1]* P[4][0]+two*P[0][2]*P[2][0]*P[3][1]*P[1][0]+two*P[0][2]*P[2][0]*P[4][1]*P[3][0]-two*P[0][1]*P[2][0]*P[1][2]*P[4][0]+two*P[0][1]*P[2][0]*P[1][2]*P[3][0]-two*P[0][1]*P[2][0]*P[3][2] *P[1][0]+two*P[0][1]*P[2][0]*P[4][2]*P[1][0]+two*P[0][1]*P[2][0]*P[3][2]*P[4][0]-two*P[0][1]*P[2][0]*P[4][2]*P[3][0]+two*P[2][0]*P[3][1]*P[1][2]*P[4][0]-two*P[2][0]*P[4][1]* P[3][0]*P[1][2]-two*P[2][0]*P[1][1]*P[3][2]*P[4][0]+two*P[2][0]*P[1][1]*P[4][2]*P[3][0]+P[0][0]*P[2][1]*P[1][0]*P[3][2]+P[0][0]*P[3][1]*P[4][2]*P[1][0]+P[0][0]*P[2][1]*P[3][0]*P[4][2]+P[0][0]*P[2][1] *P[1][2]*P[4][0]+two*P[1][0]*P[2][0]*P[4][1]*P[3][2]-two*P[1][0]*P[2][0]*P[3][1]*P[4][2]+P[0][0]*P[4][1]*P[3][0]*P[1][2]+P[0][0]*P[3][1]*P[2][2]*P[4][0]-P[0][0]*P[3][1]*P[2][2]*P[1][0]-P[0][0]* P[2][0]*P[3][1]*P[1][2]-P[0][0]*P[2][0]*P[4][1]*P[3][2]+P[0][0]*P[2][0]*P[3][1]*P[4][2]-P[0][0]*P[2][2]*P[1][1]*P[4][0]-P[0][0]*P[1][1]*P[4][2]*P[3][0]+P[0][0]*P[1][1]*P[2][2]*P[3][0]+P[0][0]*P[1][1]*P[3][2]* P[4][0]-P[0][0]*P[2][1]*P[4][0]*P[3][2]-P[0][0]*P[4][1]*P[1][0]*P[3][2]-P[0][0]*P[2][1]*P[3][0]*P[1][2]-P[0][0]*P[4][2]*P[2][1]*P[1][0]-P[0][0]*P[3][1]*P[1][2]*P[4][0]-P[0][0]*P[4][1]*P[2][2]*P[3][0]+P[0][0]* P[2][2]*P[4][1]*P[1][0]-P[0][0]*P[4][2]*P[1][1]*P[2][0]+P[0][0]*P[2][0]*P[1][1]*P[3][2]+P[0][0]*P[4][1]*P[1][2]*P[2][0])*r; M[0][1] = -(-two*P[2][1]*P[1][0]*P[4][1]*P[3][2]+P[0][1]*P[2][1]*P[1][0]*P[3][2]-P[0][1]*P[3][1]*P[4][2]*P[1][0]+P[0][1]*P[2][1]*P[3][0]*P[4][2]+P[0][1]*P[2][1]*P[1][2] *P[4][0]+P[0][1]*P[4][1]*P[2][2]*P[3][0]-P[0][1]*P[4][1]*P[3][0]*P[1][2]-P[0][1]*P[3][1]*P[2][2]*P[4][0]+P[0][1]*P[3][1]*P[2][2]*P[1][0]-P[0][1]*P[2][2]*P[4][1]*P[1][0]-P[0][1]*P[2][1]*P[4][0]*P[3][2]+P[0][1]* P[4][1]*P[1][0]*P[3][2]-P[0][1]*P[2][1]*P[3][0]*P[1][2]-P[0][1]*P[4][2]*P[2][1]*P[1][0]+P[0][1]*P[3][1]*P[1][2]*P[4][0]+P[0][1]*P[2][0]*P[3][1]*P[4][2]+P[0][1]*P[2][2]*P[1][1]*P[4][0]+P[0][1]*P[1][1]*P[4][2]* P[3][0]-P[0][1]*P[1][1]*P[2][2]*P[3][0]-P[0][1]*P[1][1]*P[3][2]*P[4][0]+P[0][1]*P[2][0]*P[1][1]*P[3][2]+P[0][1]*P[4][1]*P[1][2]*P[2][0]-P[0][1]*P[2][0]*P[3][1]*P[1][2]-P[0][1]*P[2][0]*P[4][1]*P[3][2]-P[0][1]* P[4][2]*P[1][1]*P[2][0]-two*P[2][1]*P[4][0]*P[3][1]*P[1][2]+two*P[0][0]*P[2][1]*P[4][2]*P[1][1]+two*P[2][1]*P[4][0]*P[3][2]*P[1][1]+two*P[2][1]*P[3][0]*P[4][1]*P[1][2]+two*P[0][0] *P[2][1]*P[4][1]*P[3][2]-two*P[2][1]*P[3][0]*P[4][2]*P[1][1]+two*P[0][2]*P[2][1]*P[4][1]*P[1][0]+two*P[0][2]*P[2][1]*P[3][1]*P[4][0]-two*P[0][2]*P[2][1]*P[4][1]*P[3][0]+two* P[0][2]*P[2][1]*P[1][1]*P[3][0]-two*P[0][2]*P[2][1]*P[3][1]*P[1][0]-two*P[0][2]*P[2][1]*P[1][1]*P[4][0]+two*P[2][1]*P[1][0]*P[3][1]*P[4][2]-two*P[0][0]*P[2][1]*P[3][2]*P[1][1]-two *P[0][0]*P[2][1]*P[4][1]*P[1][2]+two*P[0][0]*P[2][1]*P[3][1]*P[1][2]-two*P[0][0]*P[2][1]*P[3][1]*P[4][2])*r; M[0][2] = -(P[0][2]*P[2][2]*P[4][1]*P[1][0]-P[0][2]*P[4][1]*P[3][0]*P[1][2]+P[0][2]*P[3][1]*P[2][2]*P[4][0]-P[0][2]*P[3][1]*P[2][2]*P[1][0]-P[0][2]*P[2][1]*P[1][0]*P[3][2]- P[0][2]*P[3][1]*P[4][2]*P[1][0]-P[0][2]*P[2][1]*P[3][0]*P[4][2]-P[0][2]*P[2][1]*P[1][2]*P[4][0]-P[0][2]*P[2][0]*P[4][1]*P[3][2]+P[0][2]*P[2][0]*P[3][1]*P[4][2]-P[0][2]*P[2][2]*P[1][1]*P[4][0]+P[0][2]*P[1][1]* P[4][2]*P[3][0]+P[0][2]*P[1][1]*P[2][2]*P[3][0]-P[0][2]*P[1][1]*P[3][2]*P[4][0]+P[0][2]*P[2][1]*P[4][0]*P[3][2]+P[0][2]*P[4][1]*P[1][0]*P[3][2]+P[0][2]*P[2][1]*P[3][0]*P[1][2]+P[0][2]*P[4][2]*P[2][1]*P[1][0]+ P[0][2]*P[3][1]*P[1][2]*P[4][0]-P[0][2]*P[4][1]*P[2][2]*P[3][0]-P[0][2]*P[4][2]*P[1][1]*P[2][0]+P[0][2]*P[2][0]*P[1][1]*P[3][2]+P[0][2]*P[4][1]*P[1][2]*P[2][0]-P[0][2]*P[2][0]*P[3][1]*P[1][2]+two*P[0][1]* P[3][2]*P[2][2]*P[1][0]+two*P[3][2]*P[4][0]*P[2][2]*P[1][1]-two*P[0][1]*P[3][2]*P[2][2]*P[4][0]+two*P[0][0]*P[3][2]*P[2][2]*P[4][1]-two*P[3][2]*P[1][0]*P[2][2]*P[4][1]-two*P[0][0] *P[3][2]*P[2][2]*P[1][1]-two*P[0][1]*P[2][2]*P[4][2]*P[1][0]+two*P[0][1]*P[2][2]*P[4][2]*P[3][0]+two*P[0][1]*P[2][2]*P[1][2]*P[4][0]-two*P[2][2]*P[3][0]*P[4][2]*P[1][1]+two* P[2][2]*P[3][0]*P[4][1]*P[1][2]-two*P[2][2]*P[4][0]*P[3][1]*P[1][2]-two*P[0][1]*P[2][2]*P[1][2]*P[3][0]+two*P[0][0]*P[2][2]*P[4][2]*P[1][1]-two*P[0][0]*P[2][2]*P[4][1]*P[1][2]+two *P[0][0]*P[2][2]*P[3][1]*P[1][2]-two*P[0][0]*P[2][2]*P[3][1]*P[4][2]+two*P[2][2]*P[1][0]*P[3][1]*P[4][2])*r; M[0][3] = -(two*P[0][0]*P[4][2]*P[1][1]-two*P[0][0]*P[4][1]*P[1][2]+two*P[0][1]*P[1][2]*P[4][0]-two*P[0][1]*P[4][2]*P[1][0]-two*P[0][2]*P[1][1] *P[4][0]+two*P[0][2]*P[4][1]*P[1][0]+two*P[0][0]*P[3][2]*P[4][1]-two*P[0][1]*P[3][2]*P[4][0]-two*P[0][2]*P[4][1]*P[3][0]+two*P[0][2]*P[3][1]*P[4][0]-two*P[0][0]*P[3][2]* P[1][1]+two*P[0][2]*P[1][1]*P[3][0]+two*P[0][1]*P[3][2]*P[1][0]-two*P[0][2]*P[3][1]*P[1][0]-P[2][2]*P[4][1]*P[1][0]+P[2][2]*P[1][1]*P[4][0]-P[4][2]*P[1][1]*P[2][0]+P[4][2]*P[2][1]*P[1][0] -two*P[0][1]*P[1][2]*P[3][0]+two*P[0][1]*P[4][2]*P[3][0]-two*P[0][0]*P[3][1]*P[4][2]+two*P[0][0]*P[3][1]*P[1][2]+P[4][1]*P[1][2]*P[2][0]-P[2][1]*P[1][2]*P[4][0]-P[3][1]*P[1][2]*P[4][0] +P[4][1]*P[3][0]*P[1][2]+P[2][1]*P[3][0]*P[1][2]-P[2][0]*P[3][1]*P[1][2]+P[4][1]*P[2][2]*P[3][0]-P[1][1]*P[2][2]*P[3][0]-P[3][1]*P[2][2]*P[4][0]+P[3][1]*P[2][2]*P[1][0]+P[1][1]*P[3][2]*P[4][0]-P[2][1]*P[1][0]* P[3][2]-P[4][1]*P[1][0]*P[3][2]+P[2][1]*P[4][0]*P[3][2]+P[2][0]*P[1][1]*P[3][2]-P[2][0]*P[4][1]*P[3][2]-P[1][1]*P[4][2]*P[3][0]+P[3][1]*P[4][2]*P[1][0]-P[2][1]*P[3][0]*P[4][2]+P[2][0]*P[3][1]*P[4][2])*r; M[1][0] = (-two*P[1][0]*P[3][1]*P[2][2]*P[4][0]-two*P[0][1]*P[1][0]*P[2][2]*P[3][0]-two*P[0][1]*P[1][0]*P[3][2]*P[4][0]-two*P[0][2]*P[1][0]*P[4][1]* P[3][0]-two*P[0][2]*P[1][0]*P[2][1]*P[4][0]+two*P[0][2]*P[1][0]*P[2][1]*P[3][0]+two*P[0][2]*P[1][0]*P[3][1]*P[4][0]+two*P[1][0]*P[2][1]*P[4][0]*P[3][2]-two*P[1][0]*P[2][1]*P[3][0] *P[4][2]+two*P[1][0]*P[4][1]*P[2][2]*P[3][0]+two*P[0][1]*P[1][0]*P[2][2]*P[4][0]+two*P[0][1]*P[1][0]*P[4][2]*P[3][0]+two*P[0][2]*P[2][0]*P[4][1]*P[1][0]-two*P[0][2]*P[2][0]* P[3][1]*P[1][0]+two*P[0][1]*P[2][0]*P[3][2]*P[1][0]-two*P[0][1]*P[2][0]*P[4][2]*P[1][0]-P[0][0]*P[2][1]*P[1][0]*P[3][2]-P[0][0]*P[3][1]*P[4][2]*P[1][0]+P[0][0]*P[2][1]*P[3][0]*P[4][2]+P[0][0]*P[2][1] *P[1][2]*P[4][0]-two*P[1][0]*P[2][0]*P[4][1]*P[3][2]+two*P[1][0]*P[2][0]*P[3][1]*P[4][2]+P[0][0]*P[4][1]*P[3][0]*P[1][2]+P[0][0]*P[3][1]*P[2][2]*P[4][0]+P[0][0]*P[3][1]*P[2][2]*P[1][0]+P[0][0]* P[2][0]*P[3][1]*P[1][2]+P[0][0]*P[2][0]*P[4][1]*P[3][2]-P[0][0]*P[2][0]*P[3][1]*P[4][2]-P[0][0]*P[2][2]*P[1][1]*P[4][0]-P[0][0]*P[1][1]*P[4][2]*P[3][0]+P[0][0]*P[1][1]*P[2][2]*P[3][0]+P[0][0]*P[1][1]*P[3][2]* P[4][0]-P[0][0]*P[2][1]*P[4][0]*P[3][2]+P[0][0]*P[4][1]*P[1][0]*P[3][2]-P[0][0]*P[2][1]*P[3][0]*P[1][2]+P[0][0]*P[4][2]*P[2][1]*P[1][0]-P[0][0]*P[3][1]*P[1][2]*P[4][0]-P[0][0]*P[4][1]*P[2][2]*P[3][0]-P[0][0]* P[2][2]*P[4][1]*P[1][0]+P[0][0]*P[4][2]*P[1][1]*P[2][0]-P[0][0]*P[2][0]*P[1][1]*P[3][2]-P[0][0]*P[4][1]*P[1][2]*P[2][0])*r; M[1][1] = (P[0][1]*P[2][1]*P[1][0]*P[3][2]+P[0][1]*P[3][1]*P[4][2]*P[1][0]+P[0][1]*P[2][1]*P[3][0]*P[4][2]+P[0][1]*P[2][1]*P[1][2]*P[4][0]-P[0][1]*P[4][1]*P[2][2]*P[3][0]+P[0][1] *P[4][1]*P[3][0]*P[1][2]+P[0][1]*P[3][1]*P[2][2]*P[4][0]-P[0][1]*P[3][1]*P[2][2]*P[1][0]+P[0][1]*P[2][2]*P[4][1]*P[1][0]-P[0][1]*P[2][1]*P[4][0]*P[3][2]-P[0][1]*P[4][1]*P[1][0]*P[3][2]-P[0][1]*P[2][1]*P[3][0]* P[1][2]-P[0][1]*P[4][2]*P[2][1]*P[1][0]-P[0][1]*P[3][1]*P[1][2]*P[4][0]-P[0][1]*P[2][0]*P[3][1]*P[4][2]+P[0][1]*P[2][2]*P[1][1]*P[4][0]+P[0][1]*P[1][1]*P[4][2]*P[3][0]-P[0][1]*P[1][1]*P[2][2]*P[3][0]-P[0][1]* P[1][1]*P[3][2]*P[4][0]+P[0][1]*P[2][0]*P[1][1]*P[3][2]-P[0][1]*P[4][1]*P[1][2]*P[2][0]+P[0][1]*P[2][0]*P[3][1]*P[1][2]+P[0][1]*P[2][0]*P[4][1]*P[3][2]-P[0][1]*P[4][2]*P[1][1]*P[2][0]+two*P[0][0]*P[2][1]* P[4][2]*P[1][1]+two*P[2][1]*P[4][0]*P[3][2]*P[1][1]-two*P[2][1]*P[3][0]*P[4][2]*P[1][1]+two*P[0][2]*P[2][1]*P[1][1]*P[3][0]-two*P[0][2]*P[2][1]*P[1][1]*P[4][0]-two*P[0][0]*P[2][1] *P[3][2]*P[1][1]+two*P[0][2]*P[1][1]*P[4][1]*P[2][0]-two*P[0][2]*P[1][1]*P[3][1]*P[2][0]-two*P[0][2]*P[1][1]*P[4][1]*P[3][0]+two*P[0][2]*P[1][1]*P[3][1]*P[4][0]-two*P[1][1]* P[4][0]*P[2][2]*P[3][1]+two*P[1][1]*P[3][0]*P[2][2]*P[4][1]-two*P[1][1]*P[2][0]*P[4][1]*P[3][2]+two*P[1][1]*P[2][0]*P[3][1]*P[4][2]-two*P[0][0]*P[1][1]*P[3][1]*P[4][2]-two*P[0][0] *P[1][1]*P[2][2]*P[4][1]+two*P[0][0]*P[1][1]*P[2][2]*P[3][1]+two*P[0][0]*P[1][1]*P[4][1]*P[3][2])*r; M[1][2] = (P[0][2]*P[2][2]*P[4][1]*P[1][0]-P[0][2]*P[4][1]*P[3][0]*P[1][2]+P[0][2]*P[3][1]*P[2][2]*P[4][0]-P[0][2]*P[3][1]*P[2][2]*P[1][0]+P[0][2]*P[2][1]*P[1][0]*P[3][2]+P[0][2] *P[3][1]*P[4][2]*P[1][0]+P[0][2]*P[2][1]*P[3][0]*P[4][2]-P[0][2]*P[2][1]*P[1][2]*P[4][0]+P[0][2]*P[2][0]*P[4][1]*P[3][2]-P[0][2]*P[2][0]*P[3][1]*P[4][2]-P[0][2]*P[2][2]*P[1][1]*P[4][0]-P[0][2]*P[1][1]*P[4][2]* P[3][0]+P[0][2]*P[1][1]*P[2][2]*P[3][0]+P[0][2]*P[1][1]*P[3][2]*P[4][0]-P[0][2]*P[2][1]*P[4][0]*P[3][2]-P[0][2]*P[4][1]*P[1][0]*P[3][2]+P[0][2]*P[2][1]*P[3][0]*P[1][2]-P[0][2]*P[4][2]*P[2][1]*P[1][0]+P[0][2]* P[3][1]*P[1][2]*P[4][0]-P[0][2]*P[4][1]*P[2][2]*P[3][0]+P[0][2]*P[4][2]*P[1][1]*P[2][0]-P[0][2]*P[2][0]*P[1][1]*P[3][2]+P[0][2]*P[4][1]*P[1][2]*P[2][0]-P[0][2]*P[2][0]*P[3][1]*P[1][2]-two*P[0][1]*P[3][2]* P[1][2]*P[4][0]+two*P[3][2]*P[4][0]*P[2][1]*P[1][2]+two*P[0][1]*P[3][2]*P[1][2]*P[2][0]-two*P[2][0]*P[3][2]*P[4][1]*P[1][2]-two*P[0][0]*P[3][2]*P[2][1]*P[1][2]+two*P[0][0]*P[3][2] *P[4][1]*P[1][2]+two*P[0][1]*P[2][2]*P[1][2]*P[4][0]+two*P[2][2]*P[3][0]*P[4][1]*P[1][2]-two*P[2][2]*P[4][0]*P[3][1]*P[1][2]-two*P[0][1]*P[2][2]*P[1][2]*P[3][0]-two*P[0][0]* P[2][2]*P[4][1]*P[1][2]+two*P[0][0]*P[2][2]*P[3][1]*P[1][2]-two*P[0][1]*P[1][2]*P[4][2]*P[2][0]+two*P[0][1]*P[1][2]*P[4][2]*P[3][0]-two*P[0][0]*P[1][2]*P[3][1]*P[4][2]+two*P[0][0] *P[1][2]*P[2][1]*P[4][2]+two*P[1][2]*P[2][0]*P[3][1]*P[4][2]-two*P[1][2]*P[3][0]*P[2][1]*P[4][2])*r; M[1][3] = (two*P[0][0]*P[2][1]*P[4][2]-two*P[0][0]*P[2][2]*P[4][1]-two*P[0][1]*P[4][2]*P[2][0]+two*P[0][1]*P[2][2]*P[4][0]+two*P[0][0]*P[3][2]* P[4][1]+two*P[0][2]*P[4][1]*P[2][0]-two*P[0][1]*P[3][2]*P[4][0]-two*P[0][2]*P[4][1]*P[3][0]-two*P[0][2]*P[2][1]*P[4][0]+two*P[0][2]*P[3][1]*P[4][0]+two*P[0][1]*P[3][2]* P[2][0]-two*P[0][0]*P[3][2]*P[2][1]+two*P[0][2]*P[2][1]*P[3][0]-two*P[0][2]*P[2][0]*P[3][1]-two*P[0][1]*P[2][2]*P[3][0]+P[2][2]*P[4][1]*P[1][0]-P[2][2]*P[1][1]*P[4][0]+P[4][2]*P[1][1]* P[2][0]-P[4][2]*P[2][1]*P[1][0]+two*P[0][0]*P[3][1]*P[2][2]+two*P[0][1]*P[4][2]*P[3][0]-two*P[0][0]*P[3][1]*P[4][2]-P[4][1]*P[1][2]*P[2][0]+P[2][1]*P[1][2]*P[4][0]-P[3][1]*P[1][2]*P[4][0]+ P[4][1]*P[3][0]*P[1][2]-P[2][1]*P[3][0]*P[1][2]+P[2][0]*P[3][1]*P[1][2]+P[4][1]*P[2][2]*P[3][0]+P[1][1]*P[2][2]*P[3][0]-P[3][1]*P[2][2]*P[4][0]-P[3][1]*P[2][2]*P[1][0]+P[1][1]*P[3][2]*P[4][0]+P[2][1]*P[1][0]* P[3][2]-P[4][1]*P[1][0]*P[3][2]+P[2][1]*P[4][0]*P[3][2]-P[2][0]*P[1][1]*P[3][2]-P[2][0]*P[4][1]*P[3][2]-P[1][1]*P[4][2]*P[3][0]+P[3][1]*P[4][2]*P[1][0]-P[2][1]*P[3][0]*P[4][2]+P[2][0]*P[3][1]*P[4][2])*r; M[2][0] = (two*P[0][1]*P[3][0]*P[2][2]*P[4][0]+two*P[3][0]*P[2][1]*P[1][2]*P[4][0]-two*P[0][1]*P[3][0]*P[1][2]*P[4][0]+two*P[0][2]*P[3][0]*P[1][1]* P[4][0]-two*P[0][2]*P[3][0]*P[2][1]*P[4][0]-two*P[0][1]*P[1][0]*P[2][2]*P[3][0]-two*P[0][2]*P[1][0]*P[4][1]*P[3][0]+two*P[0][2]*P[1][0]*P[2][1]*P[3][0]-two*P[1][0]*P[2][1]*P[3][0] *P[4][2]+two*P[1][0]*P[4][1]*P[2][2]*P[3][0]+two*P[0][1]*P[1][0]*P[4][2]*P[3][0]-two*P[0][2]*P[2][0]*P[1][1]*P[3][0]+two*P[0][2]*P[2][0]*P[4][1]*P[3][0]+two*P[0][1]*P[2][0]* P[1][2]*P[3][0]-two*P[0][1]*P[2][0]*P[4][2]*P[3][0]-two*P[2][0]*P[4][1]*P[3][0]*P[1][2]+two*P[2][0]*P[1][1]*P[4][2]*P[3][0]+P[0][0]*P[2][1]*P[1][0]*P[3][2]+P[0][0]*P[3][1]*P[4][2]*P[1][0]+ three*P[0][0]*P[2][1]*P[3][0]*P[4][2]+P[0][0]*P[2][1]*P[1][2]*P[4][0]+three*P[0][0]*P[4][1]*P[3][0]*P[1][2]+P[0][0]*P[3][1]*P[2][2]*P[4][0]-P[0][0]*P[3][1]*P[2][2]*P[1][0]+P[0][0]*P[2][0]*P[3][1]*P[1][2] +P[0][0]*P[2][0]*P[4][1]*P[3][2]-P[0][0]*P[2][0]*P[3][1]*P[4][2]-P[0][0]*P[2][2]*P[1][1]*P[4][0]-three*P[0][0]*P[1][1]*P[4][2]*P[3][0]+three*P[0][0]*P[1][1]*P[2][2]*P[3][0]+P[0][0]*P[1][1]*P[3][2]* P[4][0]-P[0][0]*P[2][1]*P[4][0]*P[3][2]-P[0][0]*P[4][1]*P[1][0]*P[3][2]-three*P[0][0]*P[2][1]*P[3][0]*P[1][2]-P[0][0]*P[4][2]*P[2][1]*P[1][0]-P[0][0]*P[3][1]*P[1][2]*P[4][0]-three*P[0][0]*P[4][1]*P[2][2] *P[3][0]+P[0][0]*P[2][2]*P[4][1]*P[1][0]+P[0][0]*P[4][2]*P[1][1]*P[2][0]-P[0][0]*P[2][0]*P[1][1]*P[3][2]-P[0][0]*P[4][1]*P[1][2]*P[2][0]-two*P[3][0]*P[2][2]*P[1][1]*P[4][0])*r; M[2][1] = (P[0][1]*P[2][1]*P[1][0]*P[3][2]+three*P[0][1]*P[3][1]*P[4][2]*P[1][0]+P[0][1]*P[2][1]*P[3][0]*P[4][2]+P[0][1]*P[2][1]*P[1][2]*P[4][0]-P[0][1]*P[4][1]*P[2][2]* P[3][0]+P[0][1]*P[4][1]*P[3][0]*P[1][2]+three*P[0][1]*P[3][1]*P[2][2]*P[4][0]-three*P[0][1]*P[3][1]*P[2][2]*P[1][0]+P[0][1]*P[2][2]*P[4][1]*P[1][0]-P[0][1]*P[2][1]*P[4][0]*P[3][2]-P[0][1]*P[4][1]*P[1][0] *P[3][2]-P[0][1]*P[2][1]*P[3][0]*P[1][2]-P[0][1]*P[4][2]*P[2][1]*P[1][0]-three*P[0][1]*P[3][1]*P[1][2]*P[4][0]-three*P[0][1]*P[2][0]*P[3][1]*P[4][2]-P[0][1]*P[2][2]*P[1][1]*P[4][0]-P[0][1]*P[1][1]* P[4][2]*P[3][0]+P[0][1]*P[1][1]*P[2][2]*P[3][0]+P[0][1]*P[1][1]*P[3][2]*P[4][0]-P[0][1]*P[2][0]*P[1][1]*P[3][2]-P[0][1]*P[4][1]*P[1][2]*P[2][0]+three*P[0][1]*P[2][0]*P[3][1]*P[1][2]+P[0][1]*P[2][0]*P[4][1]* P[3][2]+P[0][1]*P[4][2]*P[1][1]*P[2][0]+two*P[2][1]*P[4][0]*P[3][1]*P[1][2]-two*P[0][2]*P[2][1]*P[3][1]*P[4][0]+two*P[0][2]*P[2][1]*P[3][1]*P[1][0]-two*P[2][1]*P[1][0]*P[3][1]*P[4][2] -two*P[0][0]*P[2][1]*P[3][1]*P[1][2]+two*P[0][0]*P[2][1]*P[3][1]*P[4][2]-two*P[0][2]*P[1][1]*P[3][1]*P[2][0]+two*P[0][2]*P[1][1]*P[3][1]*P[4][0]-two*P[1][1]*P[4][0]*P[2][2]* P[3][1]+two*P[1][1]*P[2][0]*P[3][1]*P[4][2]-two*P[0][0]*P[1][1]*P[3][1]*P[4][2]+two*P[0][0]*P[1][1]*P[2][2]*P[3][1]+two*P[0][2]*P[3][1]*P[4][1]*P[2][0]-two*P[0][2]*P[3][1]*P[4][1] *P[1][0]-two*P[3][1]*P[2][0]*P[4][1]*P[1][2]+two*P[3][1]*P[1][0]*P[2][2]*P[4][1]-two*P[0][0]*P[3][1]*P[2][2]*P[4][1]+two*P[0][0]*P[3][1]*P[4][1]*P[1][2])*r; M[2][2] = -(-P[0][2]*P[2][2]*P[4][1]*P[1][0]-P[0][2]*P[4][1]*P[3][0]*P[1][2]-P[0][2]*P[3][1]*P[2][2]*P[4][0]+P[0][2]*P[3][1]*P[2][2]*P[1][0]-three*P[0][2]*P[2][1]*P[1][0] *P[3][2]-P[0][2]*P[3][1]*P[4][2]*P[1][0]-P[0][2]*P[2][1]*P[3][0]*P[4][2]-P[0][2]*P[2][1]*P[1][2]*P[4][0]-three*P[0][2]*P[2][0]*P[4][1]*P[3][2]+P[0][2]*P[2][0]*P[3][1]*P[4][2]+P[0][2]*P[2][2]*P[1][1]*P[4][0] +P[0][2]*P[1][1]*P[4][2]*P[3][0]-P[0][2]*P[1][1]*P[2][2]*P[3][0]-three*P[0][2]*P[1][1]*P[3][2]*P[4][0]+three*P[0][2]*P[2][1]*P[4][0]*P[3][2]+three*P[0][2]*P[4][1]*P[1][0]*P[3][2]+P[0][2]*P[2][1]* P[3][0]*P[1][2]+P[0][2]*P[4][2]*P[2][1]*P[1][0]+P[0][2]*P[3][1]*P[1][2]*P[4][0]+P[0][2]*P[4][1]*P[2][2]*P[3][0]-P[0][2]*P[4][2]*P[1][1]*P[2][0]+three*P[0][2]*P[2][0]*P[1][1]*P[3][2]+P[0][2]*P[4][1]*P[1][2]* P[2][0]-P[0][2]*P[2][0]*P[3][1]*P[1][2]+two*P[0][1]*P[3][2]*P[2][2]*P[1][0]+two*P[0][1]*P[3][2]*P[1][2]*P[4][0]-two*P[0][1]*P[3][2]*P[4][2]*P[1][0]-two*P[3][2]*P[4][0]*P[2][1]*P[1][2]+ two*P[3][2]*P[4][0]*P[2][2]*P[1][1]-two*P[0][1]*P[3][2]*P[1][2]*P[2][0]+two*P[0][1]*P[3][2]*P[4][2]*P[2][0]-two*P[0][1]*P[3][2]*P[2][2]*P[4][0]+two*P[2][0]*P[3][2]*P[4][1]*P[1][2] +two*P[3][2]*P[1][0]*P[2][1]*P[4][2]-two*P[2][0]*P[3][2]*P[4][2]*P[1][1]+two*P[0][0]*P[3][2]*P[2][1]*P[1][2]-two*P[0][0]*P[3][2]*P[4][1]*P[1][2]+two*P[0][0]*P[3][2]*P[2][2]* P[4][1]-two*P[0][0]*P[3][2]*P[2][1]*P[4][2]-two*P[3][2]*P[1][0]*P[2][2]*P[4][1]-two*P[0][0]*P[3][2]*P[2][2]*P[1][1]+two*P[0][0]*P[3][2]*P[4][2]*P[1][1])*r; M[2][3] = -(-two*P[0][1]*P[2][0]*P[1][2]+two*P[0][2]*P[2][0]*P[1][1]-two*P[0][2]*P[1][0]*P[2][1]+two*P[0][1]*P[1][0]*P[2][2]+two*P[0][0]* P[2][1]*P[1][2]-two*P[0][0]*P[1][1]*P[2][2]+two*P[0][0]*P[4][2]*P[1][1]-two*P[0][0]*P[2][1]*P[4][2]-two*P[0][0]*P[4][1]*P[1][2]+two*P[0][0]*P[2][2]*P[4][1]+two*P[0][1]* P[1][2]*P[4][0]+two*P[0][1]*P[4][2]*P[2][0]-two*P[0][1]*P[2][2]*P[4][0]-two*P[0][1]*P[4][2]*P[1][0]-two*P[0][2]*P[1][1]*P[4][0]+two*P[0][2]*P[4][1]*P[1][0]-two*P[0][2]* P[4][1]*P[2][0]+two*P[0][2]*P[2][1]*P[4][0]-three*P[2][2]*P[4][1]*P[1][0]+three*P[2][2]*P[1][1]*P[4][0]-three*P[4][2]*P[1][1]*P[2][0]+three*P[4][2]*P[2][1]*P[1][0]+three*P[4][1]* P[1][2]*P[2][0]-three*P[2][1]*P[1][2]*P[4][0]+P[3][1]*P[1][2]*P[4][0]-P[4][1]*P[3][0]*P[1][2]+P[2][1]*P[3][0]*P[1][2]-P[2][0]*P[3][1]*P[1][2]+P[4][1]*P[2][2]*P[3][0]-P[1][1]*P[2][2]*P[3][0]-P[3][1]*P[2][2]* P[4][0]+P[3][1]*P[2][2]*P[1][0]-P[1][1]*P[3][2]*P[4][0]-P[2][1]*P[1][0]*P[3][2]+P[4][1]*P[1][0]*P[3][2]+P[2][1]*P[4][0]*P[3][2]+P[2][0]*P[1][1]*P[3][2]-P[2][0]*P[4][1]*P[3][2]+P[1][1]*P[4][2]*P[3][0]-P[3][1]* P[4][2]*P[1][0]-P[2][1]*P[3][0]*P[4][2]+P[2][0]*P[3][1]*P[4][2])*r; M[3][0] = P[0][0]; M[3][1] = P[0][1]; M[3][2] = P[0][2]; M[3][3] = 1.0; #else /* Agressive common sub-expressions folding via temporary variables. */ FPvalue t1, t2, t3, t4, t5, t6, t7, t9, t10, t11, t12, t13, t15, t16, t17, t18; FPvalue t19, t21, t22, t25, t28, t30, t31, t34, t36, t37, t38, t39, t40, t41; FPvalue t42, t43, t44, t45, t46, t47, t48, t50, t51, t53, t54, t55, t56, t58; FPvalue t59, t60, t61, t65, t66, t67, t68, t69, t70, t71, t72, t74, t75, t76; FPvalue t77, t78, t79, t80, t81, t82, t83, t84, t85, t86, t87, t88, t89, t90; FPvalue t93, t94, t95, t96, t97, t98, t99, t100, t101, t102, t103, t104, t105; FPvalue t106, t107, t108, t109, t110, t111, t112, t113, t114, t115, t116, t117; FPvalue t118, t119, t120, t121, t122, t123, t124, t125, t126, t127, t129, t130; FPvalue t131, t134, t135, t136, t137, t138, t139, t140, t141, t142, t143, t144; FPvalue t146, t147, t148, t150, t152, t153, t154, t155, t156, t157, t158, t159; FPvalue t160, t162, t163, t164, t165, t166, t167, t168, t169, t171, t173, t175; FPvalue t179, t181, t182, t185, t186, t187, t189, t190, t195, t196, t197, t198; FPvalue t199, t200, t201, t202, t203, t204, t205, t206, t207, t208, t210, t211; FPvalue t212, t213, t214, t219, t221, t223, t225, t226, t228, t229, t232, t233; FPvalue t235, t236, t237, t238, t239, t240, t241, t242, t243, t245, t249, t255; FPvalue t257, t259, t261, t265, t266, t272, t273, t276, t278, t280, t282, t284; FPvalue t285, t287, t289, t292, t294, t306, t310, t311, t319, t321, t325, t326; FPvalue t327, t329, t330, t331, t336, t337, t342, t344, t345, t348, t349, t353; FPvalue t357, t364, t367, t370, t371, t372, t373, t374, t375, t376, t377, t386; FPvalue t389, t393, t404, t411, t413, t415, t417, t419, t420, t432, t436, t441; FPvalue t457, t474, t482, t498, t504, t513, t530; const FPvalue two = (FPvalue) 2.0; const FPvalue three = (FPvalue) 3.0; t1 = P[0][2]*P[2][0]; t2 = P[1][1]*P[3][0]; t3 = t1*t2; t4 = P[0][1]*P[2][0]; t5 = P[3][2]*P[1][0]; t6 = t4*t5; t7 = P[1][2]*P[4][0]; t9 = P[1][2]*P[3][0]; t10 = t4*t9; t11 = P[4][1]*P[3][0]; t12 = t1*t11; t13 = P[3][1]*P[4][0]; t15 = P[3][1]*P[1][0]; t16 = t1*t15; t17 = P[4][1]*P[1][0]; t18 = t1*t17; t19 = P[1][1]*P[4][0]; t21 = P[4][1]*P[2][0]; t22 = t21*t9; t25 = P[3][2]*P[4][0]; t28 = P[4][2]*P[3][0]; t30 = two*t4*t28; t31 = P[3][1]*P[2][0]; t34 = P[4][2]*P[1][0]; t36 = two*t4*t34; t37 = P[0][0]*P[3][1]; t38 = P[2][2]*P[1][0]; t39 = t37*t38; t40 = P[0][0]*P[2][0]; t41 = P[3][1]*P[1][2]; t42 = t40*t41; t43 = P[0][0]*P[4][1]; t44 = t43*t9; t45 = P[2][2]*P[4][0]; t46 = t37*t45; t47 = P[1][0]*P[2][0]; t48 = P[4][1]*P[3][2]; t50 = two*t47*t48; t51 = P[3][1]*P[4][2]; t53 = two*t47*t51; t54 = P[0][0]*P[2][1]; t55 = t54*t28; t56 = two*t4*t25-t30+two*t31*t7+t36-t39-t42+t44+t46+t50-t53+t55; t58 = t54*t7; t59 = t37*t34; t60 = t54*t5; t61 = P[1][1]*P[2][0]; t65 = two*t61*t28; t66 = t54*t25; t67 = t43*t5; t68 = P[0][0]*P[1][1]; t69 = P[2][2]*P[3][0]; t70 = t68*t69; t71 = t68*t25; t72 = t68*t28; t74 = t40*t51; t75 = P[0][0]*P[2][2]; t76 = t75*t19; t77 = t40*t48; t78 = P[3][2]*P[1][1]; t79 = t40*t78; t80 = P[1][2]*P[2][0]; t81 = t43*t80; t82 = t75*t17; t83 = P[0][0]*P[4][2]; t84 = t83*t61; t85 = t37*t7; t86 = t43*t69; t87 = t54*t9; t88 = P[2][1]*P[1][0]; t89 = t83*t88; t90 = t74-t76-t77+t79+t81+t82-t84-t85-t86-t87-t89; t93 = P[4][2]*P[1][1]; t94 = t93*P[2][0]; t95 = t61*P[3][2]; t96 = P[4][1]*P[1][2]; t97 = t96*P[2][0]; t98 = t31*P[1][2]; t99 = t21*P[3][2]; t100 = t31*P[4][2]; t101 = P[2][2]*P[1][1]; t102 = t101*P[4][0]; t103 = t93*P[3][0]; t104 = t101*P[3][0]; t105 = t78*P[4][0]; t106 = P[2][1]*P[4][0]; t107 = t106*P[3][2]; t108 = t17*P[3][2]; t109 = -t94+t95+t97-t98-t99+t100+t102+t103-t104-t105+t107+t108; t110 = P[2][1]*P[3][0]; t111 = t110*P[1][2]; t112 = P[2][1]*P[4][2]; t113 = t112*P[1][0]; t114 = t41*P[4][0]; t115 = P[2][2]*P[4][1]; t116 = t115*P[3][0]; t117 = t115*P[1][0]; t118 = t11*P[1][2]; t119 = P[2][2]*P[3][1]; t120 = t119*P[4][0]; t121 = t119*P[1][0]; t122 = t88*P[3][2]; t123 = t51*P[1][0]; t124 = t110*P[4][2]; t125 = P[2][1]*P[1][2]; t126 = t125*P[4][0]; t127 = t111+t113+t114+t116-t117-t118-t120+t121-t122-t123-t124-t126; t129 = 1/(t109+t127); M[0][0] = (-two*t3-two*t6-two*t4*t7+two*t10+two*t12-two*t1*t13+two*t16 -two*t18+two*t1*t19-two*t22+t56+t58+t59+t60-two*t61*t25+t65-t66-t67+t70+t71-t72 +t90)*t129; t130 = P[0][1]*P[3][1]; t131 = t130*t34; t134 = P[0][1]*P[2][1]; t135 = t134*t5; t136 = t134*t28; t137 = P[0][1]*P[4][2]; t138 = t137*t88; t139 = t130*t7; t140 = P[0][1]*P[4][1]; t141 = t140*t5; t142 = t134*t9; t143 = t130*t45; t144 = t130*t38; t146 = t140*t9; t147 = t134*t7; t148 = t140*t69; t150 = two*t106*t41; t152 = two*t54*t93; t153 = t4*t48; t154 = t137*t61; t155 = t4*t41; t156 = P[0][1]*P[1][1]; t157 = t156*t25; t158 = t4*t78; t159 = t140*t80; t160 = -t146+t147+t148-t150+t152-t153-t154-t155-t157+t158+t159; t162 = t156*t28; t163 = t156*t69; t164 = t4*t51; t165 = P[0][1]*P[2][2]; t166 = t165*t19; t167 = t165*t17; t168 = t134*t25; t169 = P[0][2]*P[2][1]; t171 = two*t169*t15; t173 = two*t169*t19; t175 = two*t88*t51; t179 = t169*t13; t181 = t169*t2; t182 = t106*t78; t185 = t110*t93; t186 = t54*t51; t187 = t54*t78; t189 = t54*t41; t190 = t179-t169*t11+t181+t182+t110*t96+t54*t48-t185-t186-t187-t54*t96+t189; M[0][1] = -(-t131-two*t88*t48+t135+t136-t138+t139+t141-t142-t143+t144+ t160+t162-t163+t164+t166-t167-t168-t171-t173+t175+two*t169*t17+two*t190)*t129; t195 = P[0][2]*P[3][1]; t196 = t195*t38; t197 = t195*t34; t198 = t169*t5; t199 = P[0][2]*P[4][1]; t200 = t199*t9; t201 = t195*t45; t202 = P[0][2]*P[2][2]; t203 = t202*t17; t204 = t169*t25; t205 = P[0][2]*P[1][1]; t206 = t205*t25; t207 = t205*t28; t208 = t205*t69; t210 = t202*t19; t211 = t1*t48; t212 = t1*t51; t213 = t169*t28; t214 = t169*t7; t219 = P[0][0]*P[3][2]; t221 = two*t219*t101; t223 = two*t5*t115; t225 = two*t25*t101; t226 = P[0][1]*P[3][2]; t228 = two*t226*t45; t229 = -t210-t211+t212-t213-t214-two*t165*t34+two*t165*t28-t221-t223+t225- t228; t232 = two*t219*t115; t233 = t1*t41; t235 = two*t226*t38; t236 = t199*t5; t237 = t169*t9; t238 = t1*t78; t239 = t199*t80; t240 = t199*t69; t241 = P[0][2]*P[4][2]; t242 = t241*t61; t243 = t241*t88; t245 = t195*t7; t249 = two*t75*t41; t255 = two*t45*t41; t257 = two*t165*t9; t259 = two*t75*t96; t261 = two*t69*t96; t265 = two*t165*t7; t266 = t245-two*t75*t51+t249+two*t38*t51+two*t75*t93-t255-t257-t259+t261 -two*t69*t93+t265; M[0][2] = -(-t196-t197-t198-t200+t201+t203+t204-t206+t207+t208+t229+t232- t233+t235+t236+t237+t238+t239-t240-t242+t243+t266)*t129; t272 = two*t199*P[3][0]; t273 = -t122+t121-t120+t118-t117+t116-t114+t113+t111-t108-t272; t276 = two*t226*P[4][0]; t278 = two*t219*P[4][1]; t280 = two*t199*P[1][0]; t282 = two*t205*P[4][0]; t284 = two*t137*P[1][0]; t285 = P[0][1]*P[1][2]; t287 = two*t285*P[4][0]; t289 = two*t43*P[1][2]; t292 = two*t83*P[1][1]; t294 = two*t137*P[3][0]; t306 = two*t195*P[4][0]; t310 = two*t37*P[4][2]; t311 = t292+t294-two*t285*P[3][0]-two*t195*P[1][0]+two*t226*P[1][0]+two*t205*P[3][0]-t94-two* t219*P[1][1]+t306+two*t37*P[1][2]-t310; M[0][3] = -(t107+t105-t104-t103+t102+t100-t99-t126-t124+t123+t273-t276+ t278+t280-t282+t95-t284-t98+t97+t287-t289+t311)*t129; t319 = t55+t58-t59-t60-t66+t67+t70+t71-t72-t74-t76; t321 = P[0][1]*P[1][0]; t325 = P[0][2]*P[1][0]; t326 = t325*t11; t327 = t321*t69; t329 = t321*t28; t330 = t17*t69; t331 = t88*t28; t336 = t325*t110; t337 = -t326-t327-t15*t45+t329+t330-t331+t325*t13+t321*t45+t88*t25-t325* t106+t336; M[1][0] = (two*t6-two*t16+two*t18-t36+t39+t42+t44+t46-t50+t53+t319+t77- t79-t81-t82+t84-t85-t86-t87+t89-two*t321*t25+two*t337)*t129; t342 = t205*t31; t344 = t205*t13; t345 = t19*t119; t348 = t61*t51; t349 = t68*t51; t353 = t68*t119; t357 = two*t353+two*t68*t48+t131+t135+t136-t138-t139-t141-t142+t143-t144; t364 = t162-t163-t164+t166+t167-t168-t173+two*t181+two*t182-two*t185-two* t187; M[1][1] = (two*t205*t21-two*t342-two*t205*t11+two*t344-two*t345+two*t2* t115-two*t61*t48+two*t348-two*t349-two*t68*t115+t357+t146+t147-t148+t152+t153- t154+t155-t157+t158-t159+t364)*t129; t367 = P[4][2]*P[2][0]; t370 = t226*t7; t371 = t25*t125; t372 = t226*t80; t373 = P[2][0]*P[3][2]; t374 = t373*t96; t375 = t219*t125; t376 = t219*t96; t377 = P[0][0]*P[1][2]; t386 = two*t80*t51-two*t9*t112-t196+t197+t198-t200+t201+t203-t204+t206-t207 ; t389 = t239-t240+t242-t243+t245+t249-t255-t257-t259+t261+t265; M[1][2] = (-two*t285*t367+two*t285*t28-two*t370+two*t371+two*t372-two* t374-two*t375+two*t376-two*t377*t51+two*t377*t112+t386+t208-t210+t211-t212+t213 -t214-t233-t236+t237-t238+t389)*t129; t393 = t122-t121-t120+t118+t117+t116-t114-t113-t111-t108-t272; t404 = two*t169*P[4][0]; t411 = two*t165*P[4][0]; t413 = two*t54*P[4][2]; t415 = two*t75*P[4][1]; t417 = two*t137*P[2][0]; t419 = two*t199*P[2][0]; t420 = t411+t98-t97+t413-t415-t417+t419+t294+t94+t306-t310; M[1][3] = (t107+t105+t104-t103-t102+t100-t99+t126-t124+t123+t393-t276+ t278-t95+two*t169*P[3][0]-two*t1*P[3][1]-two*t165*P[3][0]+two*t37*P[2][2]-t404+two*t226*P[2][0]-two*t219 *P[2][1]+t420)*t129; t432 = t58+t59+t60+t65-t66-t67+three*t70+t71-three*t72-t74-t76; t436 = P[0][2]*P[3][0]; t441 = P[0][1]*P[3][0]; t457 = -t85-three*t86-three*t87-t89-two*t69*t19-two*t326-two*t327+two*t329+two* t330-two*t331+two*t336; M[2][0] = (-two*t3+two*t10+two*t12-two*t22-t30-t39+t42+three*t44+t46+three* t55+t432+t77-t79-t81+two*t110*t7+two*t436*t19-two*t436*t106-two*t441*t7+two* t441*t45+t82+t84+t457)*t129; t474 = -two*t31*t96+two*t15*t115+three*t131+t135+t136-t138-three*t139-t141-t142 +three*t143-three*t144; t482 = -t162+t163-three*t164-t166+t167-t168+t171-t175-two*t179+two*t186-two* t189; M[2][1] = (-two*t342+two*t344-two*t345+two*t348-two*t349+two*t353-two*t37 *t115+two*t37*t96+two*t195*t21-two*t195*t17+t474+t146+t147-t148+t150+t153+t154+ three*t155+t157-t158-t159+t482)*t129; t498 = two*t219*t93-two*t226*t34+t196-t197-three*t198-t200-t201-t203+three*t204 -three*t206+t207; t504 = t232-t233+t235+three*t236+t237+three*t238+t239+t240-t242+t243+t245; M[2][2] = -(two*t370-two*t371-two*t372+two*t374+two*t375-two*t376+two* t226*t367+two*t5*t112-two*t373*t93-two*t219*t112+t498-t208+t210-three*t211+t212- t213-t214-t221-t223+t225-t228+t504)*t129; t513 = -t122+t121-t120-t118-three*t117+t116+t114+three*t113+t111+t108+t280; t530 = -t419+t287-t289+t292-three*t94+two*t54*P[1][2]-two*t68*P[2][2]-two*t4*P[1][2]+two*t1* P[1][1]-two*t325*P[2][1]+two*t321*P[2][2]; M[2][3] = -(t107-t105-t104+t103+three*t102+t100-t99-three*t126-t124-t123+t513 -t282+t95-t284+t404-t411-t98+three*t97-t413+t415+t417+t530)*t129; M[3][0] = P[0][0]; M[3][1] = P[0][1]; M[3][2] = P[0][2]; M[3][3] = 1.0; #endif } /** A few simple double-precision analytical 3D geometry routines. ***/ double vlengthd(const double *v) { return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); } void vscaled(double *v, double div) { v[0] *= div; v[1] *= div; v[2] *= div; } void vnormald(double *v) { vscaled(v,1.0/vlengthd(v)); } /* GRAPHICS GEMS I, "Useful 3D Geometry", p297 */ void nearestPointOnPlaneToPoint(double J[4], double P[3], double Q[3]) { double JdotP = P[0]*J[0]+P[1]*J[1]+P[2]*J[2]; double JdotJ = J[0]*J[0]+J[1]*J[1]+J[2]*J[2]; double k = (J[3] + JdotP)/JdotJ; Q[0] = P[0] - k * J[0]; Q[1] = P[1] - k * J[1]; Q[2] = P[2] - k * J[2]; } /* GRAPHICS GEMS I, "Useful 3D Geometry", p299 */ void pointAtLineAndPlaneIntersection(double J[4], double U[3], double V[3], double P[3]) { double t = - (J[3] + (U[0]*J[0]+U[1]*J[1]+U[2]*J[2]))/ (V[0]*J[0]+V[1]*J[1]+V[2]*J[2]); P[0] = U[0] + V[0] * t; P[1] = U[1] + V[1] * t; P[2] = U[2] + V[2] * t; } /* Find the plane equation given 3 points. */ void findPlane(double plane[4], double v0[3], double v1[3], double v2[3]) { double vec0[3], vec1[3]; /* Need 2 vectors to find cross product. */ vec0[0] = v1[0] - v0[0]; vec0[1] = v1[1] - v0[1]; vec0[2] = v1[2] - v0[2]; vec1[0] = v2[0] - v0[0]; vec1[1] = v2[1] - v0[1]; vec1[2] = v2[2] - v0[2]; /* find cross product to get A, B, and C of plane equation */ plane[0] = vec0[1] * vec1[2] - vec0[2] * vec1[1]; plane[1] = -(vec0[0] * vec1[2] - vec0[2] * vec1[0]); plane[2] = vec0[0] * vec1[1] - vec0[1] * vec1[0]; plane[3] = -(plane[0] * v0[0] + plane[1] * v0[1] + plane[2] * v0[2]); } /* Compute a 4x4 matrix suitable for glMultMatrixd for projecting into a plane. */ void computeShadowVolume( double L[3], /* IN: light location */ double O[3], /* IN: cut-out plane */ double M[3], /* IN: cut-out X axis direction */ double N[3], /* IN: cut-out Y axis direction */ double G[4], /* IN: ground plane */ double P[5][3]) /* OUT: five mutually non-coplanar points defining the shadow volume projection */ { double LO[3]; /* Normalized direction vector from origin to light. */ double EP[3], LEP[3]; P[0][0] = O[0]; P[0][1] = O[1]; P[0][2] = O[2]; P[1][0] = O[0] + N[0]; P[1][1] = O[1] + N[1]; P[1][2] = O[2] + N[2]; P[2][0] = O[0] + M[0]; P[2][1] = O[1] + M[1]; P[2][2] = O[2] + M[2]; LO[0] = L[0] - O[0]; LO[1] = L[1] - O[1]; LO[2] = L[2] - O[2]; vnormald(LO); pointAtLineAndPlaneIntersection(Pbg, O, LO, P[3]); EP[0] = O[0] - N[0] - M[0]; EP[1] = O[1] - N[1] - M[1]; EP[2] = O[2] - N[2] - M[2]; LEP[0] = L[0] - EP[0]; LEP[1] = L[1] - EP[1]; LEP[2] = L[2] - EP[2]; vnormald(LEP); pointAtLineAndPlaneIntersection(Pbg, EP, LEP, P[4]); } #ifndef GLU_VERSION_1_2 /* nvshadow is written to tesselate the NVIDIA logo from its boundary points, but this is done with the GLU 1.2 tessellator. Most official OpenGL implementations provide the GLU 1.2 API, but Mesa 3.1 (and earlier) do not. For this reason, if GLU_VERSION_1_2 is not defined, use pre-tesselated version of the NVIDIA logo. */ #define bTriFan glBegin(GL_TRIANGLE_FAN); #define bTriStrip glBegin(GL_TRIANGLE_STRIP); #define bTris glBegin(GL_TRIANGLES); #define bQuadStrip glBegin(GL_QUAD_STRIP); #define e glEnd(); #define v(x,y) glVertex2f(x,y); static void preTesselatedCutOut(void) { bTriFan v(-1.06485,2.81135) v(-1.06478,2.05894) v(-2.05154,1.85121) v(-2.83056,1.43573) v(-3.5057,0.9609) v(-5,5) v(5,5) v(3.97311,2.81135) e bTriStrip v(-2.39205,0.536978) v(-2.36314,1.18348) v(-2.04704,0.806418) v(-1.79187,1.49508) v(-1.63302,1.01671) v(-1.06478,1.65831) v(-1.035,1.16786) e bTriFan v(-2.53006,0.260968) v(-2.41505,-0.047902) v(-2.10347,-1.22034) v(-2.57088,-0.760353) v(-2.83056,-0.315201) v(-2.36314,1.18348) v(-2.39205,0.536978) e bTriFan v(-2.83056,0.84219) v(-2.36314,1.18348) v(-2.83056,-0.315201) v(-3.09023,0.055759) v(-3.1941,0.471234) e bTriStrip v(-2.04704,-0.606495) v(-1.79403,-0.875934) v(-1.58413,-1.53195) v(-1.47202,-1.09937) v(-1.02549,-1.73179) v(-1.02549,-1.24824) e bTriFan v(-2.10347,-1.22034) v(-2.41505,-0.047902) v(-2.25405,-0.337056) v(-2.04704,-0.606495) v(-1.58413,-1.53195) e bTriStrip v(3.97311,2.81135) v(5,5) v(3.97311,-2.81135) v(5,-5) v(-1.02549,-2.81135) v(-5,-5) v(-2.93443,-1.20551) v(-3.29797,-0.760353) e bTriFan v(-1.02549,-2.81135) v(-2.93443,-1.20551) v(-2.41508,-1.63582) v(-1.8438,-1.96226) v(-1.02549,-2.15912) e bTriFan v(-5,-5) v(-5,5) v(-3.97311,0.545426) v(-3.86924,0.204143) v(-3.60957,-0.315201) v(-3.29797,-0.760353) e bTriStrip v(1.29669,-1.07956) v(1.69028,-0.820916) v(1.69028,-1.65308) v(2.00515,-0.51729) v(2.20194,-1.45066) v(2.4381,-0.179928) v(2.67425,-1.21451) v(3.34336,-0.719707) v(3.10721,-0.955861) e bTriStrip v(-0.474465,-2.15912) v(-0.198952,-1.7093) v(0.155277,-2.10289) v(0.273356,-1.5856) v(0.706303,-1.97919) v(0.86374,-1.3382) v(1.17861,-1.833) v(1.29669,-1.07956) v(1.69028,-1.65308) e bTriFan v(-1.02549,-2.15912) v(-1.02549,-1.73179) v(-0.198952,-1.7093) v(-0.474465,-2.15912) e bTriStrip v(2.12323,0.494796) v(1.92643,0.269888) v(1.84771,0.83216) v(1.69028,-0.033738) v(1.53284,1.12454) v(1.3242,0.426719) v(1.17861,1.39443) v(1.01259,0.753164) v(0.706303,1.7093) v(0.64905,1.09445) v(0.233576,1.36154) e bTriStrip v(-0.441573,-0.87906) v(-0.078033,-0.745515) v(0.115919,-1.1133) v(0.389378,-0.5081) v(0.588227,-0.899634) v(0.804852,-0.166817) v(0.942455,-0.652235) v(1.06452,0.189305) v(1.29669,-0.348609) v(1.3242,0.426719) v(1.69028,-0.033738) e bTriFan v(-0.474465,-1.25949) v(-1.02549,-1.24824) v(-1.01353,-0.88907) v(-0.441573,-0.87906) v(0.115919,-1.1133) e bTriStrip v(0.706303,1.7093) v(0.233576,1.36154) v(0.076562,1.96794) v(-0.233835,1.59895) v(-0.395747,2.0804) v(-1.06478,1.65831) v(-1.06478,2.05894) e bTriStrip v(-1.90903,0.07696) v(-1.86303,0.326685) v(-1.74803,-0.15962) v(-1.61002,0.530407) v(-1.54102,-0.448774) v(-1.38001,0.681555) v(-1.31101,-0.685355) v(-1.01285,0.723487) v(-1.01353,-0.88907) e bTriFan v(-0.078033,-0.107463) v(-0.233835,0.218981) v(-0.129966,1.00542) v(0.285509,0.753164) v(0.54518,0.441557) e bTriFan v(-0.493508,0.560265) v(-1.01285,0.723487) v(-0.545442,1.1538) v(-0.129966,1.00542) v(-0.233835,0.218981) e bTris v(-0.545442,1.1538) v(-1.01285,0.723487) v(-1.035,1.16786) v(-3.97311,0.545426) v(-5,5) v(-3.5057,0.9609) e } #undef v #define v(x,y,z) glVertex3f(x,y,z); static void preTesselatedCutOutVolume(void) { bQuadStrip v(-5,-5,0) v(-5,-5,1) v(-5,5,0) v(-5,5,1) v(5,5,0) v(5,5,1) v(5,-5,0) v(5,-5,1) v(-5,-5,0) v(-5,-5,1) e bQuadStrip v(-3.97311,0.545426,0) v(-3.97311,0.545426,1) v(-3.86924,0.204143,0) v(-3.86924,0.204143,1) v(-3.60957,-0.315201,0) v(-3.60957,-0.315201,1) v(-3.29797,-0.760353,0) v(-3.29797,-0.760353,1) v(-2.93443,-1.20551,0) v(-2.93443,-1.20551,1) v(-2.41508,-1.63582,0) v(-2.41508,-1.63582,1) v(-1.8438,-1.96226,0) v(-1.8438,-1.96226,1) v(-1.02549,-2.15912,0) v(-1.02549,-2.15912,1) v(-1.02549,-2.81135,0) v(-1.02549,-2.81135,1) v(3.97311,-2.81135,0) v(3.97311,-2.81135,1) v(3.97311,2.81135,0) v(3.97311,2.81135,1) v(-1.06485,2.81135,0) v(-1.06485,2.81135,1) v(-1.06478,2.05894,0) v(-1.06478,2.05894,1) v(-2.05154,1.85121,0) v(-2.05154,1.85121,1) v(-2.83056,1.43573,0) v(-2.83056,1.43573,1) v(-3.5057,0.9609,0) v(-3.5057,0.9609,1) v(-3.97311,0.545426,0) v(-3.97311,0.545426,1) e bQuadStrip v(-2.57088,-0.760353,0) v(-2.57088,-0.760353,1) v(-2.83056,-0.315201,0) v(-2.83056,-0.315201,1) v(-3.09023,0.055759,0) v(-3.09023,0.055759,1) v(-3.1941,0.471234,0) v(-3.1941,0.471234,1) v(-2.83056,0.84219,0) v(-2.83056,0.84219,1) v(-2.36315,1.18348,0) v(-2.36315,1.18348,1) v(-1.79187,1.49508,0) v(-1.79187,1.49508,1) v(-1.06478,1.65831,0) v(-1.06478,1.65831,1) v(-1.035,1.16786,0) v(-1.035,1.16786,1) v(-1.63302,1.01671,0) v(-1.63302,1.01671,1) v(-2.04704,0.806418,0) v(-2.04704,0.806418,1) v(-2.39205,0.536978,0) v(-2.39205,0.536978,1) v(-2.53006,0.260968,0) v(-2.53006,0.260968,1) v(-2.41505,-0.047902,0) v(-2.41505,-0.047902,1) v(-2.25405,-0.337056,0) v(-2.25405,-0.337056,1) v(-2.04704,-0.606495,0) v(-2.04704,-0.606495,1) v(-1.79403,-0.875934,0) v(-1.79403,-0.875934,1) v(-1.47202,-1.09937,0) v(-1.47202,-1.09937,1) v(-1.02549,-1.24824,0) v(-1.02549,-1.24824,1) v(-1.02549,-1.73179,0) v(-1.02549,-1.73179,1) v(-1.58413,-1.53195,0) v(-1.58413,-1.53195,1) v(-2.10347,-1.22034,0) v(-2.10347,-1.22034,1) v(-2.57088,-0.760353,0) v(-2.57088,-0.760353,1) e bQuadStrip v(3.34336,-0.719707,0) v(3.34336,-0.719707,1) v(3.10721,-0.955861,0) v(3.10721,-0.955861,1) v(2.67425,-1.21451,0) v(2.67425,-1.21451,1) v(2.20194,-1.45066,0) v(2.20194,-1.45066,1) v(1.69027,-1.65308,0) v(1.69027,-1.65308,1) v(1.17861,-1.833,0) v(1.17861,-1.833,1) v(0.706303,-1.97919,0) v(0.706303,-1.97919,1) v(0.155277,-2.10289,0) v(0.155277,-2.10289,1) v(-0.474465,-2.15912,0) v(-0.474465,-2.15912,1) v(-1.02549,-2.15912,0) v(-1.02549,-2.15912,1) v(-1.02549,-1.73179,0) v(-1.02549,-1.73179,1) v(-0.198952,-1.7093,0) v(-0.198952,-1.7093,1) v(0.273356,-1.5856,0) v(0.273356,-1.5856,1) v(0.86374,-1.3382,0) v(0.86374,-1.3382,1) v(1.29669,-1.07956,0) v(1.29669,-1.07956,1) v(1.69027,-0.820916,0) v(1.69027,-0.820916,1) v(2.00515,-0.51729,0) v(2.00515,-0.51729,1) v(2.4381,-0.179928,0) v(2.4381,-0.179928,1) v(3.34336,-0.719707,0) v(3.34336,-0.719707,1) e bQuadStrip v(1.53284,1.12454,0) v(1.53284,1.12454,1) v(1.84771,0.83216,0) v(1.84771,0.83216,1) v(2.12323,0.494796,0) v(2.12323,0.494796,1) v(1.92643,0.269888,0) v(1.92643,0.269888,1) v(1.69027,-0.033738,0) v(1.69027,-0.033738,1) v(1.29669,-0.348609,0) v(1.29669,-0.348609,1) v(0.942455,-0.652235,0) v(0.942455,-0.652235,1) v(0.588227,-0.899634,0) v(0.588227,-0.899634,1) v(0.115919,-1.1133,0) v(0.115919,-1.1133,1) v(-0.474465,-1.25949,0) v(-0.474465,-1.25949,1) v(-1.02549,-1.24824,0) v(-1.02549,-1.24824,1) v(-1.01353,-0.88907,0) v(-1.01353,-0.88907,1) v(-0.441573,-0.87906,0) v(-0.441573,-0.87906,1) v(-0.078033,-0.745515,0) v(-0.078033,-0.745515,1) v(0.389378,-0.5081,0) v(0.389378,-0.5081,1) v(0.804852,-0.166817,0) v(0.804852,-0.166817,1) v(1.06452,0.189305,0) v(1.06452,0.189305,1) v(1.3242,0.426719,0) v(1.3242,0.426719,1) v(1.01259,0.753164,0) v(1.01259,0.753164,1) v(0.64905,1.09445,0) v(0.64905,1.09445,1) v(0.233576,1.36154,0) v(0.233576,1.36154,1) v(-0.233835,1.59895,0) v(-0.233835,1.59895,1) v(-1.06478,1.65831,0) v(-1.06478,1.65831,1) v(-1.06478,2.05894,0) v(-1.06478,2.05894,1) v(-0.395747,2.0804,0) v(-0.395747,2.0804,1) v(0.076562,1.96794,0) v(0.076562,1.96794,1) v(0.706303,1.7093,0) v(0.706303,1.7093,1) v(1.17861,1.39443,0) v(1.17861,1.39443,1) v(1.53284,1.12454,0) v(1.53284,1.12454,1) e bQuadStrip v(-1.01285,0.723487,0) v(-1.01285,0.723487,1) v(-1.01353,-0.88907,0) v(-1.01353,-0.88907,1) v(-1.31101,-0.685355,0) v(-1.31101,-0.685355,1) v(-1.54102,-0.448774,0) v(-1.54102,-0.448774,1) v(-1.74803,-0.15962,0) v(-1.74803,-0.15962,1) v(-1.90903,0.07696,0) v(-1.90903,0.07696,1) v(-1.86303,0.326685,0) v(-1.86303,0.326685,1) v(-1.61002,0.530407,0) v(-1.61002,0.530407,1) v(-1.38001,0.681555,0) v(-1.38001,0.681555,1) v(-1.01285,0.723487,0) v(-1.01285,0.723487,1) e bQuadStrip v(0.54518,0.441557,0) v(0.54518,0.441557,1) v(-0.078033,-0.107463,0) v(-0.078033,-0.107463,1) v(-0.233835,0.218981,0) v(-0.233835,0.218981,1) v(-0.493508,0.560265,0) v(-0.493508,0.560265,1) v(-1.01285,0.723487,0) v(-1.01285,0.723487,1) v(-1.035,1.16786,0) v(-1.035,1.16786,1) v(-0.545442,1.1538,0) v(-0.545442,1.1538,1) v(-0.129966,1.00542,0) v(-0.129966,1.00542,1) v(0.285509,0.753164,0) v(0.285509,0.753164,1) v(0.54518,0.441557,0) v(0.54518,0.441557,1) e } #undef v #undef bTriStrip #undef bTriFan #undef bTris #undef bQuadStrip #endif /* !defined(GLU_VERSION_1_2) */ void doContour(GLUtesselator *tess, int n, GLdouble o[][3]) { int i; gluTessBeginContour(tess); for (i=0; i< n; i++) { gluTessVertex(tess, o[i], o[i]); } gluTessEndContour(tess); } void doCutOut(void) { gluTessBeginPolygon(tess, NULL); doContour(tess, SIZE(base), base); doContour(tess, SIZE(nvlogo0), nvlogo0); doContour(tess, SIZE(nvlogo1), nvlogo1); doContour(tess, SIZE(nvlogo2), nvlogo2); doContour(tess, SIZE(nvlogo3), nvlogo3); gluTessEndPolygon(tess); } static int first; static GLfloat fv[2]; static void CALLBACK begin(GLenum type) { glBegin(type); } /* ARGSUSED */ static void CALLBACK bside(GLenum type) { first = 1; glBegin(GL_QUAD_STRIP); } static void CALLBACK eside(void) { GLfloat v[3]; v[0] = fv[0]; v[1] = fv[1]; v[2] = 0.0; glVertex3fv(v); v[2] = 1.0; glVertex3fv(v); glEnd(); } static void CALLBACK vside(void *data) { GLdouble *d = (GLdouble*) data; GLfloat v[3]; if (first) { fv[0] = d[0]; fv[1] = d[1]; first = 0; } v[0] = d[0]; v[1] = d[1]; v[2] = 0.0; glVertex3fv(v); v[2] = 1.0; glVertex3fv(v); } static void CALLBACK end(void) { glEnd(); } void initCutOut(void) { #ifdef GLU_VERSION_1_2 gluTessProperty(tess, GLU_TESS_BOUNDARY_ONLY, GL_FALSE); gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); gluTessCallback(tess, GLU_TESS_BEGIN, (void (CALLBACK*)()) &begin); gluTessCallback(tess, GLU_TESS_VERTEX, (void (CALLBACK*)()) &glVertex3dv); gluTessCallback(tess, GLU_TESS_END, (void (CALLBACK*)()) &end); glNewList(DL_CUT_OUT, GL_COMPILE); doCutOut(); glEndList(); #else /* When GLU 1.2 is not supported. */ glNewList(DL_CUT_OUT, GL_COMPILE); preTesselatedCutOut(); glEndList(); #endif } void drawCutOut(void) { glNormal3f(0,0,1); glCallList(1); glNormal3f(0,0,-1); glCallList(1); } void CALLBACK combine(GLdouble coords[3], GLdouble *data[4], GLfloat weight[4], GLdouble **dataOut ) { GLdouble *vertex; vertex = (GLdouble *) malloc(3 * sizeof(GLdouble)); vertex[0] = coords[0]; vertex[1] = coords[1]; vertex[2] = coords[2]; *dataOut = vertex; } static void CALLBACK error(GLenum errno) { fprintf(stderr, "ERROR: %s\n", gluErrorString(errno)); } GLUtesselator * initTess(void) { GLUtesselator *tess; tess = gluNewTess(); if (tess == NULL) { return NULL; } gluTessCallback(tess, GLU_TESS_BEGIN, (void (CALLBACK*)()) &begin); gluTessCallback(tess, GLU_TESS_VERTEX, (void (CALLBACK*)()) &glVertex3dv); gluTessCallback(tess, GLU_TESS_COMBINE, (void (CALLBACK*)()) &combine); gluTessCallback(tess, GLU_TESS_END, (void (CALLBACK*)()) &end); gluTessCallback(tess, GLU_TESS_ERROR, (void (CALLBACK*)()) &error); return tess; } void initCutOutVolume(void) { #ifdef GLU_VERSION_1_2 gluTessProperty(tess, GLU_TESS_BOUNDARY_ONLY, GL_TRUE); gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); gluTessCallback(tess, GLU_TESS_BEGIN, (void (CALLBACK*)()) &bside); gluTessCallback(tess, GLU_TESS_VERTEX, (void (CALLBACK*)()) &vside); gluTessCallback(tess, GLU_TESS_END, (void (CALLBACK*)()) &eside); glNewList(DL_CUT_OUT_VOLUME, GL_COMPILE); doCutOut(); glEndList(); #else /* When GLU 1.2 is not supported. */ glNewList(DL_CUT_OUT_VOLUME, GL_COMPILE); preTesselatedCutOutVolume(); glEndList(); #endif } void drawCutOutVolume(void) { /* Note that this routine does not cap the ends of the shadow volume. The cut-out object itself and a ground plane are assumed to cap the shadow volume. */ glCallList(DL_CUT_OUT_VOLUME); } void drawFloor(void) { float x, y; float d = 1.0; /* Draw ground. */ if (useTextures) { glEnable(GL_TEXTURE_2D); } glColor3f(1,1,0); glNormal3f(0,1,0); /* Tesselate floor so lighting looks reasonable. */ for (x=-8; x<=7; x+=d) { glBegin(GL_QUAD_STRIP); for (y=-8; y<=8; y+=d) { glTexCoord2f(x+1, y); glVertex3f(x+1, -1, y); glTexCoord2f(x, y); glVertex3f(x, -1, y); } glEnd(); } if (useTextures) { glDisable(GL_TEXTURE_2D); } } void initObjects(void) { glNewList(DL_SPHERE, GL_COMPILE); glutSolidSphere(0.5, 7, 7); glEndList(); glNewList(DL_TEAPOT, GL_COMPILE); glDisable(GL_CULL_FACE); fastTeapot(3, 1.6); glEnable(GL_CULL_FACE); glEndList(); } void drawObjects(void) { float h; glPushMatrix(); h = (-(1-time1)*(1-time1) + 1) * 1.5; glTranslatef(0,-0.5+h, 0); glCallList(DL_SPHERE); glPopMatrix(); glPushMatrix(); glTranslatef(2,-0.5,2+sin(time2)); glCallList(DL_SPHERE); glPopMatrix(); glPushMatrix(); glTranslatef(2+cos(time2),-0.5,-2+0.4*sin(time2)); glCallList(DL_SPHERE); glPopMatrix(); glPushMatrix(); glTranslatef(-2,-0.0,2); glRotatef(180, 0,1,0); glRotatef(teapotAngle, 0,1,0); glCallList(DL_TEAPOT); glPopMatrix(); } void drawRoom(void) { drawFloor(); drawObjects(); } void ambientLight(int enable) { GLfloat on[4] = { 0.92, 0.92, 0.92, 1.0 }; GLfloat off[4] = { 0.0, 0.0, 0.0, 1.0 }; if (enable) { glLightModelfv(GL_LIGHT_MODEL_AMBIENT, on); } else { glLightModelfv(GL_LIGHT_MODEL_AMBIENT, off); } } void renderWithSoftShadows(int numLightSamples) { GLdouble P[5][3]; GLdouble matrix[4][4]; GLfloat Lf[4]; GLdouble Ld[4]; GLfloat Lc[4]; float sampleAngle, sampleDeltaAngle; float lightRadius = 0.1; int doOnce; int i; glDepthMask(1); glColorMask(1,1,1,1); glStencilMask(~0u); /* The subsquent shadow passes use additive blending and to prevent the possiblity of "double blending" due to "depth testing ties", stencil is used to accept the first of any depth testing ties. Therefore, use GL_LESS initially since it too accepts just the first of any depth testing ties. */ glDepthFunc(GL_LESS); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); /* The samples will be in a ring in a constant Z plane. */ sampleDeltaAngle = 3.14159 * 2.0 / numLightSamples; /* Draw light source position as a yellow dot. */ glDisable(GL_LIGHTING); glColor3f(1,1,0); glBegin(GL_POINTS); for (i=0, sampleAngle=0.0; i 2.0) { time1 = time1 - 2.0; } time2 += 0.05; } if (animateMode != 0) { logoAngle = (logoAngle + 3) % 360; updateAxis(); } glutPostRedisplay(); } static void visible(int vis) { if (vis == GLUT_VISIBLE) { if (animate) glutIdleFunc(doAnimate); } else { if (!animate) glutIdleFunc(NULL); } } static void keyboard(unsigned char c, int x, int y) { switch (c) { case 27: exit(0); return; case 'h': case 'H': O[0] -= 0.25; break; case 'l': case 'L': O[0] += 0.25; break; case 'j': case 'J': O[2] -= 0.25; break; case 'k': case 'K': O[2] += 0.25; break; case 'a': case 'A': O[1] += 0.25; break; case 'z': case 'Z': O[1] -= 0.25; break; case '2': case '3': case '4': case '5': case '6': case '7': case '8': numLightSamples = c - '0'; updateWindowTitle(); break; case 'b': case 'B': benchmark(); break; case 'm': animateMode = (animateMode+1) % 3; break; case ' ': animate = !animate; if (animate) { glutIdleFunc(doAnimate); } else { glutIdleFunc(NULL); } break; default: return; } glutPostRedisplay(); } void special(int k, int x, int y) { switch (k) { case GLUT_KEY_F1: displayMode = M_VOLUME_SHADOWS; updateWindowTitle(); break; case GLUT_KEY_F2: displayMode = M_NO_SHADOWS; updateWindowTitle(); break; case GLUT_KEY_F3: displayMode = M_SHADOW_VOLUME; updateWindowTitle(); break; case GLUT_KEY_F4: displayMode = M_SOFT_SHADOWS; updateWindowTitle(); break; case GLUT_KEY_F5: displayMode = M_PLANAR_SHADOWS; updateWindowTitle(); break; case GLUT_KEY_F6: displayMode = M_HYBRID_SHADOWS; updateWindowTitle(); break; case GLUT_KEY_UP: L[2] -= 0.25; break; case GLUT_KEY_DOWN: L[2] += 0.25; break; case GLUT_KEY_RIGHT: L[0] += 0.25; break; case GLUT_KEY_LEFT: L[0] -= 0.25; break; case GLUT_KEY_PAGE_UP: L[1] += 0.25; break; case GLUT_KEY_PAGE_DOWN: L[1] -= 0.25; break; #if 0 /* If you wanted keys to raise and lower the virtual ground plane. */ case GLUT_KEY_HOME: Pbg[3] += 0.25; break; case GLUT_KEY_END: Pbg[3] -= 0.25; break; #endif default: /* Avoid the glutPostRedisplay below. */ return; } glutPostRedisplay(); } static void mouse(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { moving = 1; beginx = x; beginy = y; } if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) { moving = 0; } } static void motion(int x, int y) { if (moving) { logoAngle = logoAngle + (beginx - x); updateAxis(); beginx = x; beginy = y; glutPostRedisplay(); } } static void menu(int item) { switch (item) { case M_ANIMATE: keyboard(' ', 0, 0); break; case M_BENCHMARK: keyboard('b', 0, 0); break; case M_VOLUME_SHADOWS: case M_SOFT_SHADOWS: case M_NO_SHADOWS: case M_SHADOW_VOLUME: case M_PLANAR_SHADOWS: case M_HYBRID_SHADOWS: displayMode = item; updateWindowTitle(); break; } glutPostRedisplay(); } static void numLightSamplesMenu(int samples) { numLightSamples = samples; updateWindowTitle(); glutPostRedisplay(); } /* XXX RIVA 128 board vendors may change their GL_VENDOR and GL_RENDERER strings. */ int needsStencilRenderingInvariantHack(void) { const char *renderer; GLint bits; renderer = glGetString(GL_RENDERER); /* Stencil rendering on RIVA 128 and RIVA 128 ZX is not invariant with stencil-disabled rendering in 16-bit hardware accelerated mode. */ if (!strncmp("RIVA 128", renderer, 8)) { glGetIntegerv(GL_INDEX_BITS, &bits); return bits == 16; } /* Stencil rendering on RIVA 128 and RIVA 128 ZX is not invariant with stencil-disabled rendering in 16-bit hardware accelerated mode. 32-bit mode is invariant (and hardware accelerated though!). */ if (!strncmp("RIVA TNT", renderer, 8)) { glGetIntegerv(GL_INDEX_BITS, &bits); return bits == 16; } return 1; } int main(int argc, char **argv) { int i; int sub1; glutInit(&argc, argv); for (i=1; i