]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_backend.c
vertex arrays renamed to varray_ and exposed to rest of engine
[xonotic/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3
4 cvar_t gl_mesh_maxtriangles = {0, "gl_mesh_maxtriangles", "1024"};
5 cvar_t gl_mesh_floatcolors = {0, "gl_mesh_floatcolors", "1"};
6 cvar_t gl_mesh_drawmode = {CVAR_SAVE, "gl_mesh_drawmode", "3"};
7
8 cvar_t r_render = {0, "r_render", "1"};
9 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1"}; // whether or not to use dithering
10 cvar_t gl_lockarrays = {0, "gl_lockarrays", "1"};
11
12 // this is used to increase gl_mesh_maxtriangles automatically if a mesh was
13 // too large for the buffers in the previous frame
14 int overflowedverts = 0;
15
16 int gl_maxdrawrangeelementsvertices;
17 int gl_maxdrawrangeelementsindices;
18
19 #ifdef DEBUGGL
20 int errornumber = 0;
21
22 void GL_PrintError(int errornumber, char *filename, int linenumber)
23 {
24         switch(errornumber)
25         {
26 #ifdef GL_INVALID_ENUM
27         case GL_INVALID_ENUM:
28                 Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
29                 break;
30 #endif
31 #ifdef GL_INVALID_VALUE
32         case GL_INVALID_VALUE:
33                 Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
34                 break;
35 #endif
36 #ifdef GL_INVALID_OPERATION
37         case GL_INVALID_OPERATION:
38                 Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
39                 break;
40 #endif
41 #ifdef GL_STACK_OVERFLOW
42         case GL_STACK_OVERFLOW:
43                 Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
44                 break;
45 #endif
46 #ifdef GL_STACK_UNDERFLOW
47         case GL_STACK_UNDERFLOW:
48                 Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
49                 break;
50 #endif
51 #ifdef GL_OUT_OF_MEMORY
52         case GL_OUT_OF_MEMORY:
53                 Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
54                 break;
55 #endif
56 #ifdef GL_TABLE_TOO_LARGE
57     case GL_TABLE_TOO_LARGE:
58                 Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
59                 break;
60 #endif
61         default:
62                 Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
63                 break;
64         }
65 }
66 #endif
67
68 float r_mesh_farclip;
69
70 static float viewdist;
71 // sign bits (true if negative) for vpn[] entries, so quick integer compares can be used instead of float compares
72 static int vpnbit0, vpnbit1, vpnbit2;
73
74 int c_meshs, c_meshtris;
75
76 int lightscalebit;
77 float lightscale;
78 float overbrightscale;
79
80 void SCR_ScreenShot_f (void);
81
82 // these are externally accessible
83 float mesh_colorscale;
84 int *varray_element;
85 float *varray_vertex;
86 float *varray_color;
87 float *varray_texcoord[MAX_TEXTUREUNITS];
88 int mesh_maxtris;
89 int mesh_maxverts; // always mesh_maxtris * 3
90
91 static matrix4x4_t backendmatrix;
92
93 static int backendunits, backendactive;
94 static qbyte *varray_bcolor;
95 static mempool_t *gl_backend_mempool;
96
97 void GL_Backend_AllocArrays(void)
98 {
99         int i;
100
101         if (!gl_backend_mempool)
102                 gl_backend_mempool = Mem_AllocPool("GL_Backend");
103
104         mesh_maxverts = mesh_maxtris * 3;
105
106         varray_element = Mem_Alloc(gl_backend_mempool, mesh_maxtris * sizeof(int[3]));
107         varray_vertex = Mem_Alloc(gl_backend_mempool, mesh_maxverts * sizeof(float[4]));
108         varray_color = Mem_Alloc(gl_backend_mempool, mesh_maxverts * sizeof(float[4]));
109         varray_bcolor = Mem_Alloc(gl_backend_mempool, mesh_maxverts * sizeof(qbyte[4]));
110         for (i = 0;i < backendunits;i++)
111                 varray_texcoord[i] = Mem_Alloc(gl_backend_mempool, mesh_maxverts * sizeof(float[2]));
112         for (;i < MAX_TEXTUREUNITS;i++)
113                 varray_texcoord[i] = NULL;
114 }
115
116 void GL_Backend_FreeArrays(int resizingbuffers)
117 {
118         int i;
119         if (resizingbuffers)
120                 Mem_EmptyPool(gl_backend_mempool);
121         else
122                 Mem_FreePool(&gl_backend_mempool);
123         varray_element = NULL;
124         varray_vertex = NULL;
125         varray_color = NULL;
126         varray_bcolor = NULL;
127         for (i = 0;i < MAX_TEXTUREUNITS;i++)
128                 varray_texcoord[i] = NULL;
129 }
130
131 static void gl_backend_start(void)
132 {
133         Con_Printf("OpenGL Backend started with gl_mesh_maxtriangles %i\n", gl_mesh_maxtriangles.integer);
134         if (qglDrawRangeElements != NULL)
135         {
136                 qglGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &gl_maxdrawrangeelementsvertices);
137                 qglGetIntegerv(GL_MAX_ELEMENTS_INDICES, &gl_maxdrawrangeelementsindices);
138                 CHECKGLERROR
139                 Con_Printf("glDrawRangeElements detected (max vertices %i, max indices %i)\n", gl_maxdrawrangeelementsvertices, gl_maxdrawrangeelementsindices);
140         }
141         if (strstr(gl_renderer, "3Dfx"))
142         {
143                 Con_Printf("3Dfx driver detected, forcing gl_mesh_floatcolors to 0 to prevent crashs\n");
144                 Cvar_SetValueQuick(&gl_mesh_floatcolors, 0);
145         }
146
147         backendunits = min(MAX_TEXTUREUNITS, gl_textureunits);
148
149         GL_Backend_AllocArrays();
150
151         backendactive = true;
152 }
153
154 static void gl_backend_shutdown(void)
155 {
156         backendunits = 0;
157         backendactive = false;
158
159         Con_Printf("OpenGL Backend shutting down\n");
160
161         GL_Backend_FreeArrays(false);
162 }
163
164 void GL_Backend_CheckCvars(void)
165 {
166         if (gl_mesh_drawmode.integer < 0)
167                 Cvar_SetValueQuick(&gl_mesh_drawmode, 0);
168         if (gl_mesh_drawmode.integer > 3)
169                 Cvar_SetValueQuick(&gl_mesh_drawmode, 3);
170
171         // change drawmode 3 to 2 if 3 won't work
172         if (gl_mesh_drawmode.integer >= 3 && qglDrawRangeElements == NULL)
173                 Cvar_SetValueQuick(&gl_mesh_drawmode, 2);
174
175         // 21760 is (65536 / 3) rounded off to a multiple of 128
176         if (gl_mesh_maxtriangles.integer < 1024)
177                 Cvar_SetValueQuick(&gl_mesh_maxtriangles, 1024);
178         if (gl_mesh_maxtriangles.integer > 21760)
179                 Cvar_SetValueQuick(&gl_mesh_maxtriangles, 21760);
180 }
181
182 void GL_Backend_ResizeArrays(int numtriangles)
183 {
184         Cvar_SetValueQuick(&gl_mesh_maxtriangles, numtriangles);
185         GL_Backend_CheckCvars();
186         mesh_maxtris = gl_mesh_maxtriangles.integer;
187         GL_Backend_FreeArrays(true);
188         GL_Backend_AllocArrays();
189 }
190
191 static void gl_backend_newmap(void)
192 {
193 }
194
195 void gl_backend_init(void)
196 {
197         Cvar_RegisterVariable(&r_render);
198         Cvar_RegisterVariable(&gl_dither);
199         Cvar_RegisterVariable(&gl_lockarrays);
200 #ifdef NORENDER
201         Cvar_SetValue("r_render", 0);
202 #endif
203
204         Cvar_RegisterVariable(&gl_mesh_maxtriangles);
205         Cvar_RegisterVariable(&gl_mesh_floatcolors);
206         Cvar_RegisterVariable(&gl_mesh_drawmode);
207         GL_Backend_CheckCvars();
208         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
209 }
210
211 int arraylocked = false;
212
213 void GL_LockArray(int first, int count)
214 {
215         if (!arraylocked && gl_supportslockarrays && gl_lockarrays.integer && gl_mesh_drawmode.integer > 0)
216         {
217                 qglLockArraysEXT(first, count);
218                 CHECKGLERROR
219                 arraylocked = true;
220         }
221 }
222
223 void GL_UnlockArray(void)
224 {
225         if (arraylocked)
226         {
227                 qglUnlockArraysEXT();
228                 CHECKGLERROR
229                 arraylocked = false;
230         }
231 }
232
233 /*
234 =============
235 GL_SetupFrame
236 =============
237 */
238 static void GL_SetupFrame (void)
239 {
240         double xmax, ymax;
241         double fovx, fovy, zNear, zFar, aspect;
242
243         if (!r_render.integer)
244                 return;
245
246         qglDepthFunc (GL_LEQUAL);CHECKGLERROR
247
248         // set up viewpoint
249         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
250         qglLoadIdentity ();CHECKGLERROR
251
252         // y is weird beause OpenGL is bottom to top, we use top to bottom
253         qglViewport(r_refdef.x, vid.realheight - (r_refdef.y + r_refdef.height), r_refdef.width, r_refdef.height);CHECKGLERROR
254
255         // depth range
256         zNear = 1.0;
257         zFar = r_mesh_farclip;
258         if (zFar < 64)
259                 zFar = 64;
260
261         // fov angles
262         fovx = r_refdef.fov_x;
263         fovy = r_refdef.fov_y;
264         aspect = r_refdef.width / r_refdef.height;
265
266         // pyramid slopes
267         xmax = zNear * tan(fovx * M_PI / 360.0) * aspect;
268         ymax = zNear * tan(fovy * M_PI / 360.0);
269
270         // set view pyramid
271         qglFrustum(-xmax, xmax, -ymax, ymax, zNear, zFar);CHECKGLERROR
272
273         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
274         qglLoadIdentity ();CHECKGLERROR
275
276         // put Z going up
277         qglRotatef (-90,  1, 0, 0);CHECKGLERROR
278         qglRotatef (90,  0, 0, 1);CHECKGLERROR
279         // camera rotation
280         qglRotatef (-r_refdef.viewangles[2],  1, 0, 0);CHECKGLERROR
281         qglRotatef (-r_refdef.viewangles[0],  0, 1, 0);CHECKGLERROR
282         qglRotatef (-r_refdef.viewangles[1],  0, 0, 1);CHECKGLERROR
283         // camera location
284         qglTranslatef (-r_refdef.vieworg[0],  -r_refdef.vieworg[1],  -r_refdef.vieworg[2]);CHECKGLERROR
285 }
286
287 static struct
288 {
289         int blendfunc1;
290         int blendfunc2;
291         int blend;
292         GLboolean depthmask;
293         int depthdisable;
294         int unit;
295         int clientunit;
296         int texture[MAX_TEXTUREUNITS];
297         float texturergbscale[MAX_TEXTUREUNITS];
298 }
299 gl_state;
300
301 void GL_SetupTextureState(void)
302 {
303         int i;
304         if (backendunits > 1)
305         {
306                 for (i = 0;i < backendunits;i++)
307                 {
308                         qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
309                         qglBindTexture(GL_TEXTURE_2D, gl_state.texture[i]);CHECKGLERROR
310                         if (gl_combine.integer)
311                         {
312                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
313                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);CHECKGLERROR
314                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);CHECKGLERROR
315                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
316                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_CONSTANT_ARB);CHECKGLERROR
317                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
318                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
319                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);CHECKGLERROR
320                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);CHECKGLERROR
321                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);CHECKGLERROR
322                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
323                                 qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);CHECKGLERROR
324                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
325                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
326                                 qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
327                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, gl_state.texturergbscale[i]);CHECKGLERROR
328                                 qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
329                         }
330                         else
331                         {
332                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
333                         }
334                         if (gl_state.texture[i])
335                         {
336                                 qglEnable(GL_TEXTURE_2D);CHECKGLERROR
337                         }
338                         else
339                         {
340                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
341                         }
342                         if (gl_mesh_drawmode.integer > 0)
343                         {
344                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
345                                 qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), varray_texcoord[i]);CHECKGLERROR
346                                 if (gl_state.texture[i])
347                                 {
348                                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
349                                 }
350                                 else
351                                 {
352                                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
353                                 }
354                         }
355                 }
356         }
357         else
358         {
359                 qglBindTexture(GL_TEXTURE_2D, gl_state.texture[0]);CHECKGLERROR
360                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
361                 if (gl_state.texture[0])
362                 {
363                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
364                 }
365                 else
366                 {
367                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
368                 }
369                 if (gl_mesh_drawmode.integer > 0)
370                 {
371                         qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), varray_texcoord[0]);CHECKGLERROR
372                         if (gl_state.texture[0])
373                         {
374                                 qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
375                         }
376                         else
377                         {
378                                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
379                         }
380                 }
381         }
382 }
383
384 int usedarrays;
385 void GL_Backend_ResetState(void)
386 {
387         int i;
388         gl_state.unit = 0;
389         gl_state.clientunit = 0;
390
391         for (i = 0;i < backendunits;i++)
392         {
393                 gl_state.texture[i] = 0;
394                 gl_state.texturergbscale[i] = 1;
395         }
396
397         qglEnable(GL_CULL_FACE);CHECKGLERROR
398         qglCullFace(GL_FRONT);CHECKGLERROR
399
400         gl_state.depthdisable = false;
401         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
402
403         gl_state.blendfunc1 = GL_ONE;
404         gl_state.blendfunc2 = GL_ZERO;
405         qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
406
407         gl_state.blend = 0;
408         qglDisable(GL_BLEND);CHECKGLERROR
409
410         gl_state.depthmask = GL_TRUE;
411         qglDepthMask(gl_state.depthmask);CHECKGLERROR
412
413         usedarrays = false;
414         if (gl_mesh_drawmode.integer > 0)
415         {
416                 usedarrays = true;
417                 qglVertexPointer(3, GL_FLOAT, sizeof(float[4]), varray_vertex);CHECKGLERROR
418                 qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
419                 if (gl_mesh_floatcolors.integer)
420                 {
421                         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), varray_color);CHECKGLERROR
422                 }
423                 else
424                 {
425                         qglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(qbyte[4]), varray_bcolor);CHECKGLERROR
426                 }
427                 qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
428         }
429
430         GL_SetupTextureState();
431 }
432
433 // called at beginning of frame
434 void R_Mesh_Start(float farclip)
435 {
436         if (!backendactive)
437                 Sys_Error("R_Mesh_Clear: called when backend is not active\n");
438
439         CHECKGLERROR
440
441         r_mesh_farclip = farclip;
442         viewdist = DotProduct(r_origin, vpn);
443         vpnbit0 = vpn[0] < 0;
444         vpnbit1 = vpn[1] < 0;
445         vpnbit2 = vpn[2] < 0;
446
447         c_meshs = 0;
448         c_meshtris = 0;
449
450         GL_Backend_CheckCvars();
451         if (mesh_maxtris != gl_mesh_maxtriangles.integer)
452                 GL_Backend_ResizeArrays(gl_mesh_maxtriangles.integer);
453
454         GL_SetupFrame();
455
456         GL_Backend_ResetState();
457 }
458
459 int gl_backend_rebindtextures;
460
461 void GL_ConvertColorsFloatToByte(int numverts)
462 {
463         int i, k, total;
464         // LordHavoc: to avoid problems with aliasing (treating memory as two
465         // different types - exactly what this is doing), these must be volatile
466         // (or a union)
467         volatile int *icolor;
468         volatile float *fcolor;
469         qbyte *bcolor;
470
471         total = numverts * 4;
472
473         // shift float to have 8bit fraction at base of number
474         fcolor = varray_color;
475         for (i = 0;i < total;)
476         {
477                 fcolor[i    ] += 32768.0f;
478                 fcolor[i + 1] += 32768.0f;
479                 fcolor[i + 2] += 32768.0f;
480                 fcolor[i + 3] += 32768.0f;
481                 i += 4;
482         }
483
484         // then read as integer and kill float bits...
485         icolor = (int *)varray_color;
486         bcolor = varray_bcolor;
487         for (i = 0;i < total;)
488         {
489                 k = icolor[i    ] & 0x7FFFFF;if (k > 255) k = 255;bcolor[i    ] = (qbyte) k;
490                 k = icolor[i + 1] & 0x7FFFFF;if (k > 255) k = 255;bcolor[i + 1] = (qbyte) k;
491                 k = icolor[i + 2] & 0x7FFFFF;if (k > 255) k = 255;bcolor[i + 2] = (qbyte) k;
492                 k = icolor[i + 3] & 0x7FFFFF;if (k > 255) k = 255;bcolor[i + 3] = (qbyte) k;
493                 i += 4;
494         }
495 }
496
497 void GL_TransformVertices(int numverts)
498 {
499         int i;
500         float m[12], tempv[4], *v;
501         m[0] = backendmatrix.m[0][0];
502         m[1] = backendmatrix.m[0][1];
503         m[2] = backendmatrix.m[0][2];
504         m[3] = backendmatrix.m[0][3];
505         m[4] = backendmatrix.m[1][0];
506         m[5] = backendmatrix.m[1][1];
507         m[6] = backendmatrix.m[1][2];
508         m[7] = backendmatrix.m[1][3];
509         m[8] = backendmatrix.m[2][0];
510         m[9] = backendmatrix.m[2][1];
511         m[10] = backendmatrix.m[2][2];
512         m[11] = backendmatrix.m[2][3];
513         for (i = 0, v = varray_vertex;i < numverts;i++, v += 4)
514         {
515                 VectorCopy(v, tempv);
516                 v[0] = tempv[0] * m[0] + tempv[1] * m[1] + tempv[2] * m[2] + m[3];
517                 v[1] = tempv[0] * m[4] + tempv[1] * m[5] + tempv[2] * m[6] + m[7];
518                 v[2] = tempv[0] * m[8] + tempv[1] * m[9] + tempv[2] * m[10] + m[11];
519         }
520 }
521
522 void GL_DrawRangeElements(int firstvert, int endvert, int indexcount, GLuint *index)
523 {
524         unsigned int i, j, in;
525         qbyte *c;
526         float *v;
527         GL_LockArray(firstvert, endvert - firstvert);
528         if (gl_mesh_drawmode.integer >= 3/* && (endvert - firstvert) <= gl_maxdrawrangeelementsvertices && (indexcount) <= gl_maxdrawrangeelementsindices*/)
529         {
530                 // GL 1.2 or GL 1.1 with extension
531                 qglDrawRangeElements(GL_TRIANGLES, firstvert, endvert, indexcount, GL_UNSIGNED_INT, index);
532                 CHECKGLERROR
533         }
534         else if (gl_mesh_drawmode.integer >= 2)
535         {
536                 // GL 1.1
537                 qglDrawElements(GL_TRIANGLES, indexcount, GL_UNSIGNED_INT, index);
538                 CHECKGLERROR
539         }
540         else if (gl_mesh_drawmode.integer >= 1)
541         {
542                 // GL 1.1
543                 // feed it manually using glArrayElement
544                 qglBegin(GL_TRIANGLES);
545                 for (i = 0;i < indexcount;i++)
546                         qglArrayElement(index[i]);
547                 qglEnd();
548                 CHECKGLERROR
549         }
550         else
551         {
552                 // GL 1.1 but not using vertex arrays - 3dfx glquake minigl driver
553                 // feed it manually
554                 qglBegin(GL_TRIANGLES);
555                 if (gl_state.texture[1]) // if the mesh uses multiple textures
556                 {
557                         // the minigl doesn't have this (because it does not have ARB_multitexture)
558                         for (i = 0;i < indexcount;i++)
559                         {
560                                 in = index[i];
561                                 c = varray_bcolor + in * 4;
562                                 qglColor4ub(c[0], c[1], c[2], c[3]);
563                                 for (j = 0;j < backendunits;j++)
564                                 {
565                                         if (gl_state.texture[j])
566                                         {
567                                                 v = varray_texcoord[j] + in * 2;
568                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, v[0], v[1]);
569                                         }
570                                 }
571                                 v = varray_vertex + in * 4;
572                                 qglVertex3f(v[0], v[1], v[2]);
573                         }
574                 }
575                 else
576                 {
577                         for (i = 0;i < indexcount;i++)
578                         {
579                                 in = index[i];
580                                 c = varray_bcolor + in * 4;
581                                 qglColor4ub(c[0], c[1], c[2], c[3]);
582                                 if (gl_state.texture[0])
583                                 {
584                                         v = varray_texcoord[j] + in * 2;
585                                         qglTexCoord2f(v[0], v[1]);
586                                 }
587                                 v = varray_vertex + in * 4;
588                                 qglVertex3f(v[0], v[1], v[2]);
589                         }
590                 }
591                 qglEnd();
592                 CHECKGLERROR
593         }
594         GL_UnlockArray();
595 }
596
597 // enlarges geometry buffers if they are too small
598 void _R_Mesh_ResizeCheck(int numverts, int numtriangles)
599 {
600         if (numtriangles > mesh_maxtris || numverts > mesh_maxverts)
601         {
602                 if (!backendactive)
603                         Sys_Error("R_Mesh_Begin: called when backend is not active\n");
604                 GL_Backend_ResizeArrays(max(numtriangles, (numverts + 2) / 3) + 100);
605                 GL_Backend_ResetState();
606         }
607 }
608
609 // renders the mesh
610 void R_Mesh_Draw(int numverts, int numtriangles)
611 {
612         if (!backendactive)
613                 Sys_Error("R_Mesh_End: called when backend is not active\n");
614
615         c_meshs++;
616         c_meshtris += numtriangles;
617
618         CHECKGLERROR
619
620         // drawmode 0 always uses byte colors
621         if (!gl_mesh_floatcolors.integer || gl_mesh_drawmode.integer <= 0)
622                 GL_ConvertColorsFloatToByte(numverts);
623         GL_TransformVertices(numverts);
624         if (!r_render.integer)
625                 return;
626         GL_DrawRangeElements(0, numverts, numtriangles * 3, varray_element);
627 }
628
629 // restores backend state, used when done with 3D rendering
630 void R_Mesh_Finish(void)
631 {
632         int i;
633         if (backendunits > 1)
634         {
635                 for (i = backendunits - 1;i >= 0;i--)
636                 {
637                         qglActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
638                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
639                         if (gl_combine.integer)
640                         {
641                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
642                         }
643                         if (i > 0)
644                         {
645                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
646                         }
647                         else
648                         {
649                                 qglEnable(GL_TEXTURE_2D);CHECKGLERROR
650                         }
651                         qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
652
653                         if (usedarrays)
654                         {
655                                 qglClientActiveTexture(GL_TEXTURE0_ARB + i);CHECKGLERROR
656                                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
657                         }
658                 }
659         }
660         else
661         {
662                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
663                 qglEnable(GL_TEXTURE_2D);CHECKGLERROR
664                 if (usedarrays)
665                 {
666                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
667                 }
668         }
669         if (usedarrays)
670         {
671                 qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
672                 qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
673         }
674
675         qglDisable(GL_BLEND);CHECKGLERROR
676         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
677         qglDepthMask(GL_TRUE);CHECKGLERROR
678         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR
679 }
680
681 void R_Mesh_ClearDepth(void)
682 {
683         R_Mesh_Finish();
684         qglClear(GL_DEPTH_BUFFER_BIT);
685         R_Mesh_Start(r_mesh_farclip);
686 }
687
688 // sets up the requested state
689 void R_Mesh_State(const rmeshstate_t *m)
690 {
691         int i, overbright;
692         int texturergbscale[MAX_TEXTUREUNITS];
693         float scaler;
694
695         if (!backendactive)
696                 Sys_Error("R_Mesh_State: called when backend is not active\n");
697
698         if (gl_backend_rebindtextures)
699         {
700                 gl_backend_rebindtextures = false;
701                 GL_SetupTextureState();
702         }
703
704         backendmatrix = m->matrix; // this copies the struct
705
706         overbright = false;
707         scaler = 1;
708         if (m->blendfunc1 == GL_DST_COLOR)
709         {
710                 // check if it is a 2x modulate with framebuffer
711                 if (m->blendfunc2 == GL_SRC_COLOR)
712                         scaler *= 0.5f;
713         }
714         else if (m->blendfunc2 != GL_SRC_COLOR)
715         {
716                 if (m->tex[0])
717                 {
718                         overbright = m->wantoverbright && gl_combine.integer;
719                         if (overbright)
720                                 scaler *= 0.25f;
721                 }
722                 scaler *= overbrightscale;
723         }
724         mesh_colorscale = scaler;
725
726         if (gl_state.blendfunc1 != m->blendfunc1 || gl_state.blendfunc2 != m->blendfunc2)
727         {
728                 qglBlendFunc(gl_state.blendfunc1 = m->blendfunc1, gl_state.blendfunc2 = m->blendfunc2);CHECKGLERROR
729                 if (gl_state.blendfunc2 == GL_ZERO)
730                 {
731                         if (gl_state.blendfunc1 == GL_ONE)
732                         {
733                                 if (gl_state.blend)
734                                 {
735                                         gl_state.blend = 0;
736                                         qglDisable(GL_BLEND);CHECKGLERROR
737                                 }
738                         }
739                         else
740                         {
741                                 if (!gl_state.blend)
742                                 {
743                                         gl_state.blend = 1;
744                                         qglEnable(GL_BLEND);CHECKGLERROR
745                                 }
746                         }
747                 }
748                 else
749                 {
750                         if (!gl_state.blend)
751                         {
752                                 gl_state.blend = 1;
753                                 qglEnable(GL_BLEND);CHECKGLERROR
754                         }
755                 }
756         }
757         if (gl_state.depthdisable != m->depthdisable)
758         {
759                 gl_state.depthdisable = m->depthdisable;
760                 if (gl_state.depthdisable)
761                         qglDisable(GL_DEPTH_TEST);
762                 else
763                         qglEnable(GL_DEPTH_TEST);
764         }
765         if (gl_state.depthmask != (m->blendfunc2 == GL_ZERO || m->depthwrite))
766         {
767                 qglDepthMask(gl_state.depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite));CHECKGLERROR
768         }
769
770         for (i = 0;i < backendunits;i++)
771         {
772                 if (m->texrgbscale[i])
773                         texturergbscale[i] = m->texrgbscale[i];
774                 else
775                         texturergbscale[i] = 1;
776         }
777         if (overbright)
778                 for (i = backendunits - 1;i >= 0;i--)
779                         if (m->tex[i])
780                                 texturergbscale[i] = 4;
781
782         if (backendunits > 1)
783         {
784                 for (i = 0;i < backendunits;i++)
785                 {
786                         if (gl_state.texture[i] != m->tex[i])
787                         {
788                                 if (gl_state.unit != i)
789                                 {
790                                         qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
791                                 }
792                                 if (gl_state.texture[i] == 0)
793                                 {
794                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
795                                         if (gl_state.clientunit != i)
796                                         {
797                                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
798                                         }
799                                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
800                                 }
801                                 qglBindTexture(GL_TEXTURE_2D, (gl_state.texture[i] = m->tex[i]));CHECKGLERROR
802                                 if (gl_state.texture[i] == 0)
803                                 {
804                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
805                                         if (gl_state.clientunit != i)
806                                         {
807                                                 qglClientActiveTexture(GL_TEXTURE0_ARB + (gl_state.clientunit = i));CHECKGLERROR
808                                         }
809                                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
810                                 }
811                         }
812                         if (gl_state.texturergbscale[i] != texturergbscale[i])
813                         {
814                                 if (gl_state.unit != i)
815                                 {
816                                         qglActiveTexture(GL_TEXTURE0_ARB + (gl_state.unit = i));CHECKGLERROR
817                                 }
818                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (gl_state.texturergbscale[i] = texturergbscale[i]));CHECKGLERROR
819                         }
820                 }
821         }
822         else
823         {
824                 if (gl_state.texture[0] != m->tex[0])
825                 {
826                         if (gl_state.texture[0] == 0)
827                         {
828                                 qglEnable(GL_TEXTURE_2D);CHECKGLERROR
829                                 qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
830                         }
831                         qglBindTexture(GL_TEXTURE_2D, (gl_state.texture[0] = m->tex[0]));CHECKGLERROR
832                         if (gl_state.texture[0] == 0)
833                         {
834                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
835                                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
836                         }
837                 }
838         }
839 }
840
841 /*
842 ==============================================================================
843
844                                                 SCREEN SHOTS
845
846 ==============================================================================
847 */
848
849 qboolean SCR_ScreenShot(char *filename, int x, int y, int width, int height)
850 {
851         qboolean ret;
852         int i;
853         qbyte *buffer;
854
855         if (!r_render.integer)
856                 return false;
857
858         buffer = Mem_Alloc(tempmempool, width*height*3);
859         qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
860         CHECKGLERROR
861
862         // LordHavoc: compensate for v_overbrightbits when using hardware gamma
863         if (v_hwgamma.integer)
864                 for (i = 0;i < width * height * 3;i++)
865                         buffer[i] <<= v_overbrightbits.integer;
866
867         ret = Image_WriteTGARGB_preflipped(filename, width, height, buffer);
868
869         Mem_Free(buffer);
870         return ret;
871 }
872
873 //=============================================================================
874
875 void R_ClearScreen(void)
876 {
877         if (r_render.integer)
878         {
879                 // clear to black
880                 qglClearColor(0,0,0,0);CHECKGLERROR
881                 // clear the screen
882                 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);CHECKGLERROR
883                 // set dithering mode
884                 if (gl_dither.integer)
885                 {
886                         qglEnable(GL_DITHER);CHECKGLERROR
887                 }
888                 else
889                 {
890                         qglDisable(GL_DITHER);CHECKGLERROR
891                 }
892         }
893 }
894
895 /*
896 ==================
897 SCR_UpdateScreen
898
899 This is called every frame, and can also be called explicitly to flush
900 text to the screen.
901 ==================
902 */
903 void SCR_UpdateScreen (void)
904 {
905         VID_Finish ();
906
907         R_TimeReport("finish");
908
909         if (r_textureunits.integer > gl_textureunits)
910                 Cvar_SetValueQuick(&r_textureunits, gl_textureunits);
911         if (r_textureunits.integer < 1)
912                 Cvar_SetValueQuick(&r_textureunits, 1);
913
914         if (gl_combine.integer && (!gl_combine_extension || r_textureunits.integer < 2))
915                 Cvar_SetValueQuick(&gl_combine, 0);
916
917         // lighting scale
918         overbrightscale = 1.0f / (float) (1 << v_overbrightbits.integer);
919
920         // lightmaps only
921         lightscalebit = v_overbrightbits.integer;
922         if (gl_combine.integer && r_textureunits.integer > 1)
923                 lightscalebit += 2;
924         lightscale = 1.0f / (float) (1 << lightscalebit);
925
926         R_TimeReport("setup");
927
928         R_ClearScreen();
929
930         R_TimeReport("clear");
931
932         if (scr_conlines < vid.conheight && cls.signon == SIGNONS)
933                 R_RenderView();
934
935         // draw 2D stuff
936         R_DrawQueue();
937
938         // tell driver to commit it's partially full geometry queue to the rendering queue
939         // (this doesn't wait for the commands themselves to complete)
940         qglFlush();
941 }
942