+ if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer || r_stereo_sidebyside.integer)
+ {
+ matrix4x4_t originalmatrix = r_refdef.viewentitymatrix;
+ r_refdef.viewentitymatrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * -0.5f * r_refdef.viewentitymatrix.m[0][1];
+ r_refdef.viewentitymatrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * -0.5f * r_refdef.viewentitymatrix.m[1][1];
+ r_refdef.viewentitymatrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * -0.5f * r_refdef.viewentitymatrix.m[2][1];
+
+ if (r_stereo_sidebyside.integer)
+ r_stereo_side = 0;
+
+ if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
+ {
+ r_refdef.colormask[0] = 1;
+ r_refdef.colormask[1] = 0;
+ r_refdef.colormask[2] = 0;
+ }
+
+ SCR_DrawScreen();
+
+ r_refdef.viewentitymatrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * 0.5f * r_refdef.viewentitymatrix.m[0][1];
+ r_refdef.viewentitymatrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * 0.5f * r_refdef.viewentitymatrix.m[1][1];
+ r_refdef.viewentitymatrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * 0.5f * r_refdef.viewentitymatrix.m[2][1];
+
+ if (r_stereo_sidebyside.integer)
+ r_stereo_side = 1;
+
+ if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
+ {
+ r_refdef.colormask[0] = 0;
+ r_refdef.colormask[1] = r_stereo_redcyan.integer || r_stereo_redgreen.integer;
+ r_refdef.colormask[2] = r_stereo_redcyan.integer || r_stereo_redblue.integer;
+ }
+
+ SCR_DrawScreen();
+
+ r_refdef.viewentitymatrix = originalmatrix;
+ }
+ else
+ {
+ r_showtrispass = false;
+ SCR_DrawScreen();
+
+ if (r_showtris.value > 0)
+ {
+ rmeshstate_t m;
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ GL_DepthTest(GL_FALSE);
+ GL_DepthMask(GL_FALSE);
+ memset(&m, 0, sizeof(m));
+ R_Mesh_State(&m);
+ r_showtrispass = true;
+ GL_ShowTrisColor(0.2,0.2,0.2,1);
+ SCR_DrawScreen();
+ r_showtrispass = false;
+ }
+ }
+
+ VID_Finish();
+ R_TimeReport("finish");
+}
+
+
+//===========================================================================
+// dynamic vertex array buffer subsystem
+//===========================================================================
+
+// FIXME: someday this should be dynamically allocated and resized?
+float varray_vertex3f[65536*3];
+float varray_svector3f[65536*3];
+float varray_tvector3f[65536*3];
+float varray_normal3f[65536*3];
+float varray_color4f[65536*4];
+float varray_texcoord2f[4][65536*2];
+float varray_texcoord3f[4][65536*3];
+int earray_element3i[65536];
+float varray_vertex3f2[65536*3];
+
+//===========================================================================
+// vertex array caching subsystem
+//===========================================================================
+
+typedef struct rcachearraylink_s
+{
+ struct rcachearraylink_s *next, *prev;
+ struct rcachearrayitem_s *data;
+}
+rcachearraylink_t;
+
+typedef struct rcachearrayitem_s
+{
+ // the original request structure
+ rcachearrayrequest_t request;
+ // active
+ int active;
+ // offset into r_mesh_rcachedata
+ int offset;
+ // for linking this into the sequential list
+ rcachearraylink_t sequentiallink;
+ // for linking this into the lookup list
+ rcachearraylink_t hashlink;
+}
+rcachearrayitem_t;
+
+#define RCACHEARRAY_HASHSIZE 65536
+#define RCACHEARRAY_ITEMS 4096
+#define RCACHEARRAY_DEFAULTSIZE (4 << 20)
+
+// all active items are linked into this chain in sorted order
+static rcachearraylink_t r_mesh_rcachesequentialchain;
+// all inactive items are linked into this chain in unknown order
+static rcachearraylink_t r_mesh_rcachefreechain;
+// all active items are also linked into these chains (using their hashlink)
+static rcachearraylink_t r_mesh_rcachechain[RCACHEARRAY_HASHSIZE];
+
+// all items are stored here, whether active or inactive
+static rcachearrayitem_t r_mesh_rcacheitems[RCACHEARRAY_ITEMS];
+
+// size of data buffer
+static int r_mesh_rcachedata_size = RCACHEARRAY_DEFAULTSIZE;
+// data buffer
+static qbyte r_mesh_rcachedata[RCACHEARRAY_DEFAULTSIZE];
+
+// current state
+static int r_mesh_rcachedata_offset;
+static rcachearraylink_t *r_mesh_rcachesequentialchain_current;
+
+static void R_Mesh_CacheArray_Startup(void)
+{
+ int i;
+ rcachearraylink_t *l;
+ // prepare all the linked lists
+ l = &r_mesh_rcachesequentialchain;l->next = l->prev = l;l->data = NULL;
+ l = &r_mesh_rcachefreechain;l->next = l->prev = l;l->data = NULL;
+ memset(&r_mesh_rcachechain, 0, sizeof(r_mesh_rcachechain));
+ for (i = 0;i < RCACHEARRAY_HASHSIZE;i++)
+ {
+ l = &r_mesh_rcachechain[i];
+ l->next = l->prev = l;
+ l->data = NULL;
+ }
+ memset(&r_mesh_rcacheitems, 0, sizeof(r_mesh_rcacheitems));
+ for (i = 0;i < RCACHEARRAY_ITEMS;i++)
+ {
+ r_mesh_rcacheitems[i].hashlink.data = r_mesh_rcacheitems[i].sequentiallink.data = &r_mesh_rcacheitems[i];
+ l = &r_mesh_rcacheitems[i].sequentiallink;
+ l->next = &r_mesh_rcachefreechain;
+ l->prev = l->next->prev;
+ l->next->prev = l->prev->next = l;
+ }
+ // clear other state
+ r_mesh_rcachedata_offset = 0;
+ r_mesh_rcachesequentialchain_current = &r_mesh_rcachesequentialchain;
+}
+
+static void R_Mesh_CacheArray_Shutdown(void)
+{
+}
+
+/*
+static void R_Mesh_CacheArray_ValidateState(int num)
+{
+ rcachearraylink_t *l, *lhead;
+ lhead = &r_mesh_rcachesequentialchain;
+ if (r_mesh_rcachesequentialchain_current == lhead)
+ return;
+ for (l = lhead->next;l != lhead;l = l->next)
+ if (r_mesh_rcachesequentialchain_current == l)
+ return;
+ Sys_Error("%i", num);
+}
+*/
+
+int R_Mesh_CacheArray(rcachearrayrequest_t *r)
+{
+ rcachearraylink_t *l, *lhead, *lnext;
+ rcachearrayitem_t *d;
+ int hashindex, offset, offsetend;
+
+ //R_Mesh_CacheArray_ValidateState(3);
+ // calculate a hashindex to choose a cache chain
+ r->data = NULL;
+ hashindex = CRC_Block((void *)r, sizeof(*r)) % RCACHEARRAY_HASHSIZE;
+
+ // is it already cached?
+ for (lhead = &r_mesh_rcachechain[hashindex], l = lhead->next;l != lhead;l = l->next)
+ {
+ if (!memcmp(&l->data->request, r, sizeof(l->data->request)))
+ {
+ // we have it cached already
+ r->data = r_mesh_rcachedata + l->data->offset;
+ return false;
+ }
+ }