]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_backend.c
fixed model shadows going through walls (by making everything use a constant project...
[divverent/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3 #include "image.h"
4 #include "jpeg.h"
5
6 cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1"};
7 cvar_t gl_mesh_testarrayelement = {0, "gl_mesh_testarrayelement", "0"};
8 cvar_t gl_mesh_testmanualfeeding = {0, "gl_mesh_testmanualfeeding", "0"};
9 cvar_t gl_delayfinish = {CVAR_SAVE, "gl_delayfinish", "0"};
10 cvar_t gl_paranoid = {0, "gl_paranoid", "0"};
11 cvar_t gl_printcheckerror = {0, "gl_printcheckerror", "0"};
12
13 cvar_t r_render = {0, "r_render", "1"};
14 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1"}; // whether or not to use dithering
15 cvar_t gl_lockarrays = {0, "gl_lockarrays", "1"};
16
17 int gl_maxdrawrangeelementsvertices;
18 int gl_maxdrawrangeelementsindices;
19
20 #ifdef DEBUGGL
21 int errornumber = 0;
22
23 void GL_PrintError(int errornumber, char *filename, int linenumber)
24 {
25         switch(errornumber)
26         {
27 #ifdef GL_INVALID_ENUM
28         case GL_INVALID_ENUM:
29                 Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
30                 break;
31 #endif
32 #ifdef GL_INVALID_VALUE
33         case GL_INVALID_VALUE:
34                 Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
35                 break;
36 #endif
37 #ifdef GL_INVALID_OPERATION
38         case GL_INVALID_OPERATION:
39                 Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
40                 break;
41 #endif
42 #ifdef GL_STACK_OVERFLOW
43         case GL_STACK_OVERFLOW:
44                 Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
45                 break;
46 #endif
47 #ifdef GL_STACK_UNDERFLOW
48         case GL_STACK_UNDERFLOW:
49                 Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
50                 break;
51 #endif
52 #ifdef GL_OUT_OF_MEMORY
53         case GL_OUT_OF_MEMORY:
54                 Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
55                 break;
56 #endif
57 #ifdef GL_TABLE_TOO_LARGE
58         case GL_TABLE_TOO_LARGE:
59                 Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
60                 break;
61 #endif
62         default:
63                 Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
64                 break;
65         }
66 }
67 #endif
68
69 #define BACKENDACTIVECHECK if (!backendactive) Sys_Error("GL backend function called when backend is not active\n");
70
71 int c_meshs, c_meshelements;
72
73 void SCR_ScreenShot_f (void);
74
75 // these are externally accessible
76 int r_lightmapscalebit;
77 float r_colorscale;
78
79 static matrix4x4_t backend_viewmatrix;
80 static matrix4x4_t backend_modelmatrix;
81 static matrix4x4_t backend_modelviewmatrix;
82 static matrix4x4_t backend_glmodelviewmatrix;
83 static matrix4x4_t backend_projectmatrix;
84
85 static int backendunits, backendactive;
86 static mempool_t *gl_backend_mempool;
87
88 /*
89 note: here's strip order for a terrain row:
90 0--1--2--3--4
91 |\ |\ |\ |\ |
92 | \| \| \| \|
93 A--B--C--D--E
94
95 A0B, 01B, B1C, 12C, C2D, 23D, D3E, 34E
96
97 *elements++ = i + row;
98 *elements++ = i;
99 *elements++ = i + row + 1;
100 *elements++ = i;
101 *elements++ = i + 1;
102 *elements++ = i + row + 1;
103 */
104
105 int polygonelements[768];
106
107 static void R_Mesh_CacheArray_Startup(void);
108 static void R_Mesh_CacheArray_Shutdown(void);
109 void GL_Backend_AllocArrays(void)
110 {
111         if (!gl_backend_mempool)
112                 gl_backend_mempool = Mem_AllocPool("GL_Backend");
113         R_Mesh_CacheArray_Startup();
114 }
115
116 void GL_Backend_FreeArrays(void)
117 {
118         R_Mesh_CacheArray_Shutdown();
119         Mem_FreePool(&gl_backend_mempool);
120 }
121
122 static void gl_backend_start(void)
123 {
124         Con_DPrintf("OpenGL Backend started\n");
125         if (qglDrawRangeElements != NULL)
126         {
127                 CHECKGLERROR
128                 qglGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &gl_maxdrawrangeelementsvertices);
129                 CHECKGLERROR
130                 qglGetIntegerv(GL_MAX_ELEMENTS_INDICES, &gl_maxdrawrangeelementsindices);
131                 CHECKGLERROR
132                 Con_DPrintf("glDrawRangeElements detected (max vertices %i, max indices %i)\n", gl_maxdrawrangeelementsvertices, gl_maxdrawrangeelementsindices);
133         }
134
135         backendunits = min(MAX_TEXTUREUNITS, gl_textureunits);
136
137         GL_Backend_AllocArrays();
138
139         backendactive = true;
140 }
141
142 static void gl_backend_shutdown(void)
143 {
144         backendunits = 0;
145         backendactive = false;
146
147         Con_DPrintf("OpenGL Backend shutting down\n");
148
149         GL_Backend_FreeArrays();
150 }
151
152 static void gl_backend_newmap(void)
153 {
154 }
155
156 void gl_backend_init(void)
157 {
158         int i;
159
160         for (i = 0;i < POLYGONELEMENTS_MAXPOINTS - 2;i++)
161         {
162                 polygonelements[i * 3 + 0] = 0;
163                 polygonelements[i * 3 + 1] = i + 1;
164                 polygonelements[i * 3 + 2] = i + 2;
165         }
166
167         Cvar_RegisterVariable(&r_render);
168         Cvar_RegisterVariable(&gl_dither);
169         Cvar_RegisterVariable(&gl_lockarrays);
170         Cvar_RegisterVariable(&gl_delayfinish);
171         Cvar_RegisterVariable(&gl_paranoid);
172         Cvar_RegisterVariable(&gl_printcheckerror);
173 #ifdef NORENDER
174         Cvar_SetValue("r_render", 0);
175 #endif
176
177         Cvar_RegisterVariable(&gl_mesh_drawrangeelements);
178         Cvar_RegisterVariable(&gl_mesh_testarrayelement);
179         Cvar_RegisterVariable(&gl_mesh_testmanualfeeding);
180         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
181 }
182
183 void GL_SetupView_ViewPort (int x, int y, int width, int height)
184 {
185         if (!r_render.integer)
186                 return;
187
188         // y is weird beause OpenGL is bottom to top, we use top to bottom
189         qglViewport(x, vid.realheight - (y + height), width, height);
190         CHECKGLERROR
191 }
192
193 void GL_SetupView_Orientation_Identity (void)
194 {
195         Matrix4x4_CreateIdentity(&backend_viewmatrix);
196         memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
197 }
198
199 void GL_SetupView_Orientation_FromEntity (vec3_t origin, vec3_t angles)
200 {
201         Matrix4x4_CreateRotate(&backend_viewmatrix, -90, 1, 0, 0);
202         Matrix4x4_ConcatRotate(&backend_viewmatrix, 90, 0, 0, 1);
203         Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[2], 1, 0, 0);
204         Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[0], 0, 1, 0);
205         Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[1], 0, 0, 1);
206         Matrix4x4_ConcatTranslate(&backend_viewmatrix, -origin[0], -origin[1], -origin[2]);
207         memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
208 }
209
210 void GL_SetupView_Mode_Perspective (double fovx, double fovy, double zNear, double zFar)
211 {
212         double xmax, ymax;
213
214         if (!r_render.integer)
215                 return;
216
217         // set up viewpoint
218         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
219         qglLoadIdentity();CHECKGLERROR
220         // pyramid slopes
221         xmax = zNear * tan(fovx * M_PI / 360.0);
222         ymax = zNear * tan(fovy * M_PI / 360.0);
223         // set view pyramid
224         qglFrustum(-xmax, xmax, -ymax, ymax, zNear, zFar);CHECKGLERROR
225         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
226         GL_SetupView_Orientation_Identity();
227 }
228
229 void GL_SetupView_Mode_PerspectiveInfiniteFarClip (double fovx, double fovy, double zNear)
230 {
231         float nudge, m[16];
232
233         if (!r_render.integer)
234                 return;
235
236         // set up viewpoint
237         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
238         qglLoadIdentity();CHECKGLERROR
239         // set view pyramid
240         nudge = 1.0 - 1.0 / (1<<23);
241         m[ 0] = 1.0 / tan(fovx * M_PI / 360.0);
242         m[ 1] = 0;
243         m[ 2] = 0;
244         m[ 3] = 0;
245         m[ 4] = 0;
246         m[ 5] = 1.0 / tan(fovy * M_PI / 360.0);
247         m[ 6] = 0;
248         m[ 7] = 0;
249         m[ 8] = 0;
250         m[ 9] = 0;
251         m[10] = -1 * nudge;
252         m[11] = -1 * nudge;
253         m[12] = 0;
254         m[13] = 0;
255         m[14] = -2 * zNear * nudge;
256         m[15] = 0;
257         qglLoadMatrixf(m);
258         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
259         GL_SetupView_Orientation_Identity();
260         backend_projectmatrix.m[0][0] = m[0];
261         backend_projectmatrix.m[1][0] = m[1];
262         backend_projectmatrix.m[2][0] = m[2];
263         backend_projectmatrix.m[3][0] = m[3];
264         backend_projectmatrix.m[0][1] = m[4];
265         backend_projectmatrix.m[1][1] = m[5];
266         backend_projectmatrix.m[2][1] = m[6];
267         backend_projectmatrix.m[3][1] = m[7];
268         backend_projectmatrix.m[0][2] = m[8];
269         backend_projectmatrix.m[1][2] = m[9];
270         backend_projectmatrix.m[2][2] = m[10];
271         backend_projectmatrix.m[3][2] = m[11];
272         backend_projectmatrix.m[0][3] = m[12];
273         backend_projectmatrix.m[1][3] = m[13];
274         backend_projectmatrix.m[2][3] = m[14];
275         backend_projectmatrix.m[3][3] = m[15];
276 }
277
278 void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double zNear, double zFar)
279 {
280         if (!r_render.integer)
281                 return;
282
283         // set up viewpoint
284         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
285         qglLoadIdentity();CHECKGLERROR
286         qglOrtho(x1, x2, y2, y1, zNear, zFar);
287         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
288         GL_SetupView_Orientation_Identity();
289 }
290
291 typedef struct gltextureunit_s
292 {
293         int t1d, t2d, t3d, tcubemap;
294         int arrayenabled;
295         int arrayis3d;
296         const void *pointer_texcoord;
297         float rgbscale, alphascale;
298         int combinergb, combinealpha;
299         // FIXME: add more combine stuff
300         matrix4x4_t matrix;
301 }
302 gltextureunit_t;
303
304 static struct
305 {
306         int blendfunc1;
307         int blendfunc2;
308         int blend;
309         GLboolean depthmask;
310         int depthtest;
311         int unit;
312         int clientunit;
313         gltextureunit_t units[MAX_TEXTUREUNITS];
314         float color4f[4];
315         int lockrange_first;
316         int lockrange_count;
317         const void *pointer_vertex;
318         const void *pointer_color;
319 }
320 gl_state;
321
322 void GL_SetupTextureState(void)
323 {
324         int i;
325         gltextureunit_t *unit;
326         gl_state.unit = -1;
327         gl_state.clientunit = -1;
328         for (i = 0;i < backendunits;i++)
329         {
330                 GL_ActiveTexture(i);
331                 GL_ClientActiveTexture(i);
332                 unit = gl_state.units + i;
333                 unit->t1d = 0;
334                 unit->t2d = 0;
335                 unit->t3d = 0;
336                 unit->tcubemap = 0;
337                 unit->pointer_texcoord = NULL;
338                 unit->rgbscale = 1;
339                 unit->alphascale = 1;
340                 unit->combinergb = GL_MODULATE;
341                 unit->combinealpha = GL_MODULATE;
342
343                 qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR
344                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
345
346                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
347                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
348                 if (gl_texture3d)
349                 {
350                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
351                 }
352                 if (gl_texturecubemap)
353                 {
354                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
355                 }
356                 if (gl_combine.integer)
357                 {
358                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
359                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);CHECKGLERROR
360                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);CHECKGLERROR
361                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
362                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);CHECKGLERROR // for GL_INTERPOLATE_ARB mode
363                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
364                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
365                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);CHECKGLERROR
366                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);CHECKGLERROR
367                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);CHECKGLERROR
368                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
369                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);CHECKGLERROR
370                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
371                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
372                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
373                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
374                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
375                 }
376                 else
377                 {
378                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
379                 }
380         }
381 }
382
383 void GL_Backend_ResetState(void)
384 {
385         memset(&gl_state, 0, sizeof(gl_state));
386         gl_state.depthtest = true;
387         gl_state.blendfunc1 = GL_ONE;
388         gl_state.blendfunc2 = GL_ZERO;
389         gl_state.blend = false;
390         gl_state.depthmask = GL_TRUE;
391         gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1;
392         gl_state.lockrange_first = 0;
393         gl_state.lockrange_count = 0;
394         gl_state.pointer_vertex = NULL;
395         gl_state.pointer_color = NULL;
396
397         CHECKGLERROR
398
399         qglEnable(GL_CULL_FACE);CHECKGLERROR
400         qglCullFace(GL_FRONT);CHECKGLERROR
401         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
402         qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
403         qglDisable(GL_BLEND);CHECKGLERROR
404         qglDepthMask(gl_state.depthmask);CHECKGLERROR
405
406         qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR
407         qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
408
409         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL);CHECKGLERROR
410         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
411
412         GL_Color(0, 0, 0, 0);
413         GL_Color(1, 1, 1, 1);
414
415         GL_SetupTextureState();
416 }
417
418 void GL_ActiveTexture(int num)
419 {
420         if (gl_state.unit != num)
421         {
422                 gl_state.unit = num;
423                 if (qglActiveTexture)
424                 {
425                         qglActiveTexture(GL_TEXTURE0_ARB + gl_state.unit);
426                         CHECKGLERROR
427                 }
428         }
429 }
430
431 void GL_ClientActiveTexture(int num)
432 {
433         if (gl_state.clientunit != num)
434         {
435                 gl_state.clientunit = num;
436                 if (qglActiveTexture)
437                 {
438                         qglClientActiveTexture(GL_TEXTURE0_ARB + gl_state.clientunit);
439                         CHECKGLERROR
440                 }
441         }
442 }
443
444 void GL_BlendFunc(int blendfunc1, int blendfunc2)
445 {
446         if (gl_state.blendfunc1 != blendfunc1 || gl_state.blendfunc2 != blendfunc2)
447         {
448                 qglBlendFunc(gl_state.blendfunc1 = blendfunc1, gl_state.blendfunc2 = blendfunc2);CHECKGLERROR
449                 if (gl_state.blendfunc2 == GL_ZERO)
450                 {
451                         if (gl_state.blendfunc1 == GL_ONE)
452                         {
453                                 if (gl_state.blend)
454                                 {
455                                         gl_state.blend = 0;
456                                         qglDisable(GL_BLEND);CHECKGLERROR
457                                 }
458                         }
459                         else
460                         {
461                                 if (!gl_state.blend)
462                                 {
463                                         gl_state.blend = 1;
464                                         qglEnable(GL_BLEND);CHECKGLERROR
465                                 }
466                         }
467                 }
468                 else
469                 {
470                         if (!gl_state.blend)
471                         {
472                                 gl_state.blend = 1;
473                                 qglEnable(GL_BLEND);CHECKGLERROR
474                         }
475                 }
476         }
477 }
478
479 void GL_DepthMask(int state)
480 {
481         if (gl_state.depthmask != state)
482         {
483                 qglDepthMask(gl_state.depthmask = state);CHECKGLERROR
484         }
485 }
486
487 void GL_DepthTest(int state)
488 {
489         if (gl_state.depthtest != state)
490         {
491                 gl_state.depthtest = state;
492                 if (gl_state.depthtest)
493                 {
494                         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
495                 }
496                 else
497                 {
498                         qglDisable(GL_DEPTH_TEST);CHECKGLERROR
499                 }
500         }
501 }
502
503 void GL_VertexPointer(const float *p)
504 {
505         if (gl_state.pointer_vertex != p)
506         {
507                 gl_state.pointer_vertex = p;
508                 CHECKGLERROR
509                 qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), gl_state.pointer_vertex);
510                 CHECKGLERROR
511         }
512 }
513
514 void GL_ColorPointer(const float *p)
515 {
516         if (gl_state.pointer_color != p)
517         {
518                 CHECKGLERROR
519                 if (!gl_state.pointer_color)
520                 {
521                         qglEnableClientState(GL_COLOR_ARRAY);
522                         CHECKGLERROR
523                 }
524                 else if (!p)
525                 {
526                         qglDisableClientState(GL_COLOR_ARRAY);
527                         CHECKGLERROR
528                 }
529                 gl_state.pointer_color = p;
530                 qglColorPointer(4, GL_FLOAT, sizeof(float[4]), gl_state.pointer_color);
531                 CHECKGLERROR
532         }
533 }
534
535 void GL_Color(float cr, float cg, float cb, float ca)
536 {
537         if (gl_state.pointer_color || gl_state.color4f[0] != cr || gl_state.color4f[1] != cg || gl_state.color4f[2] != cb || gl_state.color4f[3] != ca)
538         {
539                 GL_ColorPointer(NULL);
540                 gl_state.color4f[0] = cr;
541                 gl_state.color4f[1] = cg;
542                 gl_state.color4f[2] = cb;
543                 gl_state.color4f[3] = ca;
544                 CHECKGLERROR
545                 qglColor4f(cr, cg, cb, ca);
546                 CHECKGLERROR
547         }
548 }
549
550 void GL_LockArrays(int first, int count)
551 {
552         if (gl_state.lockrange_count != count || gl_state.lockrange_first != first)
553         {
554                 if (gl_state.lockrange_count)
555                 {
556                         gl_state.lockrange_count = 0;
557                         CHECKGLERROR
558                         qglUnlockArraysEXT();
559                         CHECKGLERROR
560                 }
561                 if (count && gl_supportslockarrays && gl_lockarrays.integer)
562                 {
563                         gl_state.lockrange_first = first;
564                         gl_state.lockrange_count = count;
565                         CHECKGLERROR
566                         qglLockArraysEXT(first, count);
567                         CHECKGLERROR
568                 }
569         }
570 }
571
572 void GL_TransformToScreen(const vec4_t in, vec4_t out)
573 {
574         vec4_t temp;
575         float iw;
576         Matrix4x4_Transform4 (&backend_viewmatrix, in, temp);
577         Matrix4x4_Transform4 (&backend_projectmatrix, temp, out);
578         iw = 1.0f / out[3];
579         out[0] = r_refdef.x + (out[0] * iw + 1.0f) * r_refdef.width * 0.5f;
580         out[1] = r_refdef.y + (out[1] * iw + 1.0f) * r_refdef.height * 0.5f;
581         out[2] = out[2] * iw;
582 }
583
584 // called at beginning of frame
585 void R_Mesh_Start(void)
586 {
587         BACKENDACTIVECHECK
588         CHECKGLERROR
589         GL_Backend_ResetState();
590 }
591
592 int gl_backend_rebindtextures;
593
594 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
595 {
596         int i;
597         if (offset)
598         {
599                 for (i = 0;i < count;i++)
600                         *out++ = *in++ + offset;
601         }
602         else
603                 memcpy(out, in, sizeof(*out) * count);
604 }
605
606 // renders triangles using vertices from the active arrays
607 int paranoidblah = 0;
608 void R_Mesh_Draw(int numverts, int numtriangles, const int *elements)
609 {
610         int numelements = numtriangles * 3;
611         if (numverts == 0 || numtriangles == 0)
612         {
613                 Con_Printf("R_Mesh_Draw(%d, %d, %08p);\n", numverts, numtriangles, elements);
614                 return;
615         }
616         c_meshs++;
617         c_meshelements += numelements;
618         CHECKGLERROR
619         if (r_render.integer)
620         {
621                 if (gl_paranoid.integer)
622                 {
623                         int i, j, size;
624                         const int *p;
625                         if (!qglIsEnabled(GL_VERTEX_ARRAY))
626                                 Con_Printf("R_Mesh_Draw: vertex array not enabled\n");
627                         for (j = 0, size = numverts * (int)sizeof(float[3]), p = gl_state.pointer_vertex;j < size;j += sizeof(int), p++)
628                                 paranoidblah += *p;
629                         if (gl_state.pointer_color)
630                         {
631                                 if (!qglIsEnabled(GL_COLOR_ARRAY))
632                                         Con_Printf("R_Mesh_Draw: color array set but not enabled\n");
633                                 for (j = 0, size = numverts * (int)sizeof(float[4]), p = gl_state.pointer_color;j < size;j += sizeof(int), p++)
634                                         paranoidblah += *p;
635                         }
636                         for (i = 0;i < backendunits;i++)
637                         {
638                                 if (gl_state.units[i].t1d || gl_state.units[i].t2d || gl_state.units[i].t3d || gl_state.units[i].tcubemap || gl_state.units[i].arrayenabled)
639                                 {
640                                         if (gl_state.units[i].arrayenabled && !(gl_state.units[i].t1d || gl_state.units[i].t2d || gl_state.units[i].t3d || gl_state.units[i].tcubemap))
641                                                 Con_Printf("R_Mesh_Draw: array enabled but no texture bound\n");
642                                         GL_ActiveTexture(i);
643                                         if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
644                                                 Con_Printf("R_Mesh_Draw: texcoord array set but not enabled\n");
645                                         for (j = 0, size = numverts * ((gl_state.units[i].t3d || gl_state.units[i].tcubemap) ? (int)sizeof(float[3]) : (int)sizeof(float[2])), p = gl_state.units[i].pointer_texcoord;j < size;j += sizeof(int), p++)
646                                                 paranoidblah += *p;
647                                 }
648                         }
649                         for (i = 0;i < numtriangles * 3;i++)
650                         {
651                                 if (elements[i] < 0 || elements[i] >= numverts)
652                                 {
653                                         Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range 0 - %i) in elements list\n", elements[i], numverts);
654                                         return;
655                                 }
656                         }
657                 }
658                 CHECKGLERROR
659                 GL_LockArrays(0, numverts);
660                 CHECKGLERROR
661                 if (gl_mesh_testmanualfeeding.integer)
662                 {
663                         int i, j;
664                         const GLfloat *p;
665                         qglBegin(GL_TRIANGLES);
666                         for (i = 0;i < numtriangles * 3;i++)
667                         {
668                                 for (j = 0;j < backendunits;j++)
669                                 {
670                                         if (gl_state.units[j].pointer_texcoord)
671                                         {
672                                                 if (backendunits > 1)
673                                                 {
674                                                         if (gl_state.units[j].t3d || gl_state.units[j].tcubemap)
675                                                         {
676                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
677                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
678                                                         }
679                                                         else
680                                                         {
681                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
682                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
683                                                         }
684                                                 }
685                                                 else
686                                                 {
687                                                         if (gl_state.units[j].t3d || gl_state.units[j].tcubemap)
688                                                         {
689                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
690                                                                 qglTexCoord3f(p[0], p[1], p[2]);
691                                                         }
692                                                         else
693                                                         {
694                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
695                                                                 qglTexCoord2f(p[0], p[1]);
696                                                         }
697                                                 }
698                                         }
699                                 }
700                                 if (gl_state.pointer_color)
701                                 {
702                                         p = ((const GLfloat *)(gl_state.pointer_color)) + elements[i] * 4;
703                                         qglColor4f(p[0], p[1], p[2], p[3]);
704                                 }
705                                 p = ((const GLfloat *)(gl_state.pointer_vertex)) + elements[i] * 3;
706                                 qglVertex3f(p[0], p[1], p[2]);
707                         }
708                         qglEnd();
709                         CHECKGLERROR
710                 }
711                 else if (gl_mesh_testarrayelement.integer)
712                 {
713                         int i;
714                         qglBegin(GL_TRIANGLES);
715                         for (i = 0;i < numtriangles * 3;i++)
716                         {
717                                 qglArrayElement(elements[i]);
718                         }
719                         qglEnd();
720                         CHECKGLERROR
721                 }
722                 else if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
723                 {
724                         qglDrawRangeElements(GL_TRIANGLES, 0, numverts, numelements, GL_UNSIGNED_INT, elements);CHECKGLERROR
725                 }
726                 else
727                 {
728                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, elements);CHECKGLERROR
729                 }
730                 CHECKGLERROR
731                 GL_LockArrays(0, 0);
732                 CHECKGLERROR
733         }
734 }
735
736 // restores backend state, used when done with 3D rendering
737 void R_Mesh_Finish(void)
738 {
739         int i;
740         BACKENDACTIVECHECK
741                 CHECKGLERROR
742         GL_LockArrays(0, 0);
743                 CHECKGLERROR
744
745         for (i = backendunits - 1;i >= 0;i--)
746         {
747                 if (qglActiveTexture)
748                         qglActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
749                 if (qglClientActiveTexture)
750                         qglClientActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
751                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
752                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
753                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
754                 if (gl_texture3d)
755                 {
756                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
757                 }
758                 if (gl_texturecubemap)
759                 {
760                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
761                 }
762                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
763                 if (gl_combine.integer)
764                 {
765                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
766                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
767                 }
768         }
769         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
770         qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
771
772         qglDisable(GL_BLEND);CHECKGLERROR
773         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
774         qglDepthMask(GL_TRUE);CHECKGLERROR
775         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR
776 }
777
778 void R_Mesh_Matrix(const matrix4x4_t *matrix)
779 {
780         if (memcmp(matrix, &backend_modelmatrix, sizeof(matrix4x4_t)))
781         {
782                 backend_modelmatrix = *matrix;
783                 Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewmatrix, matrix);
784                 Matrix4x4_Transpose(&backend_glmodelviewmatrix, &backend_modelviewmatrix);
785                 qglLoadMatrixf(&backend_glmodelviewmatrix.m[0][0]);
786         }
787 }
788
789 void R_Mesh_TextureMatrix(int unitnumber, const matrix4x4_t *matrix)
790 {
791         if (memcmp(&gl_state.units[unitnumber].matrix, matrix, sizeof(matrix4x4_t)))
792         {
793                 matrix4x4_t tempmatrix;
794                 gl_state.units[unitnumber].matrix = *matrix;
795                 Matrix4x4_Transpose(&tempmatrix, &gl_state.units[unitnumber].matrix);
796                 qglMatrixMode(GL_TEXTURE);
797                 GL_ActiveTexture(unitnumber);
798                 qglLoadMatrixf(&tempmatrix.m[0][0]);
799                 qglMatrixMode(GL_MODELVIEW);
800         }
801 }
802
803 void R_Mesh_State_Texture(const rmeshstate_t *m)
804 {
805         int i, combinergb, combinealpha, scale, arrayis3d;
806         gltextureunit_t *unit;
807
808         BACKENDACTIVECHECK
809
810         if (gl_backend_rebindtextures)
811         {
812                 gl_backend_rebindtextures = false;
813                 GL_SetupTextureState();
814         }
815
816         for (i = 0, unit = gl_state.units;i < backendunits;i++, unit++)
817         {
818                 if (unit->t1d != m->tex1d[i])
819                 {
820                         GL_ActiveTexture(i);
821                         if (m->tex1d[i])
822                         {
823                                 if (unit->t1d == 0)
824                                         qglEnable(GL_TEXTURE_1D);CHECKGLERROR
825                         }
826                         else
827                         {
828                                 if (unit->t1d)
829                                         qglDisable(GL_TEXTURE_1D);CHECKGLERROR
830                         }
831                         qglBindTexture(GL_TEXTURE_1D, (unit->t1d = m->tex1d[i]));CHECKGLERROR
832                 }
833                 if (unit->t2d != m->tex[i])
834                 {
835                         GL_ActiveTexture(i);
836                         if (m->tex[i])
837                         {
838                                 if (unit->t2d == 0)
839                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
840                         }
841                         else
842                         {
843                                 if (unit->t2d)
844                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
845                         }
846                         qglBindTexture(GL_TEXTURE_2D, (unit->t2d = m->tex[i]));CHECKGLERROR
847                 }
848                 if (unit->t3d != m->tex3d[i])
849                 {
850                         GL_ActiveTexture(i);
851                         if (m->tex3d[i])
852                         {
853                                 if (unit->t3d == 0)
854                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
855                         }
856                         else
857                         {
858                                 if (unit->t3d)
859                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
860                         }
861                         qglBindTexture(GL_TEXTURE_3D, (unit->t3d = m->tex3d[i]));CHECKGLERROR
862                 }
863                 if (unit->tcubemap != m->texcubemap[i])
864                 {
865                         GL_ActiveTexture(i);
866                         if (m->texcubemap[i])
867                         {
868                                 if (unit->tcubemap == 0)
869                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
870                         }
871                         else
872                         {
873                                 if (unit->tcubemap)
874                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
875                         }
876                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, (unit->tcubemap = m->texcubemap[i]));CHECKGLERROR
877                 }
878                 combinergb = m->texcombinergb[i];
879                 if (!combinergb)
880                         combinergb = GL_MODULATE;
881                 if (unit->combinergb != combinergb)
882                 {
883                         GL_ActiveTexture(i);
884                         unit->combinergb = combinergb;
885                         if (gl_combine.integer)
886                         {
887                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
888                         }
889                         else
890                         {
891                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
892                         }
893                 }
894                 combinealpha = m->texcombinealpha[i];
895                 if (!combinealpha)
896                         combinealpha = GL_MODULATE;
897                 if (unit->combinealpha != combinealpha)
898                 {
899                         GL_ActiveTexture(i);
900                         unit->combinealpha = combinealpha;
901                         if (gl_combine.integer)
902                         {
903                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
904                         }
905                 }
906                 scale = max(m->texrgbscale[i], 1);
907                 if (unit->rgbscale != scale)
908                 {
909                         GL_ActiveTexture(i);
910                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = scale));CHECKGLERROR
911                 }
912                 scale = max(m->texalphascale[i], 1);
913                 if (unit->alphascale != scale)
914                 {
915                         GL_ActiveTexture(i);
916                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = scale));CHECKGLERROR
917                 }
918                 arrayis3d = unit->t3d || unit->tcubemap;
919                 if (unit->pointer_texcoord != m->pointer_texcoord[i] || unit->arrayis3d != arrayis3d)
920                 {
921                         GL_ClientActiveTexture(i);
922                         if (m->pointer_texcoord[i])
923                         {
924                                 if (!unit->arrayenabled)
925                                 {
926                                         unit->arrayenabled = true;
927                                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
928                                 }
929                         }
930                         else
931                         {
932                                 if (unit->arrayenabled)
933                                 {
934                                         unit->arrayenabled = false;
935                                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
936                                 }
937                         }
938                         unit->pointer_texcoord = m->pointer_texcoord[i];
939                         unit->arrayis3d = arrayis3d;
940                         if (unit->arrayis3d)
941                                 qglTexCoordPointer(3, GL_FLOAT, sizeof(float[3]), unit->pointer_texcoord);
942                         else
943                                 qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), unit->pointer_texcoord);
944                         CHECKGLERROR
945                 }
946         }
947 }
948
949 /*
950 ==============================================================================
951
952                                                 SCREEN SHOTS
953
954 ==============================================================================
955 */
956
957 qboolean SCR_ScreenShot(char *filename, int x, int y, int width, int height, qboolean jpeg)
958 {
959         qboolean ret;
960         int i, j;
961         qbyte *buffer;
962
963         if (!r_render.integer)
964                 return false;
965
966         buffer = Mem_Alloc(tempmempool, width*height*3);
967         qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
968         CHECKGLERROR
969
970         // LordHavoc: compensate for v_overbrightbits when using hardware gamma
971         if (v_hwgamma.integer)
972         {
973                 for (i = 0;i < width * height * 3;i++)
974                 {
975                         j = buffer[i] << v_overbrightbits.integer;
976                         buffer[i] = (qbyte) (bound(0, j, 255));
977                 }
978         }
979
980         if (jpeg)
981                 ret = JPEG_SaveImage_preflipped (filename, width, height, buffer);
982         else
983                 ret = Image_WriteTGARGB_preflipped (filename, width, height, buffer);
984
985         Mem_Free(buffer);
986         return ret;
987 }
988
989 //=============================================================================
990
991 void R_ClearScreen(void)
992 {
993         if (r_render.integer)
994         {
995                 // clear to black
996                 qglClearColor(0,0,0,0);CHECKGLERROR
997                 qglClearDepth(1);CHECKGLERROR
998                 if (gl_stencil)
999                 {
1000                         // LordHavoc: we use a stencil centered around 128 instead of 0,
1001                         // to avoid clamping interfering with strange shadow volume
1002                         // drawing orders
1003                         qglClearStencil(128);CHECKGLERROR
1004                 }
1005                 // clear the screen
1006                 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | (gl_stencil ? GL_STENCIL_BUFFER_BIT : 0));CHECKGLERROR
1007                 // set dithering mode
1008                 if (gl_dither.integer)
1009                 {
1010                         qglEnable(GL_DITHER);CHECKGLERROR
1011                 }
1012                 else
1013                 {
1014                         qglDisable(GL_DITHER);CHECKGLERROR
1015                 }
1016         }
1017 }
1018
1019 /*
1020 ==================
1021 SCR_UpdateScreen
1022
1023 This is called every frame, and can also be called explicitly to flush
1024 text to the screen.
1025 ==================
1026 */
1027 void SCR_UpdateScreen (void)
1028 {
1029         if (gl_delayfinish.integer)
1030         {
1031                 VID_Finish ();
1032
1033                 R_TimeReport("finish");
1034         }
1035
1036         if (r_textureunits.integer > gl_textureunits)
1037                 Cvar_SetValueQuick(&r_textureunits, gl_textureunits);
1038         if (r_textureunits.integer < 1)
1039                 Cvar_SetValueQuick(&r_textureunits, 1);
1040
1041         if (gl_combine.integer && (!gl_combine_extension || r_textureunits.integer < 2))
1042                 Cvar_SetValueQuick(&gl_combine, 0);
1043
1044         // lighting scale
1045         r_colorscale = 1.0f / (float) (1 << v_overbrightbits.integer);
1046
1047         // lightmaps only
1048         r_lightmapscalebit = v_overbrightbits.integer;
1049         if (gl_combine.integer && r_textureunits.integer > 1)
1050                 r_lightmapscalebit += 2;
1051
1052         R_TimeReport("setup");
1053
1054         R_ClearScreen();
1055
1056         R_TimeReport("clear");
1057
1058         if (scr_conlines < vid.conheight && cls.signon == SIGNONS)
1059                 R_RenderView();
1060
1061         // draw 2D stuff
1062         R_DrawQueue();
1063
1064         if (gl_delayfinish.integer)
1065         {
1066                 // tell driver to commit it's partially full geometry queue to the rendering queue
1067                 // (this doesn't wait for the commands themselves to complete)
1068                 qglFlush();
1069         }
1070         else
1071         {
1072                 VID_Finish ();
1073
1074                 R_TimeReport("finish");
1075         }
1076 }
1077
1078
1079 //===========================================================================
1080 // dynamic vertex array buffer subsystem
1081 //===========================================================================
1082
1083 float varray_vertex3f[65536*3];
1084 float varray_color4f[65536*4];
1085 float varray_texcoord2f[4][65536*2];
1086 float varray_texcoord3f[4][65536*3];
1087 float varray_normal3f[65536*3];
1088
1089 //===========================================================================
1090 // vertex array caching subsystem
1091 //===========================================================================
1092
1093 typedef struct rcachearraylink_s
1094 {
1095         struct rcachearraylink_s *next, *prev;
1096         struct rcachearrayitem_s *data;
1097 }
1098 rcachearraylink_t;
1099
1100 typedef struct rcachearrayitem_s
1101 {
1102         // the original request structure
1103         rcachearrayrequest_t request;
1104         // active
1105         int active;
1106         // offset into r_mesh_rcachedata
1107         int offset;
1108         // for linking this into the sequential list
1109         rcachearraylink_t sequentiallink;
1110         // for linking this into the lookup list
1111         rcachearraylink_t hashlink;
1112 }
1113 rcachearrayitem_t;
1114
1115 #define RCACHEARRAY_HASHSIZE 65536
1116 #define RCACHEARRAY_ITEMS 4096
1117 #define RCACHEARRAY_DEFAULTSIZE (4 << 20)
1118
1119 // all active items are linked into this chain in sorted order
1120 static rcachearraylink_t r_mesh_rcachesequentialchain;
1121 // all inactive items are linked into this chain in unknown order
1122 static rcachearraylink_t r_mesh_rcachefreechain;
1123 // all active items are also linked into these chains (using their hashlink)
1124 static rcachearraylink_t r_mesh_rcachechain[RCACHEARRAY_HASHSIZE];
1125
1126 // all items are stored here, whether active or inactive
1127 static rcachearrayitem_t r_mesh_rcacheitems[RCACHEARRAY_ITEMS];
1128
1129 // size of data buffer
1130 static int r_mesh_rcachedata_size = RCACHEARRAY_DEFAULTSIZE;
1131 // data buffer
1132 static qbyte r_mesh_rcachedata[RCACHEARRAY_DEFAULTSIZE];
1133
1134 // current state
1135 static int r_mesh_rcachedata_offset;
1136 static rcachearraylink_t *r_mesh_rcachesequentialchain_current;
1137
1138 static void R_Mesh_CacheArray_Startup(void)
1139 {
1140         int i;
1141         rcachearraylink_t *l;
1142         // prepare all the linked lists
1143         l = &r_mesh_rcachesequentialchain;l->next = l->prev = l;l->data = NULL;
1144         l = &r_mesh_rcachefreechain;l->next = l->prev = l;l->data = NULL;
1145         memset(&r_mesh_rcachechain, 0, sizeof(r_mesh_rcachechain));
1146         for (i = 0;i < RCACHEARRAY_HASHSIZE;i++)
1147         {
1148                 l = &r_mesh_rcachechain[i];
1149                 l->next = l->prev = l;
1150                 l->data = NULL;
1151         }
1152         memset(&r_mesh_rcacheitems, 0, sizeof(r_mesh_rcacheitems));
1153         for (i = 0;i < RCACHEARRAY_ITEMS;i++)
1154         {
1155                 r_mesh_rcacheitems[i].hashlink.data = r_mesh_rcacheitems[i].sequentiallink.data = &r_mesh_rcacheitems[i];
1156                 l = &r_mesh_rcacheitems[i].sequentiallink;
1157                 l->next = &r_mesh_rcachefreechain;
1158                 l->prev = l->next->prev;
1159                 l->next->prev = l->prev->next = l;
1160         }
1161         // clear other state
1162         r_mesh_rcachedata_offset = 0;
1163         r_mesh_rcachesequentialchain_current = &r_mesh_rcachesequentialchain;
1164 }
1165
1166 static void R_Mesh_CacheArray_Shutdown(void)
1167 {
1168 }
1169
1170 /*
1171 static void R_Mesh_CacheArray_ValidateState(int num)
1172 {
1173         rcachearraylink_t *l, *lhead;
1174         lhead = &r_mesh_rcachesequentialchain;
1175         if (r_mesh_rcachesequentialchain_current == lhead)
1176                 return;
1177         for (l = lhead->next;l != lhead;l = l->next)
1178                 if (r_mesh_rcachesequentialchain_current == l)
1179                         return;
1180         Sys_Error("%i", num);
1181 }
1182 */
1183
1184 int R_Mesh_CacheArray(rcachearrayrequest_t *r)
1185 {
1186         rcachearraylink_t *l, *lhead, *lnext;
1187         rcachearrayitem_t *d;
1188         int hashindex, offset, offsetend;
1189
1190         //R_Mesh_CacheArray_ValidateState(3);
1191         // calculate a hashindex to choose a cache chain
1192         r->data = NULL;
1193         hashindex = CRC_Block((void *)r, sizeof(*r)) % RCACHEARRAY_HASHSIZE;
1194
1195         // is it already cached?
1196         for (lhead = &r_mesh_rcachechain[hashindex], l = lhead->next;l != lhead;l = l->next)
1197         {
1198                 if (!memcmp(&l->data->request, r, sizeof(l->data->request)))
1199                 {
1200                         // we have it cached already
1201                         r->data = r_mesh_rcachedata + l->data->offset;
1202                         return false;
1203                 }
1204         }
1205
1206         // we need to add a new cache item, this means finding a place for the new
1207         // data and making sure we have a free item available, lots of work...
1208
1209         // check if buffer needs to wrap
1210         if (r_mesh_rcachedata_offset + r->data_size > r_mesh_rcachedata_size)
1211         {
1212                 /*
1213                 if (r->data_size * 10 > r_mesh_rcachedata_size)
1214                 {
1215                         // realloc whole cache
1216                 }
1217                 */
1218                 // reset back to start
1219                 r_mesh_rcachedata_offset = 0;
1220                 r_mesh_rcachesequentialchain_current = &r_mesh_rcachesequentialchain;
1221         }
1222         offset = r_mesh_rcachedata_offset;
1223         r_mesh_rcachedata_offset += r->data_size;
1224         offsetend = r_mesh_rcachedata_offset;
1225         //R_Mesh_CacheArray_ValidateState(4);
1226
1227         /*
1228         {
1229                 int n;
1230                 for (lhead = &r_mesh_rcachesequentialchain, l = lhead->next, n = 0;l != lhead;l = l->next, n++);
1231                 Con_Printf("R_Mesh_CacheArray: new data range %i:%i, %i items are already linked\n", offset, offsetend, n);
1232         }
1233         */
1234
1235         // make room for the new data (remove old items)
1236         lhead = &r_mesh_rcachesequentialchain;
1237         l = r_mesh_rcachesequentialchain_current;
1238         if (l == lhead)
1239                 l = l->next;
1240         while (l != lhead && l->data->offset < offsetend && l->data->offset + l->data->request.data_size > offset)
1241         {
1242         //r_mesh_rcachesequentialchain_current = l;
1243         //R_Mesh_CacheArray_ValidateState(8);
1244                 lnext = l->next;
1245                 // if at the end of the chain, wrap around
1246                 if (lnext == lhead)
1247                         lnext = lnext->next;
1248         //r_mesh_rcachesequentialchain_current = lnext;
1249         //R_Mesh_CacheArray_ValidateState(10);
1250
1251                 // unlink from sequential chain
1252                 l->next->prev = l->prev;
1253                 l->prev->next = l->next;
1254         //R_Mesh_CacheArray_ValidateState(11);
1255                 // link into free chain
1256                 l->next = &r_mesh_rcachefreechain;
1257                 l->prev = l->next->prev;
1258                 l->next->prev = l->prev->next = l;
1259         //R_Mesh_CacheArray_ValidateState(12);
1260
1261                 l = &l->data->hashlink;
1262                 // unlink from hash chain
1263                 l->next->prev = l->prev;
1264                 l->prev->next = l->next;
1265
1266                 l = lnext;
1267         //r_mesh_rcachesequentialchain_current = l;
1268         //R_Mesh_CacheArray_ValidateState(9);
1269         }
1270         //r_mesh_rcachesequentialchain_current = l;
1271         //R_Mesh_CacheArray_ValidateState(5);
1272         // gobble an extra item if we have no free items available
1273         if (r_mesh_rcachefreechain.next == &r_mesh_rcachefreechain)
1274         {
1275                 lnext = l->next;
1276
1277                 // unlink from sequential chain
1278                 l->next->prev = l->prev;
1279                 l->prev->next = l->next;
1280                 // link into free chain
1281                 l->next = &r_mesh_rcachefreechain;
1282                 l->prev = l->next->prev;
1283                 l->next->prev = l->prev->next = l;
1284
1285                 l = &l->data->hashlink;
1286                 // unlink from hash chain
1287                 l->next->prev = l->prev;
1288                 l->prev->next = l->next;
1289
1290                 l = lnext;
1291         }
1292         r_mesh_rcachesequentialchain_current = l;
1293         //R_Mesh_CacheArray_ValidateState(6);
1294
1295         // now take an item from the free chain
1296         l = r_mesh_rcachefreechain.next;
1297         // set it up
1298         d = l->data;
1299         d->request = *r;
1300         d->offset = offset;
1301         // unlink
1302         l->next->prev = l->prev;
1303         l->prev->next = l->next;
1304         // relink to sequential
1305         l->next = r_mesh_rcachesequentialchain_current->prev;
1306         l->prev = l->next->prev;
1307         while (l->next->data && l->data && l->next->data->offset <= d->offset)
1308         {
1309                 //Con_Printf(">\n");
1310                 l->next = l->next->next;
1311                 l->prev = l->prev->next;
1312         }
1313         while (l->prev->data && l->data && l->prev->data->offset >= d->offset)
1314         {
1315                 //Con_Printf("<\n");
1316                 l->prev = l->prev->prev;
1317                 l->next = l->next->prev;
1318         }
1319         l->next->prev = l->prev->next = l;
1320         // also link into hash chain
1321         l = &l->data->hashlink;
1322         l->next = &r_mesh_rcachechain[hashindex];
1323         l->prev = l->next->prev;
1324         l->prev->next = l;
1325         l->next->prev = l->prev->next = l;
1326
1327
1328         //r_mesh_rcachesequentialchain_current = d->sequentiallink.next;
1329
1330         //R_Mesh_CacheArray_ValidateState(7);
1331         // and finally set the data pointer
1332         r->data = r_mesh_rcachedata + d->offset;
1333         // and tell the caller to fill the array
1334         return true;
1335 }
1336