]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_backend.c
fixed blendfunc issues with single pass lighting (such as ambient pass) which were...
[divverent/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3 #include "image.h"
4 #include "jpeg.h"
5 #include "cl_collision.h"
6
7 cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1"};
8 cvar_t gl_mesh_testarrayelement = {0, "gl_mesh_testarrayelement", "0"};
9 cvar_t gl_mesh_testmanualfeeding = {0, "gl_mesh_testmanualfeeding", "0"};
10 cvar_t gl_paranoid = {0, "gl_paranoid", "0"};
11 cvar_t gl_printcheckerror = {0, "gl_printcheckerror", "0"};
12 cvar_t r_stereo_separation = {0, "r_stereo_separation", "4"};
13 cvar_t r_stereo_sidebyside = {0, "r_stereo_sidebyside", "0"};
14 cvar_t r_stereo_redblue = {0, "r_stereo_redblue", "0"};
15 cvar_t r_stereo_redcyan = {0, "r_stereo_redcyan", "0"};
16 cvar_t r_stereo_redgreen = {0, "r_stereo_redgreen", "0"};
17
18 cvar_t r_render = {0, "r_render", "1"};
19 cvar_t r_waterwarp = {CVAR_SAVE, "r_waterwarp", "1"};
20 cvar_t gl_polyblend = {CVAR_SAVE, "gl_polyblend", "1"};
21 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1"}; // whether or not to use dithering
22 cvar_t gl_lockarrays = {0, "gl_lockarrays", "1"};
23
24 int gl_maxdrawrangeelementsvertices;
25 int gl_maxdrawrangeelementsindices;
26
27 #ifdef DEBUGGL
28 int errornumber = 0;
29
30 void GL_PrintError(int errornumber, char *filename, int linenumber)
31 {
32         switch(errornumber)
33         {
34 #ifdef GL_INVALID_ENUM
35         case GL_INVALID_ENUM:
36                 Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
37                 break;
38 #endif
39 #ifdef GL_INVALID_VALUE
40         case GL_INVALID_VALUE:
41                 Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
42                 break;
43 #endif
44 #ifdef GL_INVALID_OPERATION
45         case GL_INVALID_OPERATION:
46                 Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
47                 break;
48 #endif
49 #ifdef GL_STACK_OVERFLOW
50         case GL_STACK_OVERFLOW:
51                 Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
52                 break;
53 #endif
54 #ifdef GL_STACK_UNDERFLOW
55         case GL_STACK_UNDERFLOW:
56                 Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
57                 break;
58 #endif
59 #ifdef GL_OUT_OF_MEMORY
60         case GL_OUT_OF_MEMORY:
61                 Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
62                 break;
63 #endif
64 #ifdef GL_TABLE_TOO_LARGE
65         case GL_TABLE_TOO_LARGE:
66                 Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
67                 break;
68 #endif
69         default:
70                 Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
71                 break;
72         }
73 }
74 #endif
75
76 #define BACKENDACTIVECHECK if (!backendactive) Sys_Error("GL backend function called when backend is not active\n");
77
78 void SCR_ScreenShot_f (void);
79
80 static matrix4x4_t backend_viewmatrix;
81 static matrix4x4_t backend_modelmatrix;
82 static matrix4x4_t backend_modelviewmatrix;
83 static matrix4x4_t backend_glmodelviewmatrix;
84 static matrix4x4_t backend_projectmatrix;
85
86 static int backendunits, backendactive;
87 static mempool_t *gl_backend_mempool;
88
89 /*
90 note: here's strip order for a terrain row:
91 0--1--2--3--4
92 |\ |\ |\ |\ |
93 | \| \| \| \|
94 A--B--C--D--E
95 clockwise
96
97 A0B, 01B, B1C, 12C, C2D, 23D, D3E, 34E
98
99 *elements++ = i + row;
100 *elements++ = i;
101 *elements++ = i + row + 1;
102 *elements++ = i;
103 *elements++ = i + 1;
104 *elements++ = i + row + 1;
105
106
107 for (y = 0;y < rows - 1;y++)
108 {
109         for (x = 0;x < columns - 1;x++)
110         {
111                 i = y * rows + x;
112                 *elements++ = i + columns;
113                 *elements++ = i;
114                 *elements++ = i + columns + 1;
115                 *elements++ = i;
116                 *elements++ = i + 1;
117                 *elements++ = i + columns + 1;
118         }
119 }
120
121 alternative:
122 0--1--2--3--4
123 | /| /|\ | /|
124 |/ |/ | \|/ |
125 A--B--C--D--E
126 counterclockwise
127
128 for (y = 0;y < rows - 1;y++)
129 {
130         for (x = 0;x < columns - 1;x++)
131         {
132                 i = y * rows + x;
133                 *elements++ = i;
134                 *elements++ = i + columns;
135                 *elements++ = i + columns + 1;
136                 *elements++ = i + columns;
137                 *elements++ = i + columns + 1;
138                 *elements++ = i + 1;
139         }
140 }
141 */
142
143 int polygonelements[768];
144
145 static void R_Mesh_CacheArray_Startup(void);
146 static void R_Mesh_CacheArray_Shutdown(void);
147 void GL_Backend_AllocArrays(void)
148 {
149         if (!gl_backend_mempool)
150                 gl_backend_mempool = Mem_AllocPool("GL_Backend", 0, NULL);
151         R_Mesh_CacheArray_Startup();
152 }
153
154 void GL_Backend_FreeArrays(void)
155 {
156         R_Mesh_CacheArray_Shutdown();
157         Mem_FreePool(&gl_backend_mempool);
158 }
159
160 static void gl_backend_start(void)
161 {
162         Con_Print("OpenGL Backend started\n");
163         if (qglDrawRangeElements != NULL)
164         {
165                 CHECKGLERROR
166                 qglGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &gl_maxdrawrangeelementsvertices);
167                 CHECKGLERROR
168                 qglGetIntegerv(GL_MAX_ELEMENTS_INDICES, &gl_maxdrawrangeelementsindices);
169                 CHECKGLERROR
170                 Con_Printf("glDrawRangeElements detected (max vertices %i, max indices %i)\n", gl_maxdrawrangeelementsvertices, gl_maxdrawrangeelementsindices);
171         }
172
173         backendunits = min(MAX_TEXTUREUNITS, gl_textureunits);
174
175         GL_Backend_AllocArrays();
176
177         backendactive = true;
178 }
179
180 static void gl_backend_shutdown(void)
181 {
182         backendunits = 0;
183         backendactive = false;
184
185         Con_Print("OpenGL Backend shutting down\n");
186
187         GL_Backend_FreeArrays();
188 }
189
190 static void gl_backend_newmap(void)
191 {
192 }
193
194 cvar_t scr_zoomwindow = {CVAR_SAVE, "scr_zoomwindow", "0"};
195 cvar_t scr_zoomwindow_viewsizex = {CVAR_SAVE, "scr_zoomwindow_viewsizex", "20"};
196 cvar_t scr_zoomwindow_viewsizey = {CVAR_SAVE, "scr_zoomwindow_viewsizey", "20"};
197 cvar_t scr_zoomwindow_fov = {CVAR_SAVE, "scr_zoomwindow_fov", "20"};
198
199 void gl_backend_init(void)
200 {
201         int i;
202
203         for (i = 0;i < POLYGONELEMENTS_MAXPOINTS - 2;i++)
204         {
205                 polygonelements[i * 3 + 0] = 0;
206                 polygonelements[i * 3 + 1] = i + 1;
207                 polygonelements[i * 3 + 2] = i + 2;
208         }
209
210         Cvar_RegisterVariable(&r_render);
211         Cvar_RegisterVariable(&r_waterwarp);
212         Cvar_RegisterVariable(&r_stereo_separation);
213         Cvar_RegisterVariable(&r_stereo_sidebyside);
214         Cvar_RegisterVariable(&r_stereo_redblue);
215         Cvar_RegisterVariable(&r_stereo_redcyan);
216         Cvar_RegisterVariable(&r_stereo_redgreen);
217         Cvar_RegisterVariable(&gl_polyblend);
218         Cvar_RegisterVariable(&gl_dither);
219         Cvar_RegisterVariable(&gl_lockarrays);
220         Cvar_RegisterVariable(&gl_paranoid);
221         Cvar_RegisterVariable(&gl_printcheckerror);
222 #ifdef NORENDER
223         Cvar_SetValue("r_render", 0);
224 #endif
225
226         Cvar_RegisterVariable(&gl_mesh_drawrangeelements);
227         Cvar_RegisterVariable(&gl_mesh_testarrayelement);
228         Cvar_RegisterVariable(&gl_mesh_testmanualfeeding);
229
230         Cvar_RegisterVariable(&scr_zoomwindow);
231         Cvar_RegisterVariable(&scr_zoomwindow_viewsizex);
232         Cvar_RegisterVariable(&scr_zoomwindow_viewsizey);
233         Cvar_RegisterVariable(&scr_zoomwindow_fov);
234
235         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
236 }
237
238 void GL_SetupView_Orientation_Identity (void)
239 {
240         Matrix4x4_CreateIdentity(&backend_viewmatrix);
241         memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
242 }
243
244 void GL_SetupView_Orientation_FromEntity(matrix4x4_t *matrix)
245 {
246         matrix4x4_t tempmatrix, basematrix;
247         Matrix4x4_Invert_Simple(&tempmatrix, matrix);
248         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
249         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
250         Matrix4x4_Concat(&backend_viewmatrix, &basematrix, &tempmatrix);
251         //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[2], 1, 0, 0);
252         //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[0], 0, 1, 0);
253         //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[1], 0, 0, 1);
254         //Matrix4x4_ConcatTranslate(&backend_viewmatrix, -origin[0], -origin[1], -origin[2]);
255         memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
256 }
257
258 void GL_SetupView_Mode_Perspective (double fovx, double fovy, double zNear, double zFar)
259 {
260         double xmax, ymax;
261         double m[16];
262
263         if (!r_render.integer)
264                 return;
265
266         // set up viewpoint
267         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
268         qglLoadIdentity();CHECKGLERROR
269         // pyramid slopes
270         xmax = zNear * tan(fovx * M_PI / 360.0);
271         ymax = zNear * tan(fovy * M_PI / 360.0);
272         // set view pyramid
273         qglFrustum(-xmax, xmax, -ymax, ymax, zNear, zFar);CHECKGLERROR
274         qglGetDoublev(GL_PROJECTION_MATRIX, m);
275         backend_projectmatrix.m[0][0] = m[0];
276         backend_projectmatrix.m[1][0] = m[1];
277         backend_projectmatrix.m[2][0] = m[2];
278         backend_projectmatrix.m[3][0] = m[3];
279         backend_projectmatrix.m[0][1] = m[4];
280         backend_projectmatrix.m[1][1] = m[5];
281         backend_projectmatrix.m[2][1] = m[6];
282         backend_projectmatrix.m[3][1] = m[7];
283         backend_projectmatrix.m[0][2] = m[8];
284         backend_projectmatrix.m[1][2] = m[9];
285         backend_projectmatrix.m[2][2] = m[10];
286         backend_projectmatrix.m[3][2] = m[11];
287         backend_projectmatrix.m[0][3] = m[12];
288         backend_projectmatrix.m[1][3] = m[13];
289         backend_projectmatrix.m[2][3] = m[14];
290         backend_projectmatrix.m[3][3] = m[15];
291         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
292         GL_SetupView_Orientation_Identity();
293 }
294
295 void GL_SetupView_Mode_PerspectiveInfiniteFarClip (double fovx, double fovy, double zNear)
296 {
297         double nudge, m[16];
298
299         if (!r_render.integer)
300                 return;
301
302         // set up viewpoint
303         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
304         qglLoadIdentity();CHECKGLERROR
305         // set view pyramid
306         nudge = 1.0 - 1.0 / (1<<23);
307         m[ 0] = 1.0 / tan(fovx * M_PI / 360.0);
308         m[ 1] = 0;
309         m[ 2] = 0;
310         m[ 3] = 0;
311         m[ 4] = 0;
312         m[ 5] = 1.0 / tan(fovy * M_PI / 360.0);
313         m[ 6] = 0;
314         m[ 7] = 0;
315         m[ 8] = 0;
316         m[ 9] = 0;
317         m[10] = -nudge;
318         m[11] = -1;
319         m[12] = 0;
320         m[13] = 0;
321         m[14] = -2 * zNear * nudge;
322         m[15] = 0;
323         qglLoadMatrixd(m);
324         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
325         GL_SetupView_Orientation_Identity();
326         backend_projectmatrix.m[0][0] = m[0];
327         backend_projectmatrix.m[1][0] = m[1];
328         backend_projectmatrix.m[2][0] = m[2];
329         backend_projectmatrix.m[3][0] = m[3];
330         backend_projectmatrix.m[0][1] = m[4];
331         backend_projectmatrix.m[1][1] = m[5];
332         backend_projectmatrix.m[2][1] = m[6];
333         backend_projectmatrix.m[3][1] = m[7];
334         backend_projectmatrix.m[0][2] = m[8];
335         backend_projectmatrix.m[1][2] = m[9];
336         backend_projectmatrix.m[2][2] = m[10];
337         backend_projectmatrix.m[3][2] = m[11];
338         backend_projectmatrix.m[0][3] = m[12];
339         backend_projectmatrix.m[1][3] = m[13];
340         backend_projectmatrix.m[2][3] = m[14];
341         backend_projectmatrix.m[3][3] = m[15];
342 }
343
344 void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double zNear, double zFar)
345 {
346         double m[16];
347
348         if (!r_render.integer)
349                 return;
350
351         // set up viewpoint
352         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
353         qglLoadIdentity();CHECKGLERROR
354         qglOrtho(x1, x2, y2, y1, zNear, zFar);
355         qglGetDoublev(GL_PROJECTION_MATRIX, m);
356         backend_projectmatrix.m[0][0] = m[0];
357         backend_projectmatrix.m[1][0] = m[1];
358         backend_projectmatrix.m[2][0] = m[2];
359         backend_projectmatrix.m[3][0] = m[3];
360         backend_projectmatrix.m[0][1] = m[4];
361         backend_projectmatrix.m[1][1] = m[5];
362         backend_projectmatrix.m[2][1] = m[6];
363         backend_projectmatrix.m[3][1] = m[7];
364         backend_projectmatrix.m[0][2] = m[8];
365         backend_projectmatrix.m[1][2] = m[9];
366         backend_projectmatrix.m[2][2] = m[10];
367         backend_projectmatrix.m[3][2] = m[11];
368         backend_projectmatrix.m[0][3] = m[12];
369         backend_projectmatrix.m[1][3] = m[13];
370         backend_projectmatrix.m[2][3] = m[14];
371         backend_projectmatrix.m[3][3] = m[15];
372         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
373         GL_SetupView_Orientation_Identity();
374 }
375
376 typedef struct gltextureunit_s
377 {
378         int t1d, t2d, t3d, tcubemap;
379         int arrayenabled;
380         int arrayis3d;
381         const void *pointer_texcoord;
382         float rgbscale, alphascale;
383         int combinergb, combinealpha;
384         // FIXME: add more combine stuff
385         // texmatrixenabled exists only to avoid unnecessary texmatrix compares
386         int texmatrixenabled;
387         matrix4x4_t matrix;
388 }
389 gltextureunit_t;
390
391 static struct
392 {
393         int blendfunc1;
394         int blendfunc2;
395         int blend;
396         GLboolean depthmask;
397         int colormask; // stored as bottom 4 bits: r g b a (3 2 1 0 order)
398         int depthtest;
399         int scissortest;
400         int unit;
401         int clientunit;
402         gltextureunit_t units[MAX_TEXTUREUNITS];
403         float color4f[4];
404         int lockrange_first;
405         int lockrange_count;
406         const void *pointer_vertex;
407         const void *pointer_color;
408 }
409 gl_state;
410
411 void GL_SetupTextureState(void)
412 {
413         int i;
414         gltextureunit_t *unit;
415         CHECKGLERROR
416         gl_state.unit = -1;
417         gl_state.clientunit = -1;
418         for (i = 0;i < backendunits;i++)
419         {
420                 GL_ActiveTexture(i);
421                 GL_ClientActiveTexture(i);
422                 unit = gl_state.units + i;
423                 unit->t1d = 0;
424                 unit->t2d = 0;
425                 unit->t3d = 0;
426                 unit->tcubemap = 0;
427                 unit->arrayenabled = false;
428                 unit->arrayis3d = false;
429                 unit->pointer_texcoord = NULL;
430                 unit->rgbscale = 1;
431                 unit->alphascale = 1;
432                 unit->combinergb = GL_MODULATE;
433                 unit->combinealpha = GL_MODULATE;
434                 unit->texmatrixenabled = false;
435                 unit->matrix = r_identitymatrix;
436                 qglMatrixMode(GL_TEXTURE);
437                 qglLoadIdentity();
438                 qglMatrixMode(GL_MODELVIEW);
439
440                 qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR
441                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
442
443                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
444                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
445                 if (gl_texture3d)
446                 {
447                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
448                 }
449                 if (gl_texturecubemap)
450                 {
451                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
452                 }
453                 if (gl_combine.integer)
454                 {
455                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
456                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);CHECKGLERROR
457                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);CHECKGLERROR
458                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
459                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);CHECKGLERROR // for GL_INTERPOLATE_ARB mode
460                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
461                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
462                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);CHECKGLERROR
463                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);CHECKGLERROR
464                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);CHECKGLERROR
465                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
466                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);CHECKGLERROR
467                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
468                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
469                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
470                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
471                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
472                 }
473                 else
474                 {
475                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
476                 }
477         }
478         CHECKGLERROR
479 }
480
481 void GL_Backend_ResetState(void)
482 {
483         memset(&gl_state, 0, sizeof(gl_state));
484         gl_state.depthtest = true;
485         gl_state.blendfunc1 = GL_ONE;
486         gl_state.blendfunc2 = GL_ZERO;
487         gl_state.blend = false;
488         gl_state.depthmask = GL_TRUE;
489         gl_state.colormask = 15;
490         gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1;
491         gl_state.lockrange_first = 0;
492         gl_state.lockrange_count = 0;
493         gl_state.pointer_vertex = NULL;
494         gl_state.pointer_color = NULL;
495
496         CHECKGLERROR
497
498         qglColorMask(1, 1, 1, 1);
499         qglEnable(GL_CULL_FACE);CHECKGLERROR
500         qglCullFace(GL_FRONT);CHECKGLERROR
501         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
502         qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
503         qglDisable(GL_BLEND);CHECKGLERROR
504         qglDepthMask(gl_state.depthmask);CHECKGLERROR
505
506         qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR
507         qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
508
509         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL);CHECKGLERROR
510         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
511
512         GL_Color(0, 0, 0, 0);
513         GL_Color(1, 1, 1, 1);
514
515         GL_SetupTextureState();
516 }
517
518 void GL_ActiveTexture(int num)
519 {
520         if (gl_state.unit != num)
521         {
522                 gl_state.unit = num;
523                 if (qglActiveTexture)
524                 {
525                         qglActiveTexture(GL_TEXTURE0_ARB + gl_state.unit);
526                         CHECKGLERROR
527                 }
528         }
529 }
530
531 void GL_ClientActiveTexture(int num)
532 {
533         if (gl_state.clientunit != num)
534         {
535                 gl_state.clientunit = num;
536                 if (qglActiveTexture)
537                 {
538                         qglClientActiveTexture(GL_TEXTURE0_ARB + gl_state.clientunit);
539                         CHECKGLERROR
540                 }
541         }
542 }
543
544 void GL_BlendFunc(int blendfunc1, int blendfunc2)
545 {
546         if (gl_state.blendfunc1 != blendfunc1 || gl_state.blendfunc2 != blendfunc2)
547         {
548                 if (r_showtrispass)
549                         return;
550                 qglBlendFunc(gl_state.blendfunc1 = blendfunc1, gl_state.blendfunc2 = blendfunc2);CHECKGLERROR
551                 if (gl_state.blendfunc2 == GL_ZERO)
552                 {
553                         if (gl_state.blendfunc1 == GL_ONE)
554                         {
555                                 if (gl_state.blend)
556                                 {
557                                         gl_state.blend = 0;
558                                         qglDisable(GL_BLEND);CHECKGLERROR
559                                 }
560                         }
561                         else
562                         {
563                                 if (!gl_state.blend)
564                                 {
565                                         gl_state.blend = 1;
566                                         qglEnable(GL_BLEND);CHECKGLERROR
567                                 }
568                         }
569                 }
570                 else
571                 {
572                         if (!gl_state.blend)
573                         {
574                                 gl_state.blend = 1;
575                                 qglEnable(GL_BLEND);CHECKGLERROR
576                         }
577                 }
578         }
579 }
580
581 void GL_DepthMask(int state)
582 {
583         if (gl_state.depthmask != state)
584         {
585                 if (r_showtrispass)
586                         return;
587                 qglDepthMask(gl_state.depthmask = state);CHECKGLERROR
588         }
589 }
590
591 void GL_DepthTest(int state)
592 {
593         if (gl_state.depthtest != state)
594         {
595                 if (r_showtrispass)
596                         return;
597                 gl_state.depthtest = state;
598                 if (gl_state.depthtest)
599                 {
600                         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
601                 }
602                 else
603                 {
604                         qglDisable(GL_DEPTH_TEST);CHECKGLERROR
605                 }
606         }
607 }
608
609 void GL_ColorMask(int r, int g, int b, int a)
610 {
611         int state = r*8 + g*4 + b*2 + a*1;
612         if (gl_state.colormask != state)
613         {
614                 if (r_showtrispass)
615                         return;
616                 gl_state.colormask = state;
617                 qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
618         }
619 }
620
621 void GL_Color(float cr, float cg, float cb, float ca)
622 {
623         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)
624         {
625                 if (r_showtrispass)
626                         return;
627                 gl_state.color4f[0] = cr;
628                 gl_state.color4f[1] = cg;
629                 gl_state.color4f[2] = cb;
630                 gl_state.color4f[3] = ca;
631                 CHECKGLERROR
632                 qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
633                 CHECKGLERROR
634         }
635 }
636
637 void GL_ShowTrisColor(float cr, float cg, float cb, float ca)
638 {
639         if (!r_showtrispass)
640                 return;
641         r_showtrispass = false;
642         GL_Color(cr * r_showtris.value, cg * r_showtris.value, cb * r_showtris.value, ca);
643         r_showtrispass = true;
644 }
645
646
647 void GL_LockArrays(int first, int count)
648 {
649         if (gl_state.lockrange_count != count || gl_state.lockrange_first != first)
650         {
651                 if (gl_state.lockrange_count)
652                 {
653                         gl_state.lockrange_count = 0;
654                         CHECKGLERROR
655                         qglUnlockArraysEXT();
656                         CHECKGLERROR
657                 }
658                 if (count && gl_supportslockarrays && gl_lockarrays.integer && r_render.integer)
659                 {
660                         gl_state.lockrange_first = first;
661                         gl_state.lockrange_count = count;
662                         CHECKGLERROR
663                         qglLockArraysEXT(first, count);
664                         CHECKGLERROR
665                 }
666         }
667 }
668
669 void GL_Scissor (int x, int y, int width, int height)
670 {
671         CHECKGLERROR
672         qglScissor(x, vid.realheight - (y + height),width,height);
673         CHECKGLERROR
674 }
675
676 void GL_ScissorTest(int state)
677 {
678         if(gl_state.scissortest == state)
679                 return;
680
681         CHECKGLERROR
682         if((gl_state.scissortest = state))
683                 qglEnable(GL_SCISSOR_TEST);
684         else
685                 qglDisable(GL_SCISSOR_TEST);
686         CHECKGLERROR
687 }
688
689 void GL_Clear(int mask)
690 {
691         if (r_showtrispass)
692                 return;
693         qglClear(mask);CHECKGLERROR
694 }
695
696 void GL_TransformToScreen(const vec4_t in, vec4_t out)
697 {
698         vec4_t temp;
699         float iw;
700         Matrix4x4_Transform4 (&backend_viewmatrix, in, temp);
701         Matrix4x4_Transform4 (&backend_projectmatrix, temp, out);
702         iw = 1.0f / out[3];
703         out[0] = r_view_x + (out[0] * iw + 1.0f) * r_view_width * 0.5f;
704         out[1] = r_view_y + (out[1] * iw + 1.0f) * r_view_height * 0.5f;
705         out[2] = r_view_z + (out[2] * iw + 1.0f) * r_view_depth * 0.5f;
706 }
707
708 // called at beginning of frame
709 void R_Mesh_Start(void)
710 {
711         BACKENDACTIVECHECK
712         CHECKGLERROR
713         GL_Backend_ResetState();
714 }
715
716 int gl_backend_rebindtextures;
717
718 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
719 {
720         int i;
721         if (offset)
722         {
723                 for (i = 0;i < count;i++)
724                         *out++ = *in++ + offset;
725         }
726         else
727                 memcpy(out, in, sizeof(*out) * count);
728 }
729
730 // renders triangles using vertices from the active arrays
731 int paranoidblah = 0;
732 void R_Mesh_Draw(int numverts, int numtriangles, const int *elements)
733 {
734         int numelements = numtriangles * 3;
735         if (numverts == 0 || numtriangles == 0)
736         {
737                 Con_Printf("R_Mesh_Draw(%d, %d, %08p);\n", numverts, numtriangles, elements);
738                 return;
739         }
740         CHECKGLERROR
741         if (r_showtrispass)
742         {
743                 R_Mesh_Draw_ShowTris(numverts, numtriangles, elements);
744                 return;
745         }
746         c_meshs++;
747         c_meshelements += numelements;
748         if (gl_paranoid.integer)
749         {
750                 int i, j, size;
751                 const int *p;
752                 if (!qglIsEnabled(GL_VERTEX_ARRAY))
753                         Con_Print("R_Mesh_Draw: vertex array not enabled\n");
754                 for (j = 0, size = numverts * (int)sizeof(float[3]), p = gl_state.pointer_vertex;j < size;j += sizeof(int), p++)
755                         paranoidblah += *p;
756                 if (gl_state.pointer_color)
757                 {
758                         if (!qglIsEnabled(GL_COLOR_ARRAY))
759                                 Con_Print("R_Mesh_Draw: color array set but not enabled\n");
760                         for (j = 0, size = numverts * (int)sizeof(float[4]), p = gl_state.pointer_color;j < size;j += sizeof(int), p++)
761                                 paranoidblah += *p;
762                 }
763                 for (i = 0;i < backendunits;i++)
764                 {
765                         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)
766                         {
767                                 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))
768                                         Con_Print("R_Mesh_Draw: array enabled but no texture bound\n");
769                                 GL_ClientActiveTexture(i);
770                                 if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
771                                         Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
772                                 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++)
773                                         paranoidblah += *p;
774                         }
775                 }
776                 for (i = 0;i < numtriangles * 3;i++)
777                 {
778                         if (elements[i] < 0 || elements[i] >= numverts)
779                         {
780                                 Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range 0 - %i) in elements list\n", elements[i], numverts);
781                                 return;
782                         }
783                 }
784                 CHECKGLERROR
785         }
786         if (r_render.integer)
787         {
788                 CHECKGLERROR
789                 if (gl_mesh_testmanualfeeding.integer)
790                 {
791                         int i, j;
792                         const GLfloat *p;
793                         qglBegin(GL_TRIANGLES);
794                         for (i = 0;i < numtriangles * 3;i++)
795                         {
796                                 for (j = 0;j < backendunits;j++)
797                                 {
798                                         if (gl_state.units[j].pointer_texcoord)
799                                         {
800                                                 if (backendunits > 1)
801                                                 {
802                                                         if (gl_state.units[j].t3d || gl_state.units[j].tcubemap)
803                                                         {
804                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
805                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
806                                                         }
807                                                         else
808                                                         {
809                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
810                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
811                                                         }
812                                                 }
813                                                 else
814                                                 {
815                                                         if (gl_state.units[j].t3d || gl_state.units[j].tcubemap)
816                                                         {
817                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
818                                                                 qglTexCoord3f(p[0], p[1], p[2]);
819                                                         }
820                                                         else
821                                                         {
822                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
823                                                                 qglTexCoord2f(p[0], p[1]);
824                                                         }
825                                                 }
826                                         }
827                                 }
828                                 if (gl_state.pointer_color)
829                                 {
830                                         p = ((const GLfloat *)(gl_state.pointer_color)) + elements[i] * 4;
831                                         qglColor4f(p[0], p[1], p[2], p[3]);
832                                 }
833                                 p = ((const GLfloat *)(gl_state.pointer_vertex)) + elements[i] * 3;
834                                 qglVertex3f(p[0], p[1], p[2]);
835                         }
836                         qglEnd();
837                         CHECKGLERROR
838                 }
839                 else if (gl_mesh_testarrayelement.integer)
840                 {
841                         int i;
842                         qglBegin(GL_TRIANGLES);
843                         for (i = 0;i < numtriangles * 3;i++)
844                         {
845                                 qglArrayElement(elements[i]);
846                         }
847                         qglEnd();
848                         CHECKGLERROR
849                 }
850                 else if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
851                 {
852                         qglDrawRangeElements(GL_TRIANGLES, 0, numverts, numelements, GL_UNSIGNED_INT, elements);CHECKGLERROR
853                 }
854                 else
855                 {
856                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, elements);CHECKGLERROR
857                 }
858                 CHECKGLERROR
859         }
860 }
861
862 // restores backend state, used when done with 3D rendering
863 void R_Mesh_Finish(void)
864 {
865         int i;
866         BACKENDACTIVECHECK
867         CHECKGLERROR
868         GL_LockArrays(0, 0);
869         CHECKGLERROR
870
871         for (i = backendunits - 1;i >= 0;i--)
872         {
873                 if (qglActiveTexture)
874                         qglActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
875                 if (qglClientActiveTexture)
876                         qglClientActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
877                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
878                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
879                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
880                 if (gl_texture3d)
881                 {
882                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
883                 }
884                 if (gl_texturecubemap)
885                 {
886                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
887                 }
888                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
889                 if (gl_combine.integer)
890                 {
891                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
892                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
893                 }
894         }
895         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
896         qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
897
898         qglDisable(GL_BLEND);CHECKGLERROR
899         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
900         qglDepthMask(GL_TRUE);CHECKGLERROR
901         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR
902 }
903
904 void R_Mesh_Matrix(const matrix4x4_t *matrix)
905 {
906         if (memcmp(matrix, &backend_modelmatrix, sizeof(matrix4x4_t)))
907         {
908                 backend_modelmatrix = *matrix;
909                 Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewmatrix, matrix);
910                 Matrix4x4_Transpose(&backend_glmodelviewmatrix, &backend_modelviewmatrix);
911                 qglLoadMatrixf(&backend_glmodelviewmatrix.m[0][0]);
912         }
913 }
914
915 void R_Mesh_State(const rmeshstate_t *m)
916 {
917         int i, combinergb, combinealpha, scale;
918         gltextureunit_t *unit;
919         matrix4x4_t tempmatrix;
920
921         BACKENDACTIVECHECK
922
923         if (gl_state.pointer_vertex != m->pointer_vertex)
924         {
925                 gl_state.pointer_vertex = m->pointer_vertex;
926                 CHECKGLERROR
927                 qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), gl_state.pointer_vertex);
928                 CHECKGLERROR
929         }
930
931         if (r_showtrispass)
932                 return;
933
934         if (gl_state.pointer_color != m->pointer_color)
935         {
936                 CHECKGLERROR
937                 if (!gl_state.pointer_color)
938                 {
939                         qglEnableClientState(GL_COLOR_ARRAY);
940                         CHECKGLERROR
941                 }
942                 else if (!m->pointer_color)
943                 {
944                         qglDisableClientState(GL_COLOR_ARRAY);
945                         CHECKGLERROR
946                         // when color array is on the glColor gets trashed, set it again
947                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
948                         CHECKGLERROR
949                 }
950                 gl_state.pointer_color = m->pointer_color;
951                 qglColorPointer(4, GL_FLOAT, sizeof(float[4]), gl_state.pointer_color);
952                 CHECKGLERROR
953         }
954
955         if (gl_backend_rebindtextures)
956         {
957                 gl_backend_rebindtextures = false;
958                 GL_SetupTextureState();
959         }
960
961         for (i = 0, unit = gl_state.units;i < backendunits;i++, unit++)
962         {
963                 // update 1d texture binding
964                 if (unit->t1d != m->tex1d[i])
965                 {
966                         if (m->tex1d[i])
967                         {
968                                 if (unit->t1d == 0)
969                                 {
970                                         GL_ActiveTexture(i);
971                                         qglEnable(GL_TEXTURE_1D);CHECKGLERROR
972                                 }
973                                 unit->t1d = m->tex1d[i];
974                                 GL_ActiveTexture(i);
975                                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
976                         }
977                         else
978                         {
979                                 if (unit->t1d)
980                                 {
981                                         unit->t1d = 0;
982                                         GL_ActiveTexture(i);
983                                         qglDisable(GL_TEXTURE_1D);CHECKGLERROR
984                                 }
985                         }
986                 }
987                 // update 2d texture binding
988                 if (unit->t2d != m->tex[i])
989                 {
990                         if (m->tex[i])
991                         {
992                                 if (unit->t2d == 0)
993                                 {
994                                         GL_ActiveTexture(i);
995                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
996                                 }
997                                 unit->t2d = m->tex[i];
998                                 GL_ActiveTexture(i);
999                                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1000                         }
1001                         else
1002                         {
1003                                 if (unit->t2d)
1004                                 {
1005                                         unit->t2d = 0;
1006                                         GL_ActiveTexture(i);
1007                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1008                                 }
1009                         }
1010                 }
1011                 // update 3d texture binding
1012                 if (unit->t3d != m->tex3d[i])
1013                 {
1014                         if (m->tex3d[i])
1015                         {
1016                                 if (unit->t3d == 0)
1017                                 {
1018                                         GL_ActiveTexture(i);
1019                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1020                                 }
1021                                 unit->t3d = m->tex3d[i];
1022                                 GL_ActiveTexture(i);
1023                                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1024                         }
1025                         else
1026                         {
1027                                 if (unit->t3d)
1028                                 {
1029                                         unit->t3d = 0;
1030                                         GL_ActiveTexture(i);
1031                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1032                                 }
1033                         }
1034                 }
1035                 // update cubemap texture binding
1036                 if (unit->tcubemap != m->texcubemap[i])
1037                 {
1038                         if (m->texcubemap[i])
1039                         {
1040                                 if (unit->tcubemap == 0)
1041                                 {
1042                                         GL_ActiveTexture(i);
1043                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1044                                 }
1045                                 unit->tcubemap = m->texcubemap[i];
1046                                 GL_ActiveTexture(i);
1047                                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1048                         }
1049                         else
1050                         {
1051                                 if (unit->tcubemap)
1052                                 {
1053                                         unit->tcubemap = 0;
1054                                         GL_ActiveTexture(i);
1055                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1056                                 }
1057                         }
1058                 }
1059                 // update texture unit settings if the unit is enabled
1060                 if (unit->t1d || unit->t2d || unit->t3d || unit->tcubemap)
1061                 {
1062                         // texture unit is enabled, enable the array
1063                         if (!unit->arrayenabled)
1064                         {
1065                                 unit->arrayenabled = true;
1066                                 GL_ClientActiveTexture(i);
1067                                 qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1068                         }
1069                         // update combine settings
1070                         if (gl_combine.integer)
1071                         {
1072                                 // GL_ARB_texture_env_combine
1073                                 combinergb = m->texcombinergb[i] ? m->texcombinergb[i] : GL_MODULATE;
1074                                 if (unit->combinergb != combinergb)
1075                                 {
1076                                         unit->combinergb = combinergb;
1077                                         GL_ActiveTexture(i);
1078                                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
1079                                 }
1080                                 combinealpha = m->texcombinealpha[i] ? m->texcombinealpha[i] : GL_MODULATE;
1081                                 if (unit->combinealpha != combinealpha)
1082                                 {
1083                                         unit->combinealpha = combinealpha;
1084                                         GL_ActiveTexture(i);
1085                                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
1086                                 }
1087                                 scale = max(m->texrgbscale[i], 1);
1088                                 if (unit->rgbscale != scale)
1089                                 {
1090                                         GL_ActiveTexture(i);
1091                                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = scale));CHECKGLERROR
1092                                 }
1093                                 scale = max(m->texalphascale[i], 1);
1094                                 if (unit->alphascale != scale)
1095                                 {
1096                                         GL_ActiveTexture(i);
1097                                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = scale));CHECKGLERROR
1098                                 }
1099                         }
1100                         else
1101                         {
1102                                 // normal GL texenv
1103                                 combinergb = m->texcombinergb[i] ? m->texcombinergb[i] : GL_MODULATE;
1104                                 if (unit->combinergb != combinergb)
1105                                 {
1106                                         unit->combinergb = combinergb;
1107                                         GL_ActiveTexture(i);
1108                                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
1109                                 }
1110                         }
1111                         // update array settings
1112                         if (m->pointer_texcoord3f[i])
1113                         {
1114                                 // 3d texcoord array
1115                                 if (unit->pointer_texcoord != m->pointer_texcoord3f[i] || !unit->arrayis3d)
1116                                 {
1117                                         unit->pointer_texcoord = m->pointer_texcoord3f[i];
1118                                         unit->arrayis3d = true;
1119                                         GL_ClientActiveTexture(i);
1120                                         qglTexCoordPointer(3, GL_FLOAT, sizeof(float[3]), unit->pointer_texcoord);
1121                                         CHECKGLERROR
1122                                 }
1123                         }
1124                         else
1125                         {
1126                                 // 2d texcoord array
1127                                 if (unit->pointer_texcoord != m->pointer_texcoord[i] || unit->arrayis3d)
1128                                 {
1129                                         unit->pointer_texcoord = m->pointer_texcoord[i];
1130                                         unit->arrayis3d = false;
1131                                         GL_ClientActiveTexture(i);
1132                                         qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), unit->pointer_texcoord);
1133                                         CHECKGLERROR
1134                                 }
1135                         }
1136                         // update texmatrix
1137                         if (m->texmatrix[i].m[3][3])
1138                         {
1139                                 // texmatrix specified, check if it is different
1140                                 if (!unit->texmatrixenabled || memcmp(&unit->matrix, &m->texmatrix[i], sizeof(matrix4x4_t)))
1141                                 {
1142                                         unit->texmatrixenabled = true;
1143                                         unit->matrix = m->texmatrix[i];
1144                                         Matrix4x4_Transpose(&tempmatrix, &unit->matrix);
1145                                         qglMatrixMode(GL_TEXTURE);
1146                                         GL_ActiveTexture(i);
1147                                         qglLoadMatrixf(&tempmatrix.m[0][0]);
1148                                         qglMatrixMode(GL_MODELVIEW);
1149                                 }
1150                         }
1151                         else
1152                         {
1153                                 // no texmatrix specified, revert to identity
1154                                 if (unit->texmatrixenabled)
1155                                 {
1156                                         unit->texmatrixenabled = false;
1157                                         qglMatrixMode(GL_TEXTURE);
1158                                         GL_ActiveTexture(i);
1159                                         qglLoadIdentity();
1160                                         qglMatrixMode(GL_MODELVIEW);
1161                                 }
1162                         }
1163                 }
1164                 else
1165                 {
1166                         // texture unit is disabled, disable the array
1167                         if (unit->arrayenabled)
1168                         {
1169                                 unit->arrayenabled = false;
1170                                 GL_ClientActiveTexture(i);
1171                                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1172                         }
1173                         // no need to update most settings on a disabled texture unit
1174                 }
1175         }
1176 }
1177
1178 void R_Mesh_Draw_ShowTris(int numverts, int numtriangles, const int *elements)
1179 {
1180         qglBegin(GL_LINES);
1181         for (;numtriangles;numtriangles--, elements += 3)
1182         {
1183                 qglArrayElement(elements[0]);qglArrayElement(elements[1]);
1184                 qglArrayElement(elements[1]);qglArrayElement(elements[2]);
1185                 qglArrayElement(elements[2]);qglArrayElement(elements[0]);
1186         }
1187         qglEnd();
1188         CHECKGLERROR
1189 }
1190
1191 /*
1192 ==============================================================================
1193
1194                                                 SCREEN SHOTS
1195
1196 ==============================================================================
1197 */
1198
1199 qboolean SCR_ScreenShot(char *filename, qbyte *buffer1, qbyte *buffer2, qbyte *buffer3, int x, int y, int width, int height, qboolean flipx, qboolean flipy, qboolean flipdiagonal, qboolean jpeg)
1200 {
1201         int     indices[3] = {0,1,2};
1202         qboolean ret;
1203
1204         if (!r_render.integer)
1205                 return false;
1206
1207         qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer1);
1208         CHECKGLERROR
1209
1210         if (scr_screenshot_gamma.value != 1)
1211         {
1212                 int i;
1213                 double igamma = 1.0 / scr_screenshot_gamma.value;
1214                 unsigned char ramp[256];
1215                 for (i = 0;i < 256;i++)
1216                         ramp[i] = (unsigned char) (pow(i * (1.0 / 255.0), igamma) * 255.0);
1217                 for (i = 0;i < width*height*3;i++)
1218                         buffer1[i] = ramp[buffer1[i]];
1219         }
1220
1221         Image_CopyMux (buffer2, buffer1, width, height, flipx, flipy, flipdiagonal, 3, 3, indices);
1222
1223         if (jpeg)
1224                 ret = JPEG_SaveImage_preflipped (filename, width, height, buffer2);
1225         else
1226                 ret = Image_WriteTGARGB_preflipped (filename, width, height, buffer2, buffer3);
1227
1228         return ret;
1229 }
1230
1231 //=============================================================================
1232
1233 void R_ClearScreen(void)
1234 {
1235         if (r_render.integer)
1236         {
1237                 // clear to black
1238                 qglClearColor(0,0,0,0);CHECKGLERROR
1239                 qglClearDepth(1);CHECKGLERROR
1240                 if (gl_stencil)
1241                 {
1242                         // LordHavoc: we use a stencil centered around 128 instead of 0,
1243                         // to avoid clamping interfering with strange shadow volume
1244                         // drawing orders
1245                         qglClearStencil(128);CHECKGLERROR
1246                 }
1247                 // clear the screen
1248                 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | (gl_stencil ? GL_STENCIL_BUFFER_BIT : 0));
1249                 // set dithering mode
1250                 if (gl_dither.integer)
1251                 {
1252                         qglEnable(GL_DITHER);CHECKGLERROR
1253                 }
1254                 else
1255                 {
1256                         qglDisable(GL_DITHER);CHECKGLERROR
1257                 }
1258         }
1259 }
1260
1261 /*
1262 ====================
1263 CalcFov
1264 ====================
1265 */
1266 float CalcFov (float fov_x, float width, float height)
1267 {
1268         // calculate vision size and alter by aspect, then convert back to angle
1269         return atan (((height/width)/vid_pixelaspect.value)*tan(fov_x/360.0*M_PI))*360.0/M_PI; 
1270 }
1271
1272 int r_stereo_side;
1273
1274 void SCR_DrawScreen (void)
1275 {
1276         for (r_showtrispass = 0;r_showtrispass <= (r_showtris.value > 0);r_showtrispass++)
1277         {
1278                 R_Mesh_Start();
1279
1280                 R_TimeReport("setup");
1281
1282                 if (r_showtrispass)
1283                 {
1284                         rmeshstate_t m;
1285                         r_showtrispass = 0;
1286                         GL_BlendFunc(GL_ONE, GL_ONE);
1287                         GL_DepthTest(GL_FALSE);
1288                         GL_DepthMask(GL_FALSE);
1289                         memset(&m, 0, sizeof(m));
1290                         R_Mesh_State(&m);
1291                         GL_ShowTrisColor(0.2,0.2,0.2,1);
1292                         r_showtrispass = 1;
1293                 }
1294
1295                 if (cls.signon == SIGNONS)
1296                 {
1297                         float size;
1298
1299                         size = scr_viewsize.value * (1.0 / 100.0);
1300                         size = min(size, 1);
1301
1302                         if (r_stereo_sidebyside.integer)
1303                         {
1304                                 r_refdef.width = vid.realwidth * size / 2.5;
1305                                 r_refdef.height = vid.realheight * size / 2.5 * (1 - bound(0, r_letterbox.value, 100) / 100);
1306                                 r_refdef.x = (vid.realwidth - r_refdef.width * 2.5) * 0.5;
1307                                 r_refdef.y = (vid.realheight - r_refdef.height)/2;
1308                                 if (r_stereo_side)
1309                                         r_refdef.x += r_refdef.width * 1.5;
1310                         }
1311                         else
1312                         {
1313                                 r_refdef.width = vid.realwidth * size;
1314                                 r_refdef.height = vid.realheight * size * (1 - bound(0, r_letterbox.value, 100) / 100);
1315                                 r_refdef.x = (vid.realwidth - r_refdef.width)/2;
1316                                 r_refdef.y = (vid.realheight - r_refdef.height)/2;
1317                         }
1318
1319                         // LordHavoc: viewzoom (zoom in for sniper rifles, etc)
1320                         r_refdef.fov_x = scr_fov.value * cl.viewzoom * r_refdef.fovscale_x;
1321                         r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.width, r_refdef.height) * r_refdef.fovscale_y;
1322
1323                         R_RenderView();
1324
1325                         if (scr_zoomwindow.integer)
1326                         {
1327                                 float sizex = bound(10, scr_zoomwindow_viewsizex.value, 100) / 100.0;
1328                                 float sizey = bound(10, scr_zoomwindow_viewsizey.value, 100) / 100.0;
1329                                 r_refdef.width = vid.realwidth * sizex;
1330                                 r_refdef.height = vid.realheight * sizey;
1331                                 r_refdef.x = (vid.realwidth - r_refdef.width)/2;
1332                                 r_refdef.y = 0;
1333                                 r_refdef.fov_x = scr_zoomwindow_fov.value * r_refdef.fovscale_x;
1334                                 r_refdef.fov_y = CalcFov(r_refdef.fov_x, r_refdef.width, r_refdef.height) * r_refdef.fovscale_y;
1335
1336                                 R_RenderView();
1337                         }
1338                 }
1339
1340                 if (!r_stereo_sidebyside.integer)
1341                 {
1342                         r_refdef.width = vid.realwidth;
1343                         r_refdef.height = vid.realheight;
1344                         r_refdef.x = 0;
1345                         r_refdef.y = 0;
1346                 }
1347
1348                 // draw 2D stuff
1349                 R_DrawQueue();
1350
1351                 R_Mesh_Finish();
1352
1353                 R_TimeReport("meshfinish");
1354         }
1355         r_showtrispass = 0;
1356 }
1357
1358 void SCR_UpdateLoadingScreen (void)
1359 {
1360         float x, y;
1361         cachepic_t *pic;
1362         rmeshstate_t m;
1363         // don't do anything if not initialized yet
1364         if (vid_hidden)
1365                 return;
1366         r_showtrispass = 0;
1367         VID_GetWindowSize(&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
1368         VID_UpdateGamma(false);
1369         qglViewport(0, 0, vid.realwidth, vid.realheight);
1370         //qglDisable(GL_SCISSOR_TEST);
1371         //qglDepthMask(1);
1372         qglColorMask(1,1,1,1);
1373         //qglClearColor(0,0,0,0);
1374         //qglClear(GL_COLOR_BUFFER_BIT);
1375         //qglCullFace(GL_FRONT);
1376         //qglDisable(GL_CULL_FACE);
1377         //R_ClearScreen();
1378         R_Textures_Frame();
1379         GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
1380         R_Mesh_Start();
1381         R_Mesh_Matrix(&r_identitymatrix);
1382         // draw the loading plaque
1383         pic = Draw_CachePic("gfx/loading.lmp");
1384         x = (vid_conwidth.integer - pic->width)/2;
1385         y = (vid_conheight.integer - pic->height)/2;
1386         GL_Color(1,1,1,1);
1387         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1388         GL_DepthTest(false);
1389         memset(&m, 0, sizeof(m));
1390         m.pointer_vertex = varray_vertex3f;
1391         m.pointer_texcoord[0] = varray_texcoord2f[0];
1392         m.tex[0] = R_GetTexture(pic->tex);
1393         R_Mesh_State(&m);
1394         varray_vertex3f[0] = varray_vertex3f[9] = x;
1395         varray_vertex3f[1] = varray_vertex3f[4] = y;
1396         varray_vertex3f[3] = varray_vertex3f[6] = x + pic->width;
1397         varray_vertex3f[7] = varray_vertex3f[10] = y + pic->height;
1398         varray_texcoord2f[0][0] = 0;varray_texcoord2f[0][1] = 0;
1399         varray_texcoord2f[0][2] = 1;varray_texcoord2f[0][3] = 0;
1400         varray_texcoord2f[0][4] = 1;varray_texcoord2f[0][5] = 1;
1401         varray_texcoord2f[0][6] = 0;varray_texcoord2f[0][7] = 1;
1402         GL_LockArrays(0, 4);
1403         R_Mesh_Draw(4, 2, polygonelements);
1404         GL_LockArrays(0, 0);
1405         R_Mesh_Finish();
1406         // refresh
1407         VID_Finish();
1408 }
1409
1410 /*
1411 ==================
1412 SCR_UpdateScreen
1413
1414 This is called every frame, and can also be called explicitly to flush
1415 text to the screen.
1416 ==================
1417 */
1418 void SCR_UpdateScreen (void)
1419 {
1420         if (vid_hidden)
1421                 return;
1422
1423         if (r_textureunits.integer > gl_textureunits)
1424                 Cvar_SetValueQuick(&r_textureunits, gl_textureunits);
1425         if (r_textureunits.integer < 1)
1426                 Cvar_SetValueQuick(&r_textureunits, 1);
1427
1428         if (gl_combine.integer && (!gl_combine_extension || r_textureunits.integer < 2))
1429                 Cvar_SetValueQuick(&gl_combine, 0);
1430
1431         CHECKGLERROR
1432         qglViewport(0, 0, vid.realwidth, vid.realheight);
1433         qglDisable(GL_SCISSOR_TEST);
1434         qglDepthMask(1);
1435         qglColorMask(1,1,1,1);
1436         qglClearColor(0,0,0,0);
1437         qglClear(GL_COLOR_BUFFER_BIT);
1438         CHECKGLERROR
1439
1440         R_TimeReport("clear");
1441
1442         if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer || r_stereo_sidebyside.integer)
1443         {
1444                 matrix4x4_t originalmatrix = r_refdef.viewentitymatrix;
1445                 r_refdef.viewentitymatrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * -0.5f * r_refdef.viewentitymatrix.m[0][1];
1446                 r_refdef.viewentitymatrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * -0.5f * r_refdef.viewentitymatrix.m[1][1];
1447                 r_refdef.viewentitymatrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * -0.5f * r_refdef.viewentitymatrix.m[2][1];
1448
1449                 if (r_stereo_sidebyside.integer)
1450                         r_stereo_side = 0;
1451
1452                 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1453                 {
1454                         r_refdef.colormask[0] = 1;
1455                         r_refdef.colormask[1] = 0;
1456                         r_refdef.colormask[2] = 0;
1457                 }
1458
1459                 SCR_DrawScreen();
1460
1461                 r_refdef.viewentitymatrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * 0.5f * r_refdef.viewentitymatrix.m[0][1];
1462                 r_refdef.viewentitymatrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * 0.5f * r_refdef.viewentitymatrix.m[1][1];
1463                 r_refdef.viewentitymatrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * 0.5f * r_refdef.viewentitymatrix.m[2][1];
1464
1465                 if (r_stereo_sidebyside.integer)
1466                         r_stereo_side = 1;
1467
1468                 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1469                 {
1470                         r_refdef.colormask[0] = 0;
1471                         r_refdef.colormask[1] = r_stereo_redcyan.integer || r_stereo_redgreen.integer;
1472                         r_refdef.colormask[2] = r_stereo_redcyan.integer || r_stereo_redblue.integer;
1473                 }
1474
1475                 SCR_DrawScreen();
1476
1477                 r_refdef.viewentitymatrix = originalmatrix;
1478         }
1479         else
1480         {
1481                 r_showtrispass = false;
1482                 SCR_DrawScreen();
1483         
1484                 if (r_showtris.value > 0)
1485                 {
1486                         rmeshstate_t m;
1487                         GL_BlendFunc(GL_ONE, GL_ONE);
1488                         GL_DepthTest(GL_FALSE);
1489                         GL_DepthMask(GL_FALSE);
1490                         memset(&m, 0, sizeof(m));
1491                         R_Mesh_State(&m);
1492                         r_showtrispass = true;
1493                         GL_ShowTrisColor(0.2,0.2,0.2,1);
1494                         SCR_DrawScreen();
1495                         r_showtrispass = false;
1496                 }
1497         }
1498
1499         VID_Finish();
1500         R_TimeReport("finish");
1501 }
1502
1503
1504 //===========================================================================
1505 // dynamic vertex array buffer subsystem
1506 //===========================================================================
1507
1508 // FIXME: someday this should be dynamically allocated and resized?
1509 float varray_vertex3f[65536*3];
1510 float varray_svector3f[65536*3];
1511 float varray_tvector3f[65536*3];
1512 float varray_normal3f[65536*3];
1513 float varray_color4f[65536*4];
1514 float varray_texcoord2f[4][65536*2];
1515 float varray_texcoord3f[4][65536*3];
1516 int earray_element3i[65536];
1517 float varray_vertex3f2[65536*3];
1518
1519 //===========================================================================
1520 // vertex array caching subsystem
1521 //===========================================================================
1522
1523 typedef struct rcachearraylink_s
1524 {
1525         struct rcachearraylink_s *next, *prev;
1526         struct rcachearrayitem_s *data;
1527 }
1528 rcachearraylink_t;
1529
1530 typedef struct rcachearrayitem_s
1531 {
1532         // the original request structure
1533         rcachearrayrequest_t request;
1534         // active
1535         int active;
1536         // offset into r_mesh_rcachedata
1537         int offset;
1538         // for linking this into the sequential list
1539         rcachearraylink_t sequentiallink;
1540         // for linking this into the lookup list
1541         rcachearraylink_t hashlink;
1542 }
1543 rcachearrayitem_t;
1544
1545 #define RCACHEARRAY_HASHSIZE 65536
1546 #define RCACHEARRAY_ITEMS 4096
1547 #define RCACHEARRAY_DEFAULTSIZE (4 << 20)
1548
1549 // all active items are linked into this chain in sorted order
1550 static rcachearraylink_t r_mesh_rcachesequentialchain;
1551 // all inactive items are linked into this chain in unknown order
1552 static rcachearraylink_t r_mesh_rcachefreechain;
1553 // all active items are also linked into these chains (using their hashlink)
1554 static rcachearraylink_t r_mesh_rcachechain[RCACHEARRAY_HASHSIZE];
1555
1556 // all items are stored here, whether active or inactive
1557 static rcachearrayitem_t r_mesh_rcacheitems[RCACHEARRAY_ITEMS];
1558
1559 // size of data buffer
1560 static int r_mesh_rcachedata_size = RCACHEARRAY_DEFAULTSIZE;
1561 // data buffer
1562 static qbyte r_mesh_rcachedata[RCACHEARRAY_DEFAULTSIZE];
1563
1564 // current state
1565 static int r_mesh_rcachedata_offset;
1566 static rcachearraylink_t *r_mesh_rcachesequentialchain_current;
1567
1568 static void R_Mesh_CacheArray_Startup(void)
1569 {
1570         int i;
1571         rcachearraylink_t *l;
1572         // prepare all the linked lists
1573         l = &r_mesh_rcachesequentialchain;l->next = l->prev = l;l->data = NULL;
1574         l = &r_mesh_rcachefreechain;l->next = l->prev = l;l->data = NULL;
1575         memset(&r_mesh_rcachechain, 0, sizeof(r_mesh_rcachechain));
1576         for (i = 0;i < RCACHEARRAY_HASHSIZE;i++)
1577         {
1578                 l = &r_mesh_rcachechain[i];
1579                 l->next = l->prev = l;
1580                 l->data = NULL;
1581         }
1582         memset(&r_mesh_rcacheitems, 0, sizeof(r_mesh_rcacheitems));
1583         for (i = 0;i < RCACHEARRAY_ITEMS;i++)
1584         {
1585                 r_mesh_rcacheitems[i].hashlink.data = r_mesh_rcacheitems[i].sequentiallink.data = &r_mesh_rcacheitems[i];
1586                 l = &r_mesh_rcacheitems[i].sequentiallink;
1587                 l->next = &r_mesh_rcachefreechain;
1588                 l->prev = l->next->prev;
1589                 l->next->prev = l->prev->next = l;
1590         }
1591         // clear other state
1592         r_mesh_rcachedata_offset = 0;
1593         r_mesh_rcachesequentialchain_current = &r_mesh_rcachesequentialchain;
1594 }
1595
1596 static void R_Mesh_CacheArray_Shutdown(void)
1597 {
1598 }
1599
1600 /*
1601 static void R_Mesh_CacheArray_ValidateState(int num)
1602 {
1603         rcachearraylink_t *l, *lhead;
1604         lhead = &r_mesh_rcachesequentialchain;
1605         if (r_mesh_rcachesequentialchain_current == lhead)
1606                 return;
1607         for (l = lhead->next;l != lhead;l = l->next)
1608                 if (r_mesh_rcachesequentialchain_current == l)
1609                         return;
1610         Sys_Error("%i", num);
1611 }
1612 */
1613
1614 int R_Mesh_CacheArray(rcachearrayrequest_t *r)
1615 {
1616         rcachearraylink_t *l, *lhead, *lnext;
1617         rcachearrayitem_t *d;
1618         int hashindex, offset, offsetend;
1619
1620         //R_Mesh_CacheArray_ValidateState(3);
1621         // calculate a hashindex to choose a cache chain
1622         r->data = NULL;
1623         hashindex = CRC_Block((void *)r, sizeof(*r)) % RCACHEARRAY_HASHSIZE;
1624
1625         // is it already cached?
1626         for (lhead = &r_mesh_rcachechain[hashindex], l = lhead->next;l != lhead;l = l->next)
1627         {
1628                 if (!memcmp(&l->data->request, r, sizeof(l->data->request)))
1629                 {
1630                         // we have it cached already
1631                         r->data = r_mesh_rcachedata + l->data->offset;
1632                         return false;
1633                 }
1634         }
1635
1636         // we need to add a new cache item, this means finding a place for the new
1637         // data and making sure we have a free item available, lots of work...
1638
1639         // check if buffer needs to wrap
1640         if (r_mesh_rcachedata_offset + r->data_size > r_mesh_rcachedata_size)
1641         {
1642                 /*
1643                 if (r->data_size * 10 > r_mesh_rcachedata_size)
1644                 {
1645                         // realloc whole cache
1646                 }
1647                 */
1648                 // reset back to start
1649                 r_mesh_rcachedata_offset = 0;
1650                 r_mesh_rcachesequentialchain_current = &r_mesh_rcachesequentialchain;
1651         }
1652         offset = r_mesh_rcachedata_offset;
1653         r_mesh_rcachedata_offset += r->data_size;
1654         offsetend = r_mesh_rcachedata_offset;
1655         //R_Mesh_CacheArray_ValidateState(4);
1656
1657         /*
1658         {
1659                 int n;
1660                 for (lhead = &r_mesh_rcachesequentialchain, l = lhead->next, n = 0;l != lhead;l = l->next, n++);
1661                 Con_Printf("R_Mesh_CacheArray: new data range %i:%i, %i items are already linked\n", offset, offsetend, n);
1662         }
1663         */
1664
1665         // make room for the new data (remove old items)
1666         lhead = &r_mesh_rcachesequentialchain;
1667         l = r_mesh_rcachesequentialchain_current;
1668         if (l == lhead)
1669                 l = l->next;
1670         while (l != lhead && l->data->offset < offsetend && l->data->offset + l->data->request.data_size > offset)
1671         {
1672         //r_mesh_rcachesequentialchain_current = l;
1673         //R_Mesh_CacheArray_ValidateState(8);
1674                 lnext = l->next;
1675                 // if at the end of the chain, wrap around
1676                 if (lnext == lhead)
1677                         lnext = lnext->next;
1678         //r_mesh_rcachesequentialchain_current = lnext;
1679         //R_Mesh_CacheArray_ValidateState(10);
1680
1681                 // unlink from sequential chain
1682                 l->next->prev = l->prev;
1683                 l->prev->next = l->next;
1684         //R_Mesh_CacheArray_ValidateState(11);
1685                 // link into free chain
1686                 l->next = &r_mesh_rcachefreechain;
1687                 l->prev = l->next->prev;
1688                 l->next->prev = l->prev->next = l;
1689         //R_Mesh_CacheArray_ValidateState(12);
1690
1691                 l = &l->data->hashlink;
1692                 // unlink from hash chain
1693                 l->next->prev = l->prev;
1694                 l->prev->next = l->next;
1695
1696                 l = lnext;
1697         //r_mesh_rcachesequentialchain_current = l;
1698         //R_Mesh_CacheArray_ValidateState(9);
1699         }
1700         //r_mesh_rcachesequentialchain_current = l;
1701         //R_Mesh_CacheArray_ValidateState(5);
1702         // gobble an extra item if we have no free items available
1703         if (r_mesh_rcachefreechain.next == &r_mesh_rcachefreechain)
1704         {
1705                 lnext = l->next;
1706
1707                 // unlink from sequential chain
1708                 l->next->prev = l->prev;
1709                 l->prev->next = l->next;
1710                 // link into free chain
1711                 l->next = &r_mesh_rcachefreechain;
1712                 l->prev = l->next->prev;
1713                 l->next->prev = l->prev->next = l;
1714
1715                 l = &l->data->hashlink;
1716                 // unlink from hash chain
1717                 l->next->prev = l->prev;
1718                 l->prev->next = l->next;
1719
1720                 l = lnext;
1721         }
1722         r_mesh_rcachesequentialchain_current = l;
1723         //R_Mesh_CacheArray_ValidateState(6);
1724
1725         // now take an item from the free chain
1726         l = r_mesh_rcachefreechain.next;
1727         // set it up
1728         d = l->data;
1729         d->request = *r;
1730         d->offset = offset;
1731         // unlink
1732         l->next->prev = l->prev;
1733         l->prev->next = l->next;
1734         // relink to sequential
1735         l->next = r_mesh_rcachesequentialchain_current->prev;
1736         l->prev = l->next->prev;
1737         while (l->next->data && l->data && l->next->data->offset <= d->offset)
1738         {
1739                 //Con_Print(">\n");
1740                 l->next = l->next->next;
1741                 l->prev = l->prev->next;
1742         }
1743         while (l->prev->data && l->data && l->prev->data->offset >= d->offset)
1744         {
1745                 //Con_Print("<\n");
1746                 l->prev = l->prev->prev;
1747                 l->next = l->next->prev;
1748         }
1749         l->next->prev = l->prev->next = l;
1750         // also link into hash chain
1751         l = &l->data->hashlink;
1752         l->next = &r_mesh_rcachechain[hashindex];
1753         l->prev = l->next->prev;
1754         l->prev->next = l;
1755         l->next->prev = l->prev->next = l;
1756
1757
1758         //r_mesh_rcachesequentialchain_current = d->sequentiallink.next;
1759
1760         //R_Mesh_CacheArray_ValidateState(7);
1761         // and finally set the data pointer
1762         r->data = r_mesh_rcachedata + d->offset;
1763         // and tell the caller to fill the array
1764         return true;
1765 }
1766