]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_backend.c
more clean up of IN_Activate, added cl_ignoremousemove to merge some code
[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 unsigned int backendunits, backendimageunits, backendarrayunits, backendactive;
87
88 /*
89 note: here's strip order for a terrain row:
90 0--1--2--3--4
91 |\ |\ |\ |\ |
92 | \| \| \| \|
93 A--B--C--D--E
94 clockwise
95
96 A0B, 01B, B1C, 12C, C2D, 23D, D3E, 34E
97
98 *elements++ = i + row;
99 *elements++ = i;
100 *elements++ = i + row + 1;
101 *elements++ = i;
102 *elements++ = i + 1;
103 *elements++ = i + row + 1;
104
105
106 for (y = 0;y < rows - 1;y++)
107 {
108         for (x = 0;x < columns - 1;x++)
109         {
110                 i = y * rows + x;
111                 *elements++ = i + columns;
112                 *elements++ = i;
113                 *elements++ = i + columns + 1;
114                 *elements++ = i;
115                 *elements++ = i + 1;
116                 *elements++ = i + columns + 1;
117         }
118 }
119
120 alternative:
121 0--1--2--3--4
122 | /| /|\ | /|
123 |/ |/ | \|/ |
124 A--B--C--D--E
125 counterclockwise
126
127 for (y = 0;y < rows - 1;y++)
128 {
129         for (x = 0;x < columns - 1;x++)
130         {
131                 i = y * rows + x;
132                 *elements++ = i;
133                 *elements++ = i + columns;
134                 *elements++ = i + columns + 1;
135                 *elements++ = i + columns;
136                 *elements++ = i + columns + 1;
137                 *elements++ = i + 1;
138         }
139 }
140 */
141
142 int polygonelements[768];
143
144 static void R_Mesh_CacheArray_Startup(void);
145 static void R_Mesh_CacheArray_Shutdown(void);
146 void GL_Backend_AllocArrays(void)
147 {
148         R_Mesh_CacheArray_Startup();
149 }
150
151 void GL_Backend_FreeArrays(void)
152 {
153         R_Mesh_CacheArray_Shutdown();
154 }
155
156 static void gl_backend_start(void)
157 {
158         Con_Print("OpenGL Backend starting...\n");
159         CHECKGLERROR
160
161         if (qglDrawRangeElements != NULL)
162         {
163                 CHECKGLERROR
164                 qglGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &gl_maxdrawrangeelementsvertices);
165                 CHECKGLERROR
166                 qglGetIntegerv(GL_MAX_ELEMENTS_INDICES, &gl_maxdrawrangeelementsindices);
167                 CHECKGLERROR
168                 Con_Printf("glDrawRangeElements detected (max vertices %i, max indices %i)\n", gl_maxdrawrangeelementsvertices, gl_maxdrawrangeelementsindices);
169         }
170
171         backendunits = min(MAX_TEXTUREUNITS, gl_textureunits);
172         backendimageunits = backendunits;
173         backendarrayunits = backendunits;
174         if (gl_support_fragment_shader)
175         {
176                 CHECKGLERROR
177                 qglGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &backendimageunits);
178                 CHECKGLERROR
179                 qglGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, &backendarrayunits);
180                 CHECKGLERROR
181                 Con_Printf("GLSL shader support detected: texture units = %i texenv, %i image, %i array\n", backendunits, backendimageunits, backendarrayunits);
182         }
183         else if (backendunits > 1)
184                 Con_Printf("multitexture detected: texture units = %i\n", backendunits);
185         else
186                 Con_Printf("singletexture\n");
187
188         GL_Backend_AllocArrays();
189
190         Con_Printf("OpenGL backend started.\n");
191
192         CHECKGLERROR
193
194         backendactive = true;
195 }
196
197 static void gl_backend_shutdown(void)
198 {
199         backendunits = 0;
200         backendimageunits = 0;
201         backendarrayunits = 0;
202         backendactive = false;
203
204         Con_Print("OpenGL Backend shutting down\n");
205
206         GL_Backend_FreeArrays();
207 }
208
209 static void gl_backend_newmap(void)
210 {
211 }
212
213 cvar_t scr_zoomwindow = {CVAR_SAVE, "scr_zoomwindow", "0"};
214 cvar_t scr_zoomwindow_viewsizex = {CVAR_SAVE, "scr_zoomwindow_viewsizex", "20"};
215 cvar_t scr_zoomwindow_viewsizey = {CVAR_SAVE, "scr_zoomwindow_viewsizey", "20"};
216 cvar_t scr_zoomwindow_fov = {CVAR_SAVE, "scr_zoomwindow_fov", "20"};
217
218 void gl_backend_init(void)
219 {
220         int i;
221
222         for (i = 0;i < POLYGONELEMENTS_MAXPOINTS - 2;i++)
223         {
224                 polygonelements[i * 3 + 0] = 0;
225                 polygonelements[i * 3 + 1] = i + 1;
226                 polygonelements[i * 3 + 2] = i + 2;
227         }
228
229         Cvar_RegisterVariable(&r_render);
230         Cvar_RegisterVariable(&r_waterwarp);
231         Cvar_RegisterVariable(&r_stereo_separation);
232         Cvar_RegisterVariable(&r_stereo_sidebyside);
233         Cvar_RegisterVariable(&r_stereo_redblue);
234         Cvar_RegisterVariable(&r_stereo_redcyan);
235         Cvar_RegisterVariable(&r_stereo_redgreen);
236         Cvar_RegisterVariable(&gl_polyblend);
237         Cvar_RegisterVariable(&gl_dither);
238         Cvar_RegisterVariable(&gl_lockarrays);
239         Cvar_RegisterVariable(&gl_paranoid);
240         Cvar_RegisterVariable(&gl_printcheckerror);
241 #ifdef NORENDER
242         Cvar_SetValue("r_render", 0);
243 #endif
244
245         Cvar_RegisterVariable(&gl_mesh_drawrangeelements);
246         Cvar_RegisterVariable(&gl_mesh_testarrayelement);
247         Cvar_RegisterVariable(&gl_mesh_testmanualfeeding);
248
249         Cvar_RegisterVariable(&scr_zoomwindow);
250         Cvar_RegisterVariable(&scr_zoomwindow_viewsizex);
251         Cvar_RegisterVariable(&scr_zoomwindow_viewsizey);
252         Cvar_RegisterVariable(&scr_zoomwindow_fov);
253
254         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
255 }
256
257 void GL_SetupView_Orientation_Identity (void)
258 {
259         Matrix4x4_CreateIdentity(&backend_viewmatrix);
260         memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
261 }
262
263 void GL_SetupView_Orientation_FromEntity(matrix4x4_t *matrix)
264 {
265         matrix4x4_t tempmatrix, basematrix;
266         Matrix4x4_Invert_Simple(&tempmatrix, matrix);
267         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
268         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
269         Matrix4x4_Concat(&backend_viewmatrix, &basematrix, &tempmatrix);
270         //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[2], 1, 0, 0);
271         //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[0], 0, 1, 0);
272         //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[1], 0, 0, 1);
273         //Matrix4x4_ConcatTranslate(&backend_viewmatrix, -origin[0], -origin[1], -origin[2]);
274         memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
275 }
276
277 void GL_SetupView_Mode_Perspective (double fovx, double fovy, double zNear, double zFar)
278 {
279         double xmax, ymax;
280         double m[16];
281
282         if (!r_render.integer)
283                 return;
284
285         // set up viewpoint
286         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
287         qglLoadIdentity();CHECKGLERROR
288         // pyramid slopes
289         xmax = zNear * tan(fovx * M_PI / 360.0);
290         ymax = zNear * tan(fovy * M_PI / 360.0);
291         // set view pyramid
292         qglFrustum(-xmax, xmax, -ymax, ymax, zNear, zFar);CHECKGLERROR
293         qglGetDoublev(GL_PROJECTION_MATRIX, m);
294         backend_projectmatrix.m[0][0] = m[0];
295         backend_projectmatrix.m[1][0] = m[1];
296         backend_projectmatrix.m[2][0] = m[2];
297         backend_projectmatrix.m[3][0] = m[3];
298         backend_projectmatrix.m[0][1] = m[4];
299         backend_projectmatrix.m[1][1] = m[5];
300         backend_projectmatrix.m[2][1] = m[6];
301         backend_projectmatrix.m[3][1] = m[7];
302         backend_projectmatrix.m[0][2] = m[8];
303         backend_projectmatrix.m[1][2] = m[9];
304         backend_projectmatrix.m[2][2] = m[10];
305         backend_projectmatrix.m[3][2] = m[11];
306         backend_projectmatrix.m[0][3] = m[12];
307         backend_projectmatrix.m[1][3] = m[13];
308         backend_projectmatrix.m[2][3] = m[14];
309         backend_projectmatrix.m[3][3] = m[15];
310         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
311         GL_SetupView_Orientation_Identity();
312 }
313
314 void GL_SetupView_Mode_PerspectiveInfiniteFarClip (double fovx, double fovy, double zNear)
315 {
316         double nudge, m[16];
317
318         if (!r_render.integer)
319                 return;
320
321         // set up viewpoint
322         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
323         qglLoadIdentity();CHECKGLERROR
324         // set view pyramid
325         nudge = 1.0 - 1.0 / (1<<23);
326         m[ 0] = 1.0 / tan(fovx * M_PI / 360.0);
327         m[ 1] = 0;
328         m[ 2] = 0;
329         m[ 3] = 0;
330         m[ 4] = 0;
331         m[ 5] = 1.0 / tan(fovy * M_PI / 360.0);
332         m[ 6] = 0;
333         m[ 7] = 0;
334         m[ 8] = 0;
335         m[ 9] = 0;
336         m[10] = -nudge;
337         m[11] = -1;
338         m[12] = 0;
339         m[13] = 0;
340         m[14] = -2 * zNear * nudge;
341         m[15] = 0;
342         qglLoadMatrixd(m);
343         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
344         GL_SetupView_Orientation_Identity();
345         backend_projectmatrix.m[0][0] = m[0];
346         backend_projectmatrix.m[1][0] = m[1];
347         backend_projectmatrix.m[2][0] = m[2];
348         backend_projectmatrix.m[3][0] = m[3];
349         backend_projectmatrix.m[0][1] = m[4];
350         backend_projectmatrix.m[1][1] = m[5];
351         backend_projectmatrix.m[2][1] = m[6];
352         backend_projectmatrix.m[3][1] = m[7];
353         backend_projectmatrix.m[0][2] = m[8];
354         backend_projectmatrix.m[1][2] = m[9];
355         backend_projectmatrix.m[2][2] = m[10];
356         backend_projectmatrix.m[3][2] = m[11];
357         backend_projectmatrix.m[0][3] = m[12];
358         backend_projectmatrix.m[1][3] = m[13];
359         backend_projectmatrix.m[2][3] = m[14];
360         backend_projectmatrix.m[3][3] = m[15];
361 }
362
363 void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double zNear, double zFar)
364 {
365         double m[16];
366
367         if (!r_render.integer)
368                 return;
369
370         // set up viewpoint
371         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
372         qglLoadIdentity();CHECKGLERROR
373         qglOrtho(x1, x2, y2, y1, zNear, zFar);
374         qglGetDoublev(GL_PROJECTION_MATRIX, m);
375         backend_projectmatrix.m[0][0] = m[0];
376         backend_projectmatrix.m[1][0] = m[1];
377         backend_projectmatrix.m[2][0] = m[2];
378         backend_projectmatrix.m[3][0] = m[3];
379         backend_projectmatrix.m[0][1] = m[4];
380         backend_projectmatrix.m[1][1] = m[5];
381         backend_projectmatrix.m[2][1] = m[6];
382         backend_projectmatrix.m[3][1] = m[7];
383         backend_projectmatrix.m[0][2] = m[8];
384         backend_projectmatrix.m[1][2] = m[9];
385         backend_projectmatrix.m[2][2] = m[10];
386         backend_projectmatrix.m[3][2] = m[11];
387         backend_projectmatrix.m[0][3] = m[12];
388         backend_projectmatrix.m[1][3] = m[13];
389         backend_projectmatrix.m[2][3] = m[14];
390         backend_projectmatrix.m[3][3] = m[15];
391         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
392         GL_SetupView_Orientation_Identity();
393 }
394
395 typedef struct gltextureunit_s
396 {
397         int t1d, t2d, t3d, tcubemap;
398         int arrayenabled;
399         unsigned int arraycomponents;
400         const void *pointer_texcoord;
401         float rgbscale, alphascale;
402         int combinergb, combinealpha;
403         // FIXME: add more combine stuff
404         // texmatrixenabled exists only to avoid unnecessary texmatrix compares
405         int texmatrixenabled;
406         matrix4x4_t matrix;
407 }
408 gltextureunit_t;
409
410 static struct
411 {
412         int blendfunc1;
413         int blendfunc2;
414         int blend;
415         GLboolean depthmask;
416         int colormask; // stored as bottom 4 bits: r g b a (3 2 1 0 order)
417         int depthtest;
418         int scissortest;
419         unsigned int unit;
420         unsigned int clientunit;
421         gltextureunit_t units[MAX_TEXTUREUNITS];
422         float color4f[4];
423         int lockrange_first;
424         int lockrange_count;
425         const void *pointer_vertex;
426         const void *pointer_color;
427 }
428 gl_state;
429
430 void GL_SetupTextureState(void)
431 {
432         unsigned int i;
433         gltextureunit_t *unit;
434         CHECKGLERROR
435         gl_state.unit = -1;
436         gl_state.clientunit = -1;
437         for (i = 0;i < MAX_TEXTUREUNITS;i++)
438         {
439                 unit = gl_state.units + i;
440                 unit->t1d = 0;
441                 unit->t2d = 0;
442                 unit->t3d = 0;
443                 unit->tcubemap = 0;
444                 unit->arrayenabled = false;
445                 unit->arraycomponents = 0;
446                 unit->pointer_texcoord = NULL;
447                 unit->rgbscale = 1;
448                 unit->alphascale = 1;
449                 unit->combinergb = GL_MODULATE;
450                 unit->combinealpha = GL_MODULATE;
451                 unit->texmatrixenabled = false;
452                 unit->matrix = r_identitymatrix;
453         }
454
455         for (i = 0;i < backendimageunits;i++)
456         {
457                 GL_ActiveTexture(i);
458                 qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
459                 qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
460                 if (gl_texture3d)
461                 {
462                         qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
463                 }
464                 if (gl_texturecubemap)
465                 {
466                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
467                 }
468         }
469
470         for (i = 0;i < backendarrayunits;i++)
471         {
472                 GL_ClientActiveTexture(i);
473                 qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR
474                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
475         }
476
477         for (i = 0;i < backendunits;i++)
478         {
479                 GL_ActiveTexture(i);
480                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
481                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
482                 if (gl_texture3d)
483                 {
484                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
485                 }
486                 if (gl_texturecubemap)
487                 {
488                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
489                 }
490                 qglMatrixMode(GL_TEXTURE);
491                 qglLoadIdentity();
492                 qglMatrixMode(GL_MODELVIEW);
493                 if (gl_combine.integer)
494                 {
495                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
496                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);CHECKGLERROR
497                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);CHECKGLERROR
498                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
499                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);CHECKGLERROR // for GL_INTERPOLATE_ARB mode
500                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
501                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
502                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);CHECKGLERROR
503                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);CHECKGLERROR
504                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);CHECKGLERROR
505                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
506                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);CHECKGLERROR
507                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
508                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
509                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
510                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
511                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
512                 }
513                 else
514                 {
515                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
516                 }
517         }
518         CHECKGLERROR
519 }
520
521 void GL_Backend_ResetState(void)
522 {
523         memset(&gl_state, 0, sizeof(gl_state));
524         gl_state.depthtest = true;
525         gl_state.blendfunc1 = GL_ONE;
526         gl_state.blendfunc2 = GL_ZERO;
527         gl_state.blend = false;
528         gl_state.depthmask = GL_TRUE;
529         gl_state.colormask = 15;
530         gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1;
531         gl_state.lockrange_first = 0;
532         gl_state.lockrange_count = 0;
533         gl_state.pointer_vertex = NULL;
534         gl_state.pointer_color = NULL;
535
536         CHECKGLERROR
537
538         qglColorMask(1, 1, 1, 1);
539         qglEnable(GL_CULL_FACE);CHECKGLERROR
540         qglCullFace(GL_FRONT);CHECKGLERROR
541         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
542         qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
543         qglDisable(GL_BLEND);CHECKGLERROR
544         qglDepthMask(gl_state.depthmask);CHECKGLERROR
545
546         qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR
547         qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
548
549         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL);CHECKGLERROR
550         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
551
552         GL_Color(0, 0, 0, 0);
553         GL_Color(1, 1, 1, 1);
554
555         GL_SetupTextureState();
556 }
557
558 void GL_ActiveTexture(unsigned int num)
559 {
560         if (gl_state.unit != num)
561         {
562                 gl_state.unit = num;
563                 if (qglActiveTexture)
564                 {
565                         qglActiveTexture(GL_TEXTURE0_ARB + gl_state.unit);
566                         CHECKGLERROR
567                 }
568         }
569 }
570
571 void GL_ClientActiveTexture(unsigned int num)
572 {
573         if (gl_state.clientunit != num)
574         {
575                 gl_state.clientunit = num;
576                 if (qglActiveTexture)
577                 {
578                         qglClientActiveTexture(GL_TEXTURE0_ARB + gl_state.clientunit);
579                         CHECKGLERROR
580                 }
581         }
582 }
583
584 void GL_BlendFunc(int blendfunc1, int blendfunc2)
585 {
586         if (gl_state.blendfunc1 != blendfunc1 || gl_state.blendfunc2 != blendfunc2)
587         {
588                 if (r_showtrispass)
589                         return;
590                 qglBlendFunc(gl_state.blendfunc1 = blendfunc1, gl_state.blendfunc2 = blendfunc2);CHECKGLERROR
591                 if (gl_state.blendfunc2 == GL_ZERO)
592                 {
593                         if (gl_state.blendfunc1 == GL_ONE)
594                         {
595                                 if (gl_state.blend)
596                                 {
597                                         gl_state.blend = 0;
598                                         qglDisable(GL_BLEND);CHECKGLERROR
599                                 }
600                         }
601                         else
602                         {
603                                 if (!gl_state.blend)
604                                 {
605                                         gl_state.blend = 1;
606                                         qglEnable(GL_BLEND);CHECKGLERROR
607                                 }
608                         }
609                 }
610                 else
611                 {
612                         if (!gl_state.blend)
613                         {
614                                 gl_state.blend = 1;
615                                 qglEnable(GL_BLEND);CHECKGLERROR
616                         }
617                 }
618         }
619 }
620
621 void GL_DepthMask(int state)
622 {
623         if (gl_state.depthmask != state)
624         {
625                 if (r_showtrispass)
626                         return;
627                 qglDepthMask(gl_state.depthmask = state);CHECKGLERROR
628         }
629 }
630
631 void GL_DepthTest(int state)
632 {
633         if (gl_state.depthtest != state)
634         {
635                 if (r_showtrispass)
636                         return;
637                 gl_state.depthtest = state;
638                 if (gl_state.depthtest)
639                 {
640                         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
641                 }
642                 else
643                 {
644                         qglDisable(GL_DEPTH_TEST);CHECKGLERROR
645                 }
646         }
647 }
648
649 void GL_ColorMask(int r, int g, int b, int a)
650 {
651         int state = r*8 + g*4 + b*2 + a*1;
652         if (gl_state.colormask != state)
653         {
654                 if (r_showtrispass)
655                         return;
656                 gl_state.colormask = state;
657                 qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
658         }
659 }
660
661 void GL_Color(float cr, float cg, float cb, float ca)
662 {
663         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)
664         {
665                 if (r_showtrispass)
666                         return;
667                 gl_state.color4f[0] = cr;
668                 gl_state.color4f[1] = cg;
669                 gl_state.color4f[2] = cb;
670                 gl_state.color4f[3] = ca;
671                 CHECKGLERROR
672                 qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
673                 CHECKGLERROR
674         }
675 }
676
677 void GL_ShowTrisColor(float cr, float cg, float cb, float ca)
678 {
679         if (!r_showtrispass)
680                 return;
681         r_showtrispass = false;
682         GL_Color(cr * r_showtris.value, cg * r_showtris.value, cb * r_showtris.value, ca);
683         r_showtrispass = true;
684 }
685
686
687 void GL_LockArrays(int first, int count)
688 {
689         if (gl_state.lockrange_count != count || gl_state.lockrange_first != first)
690         {
691                 if (gl_state.lockrange_count)
692                 {
693                         gl_state.lockrange_count = 0;
694                         CHECKGLERROR
695                         qglUnlockArraysEXT();
696                         CHECKGLERROR
697                 }
698                 if (count && gl_supportslockarrays && gl_lockarrays.integer && r_render.integer)
699                 {
700                         gl_state.lockrange_first = first;
701                         gl_state.lockrange_count = count;
702                         CHECKGLERROR
703                         qglLockArraysEXT(first, count);
704                         CHECKGLERROR
705                 }
706         }
707 }
708
709 void GL_Scissor (int x, int y, int width, int height)
710 {
711         CHECKGLERROR
712         qglScissor(x, vid.realheight - (y + height),width,height);
713         CHECKGLERROR
714 }
715
716 void GL_ScissorTest(int state)
717 {
718         if(gl_state.scissortest == state)
719                 return;
720
721         CHECKGLERROR
722         if((gl_state.scissortest = state))
723                 qglEnable(GL_SCISSOR_TEST);
724         else
725                 qglDisable(GL_SCISSOR_TEST);
726         CHECKGLERROR
727 }
728
729 void GL_Clear(int mask)
730 {
731         if (r_showtrispass)
732                 return;
733         qglClear(mask);CHECKGLERROR
734 }
735
736 void GL_TransformToScreen(const vec4_t in, vec4_t out)
737 {
738         vec4_t temp;
739         float iw;
740         Matrix4x4_Transform4 (&backend_viewmatrix, in, temp);
741         Matrix4x4_Transform4 (&backend_projectmatrix, temp, out);
742         iw = 1.0f / out[3];
743         out[0] = r_view_x + (out[0] * iw + 1.0f) * r_view_width * 0.5f;
744         out[1] = r_view_y + (out[1] * iw + 1.0f) * r_view_height * 0.5f;
745         out[2] = r_view_z + (out[2] * iw + 1.0f) * r_view_depth * 0.5f;
746 }
747
748 // called at beginning of frame
749 void R_Mesh_Start(void)
750 {
751         BACKENDACTIVECHECK
752         CHECKGLERROR
753         GL_Backend_ResetState();
754 }
755
756 unsigned int GL_Backend_CompileProgram(int vertexstrings_count, const char **vertexstrings_list, int fragmentstrings_count, const char **fragmentstrings_list)
757 {
758         GLint vertexshadercompiled, fragmentshadercompiled, programlinked;
759         GLuint vertexshaderobject, fragmentshaderobject, programobject = 0;
760         char compilelog[4096];
761         CHECKGLERROR
762
763         programobject = qglCreateProgramObjectARB();
764         CHECKGLERROR
765         if (!programobject)
766                 return 0;
767
768         if (vertexstrings_count)
769         {
770                 CHECKGLERROR
771                 vertexshaderobject = qglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
772                 if (!vertexshaderobject)
773                 {
774                         qglDeleteObjectARB(programobject);
775                         CHECKGLERROR
776                         return 0;
777                 }
778                 qglShaderSourceARB(vertexshaderobject, vertexstrings_count, vertexstrings_list, NULL);
779                 qglCompileShaderARB(vertexshaderobject);
780                 CHECKGLERROR
781                 qglGetObjectParameterivARB(vertexshaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &vertexshadercompiled);
782                 qglGetInfoLogARB(vertexshaderobject, sizeof(compilelog), NULL, compilelog);
783                 if (compilelog[0])
784                         Con_Printf("vertex shader compile log:\n%s\n", compilelog);
785                 if (!vertexshadercompiled)
786                 {
787                         qglDeleteObjectARB(programobject);
788                         qglDeleteObjectARB(vertexshaderobject);
789                         CHECKGLERROR
790                         return 0;
791                 }
792                 qglAttachObjectARB(programobject, vertexshaderobject);
793                 qglDeleteObjectARB(vertexshaderobject);
794                 CHECKGLERROR
795         }
796
797         if (fragmentstrings_count)
798         {
799                 CHECKGLERROR
800                 fragmentshaderobject = qglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
801                 if (!fragmentshaderobject)
802                 {
803                         qglDeleteObjectARB(programobject);
804                         CHECKGLERROR
805                         return 0;
806                 }
807                 qglShaderSourceARB(fragmentshaderobject, fragmentstrings_count, fragmentstrings_list, NULL);
808                 qglCompileShaderARB(fragmentshaderobject);
809                 CHECKGLERROR
810                 qglGetObjectParameterivARB(fragmentshaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &fragmentshadercompiled);
811                 qglGetInfoLogARB(fragmentshaderobject, sizeof(compilelog), NULL, compilelog);
812                 if (compilelog[0])
813                         Con_Printf("fragment shader compile log:\n%s\n", compilelog);
814                 if (!fragmentshadercompiled)
815                 {
816                         qglDeleteObjectARB(programobject);
817                         qglDeleteObjectARB(fragmentshaderobject);
818                         CHECKGLERROR
819                         return 0;
820                 }
821                 qglAttachObjectARB(programobject, fragmentshaderobject);
822                 qglDeleteObjectARB(fragmentshaderobject);
823                 CHECKGLERROR
824         }
825
826         qglLinkProgramARB(programobject);
827         CHECKGLERROR
828         qglGetObjectParameterivARB(programobject, GL_OBJECT_LINK_STATUS_ARB, &programlinked);
829         qglGetInfoLogARB(programobject, sizeof(compilelog), NULL, compilelog);
830         if (compilelog[0])
831         {
832                 Con_Printf("program link log:\n%s\n", compilelog);
833                 // software vertex shader is ok but software fragment shader is WAY
834                 // too slow, fail program if so.
835                 // NOTE: this string might be ATI specific, but that's ok because the
836                 // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
837                 // software fragment shader due to low instruction and dependent
838                 // texture limits.
839                 if (strstr(compilelog, "fragment shader will run in software"))
840                         programlinked = false;
841         }
842         CHECKGLERROR
843         if (!programlinked)
844         {
845                 qglDeleteObjectARB(programobject);
846                 return 0;
847         }
848         CHECKGLERROR
849         return programobject;
850 }
851
852 void GL_Backend_FreeProgram(unsigned int prog)
853 {
854         CHECKGLERROR
855         qglDeleteObjectARB(prog);
856         CHECKGLERROR
857 }
858
859 int gl_backend_rebindtextures;
860
861 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
862 {
863         int i;
864         if (offset)
865         {
866                 for (i = 0;i < count;i++)
867                         *out++ = *in++ + offset;
868         }
869         else
870                 memcpy(out, in, sizeof(*out) * count);
871 }
872
873 // renders triangles using vertices from the active arrays
874 int paranoidblah = 0;
875 void R_Mesh_Draw(int firstvertex, int numvertices, int numtriangles, const int *elements)
876 {
877         unsigned int numelements = numtriangles * 3;
878         if (numvertices < 3 || numtriangles < 1)
879         {
880                 Con_Printf("R_Mesh_Draw(%d, %d, %d, %08p);\n", firstvertex, numvertices, numtriangles, elements);
881                 return;
882         }
883         //CHECKGLERROR
884         if (r_showtrispass)
885         {
886                 R_Mesh_Draw_ShowTris(firstvertex, numvertices, numtriangles, elements);
887                 return;
888         }
889         c_meshs++;
890         c_meshelements += numelements;
891         if (gl_paranoid.integer)
892         {
893                 unsigned int i, j, size;
894                 const int *p;
895                 if (!qglIsEnabled(GL_VERTEX_ARRAY))
896                         Con_Print("R_Mesh_Draw: vertex array not enabled\n");
897                 for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
898                         paranoidblah += *p;
899                 if (gl_state.pointer_color)
900                 {
901                         if (!qglIsEnabled(GL_COLOR_ARRAY))
902                                 Con_Print("R_Mesh_Draw: color array set but not enabled\n");
903                         for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
904                                 paranoidblah += *p;
905                 }
906                 for (i = 0;i < backendarrayunits;i++)
907                 {
908                         if (gl_state.units[i].arrayenabled)
909                         {
910                                 GL_ClientActiveTexture(i);
911                                 if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
912                                         Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
913                                 for (j = 0, size = numvertices * gl_state.units[i].arraycomponents, p = (int *)((float *)gl_state.units[i].pointer_texcoord + firstvertex * gl_state.units[i].arraycomponents);j < size;j++, p++)
914                                         paranoidblah += *p;
915                         }
916                 }
917                 for (i = 0;i < (unsigned int) numtriangles * 3;i++)
918                 {
919                         if (elements[i] < firstvertex || elements[i] >= firstvertex + numvertices)
920                         {
921                                 Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in elements list\n", elements[i], firstvertex, firstvertex + numvertices);
922                                 return;
923                         }
924                 }
925                 CHECKGLERROR
926         }
927         if (r_render.integer)
928         {
929                 CHECKGLERROR
930                 if (gl_mesh_testmanualfeeding.integer)
931                 {
932                         unsigned int i, j;
933                         const GLfloat *p;
934                         qglBegin(GL_TRIANGLES);
935                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
936                         {
937                                 for (j = 0;j < backendarrayunits;j++)
938                                 {
939                                         if (gl_state.units[j].pointer_texcoord)
940                                         {
941                                                 if (backendarrayunits > 1)
942                                                 {
943                                                         if (gl_state.units[j].arraycomponents == 4)
944                                                         {
945                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 4;
946                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
947                                                         }
948                                                         else if (gl_state.units[j].arraycomponents == 3)
949                                                         {
950                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
951                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
952                                                         }
953                                                         else if (gl_state.units[j].arraycomponents == 2)
954                                                         {
955                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
956                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
957                                                         }
958                                                         else
959                                                         {
960                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 1;
961                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
962                                                         }
963                                                 }
964                                                 else
965                                                 {
966                                                         if (gl_state.units[j].arraycomponents == 4)
967                                                         {
968                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 4;
969                                                                 qglTexCoord4f(p[0], p[1], p[2], p[3]);
970                                                         }
971                                                         else if (gl_state.units[j].arraycomponents == 3)
972                                                         {
973                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
974                                                                 qglTexCoord3f(p[0], p[1], p[2]);
975                                                         }
976                                                         else if (gl_state.units[j].arraycomponents == 2)
977                                                         {
978                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
979                                                                 qglTexCoord2f(p[0], p[1]);
980                                                         }
981                                                         else
982                                                         {
983                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 1;
984                                                                 qglTexCoord1f(p[0]);
985                                                         }
986                                                 }
987                                         }
988                                 }
989                                 if (gl_state.pointer_color)
990                                 {
991                                         p = ((const GLfloat *)(gl_state.pointer_color)) + elements[i] * 4;
992                                         qglColor4f(p[0], p[1], p[2], p[3]);
993                                 }
994                                 p = ((const GLfloat *)(gl_state.pointer_vertex)) + elements[i] * 3;
995                                 qglVertex3f(p[0], p[1], p[2]);
996                         }
997                         qglEnd();
998                         CHECKGLERROR
999                 }
1000                 else if (gl_mesh_testarrayelement.integer)
1001                 {
1002                         int i;
1003                         qglBegin(GL_TRIANGLES);
1004                         for (i = 0;i < numtriangles * 3;i++)
1005                         {
1006                                 qglArrayElement(elements[i]);
1007                         }
1008                         qglEnd();
1009                         CHECKGLERROR
1010                 }
1011                 else if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1012                 {
1013                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices, numelements, GL_UNSIGNED_INT, elements);
1014                         CHECKGLERROR
1015                 }
1016                 else
1017                 {
1018                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, elements);
1019                         CHECKGLERROR
1020                 }
1021         }
1022 }
1023
1024 // restores backend state, used when done with 3D rendering
1025 void R_Mesh_Finish(void)
1026 {
1027         unsigned int i;
1028         BACKENDACTIVECHECK
1029         CHECKGLERROR
1030         GL_LockArrays(0, 0);
1031         CHECKGLERROR
1032
1033         for (i = 0;i < backendimageunits;i++)
1034         {
1035                 GL_ActiveTexture(i);
1036                 qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
1037                 qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
1038                 if (gl_texture3d)
1039                 {
1040                         qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
1041                 }
1042                 if (gl_texturecubemap)
1043                 {
1044                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
1045                 }
1046         }
1047         for (i = 0;i < backendarrayunits;i++)
1048         {
1049                 GL_ActiveTexture(backendarrayunits - 1 - i);
1050                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1051         }
1052         for (i = 0;i < backendunits;i++)
1053         {
1054                 GL_ActiveTexture(backendunits - 1 - i);
1055                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1056                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1057                 if (gl_texture3d)
1058                 {
1059                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1060                 }
1061                 if (gl_texturecubemap)
1062                 {
1063                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1064                 }
1065                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
1066                 if (gl_combine.integer)
1067                 {
1068                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
1069                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
1070                 }
1071         }
1072         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1073         qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
1074
1075         qglDisable(GL_BLEND);CHECKGLERROR
1076         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1077         qglDepthMask(GL_TRUE);CHECKGLERROR
1078         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR
1079 }
1080
1081 void R_Mesh_Matrix(const matrix4x4_t *matrix)
1082 {
1083         if (memcmp(matrix, &backend_modelmatrix, sizeof(matrix4x4_t)))
1084         {
1085                 backend_modelmatrix = *matrix;
1086                 Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewmatrix, matrix);
1087                 Matrix4x4_Transpose(&backend_glmodelviewmatrix, &backend_modelviewmatrix);
1088                 qglLoadMatrixf(&backend_glmodelviewmatrix.m[0][0]);
1089         }
1090 }
1091
1092 void R_Mesh_VertexPointer(const float *vertex3f)
1093 {
1094         if (gl_state.pointer_vertex != vertex3f)
1095         {
1096                 gl_state.pointer_vertex = vertex3f;
1097                 CHECKGLERROR
1098                 qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), gl_state.pointer_vertex);
1099                 CHECKGLERROR
1100         }
1101 }
1102
1103 void R_Mesh_ColorPointer(const float *color4f)
1104 {
1105         if (gl_state.pointer_color != color4f)
1106         {
1107                 CHECKGLERROR
1108                 if (!gl_state.pointer_color)
1109                 {
1110                         qglEnableClientState(GL_COLOR_ARRAY);
1111                         CHECKGLERROR
1112                 }
1113                 else if (!color4f)
1114                 {
1115                         qglDisableClientState(GL_COLOR_ARRAY);
1116                         CHECKGLERROR
1117                         // when color array is on the glColor gets trashed, set it again
1118                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
1119                         CHECKGLERROR
1120                 }
1121                 gl_state.pointer_color = color4f;
1122                 qglColorPointer(4, GL_FLOAT, sizeof(float[4]), gl_state.pointer_color);
1123                 CHECKGLERROR
1124         }
1125 }
1126
1127 void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, const float *texcoord)
1128 {
1129         gltextureunit_t *unit = gl_state.units + unitnum;
1130         // update array settings
1131         if (texcoord)
1132         {
1133                 // texcoord array
1134                 if (unit->pointer_texcoord != texcoord || unit->arraycomponents != numcomponents)
1135                 {
1136                         unit->pointer_texcoord = texcoord;
1137                         unit->arraycomponents = numcomponents;
1138                         GL_ClientActiveTexture(unitnum);
1139                         qglTexCoordPointer(unit->arraycomponents, GL_FLOAT, sizeof(float) * unit->arraycomponents, unit->pointer_texcoord);
1140                         CHECKGLERROR
1141                 }
1142                 // texture array unit is enabled, enable the array
1143                 if (!unit->arrayenabled)
1144                 {
1145                         unit->arrayenabled = true;
1146                         GL_ClientActiveTexture(unitnum);
1147                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1148                 }
1149         }
1150         else
1151         {
1152                 // texture array unit is disabled, disable the array
1153                 if (unit->arrayenabled)
1154                 {
1155                         unit->arrayenabled = false;
1156                         GL_ClientActiveTexture(unitnum);
1157                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1158                 }
1159         }
1160 }
1161
1162 void R_Mesh_TexBindAll(unsigned int unitnum, int tex1d, int tex2d, int tex3d, int texcubemap)
1163 {
1164         gltextureunit_t *unit = gl_state.units + unitnum;
1165         if (unitnum >= backendunits)
1166                 return;
1167         // update 1d texture binding
1168         if (unit->t1d != tex1d)
1169         {
1170                 GL_ActiveTexture(unitnum);
1171                 if (unitnum < backendunits)
1172                 {
1173                         if (tex1d)
1174                         {
1175                                 if (unit->t1d == 0)
1176                                         qglEnable(GL_TEXTURE_1D);
1177                         }
1178                         else
1179                         {
1180                                 if (unit->t1d)
1181                                         qglDisable(GL_TEXTURE_1D);
1182                         }
1183                 }
1184                 unit->t1d = tex1d;
1185                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);
1186                 CHECKGLERROR
1187         }
1188         // update 2d texture binding
1189         if (unit->t2d != tex2d)
1190         {
1191                 GL_ActiveTexture(unitnum);
1192                 if (unitnum < backendunits)
1193                 {
1194                         if (tex2d)
1195                         {
1196                                 if (unit->t2d == 0)
1197                                         qglEnable(GL_TEXTURE_2D);
1198                         }
1199                         else
1200                         {
1201                                 if (unit->t2d)
1202                                         qglDisable(GL_TEXTURE_2D);
1203                         }
1204                 }
1205                 unit->t2d = tex2d;
1206                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);
1207                 CHECKGLERROR
1208         }
1209         // update 3d texture binding
1210         if (unit->t3d != tex3d)
1211         {
1212                 GL_ActiveTexture(unitnum);
1213                 if (unitnum < backendunits)
1214                 {
1215                         if (tex3d)
1216                         {
1217                                 if (unit->t3d == 0)
1218                                         qglEnable(GL_TEXTURE_3D);
1219                         }
1220                         else
1221                         {
1222                                 if (unit->t3d)
1223                                         qglDisable(GL_TEXTURE_3D);
1224                         }
1225                 }
1226                 unit->t3d = tex3d;
1227                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);
1228                 CHECKGLERROR
1229         }
1230         // update cubemap texture binding
1231         if (unit->tcubemap != texcubemap)
1232         {
1233                 GL_ActiveTexture(unitnum);
1234                 if (unitnum < backendunits)
1235                 {
1236                         if (texcubemap)
1237                         {
1238                                 if (unit->tcubemap == 0)
1239                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);
1240                         }
1241                         else
1242                         {
1243                                 if (unit->tcubemap)
1244                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
1245                         }
1246                 }
1247                 unit->tcubemap = texcubemap;
1248                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);
1249                 CHECKGLERROR
1250         }
1251 }
1252
1253 void R_Mesh_TexBind1D(unsigned int unitnum, int texnum)
1254 {
1255         gltextureunit_t *unit = gl_state.units + unitnum;
1256         if (unitnum >= backendunits)
1257                 return;
1258         // update 1d texture binding
1259         if (unit->t1d != texnum)
1260         {
1261                 GL_ActiveTexture(unitnum);
1262                 if (texnum)
1263                 {
1264                         if (unit->t1d == 0)
1265                                 qglEnable(GL_TEXTURE_1D);
1266                 }
1267                 else
1268                 {
1269                         if (unit->t1d)
1270                                 qglDisable(GL_TEXTURE_1D);
1271                 }
1272                 unit->t1d = texnum;
1273                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);
1274                 CHECKGLERROR
1275         }
1276         // update 2d texture binding
1277         if (unit->t2d)
1278         {
1279                 GL_ActiveTexture(unitnum);
1280                 if (unit->t2d)
1281                         qglDisable(GL_TEXTURE_2D);
1282                 unit->t2d = 0;
1283                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);
1284                 CHECKGLERROR
1285         }
1286         // update 3d texture binding
1287         if (unit->t3d)
1288         {
1289                 GL_ActiveTexture(unitnum);
1290                 if (unit->t3d)
1291                         qglDisable(GL_TEXTURE_3D);
1292                 unit->t3d = 0;
1293                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);
1294                 CHECKGLERROR
1295         }
1296         // update cubemap texture binding
1297         if (unit->tcubemap)
1298         {
1299                 GL_ActiveTexture(unitnum);
1300                 if (unit->tcubemap)
1301                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
1302                 unit->tcubemap = 0;
1303                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);
1304                 CHECKGLERROR
1305         }
1306 }
1307
1308 void R_Mesh_TexBind(unsigned int unitnum, int texnum)
1309 {
1310         gltextureunit_t *unit = gl_state.units + unitnum;
1311         if (unitnum >= backendunits)
1312                 return;
1313         // update 1d texture binding
1314         if (unit->t1d)
1315         {
1316                 GL_ActiveTexture(unitnum);
1317                 if (unit->t1d)
1318                         qglDisable(GL_TEXTURE_1D);
1319                 unit->t1d = 0;
1320                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);
1321                 CHECKGLERROR
1322         }
1323         // update 2d texture binding
1324         if (unit->t2d != texnum)
1325         {
1326                 GL_ActiveTexture(unitnum);
1327                 if (texnum)
1328                 {
1329                         if (unit->t2d == 0)
1330                                 qglEnable(GL_TEXTURE_2D);
1331                 }
1332                 else
1333                 {
1334                         if (unit->t2d)
1335                                 qglDisable(GL_TEXTURE_2D);
1336                 }
1337                 unit->t2d = texnum;
1338                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);
1339                 CHECKGLERROR
1340         }
1341         // update 3d texture binding
1342         if (unit->t3d)
1343         {
1344                 GL_ActiveTexture(unitnum);
1345                 if (unit->t3d)
1346                         qglDisable(GL_TEXTURE_3D);
1347                 unit->t3d = 0;
1348                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);
1349                 CHECKGLERROR
1350         }
1351         // update cubemap texture binding
1352         if (unit->tcubemap != 0)
1353         {
1354                 GL_ActiveTexture(unitnum);
1355                 if (unit->tcubemap)
1356                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
1357                 unit->tcubemap = 0;
1358                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);
1359                 CHECKGLERROR
1360         }
1361 }
1362
1363 void R_Mesh_TexBind3D(unsigned int unitnum, int texnum)
1364 {
1365         gltextureunit_t *unit = gl_state.units + unitnum;
1366         if (unitnum >= backendunits)
1367                 return;
1368         // update 1d texture binding
1369         if (unit->t1d)
1370         {
1371                 GL_ActiveTexture(unitnum);
1372                 if (unit->t1d)
1373                         qglDisable(GL_TEXTURE_1D);
1374                 unit->t1d = 0;
1375                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);
1376                 CHECKGLERROR
1377         }
1378         // update 2d texture binding
1379         if (unit->t2d)
1380         {
1381                 GL_ActiveTexture(unitnum);
1382                 if (unit->t2d)
1383                         qglDisable(GL_TEXTURE_2D);
1384                 unit->t2d = 0;
1385                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);
1386                 CHECKGLERROR
1387         }
1388         // update 3d texture binding
1389         if (unit->t3d != texnum)
1390         {
1391                 GL_ActiveTexture(unitnum);
1392                 if (texnum)
1393                 {
1394                         if (unit->t3d == 0)
1395                                 qglEnable(GL_TEXTURE_3D);
1396                 }
1397                 else
1398                 {
1399                         if (unit->t3d)
1400                                 qglDisable(GL_TEXTURE_3D);
1401                 }
1402                 unit->t3d = texnum;
1403                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);
1404                 CHECKGLERROR
1405         }
1406         // update cubemap texture binding
1407         if (unit->tcubemap != 0)
1408         {
1409                 GL_ActiveTexture(unitnum);
1410                 if (unit->tcubemap)
1411                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
1412                 unit->tcubemap = 0;
1413                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);
1414                 CHECKGLERROR
1415         }
1416 }
1417
1418 void R_Mesh_TexBindCubeMap(unsigned int unitnum, int texnum)
1419 {
1420         gltextureunit_t *unit = gl_state.units + unitnum;
1421         if (unitnum >= backendunits)
1422                 return;
1423         // update 1d texture binding
1424         if (unit->t1d)
1425         {
1426                 GL_ActiveTexture(unitnum);
1427                 if (unit->t1d)
1428                         qglDisable(GL_TEXTURE_1D);
1429                 unit->t1d = 0;
1430                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);
1431                 CHECKGLERROR
1432         }
1433         // update 2d texture binding
1434         if (unit->t2d)
1435         {
1436                 GL_ActiveTexture(unitnum);
1437                 if (unit->t2d)
1438                         qglDisable(GL_TEXTURE_2D);
1439                 unit->t2d = 0;
1440                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);
1441                 CHECKGLERROR
1442         }
1443         // update 3d texture binding
1444         if (unit->t3d)
1445         {
1446                 GL_ActiveTexture(unitnum);
1447                 if (unit->t3d)
1448                         qglDisable(GL_TEXTURE_3D);
1449                 unit->t3d = 0;
1450                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);
1451                 CHECKGLERROR
1452         }
1453         // update cubemap texture binding
1454         if (unit->tcubemap != texnum)
1455         {
1456                 GL_ActiveTexture(unitnum);
1457                 if (texnum)
1458                 {
1459                         if (unit->tcubemap == 0)
1460                                 qglEnable(GL_TEXTURE_CUBE_MAP_ARB);
1461                 }
1462                 else
1463                 {
1464                         if (unit->tcubemap)
1465                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
1466                 }
1467                 unit->tcubemap = texnum;
1468                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);
1469                 CHECKGLERROR
1470         }
1471 }
1472
1473 void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix)
1474 {
1475         gltextureunit_t *unit = gl_state.units + unitnum;
1476         if (matrix->m[3][3])
1477         {
1478                 // texmatrix specified, check if it is different
1479                 if (!unit->texmatrixenabled || memcmp(&unit->matrix, matrix, sizeof(matrix4x4_t)))
1480                 {
1481                         matrix4x4_t tempmatrix;
1482                         unit->texmatrixenabled = true;
1483                         unit->matrix = *matrix;
1484                         Matrix4x4_Transpose(&tempmatrix, &unit->matrix);
1485                         qglMatrixMode(GL_TEXTURE);
1486                         GL_ActiveTexture(unitnum);
1487                         qglLoadMatrixf(&tempmatrix.m[0][0]);
1488                         qglMatrixMode(GL_MODELVIEW);
1489                 }
1490         }
1491         else
1492         {
1493                 // no texmatrix specified, revert to identity
1494                 if (unit->texmatrixenabled)
1495                 {
1496                         unit->texmatrixenabled = false;
1497                         qglMatrixMode(GL_TEXTURE);
1498                         GL_ActiveTexture(unitnum);
1499                         qglLoadIdentity();
1500                         qglMatrixMode(GL_MODELVIEW);
1501                 }
1502         }
1503 }
1504
1505 void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, int rgbscale, int alphascale)
1506 {
1507         gltextureunit_t *unit = gl_state.units + unitnum;
1508         if (gl_combine.integer)
1509         {
1510                 // GL_ARB_texture_env_combine
1511                 if (!combinergb)
1512                         combinergb = GL_MODULATE;
1513                 if (!combinealpha)
1514                         combinealpha = GL_MODULATE;
1515                 if (!rgbscale)
1516                         rgbscale = 1;
1517                 if (!alphascale)
1518                         alphascale = 1;
1519                 if (unit->combinergb != combinergb)
1520                 {
1521                         unit->combinergb = combinergb;
1522                         GL_ActiveTexture(unitnum);
1523                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
1524                 }
1525                 if (unit->combinealpha != combinealpha)
1526                 {
1527                         unit->combinealpha = combinealpha;
1528                         GL_ActiveTexture(unitnum);
1529                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
1530                 }
1531                 if (unit->rgbscale != rgbscale)
1532                 {
1533                         GL_ActiveTexture(unitnum);
1534                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = rgbscale));CHECKGLERROR
1535                 }
1536                 if (unit->alphascale != alphascale)
1537                 {
1538                         GL_ActiveTexture(unitnum);
1539                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = alphascale));CHECKGLERROR
1540                 }
1541         }
1542         else
1543         {
1544                 // normal GL texenv
1545                 if (!combinergb)
1546                         combinergb = GL_MODULATE;
1547                 if (unit->combinergb != combinergb)
1548                 {
1549                         unit->combinergb = combinergb;
1550                         GL_ActiveTexture(unitnum);
1551                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
1552                 }
1553         }
1554 }
1555
1556 void R_Mesh_State(const rmeshstate_t *m)
1557 {
1558         unsigned int i;
1559
1560         BACKENDACTIVECHECK
1561
1562         R_Mesh_VertexPointer(m->pointer_vertex);
1563
1564         if (r_showtrispass)
1565                 return;
1566
1567         R_Mesh_ColorPointer(m->pointer_color);
1568
1569         if (gl_backend_rebindtextures)
1570         {
1571                 gl_backend_rebindtextures = false;
1572                 GL_SetupTextureState();
1573         }
1574
1575         for (i = 0;i < backendimageunits;i++)
1576                 R_Mesh_TexBindAll(i, m->tex1d[i], m->tex[i], m->tex3d[i], m->texcubemap[i]);
1577         for (i = 0;i < backendarrayunits;i++)
1578         {
1579                 if (m->pointer_texcoord3f[i])
1580                         R_Mesh_TexCoordPointer(i, 3, m->pointer_texcoord3f[i]);
1581                 else
1582                         R_Mesh_TexCoordPointer(i, 2, m->pointer_texcoord[i]);
1583         }
1584         for (i = 0;i < backendunits;i++)
1585         {
1586                 R_Mesh_TexMatrix(i, &m->texmatrix[i]);
1587                 R_Mesh_TexCombine(i, m->texcombinergb[i], m->texcombinealpha[i], m->texrgbscale[i], m->texalphascale[i]);
1588         }
1589 }
1590
1591 void R_Mesh_Draw_ShowTris(int firstvertex, int numvertices, int numtriangles, const int *elements)
1592 {
1593         qglBegin(GL_LINES);
1594         for (;numtriangles;numtriangles--, elements += 3)
1595         {
1596                 qglArrayElement(elements[0]);qglArrayElement(elements[1]);
1597                 qglArrayElement(elements[1]);qglArrayElement(elements[2]);
1598                 qglArrayElement(elements[2]);qglArrayElement(elements[0]);
1599         }
1600         qglEnd();
1601         CHECKGLERROR
1602 }
1603
1604 /*
1605 ==============================================================================
1606
1607                                                 SCREEN SHOTS
1608
1609 ==============================================================================
1610 */
1611
1612 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, qboolean gammacorrect)
1613 {
1614         int     indices[3] = {0,1,2};
1615         qboolean ret;
1616
1617         if (!r_render.integer)
1618                 return false;
1619
1620         qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer1);
1621         CHECKGLERROR
1622
1623         if (scr_screenshot_gamma.value != 1 && gammacorrect)
1624         {
1625                 int i;
1626                 double igamma = 1.0 / scr_screenshot_gamma.value;
1627                 unsigned char ramp[256];
1628                 for (i = 0;i < 256;i++)
1629                         ramp[i] = (unsigned char) (pow(i * (1.0 / 255.0), igamma) * 255.0);
1630                 for (i = 0;i < width*height*3;i++)
1631                         buffer1[i] = ramp[buffer1[i]];
1632         }
1633
1634         Image_CopyMux (buffer2, buffer1, width, height, flipx, flipy, flipdiagonal, 3, 3, indices);
1635
1636         if (jpeg)
1637                 ret = JPEG_SaveImage_preflipped (filename, width, height, buffer2);
1638         else
1639                 ret = Image_WriteTGARGB_preflipped (filename, width, height, buffer2, buffer3);
1640
1641         return ret;
1642 }
1643
1644 //=============================================================================
1645
1646 void R_ClearScreen(void)
1647 {
1648         if (r_render.integer)
1649         {
1650                 // clear to black
1651                 if (fogenabled)
1652                         qglClearColor(fogcolor[0],fogcolor[1],fogcolor[2],0);
1653                 else
1654                         qglClearColor(0,0,0,0);
1655                 CHECKGLERROR
1656                 qglClearDepth(1);CHECKGLERROR
1657                 if (gl_stencil)
1658                 {
1659                         // LordHavoc: we use a stencil centered around 128 instead of 0,
1660                         // to avoid clamping interfering with strange shadow volume
1661                         // drawing orders
1662                         qglClearStencil(128);CHECKGLERROR
1663                 }
1664                 // clear the screen
1665                 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | (gl_stencil ? GL_STENCIL_BUFFER_BIT : 0));
1666                 // set dithering mode
1667                 if (gl_dither.integer)
1668                 {
1669                         qglEnable(GL_DITHER);CHECKGLERROR
1670                 }
1671                 else
1672                 {
1673                         qglDisable(GL_DITHER);CHECKGLERROR
1674                 }
1675         }
1676 }
1677
1678 /*
1679 ====================
1680 CalcFov
1681 ====================
1682 */
1683 float CalcFov (float fov_x, float width, float height)
1684 {
1685         // calculate vision size and alter by aspect, then convert back to angle
1686         return atan (((height/width)/vid_pixelaspect.value)*tan(fov_x/360.0*M_PI))*360.0/M_PI;
1687 }
1688
1689 int r_stereo_side;
1690
1691 void SCR_DrawScreen (void)
1692 {
1693         for (r_showtrispass = 0;r_showtrispass <= (r_showtris.value > 0);r_showtrispass++)
1694         {
1695                 R_Mesh_Start();
1696
1697                 R_TimeReport("setup");
1698
1699                 if (r_showtrispass)
1700                 {
1701                         rmeshstate_t m;
1702                         r_showtrispass = 0;
1703                         GL_BlendFunc(GL_ONE, GL_ONE);
1704                         GL_DepthTest(GL_FALSE);
1705                         GL_DepthMask(GL_FALSE);
1706                         memset(&m, 0, sizeof(m));
1707                         R_Mesh_State(&m);
1708                         //qglEnable(GL_LINE_SMOOTH);
1709                         GL_ShowTrisColor(0.2,0.2,0.2,1);
1710                         r_showtrispass = 1;
1711                 }
1712
1713                 if (cls.signon == SIGNONS)
1714                 {
1715                         float size;
1716
1717                         size = scr_viewsize.value * (1.0 / 100.0);
1718                         size = min(size, 1);
1719
1720                         if (r_stereo_sidebyside.integer)
1721                         {
1722                                 r_refdef.width = vid.realwidth * size / 2.5;
1723                                 r_refdef.height = vid.realheight * size / 2.5 * (1 - bound(0, r_letterbox.value, 100) / 100);
1724                                 r_refdef.x = (vid.realwidth - r_refdef.width * 2.5) * 0.5;
1725                                 r_refdef.y = (vid.realheight - r_refdef.height)/2;
1726                                 if (r_stereo_side)
1727                                         r_refdef.x += r_refdef.width * 1.5;
1728                         }
1729                         else
1730                         {
1731                                 r_refdef.width = vid.realwidth * size;
1732                                 r_refdef.height = vid.realheight * size * (1 - bound(0, r_letterbox.value, 100) / 100);
1733                                 r_refdef.x = (vid.realwidth - r_refdef.width)/2;
1734                                 r_refdef.y = (vid.realheight - r_refdef.height)/2;
1735                         }
1736
1737                         // LordHavoc: viewzoom (zoom in for sniper rifles, etc)
1738                         r_refdef.fov_x = scr_fov.value * r_refdef.fovscale_x;
1739                         r_refdef.fov_y = CalcFov (scr_fov.value, r_refdef.width, r_refdef.height) * r_refdef.fovscale_y;
1740
1741                         R_RenderView();
1742
1743                         if (scr_zoomwindow.integer)
1744                         {
1745                                 float sizex = bound(10, scr_zoomwindow_viewsizex.value, 100) / 100.0;
1746                                 float sizey = bound(10, scr_zoomwindow_viewsizey.value, 100) / 100.0;
1747                                 r_refdef.width = vid.realwidth * sizex;
1748                                 r_refdef.height = vid.realheight * sizey;
1749                                 r_refdef.x = (vid.realwidth - r_refdef.width)/2;
1750                                 r_refdef.y = 0;
1751                                 r_refdef.fov_x = scr_zoomwindow_fov.value * r_refdef.fovscale_x;
1752                                 r_refdef.fov_y = CalcFov(scr_zoomwindow_fov.value, r_refdef.width, r_refdef.height) * r_refdef.fovscale_y;
1753
1754                                 R_RenderView();
1755                         }
1756                 }
1757
1758                 if (!r_stereo_sidebyside.integer)
1759                 {
1760                         r_refdef.width = vid.realwidth;
1761                         r_refdef.height = vid.realheight;
1762                         r_refdef.x = 0;
1763                         r_refdef.y = 0;
1764                 }
1765
1766                 // draw 2D stuff
1767                 R_DrawQueue();
1768
1769                 R_Mesh_Finish();
1770
1771                 R_TimeReport("meshfinish");
1772         }
1773         r_showtrispass = 0;
1774         //qglDisable(GL_LINE_SMOOTH);
1775 }
1776
1777 void SCR_UpdateLoadingScreen (void)
1778 {
1779         float x, y;
1780         cachepic_t *pic;
1781         rmeshstate_t m;
1782         // don't do anything if not initialized yet
1783         if (vid_hidden)
1784                 return;
1785         r_showtrispass = 0;
1786         VID_GetWindowSize(&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
1787         VID_UpdateGamma(false);
1788         qglViewport(0, 0, vid.realwidth, vid.realheight);
1789         //qglDisable(GL_SCISSOR_TEST);
1790         //qglDepthMask(1);
1791         qglColorMask(1,1,1,1);
1792         //qglClearColor(0,0,0,0);
1793         //qglClear(GL_COLOR_BUFFER_BIT);
1794         //qglCullFace(GL_FRONT);
1795         //qglDisable(GL_CULL_FACE);
1796         //R_ClearScreen();
1797         R_Textures_Frame();
1798         GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
1799         R_Mesh_Start();
1800         R_Mesh_Matrix(&r_identitymatrix);
1801         // draw the loading plaque
1802         pic = Draw_CachePic("gfx/loading", false);
1803         x = (vid_conwidth.integer - pic->width)/2;
1804         y = (vid_conheight.integer - pic->height)/2;
1805         GL_Color(1,1,1,1);
1806         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1807         GL_DepthTest(false);
1808         memset(&m, 0, sizeof(m));
1809         m.pointer_vertex = varray_vertex3f;
1810         m.pointer_texcoord[0] = varray_texcoord2f[0];
1811         m.tex[0] = R_GetTexture(pic->tex);
1812         R_Mesh_State(&m);
1813         varray_vertex3f[0] = varray_vertex3f[9] = x;
1814         varray_vertex3f[1] = varray_vertex3f[4] = y;
1815         varray_vertex3f[3] = varray_vertex3f[6] = x + pic->width;
1816         varray_vertex3f[7] = varray_vertex3f[10] = y + pic->height;
1817         varray_texcoord2f[0][0] = 0;varray_texcoord2f[0][1] = 0;
1818         varray_texcoord2f[0][2] = 1;varray_texcoord2f[0][3] = 0;
1819         varray_texcoord2f[0][4] = 1;varray_texcoord2f[0][5] = 1;
1820         varray_texcoord2f[0][6] = 0;varray_texcoord2f[0][7] = 1;
1821         GL_LockArrays(0, 4);
1822         R_Mesh_Draw(0, 4, 2, polygonelements);
1823         GL_LockArrays(0, 0);
1824         R_Mesh_Finish();
1825         // refresh
1826         VID_Finish();
1827 }
1828
1829 /*
1830 ==================
1831 SCR_UpdateScreen
1832
1833 This is called every frame, and can also be called explicitly to flush
1834 text to the screen.
1835 ==================
1836 */
1837 void SCR_UpdateScreen (void)
1838 {
1839         if (vid_hidden)
1840                 return;
1841
1842         if (r_textureunits.integer > gl_textureunits)
1843                 Cvar_SetValueQuick(&r_textureunits, gl_textureunits);
1844         if (r_textureunits.integer < 1)
1845                 Cvar_SetValueQuick(&r_textureunits, 1);
1846
1847         if (gl_combine.integer && (!gl_combine_extension || r_textureunits.integer < 2))
1848                 Cvar_SetValueQuick(&gl_combine, 0);
1849
1850         CHECKGLERROR
1851         qglViewport(0, 0, vid.realwidth, vid.realheight);
1852         qglDisable(GL_SCISSOR_TEST);
1853         qglDepthMask(1);
1854         qglColorMask(1,1,1,1);
1855         qglClearColor(0,0,0,0);
1856         qglClear(GL_COLOR_BUFFER_BIT);
1857         CHECKGLERROR
1858
1859         R_TimeReport("clear");
1860
1861         if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer || r_stereo_sidebyside.integer)
1862         {
1863                 matrix4x4_t originalmatrix = r_refdef.viewentitymatrix;
1864                 r_refdef.viewentitymatrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * -0.5f * r_refdef.viewentitymatrix.m[0][1];
1865                 r_refdef.viewentitymatrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * -0.5f * r_refdef.viewentitymatrix.m[1][1];
1866                 r_refdef.viewentitymatrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * -0.5f * r_refdef.viewentitymatrix.m[2][1];
1867
1868                 if (r_stereo_sidebyside.integer)
1869                         r_stereo_side = 0;
1870
1871                 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1872                 {
1873                         r_refdef.colormask[0] = 1;
1874                         r_refdef.colormask[1] = 0;
1875                         r_refdef.colormask[2] = 0;
1876                 }
1877
1878                 SCR_DrawScreen();
1879
1880                 r_refdef.viewentitymatrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * 0.5f * r_refdef.viewentitymatrix.m[0][1];
1881                 r_refdef.viewentitymatrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * 0.5f * r_refdef.viewentitymatrix.m[1][1];
1882                 r_refdef.viewentitymatrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * 0.5f * r_refdef.viewentitymatrix.m[2][1];
1883
1884                 if (r_stereo_sidebyside.integer)
1885                         r_stereo_side = 1;
1886
1887                 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1888                 {
1889                         r_refdef.colormask[0] = 0;
1890                         r_refdef.colormask[1] = r_stereo_redcyan.integer || r_stereo_redgreen.integer;
1891                         r_refdef.colormask[2] = r_stereo_redcyan.integer || r_stereo_redblue.integer;
1892                 }
1893
1894                 SCR_DrawScreen();
1895
1896                 r_refdef.viewentitymatrix = originalmatrix;
1897         }
1898         else
1899         {
1900                 r_showtrispass = false;
1901                 SCR_DrawScreen();
1902
1903                 if (r_showtris.value > 0)
1904                 {
1905                         rmeshstate_t m;
1906                         GL_BlendFunc(GL_ONE, GL_ONE);
1907                         GL_DepthTest(GL_FALSE);
1908                         GL_DepthMask(GL_FALSE);
1909                         memset(&m, 0, sizeof(m));
1910                         R_Mesh_State(&m);
1911                         r_showtrispass = true;
1912                         GL_ShowTrisColor(0.2,0.2,0.2,1);
1913                         SCR_DrawScreen();
1914                         r_showtrispass = false;
1915                 }
1916         }
1917
1918         VID_Finish();
1919         R_TimeReport("finish");
1920 }
1921
1922
1923 //===========================================================================
1924 // dynamic vertex array buffer subsystem
1925 //===========================================================================
1926
1927 // FIXME: someday this should be dynamically allocated and resized?
1928 float varray_vertex3f[65536*3];
1929 float varray_svector3f[65536*3];
1930 float varray_tvector3f[65536*3];
1931 float varray_normal3f[65536*3];
1932 float varray_color4f[65536*4];
1933 float varray_texcoord2f[4][65536*2];
1934 float varray_texcoord3f[4][65536*3];
1935 int earray_element3i[65536];
1936 float varray_vertex3f2[65536*3];
1937
1938 //===========================================================================
1939 // vertex array caching subsystem
1940 //===========================================================================
1941
1942 typedef struct rcachearraylink_s
1943 {
1944         struct rcachearraylink_s *next, *prev;
1945         struct rcachearrayitem_s *data;
1946 }
1947 rcachearraylink_t;
1948
1949 typedef struct rcachearrayitem_s
1950 {
1951         // the original request structure
1952         rcachearrayrequest_t request;
1953         // active
1954         int active;
1955         // offset into r_mesh_rcachedata
1956         int offset;
1957         // for linking this into the sequential list
1958         rcachearraylink_t sequentiallink;
1959         // for linking this into the lookup list
1960         rcachearraylink_t hashlink;
1961 }
1962 rcachearrayitem_t;
1963
1964 #define RCACHEARRAY_HASHSIZE 65536
1965 #define RCACHEARRAY_ITEMS 4096
1966 #define RCACHEARRAY_DEFAULTSIZE (4 << 20)
1967
1968 // all active items are linked into this chain in sorted order
1969 static rcachearraylink_t r_mesh_rcachesequentialchain;
1970 // all inactive items are linked into this chain in unknown order
1971 static rcachearraylink_t r_mesh_rcachefreechain;
1972 // all active items are also linked into these chains (using their hashlink)
1973 static rcachearraylink_t r_mesh_rcachechain[RCACHEARRAY_HASHSIZE];
1974
1975 // all items are stored here, whether active or inactive
1976 static rcachearrayitem_t r_mesh_rcacheitems[RCACHEARRAY_ITEMS];
1977
1978 // size of data buffer
1979 static int r_mesh_rcachedata_size = RCACHEARRAY_DEFAULTSIZE;
1980 // data buffer
1981 static qbyte r_mesh_rcachedata[RCACHEARRAY_DEFAULTSIZE];
1982
1983 // current state
1984 static int r_mesh_rcachedata_offset;
1985 static rcachearraylink_t *r_mesh_rcachesequentialchain_current;
1986
1987 static void R_Mesh_CacheArray_Startup(void)
1988 {
1989         int i;
1990         rcachearraylink_t *l;
1991         // prepare all the linked lists
1992         l = &r_mesh_rcachesequentialchain;l->next = l->prev = l;l->data = NULL;
1993         l = &r_mesh_rcachefreechain;l->next = l->prev = l;l->data = NULL;
1994         memset(&r_mesh_rcachechain, 0, sizeof(r_mesh_rcachechain));
1995         for (i = 0;i < RCACHEARRAY_HASHSIZE;i++)
1996         {
1997                 l = &r_mesh_rcachechain[i];
1998                 l->next = l->prev = l;
1999                 l->data = NULL;
2000         }
2001         memset(&r_mesh_rcacheitems, 0, sizeof(r_mesh_rcacheitems));
2002         for (i = 0;i < RCACHEARRAY_ITEMS;i++)
2003         {
2004                 r_mesh_rcacheitems[i].hashlink.data = r_mesh_rcacheitems[i].sequentiallink.data = &r_mesh_rcacheitems[i];
2005                 l = &r_mesh_rcacheitems[i].sequentiallink;
2006                 l->next = &r_mesh_rcachefreechain;
2007                 l->prev = l->next->prev;
2008                 l->next->prev = l->prev->next = l;
2009         }
2010         // clear other state
2011         r_mesh_rcachedata_offset = 0;
2012         r_mesh_rcachesequentialchain_current = &r_mesh_rcachesequentialchain;
2013 }
2014
2015 static void R_Mesh_CacheArray_Shutdown(void)
2016 {
2017 }
2018
2019 /*
2020 static void R_Mesh_CacheArray_ValidateState(int num)
2021 {
2022         rcachearraylink_t *l, *lhead;
2023         lhead = &r_mesh_rcachesequentialchain;
2024         if (r_mesh_rcachesequentialchain_current == lhead)
2025                 return;
2026         for (l = lhead->next;l != lhead;l = l->next)
2027                 if (r_mesh_rcachesequentialchain_current == l)
2028                         return;
2029         Sys_Error("%i", num);
2030 }
2031 */
2032
2033 int R_Mesh_CacheArray(rcachearrayrequest_t *r)
2034 {
2035         rcachearraylink_t *l, *lhead, *lnext;
2036         rcachearrayitem_t *d;
2037         int hashindex, offset, offsetend;
2038
2039         //R_Mesh_CacheArray_ValidateState(3);
2040         // calculate a hashindex to choose a cache chain
2041         r->data = NULL;
2042         hashindex = CRC_Block((void *)r, sizeof(*r)) % RCACHEARRAY_HASHSIZE;
2043
2044         // is it already cached?
2045         for (lhead = &r_mesh_rcachechain[hashindex], l = lhead->next;l != lhead;l = l->next)
2046         {
2047                 if (!memcmp(&l->data->request, r, sizeof(l->data->request)))
2048                 {
2049                         // we have it cached already
2050                         r->data = r_mesh_rcachedata + l->data->offset;
2051                         return false;
2052                 }
2053         }
2054
2055         // we need to add a new cache item, this means finding a place for the new
2056         // data and making sure we have a free item available, lots of work...
2057
2058         // check if buffer needs to wrap
2059         if (r_mesh_rcachedata_offset + r->data_size > r_mesh_rcachedata_size)
2060         {
2061                 /*
2062                 if (r->data_size * 10 > r_mesh_rcachedata_size)
2063                 {
2064                         // realloc whole cache
2065                 }
2066                 */
2067                 // reset back to start
2068                 r_mesh_rcachedata_offset = 0;
2069                 r_mesh_rcachesequentialchain_current = &r_mesh_rcachesequentialchain;
2070         }
2071         offset = r_mesh_rcachedata_offset;
2072         r_mesh_rcachedata_offset += r->data_size;
2073         offsetend = r_mesh_rcachedata_offset;
2074         //R_Mesh_CacheArray_ValidateState(4);
2075
2076         /*
2077         {
2078                 int n;
2079                 for (lhead = &r_mesh_rcachesequentialchain, l = lhead->next, n = 0;l != lhead;l = l->next, n++);
2080                 Con_Printf("R_Mesh_CacheArray: new data range %i:%i, %i items are already linked\n", offset, offsetend, n);
2081         }
2082         */
2083
2084         // make room for the new data (remove old items)
2085         lhead = &r_mesh_rcachesequentialchain;
2086         l = r_mesh_rcachesequentialchain_current;
2087         if (l == lhead)
2088                 l = l->next;
2089         while (l != lhead && l->data->offset < offsetend && l->data->offset + l->data->request.data_size > offset)
2090         {
2091         //r_mesh_rcachesequentialchain_current = l;
2092         //R_Mesh_CacheArray_ValidateState(8);
2093                 lnext = l->next;
2094                 // if at the end of the chain, wrap around
2095                 if (lnext == lhead)
2096                         lnext = lnext->next;
2097         //r_mesh_rcachesequentialchain_current = lnext;
2098         //R_Mesh_CacheArray_ValidateState(10);
2099
2100                 // unlink from sequential chain
2101                 l->next->prev = l->prev;
2102                 l->prev->next = l->next;
2103         //R_Mesh_CacheArray_ValidateState(11);
2104                 // link into free chain
2105                 l->next = &r_mesh_rcachefreechain;
2106                 l->prev = l->next->prev;
2107                 l->next->prev = l->prev->next = l;
2108         //R_Mesh_CacheArray_ValidateState(12);
2109
2110                 l = &l->data->hashlink;
2111                 // unlink from hash chain
2112                 l->next->prev = l->prev;
2113                 l->prev->next = l->next;
2114
2115                 l = lnext;
2116         //r_mesh_rcachesequentialchain_current = l;
2117         //R_Mesh_CacheArray_ValidateState(9);
2118         }
2119         //r_mesh_rcachesequentialchain_current = l;
2120         //R_Mesh_CacheArray_ValidateState(5);
2121         // gobble an extra item if we have no free items available
2122         if (r_mesh_rcachefreechain.next == &r_mesh_rcachefreechain)
2123         {
2124                 lnext = l->next;
2125
2126                 // unlink from sequential chain
2127                 l->next->prev = l->prev;
2128                 l->prev->next = l->next;
2129                 // link into free chain
2130                 l->next = &r_mesh_rcachefreechain;
2131                 l->prev = l->next->prev;
2132                 l->next->prev = l->prev->next = l;
2133
2134                 l = &l->data->hashlink;
2135                 // unlink from hash chain
2136                 l->next->prev = l->prev;
2137                 l->prev->next = l->next;
2138
2139                 l = lnext;
2140         }
2141         r_mesh_rcachesequentialchain_current = l;
2142         //R_Mesh_CacheArray_ValidateState(6);
2143
2144         // now take an item from the free chain
2145         l = r_mesh_rcachefreechain.next;
2146         // set it up
2147         d = l->data;
2148         d->request = *r;
2149         d->offset = offset;
2150         // unlink
2151         l->next->prev = l->prev;
2152         l->prev->next = l->next;
2153         // relink to sequential
2154         l->next = r_mesh_rcachesequentialchain_current->prev;
2155         l->prev = l->next->prev;
2156         while (l->next->data && l->data && l->next->data->offset <= d->offset)
2157         {
2158                 //Con_Print(">\n");
2159                 l->next = l->next->next;
2160                 l->prev = l->prev->next;
2161         }
2162         while (l->prev->data && l->data && l->prev->data->offset >= d->offset)
2163         {
2164                 //Con_Print("<\n");
2165                 l->prev = l->prev->prev;
2166                 l->next = l->next->prev;
2167         }
2168         l->next->prev = l->prev->next = l;
2169         // also link into hash chain
2170         l = &l->data->hashlink;
2171         l->next = &r_mesh_rcachechain[hashindex];
2172         l->prev = l->next->prev;
2173         l->prev->next = l;
2174         l->next->prev = l->prev->next = l;
2175
2176
2177         //r_mesh_rcachesequentialchain_current = d->sequentiallink.next;
2178
2179         //R_Mesh_CacheArray_ValidateState(7);
2180         // and finally set the data pointer
2181         r->data = r_mesh_rcachedata + d->offset;
2182         // and tell the caller to fill the array
2183         return true;
2184 }
2185