rts.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:60k
源码类别:

GIS编程

开发平台:

Visual C++

  1. /* Copyright (c) Mark J. Kilgard, 1997, 1998. */
  2. /* This program is freely distributable without licensing fees and is
  3.    provided without guarantee or warrantee expressed or implied.  This
  4.    program is -not- in the public domain. */
  5. /* Real-time Shadowing library, Version 0.97 */
  6. /* XXX This is library is not fully implemented yet, but still quite
  7.    functional. */
  8. /* XXX This code _does_ assume that you that your realloc can realloc NULL
  9.    (as specified by ANSI C).  You also should have the 1.2 version of the
  10.    OpenGL Utility (GLU) library.  SGI users need IRIX 6.2 (or higher) or IRIX 
  11.    5.3 with patch 1449 installed. */
  12. /* This code will use multiple CPUs if available in its SGI version
  13.    using IRIX's Shared Parallel Arena facility.  The generation of
  14.    silhouettes with the GLU 1.2 tessellator is farmed out to a gang for
  15.    tessellation threads. */
  16. /* This code will use Win32's multithreading and multiple CPUs if
  17.    available when compiled with the Visual C++ "/MT" option.  Just
  18.    like with the IRIX multiprocessor support, the generation of
  19.    silhouettes with the GLU 1.2 tessellator is farmed out to a gang
  20.    of tessellation threads. -mjk July 28, 1998. */
  21. /* Please do not naively assume that enabling the multiprocessor
  22.    code will make rts-based programs run any faster if you do not
  23.    have multiple CPUs.  Indeed, the extra thread overhead will in
  24.    fact likely make the program slightly slower. */
  25. #ifdef __sgi
  26. # define MP
  27. #endif
  28. #ifdef _WIN32
  29. # include <windows.h>  /* for wglGetProcAddress */
  30. # ifdef _MT  /* If Visual C++ "/MT" compiler switch specified. */
  31. #  define MP
  32. # endif
  33. #endif
  34. #ifndef NDEBUG
  35. #define NDEBUG  /* No assertions for best performance. */
  36. #endif
  37. #include <assert.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <math.h>
  41. #include <stdio.h>
  42. #ifdef MP
  43. # ifdef __sgi
  44. #  include <unistd.h>
  45. #  include <sys/prctl.h>
  46. #  include <ulocks.h>
  47. #  include <signal.h>
  48. #  include <sys/sysmp.h>
  49. # endif
  50. # ifdef _WIN32
  51. #  include <process.h>
  52. # endif
  53. #endif
  54. #include "rtshadow.h"
  55. /* The "real time shadows" (RTS) library code requires the GLU 1.2
  56.    polygon tessellator's boundary return capability to work. */
  57. #ifdef GLU_VERSION_1_2
  58. /* Win32 calling conventions. */
  59. #ifndef CALLBACK
  60. #define CALLBACK
  61. #endif
  62. /* Some <math.h> files do not define M_PI... */
  63. #ifndef M_PI
  64. #define M_PI 3.14159265358979323846
  65. #endif
  66. /* For testing... */
  67. #if 0
  68. #undef GL_VERSION_1_1
  69. #undef GL_EXT_vertex_array
  70. #endif
  71. #if defined(GL_VERSION_1_1) || defined(GL_EXT_vertex_array)
  72. static int hasVertexArray = 0;
  73. #else
  74. static const int hasVertexArray = 0;
  75. #endif
  76. #ifdef GL_EXT_blend_subtract
  77. static int hasBlendSubtract = 0;
  78. #if defined(_WIN32) && !defined(MESA)
  79. PFNGLBLENDEQUATIONEXTPROC glBlendEquationEXT = NULL;
  80. #endif
  81. #else
  82. static const int hasBlendSubtract = 0;
  83. #endif
  84. /* Coordinates. */
  85. enum {
  86.   X, Y, Z
  87. };
  88. struct VertexHolder2D {
  89.   struct VertexHolder2D *next;
  90.   GLfloat v[2];
  91. };
  92. struct VertexHolder3D {
  93.   struct VertexHolder3D *next;
  94.   GLfloat v[3];
  95. };
  96. #ifndef MP
  97. # define NUM_CONTEXTS 1
  98. # define MP_ASSERT(assertion)
  99. # define ARENA_VARIABLE(arena)
  100. # define SEMA_VARIABLE(sema)
  101. # define LOCK_VARIABLE(lock)
  102. # define THREAD_VARIABLE(thread)
  103. # define INITSEMA(arena)
  104. # define WAIT(sema)
  105. # define SIGNAL(sema)
  106. # define INITLOCK(arena)
  107. # define LOCK(lock)
  108. # define UNLOCK(lock)
  109. # define PRIVATE_MALLOC(size)        malloc(size)
  110. # define PRIVATE_FREE(ptr)           free(ptr)
  111. # define PRIVATE_REALLOC(ptr, size)  realloc(ptr, size)
  112. # define SHARED_MALLOC(size)         malloc(size)
  113. # define SHARED_FREE(ptr)            free(ptr)
  114. # define SHARED_REALLOC(ptr, size)   realloc(ptr, size)
  115. #else
  116. # define NUM_CONTEXTS 4
  117. # define MP_ASSERT(assertion)        assert(assertion)
  118. # ifdef __sgi
  119. #  define ARENA_VARIABLE(arena)      usptr_t *arena;
  120. #  define SEMA_VARIABLE(sema)        usema_t *sema;
  121. #  define LOCK_VARIABLE(lock)        ulock_t lock;
  122. #  define THREAD_VARIABLE(thread)    pid_t thread;
  123. #  define INITSEMA(arena, value)     usnewsema(arena, value)
  124. #  define WAIT(sema)                 uspsema(sema)
  125. #  define SIGNAL(sema)               usvsema(sema)
  126. #  define SAMPLE(sema)               ustestsema(sema)
  127. #  define INITLOCK(arena)            usnewlock(arena)
  128. #  define LOCK(lock)                 ussetlock(lock)
  129. #  define UNLOCK(lock)               usunsetlock(lock)
  130. #  define PRIVATE_MALLOC(size)       malloc(size)
  131. #  define PRIVATE_FREE(ptr)          free(ptr)
  132. #  define PRIVATE_REALLOC(ptr, size) realloc(ptr, size)
  133. #  define SHARED_MALLOC(size)        usmalloc(size, arena)
  134. #  define SHARED_FREE(ptr)           usfree(ptr, arena)
  135. #  define SHARED_REALLOC(ptr, size)  usrealloc(ptr, size, arena)
  136. # endif  /* __sgi */
  137. # ifdef _WIN32
  138. #  define ARENA_VARIABLE(arena)      HANDLE arena;
  139. #  define SEMA_VARIABLE(sema)        HANDLE sema;
  140. #  define LOCK_VARIABLE(lock)        HANDLE lock;
  141. #  define THREAD_VARIABLE(thread)    HANDLE thread;
  142. #  define INITSEMA(arena, value)     CreateSemaphore(NULL, value, NUM_CONTEXTS, NULL)
  143. #  define WAIT(sema)                 WaitForSingleObject(sema, INFINITE)
  144. #  define SIGNAL(sema)               ReleaseSemaphore(sema, 1, NULL)
  145.    /* Does Win32 have something cheaper than a mutex for locking? */
  146. #  define INITLOCK(arena)            CreateMutex(NULL, FALSE, NULL)
  147. #  define LOCK(lock)                 WaitForSingleObject(lock, INFINITE)
  148. #  define UNLOCK(lock)               ReleaseMutex(lock)
  149. #  define PRIVATE_MALLOC(size)       malloc(size)
  150. #  define PRIVATE_FREE(ptr)          free(ptr)
  151. #  define PRIVATE_REALLOC(ptr, size) realloc(ptr, size)
  152. #  define SHARED_MALLOC(size)        malloc(size)
  153. #  define SHARED_FREE(ptr)           free(ptr)
  154. #  define SHARED_REALLOC(ptr, size)  realloc(ptr, size)
  155. # endif  /* _WIN32 */
  156. typedef enum {
  157.   CS_UNUSED, CS_CAPTURING, CS_QUEUED, CS_GENERATING
  158. } ContextState;
  159. #endif
  160. typedef struct ShadowVolumeState ShadowVolumeState;
  161. typedef struct TessellationContext {
  162. #ifdef MP
  163.   ContextState state;
  164. #endif
  165.   RTSscene *scene;
  166.   RTSlight *light;
  167.   RTSobject *object;
  168.   ShadowVolumeState *svs;
  169.   GLUtesselator *tess;
  170.   /* For managing memory allocated by the GLU tessellator's
  171.      combine callback. */
  172.   GLfloat *combineList;
  173.   int combineListSize;
  174.   int combineNext;
  175.   struct VertexHolder2D *excessList2D;
  176.   int saveFirst;
  177.   GLfloat *firstVertex;
  178.   GLfloat *feedbackBuffer;
  179.   int feedbackBufferSize;
  180.   int feedbackBufferReturned;
  181.   GLfloat shadowProjectionDistance;
  182.   GLfloat extentScale;
  183.   int nextVertex;
  184.   int *header;
  185.   struct VertexHolder3D *excessList3D;
  186. } TessellationContext;
  187. const float uniquePassThroughValue = 34567.0;
  188. #define SmallerOf(a,b) ((a) < (b) ? (a) : (b))
  189. ARENA_VARIABLE(arena)
  190. SEMA_VARIABLE(contextAvailable)
  191. LOCK_VARIABLE(accessQueue)
  192. SEMA_VARIABLE(silhouetteNeedsGeneration)
  193. static TessellationContext *context[NUM_CONTEXTS];
  194. struct RTSscene {
  195.   GLfloat eyePos[3];
  196.   GLbitfield usableStencilBits;
  197.   int numStencilBits;
  198.   char bitList[32];
  199.   void (*renderSceneFunc) (GLenum castingLight, void *sceneData, RTSscene * scene);
  200.   void *sceneData;
  201.   SEMA_VARIABLE(silhouetteGenerationDone)
  202.   THREAD_VARIABLE(*workerPids)
  203. #ifdef MP
  204.   ShadowVolumeState *waitingForSVS;
  205. #endif
  206.   GLfloat viewScale;
  207.   GLint stencilBits;
  208.   int stencilValidateNeeded;
  209.   GLfloat sceneAmbient[4];
  210.   int lightListSize;
  211.   RTSlight **lightList;
  212.   GLboolean stencilRenderingInvariantHack;
  213. };
  214. struct ShadowVolumeState {
  215.   int lightSernum;
  216.   int objectSernum;
  217. #ifdef MP
  218.   int generationDone;
  219. #endif
  220.   int silhouetteSize;
  221.   GLfloat *silhouette;
  222.   GLfloat angle;
  223.   GLfloat axis[3];
  224.   GLfloat topScale;
  225. };
  226. struct RTSlight {
  227.   int refcnt;
  228.   int sernum;
  229.   GLenum glLight;
  230.   GLfloat lightPos[3];
  231.   GLfloat radius;
  232.   int state;
  233.   int sceneListSize;
  234.   RTSscene **sceneList;
  235.   int objectListSize;
  236.   RTSobject **objectList;
  237.   ShadowVolumeState *shadowVolumeList;
  238. };
  239. struct RTSobject {
  240.   int refcnt;
  241.   int sernum;
  242.   GLfloat objectPos[3];
  243.   GLfloat maxRadius;
  244.   void (*renderObject) (void *objectData);
  245.   void *objectData;
  246.   int feedbackBufferSizeGuess;
  247.   int state;
  248.   int lightListSize;
  249.   RTSlight **lightList;
  250. };
  251. #if defined(GL_VERSION_1_1)
  252. static int
  253. supportsOneDotOne(void)
  254. {
  255.   const char *version;
  256.   int major, minor;
  257.   version = (char *) glGetString(GL_VERSION);
  258.   if (sscanf(version, "%d.%d", &major, &minor) == 2)
  259.     return major >= 1 && minor >= 1;
  260.   return 0;             /* OpenGL version string malformed! */
  261. }
  262. #endif
  263. static int
  264. extensionSupported(const char *extension)
  265. {
  266.   static const GLubyte *extensions = NULL;
  267.   const GLubyte *start;
  268.   GLubyte *where, *terminator;
  269.   /* Extension names should not have spaces. */
  270.   where = (GLubyte *) strchr(extension, ' ');
  271.   if (where || *extension == '')
  272.     return 0;
  273.   if (!extensions)
  274.     extensions = glGetString(GL_EXTENSIONS);
  275.   /* It takes a bit of care to be fool-proof about parsing the OpenGL
  276.      extensions string.  Don't be fooled by sub-strings,  etc. */
  277.   start = extensions;
  278.   for (;;) {
  279.     where = (GLubyte *) strstr((const char *) start, extension);
  280.     if (!where)
  281.       break;
  282.     terminator = where + strlen(extension);
  283.     if (where == start || *(where - 1) == ' ') {
  284.       if (*terminator == ' ' || *terminator == '') {
  285.         return 1;
  286.       }
  287.     }
  288.     start = terminator;
  289.   }
  290.   return 0;
  291. }
  292. static GLfloat *
  293. nextVertexHolder3D(TessellationContext * context)
  294. {
  295.   struct VertexHolder3D *holder;
  296.   ShadowVolumeState *svs;
  297.   GLfloat *newHolder;
  298.   svs = context->svs;
  299.   if (context->nextVertex >= svs->silhouetteSize) {
  300.     holder = (struct VertexHolder3D *) PRIVATE_MALLOC(sizeof(struct VertexHolder3D));
  301.     if (holder == NULL) {
  302.       printf("holder alloc problemn");
  303.     }
  304.     holder->next = context->excessList3D;
  305.     context->excessList3D = holder;
  306.     newHolder = holder->v;
  307.   } else {
  308.     newHolder = &svs->silhouette[context->nextVertex * 3];
  309.   }
  310.   context->nextVertex++;
  311.   return newHolder;
  312. }
  313. /* ARGSUSED */
  314. static void CALLBACK
  315. begin(GLenum type, void *polyData)
  316. {
  317.   TessellationContext *context = polyData;
  318.   GLfloat *newHolder;
  319.   assert(type == GL_LINE_LOOP);
  320.   context->saveFirst = 1;
  321.   context->header = (int *) nextVertexHolder3D(context);
  322.   context->header[0] = context->nextVertex;
  323.   context->header[1] = 0xdeadbabe;  /* Aid assertion testing. */
  324.   context->header[2] = 0xdeadbeef;  /* Non-termintor token. */
  325.   newHolder = nextVertexHolder3D(context);
  326.   newHolder[X] = 0.0;
  327.   newHolder[Y] = 0.0;
  328.   newHolder[Z] = 0.0;
  329. }
  330. static void CALLBACK
  331. vertex(void *data, void *polyData)
  332. {
  333.   TessellationContext *context = polyData;
  334.   GLfloat *v = data;
  335.   GLfloat *newHolder;
  336.   newHolder = nextVertexHolder3D(context);
  337.   newHolder[X] = context->extentScale * v[X];
  338.   newHolder[Y] = context->extentScale * v[Y];
  339.   newHolder[Z] = context->shadowProjectionDistance;
  340.   if (context->saveFirst) {
  341.     context->firstVertex = newHolder;
  342.     context->saveFirst = 0;
  343.   }
  344. }
  345. static void CALLBACK
  346. end(void *polyData)
  347. {
  348.   TessellationContext *context = polyData;
  349.   GLfloat *newHolder;
  350.   newHolder = nextVertexHolder3D(context);
  351.   newHolder[X] = context->firstVertex[X];
  352.   newHolder[Y] = context->firstVertex[Y];
  353.   newHolder[Z] = context->firstVertex[Z];
  354.   assert(context->firstVertex[Z] == context->shadowProjectionDistance);
  355.   assert(context->header[1] == 0xdeadbabe);
  356.   assert(context->header[2] == 0xdeadbeef);
  357.   context->header[1] = context->nextVertex - context->header[0];
  358. }
  359. static void
  360. freeExcessList(TessellationContext * context)
  361. {
  362.   struct VertexHolder2D *holder, *next;
  363.   holder = context->excessList2D;
  364.   while (holder) {
  365.     next = holder->next;
  366.     PRIVATE_FREE(holder);
  367.     holder = next;
  368.   }
  369.   context->excessList2D = NULL;
  370. }
  371. /* The GLU tessellator's combine callback is called to create a
  372.    new vertex when tessellation detects an intersection or wishes
  373.    to merge features.
  374.    The memory for the new vertex must be allocated by the GLU
  375.    tessellator caller.  The caller is also responsible for this
  376.    memory's deletion.  The combineList is an array for the memory
  377.    for these combined vertices.  The array is of size combineListSize.
  378.    combineNext decides how many vertices are in use on the combineList.
  379.    The combineList is of finite size.  When this list is exhausted,
  380.    individual vertex memory is allocated via malloc in a linked list.
  381.    This is the excessList2D linked list.  After tessellation, the
  382.    combineList will be expanded by how many vertices had to be
  383.    added to the excessList2D list.  The idea is that next time the
  384.    shadow volume tessellation is done, the combineList should
  385.    hopefully be large enough.
  386. /* ARGSUSED1 */
  387. static void CALLBACK
  388. combine(GLdouble coords[3], void *d[4], GLfloat w[4],
  389.   void **dataOut, void *polyData)
  390. {
  391.   TessellationContext *context = polyData;
  392.   struct VertexHolder2D *holder;
  393.   GLfloat *newHolder;
  394.   if (context->combineNext >= context->combineListSize) {
  395.     holder = (struct VertexHolder2D *) PRIVATE_MALLOC(sizeof(struct VertexHolder2D));
  396.     if (holder == NULL) {
  397.       printf("got no holder allocn");
  398.     }
  399.     holder->next = context->excessList2D;
  400.     context->excessList2D = holder;
  401.     newHolder = holder->v;
  402.   } else {
  403.     newHolder = &context->combineList[context->combineNext * 2];
  404.   }
  405.   newHolder[0] = (GLfloat) coords[0];
  406.   newHolder[1] = (GLfloat) coords[1];
  407.   *dataOut = newHolder;
  408.   context->combineNext++;
  409. }
  410. static void CALLBACK
  411. error(GLenum errno)
  412. {
  413.   fprintf(stderr, "ERROR: %sn", gluErrorString(errno));
  414. }
  415. #ifdef DEBUG
  416. /* These verify routines are useful for asserting the sanity of
  417.    the silhouette data structures. */
  418. static void
  419. verifySilhouette(ShadowVolumeState * svs)
  420. {
  421.   int *infoPtr = (int *) svs->silhouette;
  422.   int *info = infoPtr;
  423.   int fan;
  424.   if (info[0] == 0) {
  425.     printf("2 ZEROn");
  426.   }
  427.   if (info ==0) {
  428.     printf("ZEROn");
  429.   }
  430.   fan = 0;
  431.   for (;;) {
  432.     if(info[2] == 0xdeadbeef || info[2] == 0xcafecafe) {
  433.       if (info[2] == 0xcafecafe) {
  434.         return;
  435.       }
  436.       info += ((1 + info[1]) * 3);
  437.       fan++;
  438.     } else {
  439.       printf("Corrupted silhouette! (svs=0x%x, silhouette=0x%x, fan=%d)n",
  440.         svs, svs->silhouette, fan);
  441.       abort();
  442.     }
  443.   }
  444. }
  445. static void
  446. verifySilhouettesOfScene(RTSscene *scene)
  447. {
  448.   int i, obj;
  449.   RTSlight *light;
  450.   for (i = 0; i < scene->lightListSize; i++) {
  451.     light = scene->lightList[i];
  452.     if (light) {
  453.       for (obj = 0; obj < light->objectListSize; obj++) {
  454.         ShadowVolumeState *svs;
  455.         svs = &light->shadowVolumeList[obj];
  456. if (svs && svs->generationDone) {
  457.   verifySilhouette(svs);
  458. }
  459.       }
  460.     }
  461.   }
  462. }
  463. #endif
  464. static void
  465. generateSilhouette(TessellationContext * context)
  466. {
  467.   ShadowVolumeState * svs;
  468.   GLfloat *start, *end, *loc;
  469.   GLfloat *eyeLoc;
  470.   GLdouble v[3];
  471.   int token, nvertices, i;
  472.   GLfloat passThroughToken;
  473.   int watchingForEyePos;
  474.   struct VertexHolder3D *holder, *next;
  475.   assert(context->excessList2D == NULL);
  476.   assert(context->excessList3D == NULL);
  477.   svs = context->svs;
  478.   context->nextVertex = 0;
  479.   watchingForEyePos = 0;
  480.   eyeLoc = NULL;
  481.   gluTessBeginPolygon(context->tess, context);
  482.   start = context->feedbackBuffer;
  483.   end = start + context->feedbackBufferReturned;
  484.   for (loc = start; loc < end;) {
  485.     token = *loc;
  486.     loc++;
  487.     switch (token) {
  488.     case GL_POLYGON_TOKEN:
  489.       nvertices = *loc;
  490.       loc++;
  491.       assert(nvertices >= 3);
  492.       gluTessBeginContour(context->tess);
  493.       for (i = 0; i < nvertices; i++) {
  494.         v[0] = loc[0];
  495.         v[1] = loc[1];
  496.         v[2] = 0.0;
  497.         gluTessVertex(context->tess, v, loc);
  498.         loc += 2;
  499.       }
  500.       gluTessEndContour(context->tess);
  501.       break;
  502.     case GL_PASS_THROUGH_TOKEN:
  503.       passThroughToken = *loc;
  504.       if (passThroughToken == uniquePassThroughValue) {
  505.         watchingForEyePos = !watchingForEyePos;
  506.       } else {
  507.         /* Ignore everything else. */
  508.         fprintf(stderr, "WARNING: Unexpected feedback token 0x%x (%d).n",
  509.           token, token);
  510.       }
  511.       loc++;
  512.       break;
  513.     case GL_POINT_TOKEN:
  514.       if (watchingForEyePos) {
  515.         fprintf(stderr,
  516.           "WARNING: Eye point possibly within the shadow volume.n");
  517.         fprintf(stderr,
  518.           "         Program should be improved to handle this.n");
  519.         /* XXX Write code to handle this case.  You would need to determine
  520.            if the point was instead any of the returned boundary polyons.
  521.            Once you found that you were really in the clipping volume, then I
  522.            haven't quite thought about what you do. */
  523.         eyeLoc = loc;
  524.         watchingForEyePos = 0;
  525.       } else {
  526.         /* Ignore everything else. */
  527.         fprintf(stderr, "WARNING: Unexpected feedback token 0x%x (%d).n",
  528.           token, token);
  529.       }
  530.       loc += 2;
  531.       break;
  532.     default:
  533.       /* Ignore everything else. */
  534.       fprintf(stderr, "WARING: Unexpected feedback token 0x%x (%d).n",
  535.         token, token);
  536.     }
  537.   }
  538.   gluTessEndPolygon(context->tess);
  539.   /* Free any memory that got allocated due to the combine callback during
  540.      tessellation and then enlarge the combineList so we hopefully don't need
  541.      the combine list next time. */
  542.   if (context->combineNext > context->combineListSize) {
  543.     freeExcessList(context);
  544.     context->combineListSize = context->combineNext;
  545.     SHARED_FREE(context->combineList);
  546.     context->combineList = SHARED_MALLOC(sizeof(GLfloat) * 2 * context->combineListSize);
  547.     if (context->combineList == NULL) {
  548.       printf("problem alloc context->combineListn");
  549.     }
  550.   }
  551.   context->combineNext = 0;
  552.   context->header[2] = 0xcafecafe;  /* Terminating token. */
  553.   if (context->excessList3D) {
  554. #ifndef NDEBUG
  555.     int oldSize;
  556.     oldSize = svs->silhouetteSize;
  557. #endif
  558.     assert(context->nextVertex > svs->silhouetteSize);
  559.     svs->silhouetteSize = context->nextVertex;
  560.     svs->silhouette = SHARED_REALLOC(svs->silhouette,
  561.       svs->silhouetteSize * sizeof(GLfloat) * 3);
  562.     if (svs->silhouette == NULL) {
  563.       fprintf(stderr, "libRTS: generateSilhouette: out of memoryn");
  564.       abort();
  565.     }
  566.     holder = context->excessList3D;
  567.     while (holder) {
  568.       context->nextVertex--;
  569.       svs->silhouette[context->nextVertex * 3] = holder->v[0];
  570.       svs->silhouette[context->nextVertex * 3 + 1] = holder->v[1];
  571.       svs->silhouette[context->nextVertex * 3 + 2] = holder->v[2];
  572.       next = holder->next;
  573.       PRIVATE_FREE(holder);
  574.       holder = next;
  575.     }
  576.     assert(context->nextVertex == oldSize);
  577.     context->excessList3D = NULL;
  578.   }
  579.   /* Validate shadow volume state's serial numbers. */
  580.   svs->lightSernum = context->light->sernum;
  581.   svs->objectSernum = context->object->sernum;
  582. }
  583. static int
  584. listBits(GLbitfield usableStencilBits, char bitList[32])
  585. {
  586.   int num = 0, bit = 0;
  587.   while (usableStencilBits) {
  588.     if (usableStencilBits & 0x1) {
  589.       bitList[num] = bit;
  590.       num++;
  591.     }
  592.     bit++;
  593.     usableStencilBits >>= 1;
  594.   }
  595.   return num;
  596. }
  597. /* Three element vector dot product. */
  598. static GLfloat
  599. vdot(const GLfloat * v1, const GLfloat * v2)
  600. {
  601.   return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
  602. }
  603. /* Three element vector cross product. */
  604. static void
  605. vcross(const GLfloat * v1, const GLfloat * v2, GLfloat * cross)
  606. {
  607.   assert(v1 != cross && v2 != cross);
  608.   cross[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
  609.   cross[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
  610.   cross[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
  611. }
  612. static GLfloat
  613. getViewScale(RTSscene * scene)
  614. {
  615.   if (scene->viewScale == 0.0) {
  616.     GLfloat maxViewSize[2];
  617.     glGetFloatv(GL_MAX_VIEWPORT_DIMS, maxViewSize);
  618.     scene->viewScale = SmallerOf(maxViewSize[0], maxViewSize[1]) / 2.0;
  619.     /* Other stuff piggy backs on viewScale to ensure initialization. */
  620.     glGetIntegerv(GL_STENCIL_BITS, &scene->stencilBits);
  621. #if defined(GL_VERSION_1_1)
  622.     hasVertexArray = supportsOneDotOne();
  623. #elif defined(GL_EXT_vertex_array)
  624.     hasVertexArray = extensionSupported("GL_EXT_vertex_array");
  625. #endif
  626. #ifdef GL_EXT_blend_subtract
  627.     hasBlendSubtract = extensionSupported("GL_EXT_blend_subtract");
  628. #if defined(_WIN32) && !defined(MESA)
  629.     if (hasBlendSubtract) {
  630.       glBlendEquationEXT = (PFNGLBLENDEQUATIONEXTPROC) wglGetProcAddress("glBlendEquationEXT");
  631.       if (glBlendEquationEXT == NULL) {
  632.         hasBlendSubtract = 0;
  633.       }
  634.     }
  635. #endif
  636.     /* XXX RealityEngine workaround. */
  637.     if (!strcmp((char *) glGetString(GL_VENDOR), "SGI")) {
  638.       if (!strncmp((char *) glGetString(GL_RENDERER), "RE", 2)) {
  639.         fprintf(stderr, "WARNING: RealityEngine workaround forcing additive blending.n");
  640.         hasBlendSubtract = 0;
  641.       }
  642.     }
  643. #endif
  644.   }
  645.   return scene->viewScale;
  646. }
  647. static void
  648. captureLightView(RTSscene * scene, RTSlight * light, RTSobject * object,
  649.   ShadowVolumeState * svs, TessellationContext * context)
  650. {
  651.   static GLfloat unit[3] =
  652.   {0.0, 0.0, 1.0};
  653.   int feedbackBufferSizeGuess;
  654.   GLfloat lightDelta[3], eyeDelta[3];
  655.   GLfloat lightDistance, eyeDistance, fieldOfViewRatio, viewScale;
  656.   GLdouble fieldOfViewAngle;
  657.   GLdouble nnear, ffar;  /* Avoid x86 C keywords.  Grumble. */
  658.   GLint returned;
  659.   MP_ASSERT(context->state == CS_CAPTURING);
  660.   viewScale = getViewScale(scene);
  661. #ifdef MP
  662.   svs->generationDone = 0;
  663. #endif
  664.   glMatrixMode(GL_PROJECTION);
  665.   glPushMatrix();
  666.   glLoadIdentity();
  667.   /* Calculate the light's distance from the object being shadowed. */
  668.   lightDelta[X] = object->objectPos[X] - light->lightPos[X];
  669.   lightDelta[Y] = object->objectPos[Y] - light->lightPos[Y];
  670.   lightDelta[Z] = object->objectPos[Z] - light->lightPos[Z];
  671.   lightDistance = (GLfloat) sqrt(lightDelta[X] * lightDelta[X] +
  672.     lightDelta[Y] * lightDelta[Y] + lightDelta[Z] * lightDelta[Z]);
  673.   /* Determine the appropriate field of view.  We want to use as narrow a
  674.      field of view as possible to not waste resolution, but not narrower than
  675.      the object.  Add 50% extra slop. */
  676.   fieldOfViewRatio = object->maxRadius / lightDistance;
  677.   if (fieldOfViewRatio > 0.99) {
  678.     fprintf(stderr,
  679.       "WARNING: Clamping FOV to 164 degrees for determining shadow.n");
  680.     fprintf(stderr,
  681.       "         Light distance = %g, object maxmium radius = %gn",
  682.       lightDistance, object->maxRadius);
  683.     /* 2*asin(0.99) ~= 164 degrees. */
  684.     fieldOfViewRatio = 0.99;
  685.   }
  686.   /* Pre-compute scaling factors for the near and far extent of the shadow
  687.      volume. */
  688.   context->extentScale = light->radius * fieldOfViewRatio / viewScale;
  689.   context->shadowProjectionDistance = light->radius;
  690.   nnear = 0.5 * (lightDistance - object->maxRadius);
  691.   if (nnear < 0.0001) {
  692.     fprintf(stderr,
  693.       "WARNING: Clamping near clip plane to 0.0001 because light source too near.n");
  694.     fprintf(stderr,
  695.       "         Light distance = %g, object maxmium radius = %gn",
  696.       lightDistance, object->maxRadius);
  697.     nnear = 0.0001;
  698.   }
  699.   ffar = 2.0 * (lightDistance + object->maxRadius);
  700.   eyeDelta[X] = scene->eyePos[X] - light->lightPos[X];
  701.   eyeDelta[Y] = scene->eyePos[Y] - light->lightPos[Y];
  702.   eyeDelta[Z] = scene->eyePos[Z] - light->lightPos[Z];
  703.   eyeDistance = 1.05 *
  704.     sqrt(eyeDelta[X] * eyeDelta[X] + eyeDelta[Y] * eyeDelta[Y]
  705.     + eyeDelta[Z] * eyeDelta[Z]);
  706.   if (eyeDistance > ffar) {
  707.     ffar = eyeDistance;
  708.   }
  709.   fieldOfViewAngle = 2.0 * asin(fieldOfViewRatio) * 180 / M_PI;
  710.   gluPerspective(fieldOfViewAngle, 1.0, nnear, ffar);
  711.   glMatrixMode(GL_MODELVIEW);
  712.   glPushMatrix();
  713.   glLoadIdentity();
  714.   /* XXX Look up vector needs adjusting. */
  715.   gluLookAt(light->lightPos[X], light->lightPos[Y], light->lightPos[Z],
  716.     object->objectPos[X], object->objectPos[Y], object->objectPos[Z],
  717.     0.0, 1.0, 0.0);     /* up is in positive Y direction */
  718.   glPushAttrib(GL_VIEWPORT_BIT);
  719.   glViewport(-viewScale, -viewScale, 2 * viewScale, 2 * viewScale);
  720.   feedbackBufferSizeGuess = object->feedbackBufferSizeGuess;
  721. doFeedback:
  722.   if (feedbackBufferSizeGuess > context->feedbackBufferSize) {
  723.     context->feedbackBufferSize = feedbackBufferSizeGuess;
  724.     object->feedbackBufferSizeGuess = feedbackBufferSizeGuess;
  725.     /* A "free & malloc" is better than a "realloc" below because we
  726.        do not care for the previous buffer contents to be preserved. */
  727.     /* XXX Add 32 words of slop (an extra cache line) to end for buggy
  728.        hardware that uses DMA to return feedback results but that sometimes
  729.        overrun the buffer.  Yuck. */
  730.     SHARED_FREE(context->feedbackBuffer);
  731.     context->feedbackBuffer = (GLfloat *)
  732.       SHARED_MALLOC(context->feedbackBufferSize * sizeof(GLfloat) + 32 * 4);
  733.     if (context->feedbackBuffer == NULL) {
  734.       fprintf(stderr, "libRTS: captureLightView: out of memoryn");
  735.       abort();
  736.     }
  737.   }
  738.   glFeedbackBuffer(context->feedbackBufferSize,
  739.     GL_2D, context->feedbackBuffer);
  740.   (void) glRenderMode(GL_FEEDBACK);
  741.   /* Render the eye position.  The eye position is "bracketed" by unique pass
  742.      through tokens.  These bracketing pass through tokens let us determine if
  743.      the eye position was clipped or not.  This helps us determine whether  the
  744.      eye position is possibly within the shadow volume or not.  If the point is
  745.      clipped, the eye position is not in the shadow volume.  If the point is
  746.      not clipped, a more complicated test is necessary to determine if the eye
  747.      position is really in the shadow volume or not.  See generateSilhouette. */
  748.   glPassThrough(uniquePassThroughValue);
  749.   glBegin(GL_POINTS);
  750.   glVertex3fv(scene->eyePos);
  751.   glEnd();
  752.   glPassThrough(uniquePassThroughValue);
  753.   (object->renderObject) (object->objectData);
  754.   returned = glRenderMode(GL_RENDER);
  755.   assert(returned <= context->feedbackBufferSize);
  756. #if 0
  757.   if (returned == -1) {
  758. #else
  759.   /* XXX RealityEngine workaround. */
  760.   if (returned == -1 || returned == context->feedbackBufferSize) {
  761. #endif
  762.     feedbackBufferSizeGuess = context->feedbackBufferSize
  763.       + (context->feedbackBufferSize >> 1);
  764.     goto doFeedback;    /* Try again with larger feedback buffer. */
  765.   }
  766.   glMatrixMode(GL_PROJECTION);
  767.   glPopMatrix();
  768.   glMatrixMode(GL_MODELVIEW);
  769.   glPopMatrix();
  770.   glPopAttrib();        /* Restore viewport. */
  771.   vcross(unit, lightDelta, svs->axis);
  772.   svs->angle = (GLfloat) acos(vdot(unit, lightDelta) / lightDistance) * 180.0 / M_PI;
  773.   svs->topScale = (lightDistance + object->maxRadius) / light->radius;
  774.   context->feedbackBufferReturned = returned;
  775.   context->scene = scene;
  776.   context->light = light;
  777.   context->object = object;
  778.   context->svs = svs;
  779. }
  780. static TessellationContext *
  781. createTessellationContext(void)
  782. {
  783.   TessellationContext *context;
  784.   GLUtesselator *tess;
  785.   context = (TessellationContext *) SHARED_MALLOC(sizeof(TessellationContext));
  786.   if (context == NULL) {
  787.     printf("TessellationContext alloc failedn");
  788.     return NULL;
  789.   }
  790.   tess = gluNewTess();
  791.   if (tess == NULL) {
  792.     SHARED_FREE(context);
  793.     return NULL;
  794.   }
  795.   gluTessProperty(tess, GLU_TESS_BOUNDARY_ONLY, GL_TRUE);
  796.   gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
  797.   gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (void (CALLBACK*)()) &begin);
  798.   gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (void (CALLBACK*)()) &vertex);
  799.   gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (void (CALLBACK*)()) &combine);
  800.   gluTessCallback(tess, GLU_TESS_END_DATA, (void (CALLBACK*)()) &end);
  801.   gluTessCallback(tess, GLU_TESS_ERROR, error);
  802.   context->tess = tess;
  803. #ifdef MP
  804.   context->state = CS_UNUSED;
  805. #endif
  806.   context->combineListSize = 0;
  807.   context->combineList = NULL;
  808.   context->combineNext = 0;
  809.   context->excessList2D = NULL;
  810.   context->feedbackBufferSize = 0;
  811.   context->feedbackBuffer = NULL;
  812.   context->excessList3D = NULL;
  813.   return context;
  814. }
  815. #ifdef MP
  816. static void
  817. work(void)
  818. {
  819.   TessellationContext *workContext;
  820.   RTSscene *scene;
  821.   int i;
  822.     WAIT(silhouetteNeedsGeneration);
  823.     LOCK(accessQueue);
  824.     workContext = NULL;
  825.     for (i=0; i<NUM_CONTEXTS; i++) {
  826.       if (context[i]->state == CS_QUEUED) {
  827.         workContext = context[i];
  828. break;
  829.       }
  830.     }
  831.     assert(workContext);
  832.     workContext->state = CS_GENERATING;
  833.     UNLOCK(accessQueue);
  834.     generateSilhouette(workContext);
  835.     LOCK(accessQueue);
  836.     assert(workContext->state == CS_GENERATING);
  837.     workContext->state = CS_UNUSED;
  838.     workContext->svs->generationDone = 1;
  839.     scene = workContext->scene;
  840.     /* If the main thread is sleeping on this particular
  841.        shadow volume, wake up the main thread. */
  842.     if (workContext->svs == scene->waitingForSVS) {
  843.       scene->waitingForSVS = NULL;
  844.       SIGNAL(scene->silhouetteGenerationDone);
  845.     }
  846.     UNLOCK(accessQueue);
  847.     SIGNAL(contextAvailable);
  848. }
  849. static void
  850. waitForSilhouetteGenerationDone(RTSscene * scene, ShadowVolumeState *svs)
  851. {
  852.   LOCK(accessQueue);
  853.   if (svs->generationDone == 0) {
  854.     scene->waitingForSVS = svs;
  855.     UNLOCK(accessQueue);
  856.     WAIT(scene->silhouetteGenerationDone);
  857.     assert(svs->generationDone);
  858.   } else {
  859.     UNLOCK(accessQueue);
  860.   }
  861. }
  862. #ifdef __sgi
  863. static void
  864. worker(void)
  865. {
  866.   signal(SIGHUP, SIG_DFL);
  867.   prctl(PR_TERMCHILD);
  868.   usadd(arena);
  869.   for (;;) {
  870.     work();
  871.   }
  872. }
  873. static void
  874. setupArena(int numWorkers)
  875. {
  876.   static int beenhere = 0;
  877.   int i;
  878.   THREAD_VARIABLE(pid)
  879.   if (beenhere) {
  880.     return;
  881.   }
  882.   beenhere = 1;
  883.   usconfig(CONF_INITUSERS, 1 + numWorkers);
  884.   usconfig(CONF_ARENATYPE, US_SHAREDONLY);
  885.   usconfig(CONF_INITSIZE, 1024 * 1024);
  886.   arena = usinit("/dev/zero");
  887.   if (arena == NULL) {
  888.     fprintf(stderr, "libRTS: could not create arena.n");
  889.     exit(1);
  890.   }
  891.   for (i=0; i<NUM_CONTEXTS; i++) {
  892.     context[i] = createTessellationContext();
  893.   }
  894.   contextAvailable = INITSEMA(arena, NUM_CONTEXTS);
  895.   accessQueue = INITLOCK(arena);
  896.   silhouetteNeedsGeneration = INITSEMA(arena, 0);
  897.   for (i=0; i<numWorkers; i++) {
  898.     pid = fork();
  899.     if (pid == -1) {
  900.       perror("fork");
  901.       exit(1);
  902.     }
  903.     if (pid == 0) {
  904.       worker();
  905.     }
  906.   }
  907. }
  908. #endif  /* __sgi */
  909. #ifdef _WIN32
  910. static void
  911. worker(void *unused)
  912. {
  913.   for (;;) {
  914.     work();
  915.   }
  916. }
  917. static void
  918. setupArena(int numWorkers)
  919. {
  920.   static int beenhere = 0;
  921.   int i;
  922.   unsigned long retval;
  923.   if (beenhere) {
  924.     return;
  925.   }
  926.   beenhere = 1;
  927.   for (i=0; i<NUM_CONTEXTS; i++) {
  928.     context[i] = createTessellationContext();
  929.   }
  930.   contextAvailable = INITSEMA(arena, NUM_CONTEXTS);
  931.   accessQueue = INITLOCK(arena);
  932.   silhouetteNeedsGeneration = INITSEMA(arena, 0);
  933.   for (i=0; i<numWorkers; i++) {
  934.     retval = _beginthread(worker, 0, NULL);
  935.     if (retval == -1) {
  936.       perror("_beginthread");
  937.       exit(1);
  938.     }
  939.   }
  940. }
  941. #endif  /* _WIN32 */
  942. #endif  /* MP */
  943. RTSscene *
  944. rtsCreateScene(
  945.   GLfloat eyePos[3],
  946.   GLbitfield usableStencilBits,
  947.   void (*renderSceneFunc) (GLenum castingLight, void *sceneData, RTSscene * scene),
  948.   void *sceneData)
  949. {
  950.   RTSscene *scene;
  951. #ifdef MP
  952. # ifdef __sgi
  953.   int numProcessors = (int) sysmp(MP_NAPROCS);
  954.   printf("numProcesasors = %dn", numProcessors);
  955.   setupArena(SmallerOf(4, numProcessors));
  956. # endif
  957. # ifdef _WIN32
  958.   int numProcessors = 2;
  959.   printf("numProcessors = %dn", numProcessors);
  960.   setupArena(numProcessors);
  961. # endif
  962. #else
  963.   context[0] = createTessellationContext();
  964. #endif
  965.   scene = (RTSscene *) SHARED_MALLOC(sizeof(RTSscene));
  966.   if (scene == NULL) {
  967.     printf("rtsCreateScene alloc failedn");
  968.     return NULL;
  969.   }
  970. #ifdef MP
  971.   scene->silhouetteGenerationDone = INITSEMA(arena, 0);
  972.   scene->waitingForSVS = NULL;
  973. #endif
  974.   scene->eyePos[X] = eyePos[X];
  975.   scene->eyePos[Y] = eyePos[Y];
  976.   scene->eyePos[Z] = eyePos[Z];
  977.   scene->usableStencilBits = usableStencilBits;
  978.   scene->renderSceneFunc = renderSceneFunc;
  979.   scene->sceneData = sceneData;
  980.   scene->viewScale = 0.0;  /* 0.0 means "to be determined". */
  981.   scene->stencilValidateNeeded = 1;
  982.   scene->sceneAmbient[0] = 0.2;
  983.   scene->sceneAmbient[1] = 0.2;
  984.   scene->sceneAmbient[2] = 0.2;
  985.   scene->sceneAmbient[3] = 1.0;
  986.   scene->lightListSize = 0;
  987.   scene->lightList = NULL;
  988.   scene->stencilRenderingInvariantHack = GL_FALSE;
  989.   return scene;
  990. }
  991. RTSlight *
  992. rtsCreateLight(
  993.   GLenum glLight,
  994.   GLfloat lightPos[3],
  995.   GLfloat radius)
  996. {
  997.   RTSlight *light;
  998.   light = (RTSlight *) SHARED_MALLOC(sizeof(RTSlight));
  999.   if (light == NULL) {
  1000.     printf("rtsCreateLight failedn");
  1001.     return NULL;
  1002.   }
  1003.   light->refcnt = 1;
  1004.   light->sernum = 1;
  1005.   light->glLight = glLight;
  1006.   light->lightPos[X] = lightPos[X];
  1007.   light->lightPos[Y] = lightPos[Y];
  1008.   light->lightPos[Z] = lightPos[Z];
  1009.   light->radius = radius;
  1010.   light->state = RTS_SHINING_AND_CASTING;
  1011.   light->sceneListSize = 0;
  1012.   light->sceneList = NULL;
  1013.   light->objectListSize = 0;
  1014.   light->objectList = NULL;
  1015.   light->shadowVolumeList = NULL;
  1016.   return light;
  1017. }
  1018. RTSobject *
  1019. rtsCreateObject(
  1020.   GLfloat objectPos[3],
  1021.   GLfloat maxRadius,
  1022.   void (*renderObject) (void *objectData),
  1023.   void *objectData,
  1024.   int feedbackBufferSizeGuess)
  1025. {
  1026.   RTSobject *object;
  1027.   object = (RTSobject *) SHARED_MALLOC(sizeof(RTSobject));
  1028.   if (object == NULL) {
  1029.     printf("rtsCreateObject failedn");
  1030.     return NULL;
  1031.   }
  1032.   object->refcnt = 1;
  1033.   object->sernum = 1;
  1034.   object->objectPos[X] = objectPos[X];
  1035.   object->objectPos[Y] = objectPos[Y];
  1036.   object->objectPos[Z] = objectPos[Z];
  1037.   object->maxRadius = maxRadius;
  1038.   object->renderObject = renderObject;
  1039.   object->objectData = objectData;
  1040.   object->feedbackBufferSizeGuess = feedbackBufferSizeGuess;
  1041. #ifdef __sgi
  1042.   /* XXX Impact/Octane feedback bug work around.  If the feedback
  1043.      buffer on Impact/Octane is less than 2048 entries, a buggy
  1044.      hardware accelerated path is used.  Make sure at least 2049
  1045.      entries for the feedback buffer; this forces Impact/Octane to use
  1046.      the (bug free) software feedback path.  This bug is fixed in IRIX
  1047.      6.5. */
  1048.   if (object->feedbackBufferSizeGuess < 2048) {
  1049.     object->feedbackBufferSizeGuess = 2048;
  1050.   }
  1051. #endif
  1052.   object->state = RTS_SHADOWING;
  1053.   object->lightListSize = 0;
  1054.   object->lightList = NULL;
  1055.   return object;
  1056. }
  1057. void
  1058. rtsAddLightToScene(
  1059.   RTSscene * scene,
  1060.   RTSlight * light)
  1061. {
  1062.   int i;
  1063.   for (i = 0; i < light->sceneListSize; i++) {
  1064.     if (light->sceneList[i] == scene) {
  1065.       return;
  1066.     }
  1067.     if (light->sceneList[i] == NULL) {
  1068.       goto addToSceneList;
  1069.     }
  1070.   }
  1071.   light->sceneListSize++;
  1072.   light->sceneList = (RTSscene **) SHARED_REALLOC(light->sceneList,
  1073.     light->sceneListSize * sizeof(RTSscene *));
  1074.   if (light->sceneList == NULL) {
  1075.     fprintf(stderr, "rtsAddLightToScene: out of memoryn");
  1076.     abort();
  1077.   }
  1078. addToSceneList:
  1079.   light->sceneList[i] = scene;
  1080.   for (i = 0; i < scene->lightListSize; i++) {
  1081.     if (scene->lightList[i] == light) {
  1082.       fprintf(stderr, "rtsAddLightToScene: inconsistent listsn");
  1083.       abort();
  1084.     }
  1085.     if (scene->lightList[i] == NULL) {
  1086.       goto addToLightList;
  1087.     }
  1088.   }
  1089.   scene->lightListSize++;
  1090.   scene->lightList = (RTSlight **) SHARED_REALLOC(scene->lightList,
  1091.     scene->lightListSize * sizeof(RTSlight *));
  1092.   if (scene->lightList == NULL) {
  1093.     fprintf(stderr, "rtsAddLightToScene: out of memoryn");
  1094.     abort();
  1095.   }
  1096. addToLightList:
  1097.   scene->lightList[i] = light;
  1098.   light->refcnt++;
  1099. }
  1100. static void
  1101. initShadowVolumeState(ShadowVolumeState * svs)
  1102. {
  1103.   svs->lightSernum = 0;
  1104.   svs->objectSernum = 0;
  1105.   svs->silhouette = NULL;
  1106.   svs->silhouetteSize = 0;
  1107. #ifdef MP
  1108.   svs->generationDone = 0;
  1109. #endif
  1110. }
  1111. void
  1112. rtsAddObjectToLight(
  1113.   RTSlight * light,
  1114.   RTSobject * object)
  1115. {
  1116.   int i;
  1117.   for (i = 0; i < object->lightListSize; i++) {
  1118.     if (object->lightList[i] == light) {
  1119.       return;
  1120.     }
  1121.     if (object->lightList[i] == NULL) {
  1122.       goto addToLightList;
  1123.     }
  1124.   }
  1125.   object->lightListSize++;
  1126.   object->lightList = (RTSlight **) SHARED_REALLOC(object->lightList,
  1127.     object->lightListSize * sizeof(RTSlight *));
  1128.   if (object->lightList == NULL) {
  1129.     fprintf(stderr, "rtsAddObjectToLight: out of memoryn");
  1130.     abort();
  1131.   }
  1132. addToLightList:
  1133.   object->lightList[i] = light;
  1134.   for (i = 0; i < light->objectListSize; i++) {
  1135.     if (light->objectList[i] == object) {
  1136.       fprintf(stderr, "rtsAddObjectToLight: inconsistent listsn");
  1137.       abort();
  1138.     }
  1139.     if (light->objectList[i] == NULL) {
  1140.       goto addToObjectList;
  1141.     }
  1142.   }
  1143.   /* Extend object list. */
  1144.   light->objectListSize++;
  1145.   light->objectList = (RTSobject **) SHARED_REALLOC(light->objectList,
  1146.     light->objectListSize * sizeof(RTSscene *));
  1147.   if (light->objectList == NULL) {
  1148.     fprintf(stderr, "rtsAddObjectToLight: out of memoryn");
  1149.     abort();
  1150.   }
  1151.   /* Extend shadow volume list. */
  1152.   light->shadowVolumeList = (ShadowVolumeState *)
  1153.     SHARED_REALLOC(light->shadowVolumeList,
  1154.     light->objectListSize * sizeof(ShadowVolumeState));
  1155.   if (light->shadowVolumeList == NULL) {
  1156.     fprintf(stderr, "rtsAddObjectToLight: out of memoryn");
  1157.     abort();
  1158.   }
  1159. addToObjectList:
  1160.   initShadowVolumeState(&light->shadowVolumeList[i]);
  1161.   light->objectList[i] = object;
  1162.   light->refcnt++;
  1163.   object->refcnt++;
  1164. }
  1165. void
  1166. rtsSetLightState(
  1167.   RTSlight * light,
  1168.   RTSlightState state)
  1169. {
  1170.   light->state = state;
  1171. }
  1172. void
  1173. rtsSetObjectState(
  1174.   RTSobject * object,
  1175.   RTSobjectState state)
  1176. {
  1177.   object->state = state;
  1178. }
  1179. void
  1180. rtsUpdateEyePos(
  1181.   RTSscene * scene,
  1182.   GLfloat eyePos[3])
  1183. {
  1184.   scene->eyePos[X] = eyePos[X];
  1185.   scene->eyePos[Y] = eyePos[Y];
  1186.   scene->eyePos[Z] = eyePos[Z];
  1187. }
  1188. void
  1189. rtsUpdateUsableStencilBits(
  1190.   RTSscene * scene,
  1191.   GLbitfield usableStencilBits)
  1192. {
  1193.   scene->usableStencilBits = usableStencilBits;
  1194.   scene->stencilValidateNeeded = 1;
  1195. }
  1196. void
  1197. rtsUpdateLightPos(
  1198.   RTSlight * light,
  1199.   GLfloat lightPos[3])
  1200. {
  1201.   light->lightPos[X] = lightPos[X];
  1202.   light->lightPos[Y] = lightPos[Y];
  1203.   light->lightPos[Z] = lightPos[Z];
  1204.   light->sernum++;
  1205. }
  1206. void
  1207. rtsUpdateLightRadius(
  1208.   RTSlight * light,
  1209.   GLfloat radius)
  1210. {
  1211.   light->radius = radius;
  1212.   light->sernum++;
  1213. }
  1214. void
  1215. rtsUpdateObjectPos(
  1216.   RTSobject * object,
  1217.   GLfloat objectPos[3])
  1218. {
  1219.   object->objectPos[X] = objectPos[X];
  1220.   object->objectPos[Y] = objectPos[Y];
  1221.   object->objectPos[Z] = objectPos[Z];
  1222.   object->sernum++;
  1223. }
  1224. void
  1225. rtsUpdateObjectShape(
  1226.   RTSobject * object)
  1227. {
  1228.   object->sernum++;
  1229. }
  1230. void
  1231. rtsUpdateObjectMaxRadius(
  1232.   RTSobject * object,
  1233.   GLfloat maxRadius)
  1234. {
  1235.   object->maxRadius = maxRadius;
  1236.   object->sernum++;
  1237. }
  1238. #if defined(GL_EXT_vertex_array) && !defined(GL_VERSION_1_1)
  1239. /* Only needed if has vertex array extension, but no OpenGL 1.1. */
  1240. static void
  1241. setupVertexArray(ShadowVolumeState * svs, int numCoordinates)
  1242. {
  1243.   glDisable(GL_EDGE_FLAG_ARRAY_EXT);
  1244.   glEnable(GL_VERTEX_ARRAY_EXT);
  1245.   glDisable(GL_NORMAL_ARRAY_EXT);
  1246.   glDisable(GL_COLOR_ARRAY_EXT);
  1247.   glDisable(GL_TEXTURE_COORD_ARRAY_EXT);
  1248.   glDisable(GL_EDGE_FLAG_ARRAY_EXT);
  1249.   glVertexPointerEXT(numCoordinates, GL_FLOAT, 3 * sizeof(GLfloat), svs->silhouetteSize, svs->silhouette);
  1250. }
  1251. #endif
  1252. static void
  1253. renderSilhouette(ShadowVolumeState * svs)
  1254. {
  1255.   int *infoPtr = (int *) svs->silhouette;
  1256.   int *info = infoPtr;
  1257.   int end, i;
  1258.   /* CONSTANTCONDITION */
  1259.   assert(sizeof(GLfloat) == sizeof(GLint));
  1260.   if (hasVertexArray) {
  1261. #if defined(GL_VERSION_1_1)
  1262.     glInterleavedArrays(GL_V2F, 3 * sizeof(GLfloat), svs->silhouette);
  1263. #elif defined(GL_EXT_vertex_array)
  1264.     setupVertexArray(svs, 2);
  1265. #endif
  1266.   }
  1267.   for (;;) {
  1268.     assert(info[2] == 0xdeadbeef || info[2] == 0xcafecafe);
  1269.     /* Two fewer vertices get rendered in the renderSilhouette case (compared
  1270.        to renderShadowVolumeBase) because because a line loop does not need
  1271.        the initial fan center or the final repeated first vertex. */
  1272.     if (hasVertexArray) {
  1273. #if defined(GL_VERSION_1_1)
  1274.       glDrawArrays(GL_LINE_LOOP, info[0] + 1, info[1] - 2);
  1275. #elif defined(GL_EXT_vertex_array)
  1276.       glDrawArraysEXT(GL_LINE_LOOP, info[0] + 1, info[1] - 2);
  1277. #endif
  1278.     } else {
  1279.       glBegin(GL_LINE_LOOP);
  1280.       end = info[0] + info[1] - 2;
  1281.       for (i = info[0] + 1; i < end; i++) {
  1282.         glVertex2fv(&svs->silhouette[i * 3]);
  1283.       }
  1284.       glEnd();
  1285.     }
  1286.     if (info[2] == 0xcafecafe) {
  1287.       return;
  1288.     }
  1289.     info += ((1 + info[1]) * 3);
  1290.   }
  1291. }
  1292. static void
  1293. renderShadowVolumeBase(ShadowVolumeState * svs)
  1294. {
  1295.   int *infoPtr = (int *) svs->silhouette;
  1296.   int *info = infoPtr;
  1297.   int end, i;
  1298.   int fan;
  1299.   fan = 0;
  1300.   /* CONSTANTCONDITION */
  1301.   assert(sizeof(GLfloat) == sizeof(GLint));
  1302.   glRotatef(svs->angle, svs->axis[X], svs->axis[Y], svs->axis[Z]);
  1303.   for (;;) {
  1304.     assert((info[2] == 0xdeadbeef || info[2] == 0xcafecafe) && info[1] > 0);
  1305.     if (hasVertexArray) {
  1306.       /* Note: assumes that glInterleavedArrays has already been called. */
  1307. #if defined(GL_VERSION_1_1)
  1308.       glDrawArrays(GL_TRIANGLE_FAN, info[0], info[1]);
  1309. #elif defined(GL_EXT_vertex_array)
  1310.       glDrawArraysEXT(GL_TRIANGLE_FAN, info[0], info[1]);
  1311. #endif
  1312.     } else {
  1313.       glBegin(GL_TRIANGLE_FAN);
  1314.       end = info[0] + info[1];
  1315.       for (i = info[0]; i < end; i++) {
  1316.         glVertex3fv(&svs->silhouette[i * 3]);
  1317.       }
  1318.       glEnd();
  1319.     }
  1320.     if (info[2] == 0xcafecafe) {
  1321.       return;
  1322.     }
  1323.     assert(info[1] > 0);
  1324.     info += ((1 + info[1]) * 3);
  1325.     fan++;
  1326.   }
  1327. }
  1328. static void
  1329. renderShadowVolume(ShadowVolumeState * svs, GLfloat lightPos[3])
  1330. {
  1331.   glPushMatrix();
  1332.   glTranslatef(lightPos[X], lightPos[Y], lightPos[Z]);
  1333.   renderShadowVolumeBase(svs);
  1334.   glPopMatrix();
  1335. }
  1336. static void
  1337. renderShadowVolumeTop(ShadowVolumeState * svs, GLfloat lightPos[3])
  1338. {
  1339.   glPushMatrix();
  1340.   glTranslatef(lightPos[X], lightPos[Y], lightPos[Z]);
  1341.   glScalef(svs->topScale, svs->topScale, svs->topScale);
  1342.   renderShadowVolumeBase(svs);
  1343.   glPopMatrix();
  1344. }
  1345. static void
  1346. validateShadowVolume(RTSscene * scene, RTSlight * light,
  1347.   RTSobject * object, ShadowVolumeState * svs)
  1348. {
  1349.   /* Serial number mismatch indicates light or object has changed since last
  1350.      shadow volume generation. If mismatch, regenerate the shadow volume. */
  1351.   if (light->sernum != svs->lightSernum
  1352.     || object->sernum != svs->objectSernum) {
  1353.     TessellationContext *workContext;
  1354. #ifdef MP
  1355.     int i;
  1356.     WAIT(contextAvailable);
  1357.     LOCK(accessQueue);
  1358.     workContext = NULL;
  1359.     for (i=0; i<NUM_CONTEXTS; i++) {
  1360.       if (context[i]->state == CS_UNUSED) {
  1361.         workContext = context[i];
  1362. break;
  1363.       }
  1364.     }
  1365.     assert(workContext);
  1366.     workContext->state = CS_CAPTURING;
  1367.     UNLOCK(accessQueue);
  1368.     captureLightView(scene, light,
  1369.       object, svs, workContext);
  1370.     
  1371.     workContext->state = CS_QUEUED;
  1372.     SIGNAL(silhouetteNeedsGeneration);
  1373. #else
  1374.     workContext = context[0];
  1375.     captureLightView(scene, light,
  1376.       object, svs, workContext);
  1377.     generateSilhouette(workContext);
  1378. #endif
  1379.   }
  1380. }
  1381. void
  1382. rtsRenderScene(
  1383.   RTSscene * scene,
  1384.   RTSmode mode)
  1385. {
  1386.   static GLfloat totalDarkness[4] =
  1387.   {0.0, 0.0, 0.0, 0.0};
  1388.   int i, obj, bit;
  1389.   int numStencilBits, numCastingLights, numShadowingObjects;
  1390.   RTSlight *firstLight, *prevLight, *light;
  1391.   RTSobject *object;
  1392.   GLbitfield fullStencilMask;
  1393.   /* Expect application (caller) to do the glClear (including stencil). */
  1394.   /* Expect application (caller) to enable depth testing. */
  1395.   if (mode != RTS_NO_SHADOWS) {
  1396.     /* Validate shadow volumes, count casting lights, and stash the first
  1397.        light. */
  1398.     numCastingLights = 0;
  1399.     firstLight = NULL;
  1400.     for (i = 0; i < scene->lightListSize; i++) {
  1401.       light = scene->lightList[i];
  1402.       if (light) {
  1403.         if (light->state != RTS_OFF) {
  1404.           if (light->state == RTS_SHINING_AND_CASTING) {
  1405.             if (numCastingLights == 0) {
  1406.               /* Count number of shadowing objects. */
  1407.               numShadowingObjects = 0;
  1408.               for (obj = 0; obj < light->objectListSize; obj++) {
  1409.                 if (light->objectList[obj]->state == RTS_SHADOWING) {
  1410.                   numShadowingObjects++;
  1411.                 }
  1412.               }
  1413.               if (numShadowingObjects == 0) {
  1414.                 /* Not casting on any object; skip it. */
  1415.                 continue;
  1416.               }
  1417.               assert(firstLight == NULL);
  1418.               firstLight = light;
  1419.             }
  1420.             numCastingLights++;
  1421.             if (numCastingLights == 1 || hasBlendSubtract) {
  1422.               glEnable(light->glLight);
  1423.             } else {
  1424.               glDisable(light->glLight);
  1425.             }
  1426.             for (obj = 0; obj < light->objectListSize; obj++) {
  1427.               object = light->objectList[obj];
  1428.               if (object->state == RTS_SHADOWING) {
  1429.                 ShadowVolumeState *svs;
  1430.                 svs = &light->shadowVolumeList[obj];
  1431.                 validateShadowVolume(scene, light, object, svs);
  1432.               }
  1433.             }
  1434.           } else if (light->state == RTS_SHINING_AND_CASTING) {
  1435.             glEnable(light->glLight);
  1436.           }
  1437.         } else {
  1438.           glDisable(light->glLight);
  1439.         }
  1440.       }
  1441.     }
  1442.   }
  1443.   glEnable(GL_LIGHTING);
  1444.   glEnable(GL_CULL_FACE);
  1445.   if (scene->stencilRenderingInvariantHack) {
  1446.     glEnable(GL_STENCIL_TEST);
  1447.     glStencilFunc(GL_ALWAYS, 0, 0xffffffff);
  1448.     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  1449.   } else {
  1450.     /* XXX Note that the non-hack case does not enable or
  1451.        disable stencil.  The hack case enables stencil
  1452.        testing but sets up the stencil modes so that stencil
  1453.        testing is effectively disabled.  If you wanted
  1454.        stencil testing on during the renderSceneFunc, you won't
  1455.        need to have the hack enabled though! */
  1456.   }
  1457.   scene->renderSceneFunc(GL_NONE, scene->sceneData, scene);
  1458.   if (mode == RTS_NO_SHADOWS) {
  1459.     return;
  1460.   }
  1461.   if (numCastingLights == 0) {
  1462.     /* No lights, no shadows. */
  1463.     return;
  1464.   }
  1465.   assert(firstLight);
  1466.   assert(numShadowingObjects > 0);
  1467.   /* Determine exactly which stencil bits usable for shadowing. */
  1468.   if (scene->stencilValidateNeeded) {
  1469.     GLbitfield shadowStencilBits;
  1470.     shadowStencilBits = scene->usableStencilBits & ((1 << scene->stencilBits) - 1);
  1471.     scene->numStencilBits = listBits(shadowStencilBits, scene->bitList);
  1472.     if (scene->numStencilBits == 0) {
  1473.       fprintf(stderr,
  1474.         "WARNING: No stencil bits available for shadowing, expect bad results.n");
  1475.       fprintf(stderr,
  1476.         "         Frame buffer stencil bits = %d, usable stencil bits = 0x%x.n",
  1477.         scene->stencilBits, scene->usableStencilBits);
  1478.     }
  1479.     scene->stencilValidateNeeded = 0;
  1480.   }
  1481.   numStencilBits = scene->numStencilBits;
  1482.   /* The first light is easier than the rest since we need subtractive
  1483.      blending for two or more lights. Do the first light the fast way. */
  1484.   bit = 0;
  1485.   assert(scene->stencilValidateNeeded == 0);
  1486.   glDisable(firstLight->glLight);
  1487.   glEnable(GL_STENCIL_TEST);
  1488.   glDepthMask(GL_FALSE);
  1489.   obj = 0;
  1490.   while (firstLight->objectList[obj]->state == RTS_NOT_SHADOWING) {
  1491.     obj++;
  1492.   }
  1493.   do {
  1494.     assert(bit < numStencilBits);
  1495.     assert(firstLight->objectList[obj]->state == RTS_SHADOWING);
  1496.     assert(obj < firstLight->objectListSize);
  1497.     fullStencilMask = 0;
  1498.     glDisable(GL_LIGHTING);
  1499.     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  1500.     glDisable(GL_CULL_FACE);
  1501.     glStencilFunc(GL_ALWAYS, 0, 0);
  1502.     do {
  1503. #ifdef MP
  1504.       waitForSilhouetteGenerationDone(scene, &firstLight->shadowVolumeList[obj]);
  1505. #endif
  1506.       if (hasVertexArray) {
  1507. #if defined(GL_VERSION_1_1)
  1508.         glInterleavedArrays(GL_V3F, 0,
  1509.           firstLight->shadowVolumeList[obj].silhouette);
  1510. #elif defined(GL_EXT_vertex_array)
  1511.         setupVertexArray(&firstLight->shadowVolumeList[obj], 3);
  1512. #endif
  1513.       }
  1514.       fullStencilMask |= 1 << scene->bitList[bit];
  1515.       glStencilMask(1 << scene->bitList[bit]);
  1516.       glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT);
  1517.       renderShadowVolume(&firstLight->shadowVolumeList[obj],
  1518.         firstLight->lightPos);
  1519.       glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
  1520.       renderShadowVolumeTop(&firstLight->shadowVolumeList[obj],
  1521.         firstLight->lightPos);
  1522.       bit++;
  1523.       do {
  1524.         obj++;
  1525.       } while (obj < firstLight->objectListSize
  1526.         && firstLight->objectList[obj]->state == RTS_NOT_SHADOWING);
  1527.     } while (bit < numStencilBits && obj < firstLight->objectListSize);
  1528.     glEnable(GL_CULL_FACE);
  1529.     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  1530.     glDepthFunc(GL_EQUAL);
  1531.     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  1532.     glStencilFunc(GL_NOTEQUAL, 0, fullStencilMask);
  1533.     glEnable(GL_LIGHTING);
  1534.     scene->renderSceneFunc(firstLight->glLight, scene->sceneData, scene);
  1535.     if (obj < firstLight->objectListSize) {
  1536.       glStencilMask(~0);
  1537.       glClear(GL_STENCIL_BUFFER_BIT);
  1538.       glDepthFunc(GL_LESS);  /* XXX needed? */
  1539.       bit = 0;
  1540.     }
  1541.   } while (obj < firstLight->objectListSize);
  1542.   if (numCastingLights == 1) {
  1543.     glStencilMask(~0);
  1544.     glCullFace(GL_BACK);  /* XXX Needed? */
  1545.     glDepthMask(GL_TRUE);
  1546.     glDepthFunc(GL_LESS);
  1547.     if (scene->stencilRenderingInvariantHack) {
  1548.       glEnable(GL_STENCIL_TEST);
  1549.       glStencilFunc(GL_ALWAYS, 0, 0xffffffff);
  1550.       glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  1551.     } else {
  1552.       glDisable(GL_STENCIL_TEST);
  1553.     }
  1554.     if (hasVertexArray) {
  1555. #if defined(GL_VERSION_1_1)
  1556.       glDisableClientState(GL_VERTEX_ARRAY);
  1557. #elif defined(GL_EXT_vertex_array)
  1558.       glDisable(GL_VERTEX_ARRAY_EXT);
  1559. #endif
  1560.     }
  1561.     return;
  1562.   }
  1563.   /* Get ready to subtract out the particular contribution for each light
  1564.      source in regions shadowed by the light source's shadowing objects. */
  1565.   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, totalDarkness);
  1566.   glDepthFunc(GL_LESS);
  1567. #ifdef GL_EXT_blend_subtract
  1568.   if (hasBlendSubtract) {
  1569.     glBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
  1570.   }
  1571. #endif
  1572.   glBlendFunc(GL_ONE, GL_ONE);
  1573.   glEnable(GL_BLEND);
  1574.   prevLight = firstLight;
  1575.   for (i = 1; i < scene->lightListSize; i++) {
  1576.     light = scene->lightList[i];
  1577.     if (light) {
  1578.       if (light->state == RTS_SHINING_AND_CASTING) {
  1579.         /* Count number of shadowing objects. */
  1580.         numShadowingObjects = 0;
  1581.         for (obj = 0; obj < light->objectListSize; obj++) {
  1582.           if (light->objectList[obj]->state == RTS_SHADOWING) {
  1583.             numShadowingObjects++;
  1584.           }
  1585.         }
  1586.         if (numShadowingObjects > 0) {
  1587.           int reservedStencilBit;
  1588.           assert(scene->stencilValidateNeeded == 0);
  1589.           /* Switch off the last light; switch on the current light (all
  1590.              other lights should be disabled). */
  1591.           glDisable(prevLight->glLight);
  1592.           glEnable(light->glLight);
  1593.           /* Complicated logic to try to figure out the stencil clear
  1594.              strategy.  Tries hard to conserve stencil bit planes and scene
  1595.              re-renders. */
  1596.           if (numStencilBits < numShadowingObjects) {
  1597.             if (numStencilBits == 1) {
  1598.               fprintf(stderr, "WARNING: 1 bit of stencil not enough to reserve a bit.n");
  1599.               fprintf(stderr, "         Skipping lights beyond the first.n");
  1600.               continue;
  1601.             }
  1602.             /* Going to require one or more stencil clears; this requires
  1603.                reserving a bit of stencil to avoid double subtracts. */
  1604.             reservedStencilBit = 1 << scene->bitList[0];
  1605.             bit = 1;
  1606.             glStencilMask(~0);
  1607.             glClear(GL_STENCIL_BUFFER_BIT);
  1608.             glDepthFunc(GL_LESS);  /* XXX Needed? */
  1609.           } else {
  1610.             /* Faster cases.  All the objects can be rendered each to a
  1611.                distinct available stencil plane.  No need to reserve a
  1612.                stencil bit to avoid double blending since only one scene
  1613.                render required. */
  1614.             reservedStencilBit = 0;
  1615.             if (numShadowingObjects <= numStencilBits - bit) {
  1616.               /* Best case:  Enough stencil bits available to not even
  1617.                  require a stencil clear for this light.  Keep "bit" as is. */
  1618.             } else {
  1619.               /* Not enough left over bitplanes to subtract out this light
  1620.                  with what's currently available, so clear the stencil buffer
  1621.                  to get enough. */
  1622.               glStencilMask(~0);
  1623.               glClear(GL_STENCIL_BUFFER_BIT);
  1624.               bit = 0;
  1625.             }
  1626.           }
  1627.           obj = 0;
  1628.           while (light->objectList[obj]->state == RTS_NOT_SHADOWING) {
  1629.             obj++;
  1630.           }
  1631.           do {
  1632.             assert(bit < numStencilBits);
  1633.             assert(light->objectList[obj]->state == RTS_SHADOWING);
  1634.             assert(obj < light->objectListSize);
  1635.             fullStencilMask = reservedStencilBit;
  1636.             glDisable(GL_LIGHTING);
  1637.             glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  1638.             glStencilFunc(GL_ALWAYS, 0, 0);
  1639.             glDisable(GL_CULL_FACE);
  1640.             do {
  1641. #ifdef MP
  1642.               waitForSilhouetteGenerationDone(scene,
  1643.         &light->shadowVolumeList[obj]);
  1644. #endif
  1645.               if (hasVertexArray) {
  1646. #if defined(GL_VERSION_1_1)
  1647.                 glInterleavedArrays(GL_V3F, 0,
  1648.                   light->shadowVolumeList[obj].silhouette);
  1649. #elif defined(GL_EXT_vertex_array)
  1650.                 setupVertexArray(&light->shadowVolumeList[obj], 3);
  1651. #endif
  1652.               }
  1653.               fullStencilMask |= 1 << scene->bitList[bit];
  1654.               glStencilMask(1 << scene->bitList[bit]);
  1655.               glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT);
  1656.               renderShadowVolume(&light->shadowVolumeList[obj],
  1657.                 light->lightPos);
  1658.               glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
  1659.               renderShadowVolumeTop(&light->shadowVolumeList[obj],
  1660.                 light->lightPos);
  1661.               bit++;
  1662.               do {
  1663.                 obj++;
  1664.               } while (obj < light->objectListSize
  1665.                 && light->objectList[obj]->state == RTS_NOT_SHADOWING);
  1666.             } while (bit < scene->numStencilBits && obj < light->objectListSize);
  1667.             glEnable(GL_CULL_FACE);
  1668.             glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  1669.             glDepthFunc(GL_EQUAL);
  1670.             if (reservedStencilBit) {
  1671.               glStencilMask(reservedStencilBit);
  1672.               glStencilOp(GL_KEEP, GL_KEEP, GL_ONE);
  1673.               if (hasBlendSubtract) {
  1674.                 /* Subtract lighting contribution inside of shadow; prevent
  1675.                    double drawing via stencil */
  1676.                 glStencilFunc(GL_GREATER, reservedStencilBit, fullStencilMask);
  1677.               } else {
  1678.                 /* Add lighting contribution outside of shadow; prevent
  1679.                    double drawing via stencil. */
  1680.                 glStencilFunc(GL_EQUAL, 0, fullStencilMask);
  1681.               }
  1682.             } else {
  1683.               if (hasBlendSubtract) {
  1684.                 glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
  1685.                 glStencilFunc(GL_NOTEQUAL, 0, fullStencilMask);
  1686.               } else {
  1687.                 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  1688.                 glStencilFunc(GL_EQUAL, 0, fullStencilMask);
  1689.               }
  1690.             }
  1691.             glEnable(GL_LIGHTING);
  1692.             scene->renderSceneFunc(light->glLight, scene->sceneData, scene);
  1693.             if (obj < light->objectListSize) {
  1694.               assert(reservedStencilBit);
  1695.               glStencilMask(~0);
  1696.               glClear(GL_STENCIL_BUFFER_BIT);
  1697.               glDepthFunc(GL_LESS);  /* XXX Needed? */
  1698.               bit = 1;
  1699.             }
  1700.           } while (obj < light->objectListSize);
  1701.           prevLight = light;
  1702.         }
  1703.       }
  1704.     }
  1705.   }
  1706.   glStencilMask(~0);
  1707.   glCullFace(GL_BACK);  /* XXX needed? */
  1708.   glDepthMask(GL_TRUE);
  1709.   glDepthFunc(GL_LESS);
  1710.   if (scene->stencilRenderingInvariantHack) {
  1711.     glEnable(GL_STENCIL_TEST);
  1712.     glStencilFunc(GL_ALWAYS, 0, 0xffffffff);
  1713.     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  1714.   } else {
  1715.     glDisable(GL_STENCIL_TEST);
  1716.   }
  1717.   glDisable(GL_BLEND);
  1718.   if (hasVertexArray) {
  1719. #if defined(GL_VERSION_1_1)
  1720.     glDisableClientState(GL_VERTEX_ARRAY);
  1721. #elif defined(GL_EXT_vertex_array)
  1722.     glDisable(GL_VERTEX_ARRAY_EXT);
  1723. #endif
  1724.   }
  1725.   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, scene->sceneAmbient);
  1726. }
  1727. void
  1728. rtsRenderSilhouette(
  1729.   RTSscene * scene,
  1730.   RTSlight * light,
  1731.   RTSobject * object)
  1732. {
  1733.   GLfloat lightDelta[3];
  1734.   GLfloat lightDistance, viewScale, fieldOfViewRatio, extentScale;
  1735.   ShadowVolumeState svsRec, *svs;
  1736.   int obj;
  1737.   int anonymousShadowVolumeState;
  1738.   /* Calculate the light's distance from the object being shadowed. */
  1739.   lightDelta[X] = object->objectPos[X] - light->lightPos[X];
  1740.   lightDelta[Y] = object->objectPos[Y] - light->lightPos[Y];
  1741.   lightDelta[Z] = object->objectPos[Z] - light->lightPos[Z];
  1742.   lightDistance = sqrt(lightDelta[X] * lightDelta[X] +
  1743.     lightDelta[Y] * lightDelta[Y] + lightDelta[Z] * lightDelta[Z]);
  1744.   viewScale = getViewScale(scene);
  1745.   fieldOfViewRatio = object->maxRadius / lightDistance;
  1746.   extentScale = light->radius * fieldOfViewRatio / viewScale;
  1747.   for (obj = 0; obj < light->objectListSize; obj++) {
  1748.     if (light->objectList[obj] == object) {
  1749.       svs = &light->shadowVolumeList[obj];
  1750.       anonymousShadowVolumeState = 0;
  1751.       goto gotShadowVolumeState;
  1752.     }
  1753.   }
  1754.   /* It probably makes sense to have the object on the light's object list
  1755.      already since then we would have a ShadowVolumeState structure ready to
  1756.      use and likely to have a reasonably sized silhouette vertex array. Plus,
  1757.      we'd validate the light and object's shadow volume.
  1758.      Anyway, rtsRenderSilhouette will still handle the case where the object
  1759.      is not already added to the specified light for generality (but not
  1760.      economy).  Use an "anonymous" ShadowVolumeState data structure that only
  1761.      lives during this routine. */
  1762.   svs = &svsRec;
  1763.   anonymousShadowVolumeState = 1;
  1764.   initShadowVolumeState(svs);
  1765. gotShadowVolumeState:
  1766.   validateShadowVolume(scene, light, object, svs);
  1767.   glPushAttrib(GL_ENABLE_BIT);
  1768.   /* Disable a few things likely to screw up the rendering of  the
  1769.      silhouette. */
  1770.   glDisable(GL_LIGHTING);
  1771.   glDisable(GL_DEPTH_TEST);
  1772. #if 0
  1773.   glDisable(GL_STENCIL_TEST);
  1774. #else
  1775.   glEnable(GL_STENCIL_TEST);
  1776.   glStencilFunc(GL_ALWAYS, 0, 0xffffffff);
  1777.   glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  1778. #endif
  1779.   glDisable(GL_ALPHA_TEST);
  1780.   glDisable(GL_BLEND);
  1781.   glMatrixMode(GL_PROJECTION);
  1782.   glPushMatrix();
  1783.   glLoadIdentity();
  1784.   gluOrtho2D(-viewScale, viewScale, -viewScale, viewScale);
  1785.   glMatrixMode(GL_MODELVIEW);
  1786.   glPushMatrix();
  1787.   glLoadIdentity();
  1788.   glScalef(1.0 / extentScale, 1.0 / extentScale, 1.0 / extentScale);
  1789.   renderSilhouette(svs);
  1790. #if 0
  1791.   glColor3f(0.0, 1.0, 0.0);
  1792.   glPointSize(7.0);
  1793.   glBegin(GL_POINTS);
  1794.   glVertex2fv(eyeLoc);
  1795.   glEnd();
  1796. #endif
  1797.   glMatrixMode(GL_PROJECTION);
  1798.   glPopMatrix();
  1799.   glMatrixMode(GL_MODELVIEW);
  1800.   glPopMatrix();
  1801.   glPopAttrib();
  1802.   if (anonymousShadowVolumeState) {
  1803.     /* Deallocate "anonymous" ShadowVolumeState's silhouette vertex array. */
  1804.     SHARED_FREE(svs->silhouette);
  1805.   }
  1806. }
  1807. void
  1808. rtsStencilRenderingInvariantHack(RTSscene * scene, GLboolean enableHack)
  1809. {
  1810.   scene->stencilRenderingInvariantHack = enableHack;
  1811. }
  1812. /* XXX These free routines are not complete. */
  1813. #if 0
  1814. static void
  1815. freeTessellationContext(TessellationContext *context)
  1816. {
  1817.   gluDeleteTess(context->tess);
  1818.   free(context->feedbackBuffer);
  1819.   free(context);
  1820. }
  1821. #endif
  1822. void
  1823. rtsFreeScene(
  1824.   RTSscene * scene)
  1825. {
  1826.   int i;
  1827.   for (i=0; i < scene->lightListSize; i++) {
  1828.     if (scene->lightList[i]) {
  1829.       rtsFreeLight(scene->lightList[i]);
  1830.     }
  1831.   }
  1832.   free(scene->lightList);
  1833.   free(scene);
  1834. }
  1835. void
  1836. rtsFreeLight(
  1837.   RTSlight * light)
  1838. {
  1839.   int i;
  1840.   for (i=0; i<light->sceneListSize; i++) {
  1841.     if (light->sceneList[i]) {
  1842.       rtsFreeScene(light->sceneList[i]);
  1843.     }
  1844.   }
  1845.   free(light);
  1846. }
  1847. void
  1848. rtsFreeObject(
  1849.   RTSobject * object)
  1850. {
  1851.   free(object);
  1852. }
  1853. #endif /* GLU_VERSION_1_2 */