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