]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_backend.c
removed Lights Per Model setting from effects options menu, as it only affects .light...
[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.height - (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 (r_showtrispass)
1106                 return;
1107         if (gl_state.pointer_color != color4f)
1108         {
1109                 CHECKGLERROR
1110                 if (!gl_state.pointer_color)
1111                 {
1112                         qglEnableClientState(GL_COLOR_ARRAY);
1113                         CHECKGLERROR
1114                 }
1115                 else if (!color4f)
1116                 {
1117                         qglDisableClientState(GL_COLOR_ARRAY);
1118                         CHECKGLERROR
1119                         // when color array is on the glColor gets trashed, set it again
1120                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
1121                         CHECKGLERROR
1122                 }
1123                 gl_state.pointer_color = color4f;
1124                 qglColorPointer(4, GL_FLOAT, sizeof(float[4]), gl_state.pointer_color);
1125                 CHECKGLERROR
1126         }
1127 }
1128
1129 void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, const float *texcoord)
1130 {
1131         gltextureunit_t *unit = gl_state.units + unitnum;
1132         if (r_showtrispass)
1133                 return;
1134         // update array settings
1135         if (texcoord)
1136         {
1137                 // texcoord array
1138                 if (unit->pointer_texcoord != texcoord || unit->arraycomponents != numcomponents)
1139                 {
1140                         unit->pointer_texcoord = texcoord;
1141                         unit->arraycomponents = numcomponents;
1142                         GL_ClientActiveTexture(unitnum);
1143                         qglTexCoordPointer(unit->arraycomponents, GL_FLOAT, sizeof(float) * unit->arraycomponents, unit->pointer_texcoord);
1144                         CHECKGLERROR
1145                 }
1146                 // texture array unit is enabled, enable the array
1147                 if (!unit->arrayenabled)
1148                 {
1149                         unit->arrayenabled = true;
1150                         GL_ClientActiveTexture(unitnum);
1151                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1152                 }
1153         }
1154         else
1155         {
1156                 // texture array unit is disabled, disable the array
1157                 if (unit->arrayenabled)
1158                 {
1159                         unit->arrayenabled = false;
1160                         GL_ClientActiveTexture(unitnum);
1161                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1162                 }
1163         }
1164 }
1165
1166 void R_Mesh_TexBindAll(unsigned int unitnum, int tex1d, int tex2d, int tex3d, int texcubemap)
1167 {
1168         gltextureunit_t *unit = gl_state.units + unitnum;
1169         if (unitnum >= backendunits)
1170                 return;
1171         if (r_showtrispass)
1172                 return;
1173         // update 1d texture binding
1174         if (unit->t1d != tex1d)
1175         {
1176                 GL_ActiveTexture(unitnum);
1177                 if (unitnum < backendunits)
1178                 {
1179                         if (tex1d)
1180                         {
1181                                 if (unit->t1d == 0)
1182                                         qglEnable(GL_TEXTURE_1D);
1183                         }
1184                         else
1185                         {
1186                                 if (unit->t1d)
1187                                         qglDisable(GL_TEXTURE_1D);
1188                         }
1189                 }
1190                 unit->t1d = tex1d;
1191                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);
1192                 CHECKGLERROR
1193         }
1194         // update 2d texture binding
1195         if (unit->t2d != tex2d)
1196         {
1197                 GL_ActiveTexture(unitnum);
1198                 if (unitnum < backendunits)
1199                 {
1200                         if (tex2d)
1201                         {
1202                                 if (unit->t2d == 0)
1203                                         qglEnable(GL_TEXTURE_2D);
1204                         }
1205                         else
1206                         {
1207                                 if (unit->t2d)
1208                                         qglDisable(GL_TEXTURE_2D);
1209                         }
1210                 }
1211                 unit->t2d = tex2d;
1212                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);
1213                 CHECKGLERROR
1214         }
1215         // update 3d texture binding
1216         if (unit->t3d != tex3d)
1217         {
1218                 GL_ActiveTexture(unitnum);
1219                 if (unitnum < backendunits)
1220                 {
1221                         if (tex3d)
1222                         {
1223                                 if (unit->t3d == 0)
1224                                         qglEnable(GL_TEXTURE_3D);
1225                         }
1226                         else
1227                         {
1228                                 if (unit->t3d)
1229                                         qglDisable(GL_TEXTURE_3D);
1230                         }
1231                 }
1232                 unit->t3d = tex3d;
1233                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);
1234                 CHECKGLERROR
1235         }
1236         // update cubemap texture binding
1237         if (unit->tcubemap != texcubemap)
1238         {
1239                 GL_ActiveTexture(unitnum);
1240                 if (unitnum < backendunits)
1241                 {
1242                         if (texcubemap)
1243                         {
1244                                 if (unit->tcubemap == 0)
1245                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);
1246                         }
1247                         else
1248                         {
1249                                 if (unit->tcubemap)
1250                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
1251                         }
1252                 }
1253                 unit->tcubemap = texcubemap;
1254                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);
1255                 CHECKGLERROR
1256         }
1257 }
1258
1259 void R_Mesh_TexBind1D(unsigned int unitnum, int texnum)
1260 {
1261         gltextureunit_t *unit = gl_state.units + unitnum;
1262         if (unitnum >= backendunits)
1263                 return;
1264         if (r_showtrispass)
1265                 return;
1266         // update 1d texture binding
1267         if (unit->t1d != texnum)
1268         {
1269                 GL_ActiveTexture(unitnum);
1270                 if (texnum)
1271                 {
1272                         if (unit->t1d == 0)
1273                                 qglEnable(GL_TEXTURE_1D);
1274                 }
1275                 else
1276                 {
1277                         if (unit->t1d)
1278                                 qglDisable(GL_TEXTURE_1D);
1279                 }
1280                 unit->t1d = texnum;
1281                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);
1282                 CHECKGLERROR
1283         }
1284         // update 2d texture binding
1285         if (unit->t2d)
1286         {
1287                 GL_ActiveTexture(unitnum);
1288                 if (unit->t2d)
1289                         qglDisable(GL_TEXTURE_2D);
1290                 unit->t2d = 0;
1291                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);
1292                 CHECKGLERROR
1293         }
1294         // update 3d texture binding
1295         if (unit->t3d)
1296         {
1297                 GL_ActiveTexture(unitnum);
1298                 if (unit->t3d)
1299                         qglDisable(GL_TEXTURE_3D);
1300                 unit->t3d = 0;
1301                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);
1302                 CHECKGLERROR
1303         }
1304         // update cubemap texture binding
1305         if (unit->tcubemap)
1306         {
1307                 GL_ActiveTexture(unitnum);
1308                 if (unit->tcubemap)
1309                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
1310                 unit->tcubemap = 0;
1311                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);
1312                 CHECKGLERROR
1313         }
1314 }
1315
1316 void R_Mesh_TexBind(unsigned int unitnum, int texnum)
1317 {
1318         gltextureunit_t *unit = gl_state.units + unitnum;
1319         if (unitnum >= backendunits)
1320                 return;
1321         if (r_showtrispass)
1322                 return;
1323         // update 1d texture binding
1324         if (unit->t1d)
1325         {
1326                 GL_ActiveTexture(unitnum);
1327                 if (unit->t1d)
1328                         qglDisable(GL_TEXTURE_1D);
1329                 unit->t1d = 0;
1330                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);
1331                 CHECKGLERROR
1332         }
1333         // update 2d texture binding
1334         if (unit->t2d != texnum)
1335         {
1336                 GL_ActiveTexture(unitnum);
1337                 if (texnum)
1338                 {
1339                         if (unit->t2d == 0)
1340                                 qglEnable(GL_TEXTURE_2D);
1341                 }
1342                 else
1343                 {
1344                         if (unit->t2d)
1345                                 qglDisable(GL_TEXTURE_2D);
1346                 }
1347                 unit->t2d = texnum;
1348                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);
1349                 CHECKGLERROR
1350         }
1351         // update 3d texture binding
1352         if (unit->t3d)
1353         {
1354                 GL_ActiveTexture(unitnum);
1355                 if (unit->t3d)
1356                         qglDisable(GL_TEXTURE_3D);
1357                 unit->t3d = 0;
1358                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);
1359                 CHECKGLERROR
1360         }
1361         // update cubemap texture binding
1362         if (unit->tcubemap != 0)
1363         {
1364                 GL_ActiveTexture(unitnum);
1365                 if (unit->tcubemap)
1366                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
1367                 unit->tcubemap = 0;
1368                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);
1369                 CHECKGLERROR
1370         }
1371 }
1372
1373 void R_Mesh_TexBind3D(unsigned int unitnum, int texnum)
1374 {
1375         gltextureunit_t *unit = gl_state.units + unitnum;
1376         if (unitnum >= backendunits)
1377                 return;
1378         if (r_showtrispass)
1379                 return;
1380         // update 1d texture binding
1381         if (unit->t1d)
1382         {
1383                 GL_ActiveTexture(unitnum);
1384                 if (unit->t1d)
1385                         qglDisable(GL_TEXTURE_1D);
1386                 unit->t1d = 0;
1387                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);
1388                 CHECKGLERROR
1389         }
1390         // update 2d texture binding
1391         if (unit->t2d)
1392         {
1393                 GL_ActiveTexture(unitnum);
1394                 if (unit->t2d)
1395                         qglDisable(GL_TEXTURE_2D);
1396                 unit->t2d = 0;
1397                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);
1398                 CHECKGLERROR
1399         }
1400         // update 3d texture binding
1401         if (unit->t3d != texnum)
1402         {
1403                 GL_ActiveTexture(unitnum);
1404                 if (texnum)
1405                 {
1406                         if (unit->t3d == 0)
1407                                 qglEnable(GL_TEXTURE_3D);
1408                 }
1409                 else
1410                 {
1411                         if (unit->t3d)
1412                                 qglDisable(GL_TEXTURE_3D);
1413                 }
1414                 unit->t3d = texnum;
1415                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);
1416                 CHECKGLERROR
1417         }
1418         // update cubemap texture binding
1419         if (unit->tcubemap != 0)
1420         {
1421                 GL_ActiveTexture(unitnum);
1422                 if (unit->tcubemap)
1423                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
1424                 unit->tcubemap = 0;
1425                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);
1426                 CHECKGLERROR
1427         }
1428 }
1429
1430 void R_Mesh_TexBindCubeMap(unsigned int unitnum, int texnum)
1431 {
1432         gltextureunit_t *unit = gl_state.units + unitnum;
1433         if (unitnum >= backendunits)
1434                 return;
1435         if (r_showtrispass)
1436                 return;
1437         // update 1d texture binding
1438         if (unit->t1d)
1439         {
1440                 GL_ActiveTexture(unitnum);
1441                 if (unit->t1d)
1442                         qglDisable(GL_TEXTURE_1D);
1443                 unit->t1d = 0;
1444                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);
1445                 CHECKGLERROR
1446         }
1447         // update 2d texture binding
1448         if (unit->t2d)
1449         {
1450                 GL_ActiveTexture(unitnum);
1451                 if (unit->t2d)
1452                         qglDisable(GL_TEXTURE_2D);
1453                 unit->t2d = 0;
1454                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);
1455                 CHECKGLERROR
1456         }
1457         // update 3d texture binding
1458         if (unit->t3d)
1459         {
1460                 GL_ActiveTexture(unitnum);
1461                 if (unit->t3d)
1462                         qglDisable(GL_TEXTURE_3D);
1463                 unit->t3d = 0;
1464                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);
1465                 CHECKGLERROR
1466         }
1467         // update cubemap texture binding
1468         if (unit->tcubemap != texnum)
1469         {
1470                 GL_ActiveTexture(unitnum);
1471                 if (texnum)
1472                 {
1473                         if (unit->tcubemap == 0)
1474                                 qglEnable(GL_TEXTURE_CUBE_MAP_ARB);
1475                 }
1476                 else
1477                 {
1478                         if (unit->tcubemap)
1479                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
1480                 }
1481                 unit->tcubemap = texnum;
1482                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);
1483                 CHECKGLERROR
1484         }
1485 }
1486
1487 void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix)
1488 {
1489         gltextureunit_t *unit = gl_state.units + unitnum;
1490         if (r_showtrispass)
1491                 return;
1492         if (matrix->m[3][3])
1493         {
1494                 // texmatrix specified, check if it is different
1495                 if (!unit->texmatrixenabled || memcmp(&unit->matrix, matrix, sizeof(matrix4x4_t)))
1496                 {
1497                         matrix4x4_t tempmatrix;
1498                         unit->texmatrixenabled = true;
1499                         unit->matrix = *matrix;
1500                         Matrix4x4_Transpose(&tempmatrix, &unit->matrix);
1501                         qglMatrixMode(GL_TEXTURE);
1502                         GL_ActiveTexture(unitnum);
1503                         qglLoadMatrixf(&tempmatrix.m[0][0]);
1504                         qglMatrixMode(GL_MODELVIEW);
1505                 }
1506         }
1507         else
1508         {
1509                 // no texmatrix specified, revert to identity
1510                 if (unit->texmatrixenabled)
1511                 {
1512                         unit->texmatrixenabled = false;
1513                         qglMatrixMode(GL_TEXTURE);
1514                         GL_ActiveTexture(unitnum);
1515                         qglLoadIdentity();
1516                         qglMatrixMode(GL_MODELVIEW);
1517                 }
1518         }
1519 }
1520
1521 void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, int rgbscale, int alphascale)
1522 {
1523         gltextureunit_t *unit = gl_state.units + unitnum;
1524         if (r_showtrispass)
1525                 return;
1526         if (gl_combine.integer)
1527         {
1528                 // GL_ARB_texture_env_combine
1529                 if (!combinergb)
1530                         combinergb = GL_MODULATE;
1531                 if (!combinealpha)
1532                         combinealpha = GL_MODULATE;
1533                 if (!rgbscale)
1534                         rgbscale = 1;
1535                 if (!alphascale)
1536                         alphascale = 1;
1537                 if (unit->combinergb != combinergb)
1538                 {
1539                         unit->combinergb = combinergb;
1540                         GL_ActiveTexture(unitnum);
1541                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
1542                 }
1543                 if (unit->combinealpha != combinealpha)
1544                 {
1545                         unit->combinealpha = combinealpha;
1546                         GL_ActiveTexture(unitnum);
1547                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
1548                 }
1549                 if (unit->rgbscale != rgbscale)
1550                 {
1551                         GL_ActiveTexture(unitnum);
1552                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = rgbscale));CHECKGLERROR
1553                 }
1554                 if (unit->alphascale != alphascale)
1555                 {
1556                         GL_ActiveTexture(unitnum);
1557                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = alphascale));CHECKGLERROR
1558                 }
1559         }
1560         else
1561         {
1562                 // normal GL texenv
1563                 if (!combinergb)
1564                         combinergb = GL_MODULATE;
1565                 if (unit->combinergb != combinergb)
1566                 {
1567                         unit->combinergb = combinergb;
1568                         GL_ActiveTexture(unitnum);
1569                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
1570                 }
1571         }
1572 }
1573
1574 void R_Mesh_State(const rmeshstate_t *m)
1575 {
1576         unsigned int i;
1577
1578         BACKENDACTIVECHECK
1579
1580         R_Mesh_VertexPointer(m->pointer_vertex);
1581         R_Mesh_ColorPointer(m->pointer_color);
1582
1583         if (gl_backend_rebindtextures)
1584         {
1585                 gl_backend_rebindtextures = false;
1586                 GL_SetupTextureState();
1587         }
1588
1589         for (i = 0;i < backendimageunits;i++)
1590                 R_Mesh_TexBindAll(i, m->tex1d[i], m->tex[i], m->tex3d[i], m->texcubemap[i]);
1591         for (i = 0;i < backendarrayunits;i++)
1592         {
1593                 if (m->pointer_texcoord3f[i])
1594                         R_Mesh_TexCoordPointer(i, 3, m->pointer_texcoord3f[i]);
1595                 else
1596                         R_Mesh_TexCoordPointer(i, 2, m->pointer_texcoord[i]);
1597         }
1598         for (i = 0;i < backendunits;i++)
1599         {
1600                 R_Mesh_TexMatrix(i, &m->texmatrix[i]);
1601                 R_Mesh_TexCombine(i, m->texcombinergb[i], m->texcombinealpha[i], m->texrgbscale[i], m->texalphascale[i]);
1602         }
1603 }
1604
1605 void R_Mesh_Draw_ShowTris(int firstvertex, int numvertices, int numtriangles, const int *elements)
1606 {
1607         qglBegin(GL_LINES);
1608         for (;numtriangles;numtriangles--, elements += 3)
1609         {
1610                 qglArrayElement(elements[0]);qglArrayElement(elements[1]);
1611                 qglArrayElement(elements[1]);qglArrayElement(elements[2]);
1612                 qglArrayElement(elements[2]);qglArrayElement(elements[0]);
1613         }
1614         qglEnd();
1615         CHECKGLERROR
1616 }
1617
1618 /*
1619 ==============================================================================
1620
1621                                                 SCREEN SHOTS
1622
1623 ==============================================================================
1624 */
1625
1626 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)
1627 {
1628         int     indices[3] = {0,1,2};
1629         qboolean ret;
1630
1631         if (!r_render.integer)
1632                 return false;
1633
1634         qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer1);
1635         CHECKGLERROR
1636
1637         if (scr_screenshot_gamma.value != 1 && gammacorrect)
1638         {
1639                 int i;
1640                 double igamma = 1.0 / scr_screenshot_gamma.value;
1641                 unsigned char ramp[256];
1642                 for (i = 0;i < 256;i++)
1643                         ramp[i] = (unsigned char) (pow(i * (1.0 / 255.0), igamma) * 255.0);
1644                 for (i = 0;i < width*height*3;i++)
1645                         buffer1[i] = ramp[buffer1[i]];
1646         }
1647
1648         Image_CopyMux (buffer2, buffer1, width, height, flipx, flipy, flipdiagonal, 3, 3, indices);
1649
1650         if (jpeg)
1651                 ret = JPEG_SaveImage_preflipped (filename, width, height, buffer2);
1652         else
1653                 ret = Image_WriteTGARGB_preflipped (filename, width, height, buffer2, buffer3);
1654
1655         return ret;
1656 }
1657
1658 //=============================================================================
1659
1660 void R_ClearScreen(void)
1661 {
1662         if (r_render.integer)
1663         {
1664                 // clear to black
1665                 if (fogenabled)
1666                         qglClearColor(fogcolor[0],fogcolor[1],fogcolor[2],0);
1667                 else
1668                         qglClearColor(0,0,0,0);
1669                 CHECKGLERROR
1670                 qglClearDepth(1);CHECKGLERROR
1671                 if (gl_stencil)
1672                 {
1673                         // LordHavoc: we use a stencil centered around 128 instead of 0,
1674                         // to avoid clamping interfering with strange shadow volume
1675                         // drawing orders
1676                         qglClearStencil(128);CHECKGLERROR
1677                 }
1678                 // clear the screen
1679                 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | (gl_stencil ? GL_STENCIL_BUFFER_BIT : 0));
1680                 // set dithering mode
1681                 if (gl_dither.integer)
1682                 {
1683                         qglEnable(GL_DITHER);CHECKGLERROR
1684                 }
1685                 else
1686                 {
1687                         qglDisable(GL_DITHER);CHECKGLERROR
1688                 }
1689         }
1690 }
1691
1692 /*
1693 ====================
1694 CalcFov
1695 ====================
1696 */
1697 float CalcFov (float fov_x, float width, float height)
1698 {
1699         // calculate vision size and alter by aspect, then convert back to angle
1700         return atan (((height/width)/vid_pixelaspect.value)*tan(fov_x/360.0*M_PI))*360.0/M_PI;
1701 }
1702
1703 int r_stereo_side;
1704
1705 void SCR_DrawScreen (void)
1706 {
1707         for (r_showtrispass = 0;r_showtrispass <= (r_showtris.value > 0);r_showtrispass++)
1708         {
1709                 R_Mesh_Start();
1710
1711                 R_TimeReport("setup");
1712
1713                 if (r_showtrispass)
1714                 {
1715                         rmeshstate_t m;
1716                         r_showtrispass = 0;
1717                         GL_BlendFunc(GL_ONE, GL_ONE);
1718                         GL_DepthTest(GL_FALSE);
1719                         GL_DepthMask(GL_FALSE);
1720                         memset(&m, 0, sizeof(m));
1721                         R_Mesh_State(&m);
1722                         //qglEnable(GL_LINE_SMOOTH);
1723                         GL_ShowTrisColor(0.2,0.2,0.2,1);
1724                         r_showtrispass = 1;
1725                 }
1726
1727                 if (cls.signon == SIGNONS)
1728                 {
1729                         float size;
1730
1731                         size = scr_viewsize.value * (1.0 / 100.0);
1732                         size = min(size, 1);
1733
1734                         if (r_stereo_sidebyside.integer)
1735                         {
1736                                 r_refdef.width = vid.width * size / 2.5;
1737                                 r_refdef.height = vid.height * size / 2.5 * (1 - bound(0, r_letterbox.value, 100) / 100);
1738                                 r_refdef.x = (vid.width - r_refdef.width * 2.5) * 0.5;
1739                                 r_refdef.y = (vid.height - r_refdef.height)/2;
1740                                 if (r_stereo_side)
1741                                         r_refdef.x += r_refdef.width * 1.5;
1742                         }
1743                         else
1744                         {
1745                                 r_refdef.width = vid.width * size;
1746                                 r_refdef.height = vid.height * size * (1 - bound(0, r_letterbox.value, 100) / 100);
1747                                 r_refdef.x = (vid.width - r_refdef.width)/2;
1748                                 r_refdef.y = (vid.height - r_refdef.height)/2;
1749                         }
1750
1751                         // LordHavoc: viewzoom (zoom in for sniper rifles, etc)
1752                         r_refdef.fov_x = scr_fov.value * r_refdef.fovscale_x;
1753                         r_refdef.fov_y = CalcFov (scr_fov.value, r_refdef.width, r_refdef.height) * r_refdef.fovscale_y;
1754
1755                         R_RenderView();
1756
1757                         if (scr_zoomwindow.integer)
1758                         {
1759                                 float sizex = bound(10, scr_zoomwindow_viewsizex.value, 100) / 100.0;
1760                                 float sizey = bound(10, scr_zoomwindow_viewsizey.value, 100) / 100.0;
1761                                 r_refdef.width = vid.width * sizex;
1762                                 r_refdef.height = vid.height * sizey;
1763                                 r_refdef.x = (vid.width - r_refdef.width)/2;
1764                                 r_refdef.y = 0;
1765                                 r_refdef.fov_x = scr_zoomwindow_fov.value * r_refdef.fovscale_x;
1766                                 r_refdef.fov_y = CalcFov(scr_zoomwindow_fov.value, r_refdef.width, r_refdef.height) * r_refdef.fovscale_y;
1767
1768                                 R_RenderView();
1769                         }
1770                 }
1771
1772                 if (!r_stereo_sidebyside.integer)
1773                 {
1774                         r_refdef.width = vid.width;
1775                         r_refdef.height = vid.height;
1776                         r_refdef.x = 0;
1777                         r_refdef.y = 0;
1778                 }
1779
1780                 // draw 2D stuff
1781                 R_DrawQueue();
1782
1783                 R_Mesh_Finish();
1784
1785                 R_TimeReport("meshfinish");
1786         }
1787         r_showtrispass = 0;
1788         //qglDisable(GL_LINE_SMOOTH);
1789 }
1790
1791 void SCR_UpdateLoadingScreen (void)
1792 {
1793         float x, y;
1794         cachepic_t *pic;
1795         rmeshstate_t m;
1796         // don't do anything if not initialized yet
1797         if (vid_hidden)
1798                 return;
1799         r_showtrispass = 0;
1800         VID_UpdateGamma(false);
1801         qglViewport(0, 0, vid.width, vid.height);
1802         //qglDisable(GL_SCISSOR_TEST);
1803         //qglDepthMask(1);
1804         qglColorMask(1,1,1,1);
1805         //qglClearColor(0,0,0,0);
1806         //qglClear(GL_COLOR_BUFFER_BIT);
1807         //qglCullFace(GL_FRONT);
1808         //qglDisable(GL_CULL_FACE);
1809         //R_ClearScreen();
1810         R_Textures_Frame();
1811         GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
1812         R_Mesh_Start();
1813         R_Mesh_Matrix(&r_identitymatrix);
1814         // draw the loading plaque
1815         pic = Draw_CachePic("gfx/loading", false);
1816         x = (vid_conwidth.integer - pic->width)/2;
1817         y = (vid_conheight.integer - pic->height)/2;
1818         GL_Color(1,1,1,1);
1819         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1820         GL_DepthTest(false);
1821         memset(&m, 0, sizeof(m));
1822         m.pointer_vertex = varray_vertex3f;
1823         m.pointer_texcoord[0] = varray_texcoord2f[0];
1824         m.tex[0] = R_GetTexture(pic->tex);
1825         R_Mesh_State(&m);
1826         varray_vertex3f[0] = varray_vertex3f[9] = x;
1827         varray_vertex3f[1] = varray_vertex3f[4] = y;
1828         varray_vertex3f[3] = varray_vertex3f[6] = x + pic->width;
1829         varray_vertex3f[7] = varray_vertex3f[10] = y + pic->height;
1830         varray_texcoord2f[0][0] = 0;varray_texcoord2f[0][1] = 0;
1831         varray_texcoord2f[0][2] = 1;varray_texcoord2f[0][3] = 0;
1832         varray_texcoord2f[0][4] = 1;varray_texcoord2f[0][5] = 1;
1833         varray_texcoord2f[0][6] = 0;varray_texcoord2f[0][7] = 1;
1834         GL_LockArrays(0, 4);
1835         R_Mesh_Draw(0, 4, 2, polygonelements);
1836         GL_LockArrays(0, 0);
1837         R_Mesh_Finish();
1838         // refresh
1839         VID_Finish();
1840 }
1841
1842 /*
1843 ==================
1844 SCR_UpdateScreen
1845
1846 This is called every frame, and can also be called explicitly to flush
1847 text to the screen.
1848 ==================
1849 */
1850 void SCR_UpdateScreen (void)
1851 {
1852         if (vid_hidden)
1853                 return;
1854
1855         if (r_textureunits.integer > gl_textureunits)
1856                 Cvar_SetValueQuick(&r_textureunits, gl_textureunits);
1857         if (r_textureunits.integer < 1)
1858                 Cvar_SetValueQuick(&r_textureunits, 1);
1859
1860         if (gl_combine.integer && !gl_combine_extension)
1861                 Cvar_SetValueQuick(&gl_combine, 0);
1862
1863         CHECKGLERROR
1864         qglViewport(0, 0, vid.width, vid.height);
1865         qglDisable(GL_SCISSOR_TEST);
1866         qglDepthMask(1);
1867         qglColorMask(1,1,1,1);
1868         qglClearColor(0,0,0,0);
1869         qglClear(GL_COLOR_BUFFER_BIT);
1870         CHECKGLERROR
1871
1872         R_TimeReport("clear");
1873
1874         if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer || r_stereo_sidebyside.integer)
1875         {
1876                 matrix4x4_t originalmatrix = r_refdef.viewentitymatrix;
1877                 r_refdef.viewentitymatrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * -0.5f * r_refdef.viewentitymatrix.m[0][1];
1878                 r_refdef.viewentitymatrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * -0.5f * r_refdef.viewentitymatrix.m[1][1];
1879                 r_refdef.viewentitymatrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * -0.5f * r_refdef.viewentitymatrix.m[2][1];
1880
1881                 if (r_stereo_sidebyside.integer)
1882                         r_stereo_side = 0;
1883
1884                 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1885                 {
1886                         r_refdef.colormask[0] = 1;
1887                         r_refdef.colormask[1] = 0;
1888                         r_refdef.colormask[2] = 0;
1889                 }
1890
1891                 SCR_DrawScreen();
1892
1893                 r_refdef.viewentitymatrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * 0.5f * r_refdef.viewentitymatrix.m[0][1];
1894                 r_refdef.viewentitymatrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * 0.5f * r_refdef.viewentitymatrix.m[1][1];
1895                 r_refdef.viewentitymatrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * 0.5f * r_refdef.viewentitymatrix.m[2][1];
1896
1897                 if (r_stereo_sidebyside.integer)
1898                         r_stereo_side = 1;
1899
1900                 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1901                 {
1902                         r_refdef.colormask[0] = 0;
1903                         r_refdef.colormask[1] = r_stereo_redcyan.integer || r_stereo_redgreen.integer;
1904                         r_refdef.colormask[2] = r_stereo_redcyan.integer || r_stereo_redblue.integer;
1905                 }
1906
1907                 SCR_DrawScreen();
1908
1909                 r_refdef.viewentitymatrix = originalmatrix;
1910         }
1911         else
1912         {
1913                 r_showtrispass = false;
1914                 SCR_DrawScreen();
1915
1916                 if (r_showtris.value > 0)
1917                 {
1918                         rmeshstate_t m;
1919                         GL_BlendFunc(GL_ONE, GL_ONE);
1920                         GL_DepthTest(GL_FALSE);
1921                         GL_DepthMask(GL_FALSE);
1922                         memset(&m, 0, sizeof(m));
1923                         R_Mesh_State(&m);
1924                         r_showtrispass = true;
1925                         GL_ShowTrisColor(0.2,0.2,0.2,1);
1926                         SCR_DrawScreen();
1927                         r_showtrispass = false;
1928                 }
1929         }
1930
1931         VID_Finish();
1932         R_TimeReport("finish");
1933 }
1934
1935
1936 //===========================================================================
1937 // dynamic vertex array buffer subsystem
1938 //===========================================================================
1939
1940 // FIXME: someday this should be dynamically allocated and resized?
1941 float varray_vertex3f[65536*3];
1942 float varray_svector3f[65536*3];
1943 float varray_tvector3f[65536*3];
1944 float varray_normal3f[65536*3];
1945 float varray_color4f[65536*4];
1946 float varray_texcoord2f[4][65536*2];
1947 float varray_texcoord3f[4][65536*3];
1948 int earray_element3i[65536];
1949 float varray_vertex3f2[65536*3];
1950
1951 //===========================================================================
1952 // vertex array caching subsystem
1953 //===========================================================================
1954
1955 typedef struct rcachearraylink_s
1956 {
1957         struct rcachearraylink_s *next, *prev;
1958         struct rcachearrayitem_s *data;
1959 }
1960 rcachearraylink_t;
1961
1962 typedef struct rcachearrayitem_s
1963 {
1964         // the original request structure
1965         rcachearrayrequest_t request;
1966         // active
1967         int active;
1968         // offset into r_mesh_rcachedata
1969         int offset;
1970         // for linking this into the sequential list
1971         rcachearraylink_t sequentiallink;
1972         // for linking this into the lookup list
1973         rcachearraylink_t hashlink;
1974 }
1975 rcachearrayitem_t;
1976
1977 #define RCACHEARRAY_HASHSIZE 65536
1978 #define RCACHEARRAY_ITEMS 4096
1979 #define RCACHEARRAY_DEFAULTSIZE (4 << 20)
1980
1981 // all active items are linked into this chain in sorted order
1982 static rcachearraylink_t r_mesh_rcachesequentialchain;
1983 // all inactive items are linked into this chain in unknown order
1984 static rcachearraylink_t r_mesh_rcachefreechain;
1985 // all active items are also linked into these chains (using their hashlink)
1986 static rcachearraylink_t r_mesh_rcachechain[RCACHEARRAY_HASHSIZE];
1987
1988 // all items are stored here, whether active or inactive
1989 static rcachearrayitem_t r_mesh_rcacheitems[RCACHEARRAY_ITEMS];
1990
1991 // size of data buffer
1992 static int r_mesh_rcachedata_size = RCACHEARRAY_DEFAULTSIZE;
1993 // data buffer
1994 static qbyte r_mesh_rcachedata[RCACHEARRAY_DEFAULTSIZE];
1995
1996 // current state
1997 static int r_mesh_rcachedata_offset;
1998 static rcachearraylink_t *r_mesh_rcachesequentialchain_current;
1999
2000 static void R_Mesh_CacheArray_Startup(void)
2001 {
2002         int i;
2003         rcachearraylink_t *l;
2004         // prepare all the linked lists
2005         l = &r_mesh_rcachesequentialchain;l->next = l->prev = l;l->data = NULL;
2006         l = &r_mesh_rcachefreechain;l->next = l->prev = l;l->data = NULL;
2007         memset(&r_mesh_rcachechain, 0, sizeof(r_mesh_rcachechain));
2008         for (i = 0;i < RCACHEARRAY_HASHSIZE;i++)
2009         {
2010                 l = &r_mesh_rcachechain[i];
2011                 l->next = l->prev = l;
2012                 l->data = NULL;
2013         }
2014         memset(&r_mesh_rcacheitems, 0, sizeof(r_mesh_rcacheitems));
2015         for (i = 0;i < RCACHEARRAY_ITEMS;i++)
2016         {
2017                 r_mesh_rcacheitems[i].hashlink.data = r_mesh_rcacheitems[i].sequentiallink.data = &r_mesh_rcacheitems[i];
2018                 l = &r_mesh_rcacheitems[i].sequentiallink;
2019                 l->next = &r_mesh_rcachefreechain;
2020                 l->prev = l->next->prev;
2021                 l->next->prev = l->prev->next = l;
2022         }
2023         // clear other state
2024         r_mesh_rcachedata_offset = 0;
2025         r_mesh_rcachesequentialchain_current = &r_mesh_rcachesequentialchain;
2026 }
2027
2028 static void R_Mesh_CacheArray_Shutdown(void)
2029 {
2030 }
2031
2032 /*
2033 static void R_Mesh_CacheArray_ValidateState(int num)
2034 {
2035         rcachearraylink_t *l, *lhead;
2036         lhead = &r_mesh_rcachesequentialchain;
2037         if (r_mesh_rcachesequentialchain_current == lhead)
2038                 return;
2039         for (l = lhead->next;l != lhead;l = l->next)
2040                 if (r_mesh_rcachesequentialchain_current == l)
2041                         return;
2042         Sys_Error("%i", num);
2043 }
2044 */
2045
2046 int R_Mesh_CacheArray(rcachearrayrequest_t *r)
2047 {
2048         rcachearraylink_t *l, *lhead, *lnext;
2049         rcachearrayitem_t *d;
2050         int hashindex, offset, offsetend;
2051
2052         //R_Mesh_CacheArray_ValidateState(3);
2053         // calculate a hashindex to choose a cache chain
2054         r->data = NULL;
2055         hashindex = CRC_Block((void *)r, sizeof(*r)) % RCACHEARRAY_HASHSIZE;
2056
2057         // is it already cached?
2058         for (lhead = &r_mesh_rcachechain[hashindex], l = lhead->next;l != lhead;l = l->next)
2059         {
2060                 if (!memcmp(&l->data->request, r, sizeof(l->data->request)))
2061                 {
2062                         // we have it cached already
2063                         r->data = r_mesh_rcachedata + l->data->offset;
2064                         return false;
2065                 }
2066         }
2067
2068         // we need to add a new cache item, this means finding a place for the new
2069         // data and making sure we have a free item available, lots of work...
2070
2071         // check if buffer needs to wrap
2072         if (r_mesh_rcachedata_offset + r->data_size > r_mesh_rcachedata_size)
2073         {
2074                 /*
2075                 if (r->data_size * 10 > r_mesh_rcachedata_size)
2076                 {
2077                         // realloc whole cache
2078                 }
2079                 */
2080                 // reset back to start
2081                 r_mesh_rcachedata_offset = 0;
2082                 r_mesh_rcachesequentialchain_current = &r_mesh_rcachesequentialchain;
2083         }
2084         offset = r_mesh_rcachedata_offset;
2085         r_mesh_rcachedata_offset += r->data_size;
2086         offsetend = r_mesh_rcachedata_offset;
2087         //R_Mesh_CacheArray_ValidateState(4);
2088
2089         /*
2090         {
2091                 int n;
2092                 for (lhead = &r_mesh_rcachesequentialchain, l = lhead->next, n = 0;l != lhead;l = l->next, n++);
2093                 Con_Printf("R_Mesh_CacheArray: new data range %i:%i, %i items are already linked\n", offset, offsetend, n);
2094         }
2095         */
2096
2097         // make room for the new data (remove old items)
2098         lhead = &r_mesh_rcachesequentialchain;
2099         l = r_mesh_rcachesequentialchain_current;
2100         if (l == lhead)
2101                 l = l->next;
2102         while (l != lhead && l->data->offset < offsetend && l->data->offset + l->data->request.data_size > offset)
2103         {
2104         //r_mesh_rcachesequentialchain_current = l;
2105         //R_Mesh_CacheArray_ValidateState(8);
2106                 lnext = l->next;
2107                 // if at the end of the chain, wrap around
2108                 if (lnext == lhead)
2109                         lnext = lnext->next;
2110         //r_mesh_rcachesequentialchain_current = lnext;
2111         //R_Mesh_CacheArray_ValidateState(10);
2112
2113                 // unlink from sequential chain
2114                 l->next->prev = l->prev;
2115                 l->prev->next = l->next;
2116         //R_Mesh_CacheArray_ValidateState(11);
2117                 // link into free chain
2118                 l->next = &r_mesh_rcachefreechain;
2119                 l->prev = l->next->prev;
2120                 l->next->prev = l->prev->next = l;
2121         //R_Mesh_CacheArray_ValidateState(12);
2122
2123                 l = &l->data->hashlink;
2124                 // unlink from hash chain
2125                 l->next->prev = l->prev;
2126                 l->prev->next = l->next;
2127
2128                 l = lnext;
2129         //r_mesh_rcachesequentialchain_current = l;
2130         //R_Mesh_CacheArray_ValidateState(9);
2131         }
2132         //r_mesh_rcachesequentialchain_current = l;
2133         //R_Mesh_CacheArray_ValidateState(5);
2134         // gobble an extra item if we have no free items available
2135         if (r_mesh_rcachefreechain.next == &r_mesh_rcachefreechain)
2136         {
2137                 lnext = l->next;
2138
2139                 // unlink from sequential chain
2140                 l->next->prev = l->prev;
2141                 l->prev->next = l->next;
2142                 // link into free chain
2143                 l->next = &r_mesh_rcachefreechain;
2144                 l->prev = l->next->prev;
2145                 l->next->prev = l->prev->next = l;
2146
2147                 l = &l->data->hashlink;
2148                 // unlink from hash chain
2149                 l->next->prev = l->prev;
2150                 l->prev->next = l->next;
2151
2152                 l = lnext;
2153         }
2154         r_mesh_rcachesequentialchain_current = l;
2155         //R_Mesh_CacheArray_ValidateState(6);
2156
2157         // now take an item from the free chain
2158         l = r_mesh_rcachefreechain.next;
2159         // set it up
2160         d = l->data;
2161         d->request = *r;
2162         d->offset = offset;
2163         // unlink
2164         l->next->prev = l->prev;
2165         l->prev->next = l->next;
2166         // relink to sequential
2167         l->next = r_mesh_rcachesequentialchain_current->prev;
2168         l->prev = l->next->prev;
2169         while (l->next->data && l->data && l->next->data->offset <= d->offset)
2170         {
2171                 //Con_Print(">\n");
2172                 l->next = l->next->next;
2173                 l->prev = l->prev->next;
2174         }
2175         while (l->prev->data && l->data && l->prev->data->offset >= d->offset)
2176         {
2177                 //Con_Print("<\n");
2178                 l->prev = l->prev->prev;
2179                 l->next = l->next->prev;
2180         }
2181         l->next->prev = l->prev->next = l;
2182         // also link into hash chain
2183         l = &l->data->hashlink;
2184         l->next = &r_mesh_rcachechain[hashindex];
2185         l->prev = l->next->prev;
2186         l->prev->next = l;
2187         l->next->prev = l->prev->next = l;
2188
2189
2190         //r_mesh_rcachesequentialchain_current = d->sequentiallink.next;
2191
2192         //R_Mesh_CacheArray_ValidateState(7);
2193         // and finally set the data pointer
2194         r->data = r_mesh_rcachedata + d->offset;
2195         // and tell the caller to fill the array
2196         return true;
2197 }
2198