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