nVidia's Stencil Shadow demo

Started by
5 comments, last by ShlomiSteinberg 20 years, 9 months ago
The NVShadow demo uses two Vectors (M,N) described in the "nvShadow.c" as "Vectors to orient the cut-out". Now I tried to figure out what these vectors are but no luck. Any help? "C lets you shoot yourself in the foot rather easily. C++ allows you to reuse the bullet!"
Member of the Shove Pouya Off A Cliff club, SPOAC. (If you wish to join, add this line to your signature.)Member of "Un-Ban nes8bit" association, UNA (to join put this in your sig)"C lets you shoot yourself in the foot rather easily. C++ allows you to reuse the bullet!"
Advertisement
*bump* Anyone?

"C lets you shoot yourself in the foot rather easily. C++ allows you to reuse the bullet!"
Member of the Shove Pouya Off A Cliff club, SPOAC. (If you wish to join, add this line to your signature.)Member of "Un-Ban nes8bit" association, UNA (to join put this in your sig)"C lets you shoot yourself in the foot rather easily. C++ allows you to reuse the bullet!"
don''t recommend using the nVidia stuff since ATI has the hottest Cards
quote:Original post by Anonymous Poster
don''t recommend using the nVidia stuff since ATI has the hottest Cards



Oh really....

"C lets you shoot yourself in the foot rather easily. C++ allows you to reuse the bullet!"
Member of the Shove Pouya Off A Cliff club, SPOAC. (If you wish to join, add this line to your signature.)Member of "Un-Ban nes8bit" association, UNA (to join put this in your sig)"C lets you shoot yourself in the foot rather easily. C++ allows you to reuse the bullet!"
Need some more info...
What more information? I can give you the source of the demo:
#include <stdlib.h>#include <string.h>#include <stdio.h>#include <assert.h>#include <math.h>#include <GL/glut.h>/* Some <math.h> 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 voidmakeFloorTexture(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. */voidshadowMatrix(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. */voidconstructShadowVolumeMatrix(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. ***/doublevlengthd(const double *v){    return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);}voidvscaled(double *v, double div){    v[0] *= div;    v[1] *= div;    v[2] *= div;}voidvnormald(double *v){    vscaled(v,1.0/vlengthd(v));}/* GRAPHICS GEMS I, "Useful 3D Geometry", p297 */voidnearestPointOnPlaneToPoint(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 */voidpointAtLineAndPlaneIntersection(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. */voidfindPlane(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. */voidcomputeShadowVolume(  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) {bTriFanv(-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) ebTriStripv(-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) ebTriFanv(-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) ebTriFanv(-2.83056,0.84219) v(-2.36314,1.18348) v(-2.83056,-0.315201)v(-3.09023,0.055759) v(-3.1941,0.471234) ebTriStripv(-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) ebTriFanv(-2.10347,-1.22034) v(-2.41505,-0.047902) v(-2.25405,-0.337056)v(-2.04704,-0.606495) v(-1.58413,-1.53195) ebTriStripv(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) ebTriFanv(-1.02549,-2.81135) v(-2.93443,-1.20551) v(-2.41508,-1.63582)v(-1.8438,-1.96226) v(-1.02549,-2.15912) ebTriFanv(-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) ebTriStripv(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) ebTriStripv(-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) ebTriFanv(-1.02549,-2.15912) v(-1.02549,-1.73179) v(-0.198952,-1.7093)v(-0.474465,-2.15912) ebTriStripv(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) ebTriStripv(-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) ebTriFanv(-0.474465,-1.25949) v(-1.02549,-1.24824) v(-1.01353,-0.88907)v(-0.441573,-0.87906) v(0.115919,-1.1133) ebTriStripv(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) ebTriStripv(-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) ebTriFanv(-0.078033,-0.107463) v(-0.233835,0.218981) v(-0.129966,1.00542)v(0.285509,0.753164) v(0.54518,0.441557) ebTriFanv(-0.493508,0.560265) v(-1.01285,0.723487) v(-0.545442,1.1538)v(-0.129966,1.00542) v(-0.233835,0.218981) ebTrisv(-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) {bQuadStripv(-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) ebQuadStripv(-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) ebQuadStripv(-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) ebQuadStripv(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) ebQuadStripv(-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) ebQuadStripv(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) */voiddoContour(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);}voiddoCutOut(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 CALLBACKbegin(GLenum type){  glBegin(type);}/* ARGSUSED */static void CALLBACKbside(GLenum type){  first = 1;  glBegin(GL_QUAD_STRIP);}static void CALLBACKeside(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 CALLBACKvside(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 CALLBACKend(void){   glEnd();}voidinitCutOut(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}voiddrawCutOut(void){  glNormal3f(0,0,1);  glCallList(1);  glNormal3f(0,0,-1);  glCallList(1);}void CALLBACKcombine(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 CALLBACKerror(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;}voidinitCutOutVolume(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}voiddrawCutOutVolume(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);}voiddrawFloor(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);  }}voidinitObjects(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();}voiddrawObjects(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();}voiddrawRoom(void){  drawFloor();  drawObjects();}voidambientLight(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);  }}voidrenderWithSoftShadows(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<numLightSamples;       i++, sampleAngle += sampleDeltaAngle) {    glVertex3d(      L[0] + lightRadius * cos(sampleAngle),      L[1],      L[2] + lightRadius * sin(sampleAngle));  }  glEnd();  /* Draw room with no lights sources on, but still have ambient lighting. */  glEnable(GL_LIGHTING);  glDisable(GL_LIGHT0);  ambientLight(1);  /* Use back face culling for better performance. */  /* XXX Too bad that crappy glutSolidTeapot model is not a true closed     surface.  You may notice minor cracks in the teapot when backface     culling is enabled. */  glEnable(GL_CULL_FACE);  glCullFace(GL_BACK);  if (forceStencilHack) {    glEnable(GL_STENCIL_TEST);    glStencilFunc(GL_ALWAYS, 0, 0xffffffff);    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);  } else {    /* XXX Note that the non-hack case does not enable or       disable stencil.  The hack case enables stencil       testing but sets up the stencil modes so that stencil       testing is effectively disabled.  If you wanted       stencil testing on during the renderSceneFunc, you won''t       need to have the hack enabled though! */  }  drawRoom();  /* Set the light source samples to be 1/nth of the strength of the true     area light source. */  Lc[0] = 1.0 / numLightSamples;  Lc[1] = 1.0 / numLightSamples;  Lc[2] = 1.0 / numLightSamples;  Lc[3] = 1.0 / numLightSamples;  glLightfv(GL_LIGHT0, GL_DIFFUSE, &Lc[0]);  glLightfv(GL_LIGHT0, GL_SPECULAR, &Lc[0]);  glEnable(GL_LIGHT0);  doOnce = 1;  for (i=0, sampleAngle=0.0;       i<numLightSamples;       i++, sampleAngle += sampleDeltaAngle) {    /* Compute each light sample position. */    Lf[0] = Ld[0] = L[0] + lightRadius * cos(sampleAngle);    Lf[1] = Ld[1] = L[1] + lightRadius * sin(sampleAngle);    Lf[2] = Ld[2] = L[2];    Lf[3] = Ld[3] = L[3];    /* Tell OpenGL the light sample''s position. */    glLightfv(GL_LIGHT0, GL_POSITION, &Lf[0]);    /* Given: the light source position (L), the cut-out origin (O), the       cut-out Y direction (N), the cut-out X direction (M), the ground       plane equation, compute five points in world space to project       the cut-out space volume into. */    computeShadowVolume(Ld, O, M, N, Pbg, P);      /* Generate a cut-out shadow volume projection matrix from the five       points in world space. */    constructShadowVolumeMatrixd(P, matrix);      glPushMatrix();      /* Concatenate the previously computed 4x4 projective matrix         onto the current modelview matrix.  With this matrix in place,         the "drawCutOut" routine will draw the cut-out in the proper         orientation as described by the parameters to the call to         computeShadowVolume and the "drawCutOutVolume" routine will         draw the cut-out''s shadow volume extended to the ground plane as         described by the parameters to the computeShadowVolume call. */      glMultMatrixd(&matrix[0][0]);      glDepthFunc(GL_ALWAYS);  /* XXX hack */      drawCutOut();      if (doOnce) {        /* Disable the global ambient light for subsequent passes. */        ambientLight(0);        /* Enable additive blending to add in each light source sample''s           lighitng contribution. */        glEnable(GL_BLEND);        glBlendFunc(GL_ONE, GL_ONE);        glDepthMask(0);        doOnce = 0;      }      /* Draw the shadow volume. */      glEnable(GL_STENCIL_TEST);      glDepthFunc(GL_LESS);      glColorMask(0,0,0,0);      glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT);      glStencilFunc(GL_ALWAYS, 0, 1 << i);      glStencilMask(1 << i);      glDisable(GL_CULL_FACE);      drawCutOutVolume();      glEnable(GL_CULL_FACE);     glPopMatrix();    glColorMask(1,1,1,1);    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);    glStencilFunc(GL_NOTEQUAL, 1 << i, 1 << i);    glDepthFunc(GL_EQUAL);    /* Draw the room with the ith light sample enabled. */    drawRoom();    if (forceStencilHack) {      glEnable(GL_STENCIL_TEST);      glStencilFunc(GL_ALWAYS, 0, 0xffffffff);      glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);    } else {      glDisable(GL_STENCIL_TEST);    }  }  glDisable(GL_BLEND);}voidreshape(int w, int h){  windowWidth = w;  windowHeight = h;  glViewport(0,0,w,h);  glMatrixMode(GL_PROJECTION);  glLoadIdentity();  gluPerspective(60.0, (GLdouble)w/h, 1.0, 20.0);  glPushMatrix();  glMatrixMode(GL_MODELVIEW);  }voidrender(void){  GLdouble P[5][3];  GLdouble matrix[4][4];  GLfloat shadowMat[4][4];  GLfloat Lf[4];  GLfloat Lc[4];  /* Use a white light. */  Lc[0] = 1.0;  Lc[1] = 1.0;  Lc[2] = 1.0;  Lc[3] = 1.0;  glLightfv(GL_LIGHT0, GL_DIFFUSE, &Lc[0]);  glLightfv(GL_LIGHT0, GL_SPECULAR, &Lc[0]);  glColorMask(1,1,1,1);  glDepthMask(1);  glStencilMask(~0u);  /* GL_LESS means that depth test "ties" go to the FIRST tieing fragment.     This is OpenGL''s default depth test, but when depth testing with     shadow volumes, we later use GL_EQUAL to match depth values.  However,     GL_EQUAL means that depth test "ties" go to the LAST tieing fragment.     Therefore, we use GL_LEQUAL initially so we can match the later     "depth test tie goes to the last fragment" passes. */  glDepthFunc(GL_LEQUAL);  if (forceStencilHack) {    glEnable(GL_STENCIL_TEST);    glStencilFunc(GL_ALWAYS, 0, 0xffffffff);    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);  } else {    glDisable(GL_STENCIL_TEST);  }  glEnable(GL_LIGHT0);  ambientLight(1);  Lf[0] = L[0];  Lf[1] = L[1];  Lf[2] = L[2];  Lf[3] = L[3];  glLightfv(GL_LIGHT0, GL_POSITION, &Lf[0]);    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);    /* Given: the light source position (L), the cut-out origin (O), the     cut-out Y direction (N), the cut-out X direction (M), the ground     plane equation, compute five points in world space to project the     cut-out space volume into. */  computeShadowVolume(L, O, M, N, Pbg, P);    /* Generate a volume projection matrix from the five points in world     space. */  constructShadowVolumeMatrixd(P, matrix);  shadowMatrix(shadowMat, Pg, Lf);     glDisable(GL_LIGHTING);  /* Draw light source position as a yellow dot. */  glColor3f(1,1,0);  glBegin(GL_POINTS);  glVertex3dv(L);  glEnd();  glEnable(GL_LIGHTING);  glEnable(GL_CULL_FACE);  glCullFace(GL_BACK);  drawObjects();  glPushMatrix();    glMultMatrixd(&matrix[0][0]);    drawCutOut();  glPopMatrix();  if (displayMode == M_PLANAR_SHADOWS || displayMode == M_HYBRID_SHADOWS) {    glEnable(GL_STENCIL_TEST);    glStencilFunc(GL_ALWAYS, 0x2, 0);    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);  }  drawFloor();  if (displayMode != M_NO_SHADOWS) {    glPushMatrix();    glMultMatrixd(&matrix[0][0]);    if (displayMode == M_VOLUME_SHADOWS || displayMode == M_HYBRID_SHADOWS) {            /* Draw the shadow volume. */      glColorMask(0,0,0,0);      glDepthMask(0);      glEnable(GL_STENCIL_TEST);      glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT);      glStencilFunc(GL_ALWAYS, 0, 0x1);      glStencilMask(0x1);      glDisable(GL_CULL_FACE);      drawCutOutVolume();      glEnable(GL_CULL_FACE);     }    if (displayMode == M_SHADOW_VOLUME) {      glDisable(GL_LIGHTING);      glEnable(GL_BLEND);      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);      glDepthMask(0);      glColor4f(1,0,1,0.8);      glColorMask(1,0,0,0);      glCullFace(GL_FRONT);      drawCutOutVolume();      glColorMask(0,0,1,0);      glColor4f(1,0,1,0.8);      glCullFace(GL_BACK);      drawCutOutVolume();      glDepthMask(1);      glDisable(GL_BLEND);      glEnable(GL_LIGHTING);      glColorMask(1,1,1,1);    }    glPopMatrix();  }  if (displayMode == M_VOLUME_SHADOWS || displayMode == M_HYBRID_SHADOWS) {    glColorMask(1,1,1,1);    glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);    glStencilFunc(GL_EQUAL, 0x1, 0x1);    glDepthFunc(GL_EQUAL);    glDisable(GL_LIGHT0);        drawRoom();        glEnable(GL_LIGHT0);  }  if (displayMode == M_PLANAR_SHADOWS || displayMode == M_HYBRID_SHADOWS) {    glDisable(GL_DEPTH_TEST);    glPushMatrix();      glMultMatrixf((GLfloat *) shadowMat);      glStencilFunc(GL_EQUAL, 0x3, 0x2);      glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);      drawObjects();      if (displayMode == M_PLANAR_SHADOWS) {        glPushMatrix();          glMultMatrixd(&matrix[0][0]);          drawCutOut();        glPopMatrix();      }    glPopMatrix();    glStencilFunc(GL_EQUAL, 0x1, 0x1);    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);    glColorMask(1,1,1,1);    glDisable(GL_LIGHT0);    drawFloor();    glEnable(GL_DEPTH_TEST);   }  if (forceStencilHack) {    glEnable(GL_STENCIL_TEST);    glStencilFunc(GL_ALWAYS, 0, 0xffffffff);    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);  } else {    glDisable(GL_STENCIL_TEST);  }}voiddisplay(void){  if (displayMode == M_SOFT_SHADOWS) {    /* Handle with a special routine. */    renderWithSoftShadows(numLightSamples);  } else {    /* Handle all the non-soft shadow cases. */    render();  }  if (doubleBuffer) {    glutSwapBuffers();  } else {    glFlush();  }  if (oneFrame) {    exit(0);  }}voidupdateWindowTitle(void){  char title[100];  switch (displayMode) {  case M_VOLUME_SHADOWS:    glutSetWindowTitle("nvshadow: Hard Volmetric Shadows");    break;  case M_SOFT_SHADOWS:    sprintf(title, "nvshadow: Soft Shadows (%d samples)",      numLightSamples);    glutSetWindowTitle(title);    break;  case M_NO_SHADOWS:    glutSetWindowTitle("nvshadow: No Shadows");    break;  case M_SHADOW_VOLUME:    glutSetWindowTitle("nvshadow: Visualize Shadow Volume");    break;  case M_PLANAR_SHADOWS:    glutSetWindowTitle("nvshadow: Planar Projected Shadows");    break;  case M_HYBRID_SHADOWS:    glutSetWindowTitle("nvshadow: Hybrid Shadows");    break;  }}voidupdateAxis(void){  M[0] = 0.3 * cos(logoAngle/180.0*M_PI);  M[1] = 0.3 * 0.0;  M[2] = 0.3 * -sin(logoAngle/180.0*M_PI);  N[0] = 0.3 * sin(logoAngle/180.0*M_PI);  N[1] = 0.3 * 0.0;  N[2] = 0.3 * cos(logoAngle/180.0*M_PI);}voidbenchmark(void){  float start, end;  int frames = 25;  int i;  L[0] = 3;  L[1] = 4;  L[2] = 2;  L[3] = 1;  O[0] = 3;  O[1] = 2;  O[2] = 2;  updateAxis();  start = glutGet(GLUT_ELAPSED_TIME);  for (i=0; i<frames; i++) {    L[0] = L[0] + 0.15;    display();  }  end = glutGet(GLUT_ELAPSED_TIME);  printf("\nseconds = %g\n", (end - start)/1000.0);  printf("seconds/frame = %.3g\n", ((end - start)/1000.0)/frames);  printf("frames/second = %.2g\n", frames/((end - start)/1000.0));  printf("size = %dx%d\n",    glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT));}voiddoAnimate(void){  if (animateMode != 2) {    teapotAngle = (teapotAngle + 5) % 360;    time1 += 0.1;    if (time1 > 2.0) {      time1 = time1 - 2.0;    }    time2 += 0.05;  }  if (animateMode != 0) {    logoAngle = (logoAngle + 3) % 360;    updateAxis();  }  glutPostRedisplay();}static voidvisible(int vis){  if (vis == GLUT_VISIBLE) {    if (animate)       glutIdleFunc(doAnimate);  } else {    if (!animate)      glutIdleFunc(NULL);  }}static voidkeyboard(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();}voidspecial(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 voidmouse(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 voidmotion(int x, int y){  if (moving) {    logoAngle = logoAngle + (beginx - x);    updateAxis();    beginx = x;    beginy = y;    glutPostRedisplay();  }}static voidmenu(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 voidnumLightSamplesMenu(int samples){  numLightSamples = samples;  updateWindowTitle();  glutPostRedisplay();}/* XXX NVIDIA board vendors may change their GL_VENDOR   and GL_RENDERER strings. */intneedsStencilRenderingInvariantHack(void){  const char *renderer;  GLint bits;  renderer = (const char*) glGetString(GL_RENDERER);  if (!strncmp("RIVA 128", renderer, 8)) {    glGetIntegerv(GL_INDEX_BITS, &bits);    return bits == 16;  }  /* Stencil rendering on RIVA TNT and TNT2     is not invariant with stencil-disabled rendering     in 16-bit hardware accelerated mode.  32-bit mode     is invariant (and hardware accelerated too!).  */  if (!strncmp("RIVA TNT", renderer, 8)) {    glGetIntegerv(GL_INDEX_BITS, &bits);    if (bits == 16) {      printf("nvshadow: This program will run MUCH faster if you switch\n");      printf("          to a 32-bit display mode and restart nvshadow.\n");      return 1;    } else {      return 0;    }  }  /* Stencil rendering on GeForce and Quadro     is not invariant with stencil-disabled rendering     in 16-bit hardware accelerated mode.  32-bit mode     is invariant (and hardware accelerated too!).  */  if (!strncmp("GeForce", renderer, 7) || !strncmp("Quadro", renderer, 6)) {    glGetIntegerv(GL_INDEX_BITS, &bits);    if (bits == 16) {      printf("nvshadow: This program will run MUCH faster if you switch\n");      printf("          to a 32-bit display mode and restart nvshadow.\n");      return 1;    } else {      return 0;    }  }  return 1;}intmain(int argc, char **argv){  int i;  int sub1;  glutInit(&argc, argv);  for (i=1; i<argc; i++) {    if(!strcmp("-notex", argv[i])) {      useTextures = 0;    }    else    if(!strcmp("-stencilhack", argv[i])) {      forceStencilHack = 1;    }    else    if(!strcmp("-fullscreen", argv[i])) {      fullscreen = 1;    }    else    if(!strcmp("-400x300", argv[i])) {      fullscreen = 1;      smallFullscreen = 1;    }    else    if(!strcmp("-soft", argv[i])) {      displayMode = M_SOFT_SHADOWS;    }    else    if(!strcmp("-volume", argv[i])) {      displayMode = M_SHADOW_VOLUME;    }    else    if(!strcmp("-planar", argv[i])) {      displayMode = M_PLANAR_SHADOWS;    }    else    if(!strcmp("-noshadow", argv[i])) {      displayMode = M_NO_SHADOWS;    }    else    if(!strcmp("-nomipmaps", argv[i])) {      useMipmaps = 0;    }    else    if(!strcmp("-oneframe", argv[i])) {      oneFrame = 1;    }    else    if(!strcmp("-cool", argv[i])) {      time1 = 0.5;      time2 = 2.42;      teapotAngle = 65;      logoAngle = 78;      updateAxis();    }    else    if(!strcmp("-sb", argv[i])) {      doubleBuffer = 0;    }  }  if (doubleBuffer) {    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);  } else {    glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH | GLUT_STENCIL);  }/* #if is for old GLUT implementations without GameGLUT support. */#if GLUT_XLIB_IMPLEMENTATION>=13  if (fullscreen) {    if (smallFullscreen) {      glutGameModeString("400x300:32");    } else {      glutGameModeString("640x480:32");    }    glutEnterGameMode();    glutSetCursor(GLUT_CURSOR_NONE);  } else#endif  {    glutCreateWindow("nvshadow");    updateWindowTitle();  }  glutReshapeFunc(reshape);  glutDisplayFunc(display);  glutVisibilityFunc(visible);  glutSpecialFunc(special);  glutKeyboardFunc(keyboard);  glutMouseFunc(mouse);  glutMotionFunc(motion);  glMatrixMode(GL_PROJECTION);  glLoadIdentity();  gluPerspective(60.0, 1.0, 1.0, 20.0);  glMatrixMode(GL_MODELVIEW);  glLoadIdentity();  gluLookAt(    0,5,10,          /* eye */    0,0,0,           /* center */    0,1,0);          /* up */  glEnable(GL_DEPTH_TEST);  glPointSize(4.0);  /* Determine the plane equation of the ground plane from three points. */  findPlane(Pbg, Sbg, Tbg, Rbg);  findPlane(Pg, Sg, Tg, Rg);  if (useTextures) {    makeFloorTexture();  }  glEnable(GL_LIGHTING);  glEnable(GL_LIGHT0);  tess = initTess();  initCutOut();  initCutOutVolume();  initObjects();  if (!fullscreen) {    sub1 = glutCreateMenu(numLightSamplesMenu);    glutAddMenuEntry("2", 2);    glutAddMenuEntry("3", 3);    glutAddMenuEntry("4", 4);    glutAddMenuEntry("5", 5);    glutAddMenuEntry("6", 6);    glutAddMenuEntry("7", 7);    glutAddMenuEntry("8", 8);    glutCreateMenu(menu);    glutAddMenuEntry("Toggle animation", M_ANIMATE);    glutAddMenuEntry("Volumetric shadows", M_VOLUME_SHADOWS);    glutAddMenuEntry("Soft shadows", M_SOFT_SHADOWS);    glutAddMenuEntry("No shadows", M_NO_SHADOWS);    glutAddMenuEntry("Shadow volumes", M_SHADOW_VOLUME);    glutAddMenuEntry("Planar shadows", M_PLANAR_SHADOWS);    glutAddMenuEntry("Hybrid shadows", M_HYBRID_SHADOWS);    glutAddSubMenu("Light samples", sub1);    glutAddMenuEntry("Do benchmark", M_BENCHMARK);    glutAttachMenu(GLUT_RIGHT_BUTTON);  }  if (needsStencilRenderingInvariantHack()) {    forceStencilHack = 1;  }  if (forceStencilHack) {    printf("nvshadow: using stencil hack\n");  }  /* Scale the orientations for the cut-out. */  M[0] = 0.3;  M[1] = 0.0;  M[2] = 0.0;  N[0] = 0.0;  N[1] = 0.0;  N[2] = 0.3;  glutMainLoop();  return 0;}/* Rim, body, lid, and bottom data must be reflected in x and   y; handle and spout data across the y axis only.  */static int patchdata[][16] ={    /* rim */  {102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11,    12, 13, 14, 15},    /* body */  {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,    24, 25, 26, 27},  {24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36,    37, 38, 39, 40},    /* lid */  {96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101,    101, 0, 1, 2, 3,},  {0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112,    113, 114, 115, 116, 117},    /* bottom */  {118, 118, 118, 118, 124, 122, 119, 121, 123, 126,    125, 120, 40, 39, 38, 37},    /* handle */  {41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,    53, 54, 55, 56},  {53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,    28, 65, 66, 67},    /* spout */  {68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,    80, 81, 82, 83},  {80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,    92, 93, 94, 95}};/* *INDENT-OFF* */static float cpdata[][3] ={    {0.2, 0, 2.7}, {0.2, -0.112, 2.7}, {0.112, -0.2, 2.7}, {0,    -0.2, 2.7}, {1.3375, 0, 2.53125}, {1.3375, -0.749, 2.53125},    {0.749, -1.3375, 2.53125}, {0, -1.3375, 2.53125}, {1.4375,    0, 2.53125}, {1.4375, -0.805, 2.53125}, {0.805, -1.4375,    2.53125}, {0, -1.4375, 2.53125}, {1.5, 0, 2.4}, {1.5, -0.84,    2.4}, {0.84, -1.5, 2.4}, {0, -1.5, 2.4}, {1.75, 0, 1.875},    {1.75, -0.98, 1.875}, {0.98, -1.75, 1.875}, {0, -1.75,    1.875}, {2, 0, 1.35}, {2, -1.12, 1.35}, {1.12, -2, 1.35},    {0, -2, 1.35}, {2, 0, 0.9}, {2, -1.12, 0.9}, {1.12, -2,    0.9}, {0, -2, 0.9}, {-2, 0, 0.9}, {2, 0, 0.45}, {2, -1.12,    0.45}, {1.12, -2, 0.45}, {0, -2, 0.45}, {1.5, 0, 0.225},    {1.5, -0.84, 0.225}, {0.84, -1.5, 0.225}, {0, -1.5, 0.225},    {1.5, 0, 0.15}, {1.5, -0.84, 0.15}, {0.84, -1.5, 0.15}, {0,    -1.5, 0.15}, {-1.6, 0, 2.025}, {-1.6, -0.3, 2.025}, {-1.5,    -0.3, 2.25}, {-1.5, 0, 2.25}, {-2.3, 0, 2.025}, {-2.3, -0.3,    2.025}, {-2.5, -0.3, 2.25}, {-2.5, 0, 2.25}, {-2.7, 0,    2.025}, {-2.7, -0.3, 2.025}, {-3, -0.3, 2.25}, {-3, 0,    2.25}, {-2.7, 0, 1.8}, {-2.7, -0.3, 1.8}, {-3, -0.3, 1.8},    {-3, 0, 1.8}, {-2.7, 0, 1.575}, {-2.7, -0.3, 1.575}, {-3,    -0.3, 1.35}, {-3, 0, 1.35}, {-2.5, 0, 1.125}, {-2.5, -0.3,    1.125}, {-2.65, -0.3, 0.9375}, {-2.65, 0, 0.9375}, {-2,    -0.3, 0.9}, {-1.9, -0.3, 0.6}, {-1.9, 0, 0.6}, {1.7, 0,    1.425}, {1.7, -0.66, 1.425}, {1.7, -0.66, 0.6}, {1.7, 0,    0.6}, {2.6, 0, 1.425}, {2.6, -0.66, 1.425}, {3.1, -0.66,    0.825}, {3.1, 0, 0.825}, {2.3, 0, 2.1}, {2.3, -0.25, 2.1},    {2.4, -0.25, 2.025}, {2.4, 0, 2.025}, {2.7, 0, 2.4}, {2.7,    -0.25, 2.4}, {3.3, -0.25, 2.4}, {3.3, 0, 2.4}, {2.8, 0,    2.475}, {2.8, -0.25, 2.475}, {3.525, -0.25, 2.49375},    {3.525, 0, 2.49375}, {2.9, 0, 2.475}, {2.9, -0.15, 2.475},    {3.45, -0.15, 2.5125}, {3.45, 0, 2.5125}, {2.8, 0, 2.4},    {2.8, -0.15, 2.4}, {3.2, -0.15, 2.4}, {3.2, 0, 2.4}, {0, 0,    3.15}, {0.8, 0, 3.15}, {0.8, -0.45, 3.15}, {0.45, -0.8,    3.15}, {0, -0.8, 3.15}, {0, 0, 2.85}, {1.4, 0, 2.4}, {1.4,    -0.784, 2.4}, {0.784, -1.4, 2.4}, {0, -1.4, 2.4}, {0.4, 0,    2.55}, {0.4, -0.224, 2.55}, {0.224, -0.4, 2.55}, {0, -0.4,    2.55}, {1.3, 0, 2.55}, {1.3, -0.728, 2.55}, {0.728, -1.3,    2.55}, {0, -1.3, 2.55}, {1.3, 0, 2.4}, {1.3, -0.728, 2.4},    {0.728, -1.3, 2.4}, {0, -1.3, 2.4}, {0, 0, 0}, {1.425,    -0.798, 0}, {1.5, 0, 0.075}, {1.425, 0, 0}, {0.798, -1.425,    0}, {0, -1.5, 0.075}, {0, -1.425, 0}, {1.5, -0.84, 0.075},    {0.84, -1.5, 0.075}};/* *INDENT-ON* */static voidfastTeapot(GLint grid, GLdouble scale){  float p[4][4][3], q[4][4][3], r[4][4][3], s[4][4][3];  long i, j, k, l;  glEnable(GL_AUTO_NORMAL);  glEnable(GL_MAP2_VERTEX_3);  glRotatef(270.0, 1.0, 0.0, 0.0);  glScalef(0.5 * scale, 0.5 * scale, 0.5 * scale);  glTranslatef(0.0, 0.0, -1.5);  for (i = 0; i < 10; i++) {    for (j = 0; j < 4; j++) {      for (k = 0; k < 4; k++) {        for (l = 0; l < 3; l++) {          p[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l];          q[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l];          if (l == 1)            q[j][k][l] *= -1.0;          if (i < 6) {            r[j][k][l] =              cpdata[patchdata[i][j * 4 + (3 - k)]][l];            if (l == 0)              r[j][k][l] *= -1.0;            s[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l];            if (l == 0)              s[j][k][l] *= -1.0;            if (l == 1)              s[j][k][l] *= -1.0;          }        }      }    }    glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,      &p[0][0][0]);    glMapGrid2f(grid, 0.0, 1.0, grid, 0.0, 1.0);    glEvalMesh2(GL_FILL, 0, grid, 0, grid);    glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,      &q[0][0][0]);    glEvalMesh2(GL_FILL, 0, grid, 0, grid);    if (i < 6) {      glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,        &r[0][0][0]);      glEvalMesh2(GL_FILL, 0, grid, 0, grid);      glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,        &s[0][0][0]);      glEvalMesh2(GL_FILL, 0, grid, 0, grid);    }  }}


The M and N vectors are declared like this:

double M[3], N[3]; /* Vectors to orient the cut-out. */

Any help?

"C lets you shoot yourself in the foot rather easily. C++ allows you to reuse the bullet!"
Member of the Shove Pouya Off A Cliff club, SPOAC. (If you wish to join, add this line to your signature.)Member of "Un-Ban nes8bit" association, UNA (to join put this in your sig)"C lets you shoot yourself in the foot rather easily. C++ allows you to reuse the bullet!"
lovely...
Useful information would have been a high-level description of the demo, and a snippet of relevant code.

it looks like they''re orthogonal basis vectors used to create 5 non-coplanar points. Why they''re doing that, I don''t know, and I''m not going to parse that code to find out tonight.

This topic is closed to new replies.

Advertisement