1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 Copyright (C) 2006 Robert Beckebans <trebor_7@users.sourceforge.net>
5
6 This file is part of XreaL source code.
7
8 XreaL source code is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
12
13 XreaL source code is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with XreaL source code; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 ===========================================================================
22 */
23 // tr_backend.c
24 #include "tr_local.h"
25
26 backEndData_t *backEndData[SMP_FRAMES];
27 backEndState_t backEnd;
28
GL_Bind(image_t * image)29 void GL_Bind(image_t * image)
30 {
31 int texnum;
32
33 if(!image)
34 {
35 ri.Printf(PRINT_WARNING, "GL_Bind: NULL image\n");
36 texnum = tr.defaultImage->texnum;
37 }
38 else
39 {
40 if(r_logFile->integer)
41 {
42 // don't just call LogComment, or we will get a call to va() every frame!
43 GLimp_LogComment(va("--- GL_Bind( %s ) ---\n", image->name));
44 }
45
46 texnum = image->texnum;
47 }
48
49 if(r_nobind->integer && tr.blackImage)
50 {
51 // performance evaluation option
52 texnum = tr.blackImage->texnum;
53 }
54
55 if(glState.currenttextures[glState.currenttmu] != texnum)
56 {
57 image->frameUsed = tr.frameCount;
58 glState.currenttextures[glState.currenttmu] = texnum;
59 qglBindTexture(image->type, texnum);
60 }
61 }
62
GL_Program(GLhandleARB program)63 void GL_Program(GLhandleARB program)
64 {
65 if(glConfig2.shadingLanguage100Available)
66 {
67 if(glState.currentProgram != program)
68 {
69 glState.currentProgram = program;
70 qglUseProgramObjectARB(program);
71 }
72 }
73 }
74
75 /*
76 ** GL_SelectTexture
77 */
GL_SelectTexture(int unit)78 void GL_SelectTexture(int unit)
79 {
80 if(glState.currenttmu == unit)
81 {
82 return;
83 }
84
85 if(unit >= 0 && unit <= 7)
86 {
87 qglActiveTextureARB(GL_TEXTURE0_ARB + unit);
88 qglClientActiveTextureARB(GL_TEXTURE0_ARB + unit);
89
90 if(r_logFile->integer)
91 {
92 GLimp_LogComment(va("glActiveTextureARB( GL_TEXTURE%i_ARB )\n", unit));
93 GLimp_LogComment(va("glClientActiveTextureARB( GL_TEXTURE%i_ARB )\n", unit));
94 }
95 }
96 else
97 {
98 ri.Error(ERR_DROP, "GL_SelectTexture: unit = %i", unit);
99 }
100
101 glState.currenttmu = unit;
102 }
103
104
105 /*
106 ** GL_BindMultitexture
107 */
GL_BindMultitexture(image_t * image0,GLuint env0,image_t * image1,GLuint env1)108 void GL_BindMultitexture(image_t * image0, GLuint env0, image_t * image1, GLuint env1)
109 {
110 int texnum0, texnum1;
111
112 texnum0 = image0->texnum;
113 texnum1 = image1->texnum;
114
115 if(r_nobind->integer && tr.blackImage)
116 {
117 // performance evaluation option
118 texnum0 = texnum1 = tr.blackImage->texnum;
119 }
120
121 if(glState.currenttextures[1] != texnum1)
122 {
123 GL_SelectTexture(1);
124 image1->frameUsed = tr.frameCount;
125 glState.currenttextures[1] = texnum1;
126 qglBindTexture(GL_TEXTURE_2D, texnum1);
127 }
128 if(glState.currenttextures[0] != texnum0)
129 {
130 GL_SelectTexture(0);
131 image0->frameUsed = tr.frameCount;
132 glState.currenttextures[0] = texnum0;
133 qglBindTexture(GL_TEXTURE_2D, texnum0);
134 }
135 }
136
137
138 /*
139 ** GL_Cull
140 */
GL_Cull(int cullType)141 void GL_Cull(int cullType)
142 {
143 if(glState.faceCulling == cullType)
144 {
145 return;
146 }
147
148 glState.faceCulling = cullType;
149
150 if(cullType == CT_TWO_SIDED)
151 {
152 qglDisable(GL_CULL_FACE);
153 }
154 else
155 {
156 qglEnable(GL_CULL_FACE);
157
158 if(cullType == CT_BACK_SIDED)
159 {
160 if(backEnd.viewParms.isMirror)
161 {
162 qglCullFace(GL_FRONT);
163 }
164 else
165 {
166 qglCullFace(GL_BACK);
167 }
168 }
169 else
170 {
171 if(backEnd.viewParms.isMirror)
172 {
173 qglCullFace(GL_BACK);
174 }
175 else
176 {
177 qglCullFace(GL_FRONT);
178 }
179 }
180 }
181 }
182
183 /*
184 ** GL_TexEnv
185 */
GL_TexEnv(int env)186 void GL_TexEnv(int env)
187 {
188 if(env == glState.texEnv[glState.currenttmu])
189 {
190 return;
191 }
192
193 glState.texEnv[glState.currenttmu] = env;
194
195
196 switch (env)
197 {
198 case GL_MODULATE:
199 qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
200 break;
201 case GL_REPLACE:
202 qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
203 break;
204 case GL_DECAL:
205 qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
206 break;
207 case GL_ADD:
208 qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
209 break;
210 default:
211 ri.Error(ERR_DROP, "GL_TexEnv: invalid env '%d' passed\n", env);
212 break;
213 }
214 }
215
216 /*
217 ** GL_State
218 **
219 ** This routine is responsible for setting the most commonly changed state
220 ** in Q3.
221 */
GL_State(unsigned long stateBits)222 void GL_State(unsigned long stateBits)
223 {
224 unsigned long diff = stateBits ^ glState.glStateBits;
225
226 if(!diff)
227 {
228 return;
229 }
230
231 // check depthFunc bits
232 if(diff & GLS_DEPTHFUNC_BITS)
233 {
234 switch (stateBits & GLS_DEPTHFUNC_BITS)
235 {
236 case 0:
237 qglDepthFunc(GL_LEQUAL);
238 break;
239 case GLS_DEPTHFUNC_LESS:
240 qglDepthFunc(GL_LESS);
241 break;
242 case GLS_DEPTHFUNC_EQUAL:
243 qglDepthFunc(GL_EQUAL);
244 break;
245 default:
246 assert(0);
247 break;
248 }
249 }
250
251 // check blend bits
252 if(diff & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS))
253 {
254 GLenum srcFactor, dstFactor;
255
256 if(stateBits & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS))
257 {
258 switch (stateBits & GLS_SRCBLEND_BITS)
259 {
260 case GLS_SRCBLEND_ZERO:
261 srcFactor = GL_ZERO;
262 break;
263 case GLS_SRCBLEND_ONE:
264 srcFactor = GL_ONE;
265 break;
266 case GLS_SRCBLEND_DST_COLOR:
267 srcFactor = GL_DST_COLOR;
268 break;
269 case GLS_SRCBLEND_ONE_MINUS_DST_COLOR:
270 srcFactor = GL_ONE_MINUS_DST_COLOR;
271 break;
272 case GLS_SRCBLEND_SRC_ALPHA:
273 srcFactor = GL_SRC_ALPHA;
274 break;
275 case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA:
276 srcFactor = GL_ONE_MINUS_SRC_ALPHA;
277 break;
278 case GLS_SRCBLEND_DST_ALPHA:
279 srcFactor = GL_DST_ALPHA;
280 break;
281 case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA:
282 srcFactor = GL_ONE_MINUS_DST_ALPHA;
283 break;
284 case GLS_SRCBLEND_ALPHA_SATURATE:
285 srcFactor = GL_SRC_ALPHA_SATURATE;
286 break;
287 default:
288 srcFactor = GL_ONE; // to get warning to shut up
289 ri.Error(ERR_DROP, "GL_State: invalid src blend state bits\n");
290 break;
291 }
292
293 switch (stateBits & GLS_DSTBLEND_BITS)
294 {
295 case GLS_DSTBLEND_ZERO:
296 dstFactor = GL_ZERO;
297 break;
298 case GLS_DSTBLEND_ONE:
299 dstFactor = GL_ONE;
300 break;
301 case GLS_DSTBLEND_SRC_COLOR:
302 dstFactor = GL_SRC_COLOR;
303 break;
304 case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR:
305 dstFactor = GL_ONE_MINUS_SRC_COLOR;
306 break;
307 case GLS_DSTBLEND_SRC_ALPHA:
308 dstFactor = GL_SRC_ALPHA;
309 break;
310 case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA:
311 dstFactor = GL_ONE_MINUS_SRC_ALPHA;
312 break;
313 case GLS_DSTBLEND_DST_ALPHA:
314 dstFactor = GL_DST_ALPHA;
315 break;
316 case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA:
317 dstFactor = GL_ONE_MINUS_DST_ALPHA;
318 break;
319 default:
320 dstFactor = GL_ONE; // to get warning to shut up
321 ri.Error(ERR_DROP, "GL_State: invalid dst blend state bits\n");
322 break;
323 }
324
325 qglEnable(GL_BLEND);
326 qglBlendFunc(srcFactor, dstFactor);
327 }
328 else
329 {
330 qglDisable(GL_BLEND);
331 }
332 }
333
334 // check colormask
335 if(diff & GLS_COLORMASK_BITS)
336 {
337 if(stateBits & GLS_COLORMASK_BITS)
338 {
339 qglColorMask((stateBits & GLS_REDMASK_FALSE) ? GL_FALSE : GL_TRUE,
340 (stateBits & GLS_GREENMASK_FALSE) ? GL_FALSE : GL_TRUE,
341 (stateBits & GLS_BLUEMASK_FALSE) ? GL_FALSE : GL_TRUE,
342 (stateBits & GLS_ALPHAMASK_FALSE) ? GL_FALSE : GL_TRUE);
343 }
344 else
345 {
346 qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
347 }
348 }
349
350 // check depthmask
351 if(diff & GLS_DEPTHMASK_TRUE)
352 {
353 if(stateBits & GLS_DEPTHMASK_TRUE)
354 {
355 qglDepthMask(GL_TRUE);
356 }
357 else
358 {
359 qglDepthMask(GL_FALSE);
360 }
361 }
362
363 // fill/line mode
364 if(diff & GLS_POLYMODE_LINE)
365 {
366 if(stateBits & GLS_POLYMODE_LINE)
367 {
368 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
369 }
370 else
371 {
372 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
373 }
374 }
375
376 // depthtest
377 if(diff & GLS_DEPTHTEST_DISABLE)
378 {
379 if(stateBits & GLS_DEPTHTEST_DISABLE)
380 {
381 qglDisable(GL_DEPTH_TEST);
382 }
383 else
384 {
385 qglEnable(GL_DEPTH_TEST);
386 }
387 }
388
389 // alpha test
390 if(diff & GLS_ATEST_BITS)
391 {
392 switch (stateBits & GLS_ATEST_BITS)
393 {
394 case 0:
395 qglDisable(GL_ALPHA_TEST);
396 break;
397 case GLS_ATEST_GT_0:
398 qglEnable(GL_ALPHA_TEST);
399 qglAlphaFunc(GL_GREATER, 0.0f);
400 break;
401 case GLS_ATEST_LT_80:
402 qglEnable(GL_ALPHA_TEST);
403 qglAlphaFunc(GL_LESS, 0.5f);
404 break;
405 case GLS_ATEST_GE_80:
406 qglEnable(GL_ALPHA_TEST);
407 qglAlphaFunc(GL_GEQUAL, 0.5f);
408 break;
409 case GLS_ATEST_GT_CUSTOM:
410 // FIXME
411 qglEnable(GL_ALPHA_TEST);
412 qglAlphaFunc(GL_GREATER, 0.5f);
413 break;
414 default:
415 assert(0);
416 break;
417 }
418 }
419
420 // stenciltest
421 if(diff & GLS_STENCILTEST_ENABLE)
422 {
423 if(stateBits & GLS_STENCILTEST_ENABLE)
424 {
425 qglEnable(GL_STENCIL_TEST);
426 }
427 else
428 {
429 qglDisable(GL_STENCIL_TEST);
430 }
431 }
432
433 glState.glStateBits = stateBits;
434 }
435
436
437
438 /*
439 ================
440 RB_Hyperspace
441
442 A player has predicted a teleport, but hasn't arrived yet
443 ================
444 */
RB_Hyperspace(void)445 static void RB_Hyperspace(void)
446 {
447 float c;
448
449 if(!backEnd.isHyperspace)
450 {
451 // do initialization shit
452 }
453
454 c = (backEnd.refdef.time & 255) / 255.0f;
455 qglClearColor(c, c, c, 1);
456 qglClear(GL_COLOR_BUFFER_BIT);
457
458 backEnd.isHyperspace = qtrue;
459 }
460
461
SetViewportAndScissor(void)462 static void SetViewportAndScissor(void)
463 {
464 #if 0
465 matrix_t projectionMatrix;
466
467 // convert from our coordinate system (looking down X)
468 // to OpenGL's coordinate system (looking down -Z)
469 MatrixMultiply(backEnd.viewParms.projectionMatrix, quakeToOpenGLMatrix, projectionMatrix);
470
471 qglMatrixMode(GL_PROJECTION);
472 qglLoadMatrixf(projectionMatrix);
473 qglMatrixMode(GL_MODELVIEW);
474 #else
475 qglMatrixMode(GL_PROJECTION);
476 qglLoadMatrixf(backEnd.viewParms.projectionMatrix);
477 qglMatrixMode(GL_MODELVIEW);
478 #endif
479
480 // set the window clipping
481 qglViewport(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY,
482 backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight);
483
484 qglScissor(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY,
485 backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight);
486 }
487
488
489 /*
490 ================
491 RB_SetGL2D
492 ================
493 */
RB_SetGL2D(void)494 static void RB_SetGL2D(void)
495 {
496 GLimp_LogComment("--- RB_SetGL2D ---\n");
497
498 backEnd.projection2D = qtrue;
499
500 // set 2D virtual screen size
501 qglViewport(0, 0, glConfig.vidWidth, glConfig.vidHeight);
502 qglScissor(0, 0, glConfig.vidWidth, glConfig.vidHeight);
503 qglMatrixMode(GL_PROJECTION);
504 qglLoadIdentity();
505 qglOrtho(0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1);
506 qglMatrixMode(GL_MODELVIEW);
507 qglLoadIdentity();
508
509 GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
510
511 qglDisable(GL_CULL_FACE);
512 qglDisable(GL_CLIP_PLANE0);
513
514 // set time for 2D shaders
515 backEnd.refdef.time = ri.Milliseconds();
516 backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f;
517 }
518
519 /*
520 =================
521 RB_BeginDrawingView
522
523 Any mirrored or portaled views have already been drawn, so prepare
524 to actually render the visible surfaces for this view
525 =================
526 */
RB_BeginDrawingView(void)527 static void RB_BeginDrawingView(void)
528 {
529 int clearBits = 0;
530
531 GLimp_LogComment("--- RB_BeginDrawingView ---\n");
532
533 // sync with gl if needed
534 if(r_finish->integer == 1 && !glState.finishCalled)
535 {
536 qglFinish();
537 glState.finishCalled = qtrue;
538 }
539 if(r_finish->integer == 0)
540 {
541 glState.finishCalled = qtrue;
542 }
543
544 // we will need to change the projection matrix before drawing
545 // 2D images again
546 backEnd.projection2D = qfalse;
547
548 // set the modelview matrix for the viewer
549 SetViewportAndScissor();
550
551 // ensures that depth writes are enabled for the depth clear
552 GL_State(GLS_DEFAULT);
553
554 // clear relevant buffers
555 clearBits = GL_DEPTH_BUFFER_BIT;
556
557 if(r_measureOverdraw->integer || r_shadows->integer == 3)
558 {
559 clearBits |= GL_STENCIL_BUFFER_BIT;
560 }
561 if(r_fastsky->integer && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL))
562 {
563 clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used
564 #ifdef _DEBUG
565 qglClearColor(0.0f, 0.0f, 1.0f, 1.0f); // FIXME: get color of sky
566 #else
567 qglClearColor(0.0f, 0.0f, 0.0f, 1.0f); // FIXME: get color of sky
568 #endif
569 }
570 qglClear(clearBits);
571
572 if((backEnd.refdef.rdflags & RDF_HYPERSPACE))
573 {
574 RB_Hyperspace();
575 return;
576 }
577 else
578 {
579 backEnd.isHyperspace = qfalse;
580 }
581
582 glState.faceCulling = -1; // force face culling to set next time
583
584 // we will only draw a sun if there was sky rendered in this view
585 backEnd.skyRenderedThisView = qfalse;
586
587 // clip to the plane of the portal
588 if(backEnd.viewParms.isPortal)
589 {
590 float plane[4];
591 double plane2[4];
592
593 plane[0] = backEnd.viewParms.portalPlane.normal[0];
594 plane[1] = backEnd.viewParms.portalPlane.normal[1];
595 plane[2] = backEnd.viewParms.portalPlane.normal[2];
596 plane[3] = backEnd.viewParms.portalPlane.dist;
597
598 plane2[0] = DotProduct(backEnd.viewParms.or.axis[0], plane);
599 plane2[1] = DotProduct(backEnd.viewParms.or.axis[1], plane);
600 plane2[2] = DotProduct(backEnd.viewParms.or.axis[2], plane);
601 plane2[3] = DotProduct(plane, backEnd.viewParms.or.origin) - plane[3];
602
603 // qglLoadIdentity();
604 qglLoadMatrixf(quakeToOpenGLMatrix);
605 qglClipPlane(GL_CLIP_PLANE0, plane2);
606 qglEnable(GL_CLIP_PLANE0);
607 }
608 else
609 {
610 qglDisable(GL_CLIP_PLANE0);
611 }
612
613 GL_CheckErrors();
614 }
615
RB_RenderDrawSurfaces(float originalTime,drawSurf_t * drawSurfs,int numDrawSurfs,qboolean opaque)616 static void RB_RenderDrawSurfaces(float originalTime, drawSurf_t * drawSurfs, int numDrawSurfs, qboolean opaque)
617 {
618 trRefEntity_t *entity, *oldEntity;
619 int lightmapNum, oldLightmapNum;
620 shader_t *shader, *oldShader;
621 int fogNum, oldFogNum;
622 qboolean depthRange, oldDepthRange;
623 int i;
624 drawSurf_t *drawSurf;
625 int oldSort;
626
627 GLimp_LogComment("--- RB_RenderDrawSurfaces ---\n");
628
629 // draw everything
630 oldEntity = NULL;
631 oldShader = NULL;
632 oldLightmapNum = -1;
633 oldFogNum = -1;
634 oldDepthRange = qfalse;
635 oldSort = -1;
636 depthRange = qfalse;
637
638 for(i = 0, drawSurf = drawSurfs; i < numDrawSurfs; i++, drawSurf++)
639 {
640 // update locals
641 entity = drawSurf->entity;
642 shader = tr.sortedShaders[drawSurf->shaderNum];
643 lightmapNum = drawSurf->lightmapNum;
644 fogNum = drawSurf->fogNum;
645
646 if(opaque)
647 {
648 // skip all translucent surfaces that don't matter for this pass
649 if(shader->sort > SS_OPAQUE)
650 {
651 break;
652 }
653 }
654 else
655 {
656 // skip all opaque surfaces that don't matter for this pass
657 if(shader->sort <= SS_OPAQUE)
658 {
659 continue;
660 }
661 }
662
663 if(entity == oldEntity && shader == oldShader && lightmapNum == oldLightmapNum && fogNum == oldFogNum)
664 {
665 // fast path, same as previous sort
666 tess_surfaceTable[*drawSurf->surface] (drawSurf->surface, 0, NULL, 0, NULL);
667 continue;
668 }
669
670 // change the tess parameters if needed
671 // a "entityMergable" shader is a shader that can have surfaces from seperate
672 // entities merged into a single batch, like smoke and blood puff sprites
673 if(shader != oldShader
674 || fogNum != oldFogNum || lightmapNum != oldLightmapNum || (entity != oldEntity && !shader->entityMergable))
675 {
676 if(oldShader != NULL)
677 {
678 Tess_End();
679 }
680
681 Tess_Begin(shader, NULL, lightmapNum, fogNum, qfalse, qfalse);
682 oldShader = shader;
683 oldLightmapNum = lightmapNum;
684 oldFogNum = fogNum;
685 }
686
687 // change the modelview matrix if needed
688 if(entity != oldEntity)
689 {
690 depthRange = qfalse;
691
692 if(entity != &tr.worldEntity)
693 {
694 backEnd.currentEntity = entity;
695 backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime;
696
697 // we have to reset the shaderTime as well otherwise image animations start
698 // from the wrong frame
699 tess.shaderTime = backEnd.refdef.floatTime - tess.surfaceShader->timeOffset;
700
701 // set up the transformation matrix
702 R_RotateForEntity(backEnd.currentEntity, &backEnd.viewParms, &backEnd.or);
703
704 if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK)
705 {
706 // hack the depth range to prevent view model from poking into walls
707 depthRange = qtrue;
708 }
709 }
710 else
711 {
712 backEnd.currentEntity = &tr.worldEntity;
713 backEnd.refdef.floatTime = originalTime;
714 backEnd.or = backEnd.viewParms.world;
715
716 // we have to reset the shaderTime as well otherwise image animations on
717 // the world (like water) continue with the wrong frame
718 tess.shaderTime = backEnd.refdef.floatTime - tess.surfaceShader->timeOffset;
719 }
720
721 qglLoadMatrixf(backEnd.or.modelViewMatrix);
722
723 // change depthrange if needed
724 if(oldDepthRange != depthRange)
725 {
726 if(depthRange)
727 {
728 qglDepthRange(0, 0.3);
729 }
730 else
731 {
732 qglDepthRange(0, 1);
733 }
734 oldDepthRange = depthRange;
735 }
736
737 oldEntity = entity;
738 }
739
740 // add the triangles for this surface
741 tess_surfaceTable[*drawSurf->surface] (drawSurf->surface, 0, NULL, 0, NULL);
742 }
743
744 backEnd.refdef.floatTime = originalTime;
745
746 // draw the contents of the last shader batch
747 if(oldShader != NULL)
748 {
749 Tess_End();
750 }
751
752 // go back to the world modelview matrix
753 qglLoadMatrixf(backEnd.viewParms.world.modelViewMatrix);
754 if(depthRange)
755 {
756 qglDepthRange(0, 1);
757 }
758
759 GL_CheckErrors();
760 }
761
762 /*
763 =================
764 RB_RenderInteractions
765 =================
766 */
RB_RenderInteractions(float originalTime,interaction_t * interactions,int numInteractions)767 static void RB_RenderInteractions(float originalTime, interaction_t * interactions, int numInteractions)
768 {
769 shader_t *shader, *oldShader;
770 trRefEntity_t *entity, *oldEntity;
771 trRefDlight_t *light, *oldLight;
772 interaction_t *ia;
773 qboolean depthRange, oldDepthRange;
774 int iaCount;
775 surfaceType_t *surface;
776 vec3_t tmp;
777 matrix_t modelToLight;
778
779 GLimp_LogComment("--- RB_RenderInteractions ---\n");
780
781 // draw everything
782 oldLight = NULL;
783 oldEntity = NULL;
784 oldShader = NULL;
785 oldDepthRange = qfalse;
786 depthRange = qfalse;
787
788 tess.currentStageIteratorType = SIT_LIGHTING;
789
790 // render interactions
791 for(iaCount = 0, ia = &interactions[0]; iaCount < numInteractions;)
792 {
793 backEnd.currentLight = light = ia->dlight;
794 backEnd.currentEntity = entity = ia->entity;
795 surface = ia->surface;
796 shader = ia->surfaceShader;
797
798 if(glConfig2.occlusionQueryBits && !ia->occlusionQuerySamples)
799 {
800 // skip all interactions of this light because it failed the occlusion query
801 goto nextInteraction;
802 }
803
804 if(!shader->interactLight)
805 {
806 // skip this interaction because the surface shader has no ability to interact with light
807 // this will save texcoords and matrix calculations
808 goto nextInteraction;
809 }
810
811 if(light != oldLight)
812 {
813 // set light scissor to reduce fillrate
814 qglScissor(ia->scissorX, ia->scissorY, ia->scissorWidth, ia->scissorHeight);
815
816 #if 0
817 if(!light->additive)
818 {
819 GL_State(GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL);
820 }
821 else
822 #endif
823 {
824 GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL);
825 }
826 }
827
828 // Tr3B - this should never happen in the first iteration
829 if(!r_nobatching->integer && light == oldLight && entity == oldEntity && shader == oldShader)
830 {
831 if(ia->type != IA_SHADOWONLY)
832 {
833 // fast path, same as previous
834 tess_surfaceTable[*surface] (surface, ia->numLightIndexes, ia->lightIndexes, 0, NULL);
835 goto nextInteraction;
836 }
837 }
838
839 // draw the contents of the last shader batch
840 if(oldEntity != NULL || oldLight != NULL || oldShader != NULL)
841 {
842 Tess_End();
843 }
844
845 // we need a new batch
846 Tess_Begin(shader, ia->dlightShader, -1, 0, qfalse, qfalse);
847
848 // change the modelview matrix if needed
849 if(entity != oldEntity)
850 {
851 depthRange = qfalse;
852
853 if(entity != &tr.worldEntity)
854 {
855 backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime;
856 // we have to reset the shaderTime as well otherwise image animations start
857 // from the wrong frame
858 tess.shaderTime = backEnd.refdef.floatTime - tess.surfaceShader->timeOffset;
859
860 // set up the transformation matrix
861 R_RotateForEntity(backEnd.currentEntity, &backEnd.viewParms, &backEnd.or);
862
863 if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK)
864 {
865 // hack the depth range to prevent view model from poking into walls
866 depthRange = qtrue;
867 }
868 }
869 else
870 {
871 backEnd.refdef.floatTime = originalTime;
872 backEnd.or = backEnd.viewParms.world;
873 // we have to reset the shaderTime as well otherwise image animations on
874 // the world (like water) continue with the wrong frame
875 tess.shaderTime = backEnd.refdef.floatTime - tess.surfaceShader->timeOffset;
876 }
877
878 qglLoadMatrixf(backEnd.or.modelViewMatrix);
879
880 // change depthrange if needed
881 if(oldDepthRange != depthRange)
882 {
883 if(depthRange)
884 {
885 qglDepthRange(0, 0.3);
886 }
887 else
888 {
889 qglDepthRange(0, 1);
890 }
891 oldDepthRange = depthRange;
892 }
893 }
894
895 // change the attenuation matrix if needed
896 if(light != oldLight || entity != oldEntity)
897 {
898 // transform light origin into model space for u_LightOrigin parameter
899 if(entity != &tr.worldEntity)
900 {
901 VectorSubtract(light->origin, backEnd.or.origin, tmp);
902 light->transformed[0] = DotProduct(tmp, backEnd.or.axis[0]);
903 light->transformed[1] = DotProduct(tmp, backEnd.or.axis[1]);
904 light->transformed[2] = DotProduct(tmp, backEnd.or.axis[2]);
905 }
906 else
907 {
908 VectorCopy(light->origin, light->transformed);
909 }
910
911 // build the attenuation matrix using the entity transform
912 MatrixMultiply(light->viewMatrix, backEnd.or.transformMatrix, modelToLight);
913
914 MatrixSetupTranslation(light->attenuationMatrix, 0.5, 0.5, 0.5); // bias
915 MatrixMultiplyScale(light->attenuationMatrix, 0.5, 0.5, 0.5); // scale
916 MatrixMultiply2(light->attenuationMatrix, light->projectionMatrix); // light projection (frustum)
917 MatrixMultiply2(light->attenuationMatrix, modelToLight);
918 }
919
920 if(ia->type != IA_SHADOWONLY)
921 {
922 // add the triangles for this surface
923 tess_surfaceTable[*surface] (surface, ia->numLightIndexes, ia->lightIndexes, 0, NULL);
924 }
925
926 nextInteraction:
927 if(!ia->next)
928 {
929 if(glConfig2.occlusionQueryBits && !ia->occlusionQuerySamples)
930 {
931 // do nothing
932 }
933 else if(!shader->interactLight)
934 {
935 // do nothing as well
936 }
937 else
938 {
939 // draw the contents of the current shader batch
940 Tess_End();
941 }
942
943 if(iaCount < (numInteractions - 1))
944 {
945 // jump to next interaction and continue
946 ia++;
947 iaCount++;
948 }
949 else
950 {
951 // increase last time to leave for loop
952 iaCount++;
953 }
954 }
955 else
956 {
957 // just continue
958 ia = ia->next;
959 iaCount++;
960 }
961
962 // remember values
963 oldLight = light;
964 oldEntity = entity;
965 oldShader = shader;
966 }
967
968 backEnd.refdef.floatTime = originalTime;
969
970 // go back to the world modelview matrix
971 qglLoadMatrixf(backEnd.viewParms.world.modelViewMatrix);
972 if(depthRange)
973 {
974 qglDepthRange(0, 1);
975 }
976
977 // reset scissor
978 qglScissor(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY,
979 backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight);
980
981 // reset stage iterator
982 tess.currentStageIteratorType = SIT_DEFAULT;
983
984 GL_CheckErrors();
985 }
986
987
988 /*
989 =================
990 RB_RenderInteractionsStencilShadowed
991 =================
992 */
RB_RenderInteractionsStencilShadowed(float originalTime,interaction_t * interactions,int numInteractions)993 static void RB_RenderInteractionsStencilShadowed(float originalTime, interaction_t * interactions, int numInteractions)
994 {
995 shader_t *shader, *oldShader;
996 trRefEntity_t *entity, *oldEntity;
997 trRefDlight_t *light, *oldLight;
998 interaction_t *ia;
999 int iaCount;
1000 int iaFirst = 0;
1001 surfaceType_t *surface;
1002 qboolean depthRange, oldDepthRange;
1003 vec3_t tmp;
1004 matrix_t modelToLight;
1005 qboolean drawShadows;
1006
1007 if(glConfig.stencilBits < 4 || !glConfig2.shadingLanguage100Available)
1008 {
1009 RB_RenderInteractions(originalTime, interactions, numInteractions);
1010 return;
1011 }
1012
1013 GLimp_LogComment("--- RB_RenderInteractionsStencilShadowed ---\n");
1014
1015 // draw everything
1016 oldLight = NULL;
1017 oldEntity = NULL;
1018 oldShader = NULL;
1019 oldDepthRange = qfalse;
1020 depthRange = qfalse;
1021 drawShadows = qtrue;
1022
1023 tess.currentStageIteratorType = SIT_LIGHTING_STENCIL;
1024
1025 // render interactions
1026 for(iaCount = 0, ia = &interactions[0]; iaCount < numInteractions;)
1027 {
1028 backEnd.currentLight = light = ia->dlight;
1029 backEnd.currentEntity = entity = ia->entity;
1030 surface = ia->surface;
1031 shader = ia->surfaceShader;
1032
1033 // only iaFirst == iaCount if first iteration or counters were reset
1034 if(light != oldLight || iaFirst == iaCount)
1035 {
1036 iaFirst = iaCount;
1037
1038 if(drawShadows)
1039 {
1040 // set light scissor to reduce fillrate
1041 qglScissor(ia->scissorX, ia->scissorY, ia->scissorWidth, ia->scissorHeight);
1042
1043 // set depth test to reduce fillrate
1044 if(qglDepthBoundsEXT)
1045 {
1046 if(!ia->noDepthBoundsTest)
1047 {
1048 qglEnable(GL_DEPTH_BOUNDS_TEST_EXT);
1049 qglDepthBoundsEXT(ia->depthNear, ia->depthFar);
1050 }
1051 else
1052 {
1053 qglDisable(GL_DEPTH_BOUNDS_TEST_EXT);
1054 }
1055 }
1056
1057 // set the reference stencil value
1058 qglClearStencil(128);
1059
1060 // reset stencil buffer
1061 qglClear(GL_STENCIL_BUFFER_BIT);
1062
1063 // use less compare as depthfunc
1064 // don't write to the color buffer or depth buffer
1065 // enable stencil testing for this light
1066 GL_State(GLS_DEPTHFUNC_LESS | GLS_COLORMASK_BITS | GLS_STENCILTEST_ENABLE);
1067
1068 qglStencilFunc(GL_ALWAYS, 128, ~0);
1069 qglStencilMask(~0);
1070
1071 qglEnable(GL_POLYGON_OFFSET_FILL);
1072 qglPolygonOffset(r_shadowOffsetFactor->value, r_shadowOffsetUnits->value);
1073
1074 // enable shadow volume extrusion shader
1075 #if 1
1076 GL_Program(tr.shadowShader.program);
1077 GL_ClientState(tr.shadowShader.attribs);
1078 #else
1079 GL_Program(0);
1080 GL_ClientState(GLCS_VERTEX);
1081 GL_SelectTexture(0);
1082 GL_Bind(tr.whiteImage);
1083 #endif
1084
1085 qglVertexPointer(4, GL_FLOAT, 0, tess.xyz);
1086 }
1087 else
1088 {
1089 // Tr3B - see RobustShadowVolumes.pdf by Nvidia
1090 // Set stencil testing to render only pixels with a zero
1091 // stencil value, i.e., visible fragments illuminated by the
1092 // current light. Use equal depth testing to update only the
1093 // visible fragments, and then, increment stencil to avoid
1094 // double blending. Re-enable color buffer writes again.
1095
1096 #if 0
1097 if(!light->additive)
1098 {
1099 GL_State(GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL | GLS_STENCILTEST_ENABLE);
1100 }
1101 else
1102 #endif
1103 {
1104 GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL | GLS_STENCILTEST_ENABLE);
1105 }
1106
1107 if(light->l.noShadows)
1108 {
1109 // don't consider shadow volumes
1110 qglStencilFunc(GL_ALWAYS, 128, ~0);
1111 }
1112 else
1113 {
1114 qglStencilFunc(GL_EQUAL, 128, ~0);
1115 }
1116 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);//GL_INCR);
1117
1118 qglDisable(GL_POLYGON_OFFSET_FILL);
1119
1120 // disable shadow volume extrusion shader
1121 GL_Program(0);
1122 }
1123 }
1124
1125 if(drawShadows)
1126 {
1127 if(!r_nobatching->integer && light == oldLight && entity == oldEntity && shader == oldShader)
1128 {
1129 if(!(entity->e.renderfx & (RF_NOSHADOW | RF_DEPTHHACK)) &&
1130 shader->sort == SS_OPAQUE &&
1131 !shader->noShadows &&
1132 !light->l.noShadows &&
1133 ia->type != IA_LIGHTONLY)
1134 {
1135 // fast path, same as previous
1136 tess_surfaceTable[*surface] (surface, 0, NULL, ia->numShadowIndexes, ia->shadowIndexes);
1137 goto nextInteraction;
1138 }
1139 }
1140 else
1141 {
1142 // draw the contents of the last shader batch
1143 if(oldEntity != NULL || oldLight != NULL || oldShader != NULL)
1144 {
1145 Tess_End();
1146 }
1147
1148 // we don't need tangent space calculations here
1149 Tess_Begin(shader, ia->dlightShader, -1, 0, qtrue, qtrue);
1150 }
1151 }
1152 else
1153 {
1154 if(!r_nobatching->integer && light == oldLight && entity == oldEntity && shader == oldShader)
1155 {
1156 if(shader->interactLight && ia->type != IA_SHADOWONLY)
1157 {
1158 // fast path, same as previous
1159 tess_surfaceTable[*surface] (surface, ia->numLightIndexes, ia->lightIndexes, 0, NULL);
1160 goto nextInteraction;
1161 }
1162 }
1163 else
1164 {
1165 // draw the contents of the last shader batch
1166 if(oldEntity != NULL || oldLight != NULL || oldShader != NULL)
1167 {
1168 Tess_End();
1169 }
1170
1171 Tess_Begin(shader, ia->dlightShader, -1, 0, qfalse, qfalse);
1172 }
1173 }
1174
1175 // change the modelview matrix if needed
1176 if(entity != oldEntity)
1177 {
1178 depthRange = qfalse;
1179
1180 if(entity != &tr.worldEntity)
1181 {
1182 backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime;
1183 // we have to reset the shaderTime as well otherwise image animations start
1184 // from the wrong frame
1185 tess.shaderTime = backEnd.refdef.floatTime - tess.surfaceShader->timeOffset;
1186
1187 // set up the transformation matrix
1188 R_RotateForEntity(backEnd.currentEntity, &backEnd.viewParms, &backEnd.or);
1189
1190 if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK)
1191 {
1192 // hack the depth range to prevent view model from poking into walls
1193 depthRange = qtrue;
1194 }
1195 }
1196 else
1197 {
1198 backEnd.refdef.floatTime = originalTime;
1199 backEnd.or = backEnd.viewParms.world;
1200 // we have to reset the shaderTime as well otherwise image animations on
1201 // the world (like water) continue with the wrong frame
1202 tess.shaderTime = backEnd.refdef.floatTime - tess.surfaceShader->timeOffset;
1203 }
1204
1205 qglLoadMatrixf(backEnd.or.modelViewMatrix);
1206
1207 // change depthrange if needed
1208 if(oldDepthRange != depthRange)
1209 {
1210 if(depthRange)
1211 {
1212 qglDepthRange(0, 0.3);
1213 }
1214 else
1215 {
1216 qglDepthRange(0, 1);
1217 }
1218 oldDepthRange = depthRange;
1219 }
1220 }
1221
1222 // change the attenuation matrix if needed
1223 if(light != oldLight || entity != oldEntity)
1224 {
1225 // transform light origin into model space for u_LightOrigin parameter
1226 if(entity != &tr.worldEntity)
1227 {
1228 VectorSubtract(light->origin, backEnd.or.origin, tmp);
1229 light->transformed[0] = DotProduct(tmp, backEnd.or.axis[0]);
1230 light->transformed[1] = DotProduct(tmp, backEnd.or.axis[1]);
1231 light->transformed[2] = DotProduct(tmp, backEnd.or.axis[2]);
1232 }
1233 else
1234 {
1235 VectorCopy(light->origin, light->transformed);
1236 }
1237
1238 if(drawShadows)
1239 {
1240 // set uniform parameter u_LightOrigin for GLSL shader
1241 #if 1
1242 qglUniform3fARB(tr.shadowShader.u_LightOrigin,
1243 light->transformed[0], light->transformed[1], light->transformed[2]);
1244 #endif
1245 }
1246
1247 // build the attenuation matrix using the entity transform
1248 MatrixMultiply(light->viewMatrix, backEnd.or.transformMatrix, modelToLight);
1249
1250 MatrixSetupTranslation(light->attenuationMatrix, 0.5, 0.5, 0.5); // bias
1251 MatrixMultiplyScale(light->attenuationMatrix, 0.5, 0.5, 0.5); // scale
1252 MatrixMultiply2(light->attenuationMatrix, light->projectionMatrix); // light projection (frustum)
1253 MatrixMultiply2(light->attenuationMatrix, modelToLight);
1254 }
1255
1256 if(drawShadows)
1257 {
1258 if(!(entity->e.renderfx & (RF_NOSHADOW | RF_DEPTHHACK)) &&
1259 shader->sort == SS_OPAQUE &&
1260 !shader->noShadows &&
1261 !light->l.noShadows &&
1262 ia->type != IA_LIGHTONLY)
1263 {
1264 // add the triangles for this surface
1265 tess_surfaceTable[*surface] (surface, 0, NULL, ia->numShadowIndexes, ia->shadowIndexes);
1266 }
1267 }
1268 else
1269 {
1270 if(shader->interactLight && ia->type != IA_SHADOWONLY)
1271 {
1272 // add the triangles for this surface
1273 tess_surfaceTable[*surface] (surface, ia->numLightIndexes, ia->lightIndexes, 0, NULL);
1274 }
1275 }
1276
1277 nextInteraction:
1278 if(!ia->next)
1279 {
1280 // if ia->next does not point to any other interaction then
1281 // this is the last interaction of the current light
1282
1283 if(drawShadows)
1284 {
1285 // jump back to first interaction of this light and start lighting
1286 ia = &interactions[iaFirst];
1287 iaCount = iaFirst;
1288 drawShadows = qfalse;
1289 }
1290 else
1291 {
1292 if(iaCount < (numInteractions - 1))
1293 {
1294 // jump to next interaction and start shadowing
1295 ia++;
1296 iaCount++;
1297 drawShadows = qtrue;
1298 }
1299 else
1300 {
1301 // increase last time to leave for loop
1302 iaCount++;
1303 }
1304 }
1305
1306 // draw the contents of the current shader batch
1307 Tess_End();
1308 }
1309 else
1310 {
1311 // just continue
1312 ia = ia->next;
1313 iaCount++;
1314 }
1315
1316 // remember values
1317 oldLight = light;
1318 oldEntity = entity;
1319 oldShader = shader;
1320 }
1321
1322 backEnd.refdef.floatTime = originalTime;
1323
1324 // go back to the world modelview matrix
1325 qglLoadMatrixf(backEnd.viewParms.world.modelViewMatrix);
1326 if(depthRange)
1327 {
1328 qglDepthRange(0, 1);
1329 }
1330
1331 // reset scissor clamping
1332 qglScissor(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY,
1333 backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight);
1334
1335 // reset depth clamping
1336 if(qglDepthBoundsEXT)
1337 {
1338 qglDisable(GL_DEPTH_BOUNDS_TEST_EXT);
1339 }
1340
1341 // reset stage iterator
1342 tess.currentStageIteratorType = SIT_DEFAULT;
1343
1344 GL_CheckErrors();
1345 }
1346
RB_RenderOcclusionQueries(interaction_t * interactions,int numInteractions)1347 static void RB_RenderOcclusionQueries(interaction_t * interactions, int numInteractions)
1348 {
1349 GLimp_LogComment("--- RB_RenderOcclusionQueries ---\n");
1350
1351 if(glConfig2.occlusionQueryBits)
1352 {
1353 int i;
1354 interaction_t *ia;
1355 int iaCount;
1356 int iaFirst;
1357 trRefDlight_t *light, *oldLight;
1358 int ocCount;
1359 GLint ocSamples = 0;
1360 qboolean queryObjects;
1361 GLint available;
1362
1363 qglColor4f(1.0f, 0.0f, 0.0f, 0.05f);
1364
1365 GL_Program(0);
1366 GL_Cull(CT_TWO_SIDED);
1367 GL_SelectTexture(0);
1368 qglDisable(GL_TEXTURE_2D);
1369
1370 // don't write to the color buffer or depth buffer
1371 if(r_showOcclusionQueries->integer)
1372 {
1373 GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
1374 }
1375 else
1376 {
1377 GL_State(GLS_COLORMASK_BITS);
1378 }
1379
1380 // loop trough all light interactions and render the light OBB for each last interaction
1381 ocCount = -1;
1382 for(iaCount = 0, ia = &interactions[0]; iaCount < numInteractions;)
1383 {
1384 backEnd.currentLight = light = ia->dlight;
1385
1386 if(!ia->next)
1387 {
1388 ocCount++;
1389
1390 // last interaction of current light
1391 if(ocCount < (MAX_OCCLUSION_QUERIES - 1) /*&& R_CullLightPoint(light, backEnd.viewParms.or.origin) == CULL_OUT */ )
1392 {
1393 R_RotateForDlight(light, &backEnd.viewParms, &backEnd.or);
1394 qglLoadMatrixf(backEnd.or.modelViewMatrix);
1395
1396 // begin the occlusion query
1397 qglBeginQueryARB(GL_SAMPLES_PASSED, tr.occlusionQueryObjects[ocCount]);
1398
1399 qglBegin(GL_QUADS);
1400
1401 qglVertex3f(light->localBounds[0][0], light->localBounds[0][1], light->localBounds[0][2]);
1402 qglVertex3f(light->localBounds[0][0], light->localBounds[1][1], light->localBounds[0][2]);
1403 qglVertex3f(light->localBounds[0][0], light->localBounds[1][1], light->localBounds[1][2]);
1404 qglVertex3f(light->localBounds[0][0], light->localBounds[0][1], light->localBounds[1][2]);
1405
1406 qglVertex3f(light->localBounds[1][0], light->localBounds[0][1], light->localBounds[0][2]);
1407 qglVertex3f(light->localBounds[1][0], light->localBounds[1][1], light->localBounds[0][2]);
1408 qglVertex3f(light->localBounds[1][0], light->localBounds[1][1], light->localBounds[1][2]);
1409 qglVertex3f(light->localBounds[1][0], light->localBounds[0][1], light->localBounds[1][2]);
1410
1411 qglVertex3f(light->localBounds[0][0], light->localBounds[0][1], light->localBounds[1][2]);
1412 qglVertex3f(light->localBounds[0][0], light->localBounds[1][1], light->localBounds[1][2]);
1413 qglVertex3f(light->localBounds[1][0], light->localBounds[1][1], light->localBounds[1][2]);
1414 qglVertex3f(light->localBounds[1][0], light->localBounds[0][1], light->localBounds[1][2]);
1415
1416 qglVertex3f(light->localBounds[0][0], light->localBounds[0][1], light->localBounds[0][2]);
1417 qglVertex3f(light->localBounds[0][0], light->localBounds[1][1], light->localBounds[0][2]);
1418 qglVertex3f(light->localBounds[1][0], light->localBounds[1][1], light->localBounds[0][2]);
1419 qglVertex3f(light->localBounds[1][0], light->localBounds[0][1], light->localBounds[0][2]);
1420
1421 qglVertex3f(light->localBounds[0][0], light->localBounds[0][1], light->localBounds[0][2]);
1422 qglVertex3f(light->localBounds[0][0], light->localBounds[0][1], light->localBounds[1][2]);
1423 qglVertex3f(light->localBounds[1][0], light->localBounds[0][1], light->localBounds[1][2]);
1424 qglVertex3f(light->localBounds[1][0], light->localBounds[0][1], light->localBounds[0][2]);
1425
1426 qglVertex3f(light->localBounds[0][0], light->localBounds[1][1], light->localBounds[0][2]);
1427 qglVertex3f(light->localBounds[0][0], light->localBounds[1][1], light->localBounds[1][2]);
1428 qglVertex3f(light->localBounds[1][0], light->localBounds[1][1], light->localBounds[1][2]);
1429 qglVertex3f(light->localBounds[1][0], light->localBounds[1][1], light->localBounds[0][2]);
1430
1431 qglEnd();
1432
1433 // end the query
1434 // don't read back immediately so that we give the query time to be ready
1435 qglEndQueryARB(GL_SAMPLES_PASSED);
1436
1437 backEnd.pc.c_occlusionQueries++;
1438 }
1439
1440 if(iaCount < (numInteractions - 1))
1441 {
1442 // jump to next interaction and continue
1443 ia++;
1444 iaCount++;
1445 }
1446 else
1447 {
1448 // increase last time to leave for loop
1449 iaCount++;
1450 }
1451 }
1452 else
1453 {
1454 // just continue
1455 ia = ia->next;
1456 iaCount++;
1457 }
1458 }
1459
1460 // go back to the world modelview matrix
1461 backEnd.or = backEnd.viewParms.world;
1462 qglLoadMatrixf(backEnd.viewParms.world.modelViewMatrix);
1463
1464 if(!ocCount)
1465 {
1466 qglEnable(GL_TEXTURE_2D);
1467 return;
1468 }
1469
1470 qglFlush();
1471
1472 // do other work until "most" of the queries are back, to avoid
1473 // wasting time spinning
1474 #if 1
1475 i = (int)(ocCount * 3 / 4); // instead of N-1, to prevent the GPU from going idle
1476 do
1477 {
1478 i++;
1479
1480 //if(i >= ocCount)
1481 // i = (int)(ocCount * 3 / 4);
1482
1483 qglGetQueryObjectivARB(tr.occlusionQueryObjects[i], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
1484 }while(!available && i < ocCount);
1485 #endif
1486
1487 // reenable writes to depth and color buffers
1488 GL_State(GLS_DEPTHMASK_TRUE);
1489 qglEnable(GL_TEXTURE_2D);
1490
1491 // loop trough all light interactions and fetch results for each last interaction
1492 // then copy result to all other interactions that belong to the same light
1493 ocCount = -1;
1494 iaFirst = 0;
1495 queryObjects = qtrue;
1496 oldLight = NULL;
1497 for(iaCount = 0, ia = &interactions[0]; iaCount < numInteractions;)
1498 {
1499 backEnd.currentLight = light = ia->dlight;
1500
1501 if(light != oldLight)
1502 {
1503 iaFirst = iaCount;
1504 }
1505
1506 if(!queryObjects)
1507 {
1508 ia->occlusionQuerySamples = ocSamples;
1509 }
1510
1511 if(!ia->next)
1512 {
1513 if(queryObjects)
1514 {
1515 ocCount++;
1516
1517 if(ocCount < (MAX_OCCLUSION_QUERIES - 1) /*&& R_CullLightPoint(light, backEnd.viewParms.or.origin) == CULL_OUT */ )
1518 {
1519 qglGetQueryObjectivARB(tr.occlusionQueryObjects[ocCount], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
1520 if(available)
1521 {
1522 backEnd.pc.c_occlusionQueriesAvailable++;
1523
1524 // get the object and store it in the occlusion bits for the light
1525 qglGetQueryObjectivARB(tr.occlusionQueryObjects[ocCount], GL_QUERY_RESULT, &ocSamples);
1526
1527 if(ocSamples <= 0)
1528 {
1529 backEnd.pc.c_occlusionQueriesCulled++;
1530 }
1531 }
1532 else
1533 {
1534 ocSamples = 1;
1535 }
1536 }
1537 else
1538 {
1539 ocSamples = 1;
1540 }
1541
1542 // jump back to first interaction of this light copy query result
1543 ia = &interactions[iaFirst];
1544 iaCount = iaFirst;
1545 queryObjects = qfalse;
1546 }
1547 else
1548 {
1549 if(iaCount < (numInteractions - 1))
1550 {
1551 // jump to next interaction and start querying
1552 ia++;
1553 iaCount++;
1554 queryObjects = qtrue;
1555 }
1556 else
1557 {
1558 // increase last time to leave for loop
1559 iaCount++;
1560 }
1561 }
1562 }
1563 else
1564 {
1565 // just continue
1566 ia = ia->next;
1567 iaCount++;
1568 }
1569
1570 oldLight = light;
1571 }
1572 }
1573 #if 0
1574 // Tr3B - try to cull light interactions manually with stencil overdraw test
1575 else
1576 {
1577 interaction_t *ia;
1578 int iaCount;
1579 int iaFirst = 0;
1580 trRefDlight_t *light, *oldLight;
1581 int i;
1582 long sum = 0;
1583 unsigned char *stencilReadback;
1584 qboolean calcSum;
1585
1586 qglColor4f(1.0f, 0.0f, 0.0f, 0.05f);
1587
1588 GL_Program(0);
1589 GL_Cull(CT_TWO_SIDED);
1590 GL_SelectTexture(0);
1591 GL_Bind(tr.whiteImage);
1592
1593 stencilReadback = ri.Hunk_AllocateTempMemory(glConfig.vidWidth * glConfig.vidHeight);
1594
1595 // don't write to the color buffer or depth buffer
1596 if(r_showOcclusionQueries->integer)
1597 {
1598 GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
1599 }
1600 else
1601 {
1602 GL_State(GLS_COLORMASK_BITS | GLS_STENCILTEST_ENABLE);
1603 }
1604
1605 oldLight = NULL;
1606 calcSum = qtrue;
1607
1608 // loop trough all light interactions and render the light OBB for each last interaction
1609 for(iaCount = 0, ia = &interactions[0]; iaCount < numInteractions;)
1610 {
1611 backEnd.currentLight = light = ia->dlight;
1612
1613 if(light != oldLight)
1614 {
1615 iaFirst = iaCount;
1616 }
1617
1618 if(!calcSum)
1619 {
1620 ia->occlusionQuerySamples = sum;
1621 }
1622
1623 if(!ia->next)
1624 {
1625 // last interaction of current light
1626 if(calcSum)
1627 {
1628 if(R_CullLightPoint(light, backEnd.viewParms.or.origin) == CULL_OUT)
1629 {
1630 // clear stencil buffer
1631 qglClear(GL_STENCIL_BUFFER_BIT);
1632
1633 // set the reference stencil value
1634 //qglClearStencil(0U);
1635 qglStencilMask(~0);
1636 qglStencilFunc(GL_ALWAYS, 0, ~0);
1637 qglStencilOp(GL_KEEP, GL_INCR, GL_INCR);
1638
1639 R_RotateForDlight(light, &backEnd.viewParms, &backEnd.or);
1640 qglLoadMatrixf(backEnd.or.modelViewMatrix);
1641
1642 qglBegin(GL_QUADS);
1643
1644 qglVertex3f(light->localBounds[0][0], light->localBounds[0][1], light->localBounds[0][2]);
1645 qglVertex3f(light->localBounds[0][0], light->localBounds[1][1], light->localBounds[0][2]);
1646 qglVertex3f(light->localBounds[0][0], light->localBounds[1][1], light->localBounds[1][2]);
1647 qglVertex3f(light->localBounds[0][0], light->localBounds[0][1], light->localBounds[1][2]);
1648
1649 qglVertex3f(light->localBounds[1][0], light->localBounds[0][1], light->localBounds[0][2]);
1650 qglVertex3f(light->localBounds[1][0], light->localBounds[1][1], light->localBounds[0][2]);
1651 qglVertex3f(light->localBounds[1][0], light->localBounds[1][1], light->localBounds[1][2]);
1652 qglVertex3f(light->localBounds[1][0], light->localBounds[0][1], light->localBounds[1][2]);
1653
1654 qglVertex3f(light->localBounds[0][0], light->localBounds[0][1], light->localBounds[1][2]);
1655 qglVertex3f(light->localBounds[0][0], light->localBounds[1][1], light->localBounds[1][2]);
1656 qglVertex3f(light->localBounds[1][0], light->localBounds[1][1], light->localBounds[1][2]);
1657 qglVertex3f(light->localBounds[1][0], light->localBounds[0][1], light->localBounds[1][2]);
1658
1659 qglVertex3f(light->localBounds[0][0], light->localBounds[0][1], light->localBounds[0][2]);
1660 qglVertex3f(light->localBounds[0][0], light->localBounds[1][1], light->localBounds[0][2]);
1661 qglVertex3f(light->localBounds[1][0], light->localBounds[1][1], light->localBounds[0][2]);
1662 qglVertex3f(light->localBounds[1][0], light->localBounds[0][1], light->localBounds[0][2]);
1663
1664 qglVertex3f(light->localBounds[0][0], light->localBounds[0][1], light->localBounds[0][2]);
1665 qglVertex3f(light->localBounds[0][0], light->localBounds[0][1], light->localBounds[1][2]);
1666 qglVertex3f(light->localBounds[1][0], light->localBounds[0][1], light->localBounds[1][2]);
1667 qglVertex3f(light->localBounds[1][0], light->localBounds[0][1], light->localBounds[0][2]);
1668
1669 qglVertex3f(light->localBounds[0][0], light->localBounds[1][1], light->localBounds[0][2]);
1670 qglVertex3f(light->localBounds[0][0], light->localBounds[1][1], light->localBounds[1][2]);
1671 qglVertex3f(light->localBounds[1][0], light->localBounds[1][1], light->localBounds[1][2]);
1672 qglVertex3f(light->localBounds[1][0], light->localBounds[1][1], light->localBounds[0][2]);
1673
1674 qglEnd();
1675
1676 backEnd.pc.c_occlusionQueries++;
1677 backEnd.pc.c_occlusionQueriesAvailable++;
1678
1679 #if 1
1680 qglReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback);
1681
1682 for(i = 0, sum = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++)
1683 {
1684 sum += stencilReadback[i];
1685 }
1686 #else
1687 // only consider the 2D light scissor of current light
1688 qglReadPixels(ia->scissorX, ia->scissorY, ia->scissorWidth, ia->scissorHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback);
1689
1690 for(i = 0, sum = 0; i < ia->scissorWidth * ia->scissorHeight; i++)
1691 {
1692 sum += stencilReadback[i];
1693 }
1694 #endif
1695
1696 if(!sum)
1697 {
1698 backEnd.pc.c_occlusionQueriesCulled++;
1699 }
1700 }
1701 else
1702 {
1703 sum = 1;
1704 }
1705
1706 // jump back to first interaction of this light copy sum to all interactions
1707 ia = &interactions[iaFirst];
1708 iaCount = iaFirst;
1709 calcSum = qfalse;
1710 }
1711 else
1712 {
1713 if(iaCount < (numInteractions - 1))
1714 {
1715 // jump to next interaction and continue
1716 ia++;
1717 iaCount++;
1718 calcSum = qtrue;
1719 }
1720 else
1721 {
1722 // increase last time to leave for loop
1723 iaCount++;
1724 }
1725 }
1726 }
1727 else
1728 {
1729 // just continue
1730 ia = ia->next;
1731 iaCount++;
1732 }
1733
1734 oldLight = light;
1735 }
1736
1737 // go back to the world modelview matrix
1738 backEnd.or = backEnd.viewParms.world;
1739 qglLoadMatrixf(backEnd.viewParms.world.modelViewMatrix);
1740
1741 // reenable writes to depth and color buffers
1742 GL_State(GLS_DEPTHMASK_TRUE);
1743
1744 ri.Hunk_FreeTempMemory(stencilReadback);
1745 }
1746 #endif
1747
1748 GL_CheckErrors();
1749 }
1750
RB_RenderDebugUtils(interaction_t * interactions,int numInteractions)1751 static void RB_RenderDebugUtils(interaction_t * interactions, int numInteractions)
1752 {
1753 GLimp_LogComment("--- RB_RenderDebugUtils ---\n");
1754
1755 if(r_showLightTransforms->integer)
1756 {
1757 int i;
1758 trRefDlight_t *dl;
1759 vec3_t forward, left, up;
1760 vec3_t tmp;
1761
1762 if(r_dynamicLighting->integer)
1763 {
1764 GL_Program(0);
1765 GL_State(0);
1766 GL_SelectTexture(0);
1767 GL_Bind(tr.whiteImage);
1768
1769 dl = backEnd.refdef.dlights;
1770 for(i = 0; i < backEnd.refdef.numDlights; i++, dl++)
1771 {
1772 // set up the transformation matrix
1773 R_RotateForDlight(dl, &backEnd.viewParms, &backEnd.or);
1774 qglLoadMatrixf(backEnd.or.modelViewMatrix);
1775
1776 MatrixToVectorsFLU(matrixIdentity, forward, left, up);
1777 VectorMA(vec3_origin, 16, forward, forward);
1778 VectorMA(vec3_origin, 16, left, left);
1779 VectorMA(vec3_origin, 16, up, up);
1780
1781 // draw axis
1782 //qglLineWidth(3);
1783 qglBegin(GL_LINES);
1784
1785 qglColor4fv(colorRed);
1786 qglVertex3fv(vec3_origin);
1787 qglVertex3fv(forward);
1788
1789 qglColor4fv(colorGreen);
1790 qglVertex3fv(vec3_origin);
1791 qglVertex3fv(left);
1792
1793 qglColor4fv(colorBlue);
1794 qglVertex3fv(vec3_origin);
1795 qglVertex3fv(up);
1796
1797 qglColor4fv(colorYellow);
1798 qglVertex3fv(vec3_origin);
1799 VectorSubtract(dl->origin, backEnd.or.origin, tmp);
1800 dl->transformed[0] = DotProduct(tmp, backEnd.or.axis[0]);
1801 dl->transformed[1] = DotProduct(tmp, backEnd.or.axis[1]);
1802 dl->transformed[2] = DotProduct(tmp, backEnd.or.axis[2]);
1803 qglVertex3fv(dl->transformed);
1804
1805 qglColor4fv(colorMagenta);
1806 qglVertex3fv(vec3_origin);
1807 qglVertex3fv(dl->l.target);
1808
1809 qglColor4fv(colorCyan);
1810 qglVertex3fv(vec3_origin);
1811 qglVertex3fv(dl->l.right);
1812
1813 qglColor4fv(colorWhite);
1814 qglVertex3fv(vec3_origin);
1815 qglVertex3fv(dl->l.up);
1816
1817 qglColor4fv(colorMdGrey);
1818 qglVertex3fv(vec3_origin);
1819 VectorAdd(dl->l.target, dl->l.up, tmp);
1820 qglVertex3fv(tmp);
1821
1822 qglEnd();
1823 //qglLineWidth(1);
1824
1825 R_DebugBoundingBox(vec3_origin, dl->localBounds[0], dl->localBounds[1], colorRed);
1826
1827 // go back to the world modelview matrix
1828 backEnd.or = backEnd.viewParms.world;
1829 qglLoadMatrixf(backEnd.viewParms.world.modelViewMatrix);
1830
1831 R_DebugBoundingBox(vec3_origin, dl->worldBounds[0], dl->worldBounds[1], colorGreen);
1832 }
1833 }
1834
1835 if(!(backEnd.refdef.rdflags & RDF_NOWORLDMODEL))
1836 {
1837 GL_Program(0);
1838 GL_State(0);
1839 GL_SelectTexture(0);
1840 GL_Bind(tr.whiteImage);
1841
1842 for(i = 0; i < tr.world->numDlights; i++)
1843 {
1844 dl = &tr.world->dlights[i];
1845
1846 // set up the transformation matrix
1847 R_RotateForDlight(dl, &backEnd.viewParms, &backEnd.or);
1848 qglLoadMatrixf(backEnd.or.modelViewMatrix);
1849
1850 MatrixToVectorsFLU(matrixIdentity, forward, left, up);
1851 VectorMA(vec3_origin, 16, forward, forward);
1852 VectorMA(vec3_origin, 16, left, left);
1853 VectorMA(vec3_origin, 16, up, up);
1854
1855 // draw axis
1856 //qglLineWidth(3);
1857 qglBegin(GL_LINES);
1858
1859 qglColor4fv(colorRed);
1860 qglVertex3fv(vec3_origin);
1861 qglVertex3fv(forward);
1862
1863 qglColor4fv(colorGreen);
1864 qglVertex3fv(vec3_origin);
1865 qglVertex3fv(left);
1866
1867 qglColor4fv(colorBlue);
1868 qglVertex3fv(vec3_origin);
1869 qglVertex3fv(up);
1870
1871 qglColor4fv(colorYellow);
1872 qglVertex3fv(vec3_origin);
1873 VectorSubtract(dl->origin, backEnd.or.origin, tmp);
1874 dl->transformed[0] = DotProduct(tmp, backEnd.or.axis[0]);
1875 dl->transformed[1] = DotProduct(tmp, backEnd.or.axis[1]);
1876 dl->transformed[2] = DotProduct(tmp, backEnd.or.axis[2]);
1877 qglVertex3fv(dl->transformed);
1878
1879 qglColor4fv(colorMagenta);
1880 qglVertex3fv(vec3_origin);
1881 qglVertex3fv(dl->l.target);
1882
1883 qglColor4fv(colorCyan);
1884 qglVertex3fv(vec3_origin);
1885 qglVertex3fv(dl->l.right);
1886
1887 qglColor4fv(colorWhite);
1888 qglVertex3fv(vec3_origin);
1889 qglVertex3fv(dl->l.up);
1890
1891 qglColor4fv(colorMdGrey);
1892 qglVertex3fv(vec3_origin);
1893 VectorAdd(dl->l.target, dl->l.up, tmp);
1894 qglVertex3fv(tmp);
1895
1896 qglEnd();
1897 //qglLineWidth(1);
1898
1899 R_DebugBoundingBox(vec3_origin, dl->localBounds[0], dl->localBounds[1], colorBlue);
1900
1901 // go back to the world modelview matrix
1902 backEnd.or = backEnd.viewParms.world;
1903 qglLoadMatrixf(backEnd.viewParms.world.modelViewMatrix);
1904
1905 R_DebugBoundingBox(vec3_origin, dl->worldBounds[0], dl->worldBounds[1], colorYellow);
1906 }
1907 }
1908 }
1909
1910 if(r_showLightInteractions->integer)
1911 {
1912 interaction_t *ia;
1913 int iaCount;
1914 trRefEntity_t *entity;
1915 surfaceType_t *surface;
1916
1917 GL_Program(0);
1918 GL_State(0);
1919 GL_SelectTexture(0);
1920 GL_Bind(tr.whiteImage);
1921
1922 for(iaCount = 0, ia = &interactions[0]; iaCount < numInteractions;)
1923 {
1924 backEnd.currentEntity = entity = ia->entity;
1925 surface = ia->surface;
1926
1927 R_RotateForEntity(entity, &backEnd.viewParms, &backEnd.or);
1928 qglLoadMatrixf(backEnd.or.modelViewMatrix);
1929
1930 if(*surface == SF_FACE)
1931 {
1932 srfSurfaceFace_t *face;
1933
1934 face = (srfSurfaceFace_t *) surface;
1935 R_DebugBoundingBox(vec3_origin, face->bounds[0], face->bounds[1], colorYellow);
1936 }
1937 else if(*surface == SF_GRID)
1938 {
1939 srfGridMesh_t *grid;
1940
1941 grid = (srfGridMesh_t *) surface;
1942 R_DebugBoundingBox(vec3_origin, grid->meshBounds[0], grid->meshBounds[1], colorMagenta);
1943 }
1944 else if(*surface == SF_TRIANGLES)
1945 {
1946 srfTriangles_t *tri;
1947
1948 tri = (srfTriangles_t *) surface;
1949 R_DebugBoundingBox(vec3_origin, tri->bounds[0], tri->bounds[1], colorCyan);
1950 }
1951 else if(*surface == SF_MDX)
1952 {
1953 R_DebugBoundingBox(vec3_origin, entity->localBounds[0], entity->localBounds[1], colorMdGrey);
1954 }
1955
1956 if(!ia->next)
1957 {
1958 if(iaCount < (numInteractions - 1))
1959 {
1960 // jump to next interaction and continue
1961 ia++;
1962 iaCount++;
1963 }
1964 else
1965 {
1966 // increase last time to leave for loop
1967 iaCount++;
1968 }
1969 }
1970 else
1971 {
1972 // just continue
1973 ia = ia->next;
1974 iaCount++;
1975 }
1976 }
1977
1978 // go back to the world modelview matrix
1979 backEnd.or = backEnd.viewParms.world;
1980 qglLoadMatrixf(backEnd.viewParms.world.modelViewMatrix);
1981 }
1982
1983 if(r_showEntityTransforms->integer)
1984 {
1985 trRefEntity_t *ent;
1986 int i;
1987
1988 GL_Program(0);
1989 GL_State(0);
1990 GL_SelectTexture(0);
1991 GL_Bind(tr.whiteImage);
1992
1993 ent = backEnd.refdef.entities;
1994 for(i = 0; i < backEnd.refdef.numEntities; i++, ent++)
1995 {
1996 if((ent->e.renderfx & RF_THIRD_PERSON) && !backEnd.viewParms.isPortal)
1997 continue;
1998
1999 // set up the transformation matrix
2000 R_RotateForEntity(ent, &backEnd.viewParms, &backEnd.or);
2001 qglLoadMatrixf(backEnd.or.modelViewMatrix);
2002
2003 R_DebugAxis(vec3_origin, matrixIdentity);
2004 R_DebugBoundingBox(vec3_origin, ent->localBounds[0], ent->localBounds[1], colorMagenta);
2005
2006 // go back to the world modelview matrix
2007 backEnd.or = backEnd.viewParms.world;
2008 qglLoadMatrixf(backEnd.viewParms.world.modelViewMatrix);
2009
2010 R_DebugBoundingBox(vec3_origin, ent->worldBounds[0], ent->worldBounds[1], colorCyan);
2011 }
2012 }
2013
2014 if(r_showLightScissors->integer)
2015 {
2016 interaction_t *ia;
2017 int iaCount;
2018
2019 GL_Program(0);
2020 GL_SelectTexture(0);
2021 GL_Bind(tr.whiteImage);
2022 GL_State(GLS_POLYMODE_LINE | GLS_DEPTHTEST_DISABLE);
2023 GL_Cull(CT_TWO_SIDED);
2024
2025 // set 2D virtual screen size
2026 qglPushMatrix();
2027 qglLoadIdentity();
2028 qglMatrixMode(GL_PROJECTION);
2029 qglPushMatrix();
2030 qglLoadIdentity();
2031 qglOrtho(backEnd.viewParms.viewportX,
2032 backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
2033 backEnd.viewParms.viewportY,
2034 backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight, -99999, 99999);
2035
2036 for(iaCount = 0, ia = &interactions[0]; iaCount < numInteractions;)
2037 {
2038 if(qglDepthBoundsEXT)
2039 {
2040 if(ia->noDepthBoundsTest)
2041 {
2042 qglColor4fv(colorRed);
2043 }
2044 else
2045 {
2046 qglColor4fv(colorGreen);
2047 }
2048
2049 qglBegin(GL_QUADS);
2050 qglVertex2f(ia->scissorX, ia->scissorY);
2051 qglVertex2f(ia->scissorX + ia->scissorWidth - 1, ia->scissorY);
2052 qglVertex2f(ia->scissorX + ia->scissorWidth - 1, ia->scissorY + ia->scissorHeight - 1);
2053 qglVertex2f(ia->scissorX, ia->scissorY + ia->scissorHeight - 1);
2054 qglEnd();
2055 }
2056 else
2057 {
2058 qglBegin(GL_QUADS);
2059 qglColor4fv(colorRed);
2060 qglVertex2f(ia->scissorX, ia->scissorY);
2061 qglColor4fv(colorGreen);
2062 qglVertex2f(ia->scissorX + ia->scissorWidth - 1, ia->scissorY);
2063 qglColor4fv(colorBlue);
2064 qglVertex2f(ia->scissorX + ia->scissorWidth - 1, ia->scissorY + ia->scissorHeight - 1);
2065 qglColor4fv(colorWhite);
2066 qglVertex2f(ia->scissorX, ia->scissorY + ia->scissorHeight - 1);
2067 qglEnd();
2068 }
2069
2070 if(!ia->next)
2071 {
2072 if(iaCount < (numInteractions - 1))
2073 {
2074 // jump to next interaction and continue
2075 ia++;
2076 iaCount++;
2077 }
2078 else
2079 {
2080 // increase last time to leave for loop
2081 iaCount++;
2082 }
2083 }
2084 else
2085 {
2086 // just continue
2087 ia = ia->next;
2088 iaCount++;
2089 }
2090 }
2091
2092 qglPopMatrix();
2093 qglMatrixMode(GL_MODELVIEW);
2094 qglPopMatrix();
2095 }
2096
2097 GL_CheckErrors();
2098 }
2099
RB_RenderBloom(void)2100 static void RB_RenderBloom(void)
2101 {
2102 GLimp_LogComment("--- RB_RenderBloom ---\n");
2103
2104 if((backEnd.refdef.rdflags & RDF_NOWORLDMODEL) || !r_drawBloom->integer)
2105 return;
2106
2107 // set 2D virtual screen size
2108 qglPushMatrix();
2109 qglLoadIdentity();
2110 qglMatrixMode(GL_PROJECTION);
2111 qglPushMatrix();
2112 qglLoadIdentity();
2113 qglOrtho(backEnd.viewParms.viewportX,
2114 backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
2115 backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight, -99999, 99999);
2116
2117 if(r_drawBloom->integer == 1)
2118 {
2119 GL_State(GLS_DEPTHTEST_DISABLE);
2120 GL_Cull(CT_TWO_SIDED);
2121
2122 // render contrast
2123 GL_Program(tr.contrastShader.program);
2124 GL_ClientState(tr.contrastShader.attribs);
2125 GL_SetVertexAttribs();
2126
2127 GL_SelectTexture(0);
2128 GL_Bind(tr.currentRenderImage);
2129 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, tr.currentRenderImage->uploadWidth, tr.currentRenderImage->uploadHeight);
2130
2131 // draw viewport
2132 qglBegin(GL_QUADS);
2133 qglVertex2f(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY);
2134 qglVertex2f(backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportY);
2135 qglVertex2f(backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
2136 backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight);
2137 qglVertex2f(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight);
2138 qglEnd();
2139
2140 // render bloom
2141 GL_Program(tr.bloomShader.program);
2142 GL_ClientState(tr.bloomShader.attribs);
2143 GL_SetVertexAttribs();
2144
2145 qglUniform1fARB(tr.bloomShader.u_BlurMagnitude, r_bloomBlur->value);
2146
2147 GL_SelectTexture(1);
2148 GL_Bind(tr.currentRenderNearestImage);
2149 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, tr.currentRenderNearestImage->uploadWidth, tr.currentRenderNearestImage->uploadHeight);
2150
2151 // draw viewport
2152 qglBegin(GL_QUADS);
2153 qglVertex2f(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY);
2154 qglVertex2f(backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportY);
2155 qglVertex2f(backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
2156 backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight);
2157 qglVertex2f(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight);
2158 qglEnd();
2159 }
2160 else if(r_drawBloom->integer == 2)
2161 {
2162 GL_State(GLS_DEPTHTEST_DISABLE);
2163 GL_Cull(CT_TWO_SIDED);
2164
2165 // render contrast
2166 GL_Program(tr.contrastShader.program);
2167 GL_ClientState(tr.contrastShader.attribs);
2168 GL_SetVertexAttribs();
2169
2170 GL_SelectTexture(0);
2171 GL_Bind(tr.currentRenderImage);
2172 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, tr.currentRenderImage->uploadWidth, tr.currentRenderImage->uploadHeight);
2173
2174 // draw viewport
2175 qglBegin(GL_QUADS);
2176 qglVertex2f(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY);
2177 qglVertex2f(backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportY);
2178 qglVertex2f(backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
2179 backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight);
2180 qglVertex2f(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight);
2181 qglEnd();
2182
2183 // render blurX
2184 GL_Program(tr.blurXShader.program);
2185 GL_ClientState(tr.blurXShader.attribs);
2186 GL_SetVertexAttribs();
2187
2188 qglUniform1fARB(tr.blurXShader.u_BlurMagnitude, r_bloomBlur->value);
2189
2190 GL_Bind(tr.currentRenderNearestImage);
2191 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, tr.currentRenderNearestImage->uploadWidth, tr.currentRenderNearestImage->uploadHeight);
2192
2193 // draw viewport
2194 qglBegin(GL_QUADS);
2195 qglVertex2f(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY);
2196 qglVertex2f(backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportY);
2197 qglVertex2f(backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
2198 backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight);
2199 qglVertex2f(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight);
2200 qglEnd();
2201
2202 // render blurY
2203 GL_Program(tr.blurYShader.program);
2204 GL_ClientState(tr.blurYShader.attribs);
2205 GL_SetVertexAttribs();
2206
2207 qglUniform1fARB(tr.blurYShader.u_BlurMagnitude, r_bloomBlur->value);
2208
2209 GL_Bind(tr.currentRenderNearestImage);
2210 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, tr.currentRenderNearestImage->uploadWidth, tr.currentRenderNearestImage->uploadHeight);
2211
2212 // draw viewport
2213 qglBegin(GL_QUADS);
2214 qglVertex2f(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY);
2215 qglVertex2f(backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportY);
2216 qglVertex2f(backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
2217 backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight);
2218 qglVertex2f(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight);
2219 qglEnd();
2220
2221 // render bloom
2222 GL_Program(tr.bloomShader.program);
2223 GL_ClientState(tr.bloomShader.attribs);
2224 GL_SetVertexAttribs();
2225
2226 qglUniform1fARB(tr.bloomShader.u_BlurMagnitude, r_bloomBlur->value);
2227
2228 GL_SelectTexture(0);
2229 GL_Bind(tr.currentRenderImage);
2230
2231 GL_SelectTexture(1);
2232 GL_Bind(tr.currentRenderNearestImage);
2233
2234 // draw viewport
2235 qglBegin(GL_QUADS);
2236 qglVertex2f(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY);
2237 qglVertex2f(backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportY);
2238 qglVertex2f(backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
2239 backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight);
2240 qglVertex2f(backEnd.viewParms.viewportX, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight);
2241 qglEnd();
2242 }
2243
2244 // go back to 3D
2245 qglMatrixMode(GL_PROJECTION);
2246 qglPopMatrix();
2247 qglMatrixMode(GL_MODELVIEW);
2248 qglPopMatrix();
2249 }
2250
2251 /*
2252 ==================
2253 RB_RenderDrawSurfList
2254 ==================
2255 */
RB_RenderDrawSurfList(drawSurf_t * drawSurfs,int numDrawSurfs,interaction_t * interactions,int numInteractions)2256 static void RB_RenderDrawSurfList(drawSurf_t * drawSurfs, int numDrawSurfs, interaction_t * interactions, int numInteractions)
2257 {
2258 float originalTime;
2259
2260 if(r_logFile->integer)
2261 {
2262 // don't just call LogComment, or we will get a call to va() every frame!
2263 GLimp_LogComment(va("--- RB_RenderDrawSurfList( %i surfaces, %i interactions ) ---\n", numDrawSurfs, numInteractions));
2264 }
2265
2266 GL_CheckErrors();
2267
2268 // save original time for entity shader offsets
2269 originalTime = backEnd.refdef.floatTime;
2270
2271 // clear the z buffer, set the modelview, etc
2272 RB_BeginDrawingView();
2273
2274 backEnd.pc.c_surfaces += numDrawSurfs;
2275
2276 // draw everything that is opaque
2277 RB_RenderDrawSurfaces(originalTime, drawSurfs, numDrawSurfs, qtrue);
2278
2279 // try to cull lights using occlusion queries
2280 RB_RenderOcclusionQueries(interactions, numInteractions);
2281
2282 if(r_shadows->integer == 3)
2283 {
2284 // render dynamic shadowing and lighting using stencil shadow volumes
2285 RB_RenderInteractionsStencilShadowed(originalTime, interactions, numInteractions);
2286 }
2287 else
2288 {
2289 // render dynamic lighting
2290 RB_RenderInteractions(originalTime, interactions, numInteractions);
2291 }
2292
2293 // draw everything that is translucent
2294 RB_RenderDrawSurfaces(originalTime, drawSurfs, numDrawSurfs, qfalse);
2295
2296 // add the sun flare
2297 RB_DrawSun();
2298
2299 // add light flares on lights that aren't obscured
2300 RB_RenderFlares();
2301
2302 // render bloom post process effect
2303 RB_RenderBloom();
2304
2305 // render debug information
2306 RB_RenderDebugUtils(interactions, numInteractions);
2307 }
2308
2309
2310 /*
2311 ============================================================================
2312
2313 RENDER BACK END THREAD FUNCTIONS
2314
2315 ============================================================================
2316 */
2317
2318
2319 /*
2320 =============
2321 RE_StretchRaw
2322
2323 FIXME: not exactly backend
2324 Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle.
2325 Used for cinematics.
2326 =============
2327 */
RE_StretchRaw(int x,int y,int w,int h,int cols,int rows,const byte * data,int client,qboolean dirty)2328 void RE_StretchRaw(int x, int y, int w, int h, int cols, int rows, const byte * data, int client, qboolean dirty)
2329 {
2330 int i, j;
2331 int start, end;
2332
2333 if(!tr.registered)
2334 {
2335 return;
2336 }
2337 R_SyncRenderThread();
2338
2339 // we definately want to sync every frame for the cinematics
2340 qglFinish();
2341
2342 start = end = 0;
2343 if(r_speeds->integer)
2344 {
2345 start = ri.Milliseconds();
2346 }
2347
2348 // make sure rows and cols are powers of 2
2349 for(i = 0; (1 << i) < cols; i++)
2350 {
2351 }
2352 for(j = 0; (1 << j) < rows; j++)
2353 {
2354 }
2355 if((1 << i) != cols || (1 << j) != rows)
2356 {
2357 ri.Error(ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows);
2358 }
2359
2360 GL_SelectTexture(0);
2361 GL_Bind(tr.scratchImage[client]);
2362
2363 // if the scratchImage isn't in the format we want, specify it as a new texture
2364 if(cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height)
2365 {
2366 tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
2367 tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
2368 qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
2369 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2370 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2371 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2372 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2373 }
2374 else
2375 {
2376 if(dirty)
2377 {
2378 // otherwise, just subimage upload it so that drivers can tell we are going to be changing
2379 // it and don't try and do a texture compression
2380 qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data);
2381 }
2382 }
2383
2384 if(r_speeds->integer)
2385 {
2386 end = ri.Milliseconds();
2387 ri.Printf(PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start);
2388 }
2389
2390 RB_SetGL2D();
2391
2392 qglColor3f(tr.identityLight, tr.identityLight, tr.identityLight);
2393
2394 qglBegin(GL_QUADS);
2395 qglTexCoord2f(0.5f / cols, 0.5f / rows);
2396 qglVertex2f(x, y);
2397 qglTexCoord2f((cols - 0.5f) / cols, 0.5f / rows);
2398 qglVertex2f(x + w, y);
2399 qglTexCoord2f((cols - 0.5f) / cols, (rows - 0.5f) / rows);
2400 qglVertex2f(x + w, y + h);
2401 qglTexCoord2f(0.5f / cols, (rows - 0.5f) / rows);
2402 qglVertex2f(x, y + h);
2403 qglEnd();
2404 }
2405
RE_UploadCinematic(int w,int h,int cols,int rows,const byte * data,int client,qboolean dirty)2406 void RE_UploadCinematic(int w, int h, int cols, int rows, const byte * data, int client, qboolean dirty)
2407 {
2408 GL_Bind(tr.scratchImage[client]);
2409
2410 // if the scratchImage isn't in the format we want, specify it as a new texture
2411 if(cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height)
2412 {
2413 tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
2414 tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
2415 qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
2416 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2417 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2418 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2419 qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2420 }
2421 else
2422 {
2423 if(dirty)
2424 {
2425 // otherwise, just subimage upload it so that drivers can tell we are going to be changing
2426 // it and don't try and do a texture compression
2427 qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data);
2428 }
2429 }
2430 }
2431
2432
2433 /*
2434 =============
2435 RB_SetColor
2436 =============
2437 */
RB_SetColor(const void * data)2438 const void *RB_SetColor(const void *data)
2439 {
2440 const setColorCommand_t *cmd;
2441
2442 GLimp_LogComment("--- RB_SetColor ---\n");
2443
2444 cmd = (const setColorCommand_t *)data;
2445
2446 backEnd.color2D[0] = cmd->color[0] * 255;
2447 backEnd.color2D[1] = cmd->color[1] * 255;
2448 backEnd.color2D[2] = cmd->color[2] * 255;
2449 backEnd.color2D[3] = cmd->color[3] * 255;
2450
2451 return (const void *)(cmd + 1);
2452 }
2453
2454 /*
2455 =============
2456 RB_StretchPic
2457 =============
2458 */
RB_StretchPic(const void * data)2459 const void *RB_StretchPic(const void *data)
2460 {
2461 const stretchPicCommand_t *cmd;
2462 shader_t *shader;
2463 int numVerts, numIndexes;
2464
2465 GLimp_LogComment("--- RB_StretchPic ---\n");
2466
2467 cmd = (const stretchPicCommand_t *)data;
2468
2469 if(!backEnd.projection2D)
2470 {
2471 RB_SetGL2D();
2472 }
2473
2474 shader = cmd->shader;
2475 if(shader != tess.surfaceShader)
2476 {
2477 if(tess.numIndexes)
2478 {
2479 Tess_End();
2480 }
2481 backEnd.currentEntity = &backEnd.entity2D;
2482 Tess_Begin(shader, NULL, -1, 0, qfalse, qfalse);
2483 }
2484
2485 Tess_CheckOverflow(4, 6);
2486 numVerts = tess.numVertexes;
2487 numIndexes = tess.numIndexes;
2488
2489 tess.numVertexes += 4;
2490 tess.numIndexes += 6;
2491
2492 tess.indexes[numIndexes] = numVerts + 3;
2493 tess.indexes[numIndexes + 1] = numVerts + 0;
2494 tess.indexes[numIndexes + 2] = numVerts + 2;
2495 tess.indexes[numIndexes + 3] = numVerts + 2;
2496 tess.indexes[numIndexes + 4] = numVerts + 0;
2497 tess.indexes[numIndexes + 5] = numVerts + 1;
2498
2499 *(int *)tess.colors[numVerts] =
2500 *(int *)tess.colors[numVerts + 1] =
2501 *(int *)tess.colors[numVerts + 2] = *(int *)tess.colors[numVerts + 3] = *(int *)backEnd.color2D;
2502
2503 tess.xyz[numVerts][0] = cmd->x;
2504 tess.xyz[numVerts][1] = cmd->y;
2505 tess.xyz[numVerts][2] = 0;
2506 tess.xyz[numVerts][3] = 1;
2507
2508 tess.texCoords[numVerts][0][0] = cmd->s1;
2509 tess.texCoords[numVerts][0][1] = cmd->t1;
2510
2511 tess.xyz[numVerts + 1][0] = cmd->x + cmd->w;
2512 tess.xyz[numVerts + 1][1] = cmd->y;
2513 tess.xyz[numVerts + 1][2] = 0;
2514 tess.xyz[numVerts + 1][3] = 1;
2515
2516 tess.texCoords[numVerts + 1][0][0] = cmd->s2;
2517 tess.texCoords[numVerts + 1][0][1] = cmd->t1;
2518
2519 tess.xyz[numVerts + 2][0] = cmd->x + cmd->w;
2520 tess.xyz[numVerts + 2][1] = cmd->y + cmd->h;
2521 tess.xyz[numVerts + 2][2] = 0;
2522 tess.xyz[numVerts + 2][3] = 1;
2523
2524 tess.texCoords[numVerts + 2][0][0] = cmd->s2;
2525 tess.texCoords[numVerts + 2][0][1] = cmd->t2;
2526
2527 tess.xyz[numVerts + 3][0] = cmd->x;
2528 tess.xyz[numVerts + 3][1] = cmd->y + cmd->h;
2529 tess.xyz[numVerts + 3][2] = 0;
2530 tess.xyz[numVerts + 3][3] = 1;
2531
2532 tess.texCoords[numVerts + 3][0][0] = cmd->s1;
2533 tess.texCoords[numVerts + 3][0][1] = cmd->t2;
2534
2535 return (const void *)(cmd + 1);
2536 }
2537
2538
2539 /*
2540 =============
2541 RB_DrawSurfs
2542 =============
2543 */
RB_DrawSurfs(const void * data)2544 const void *RB_DrawSurfs(const void *data)
2545 {
2546 const drawSurfsCommand_t *cmd;
2547
2548 GLimp_LogComment("--- RB_DrawSurfs ---\n");
2549
2550 // finish any 2D drawing if needed
2551 if(tess.numIndexes)
2552 {
2553 Tess_End();
2554 }
2555
2556 cmd = (const drawSurfsCommand_t *)data;
2557
2558 backEnd.refdef = cmd->refdef;
2559 backEnd.viewParms = cmd->viewParms;
2560
2561 RB_RenderDrawSurfList(cmd->drawSurfs, cmd->numDrawSurfs, cmd->interactions, cmd->numInteractions);
2562
2563 return (const void *)(cmd + 1);
2564 }
2565
2566
2567 /*
2568 =============
2569 RB_DrawBuffer
2570 =============
2571 */
RB_DrawBuffer(const void * data)2572 const void *RB_DrawBuffer(const void *data)
2573 {
2574 const drawBufferCommand_t *cmd;
2575
2576 GLimp_LogComment("--- RB_DrawBuffer ---\n");
2577
2578 cmd = (const drawBufferCommand_t *)data;
2579
2580 qglDrawBuffer(cmd->buffer);
2581
2582 // clear screen for debugging
2583 if(r_clear->integer)
2584 {
2585 // qglClearColor(1, 0, 0.5, 1);
2586 qglClearColor(0, 0, 0, 1);
2587 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2588 }
2589
2590 return (const void *)(cmd + 1);
2591 }
2592
2593 /*
2594 ===============
2595 RB_ShowImages
2596
2597 Draw all the images to the screen, on top of whatever
2598 was there. This is used to test for texture thrashing.
2599
2600 Also called by RE_EndRegistration
2601 ===============
2602 */
RB_ShowImages(void)2603 void RB_ShowImages(void)
2604 {
2605 int i;
2606 image_t *image;
2607 float x, y, w, h;
2608 int start, end;
2609
2610 GLimp_LogComment("--- RB_ShowImages ---\n");
2611
2612 if(!backEnd.projection2D)
2613 {
2614 RB_SetGL2D();
2615 }
2616
2617 qglClear(GL_COLOR_BUFFER_BIT);
2618
2619 qglFinish();
2620
2621 GL_SelectTexture(0);
2622
2623 start = ri.Milliseconds();
2624
2625 for(i = 0; i < tr.numImages; i++)
2626 {
2627 image = tr.images[i];
2628
2629 w = glConfig.vidWidth / 20;
2630 h = glConfig.vidHeight / 15;
2631 x = i % 20 * w;
2632 y = i / 20 * h;
2633
2634 // show in proportional size in mode 2
2635 if(r_showImages->integer == 2)
2636 {
2637 w *= image->uploadWidth / 512.0f;
2638 h *= image->uploadHeight / 512.0f;
2639 }
2640
2641 GL_Bind(image);
2642 qglBegin(GL_QUADS);
2643 qglTexCoord2f(0, 0);
2644 qglVertex2f(x, y);
2645 qglTexCoord2f(1, 0);
2646 qglVertex2f(x + w, y);
2647 qglTexCoord2f(1, 1);
2648 qglVertex2f(x + w, y + h);
2649 qglTexCoord2f(0, 1);
2650 qglVertex2f(x, y + h);
2651 qglEnd();
2652 }
2653
2654 qglFinish();
2655
2656 end = ri.Milliseconds();
2657 ri.Printf(PRINT_ALL, "%i msec to draw all images\n", end - start);
2658 }
2659
2660
2661 /*
2662 =============
2663 RB_SwapBuffers
2664 =============
2665 */
RB_SwapBuffers(const void * data)2666 const void *RB_SwapBuffers(const void *data)
2667 {
2668 const swapBuffersCommand_t *cmd;
2669
2670 // finish any 2D drawing if needed
2671 if(tess.numIndexes)
2672 {
2673 Tess_End();
2674 }
2675
2676 // texture swapping test
2677 if(r_showImages->integer)
2678 {
2679 RB_ShowImages();
2680 }
2681
2682 cmd = (const swapBuffersCommand_t *)data;
2683
2684 // we measure overdraw by reading back the stencil buffer and
2685 // counting up the number of increments that have happened
2686 if(r_measureOverdraw->integer)
2687 {
2688 int i;
2689 long sum = 0;
2690 unsigned char *stencilReadback;
2691
2692 stencilReadback = ri.Hunk_AllocateTempMemory(glConfig.vidWidth * glConfig.vidHeight);
2693 qglReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback);
2694
2695 for(i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++)
2696 {
2697 sum += stencilReadback[i];
2698 }
2699
2700 backEnd.pc.c_overDraw += sum;
2701 ri.Hunk_FreeTempMemory(stencilReadback);
2702 }
2703
2704
2705 if(!glState.finishCalled)
2706 {
2707 qglFinish();
2708 }
2709
2710 GLimp_LogComment("***************** RB_SwapBuffers *****************\n\n\n");
2711
2712 GLimp_EndFrame();
2713
2714 backEnd.projection2D = qfalse;
2715
2716 return (const void *)(cmd + 1);
2717 }
2718
2719 /*
2720 ====================
2721 RB_ExecuteRenderCommands
2722
2723 This function will be called synchronously if running without
2724 smp extensions, or asynchronously by another thread.
2725 ====================
2726 */
RB_ExecuteRenderCommands(const void * data)2727 void RB_ExecuteRenderCommands(const void *data)
2728 {
2729 int t1, t2;
2730
2731 GLimp_LogComment("--- RB_ExecuteRenderCommands ---\n");
2732
2733 t1 = ri.Milliseconds();
2734
2735 if(!r_smp->integer || data == backEndData[0]->commands.cmds)
2736 {
2737 backEnd.smpFrame = 0;
2738 }
2739 else
2740 {
2741 backEnd.smpFrame = 1;
2742 }
2743
2744 while(1)
2745 {
2746 switch (*(const int *)data)
2747 {
2748 case RC_SET_COLOR:
2749 data = RB_SetColor(data);
2750 break;
2751 case RC_STRETCH_PIC:
2752 data = RB_StretchPic(data);
2753 break;
2754 case RC_DRAW_SURFS:
2755 data = RB_DrawSurfs(data);
2756 break;
2757 case RC_DRAW_BUFFER:
2758 data = RB_DrawBuffer(data);
2759 break;
2760 case RC_SWAP_BUFFERS:
2761 data = RB_SwapBuffers(data);
2762 break;
2763 case RC_SCREENSHOT:
2764 data = RB_TakeScreenshotCmd(data);
2765 break;
2766
2767 case RC_END_OF_LIST:
2768 default:
2769 // stop rendering on this thread
2770 t2 = ri.Milliseconds();
2771 backEnd.pc.msec = t2 - t1;
2772 return;
2773 }
2774 }
2775 }
2776
2777
2778 /*
2779 ================
2780 RB_RenderThread
2781 ================
2782 */
RB_RenderThread(void)2783 void RB_RenderThread(void)
2784 {
2785 const void *data;
2786
2787 // wait for either a rendering command or a quit command
2788 while(1)
2789 {
2790 // sleep until we have work to do
2791 data = GLimp_RendererSleep();
2792
2793 if(!data)
2794 {
2795 return; // all done, renderer is shutting down
2796 }
2797
2798 renderThreadActive = qtrue;
2799
2800 RB_ExecuteRenderCommands(data);
2801
2802 renderThreadActive = qfalse;
2803 }
2804 }
2805