]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_backend.c
implemented shownetgraph
[divverent/darkplaces.git] / gl_backend.c
1
2 #include "quakedef.h"
3 #include "cl_collision.h"
4
5 cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1", "use glDrawRangeElements function if available instead of glDrawElements (for performance comparisons or bug testing)"};
6 cvar_t gl_mesh_testarrayelement = {0, "gl_mesh_testarrayelement", "0", "use glBegin(GL_TRIANGLES);glArrayElement();glEnd(); primitives instead of glDrawElements (useful to test for driver bugs with glDrawElements)"};
7 cvar_t gl_mesh_testmanualfeeding = {0, "gl_mesh_testmanualfeeding", "0", "use glBegin(GL_TRIANGLES);glTexCoord2f();glVertex3f();glEnd(); primitives instead of glDrawElements (useful to test for driver bugs with glDrawElements)"};
8 cvar_t gl_paranoid = {0, "gl_paranoid", "0", "enables OpenGL error checking and other tests"};
9 cvar_t gl_printcheckerror = {0, "gl_printcheckerror", "0", "prints all OpenGL error checks, useful to identify location of driver crashes"};
10
11 cvar_t r_render = {0, "r_render", "1", "enables rendering calls (you want this on!)"};
12 cvar_t r_waterwarp = {CVAR_SAVE, "r_waterwarp", "1", "warp view while underwater"};
13 cvar_t gl_polyblend = {CVAR_SAVE, "gl_polyblend", "1", "tints view while underwater, hurt, etc"};
14 cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1", "enables OpenGL dithering (16bit looks bad with this off)"};
15 cvar_t gl_lockarrays = {0, "gl_lockarrays", "0", "enables use of glLockArraysEXT, may cause glitches with some broken drivers, and may be slower than normal"};
16 cvar_t gl_lockarrays_minimumvertices = {0, "gl_lockarrays_minimumvertices", "1", "minimum number of vertices required for use of glLockArraysEXT, setting this too low may reduce performance"};
17 cvar_t gl_vbo = {0, "gl_vbo", "1", "make use of GL_ARB_vertex_buffer_object extension to store static geometry in video memory for faster rendering"};
18
19 int gl_maxdrawrangeelementsvertices;
20 int gl_maxdrawrangeelementsindices;
21
22 #ifdef DEBUGGL
23 int errornumber = 0;
24
25 void GL_PrintError(int errornumber, char *filename, int linenumber)
26 {
27         switch(errornumber)
28         {
29 #ifdef GL_INVALID_ENUM
30         case GL_INVALID_ENUM:
31                 Con_Printf("GL_INVALID_ENUM at %s:%i\n", filename, linenumber);
32                 break;
33 #endif
34 #ifdef GL_INVALID_VALUE
35         case GL_INVALID_VALUE:
36                 Con_Printf("GL_INVALID_VALUE at %s:%i\n", filename, linenumber);
37                 break;
38 #endif
39 #ifdef GL_INVALID_OPERATION
40         case GL_INVALID_OPERATION:
41                 Con_Printf("GL_INVALID_OPERATION at %s:%i\n", filename, linenumber);
42                 break;
43 #endif
44 #ifdef GL_STACK_OVERFLOW
45         case GL_STACK_OVERFLOW:
46                 Con_Printf("GL_STACK_OVERFLOW at %s:%i\n", filename, linenumber);
47                 break;
48 #endif
49 #ifdef GL_STACK_UNDERFLOW
50         case GL_STACK_UNDERFLOW:
51                 Con_Printf("GL_STACK_UNDERFLOW at %s:%i\n", filename, linenumber);
52                 break;
53 #endif
54 #ifdef GL_OUT_OF_MEMORY
55         case GL_OUT_OF_MEMORY:
56                 Con_Printf("GL_OUT_OF_MEMORY at %s:%i\n", filename, linenumber);
57                 break;
58 #endif
59 #ifdef GL_TABLE_TOO_LARGE
60         case GL_TABLE_TOO_LARGE:
61                 Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
62                 break;
63 #endif
64         default:
65                 Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
66                 break;
67         }
68 }
69 #endif
70
71 #define BACKENDACTIVECHECK if (!backendactive) Sys_Error("GL backend function called when backend is not active");
72
73 void SCR_ScreenShot_f (void);
74
75 static matrix4x4_t backend_viewmatrix;
76 static matrix4x4_t backend_modelmatrix;
77 static matrix4x4_t backend_modelviewmatrix;
78 static matrix4x4_t backend_projectmatrix;
79
80 static unsigned int backendunits, backendimageunits, backendarrayunits, backendactive;
81
82 /*
83 note: here's strip order for a terrain row:
84 0--1--2--3--4
85 |\ |\ |\ |\ |
86 | \| \| \| \|
87 A--B--C--D--E
88 clockwise
89
90 A0B, 01B, B1C, 12C, C2D, 23D, D3E, 34E
91
92 *elements++ = i + row;
93 *elements++ = i;
94 *elements++ = i + row + 1;
95 *elements++ = i;
96 *elements++ = i + 1;
97 *elements++ = i + row + 1;
98
99
100 for (y = 0;y < rows - 1;y++)
101 {
102         for (x = 0;x < columns - 1;x++)
103         {
104                 i = y * rows + x;
105                 *elements++ = i + columns;
106                 *elements++ = i;
107                 *elements++ = i + columns + 1;
108                 *elements++ = i;
109                 *elements++ = i + 1;
110                 *elements++ = i + columns + 1;
111         }
112 }
113
114 alternative:
115 0--1--2--3--4
116 | /| /|\ | /|
117 |/ |/ | \|/ |
118 A--B--C--D--E
119 counterclockwise
120
121 for (y = 0;y < rows - 1;y++)
122 {
123         for (x = 0;x < columns - 1;x++)
124         {
125                 i = y * rows + x;
126                 *elements++ = i;
127                 *elements++ = i + columns;
128                 *elements++ = i + columns + 1;
129                 *elements++ = i + columns;
130                 *elements++ = i + columns + 1;
131                 *elements++ = i + 1;
132         }
133 }
134 */
135
136 int polygonelements[(POLYGONELEMENTS_MAXPOINTS-2)*3];
137 int quadelements[QUADELEMENTS_MAXQUADS*6];
138
139 void GL_Backend_AllocArrays(void)
140 {
141 }
142
143 void GL_Backend_FreeArrays(void)
144 {
145 }
146
147 static void gl_backend_start(void)
148 {
149         Con_Print("OpenGL Backend starting...\n");
150         CHECKGLERROR
151
152         if (qglDrawRangeElements != NULL)
153         {
154                 CHECKGLERROR
155                 qglGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &gl_maxdrawrangeelementsvertices);
156                 CHECKGLERROR
157                 qglGetIntegerv(GL_MAX_ELEMENTS_INDICES, &gl_maxdrawrangeelementsindices);
158                 CHECKGLERROR
159                 Con_Printf("glDrawRangeElements detected (max vertices %i, max indices %i)\n", gl_maxdrawrangeelementsvertices, gl_maxdrawrangeelementsindices);
160         }
161
162         backendunits = bound(1, gl_textureunits, MAX_TEXTUREUNITS);
163         backendimageunits = backendunits;
164         backendarrayunits = backendunits;
165         if (gl_support_fragment_shader)
166         {
167                 CHECKGLERROR
168                 qglGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, (int *)&backendimageunits);
169                 CHECKGLERROR
170                 qglGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, (int *)&backendarrayunits);
171                 CHECKGLERROR
172                 Con_Printf("GLSL shader support detected: texture units = %i texenv, %i image, %i array\n", backendunits, backendimageunits, backendarrayunits);
173                 backendimageunits = bound(1, backendimageunits, MAX_TEXTUREUNITS);
174                 backendarrayunits = bound(1, backendarrayunits, MAX_TEXTUREUNITS);
175         }
176         else if (backendunits > 1)
177                 Con_Printf("multitexture detected: texture units = %i\n", backendunits);
178         else
179                 Con_Printf("singletexture\n");
180
181         GL_Backend_AllocArrays();
182
183         Con_Printf("OpenGL backend started.\n");
184
185         CHECKGLERROR
186
187         backendactive = true;
188 }
189
190 static void gl_backend_shutdown(void)
191 {
192         backendunits = 0;
193         backendimageunits = 0;
194         backendarrayunits = 0;
195         backendactive = false;
196
197         Con_Print("OpenGL Backend shutting down\n");
198
199         GL_Backend_FreeArrays();
200 }
201
202 static void gl_backend_newmap(void)
203 {
204 }
205
206 void gl_backend_init(void)
207 {
208         int i;
209
210         for (i = 0;i < POLYGONELEMENTS_MAXPOINTS - 2;i++)
211         {
212                 polygonelements[i * 3 + 0] = 0;
213                 polygonelements[i * 3 + 1] = i + 1;
214                 polygonelements[i * 3 + 2] = i + 2;
215         }
216         // elements for rendering a series of quads as triangles
217         for (i = 0;i < QUADELEMENTS_MAXQUADS;i++)
218         {
219                 quadelements[i * 6 + 0] = i * 4;
220                 quadelements[i * 6 + 1] = i * 4 + 1;
221                 quadelements[i * 6 + 2] = i * 4 + 2;
222                 quadelements[i * 6 + 3] = i * 4;
223                 quadelements[i * 6 + 4] = i * 4 + 2;
224                 quadelements[i * 6 + 5] = i * 4 + 3;
225         }
226
227         Cvar_RegisterVariable(&r_render);
228         Cvar_RegisterVariable(&r_waterwarp);
229         Cvar_RegisterVariable(&gl_polyblend);
230         Cvar_RegisterVariable(&gl_dither);
231         Cvar_RegisterVariable(&gl_lockarrays);
232         Cvar_RegisterVariable(&gl_lockarrays_minimumvertices);
233         Cvar_RegisterVariable(&gl_vbo);
234         Cvar_RegisterVariable(&gl_paranoid);
235         Cvar_RegisterVariable(&gl_printcheckerror);
236 #ifdef NORENDER
237         Cvar_SetValue("r_render", 0);
238 #endif
239
240         Cvar_RegisterVariable(&gl_mesh_drawrangeelements);
241         Cvar_RegisterVariable(&gl_mesh_testarrayelement);
242         Cvar_RegisterVariable(&gl_mesh_testmanualfeeding);
243
244         R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap);
245 }
246
247 void GL_SetupView_Orientation_Identity (void)
248 {
249         backend_viewmatrix = identitymatrix;
250         memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
251 }
252
253 void GL_SetupView_Orientation_FromEntity(const matrix4x4_t *matrix)
254 {
255         matrix4x4_t tempmatrix, basematrix;
256         Matrix4x4_Invert_Simple(&tempmatrix, matrix);
257         Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
258         Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
259         Matrix4x4_Concat(&backend_viewmatrix, &basematrix, &tempmatrix);
260         //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[2], 1, 0, 0);
261         //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[0], 0, 1, 0);
262         //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[1], 0, 0, 1);
263         //Matrix4x4_ConcatTranslate(&backend_viewmatrix, -origin[0], -origin[1], -origin[2]);
264         memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
265 }
266
267 void GL_SetupView_Mode_Perspective (double frustumx, double frustumy, double zNear, double zFar)
268 {
269         double m[16];
270
271         // set up viewpoint
272         CHECKGLERROR
273         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
274         qglLoadIdentity();CHECKGLERROR
275         // set view pyramid
276         qglFrustum(-frustumx * zNear, frustumx * zNear, -frustumy * zNear, frustumy * zNear, zNear, zFar);CHECKGLERROR
277         qglGetDoublev(GL_PROJECTION_MATRIX, m);CHECKGLERROR
278         Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
279         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
280         GL_SetupView_Orientation_Identity();
281         CHECKGLERROR
282 }
283
284 void GL_SetupView_Mode_PerspectiveInfiniteFarClip (double frustumx, double frustumy, double zNear)
285 {
286         double nudge, m[16];
287
288         // set up viewpoint
289         CHECKGLERROR
290         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
291         qglLoadIdentity();CHECKGLERROR
292         // set view pyramid
293         nudge = 1.0 - 1.0 / (1<<23);
294         m[ 0] = 1.0 / frustumx;
295         m[ 1] = 0;
296         m[ 2] = 0;
297         m[ 3] = 0;
298         m[ 4] = 0;
299         m[ 5] = 1.0 / frustumy;
300         m[ 6] = 0;
301         m[ 7] = 0;
302         m[ 8] = 0;
303         m[ 9] = 0;
304         m[10] = -nudge;
305         m[11] = -1;
306         m[12] = 0;
307         m[13] = 0;
308         m[14] = -2 * zNear * nudge;
309         m[15] = 0;
310         qglLoadMatrixd(m);CHECKGLERROR
311         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
312         GL_SetupView_Orientation_Identity();
313         CHECKGLERROR
314         Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
315 }
316
317 void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double zNear, double zFar)
318 {
319         double m[16];
320
321         // set up viewpoint
322         CHECKGLERROR
323         qglMatrixMode(GL_PROJECTION);CHECKGLERROR
324         qglLoadIdentity();CHECKGLERROR
325         qglOrtho(x1, x2, y2, y1, zNear, zFar);CHECKGLERROR
326         qglGetDoublev(GL_PROJECTION_MATRIX, m);CHECKGLERROR
327         Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
328         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
329         GL_SetupView_Orientation_Identity();
330         CHECKGLERROR
331 }
332
333 typedef struct gltextureunit_s
334 {
335         const void *pointer_texcoord;
336         size_t pointer_texcoord_offset;
337         int pointer_texcoord_buffer;
338         int t1d, t2d, t3d, tcubemap;
339         int arrayenabled;
340         unsigned int arraycomponents;
341         int rgbscale, alphascale;
342         int combinergb, combinealpha;
343         // FIXME: add more combine stuff
344         // texmatrixenabled exists only to avoid unnecessary texmatrix compares
345         int texmatrixenabled;
346         matrix4x4_t matrix;
347 }
348 gltextureunit_t;
349
350 static struct gl_state_s
351 {
352         int cullface;
353         int cullfaceenable;
354         int blendfunc1;
355         int blendfunc2;
356         int blend;
357         GLboolean depthmask;
358         int colormask; // stored as bottom 4 bits: r g b a (3 2 1 0 order)
359         int depthtest;
360         float depthrange[2];
361         int alphatest;
362         int scissortest;
363         unsigned int unit;
364         unsigned int clientunit;
365         gltextureunit_t units[MAX_TEXTUREUNITS];
366         float color4f[4];
367         int lockrange_first;
368         int lockrange_count;
369         int vertexbufferobject;
370         int elementbufferobject;
371         qboolean pointer_color_enabled;
372         const void *pointer_vertex;
373         const void *pointer_color;
374         size_t pointer_vertex_offset;
375         size_t pointer_color_offset;
376         int pointer_vertex_buffer;
377         int pointer_color_buffer;
378 }
379 gl_state;
380
381 static void GL_BindVBO(int bufferobject)
382 {
383         if (gl_state.vertexbufferobject != bufferobject)
384         {
385                 gl_state.vertexbufferobject = bufferobject;
386                 CHECKGLERROR
387                 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, bufferobject);
388                 CHECKGLERROR
389         }
390 }
391
392 static void GL_BindEBO(int bufferobject)
393 {
394         if (gl_state.elementbufferobject != bufferobject)
395         {
396                 gl_state.elementbufferobject = bufferobject;
397                 CHECKGLERROR
398                 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, bufferobject);
399                 CHECKGLERROR
400         }
401 }
402
403 void GL_SetupTextureState(void)
404 {
405         unsigned int i;
406         gltextureunit_t *unit;
407         CHECKGLERROR
408         gl_state.unit = MAX_TEXTUREUNITS;
409         gl_state.clientunit = MAX_TEXTUREUNITS;
410         for (i = 0;i < MAX_TEXTUREUNITS;i++)
411         {
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->arraycomponents = 0;
419                 unit->pointer_texcoord = NULL;
420                 unit->pointer_texcoord_buffer = 0;
421                 unit->pointer_texcoord_offset = 0;
422                 unit->rgbscale = 1;
423                 unit->alphascale = 1;
424                 unit->combinergb = GL_MODULATE;
425                 unit->combinealpha = GL_MODULATE;
426                 unit->texmatrixenabled = false;
427                 unit->matrix = identitymatrix;
428         }
429
430         for (i = 0;i < backendimageunits;i++)
431         {
432                 GL_ActiveTexture(i);
433                 qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
434                 qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
435                 if (gl_texture3d)
436                 {
437                         qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
438                 }
439                 if (gl_texturecubemap)
440                 {
441                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
442                 }
443         }
444
445         for (i = 0;i < backendarrayunits;i++)
446         {
447                 GL_ClientActiveTexture(i);
448                 GL_BindVBO(0);
449                 qglTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), NULL);CHECKGLERROR
450                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
451         }
452
453         for (i = 0;i < backendunits;i++)
454         {
455                 GL_ActiveTexture(i);
456                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
457                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
458                 if (gl_texture3d)
459                 {
460                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
461                 }
462                 if (gl_texturecubemap)
463                 {
464                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
465                 }
466                 qglMatrixMode(GL_TEXTURE);CHECKGLERROR
467                 qglLoadIdentity();CHECKGLERROR
468                 qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
469                 if (gl_combine.integer)
470                 {
471                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);CHECKGLERROR
472                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);CHECKGLERROR
473                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);CHECKGLERROR
474                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
475                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);CHECKGLERROR // for GL_INTERPOLATE_ARB mode
476                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
477                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);CHECKGLERROR
478                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);CHECKGLERROR
479                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);CHECKGLERROR
480                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);CHECKGLERROR
481                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);CHECKGLERROR
482                         qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, GL_CONSTANT_ARB);CHECKGLERROR
483                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
484                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
485                         qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA);CHECKGLERROR
486                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
487                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
488                 }
489                 else
490                 {
491                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
492                 }
493                 CHECKGLERROR
494         }
495         CHECKGLERROR
496 }
497
498 void GL_Backend_ResetState(void)
499 {
500         memset(&gl_state, 0, sizeof(gl_state));
501         gl_state.depthtest = true;
502         gl_state.alphatest = false;
503         gl_state.blendfunc1 = GL_ONE;
504         gl_state.blendfunc2 = GL_ZERO;
505         gl_state.blend = false;
506         gl_state.depthmask = GL_TRUE;
507         gl_state.colormask = 15;
508         gl_state.color4f[0] = gl_state.color4f[1] = gl_state.color4f[2] = gl_state.color4f[3] = 1;
509         gl_state.lockrange_first = 0;
510         gl_state.lockrange_count = 0;
511         gl_state.cullface = GL_FRONT; // quake is backwards, this culls back faces
512         gl_state.cullfaceenable = true;
513
514         CHECKGLERROR
515
516         qglColorMask(1, 1, 1, 1);
517         qglAlphaFunc(GL_GEQUAL, 0.5);CHECKGLERROR
518         qglDisable(GL_ALPHA_TEST);CHECKGLERROR
519         qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
520         qglDisable(GL_BLEND);CHECKGLERROR
521         qglCullFace(gl_state.cullface);CHECKGLERROR
522         qglEnable(GL_CULL_FACE);CHECKGLERROR
523         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
524         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
525         qglDepthMask(gl_state.depthmask);CHECKGLERROR
526
527         if (gl_support_arb_vertex_buffer_object)
528         {
529                 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
530                 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
531         }
532
533         qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), NULL);CHECKGLERROR
534         qglEnableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
535
536         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL);CHECKGLERROR
537         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
538
539         GL_Color(0, 0, 0, 0);
540         GL_Color(1, 1, 1, 1);
541
542         GL_SetupTextureState();
543 }
544
545 void GL_ActiveTexture(unsigned int num)
546 {
547         if (gl_state.unit != num)
548         {
549                 gl_state.unit = num;
550                 if (qglActiveTexture)
551                 {
552                         CHECKGLERROR
553                         qglActiveTexture(GL_TEXTURE0_ARB + gl_state.unit);
554                         CHECKGLERROR
555                 }
556         }
557 }
558
559 void GL_ClientActiveTexture(unsigned int num)
560 {
561         if (gl_state.clientunit != num)
562         {
563                 gl_state.clientunit = num;
564                 if (qglActiveTexture)
565                 {
566                         CHECKGLERROR
567                         qglClientActiveTexture(GL_TEXTURE0_ARB + gl_state.clientunit);
568                         CHECKGLERROR
569                 }
570         }
571 }
572
573 void GL_BlendFunc(int blendfunc1, int blendfunc2)
574 {
575         if (gl_state.blendfunc1 != blendfunc1 || gl_state.blendfunc2 != blendfunc2)
576         {
577                 CHECKGLERROR
578                 qglBlendFunc(gl_state.blendfunc1 = blendfunc1, gl_state.blendfunc2 = blendfunc2);CHECKGLERROR
579                 if (gl_state.blendfunc2 == GL_ZERO)
580                 {
581                         if (gl_state.blendfunc1 == GL_ONE)
582                         {
583                                 if (gl_state.blend)
584                                 {
585                                         gl_state.blend = 0;
586                                         qglDisable(GL_BLEND);CHECKGLERROR
587                                 }
588                         }
589                         else
590                         {
591                                 if (!gl_state.blend)
592                                 {
593                                         gl_state.blend = 1;
594                                         qglEnable(GL_BLEND);CHECKGLERROR
595                                 }
596                         }
597                 }
598                 else
599                 {
600                         if (!gl_state.blend)
601                         {
602                                 gl_state.blend = 1;
603                                 qglEnable(GL_BLEND);CHECKGLERROR
604                         }
605                 }
606         }
607 }
608
609 void GL_DepthMask(int state)
610 {
611         if (gl_state.depthmask != state)
612         {
613                 CHECKGLERROR
614                 qglDepthMask(gl_state.depthmask = state);CHECKGLERROR
615         }
616 }
617
618 void GL_DepthTest(int state)
619 {
620         if (gl_state.depthtest != state)
621         {
622                 gl_state.depthtest = state;
623                 CHECKGLERROR
624                 if (gl_state.depthtest)
625                 {
626                         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
627                 }
628                 else
629                 {
630                         qglDisable(GL_DEPTH_TEST);CHECKGLERROR
631                 }
632         }
633 }
634
635 void GL_DepthRange(float nearfrac, float farfrac)
636 {
637         if (gl_state.depthrange[0] != nearfrac || gl_state.depthrange[1] != farfrac)
638         {
639                 gl_state.depthrange[0] = nearfrac;
640                 gl_state.depthrange[1] = farfrac;
641                 qglDepthRange(nearfrac, farfrac);
642         }
643 }
644
645 void GL_CullFace(int state)
646 {
647         CHECKGLERROR
648         if (state != GL_NONE)
649         {
650                 if (!gl_state.cullfaceenable)
651                 {
652                         gl_state.cullfaceenable = true;
653                         qglEnable(GL_CULL_FACE);CHECKGLERROR
654                 }
655                 if (gl_state.cullface != state)
656                 {
657                         gl_state.cullface = state;
658                         qglCullFace(gl_state.cullface);CHECKGLERROR
659                 }
660         }
661         else
662         {
663                 if (gl_state.cullfaceenable)
664                 {
665                         gl_state.cullfaceenable = false;
666                         qglDisable(GL_CULL_FACE);CHECKGLERROR
667                 }
668         }
669 }
670
671 void GL_AlphaTest(int state)
672 {
673         if (gl_state.alphatest != state)
674         {
675                 gl_state.alphatest = state;
676                 CHECKGLERROR
677                 if (gl_state.alphatest)
678                 {
679                         qglEnable(GL_ALPHA_TEST);CHECKGLERROR
680                 }
681                 else
682                 {
683                         qglDisable(GL_ALPHA_TEST);CHECKGLERROR
684                 }
685         }
686 }
687
688 void GL_ColorMask(int r, int g, int b, int a)
689 {
690         int state = r*8 + g*4 + b*2 + a*1;
691         if (gl_state.colormask != state)
692         {
693                 gl_state.colormask = state;
694                 CHECKGLERROR
695                 qglColorMask((GLboolean)r, (GLboolean)g, (GLboolean)b, (GLboolean)a);CHECKGLERROR
696         }
697 }
698
699 void GL_Color(float cr, float cg, float cb, float ca)
700 {
701         if (gl_state.pointer_color_enabled || gl_state.color4f[0] != cr || gl_state.color4f[1] != cg || gl_state.color4f[2] != cb || gl_state.color4f[3] != ca)
702         {
703                 gl_state.color4f[0] = cr;
704                 gl_state.color4f[1] = cg;
705                 gl_state.color4f[2] = cb;
706                 gl_state.color4f[3] = ca;
707                 CHECKGLERROR
708                 qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);
709                 CHECKGLERROR
710         }
711 }
712
713 void GL_LockArrays(int first, int count)
714 {
715         if (count < gl_lockarrays_minimumvertices.integer)
716         {
717                 first = 0;
718                 count = 0;
719         }
720         if (gl_state.lockrange_count != count || gl_state.lockrange_first != first)
721         {
722                 if (gl_state.lockrange_count)
723                 {
724                         gl_state.lockrange_count = 0;
725                         CHECKGLERROR
726                         qglUnlockArraysEXT();
727                         CHECKGLERROR
728                 }
729                 if (count && gl_supportslockarrays && gl_lockarrays.integer && r_render.integer)
730                 {
731                         gl_state.lockrange_first = first;
732                         gl_state.lockrange_count = count;
733                         CHECKGLERROR
734                         qglLockArraysEXT(first, count);
735                         CHECKGLERROR
736                 }
737         }
738 }
739
740 void GL_Scissor (int x, int y, int width, int height)
741 {
742         CHECKGLERROR
743         qglScissor(x, vid.height - (y + height),width,height);
744         CHECKGLERROR
745 }
746
747 void GL_ScissorTest(int state)
748 {
749         if(gl_state.scissortest == state)
750                 return;
751
752         CHECKGLERROR
753         if((gl_state.scissortest = state))
754                 qglEnable(GL_SCISSOR_TEST);
755         else
756                 qglDisable(GL_SCISSOR_TEST);
757         CHECKGLERROR
758 }
759
760 void GL_Clear(int mask)
761 {
762         CHECKGLERROR
763         qglClear(mask);CHECKGLERROR
764 }
765
766 void GL_TransformToScreen(const vec4_t in, vec4_t out)
767 {
768         vec4_t temp;
769         float iw;
770         Matrix4x4_Transform4 (&backend_viewmatrix, in, temp);
771         Matrix4x4_Transform4 (&backend_projectmatrix, temp, out);
772         iw = 1.0f / out[3];
773         out[0] = r_view.x + (out[0] * iw + 1.0f) * r_view.width * 0.5f;
774         out[1] = r_view.y + r_view.height - (out[1] * iw + 1.0f) * r_view.height * 0.5f;
775         out[2] = r_view.z + (out[2] * iw + 1.0f) * r_view.depth * 0.5f;
776 }
777
778 // called at beginning of frame
779 void R_Mesh_Start(void)
780 {
781         BACKENDACTIVECHECK
782         CHECKGLERROR
783         if (gl_printcheckerror.integer && !gl_paranoid.integer)
784         {
785                 Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
786                 Cvar_SetValueQuick(&gl_paranoid, 1);
787         }
788         GL_Backend_ResetState();
789 }
790
791 qboolean GL_Backend_CompileShader(int programobject, GLenum shadertypeenum, const char *shadertype, int numstrings, const char **strings)
792 {
793         int shaderobject;
794         int shadercompiled;
795         char compilelog[MAX_INPUTLINE];
796         shaderobject = qglCreateShaderObjectARB(shadertypeenum);CHECKGLERROR
797         if (!shaderobject)
798                 return false;
799         qglShaderSourceARB(shaderobject, numstrings, strings, NULL);CHECKGLERROR
800         qglCompileShaderARB(shaderobject);CHECKGLERROR
801         qglGetObjectParameterivARB(shaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &shadercompiled);CHECKGLERROR
802         qglGetInfoLogARB(shaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
803         if (compilelog[0])
804                 Con_DPrintf("%s shader compile log:\n%s\n", shadertype, compilelog);
805         if (!shadercompiled)
806         {
807                 qglDeleteObjectARB(shaderobject);CHECKGLERROR
808                 return false;
809         }
810         qglAttachObjectARB(programobject, shaderobject);CHECKGLERROR
811         qglDeleteObjectARB(shaderobject);CHECKGLERROR
812         return true;
813 }
814
815 unsigned int GL_Backend_CompileProgram(int vertexstrings_count, const char **vertexstrings_list, int geometrystrings_count, const char **geometrystrings_list, int fragmentstrings_count, const char **fragmentstrings_list)
816 {
817         GLint programlinked;
818         GLuint programobject = 0;
819         char linklog[MAX_INPUTLINE];
820         CHECKGLERROR
821
822         programobject = qglCreateProgramObjectARB();CHECKGLERROR
823         if (!programobject)
824                 return 0;
825
826         if (vertexstrings_count && !GL_Backend_CompileShader(programobject, GL_VERTEX_SHADER_ARB, "vertex", vertexstrings_count, vertexstrings_list))
827                 goto cleanup;
828
829 #ifdef GL_GEOMETRY_SHADER_ARB
830         if (geometrystrings_count && !GL_Backend_CompileShader(programobject, GL_GEOMETRY_SHADER_ARB, "geometry", geometrystrings_count, geometrystrings_list))
831                 goto cleanup;
832 #endif
833
834         if (fragmentstrings_count && !GL_Backend_CompileShader(programobject, GL_FRAGMENT_SHADER_ARB, "fragment", fragmentstrings_count, fragmentstrings_list))
835                 goto cleanup;
836
837         qglLinkProgramARB(programobject);CHECKGLERROR
838         qglGetObjectParameterivARB(programobject, GL_OBJECT_LINK_STATUS_ARB, &programlinked);CHECKGLERROR
839         qglGetInfoLogARB(programobject, sizeof(linklog), NULL, linklog);CHECKGLERROR
840         if (linklog[0])
841         {
842                 Con_DPrintf("program link log:\n%s\n", linklog);
843                 // software vertex shader is ok but software fragment shader is WAY
844                 // too slow, fail program if so.
845                 // NOTE: this string might be ATI specific, but that's ok because the
846                 // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
847                 // software fragment shader due to low instruction and dependent
848                 // texture limits.
849                 if (strstr(linklog, "fragment shader will run in software"))
850                         programlinked = false;
851         }
852         if (!programlinked)
853                 goto cleanup;
854         return programobject;
855 cleanup:
856         qglDeleteObjectARB(programobject);CHECKGLERROR
857         return 0;
858 }
859
860 void GL_Backend_FreeProgram(unsigned int prog)
861 {
862         CHECKGLERROR
863         qglDeleteObjectARB(prog);
864         CHECKGLERROR
865 }
866
867 int gl_backend_rebindtextures;
868
869 void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
870 {
871         int i;
872         if (offset)
873         {
874                 for (i = 0;i < count;i++)
875                         *out++ = *in++ + offset;
876         }
877         else
878                 memcpy(out, in, sizeof(*out) * count);
879 }
880
881 // renders triangles using vertices from the active arrays
882 int paranoidblah = 0;
883 void R_Mesh_Draw(int firstvertex, int numvertices, int numtriangles, const int *elements, int bufferobject, size_t bufferoffset)
884 {
885         unsigned int numelements = numtriangles * 3;
886         if (numvertices < 3 || numtriangles < 1)
887         {
888                 Con_Printf("R_Mesh_Draw(%d, %d, %d, %8p, %i, %p);\n", firstvertex, numvertices, numtriangles, elements, bufferobject, (void *)bufferoffset);
889                 return;
890         }
891         if (!gl_vbo.integer)
892                 bufferobject = 0;
893         CHECKGLERROR
894         r_refdef.stats.meshes++;
895         r_refdef.stats.meshes_elements += numelements;
896         if (gl_paranoid.integer)
897         {
898                 unsigned int i, j, size;
899                 const int *p;
900                 // note: there's no validation done here on buffer objects because it
901                 // is somewhat difficult to get at the data, and gl_paranoid can be
902                 // used without buffer objects if the need arises
903                 // (the data could be gotten using glMapBuffer but it would be very
904                 //  slow due to uncachable video memory reads)
905                 if (!qglIsEnabled(GL_VERTEX_ARRAY))
906                         Con_Print("R_Mesh_Draw: vertex array not enabled\n");
907                 CHECKGLERROR
908                 if (gl_state.pointer_vertex)
909                         for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++)
910                                 paranoidblah += *p;
911                 if (gl_state.pointer_color_enabled)
912                 {
913                         if (!qglIsEnabled(GL_COLOR_ARRAY))
914                                 Con_Print("R_Mesh_Draw: color array set but not enabled\n");
915                         CHECKGLERROR
916                         if (gl_state.pointer_color && gl_state.pointer_color_enabled)
917                                 for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
918                                         paranoidblah += *p;
919                 }
920                 for (i = 0;i < backendarrayunits;i++)
921                 {
922                         if (gl_state.units[i].arrayenabled)
923                         {
924                                 GL_ClientActiveTexture(i);
925                                 if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
926                                         Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
927                                 CHECKGLERROR
928                                 if (gl_state.units[i].pointer_texcoord && gl_state.units[i].arrayenabled)
929                                         for (j = 0, size = numvertices * gl_state.units[i].arraycomponents, p = (int *)((float *)gl_state.units[i].pointer_texcoord + firstvertex * gl_state.units[i].arraycomponents);j < size;j++, p++)
930                                                 paranoidblah += *p;
931                         }
932                 }
933                 for (i = 0;i < (unsigned int) numtriangles * 3;i++)
934                 {
935                         if (elements[i] < firstvertex || elements[i] >= firstvertex + numvertices)
936                         {
937                                 Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in elements list\n", elements[i], firstvertex, firstvertex + numvertices);
938                                 return;
939                         }
940                 }
941                 CHECKGLERROR
942         }
943         if (r_render.integer)
944         {
945                 CHECKGLERROR
946                 if (gl_mesh_testmanualfeeding.integer)
947                 {
948                         unsigned int i, j;
949                         const GLfloat *p;
950                         qglBegin(GL_TRIANGLES);
951                         for (i = 0;i < (unsigned int) numtriangles * 3;i++)
952                         {
953                                 for (j = 0;j < backendarrayunits;j++)
954                                 {
955                                         if (gl_state.units[j].pointer_texcoord && gl_state.units[j].arrayenabled)
956                                         {
957                                                 if (backendarrayunits > 1)
958                                                 {
959                                                         if (gl_state.units[j].arraycomponents == 4)
960                                                         {
961                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 4;
962                                                                 qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]);
963                                                         }
964                                                         else if (gl_state.units[j].arraycomponents == 3)
965                                                         {
966                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
967                                                                 qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]);
968                                                         }
969                                                         else if (gl_state.units[j].arraycomponents == 2)
970                                                         {
971                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
972                                                                 qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
973                                                         }
974                                                         else
975                                                         {
976                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 1;
977                                                                 qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
978                                                         }
979                                                 }
980                                                 else
981                                                 {
982                                                         if (gl_state.units[j].arraycomponents == 4)
983                                                         {
984                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 4;
985                                                                 qglTexCoord4f(p[0], p[1], p[2], p[3]);
986                                                         }
987                                                         else if (gl_state.units[j].arraycomponents == 3)
988                                                         {
989                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 3;
990                                                                 qglTexCoord3f(p[0], p[1], p[2]);
991                                                         }
992                                                         else if (gl_state.units[j].arraycomponents == 2)
993                                                         {
994                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 2;
995                                                                 qglTexCoord2f(p[0], p[1]);
996                                                         }
997                                                         else
998                                                         {
999                                                                 p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 1;
1000                                                                 qglTexCoord1f(p[0]);
1001                                                         }
1002                                                 }
1003                                         }
1004                                 }
1005                                 if (gl_state.pointer_color && gl_state.pointer_color_enabled)
1006                                 {
1007                                         p = ((const GLfloat *)(gl_state.pointer_color)) + elements[i] * 4;
1008                                         qglColor4f(p[0], p[1], p[2], p[3]);
1009                                 }
1010                                 p = ((const GLfloat *)(gl_state.pointer_vertex)) + elements[i] * 3;
1011                                 qglVertex3f(p[0], p[1], p[2]);
1012                         }
1013                         qglEnd();
1014                         CHECKGLERROR
1015                 }
1016                 else if (gl_mesh_testarrayelement.integer)
1017                 {
1018                         int i;
1019                         qglBegin(GL_TRIANGLES);
1020                         for (i = 0;i < numtriangles * 3;i++)
1021                         {
1022                                 qglArrayElement(elements[i]);
1023                         }
1024                         qglEnd();
1025                         CHECKGLERROR
1026                 }
1027                 else if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
1028                 {
1029                         GL_BindEBO(bufferobject);
1030                         qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices, numelements, GL_UNSIGNED_INT, bufferobject ? (void *)bufferoffset : elements);
1031                         CHECKGLERROR
1032                 }
1033                 else
1034                 {
1035                         GL_BindEBO(bufferobject);
1036                         qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, bufferobject ? (void *)bufferoffset : elements);
1037                         CHECKGLERROR
1038                 }
1039         }
1040 }
1041
1042 // restores backend state, used when done with 3D rendering
1043 void R_Mesh_Finish(void)
1044 {
1045         unsigned int i;
1046         BACKENDACTIVECHECK
1047         CHECKGLERROR
1048         GL_LockArrays(0, 0);
1049         CHECKGLERROR
1050
1051         for (i = 0;i < backendimageunits;i++)
1052         {
1053                 GL_ActiveTexture(i);
1054                 qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
1055                 qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
1056                 if (gl_texture3d)
1057                 {
1058                         qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
1059                 }
1060                 if (gl_texturecubemap)
1061                 {
1062                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
1063                 }
1064         }
1065         for (i = 0;i < backendarrayunits;i++)
1066         {
1067                 GL_ActiveTexture(backendarrayunits - 1 - i);
1068                 qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1069         }
1070         for (i = 0;i < backendunits;i++)
1071         {
1072                 GL_ActiveTexture(backendunits - 1 - i);
1073                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1074                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1075                 if (gl_texture3d)
1076                 {
1077                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1078                 }
1079                 if (gl_texturecubemap)
1080                 {
1081                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1082                 }
1083                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
1084                 if (gl_combine.integer)
1085                 {
1086                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
1087                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
1088                 }
1089         }
1090         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1091         qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR
1092
1093         qglDisable(GL_BLEND);CHECKGLERROR
1094         qglEnable(GL_DEPTH_TEST);CHECKGLERROR
1095         qglDepthMask(GL_TRUE);CHECKGLERROR
1096         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR
1097 }
1098
1099 int R_Mesh_CreateStaticEBO(void *data, size_t size)
1100 {
1101         GLuint bufferobject;
1102         if (!gl_vbo.integer)
1103                 return 0;
1104         qglGenBuffersARB(1, &bufferobject);
1105         GL_BindEBO(bufferobject);
1106         qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, size, data, GL_STATIC_DRAW_ARB);
1107         return (int)bufferobject;
1108 }
1109
1110 void R_Mesh_DestroyEBO(int bufferobject)
1111 {
1112         qglDeleteBuffersARB(1, (GLuint *)&bufferobject);
1113 }
1114
1115 int R_Mesh_CreateStaticVBO(void *data, size_t size)
1116 {
1117         GLuint bufferobject;
1118         if (!gl_vbo.integer)
1119                 return 0;
1120         qglGenBuffersARB(1, &bufferobject);
1121         GL_BindVBO(bufferobject);
1122         qglBufferDataARB(GL_ARRAY_BUFFER_ARB, size, data, GL_STATIC_DRAW_ARB);
1123         return (int)bufferobject;
1124 }
1125
1126 void R_Mesh_DestroyVBO(int bufferobject)
1127 {
1128         qglDeleteBuffersARB(1, (GLuint *)&bufferobject);
1129 }
1130
1131 void R_Mesh_Matrix(const matrix4x4_t *matrix)
1132 {
1133         if (memcmp(matrix, &backend_modelmatrix, sizeof(matrix4x4_t)))
1134         {
1135                 double glmatrix[16];
1136                 backend_modelmatrix = *matrix;
1137                 Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewmatrix, matrix);
1138                 Matrix4x4_ToArrayDoubleGL(&backend_modelviewmatrix, glmatrix);
1139                 CHECKGLERROR
1140                 qglLoadMatrixd(glmatrix);CHECKGLERROR
1141         }
1142 }
1143
1144 void R_Mesh_VertexPointer(const float *vertex3f, int bufferobject, size_t bufferoffset)
1145 {
1146         if (!gl_vbo.integer)
1147                 bufferobject = 0;
1148         if (gl_state.pointer_vertex != vertex3f || gl_state.pointer_vertex_buffer != bufferobject || gl_state.pointer_vertex_offset != bufferoffset)
1149         {
1150                 gl_state.pointer_vertex = vertex3f;
1151                 gl_state.pointer_vertex_buffer = bufferobject;
1152                 gl_state.pointer_vertex_offset = bufferoffset;
1153                 CHECKGLERROR
1154                 GL_BindVBO(bufferobject);
1155                 qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), bufferobject ? (void *)bufferoffset : vertex3f);CHECKGLERROR
1156         }
1157 }
1158
1159 void R_Mesh_ColorPointer(const float *color4f, int bufferobject, size_t bufferoffset)
1160 {
1161         // note: this can not rely on bufferobject to decide whether a color array
1162         // is supplied, because surfmesh_t shares one vbo for all arrays, which
1163         // means that a valid vbo may be supplied even if there is no color array.
1164         if (color4f)
1165         {
1166                 if (!gl_vbo.integer)
1167                         bufferobject = 0;
1168                 // caller wants color array enabled
1169                 if (!gl_state.pointer_color_enabled)
1170                 {
1171                         gl_state.pointer_color_enabled = true;
1172                         CHECKGLERROR
1173                         qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1174                 }
1175                 if (gl_state.pointer_color != color4f || gl_state.pointer_color_buffer != bufferobject || gl_state.pointer_color_offset != bufferoffset)
1176                 {
1177                         gl_state.pointer_color = color4f;
1178                         gl_state.pointer_color_buffer = bufferobject;
1179                         gl_state.pointer_color_offset = bufferoffset;
1180                         CHECKGLERROR
1181                         GL_BindVBO(bufferobject);
1182                         qglColorPointer(4, GL_FLOAT, sizeof(float[4]), bufferobject ? (void *)bufferoffset : color4f);CHECKGLERROR
1183                 }
1184         }
1185         else
1186         {
1187                 // caller wants color array disabled
1188                 if (gl_state.pointer_color_enabled)
1189                 {
1190                         gl_state.pointer_color_enabled = false;
1191                         CHECKGLERROR
1192                         qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
1193                         // when color array is on the glColor gets trashed, set it again
1194                         qglColor4f(gl_state.color4f[0], gl_state.color4f[1], gl_state.color4f[2], gl_state.color4f[3]);CHECKGLERROR
1195                 }
1196         }
1197 }
1198
1199 void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, const float *texcoord, int bufferobject, size_t bufferoffset)
1200 {
1201         gltextureunit_t *unit = gl_state.units + unitnum;
1202         // update array settings
1203         CHECKGLERROR
1204         // note: there is no need to check bufferobject here because all cases
1205         // that involve a valid bufferobject also supply a texcoord array
1206         if (texcoord)
1207         {
1208                 if (!gl_vbo.integer)
1209                         bufferobject = 0;
1210                 // texture array unit is enabled, enable the array
1211                 if (!unit->arrayenabled)
1212                 {
1213                         unit->arrayenabled = true;
1214                         GL_ClientActiveTexture(unitnum);
1215                         qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1216                 }
1217                 // texcoord array
1218                 if (unit->pointer_texcoord != texcoord || unit->pointer_texcoord_buffer != bufferobject || unit->pointer_texcoord_offset != bufferoffset || unit->arraycomponents != numcomponents)
1219                 {
1220                         unit->pointer_texcoord = texcoord;
1221                         unit->pointer_texcoord_buffer = bufferobject;
1222                         unit->pointer_texcoord_offset = bufferoffset;
1223                         unit->arraycomponents = numcomponents;
1224                         GL_ClientActiveTexture(unitnum);
1225                         GL_BindVBO(bufferobject);
1226                         qglTexCoordPointer(unit->arraycomponents, GL_FLOAT, sizeof(float) * unit->arraycomponents, bufferobject ? (void *)bufferoffset : texcoord);CHECKGLERROR
1227                 }
1228         }
1229         else
1230         {
1231                 // texture array unit is disabled, disable the array
1232                 if (unit->arrayenabled)
1233                 {
1234                         unit->arrayenabled = false;
1235                         GL_ClientActiveTexture(unitnum);
1236                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1237                 }
1238         }
1239 }
1240
1241 void R_Mesh_TexBindAll(unsigned int unitnum, int tex1d, int tex2d, int tex3d, int texcubemap)
1242 {
1243         gltextureunit_t *unit = gl_state.units + unitnum;
1244         if (unitnum >= backendimageunits)
1245                 return;
1246         // update 1d texture binding
1247         if (unit->t1d != tex1d)
1248         {
1249                 GL_ActiveTexture(unitnum);
1250                 if (unitnum < backendunits)
1251                 {
1252                         if (tex1d)
1253                         {
1254                                 if (unit->t1d == 0)
1255                                 {
1256                                         qglEnable(GL_TEXTURE_1D);CHECKGLERROR
1257                                 }
1258                         }
1259                         else
1260                         {
1261                                 if (unit->t1d)
1262                                 {
1263                                         qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1264                                 }
1265                         }
1266                 }
1267                 unit->t1d = tex1d;
1268                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1269         }
1270         // update 2d texture binding
1271         if (unit->t2d != tex2d)
1272         {
1273                 GL_ActiveTexture(unitnum);
1274                 if (unitnum < backendunits)
1275                 {
1276                         if (tex2d)
1277                         {
1278                                 if (unit->t2d == 0)
1279                                 {
1280                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1281                                 }
1282                         }
1283                         else
1284                         {
1285                                 if (unit->t2d)
1286                                 {
1287                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1288                                 }
1289                         }
1290                 }
1291                 unit->t2d = tex2d;
1292                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1293         }
1294         // update 3d texture binding
1295         if (unit->t3d != tex3d)
1296         {
1297                 GL_ActiveTexture(unitnum);
1298                 if (unitnum < backendunits)
1299                 {
1300                         if (tex3d)
1301                         {
1302                                 if (unit->t3d == 0)
1303                                 {
1304                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1305                                 }
1306                         }
1307                         else
1308                         {
1309                                 if (unit->t3d)
1310                                 {
1311                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1312                                 }
1313                         }
1314                 }
1315                 unit->t3d = tex3d;
1316                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1317         }
1318         // update cubemap texture binding
1319         if (unit->tcubemap != texcubemap)
1320         {
1321                 GL_ActiveTexture(unitnum);
1322                 if (unitnum < backendunits)
1323                 {
1324                         if (texcubemap)
1325                         {
1326                                 if (unit->tcubemap == 0)
1327                                 {
1328                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1329                                 }
1330                         }
1331                         else
1332                         {
1333                                 if (unit->tcubemap)
1334                                 {
1335                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1336                                 }
1337                         }
1338                 }
1339                 unit->tcubemap = texcubemap;
1340                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1341         }
1342 }
1343
1344 void R_Mesh_TexBind1D(unsigned int unitnum, int texnum)
1345 {
1346         gltextureunit_t *unit = gl_state.units + unitnum;
1347         if (unitnum >= backendimageunits)
1348                 return;
1349         // update 1d texture binding
1350         if (unit->t1d != texnum)
1351         {
1352                 GL_ActiveTexture(unitnum);
1353                 if (unitnum < backendunits)
1354                 {
1355                         if (texnum)
1356                         {
1357                                 if (unit->t1d == 0)
1358                                 {
1359                                         qglEnable(GL_TEXTURE_1D);CHECKGLERROR
1360                                 }
1361                         }
1362                         else
1363                         {
1364                                 if (unit->t1d)
1365                                 {
1366                                         qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1367                                 }
1368                         }
1369                 }
1370                 unit->t1d = texnum;
1371                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1372         }
1373         // update 2d texture binding
1374         if (unit->t2d)
1375         {
1376                 GL_ActiveTexture(unitnum);
1377                 if (unitnum < backendunits)
1378                 {
1379                         if (unit->t2d)
1380                         {
1381                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1382                         }
1383                 }
1384                 unit->t2d = 0;
1385                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1386         }
1387         // update 3d texture binding
1388         if (unit->t3d)
1389         {
1390                 GL_ActiveTexture(unitnum);
1391                 if (unitnum < backendunits)
1392                 {
1393                         if (unit->t3d)
1394                         {
1395                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1396                         }
1397                 }
1398                 unit->t3d = 0;
1399                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1400         }
1401         // update cubemap texture binding
1402         if (unit->tcubemap)
1403         {
1404                 GL_ActiveTexture(unitnum);
1405                 if (unitnum < backendunits)
1406                 {
1407                         if (unit->tcubemap)
1408                         {
1409                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1410                         }
1411                 }
1412                 unit->tcubemap = 0;
1413                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1414         }
1415 }
1416
1417 void R_Mesh_TexBind(unsigned int unitnum, int texnum)
1418 {
1419         gltextureunit_t *unit = gl_state.units + unitnum;
1420         if (unitnum >= backendimageunits)
1421                 return;
1422         // update 1d texture binding
1423         if (unit->t1d)
1424         {
1425                 GL_ActiveTexture(unitnum);
1426                 if (unitnum < backendunits)
1427                 {
1428                         if (unit->t1d)
1429                         {
1430                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1431                         }
1432                 }
1433                 unit->t1d = 0;
1434                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1435         }
1436         // update 2d texture binding
1437         if (unit->t2d != texnum)
1438         {
1439                 GL_ActiveTexture(unitnum);
1440                 if (unitnum < backendunits)
1441                 {
1442                         if (texnum)
1443                         {
1444                                 if (unit->t2d == 0)
1445                                 {
1446                                         qglEnable(GL_TEXTURE_2D);CHECKGLERROR
1447                                 }
1448                         }
1449                         else
1450                         {
1451                                 if (unit->t2d)
1452                                 {
1453                                         qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1454                                 }
1455                         }
1456                 }
1457                 unit->t2d = texnum;
1458                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1459         }
1460         // update 3d texture binding
1461         if (unit->t3d)
1462         {
1463                 GL_ActiveTexture(unitnum);
1464                 if (unitnum < backendunits)
1465                 {
1466                         if (unit->t3d)
1467                         {
1468                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1469                         }
1470                 }
1471                 unit->t3d = 0;
1472                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1473         }
1474         // update cubemap texture binding
1475         if (unit->tcubemap != 0)
1476         {
1477                 GL_ActiveTexture(unitnum);
1478                 if (unitnum < backendunits)
1479                 {
1480                         if (unit->tcubemap)
1481                         {
1482                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1483                         }
1484                 }
1485                 unit->tcubemap = 0;
1486                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1487         }
1488 }
1489
1490 void R_Mesh_TexBind3D(unsigned int unitnum, int texnum)
1491 {
1492         gltextureunit_t *unit = gl_state.units + unitnum;
1493         if (unitnum >= backendimageunits)
1494                 return;
1495         // update 1d texture binding
1496         if (unit->t1d)
1497         {
1498                 GL_ActiveTexture(unitnum);
1499                 if (unitnum < backendunits)
1500                 {
1501                         if (unit->t1d)
1502                         {
1503                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1504                         }
1505                 }
1506                 unit->t1d = 0;
1507                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1508         }
1509         // update 2d texture binding
1510         if (unit->t2d)
1511         {
1512                 GL_ActiveTexture(unitnum);
1513                 if (unitnum < backendunits)
1514                 {
1515                         if (unit->t2d)
1516                         {
1517                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1518                         }
1519                 }
1520                 unit->t2d = 0;
1521                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1522         }
1523         // update 3d texture binding
1524         if (unit->t3d != texnum)
1525         {
1526                 GL_ActiveTexture(unitnum);
1527                 if (unitnum < backendunits)
1528                 {
1529                         if (texnum)
1530                         {
1531                                 if (unit->t3d == 0)
1532                                 {
1533                                         qglEnable(GL_TEXTURE_3D);CHECKGLERROR
1534                                 }
1535                         }
1536                         else
1537                         {
1538                                 if (unit->t3d)
1539                                 {
1540                                         qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1541                                 }
1542                         }
1543                 }
1544                 unit->t3d = texnum;
1545                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1546         }
1547         // update cubemap texture binding
1548         if (unit->tcubemap != 0)
1549         {
1550                 GL_ActiveTexture(unitnum);
1551                 if (unitnum < backendunits)
1552                 {
1553                         if (unit->tcubemap)
1554                         {
1555                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1556                         }
1557                 }
1558                 unit->tcubemap = 0;
1559                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1560         }
1561 }
1562
1563 void R_Mesh_TexBindCubeMap(unsigned int unitnum, int texnum)
1564 {
1565         gltextureunit_t *unit = gl_state.units + unitnum;
1566         if (unitnum >= backendimageunits)
1567                 return;
1568         // update 1d texture binding
1569         if (unit->t1d)
1570         {
1571                 GL_ActiveTexture(unitnum);
1572                 if (unitnum < backendunits)
1573                 {
1574                         if (unit->t1d)
1575                         {
1576                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1577                         }
1578                 }
1579                 unit->t1d = 0;
1580                 qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1581         }
1582         // update 2d texture binding
1583         if (unit->t2d)
1584         {
1585                 GL_ActiveTexture(unitnum);
1586                 if (unitnum < backendunits)
1587                 {
1588                         if (unit->t2d)
1589                         {
1590                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1591                         }
1592                 }
1593                 unit->t2d = 0;
1594                 qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1595         }
1596         // update 3d texture binding
1597         if (unit->t3d)
1598         {
1599                 GL_ActiveTexture(unitnum);
1600                 if (unitnum < backendunits)
1601                 {
1602                         if (unit->t3d)
1603                         {
1604                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1605                         }
1606                 }
1607                 unit->t3d = 0;
1608                 qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1609         }
1610         // update cubemap texture binding
1611         if (unit->tcubemap != texnum)
1612         {
1613                 GL_ActiveTexture(unitnum);
1614                 if (unitnum < backendunits)
1615                 {
1616                         if (texnum)
1617                         {
1618                                 if (unit->tcubemap == 0)
1619                                 {
1620                                         qglEnable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1621                                 }
1622                         }
1623                         else
1624                         {
1625                                 if (unit->tcubemap)
1626                                 {
1627                                         qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1628                                 }
1629                         }
1630                 }
1631                 unit->tcubemap = texnum;
1632                 qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1633         }
1634 }
1635
1636 void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix)
1637 {
1638         gltextureunit_t *unit = gl_state.units + unitnum;
1639         if (matrix->m[3][3])
1640         {
1641                 // texmatrix specified, check if it is different
1642                 if (!unit->texmatrixenabled || memcmp(&unit->matrix, matrix, sizeof(matrix4x4_t)))
1643                 {
1644                         double glmatrix[16];
1645                         unit->texmatrixenabled = true;
1646                         unit->matrix = *matrix;
1647                         CHECKGLERROR
1648                         Matrix4x4_ToArrayDoubleGL(&unit->matrix, glmatrix);
1649                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1650                         GL_ActiveTexture(unitnum);
1651                         qglLoadMatrixd(glmatrix);CHECKGLERROR
1652                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1653                 }
1654         }
1655         else
1656         {
1657                 // no texmatrix specified, revert to identity
1658                 if (unit->texmatrixenabled)
1659                 {
1660                         unit->texmatrixenabled = false;
1661                         CHECKGLERROR
1662                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1663                         GL_ActiveTexture(unitnum);
1664                         qglLoadIdentity();CHECKGLERROR
1665                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1666                 }
1667         }
1668 }
1669
1670 void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, int rgbscale, int alphascale)
1671 {
1672         gltextureunit_t *unit = gl_state.units + unitnum;
1673         CHECKGLERROR
1674         if (gl_combine.integer)
1675         {
1676                 // GL_ARB_texture_env_combine
1677                 if (!combinergb)
1678                         combinergb = GL_MODULATE;
1679                 if (!combinealpha)
1680                         combinealpha = GL_MODULATE;
1681                 if (!rgbscale)
1682                         rgbscale = 1;
1683                 if (!alphascale)
1684                         alphascale = 1;
1685                 if (unit->combinergb != combinergb)
1686                 {
1687                         unit->combinergb = combinergb;
1688                         GL_ActiveTexture(unitnum);
1689                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
1690                 }
1691                 if (unit->combinealpha != combinealpha)
1692                 {
1693                         unit->combinealpha = combinealpha;
1694                         GL_ActiveTexture(unitnum);
1695                         qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
1696                 }
1697                 if (unit->rgbscale != rgbscale)
1698                 {
1699                         GL_ActiveTexture(unitnum);
1700                         qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = rgbscale));CHECKGLERROR
1701                 }
1702                 if (unit->alphascale != alphascale)
1703                 {
1704                         GL_ActiveTexture(unitnum);
1705                         qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = alphascale));CHECKGLERROR
1706                 }
1707         }
1708         else
1709         {
1710                 // normal GL texenv
1711                 if (!combinergb)
1712                         combinergb = GL_MODULATE;
1713                 if (unit->combinergb != combinergb)
1714                 {
1715                         unit->combinergb = combinergb;
1716                         GL_ActiveTexture(unitnum);
1717                         qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
1718                 }
1719         }
1720 }
1721
1722 void R_Mesh_TextureState(const rmeshstate_t *m)
1723 {
1724         unsigned int i;
1725
1726         BACKENDACTIVECHECK
1727
1728         CHECKGLERROR
1729         if (gl_backend_rebindtextures)
1730         {
1731                 gl_backend_rebindtextures = false;
1732                 GL_SetupTextureState();
1733                 CHECKGLERROR
1734         }
1735
1736         for (i = 0;i < backendimageunits;i++)
1737                 R_Mesh_TexBindAll(i, m->tex1d[i], m->tex[i], m->tex3d[i], m->texcubemap[i]);
1738         for (i = 0;i < backendarrayunits;i++)
1739         {
1740                 if (m->pointer_texcoord3f[i])
1741                         R_Mesh_TexCoordPointer(i, 3, m->pointer_texcoord3f[i], m->pointer_texcoord_bufferobject[i], m->pointer_texcoord_bufferoffset[i]);
1742                 else
1743                         R_Mesh_TexCoordPointer(i, 2, m->pointer_texcoord[i], m->pointer_texcoord_bufferobject[i], m->pointer_texcoord_bufferoffset[i]);
1744         }
1745         for (i = 0;i < backendunits;i++)
1746         {
1747                 R_Mesh_TexMatrix(i, &m->texmatrix[i]);
1748                 R_Mesh_TexCombine(i, m->texcombinergb[i], m->texcombinealpha[i], m->texrgbscale[i], m->texalphascale[i]);
1749         }
1750         CHECKGLERROR
1751 }
1752
1753 void R_Mesh_ResetTextureState(void)
1754 {
1755         unsigned int unitnum;
1756
1757         BACKENDACTIVECHECK
1758
1759         CHECKGLERROR
1760         if (gl_backend_rebindtextures)
1761         {
1762                 gl_backend_rebindtextures = false;
1763                 GL_SetupTextureState();
1764                 CHECKGLERROR
1765         }
1766
1767         for (unitnum = 0;unitnum < backendimageunits;unitnum++)
1768         {
1769                 gltextureunit_t *unit = gl_state.units + unitnum;
1770                 // update 1d texture binding
1771                 if (unit->t1d)
1772                 {
1773                         GL_ActiveTexture(unitnum);
1774                         if (unitnum < backendunits)
1775                         {
1776                                 qglDisable(GL_TEXTURE_1D);CHECKGLERROR
1777                         }
1778                         unit->t1d = 0;
1779                         qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
1780                 }
1781                 // update 2d texture binding
1782                 if (unit->t2d)
1783                 {
1784                         GL_ActiveTexture(unitnum);
1785                         if (unitnum < backendunits)
1786                         {
1787                                 qglDisable(GL_TEXTURE_2D);CHECKGLERROR
1788                         }
1789                         unit->t2d = 0;
1790                         qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
1791                 }
1792                 // update 3d texture binding
1793                 if (unit->t3d)
1794                 {
1795                         GL_ActiveTexture(unitnum);
1796                         if (unitnum < backendunits)
1797                         {
1798                                 qglDisable(GL_TEXTURE_3D);CHECKGLERROR
1799                         }
1800                         unit->t3d = 0;
1801                         qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
1802                 }
1803                 // update cubemap texture binding
1804                 if (unit->tcubemap)
1805                 {
1806                         GL_ActiveTexture(unitnum);
1807                         if (unitnum < backendunits)
1808                         {
1809                                 qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
1810                         }
1811                         unit->tcubemap = 0;
1812                         qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
1813                 }
1814         }
1815         for (unitnum = 0;unitnum < backendarrayunits;unitnum++)
1816         {
1817                 gltextureunit_t *unit = gl_state.units + unitnum;
1818                 // texture array unit is disabled, disable the array
1819                 if (unit->arrayenabled)
1820                 {
1821                         unit->arrayenabled = false;
1822                         GL_ClientActiveTexture(unitnum);
1823                         qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
1824                 }
1825         }
1826         for (unitnum = 0;unitnum < backendunits;unitnum++)
1827         {
1828                 gltextureunit_t *unit = gl_state.units + unitnum;
1829                 // no texmatrix specified, revert to identity
1830                 if (unit->texmatrixenabled)
1831                 {
1832                         unit->texmatrixenabled = false;
1833                         CHECKGLERROR
1834                         qglMatrixMode(GL_TEXTURE);CHECKGLERROR
1835                         GL_ActiveTexture(unitnum);
1836                         qglLoadIdentity();CHECKGLERROR
1837                         qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
1838                 }
1839                 if (gl_combine.integer)
1840                 {
1841                         // GL_ARB_texture_env_combine
1842                         if (unit->combinergb != GL_MODULATE)
1843                         {
1844                                 unit->combinergb = GL_MODULATE;
1845                                 GL_ActiveTexture(unitnum);
1846                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, unit->combinergb);CHECKGLERROR
1847                         }
1848                         if (unit->combinealpha != GL_MODULATE)
1849                         {
1850                                 unit->combinealpha = GL_MODULATE;
1851                                 GL_ActiveTexture(unitnum);
1852                                 qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, unit->combinealpha);CHECKGLERROR
1853                         }
1854                         if (unit->rgbscale != 1)
1855                         {
1856                                 GL_ActiveTexture(unitnum);
1857                                 qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (unit->rgbscale = 1));CHECKGLERROR
1858                         }
1859                         if (unit->alphascale != 1)
1860                         {
1861                                 GL_ActiveTexture(unitnum);
1862                                 qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, (unit->alphascale = 1));CHECKGLERROR
1863                         }
1864                 }
1865                 else
1866                 {
1867                         // normal GL texenv
1868                         if (unit->combinergb != GL_MODULATE)
1869                         {
1870                                 unit->combinergb = GL_MODULATE;
1871                                 GL_ActiveTexture(unitnum);
1872                                 qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->combinergb);CHECKGLERROR
1873                         }
1874                 }
1875         }
1876 }
1877
1878 void R_Mesh_Draw_ShowTris(int firstvertex, int numvertices, int numtriangles, const int *elements)
1879 {
1880         CHECKGLERROR
1881         qglBegin(GL_LINES);
1882         for (;numtriangles;numtriangles--, elements += 3)
1883         {
1884                 qglArrayElement(elements[0]);qglArrayElement(elements[1]);
1885                 qglArrayElement(elements[1]);qglArrayElement(elements[2]);
1886                 qglArrayElement(elements[2]);qglArrayElement(elements[0]);
1887         }
1888         qglEnd();
1889         CHECKGLERROR
1890 }