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