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