1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 //
21 // rb_state.c
22 // FIXME TODO:
23 // - Statebit pushing, which will require that all state changes are local to the backend
24 //
25
26 #include "rb_local.h"
27
28 rb_glState_t rb_glState;
29
30 /*
31 ==============================================================================
32
33 STATEBIT MANAGEMENT
34
35 ==============================================================================
36 */
37
38 /*
39 ===============
40 RB_StateForBits
41 ===============
42 */
RB_StateForBits(uint32 bits1)43 void RB_StateForBits (uint32 bits1)
44 {
45 uint32 diff;
46
47 // Process bit group one
48 diff = bits1 ^ rb_glState.stateBits1;
49 if (diff) {
50 // Alpha testing
51 if (diff & SB1_ATEST_BITS) {
52 switch (bits1 & SB1_ATEST_BITS) {
53 case 0:
54 qglDisable (GL_ALPHA_TEST);
55 break;
56 case SB1_ATEST_GT0:
57 qglEnable (GL_ALPHA_TEST);
58 qglAlphaFunc (GL_GREATER, 0);
59 break;
60 case SB1_ATEST_LT128:
61 qglEnable (GL_ALPHA_TEST);
62 qglAlphaFunc (GL_LESS, 0.5f);
63 break;
64 case SB1_ATEST_GE128:
65 qglEnable (GL_ALPHA_TEST);
66 qglAlphaFunc (GL_GEQUAL, 0.5f);
67 break;
68 default:
69 assert (0);
70 break;
71 }
72
73 ri.pc.stateChanges++;
74 }
75
76 // Blending
77 if (diff & SB1_BLEND_ON) {
78 if (bits1 & SB1_BLEND_ON)
79 qglEnable (GL_BLEND);
80 else
81 qglDisable (GL_BLEND);
82 ri.pc.stateChanges++;
83 }
84
85 if (diff & (SB1_BLENDSRC_BITS|SB1_BLENDDST_BITS)
86 && bits1 & (SB1_BLENDSRC_BITS|SB1_BLENDDST_BITS)) {
87 GLenum sFactor, dFactor;
88
89 switch (bits1 & SB1_BLENDSRC_BITS) {
90 case SB1_BLENDSRC_ZERO: sFactor = GL_ZERO; break;
91 case SB1_BLENDSRC_ONE: sFactor = GL_ONE; break;
92 case SB1_BLENDSRC_DST_COLOR: sFactor = GL_DST_COLOR; break;
93 case SB1_BLENDSRC_ONE_MINUS_DST_COLOR: sFactor = GL_ONE_MINUS_DST_COLOR; break;
94 case SB1_BLENDSRC_SRC_ALPHA: sFactor = GL_SRC_ALPHA; break;
95 case SB1_BLENDSRC_ONE_MINUS_SRC_ALPHA: sFactor = GL_ONE_MINUS_SRC_ALPHA; break;
96 case SB1_BLENDSRC_DST_ALPHA: sFactor = GL_DST_ALPHA; break;
97 case SB1_BLENDSRC_ONE_MINUS_DST_ALPHA: sFactor = GL_ONE_MINUS_DST_ALPHA; break;
98 case SB1_BLENDSRC_SRC_ALPHA_SATURATE: sFactor = GL_SRC_ALPHA_SATURATE; break;
99 default: assert (0); break;
100 }
101
102 switch (bits1 & SB1_BLENDDST_BITS) {
103 case SB1_BLENDDST_ZERO: dFactor = GL_ZERO; break;
104 case SB1_BLENDDST_ONE: dFactor = GL_ONE; break;
105 case SB1_BLENDDST_SRC_COLOR: dFactor = GL_SRC_COLOR; break;
106 case SB1_BLENDDST_ONE_MINUS_SRC_COLOR: dFactor = GL_ONE_MINUS_SRC_COLOR; break;
107 case SB1_BLENDDST_SRC_ALPHA: dFactor = GL_SRC_ALPHA; break;
108 case SB1_BLENDDST_ONE_MINUS_SRC_ALPHA: dFactor = GL_ONE_MINUS_SRC_ALPHA; break;
109 case SB1_BLENDDST_DST_ALPHA: dFactor = GL_DST_ALPHA; break;
110 case SB1_BLENDDST_ONE_MINUS_DST_ALPHA: dFactor = GL_ONE_MINUS_DST_ALPHA; break;
111 default: assert (0); break;
112 }
113
114 qglBlendFunc (sFactor, dFactor);
115 ri.pc.stateChanges++;
116 }
117
118 // Culling
119 if (diff & SB1_CULL_BITS) {
120 switch (bits1 & SB1_CULL_BITS) {
121 case 0:
122 qglDisable (GL_CULL_FACE);
123 break;
124 case SB1_CULL_FRONT:
125 qglCullFace (GL_FRONT);
126 qglEnable (GL_CULL_FACE);
127 break;
128 case SB1_CULL_BACK:
129 qglCullFace (GL_BACK);
130 qglEnable (GL_CULL_FACE);
131 break;
132 default:
133 assert (0);
134 break;
135 }
136 ri.pc.stateChanges++;
137 }
138
139 // Depth masking
140 if (diff & SB1_DEPTHMASK_ON) {
141 if (bits1 & SB1_DEPTHMASK_ON)
142 qglDepthMask (GL_TRUE);
143 else
144 qglDepthMask (GL_FALSE);
145 ri.pc.stateChanges++;
146 }
147
148 // Depth testing
149 if (diff & SB1_DEPTHTEST_ON) {
150 if (bits1 & SB1_DEPTHTEST_ON)
151 qglEnable (GL_DEPTH_TEST);
152 else
153 qglDisable (GL_DEPTH_TEST);
154 ri.pc.stateChanges++;
155 }
156
157 // Polygon offset
158 if (diff & SB1_POLYOFFSET_ON) {
159 if (bits1 & SB1_POLYOFFSET_ON) {
160 qglEnable (GL_POLYGON_OFFSET_FILL);
161 qglPolygonOffset (r_offsetFactor->intVal, r_offsetUnits->intVal);
162 }
163 else
164 qglDisable (GL_POLYGON_OFFSET_FILL);
165 ri.pc.stateChanges++;
166 }
167
168 // Save for the next diff
169 rb_glState.stateBits1 = bits1;
170 }
171 }
172
173 /*
174 ==============================================================================
175
176 TEXTURE STATE
177
178 ==============================================================================
179 */
180
181 /*
182 ===============
183 RB_BindTexture
184 ===============
185 */
RB_BindTexture(image_t * image)186 void RB_BindTexture (image_t *image)
187 {
188 // Performance evaluation option
189 if (gl_nobind->intVal || !image)
190 image = ri.noTexture;
191
192 // Determine if it's already bound
193 if (rb_glState.texBound[rb_glState.texUnit] == image)
194 return;
195 rb_glState.texBound[rb_glState.texUnit] = image;
196
197 // Nope, bind it
198 qglBindTexture (image->target, image->texNum);
199
200 // Performance counters
201 if (r_speeds->intVal) {
202 ri.pc.textureBinds++;
203 if (image->visFrame != ri.frameCount) {
204 image->visFrame = ri.frameCount;
205 ri.pc.texturesInUse++;
206 ri.pc.texelsInUse += image->upWidth * image->upHeight;
207 }
208 }
209 }
210
211
212 /*
213 ===============
214 RB_SelectTexture
215 ===============
216 */
RB_SelectTexture(texUnit_t texUnit)217 void RB_SelectTexture (texUnit_t texUnit)
218 {
219 if (texUnit == rb_glState.texUnit)
220 return;
221 if (texUnit > ri.config.maxTexUnits) {
222 Com_Error (ERR_DROP, "Attempted selection of an out of bounds (%d) texture unit!", texUnit);
223 return;
224 }
225
226 // Select the unit
227 rb_glState.texUnit = texUnit;
228 if (ri.config.extArbMultitexture) {
229 qglActiveTextureARB (texUnit + GL_TEXTURE0_ARB);
230 qglClientActiveTextureARB (texUnit + GL_TEXTURE0_ARB);
231 }
232 else if (ri.config.extSGISMultiTexture) {
233 qglSelectTextureSGIS (texUnit + GL_TEXTURE0_SGIS);
234 }
235 else {
236 return;
237 }
238
239 // Performance counter
240 ri.pc.textureUnitChanges++;
241 }
242
243
244 /*
245 ===============
246 RB_TextureEnv
247 ===============
248 */
RB_TextureEnv(GLfloat mode)249 void RB_TextureEnv (GLfloat mode)
250 {
251 if (mode == GL_ADD && !ri.config.extTexEnvAdd)
252 mode = GL_MODULATE;
253
254 if (mode != rb_glState.texEnvModes[rb_glState.texUnit]) {
255 qglTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode);
256 rb_glState.texEnvModes[rb_glState.texUnit] = mode;
257
258 // Performance counter
259 ri.pc.textureEnvChanges++;
260 }
261 }
262
263
264 /*
265 ===============
266 RB_TextureTarget
267
268 Supplements qglEnable/qglDisable on GL_TEXTURE_1D/2D/3D/CUBE_MAP_ARB.
269 ===============
270 */
RB_TextureTarget(GLenum target)271 void RB_TextureTarget (GLenum target)
272 {
273 if (target == rb_glState.texTarget[rb_glState.texUnit])
274 return;
275
276 if (rb_glState.texTarget[rb_glState.texUnit])
277 qglDisable (rb_glState.texTarget[rb_glState.texUnit]);
278
279 rb_glState.texTarget[rb_glState.texUnit] = target;
280
281 if (target)
282 qglEnable (target);
283 }
284
285
286 /*
287 ===============
288 RB_LoadTexMatrix
289 ===============
290 */
RB_LoadTexMatrix(mat4x4_t m)291 void RB_LoadTexMatrix (mat4x4_t m)
292 {
293 qglLoadMatrixf (m);
294 rb_glState.texMatIdentity[rb_glState.texUnit] = qFalse;
295 }
296
297
298 /*
299 ===============
300 RB_LoadIdentityTexMatrix
301 ===============
302 */
RB_LoadIdentityTexMatrix(void)303 void RB_LoadIdentityTexMatrix (void)
304 {
305 if (!rb_glState.texMatIdentity[rb_glState.texUnit]) {
306 qglLoadIdentity ();
307 rb_glState.texMatIdentity[rb_glState.texUnit] = qTrue;
308 }
309 }
310
311 /*
312 ==============================================================================
313
314 PROGRAM STATE
315
316 ==============================================================================
317 */
318
319 /*
320 ===============
321 RB_BindProgram
322 ===============
323 */
RB_BindProgram(program_t * program)324 void RB_BindProgram (program_t *program)
325 {
326 switch (program->target) {
327 case GL_FRAGMENT_PROGRAM_ARB:
328 if (rb_glState.boundFragProgram == program->progNum)
329 return;
330 rb_glState.boundFragProgram = program->progNum;
331
332 qglBindProgramARB (GL_FRAGMENT_PROGRAM_ARB, program->progNum);
333 break;
334
335 case GL_VERTEX_PROGRAM_ARB:
336 if (rb_glState.boundVertProgram == program->progNum)
337 return;
338 rb_glState.boundVertProgram = program->progNum;
339
340 qglBindProgramARB (GL_VERTEX_PROGRAM_ARB, program->progNum);
341 break;
342
343 #ifdef _DEBUG
344 default:
345 assert (0);
346 break;
347 #endif // _DEBUG
348 }
349 }
350
351 /*
352 ==============================================================================
353
354 GENERIC STATE MANAGEMENT
355
356 ==============================================================================
357 */
358
359 /*
360 ==================
361 RB_SetupGL2D
362 ==================
363 */
RB_SetupGL2D(void)364 void RB_SetupGL2D (void)
365 {
366 // State
367 rb_glState.in2D = qTrue;
368 rb_glState.stateBits1 &= ~SB1_DEPTHMASK_ON;
369 qglDepthMask (GL_FALSE);
370
371 // Set 2D virtual screen size
372 qglViewport (0, 0, ri.config.vidWidth, ri.config.vidHeight);
373 qglScissor (0, 0, ri.config.vidWidth, ri.config.vidHeight);
374
375 qglMatrixMode (GL_PROJECTION);
376 qglLoadIdentity ();
377 qglOrtho (0, ri.config.vidWidth, ri.config.vidHeight, 0, -99999, 99999);
378
379 qglMatrixMode (GL_MODELVIEW);
380 qglLoadIdentity ();
381 }
382
383
384 /*
385 =============
386 RB_SetupGL3D
387 =============
388 */
RB_SetupGL3D(void)389 void RB_SetupGL3D (void)
390 {
391 // State
392 rb_glState.in2D = qFalse;
393 rb_glState.stateBits1 |= SB1_DEPTHMASK_ON;
394 qglDepthMask (GL_TRUE);
395
396 // Set up viewport
397 if (!ri.scn.mirrorView && !ri.scn.portalView) {
398 qglScissor (ri.def.x, ri.config.vidHeight - ri.def.height - ri.def.y, ri.def.width, ri.def.height);
399 qglViewport (ri.def.x, ri.config.vidHeight - ri.def.height - ri.def.y, ri.def.width, ri.def.height);
400 qglClear (GL_DEPTH_BUFFER_BIT);
401 }
402
403 // Set up projection matrix
404 R_SetupProjectionMatrix (&ri.def, ri.scn.projectionMatrix);
405 if (ri.scn.mirrorView)
406 ri.scn.projectionMatrix[0] = -ri.scn.projectionMatrix[0];
407
408 qglMatrixMode (GL_PROJECTION);
409 qglLoadMatrixf (ri.scn.projectionMatrix);
410
411 // Set up the world view matrix
412 R_SetupModelviewMatrix (&ri.def, ri.scn.worldViewMatrix);
413
414 qglMatrixMode (GL_MODELVIEW);
415 qglLoadMatrixf (ri.scn.worldViewMatrix);
416
417 // Handle portal/mirror rendering
418 if (ri.scn.mirrorView || ri.scn.portalView) {
419 GLdouble clip[4];
420
421 clip[0] = ri.scn.clipPlane.normal[0];
422 clip[1] = ri.scn.clipPlane.normal[1];
423 clip[2] = ri.scn.clipPlane.normal[2];
424 clip[3] = -ri.scn.clipPlane.dist;
425
426 qglClipPlane (GL_CLIP_PLANE0, clip);
427 qglEnable (GL_CLIP_PLANE0);
428 }
429 }
430
431
432 /*
433 ================
434 RB_ClearBuffers
435 ================
436 */
RB_ClearBuffers(void)437 void RB_ClearBuffers (void)
438 {
439 int clearBits;
440
441 clearBits = GL_DEPTH_BUFFER_BIT;
442 if (gl_clear->intVal) {
443 qglClearColor (0.5f, 0.5f, 0.5f, 1.0f);
444 clearBits |= GL_COLOR_BUFFER_BIT;
445 }
446
447 if (ri.useStencil && gl_shadows->intVal) {
448 qglClearStencil (128);
449 clearBits |= GL_STENCIL_BUFFER_BIT;
450 }
451
452 qglClear (clearBits);
453
454 qglDepthRange (0, 1);
455 }
456
457
458 /*
459 ==================
460 RB_SetDefaultState
461
462 Sets our default OpenGL state
463 ==================
464 */
RB_SetDefaultState(void)465 void RB_SetDefaultState (void)
466 {
467 texUnit_t i;
468
469 rb_glState.stateBits1 = 0;
470
471 qglFinish ();
472
473 qglColor4f (1, 1, 1, 1);
474 qglClearColor (0.5f, 0.5f, 0.5f, 1.0f);
475
476 qglEnable (GL_SCISSOR_TEST);
477
478 qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
479 qglPolygonOffset (0, 0);
480
481 // Texture-unit specific
482 for (i=MAX_TEXUNITS-1 ; i>=0 ; i--) {
483 rb_glState.texBound[i] = NULL;
484 rb_glState.texEnvModes[i] = 0;
485 rb_glState.texMatIdentity[i] = qTrue;
486 if (i >= ri.config.maxTexUnits)
487 continue;
488
489 // Texture
490 RB_SelectTexture (i);
491
492 qglDisable (GL_TEXTURE_1D);
493 qglBindTexture (GL_TEXTURE_1D, 0);
494
495 if (ri.config.extTex3D) {
496 qglDisable (GL_TEXTURE_3D);
497 qglBindTexture (GL_TEXTURE_3D, 0);
498 }
499 if (ri.config.extTexCubeMap) {
500 qglDisable (GL_TEXTURE_CUBE_MAP_ARB);
501 qglBindTexture (GL_TEXTURE_CUBE_MAP_ARB, 0);
502 }
503
504 if (i == 0) {
505 qglEnable (GL_TEXTURE_2D);
506 rb_glState.texTarget[i] = GL_TEXTURE_2D;
507 }
508 else {
509 qglDisable (GL_TEXTURE_2D);
510 rb_glState.texTarget[i] = 0;
511 }
512 qglBindTexture (GL_TEXTURE_2D, 0);
513
514 // Texgen
515 qglDisable (GL_TEXTURE_GEN_S);
516 qglDisable (GL_TEXTURE_GEN_T);
517 qglDisable (GL_TEXTURE_GEN_R);
518 qglDisable (GL_TEXTURE_GEN_Q);
519 }
520
521 // Fragment programs
522 if (ri.config.extFragmentProgram)
523 qglDisable (GL_FRAGMENT_PROGRAM_ARB);
524
525 // Vertex programs
526 if (ri.config.extVertexProgram)
527 qglDisable (GL_VERTEX_PROGRAM_ARB);
528
529 // Stencil testing
530 if (ri.useStencil)
531 qglDisable (GL_STENCIL_TEST);
532
533 // Polygon offset testing
534 qglDisable (GL_POLYGON_OFFSET_FILL);
535
536 // Depth testing
537 qglDisable (GL_DEPTH_TEST);
538 qglDepthFunc (GL_LEQUAL);
539 qglDepthRange (0, 1);
540
541 // Face culling
542 qglDisable (GL_CULL_FACE);
543 qglCullFace (GL_FRONT);
544 rb_glState.stateBits1 |= SB1_CULL_FRONT;
545
546 // Alpha testing
547 qglDisable (GL_ALPHA_TEST);
548 qglAlphaFunc (GL_GREATER, 0);
549
550 // Blending
551 qglDisable (GL_BLEND);
552 qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
553 rb_glState.stateBits1 |= SB1_BLENDSRC_SRC_ALPHA|SB1_BLENDDST_ONE_MINUS_SRC_ALPHA;
554
555 // Model shading
556 qglShadeModel (GL_SMOOTH);
557
558 // Check for errors
559 GL_CheckForError ("RB_SetDefaultState");
560 }
561