2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
24 // used for dlight push checking and other things
27 // used for visibility checking
28 qbyte r_pvsbits[(MAX_MAP_LEAFS+7)>>3];
32 matrix4x4_t r_identitymatrix;
34 int c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights;
36 // true during envmap command capture
52 // 8.8 fraction of base light value
53 unsigned short d_lightstylevalue[256];
55 cvar_t r_drawentities = {0, "r_drawentities","1"};
56 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
57 cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0"};
58 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
59 cvar_t r_speeds = {0, "r_speeds","0"};
60 cvar_t r_fullbright = {0, "r_fullbright","0"};
61 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
62 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
63 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
64 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
66 cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
67 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
68 cvar_t gl_fogred = {0, "gl_fogred","0.3"};
69 cvar_t gl_foggreen = {0, "gl_foggreen","0.3"};
70 cvar_t gl_fogblue = {0, "gl_fogblue","0.3"};
71 cvar_t gl_fogstart = {0, "gl_fogstart", "0"};
72 cvar_t gl_fogend = {0, "gl_fogend","0"};
74 cvar_t r_textureunits = {0, "r_textureunits", "32"};
76 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1"};
77 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1"};
78 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1"};
82 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
85 for (i = 0;i < verts;i++)
96 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
99 for (i = 0;i < verts;i++)
113 For program optimization
116 qboolean intimerefresh = 0;
117 static void R_TimeRefresh_f (void)
120 float start, stop, time;
123 start = Sys_DoubleTime ();
124 for (i = 0;i < 128;i++)
126 r_refdef.viewangles[0] = 0;
127 r_refdef.viewangles[1] = i/128.0*360.0;
128 r_refdef.viewangles[2] = 0;
132 stop = Sys_DoubleTime ();
135 Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
140 float fog_density, fog_red, fog_green, fog_blue;
142 qboolean oldgl_fogenable;
143 void R_SetupFog(void)
145 if (gamemode == GAME_NEHAHRA)
147 if (gl_fogenable.integer)
149 oldgl_fogenable = true;
150 fog_density = gl_fogdensity.value;
151 fog_red = gl_fogred.value;
152 fog_green = gl_foggreen.value;
153 fog_blue = gl_fogblue.value;
155 else if (oldgl_fogenable)
157 oldgl_fogenable = false;
166 fogcolor[0] = fog_red = bound(0.0f, fog_red , 1.0f);
167 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
168 fogcolor[2] = fog_blue = bound(0.0f, fog_blue , 1.0f);
173 fogdensity = -4000.0f / (fog_density * fog_density);
174 // fog color was already set
180 // FIXME: move this to client?
183 if (gamemode == GAME_NEHAHRA)
185 Cvar_Set("gl_fogenable", "0");
186 Cvar_Set("gl_fogdensity", "0.2");
187 Cvar_Set("gl_fogred", "0.3");
188 Cvar_Set("gl_foggreen", "0.3");
189 Cvar_Set("gl_fogblue", "0.3");
191 fog_density = fog_red = fog_green = fog_blue = 0.0f;
194 // FIXME: move this to client?
195 void FOG_registercvars(void)
197 if (gamemode == GAME_NEHAHRA)
199 Cvar_RegisterVariable (&gl_fogenable);
200 Cvar_RegisterVariable (&gl_fogdensity);
201 Cvar_RegisterVariable (&gl_fogred);
202 Cvar_RegisterVariable (&gl_foggreen);
203 Cvar_RegisterVariable (&gl_fogblue);
204 Cvar_RegisterVariable (&gl_fogstart);
205 Cvar_RegisterVariable (&gl_fogend);
209 void gl_main_start(void)
213 void gl_main_shutdown(void)
217 extern void CL_ParseEntityLump(char *entitystring);
218 void gl_main_newmap(void)
221 char *entities, entname[MAX_QPATH];
225 strcpy(entname, cl.worldmodel->name);
226 l = strlen(entname) - 4;
227 if (l >= 0 && !strcmp(entname + l, ".bsp"))
229 strcpy(entname + l, ".ent");
230 if ((entities = FS_LoadFile(entname, true)))
232 CL_ParseEntityLump(entities);
237 if (cl.worldmodel->brush.entities)
238 CL_ParseEntityLump(cl.worldmodel->brush.entities);
242 void GL_Main_Init(void)
244 Matrix4x4_CreateIdentity(&r_identitymatrix);
245 // FIXME: move this to client?
247 Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
248 Cvar_RegisterVariable (&r_drawentities);
249 Cvar_RegisterVariable (&r_drawviewmodel);
250 Cvar_RegisterVariable (&r_shadows);
251 Cvar_RegisterVariable (&r_shadow_staticworldlights);
252 Cvar_RegisterVariable (&r_speeds);
253 Cvar_RegisterVariable (&r_fullbrights);
254 Cvar_RegisterVariable (&r_wateralpha);
255 Cvar_RegisterVariable (&r_dynamic);
256 Cvar_RegisterVariable (&r_fullbright);
257 Cvar_RegisterVariable (&r_textureunits);
258 Cvar_RegisterVariable (&r_shadow_cull);
259 Cvar_RegisterVariable (&r_lerpsprites);
260 Cvar_RegisterVariable (&r_lerpmodels);
261 Cvar_RegisterVariable (&r_waterscroll);
262 if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ)
263 Cvar_SetValue("r_fullbrights", 0);
264 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
267 vec3_t r_farclip_origin;
268 vec3_t r_farclip_direction;
269 vec_t r_farclip_directiondist;
270 vec_t r_farclip_meshfarclip;
271 int r_farclip_directionbit0;
272 int r_farclip_directionbit1;
273 int r_farclip_directionbit2;
275 // start a farclip measuring session
276 void R_FarClip_Start(vec3_t origin, vec3_t direction, vec_t startfarclip)
278 VectorCopy(origin, r_farclip_origin);
279 VectorCopy(direction, r_farclip_direction);
280 r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
281 r_farclip_directionbit0 = r_farclip_direction[0] < 0;
282 r_farclip_directionbit1 = r_farclip_direction[1] < 0;
283 r_farclip_directionbit2 = r_farclip_direction[2] < 0;
284 r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
287 // enlarge farclip to accomodate box
288 void R_FarClip_Box(vec3_t mins, vec3_t maxs)
291 d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
292 + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
293 + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
294 if (r_farclip_meshfarclip < d)
295 r_farclip_meshfarclip = d;
298 // return farclip value
299 float R_FarClip_Finish(void)
301 return r_farclip_meshfarclip - r_farclip_directiondist;
304 extern void R_Textures_Init(void);
305 extern void Mod_RenderInit(void);
306 extern void GL_Draw_Init(void);
307 extern void GL_Main_Init(void);
308 extern void R_Shadow_Init(void);
309 extern void GL_Models_Init(void);
310 extern void R_Sky_Init(void);
311 extern void GL_Surf_Init(void);
312 extern void R_Crosshairs_Init(void);
313 extern void R_Light_Init(void);
314 extern void R_Particles_Init(void);
315 extern void R_Explosion_Init(void);
316 extern void ui_init(void);
317 extern void gl_backend_init(void);
318 extern void Sbar_Init(void);
319 extern void R_LightningBeams_Init(void);
321 void Render_Init(void)
339 R_LightningBeams_Init();
347 extern char *ENGINE_EXTENSIONS;
350 VID_CheckExtensions();
352 // LordHavoc: report supported extensions
353 Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
356 int R_CullBox(const vec3_t mins, const vec3_t maxs)
360 for (i = 0;i < 4;i++)
367 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
371 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
375 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
379 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
383 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
387 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
391 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
395 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
403 #define VIS_CullBox(mins,maxs) (R_CullBox((mins), (maxs)) || (cl.worldmodel && cl.worldmodel->brush.BoxTouchingPVS && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, r_pvsbits, (mins), (maxs))))
405 //==================================================================================
407 static void R_MarkEntities (void)
410 entity_render_t *ent;
412 ent = &cl_entities[0].render;
413 Matrix4x4_CreateIdentity(&ent->matrix);
414 Matrix4x4_CreateIdentity(&ent->inversematrix);
417 R_FarClip_Box(cl.worldmodel->normalmins, cl.worldmodel->normalmaxs);
419 if (!r_drawentities.integer)
422 for (i = 0;i < r_refdef.numentities;i++)
424 ent = r_refdef.entities[i];
425 Mod_CheckLoaded(ent->model);
426 // some of the renderer still relies on origin...
427 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
428 // some of the renderer still relies on scale...
429 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
430 R_LerpAnimation(ent);
431 R_UpdateEntLights(ent);
432 if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
433 && !VIS_CullBox(ent->mins, ent->maxs))
435 ent->visframe = r_framecount;
436 R_FarClip_Box(ent->mins, ent->maxs);
441 // only used if skyrendermasked, and normally returns false
442 int R_DrawBrushModelsSky (void)
445 entity_render_t *ent;
447 if (!r_drawentities.integer)
451 for (i = 0;i < r_refdef.numentities;i++)
453 ent = r_refdef.entities[i];
454 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
456 ent->model->DrawSky(ent);
469 void R_DrawViewModel (void)
471 entity_render_t *ent;
473 // FIXME: move these checks to client
474 if (!r_drawviewmodel.integer || chase_active.integer || envmap || !r_drawentities.integer || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model)
477 ent = &cl.viewent.render;
478 Mod_CheckLoaded(ent->model);
479 R_LerpAnimation(ent);
480 Matrix4x4_CreateFromQuakeEntity(&ent->matrix, ent->origin[0], ent->origin[1], ent->origin[2], -ent->angles[0], ent->angles[1], ent->angles[2], ent->scale);
481 Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix);
482 R_UpdateEntLights(ent);
483 ent->model->Draw(ent);
487 void R_DrawNoModel(entity_render_t *ent);
491 entity_render_t *ent;
493 if (!r_drawentities.integer)
496 for (i = 0;i < r_refdef.numentities;i++)
498 ent = r_refdef.entities[i];
499 if (ent->visframe == r_framecount)
501 if (ent->model && ent->model->Draw != NULL)
502 ent->model->Draw(ent);
509 void R_DrawFakeShadows (void)
512 entity_render_t *ent;
514 ent = &cl_entities[0].render;
515 if (ent->model && ent->model->DrawFakeShadow)
516 ent->model->DrawFakeShadow(ent);
518 if (!r_drawentities.integer)
520 for (i = 0;i < r_refdef.numentities;i++)
522 ent = r_refdef.entities[i];
523 if ((ent->flags & RENDER_SHADOW) && ent->model && ent->model->DrawFakeShadow)
524 ent->model->DrawFakeShadow(ent);
528 #include "r_shadow.h"
530 int shadowframecount = 0;
532 void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float cullradius, float lightradius, vec3_t lightmins, vec3_t lightmaxs, vec3_t clipmins, vec3_t clipmaxs, int lightmarked)
534 vec3_t relativelightorigin;
536 if ((ent->flags & RENDER_SHADOW) && ent->model && ent->model->DrawShadowVolume && !(r_shadow_cull.integer && (ent->maxs[0] < lightmins[0] || ent->mins[0] > lightmaxs[0] || ent->maxs[1] < lightmins[1] || ent->mins[1] > lightmaxs[1] || ent->maxs[2] < lightmins[2] || ent->mins[2] > lightmaxs[2])))
538 Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin);
539 ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius);
543 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light);
545 extern void R_Model_Brush_DrawLightForSurfaceList(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, msurface_t **surflist, int numsurfaces, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
546 void R_ShadowVolumeLighting(int visiblevolumes)
549 entity_render_t *ent;
551 float f, lightradius, cullradius;
552 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, clipmins, clipmaxs;
557 matrix4x4_t matrix_worldtofilter, matrix_worldtoattenuationxyz, matrix_worldtoattenuationz;
558 matrix4x4_t matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
562 memset(&m, 0, sizeof(m));
563 R_Mesh_State_Texture(&m);
565 GL_BlendFunc(GL_ONE, GL_ONE);
567 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
568 qglDisable(GL_CULL_FACE);
569 GL_Color(0.0 * r_colorscale, 0.0125 * r_colorscale, 0.1 * r_colorscale, 1);
572 R_Shadow_Stage_Begin();
574 if (r_shadow_realtime_world.integer)
576 R_Shadow_LoadWorldLightsIfNeeded();
577 for (lnum = 0, wl = r_shadow_worldlightchain;wl;wl = wl->next, lnum++)
579 if (d_lightstylevalue[wl->style] <= 0)
581 if (VIS_CullBox(wl->mins, wl->maxs))
583 if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer)
585 if (R_Shadow_ScissorForBBox(wl->mins, wl->maxs))
588 cullradius = wl->cullradius;
589 lightradius = wl->lightradius;
590 VectorCopy(wl->mins, clipmins);
591 VectorCopy(wl->maxs, clipmaxs);
593 f = d_lightstylevalue[wl->style] * (1.0f / 256.0f);
594 VectorScale(wl->light, f, lightcolor);
597 f = 2 + sin(realtime * M_PI * 4.0);
598 VectorScale(lightcolor, f, lightcolor);
601 if (wl->castshadows && (gl_stencil || visiblevolumes))
604 R_Shadow_Stage_ShadowVolumes();
605 ent = &cl_entities[0].render;
606 if (wl->shadowvolume && r_shadow_staticworldlights.integer)
607 R_Shadow_DrawWorldLightShadowVolume(&ent->matrix, wl);
609 R_TestAndDrawShadowVolume(ent, wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
610 if (r_drawentities.integer)
611 for (i = 0;i < r_refdef.numentities;i++)
612 R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
617 if (wl->castshadows && gl_stencil)
618 R_Shadow_Stage_LightWithShadows();
620 R_Shadow_Stage_LightWithoutShadows();
622 // calculate world to filter matrix
623 Matrix4x4_CreateFromQuakeEntity(&matrix, wl->origin[0], wl->origin[1], wl->origin[2], wl->angles[0], wl->angles[1], wl->angles[2], lightradius);
624 Matrix4x4_Invert_Simple(&matrix_worldtofilter, &matrix);
625 // calculate world to attenuationxyz/xy matrix
626 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5, 0.5, 0.5, 0, 0, 0, 0.5);
627 Matrix4x4_Concat(&matrix_worldtoattenuationxyz, &matrix, &matrix_worldtofilter);
628 // calculate world to attenuationz matrix
629 matrix.m[0][0] = 0;matrix.m[0][1] = 0;matrix.m[0][2] = 0.5;matrix.m[0][3] = 0.5;
630 matrix.m[1][0] = 0;matrix.m[1][1] = 0;matrix.m[1][2] = 0 ;matrix.m[1][3] = 0.5;
631 matrix.m[2][0] = 0;matrix.m[2][1] = 0;matrix.m[2][2] = 0 ;matrix.m[2][3] = 0.5;
632 matrix.m[3][0] = 0;matrix.m[3][1] = 0;matrix.m[3][2] = 0 ;matrix.m[3][3] = 1;
633 Matrix4x4_Concat(&matrix_worldtoattenuationz, &matrix, &matrix_worldtofilter);
635 ent = &cl_entities[0].render;
636 if (ent->model && ent->model->DrawLight)
638 Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
639 Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
640 Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
641 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
642 Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
644 R_Model_Brush_DrawLightForSurfaceList(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, wl->surfaces, wl->numsurfaces, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
646 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
648 if (r_drawentities.integer)
650 for (i = 0;i < r_refdef.numentities;i++)
652 ent = r_refdef.entities[i];
653 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
654 && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
655 && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
657 Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
658 Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
659 Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
660 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
661 Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
662 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
669 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
671 for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++)
673 lightradius = rd->cullradius;
674 clipmins[0] = rd->origin[0] - lightradius;
675 clipmins[1] = rd->origin[1] - lightradius;
676 clipmins[2] = rd->origin[2] - lightradius;
677 clipmaxs[0] = rd->origin[0] + lightradius;
678 clipmaxs[1] = rd->origin[1] + lightradius;
679 clipmaxs[2] = rd->origin[2] + lightradius;
680 if (VIS_CullBox(clipmins, clipmaxs) || R_Shadow_ScissorForBBox(clipmins, clipmaxs))
683 cullradius = RadiusFromBoundsAndOrigin(clipmins, clipmaxs, rd->origin);
684 VectorScale(rd->light, (1.0f / 4096.0f), lightcolor);
686 if (gl_stencil || visiblevolumes)
689 R_Shadow_Stage_ShadowVolumes();
690 ent = &cl_entities[0].render;
691 R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
692 if (r_drawentities.integer)
694 for (i = 0;i < r_refdef.numentities;i++)
696 ent = r_refdef.entities[i];
698 R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
706 R_Shadow_Stage_LightWithShadows();
708 R_Shadow_Stage_LightWithoutShadows();
710 // calculate world to filter matrix
711 Matrix4x4_CreateFromQuakeEntity(&matrix, rd->origin[0], rd->origin[1], rd->origin[2], 0, 0, 0, lightradius);
712 Matrix4x4_Invert_Simple(&matrix_worldtofilter, &matrix);
713 // calculate world to attenuationxyz/xy matrix
714 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5, 0.5, 0.5, 0, 0, 0, 0.5);
715 Matrix4x4_Concat(&matrix_worldtoattenuationxyz, &matrix, &matrix_worldtofilter);
716 // calculate world to attenuationz matrix
717 matrix.m[0][0] = 0;matrix.m[0][1] = 0;matrix.m[0][2] = 0.5;matrix.m[0][3] = 0.5;
718 matrix.m[1][0] = 0;matrix.m[1][1] = 0;matrix.m[1][2] = 0 ;matrix.m[1][3] = 0.5;
719 matrix.m[2][0] = 0;matrix.m[2][1] = 0;matrix.m[2][2] = 0 ;matrix.m[2][3] = 0.5;
720 matrix.m[3][0] = 0;matrix.m[3][1] = 0;matrix.m[3][2] = 0 ;matrix.m[3][3] = 1;
721 Matrix4x4_Concat(&matrix_worldtoattenuationz, &matrix, &matrix_worldtofilter);
723 ent = &cl_entities[0].render;
724 if (ent->model && ent->model->DrawLight)
726 Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
727 Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
728 Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
729 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
730 Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
731 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
733 if (r_drawentities.integer)
735 for (i = 0;i < r_refdef.numentities;i++)
737 ent = r_refdef.entities[i];
738 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
739 && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
740 && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
742 Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
743 Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
744 Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
745 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
746 Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
747 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
756 qglEnable(GL_CULL_FACE);
758 R_Shadow_Stage_End();
759 qglDisable(GL_SCISSOR_TEST);
762 static void R_SetFrustum (void)
764 // LordHavoc: note to all quake engine coders, the special case for 90
765 // degrees assumed a square view (wrong), so I removed it, Quake2 has it
768 // rotate VPN right by FOV_X/2 degrees
769 RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
770 frustum[0].dist = DotProduct (r_origin, frustum[0].normal);
771 PlaneClassify(&frustum[0]);
773 // rotate VPN left by FOV_X/2 degrees
774 RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
775 frustum[1].dist = DotProduct (r_origin, frustum[1].normal);
776 PlaneClassify(&frustum[1]);
778 // rotate VPN up by FOV_X/2 degrees
779 RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
780 frustum[2].dist = DotProduct (r_origin, frustum[2].normal);
781 PlaneClassify(&frustum[2]);
783 // rotate VPN down by FOV_X/2 degrees
784 RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
785 frustum[3].dist = DotProduct (r_origin, frustum[3].normal);
786 PlaneClassify(&frustum[3]);
794 static void R_SetupFrame (void)
796 // don't allow cheats in multiplayer
799 if (r_fullbright.integer != 0)
800 Cvar_Set ("r_fullbright", "0");
801 if (r_ambient.value != 0)
802 Cvar_Set ("r_ambient", "0");
807 // build the transformation matrix for the given view angles
808 VectorCopy (r_refdef.vieworg, r_origin);
810 AngleVectors (r_refdef.viewangles, vpn, vright, vup);
816 static void R_BlendView(void)
822 if (r_refdef.viewblend[3] < 0.01f)
825 R_Mesh_Matrix(&r_identitymatrix);
827 memset(&m, 0, sizeof(m));
828 R_Mesh_State_Texture(&m);
830 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
832 GL_DepthTest(false); // magic
833 GL_VertexPointer(vertex3f);
834 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
836 vertex3f[0] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r - vup[0] * r;
837 vertex3f[1] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r - vup[1] * r;
838 vertex3f[2] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r - vup[2] * r;
839 vertex3f[3] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r + vup[0] * r * 3;
840 vertex3f[4] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r + vup[1] * r * 3;
841 vertex3f[5] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r + vup[2] * r * 3;
842 vertex3f[6] = r_origin[0] + vpn[0] * 1.5 + vright[0] * r * 3 - vup[0] * r;
843 vertex3f[7] = r_origin[1] + vpn[1] * 1.5 + vright[1] * r * 3 - vup[1] * r;
844 vertex3f[8] = r_origin[2] + vpn[2] * 1.5 + vright[2] * r * 3 - vup[2] * r;
845 R_Mesh_Draw(3, 1, polygonelements);
852 r_refdef must be set before the first call
855 extern void R_DrawLightningBeams (void);
856 void R_RenderView (void)
858 entity_render_t *world;
859 if (!r_refdef.entities/* || !cl.worldmodel*/)
860 return; //Host_Error ("R_RenderView: NULL worldmodel");
862 if (r_shadow_realtime_world.integer)
866 Con_Printf("Stencil not enabled, turning off r_shadow_realtime_world, please type vid_stencil 1;vid_bitsperpixel 32;vid_restart and try again\n");
867 Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
871 world = &cl_entities[0].render;
873 // FIXME: move to client
875 R_TimeReport("mexplosion");
883 R_TimeReport("setup");
885 if (cl.worldmodel && cl.worldmodel->brush.FatPVS)
886 cl.worldmodel->brush.FatPVS(cl.worldmodel, r_origin, 2, r_pvsbits, sizeof(r_pvsbits));
888 R_WorldVisibility(world);
889 R_TimeReport("worldvis");
891 R_FarClip_Start(r_origin, vpn, 768.0f);
893 r_farclip = R_FarClip_Finish() + 256.0f;
894 R_TimeReport("markentity");
896 GL_SetupView_ViewPort(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
897 if (r_shadow_realtime_world.integer || gl_stencil)
898 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.fov_x, r_refdef.fov_y, 1.0f);
900 GL_SetupView_Mode_Perspective(r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip);
901 GL_SetupView_Orientation_FromEntity (r_refdef.vieworg, r_refdef.viewangles);
902 qglDepthFunc(GL_LEQUAL);
905 R_MeshQueue_BeginScene();
907 R_Shadow_UpdateWorldLightSelection();
909 if (R_DrawBrushModelsSky())
910 R_TimeReport("bmodelsky");
912 // must occur early because it can draw sky
914 R_TimeReport("world");
916 // don't let sound skip if going slow
917 if (!intimerefresh && !r_speeds.integer)
920 R_DrawModels(r_shadow_realtime_world.integer);
921 R_TimeReport("models");
923 if (r_shadows.integer == 1 && !r_shadow_realtime_world.integer)
926 R_TimeReport("fakeshadow");
929 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
931 R_ShadowVolumeLighting(false);
932 R_TimeReport("dynlight");
935 R_DrawLightningBeams();
936 R_TimeReport("lightning");
939 R_TimeReport("particles");
942 R_TimeReport("explosions");
944 R_MeshQueue_RenderTransparent();
945 R_TimeReport("drawtrans");
948 R_TimeReport("coronas");
950 R_DrawWorldCrosshair();
951 R_TimeReport("crosshair");
954 R_TimeReport("blendview");
956 R_MeshQueue_Render();
957 R_MeshQueue_EndScene();
959 if (r_shadow_visiblevolumes.integer)
961 R_ShadowVolumeLighting(true);
962 R_TimeReport("shadowvolume");
966 R_TimeReport("meshfinish");
970 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
973 float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
975 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
978 R_Mesh_Matrix(&r_identitymatrix);
980 memset(&m, 0, sizeof(m));
981 R_Mesh_State_Texture(&m);
984 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
985 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
986 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
987 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
988 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
989 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
990 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
991 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
992 GL_ColorPointer(color);
993 R_FillColors(color, 8, cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
996 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
998 VectorSubtract(v, r_origin, diff);
999 f2 = exp(fogdensity/DotProduct(diff, diff));
1002 c[0] = c[0] * f1 + fogcolor[0] * f2;
1003 c[1] = c[1] * f1 + fogcolor[1] * f2;
1004 c[2] = c[2] * f1 + fogcolor[2] * f2;
1011 int nomodelelements[24] =
1023 float nomodelvertex3f[6*3] =
1033 float nomodelcolor4f[6*4] =
1035 0.0f, 0.0f, 0.5f, 1.0f,
1036 0.0f, 0.0f, 0.5f, 1.0f,
1037 0.0f, 0.5f, 0.0f, 1.0f,
1038 0.0f, 0.5f, 0.0f, 1.0f,
1039 0.5f, 0.0f, 0.0f, 1.0f,
1040 0.5f, 0.0f, 0.0f, 1.0f
1043 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1045 const entity_render_t *ent = calldata1;
1047 float f1, f2, *c, diff[3];
1050 R_Mesh_Matrix(&ent->matrix);
1052 memset(&m, 0, sizeof(m));
1053 R_Mesh_State_Texture(&m);
1055 if (ent->flags & EF_ADDITIVE)
1057 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1058 GL_DepthMask(false);
1060 else if (ent->alpha < 1)
1062 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1063 GL_DepthMask(false);
1067 GL_BlendFunc(GL_ONE, GL_ZERO);
1071 GL_VertexPointer(nomodelvertex3f);
1074 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1075 GL_ColorPointer(color4f);
1076 VectorSubtract(ent->origin, r_origin, diff);
1077 f2 = exp(fogdensity/DotProduct(diff, diff));
1079 for (i = 0, c = color4f;i < 6;i++, c += 4)
1081 c[0] = (c[0] * f1 + fogcolor[0] * f2) * r_colorscale;
1082 c[1] = (c[1] * f1 + fogcolor[1] * f2) * r_colorscale;
1083 c[2] = (c[2] * f1 + fogcolor[2] * f2) * r_colorscale;
1087 else if (r_colorscale != 1 || ent->alpha != 1)
1089 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1090 GL_ColorPointer(color4f);
1091 for (i = 0, c = color4f;i < 6;i++, c += 4)
1093 c[0] *= r_colorscale;
1094 c[1] *= r_colorscale;
1095 c[2] *= r_colorscale;
1100 GL_ColorPointer(nomodelcolor4f);
1101 R_Mesh_Draw(6, 8, nomodelelements);
1104 void R_DrawNoModel(entity_render_t *ent)
1106 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1107 R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0);
1109 // R_DrawNoModelCallback(ent, 0);
1112 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1114 vec3_t right1, right2, diff, normal;
1116 VectorSubtract (org2, org1, normal);
1117 VectorNormalizeFast (normal);
1119 // calculate 'right' vector for start
1120 VectorSubtract (r_origin, org1, diff);
1121 VectorNormalizeFast (diff);
1122 CrossProduct (normal, diff, right1);
1124 // calculate 'right' vector for end
1125 VectorSubtract (r_origin, org2, diff);
1126 VectorNormalizeFast (diff);
1127 CrossProduct (normal, diff, right2);
1129 vert[ 0] = org1[0] + width * right1[0];
1130 vert[ 1] = org1[1] + width * right1[1];
1131 vert[ 2] = org1[2] + width * right1[2];
1132 vert[ 3] = org1[0] - width * right1[0];
1133 vert[ 4] = org1[1] - width * right1[1];
1134 vert[ 5] = org1[2] - width * right1[2];
1135 vert[ 6] = org2[0] - width * right2[0];
1136 vert[ 7] = org2[1] - width * right2[1];
1137 vert[ 8] = org2[2] - width * right2[2];
1138 vert[ 9] = org2[0] + width * right2[0];
1139 vert[10] = org2[1] + width * right2[1];
1140 vert[11] = org2[2] + width * right2[2];
1143 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1145 void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, int depthdisable, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2, float cr, float cg, float cb, float ca)
1152 VectorSubtract(origin, r_origin, diff);
1153 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1156 R_Mesh_Matrix(&r_identitymatrix);
1157 GL_Color(cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
1158 GL_VertexPointer(varray_vertex3f);
1159 GL_BlendFunc(blendfunc1, blendfunc2);
1160 GL_DepthMask(false);
1161 GL_DepthTest(!depthdisable);
1163 memset(&m, 0, sizeof(m));
1164 m.tex[0] = R_GetTexture(texture);
1165 m.pointer_texcoord[0] = spritetexcoord2f;
1166 R_Mesh_State_Texture(&m);
1168 varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1169 varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1170 varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1171 varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1172 varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1173 varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1174 varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1175 varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1176 varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1177 varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1178 varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1179 varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1180 R_Mesh_Draw(4, 2, polygonelements);