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
29 matrix4x4_t r_identitymatrix;
31 int c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights;
33 // true during envmap command capture
49 // 8.8 fraction of base light value
50 unsigned short d_lightstylevalue[256];
52 cvar_t r_drawentities = {0, "r_drawentities","1"};
53 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
54 cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0"};
55 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
56 cvar_t r_speeds = {0, "r_speeds","0"};
57 cvar_t r_fullbright = {0, "r_fullbright","0"};
58 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
59 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
60 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
61 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
63 cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
64 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
65 cvar_t gl_fogred = {0, "gl_fogred","0.3"};
66 cvar_t gl_foggreen = {0, "gl_foggreen","0.3"};
67 cvar_t gl_fogblue = {0, "gl_fogblue","0.3"};
68 cvar_t gl_fogstart = {0, "gl_fogstart", "0"};
69 cvar_t gl_fogend = {0, "gl_fogend","0"};
71 cvar_t r_textureunits = {0, "r_textureunits", "32"};
73 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1"};
74 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1"};
75 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1"};
79 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
82 for (i = 0;i < verts;i++)
93 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
96 for (i = 0;i < verts;i++)
110 For program optimization
113 qboolean intimerefresh = 0;
114 static void R_TimeRefresh_f (void)
117 float start, stop, time;
120 start = Sys_DoubleTime ();
121 for (i = 0;i < 128;i++)
123 r_refdef.viewangles[0] = 0;
124 r_refdef.viewangles[1] = i/128.0*360.0;
125 r_refdef.viewangles[2] = 0;
129 stop = Sys_DoubleTime ();
132 Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
137 float fog_density, fog_red, fog_green, fog_blue;
139 qboolean oldgl_fogenable;
140 void R_SetupFog(void)
142 if (gamemode == GAME_NEHAHRA)
144 if (gl_fogenable.integer)
146 oldgl_fogenable = true;
147 fog_density = gl_fogdensity.value;
148 fog_red = gl_fogred.value;
149 fog_green = gl_foggreen.value;
150 fog_blue = gl_fogblue.value;
152 else if (oldgl_fogenable)
154 oldgl_fogenable = false;
163 fogcolor[0] = fog_red = bound(0.0f, fog_red , 1.0f);
164 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
165 fogcolor[2] = fog_blue = bound(0.0f, fog_blue , 1.0f);
170 fogdensity = -4000.0f / (fog_density * fog_density);
171 // fog color was already set
177 // FIXME: move this to client?
180 if (gamemode == GAME_NEHAHRA)
182 Cvar_Set("gl_fogenable", "0");
183 Cvar_Set("gl_fogdensity", "0.2");
184 Cvar_Set("gl_fogred", "0.3");
185 Cvar_Set("gl_foggreen", "0.3");
186 Cvar_Set("gl_fogblue", "0.3");
188 fog_density = fog_red = fog_green = fog_blue = 0.0f;
191 // FIXME: move this to client?
192 void FOG_registercvars(void)
194 if (gamemode == GAME_NEHAHRA)
196 Cvar_RegisterVariable (&gl_fogenable);
197 Cvar_RegisterVariable (&gl_fogdensity);
198 Cvar_RegisterVariable (&gl_fogred);
199 Cvar_RegisterVariable (&gl_foggreen);
200 Cvar_RegisterVariable (&gl_fogblue);
201 Cvar_RegisterVariable (&gl_fogstart);
202 Cvar_RegisterVariable (&gl_fogend);
206 void gl_main_start(void)
210 void gl_main_shutdown(void)
214 extern void CL_ParseEntityLump(char *entitystring);
215 void gl_main_newmap(void)
217 if (cl.worldmodel && cl.worldmodel->entities)
218 CL_ParseEntityLump(cl.worldmodel->entities);
222 void GL_Main_Init(void)
224 Matrix4x4_CreateIdentity(&r_identitymatrix);
225 // FIXME: move this to client?
227 Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
228 Cvar_RegisterVariable (&r_drawentities);
229 Cvar_RegisterVariable (&r_drawviewmodel);
230 Cvar_RegisterVariable (&r_shadows);
231 Cvar_RegisterVariable (&r_shadow_staticworldlights);
232 Cvar_RegisterVariable (&r_speeds);
233 Cvar_RegisterVariable (&r_fullbrights);
234 Cvar_RegisterVariable (&r_wateralpha);
235 Cvar_RegisterVariable (&r_dynamic);
236 Cvar_RegisterVariable (&r_fullbright);
237 Cvar_RegisterVariable (&r_textureunits);
238 Cvar_RegisterVariable (&r_shadow_cull);
239 Cvar_RegisterVariable (&r_lerpsprites);
240 Cvar_RegisterVariable (&r_lerpmodels);
241 Cvar_RegisterVariable (&r_waterscroll);
242 if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ)
243 Cvar_SetValue("r_fullbrights", 0);
244 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
247 vec3_t r_farclip_origin;
248 vec3_t r_farclip_direction;
249 vec_t r_farclip_directiondist;
250 vec_t r_farclip_meshfarclip;
251 int r_farclip_directionbit0;
252 int r_farclip_directionbit1;
253 int r_farclip_directionbit2;
255 // start a farclip measuring session
256 void R_FarClip_Start(vec3_t origin, vec3_t direction, vec_t startfarclip)
258 VectorCopy(origin, r_farclip_origin);
259 VectorCopy(direction, r_farclip_direction);
260 r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
261 r_farclip_directionbit0 = r_farclip_direction[0] < 0;
262 r_farclip_directionbit1 = r_farclip_direction[1] < 0;
263 r_farclip_directionbit2 = r_farclip_direction[2] < 0;
264 r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
267 // enlarge farclip to accomodate box
268 void R_FarClip_Box(vec3_t mins, vec3_t maxs)
271 d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
272 + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
273 + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
274 if (r_farclip_meshfarclip < d)
275 r_farclip_meshfarclip = d;
278 // return farclip value
279 float R_FarClip_Finish(void)
281 return r_farclip_meshfarclip - r_farclip_directiondist;
284 extern void R_Textures_Init(void);
285 extern void Mod_RenderInit(void);
286 extern void GL_Draw_Init(void);
287 extern void GL_Main_Init(void);
288 extern void R_Shadow_Init(void);
289 extern void GL_Models_Init(void);
290 extern void R_Sky_Init(void);
291 extern void GL_Surf_Init(void);
292 extern void R_Crosshairs_Init(void);
293 extern void R_Light_Init(void);
294 extern void R_Particles_Init(void);
295 extern void R_Explosion_Init(void);
296 extern void ui_init(void);
297 extern void gl_backend_init(void);
298 extern void Sbar_Init(void);
300 void Render_Init(void)
325 extern char *ENGINE_EXTENSIONS;
328 VID_CheckExtensions();
330 // LordHavoc: report supported extensions
331 Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
334 int R_CullBox(const vec3_t mins, const vec3_t maxs)
338 for (i = 0;i < 4;i++)
345 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
349 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
353 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
357 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
361 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
365 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
369 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
373 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
381 int PVS_CullBox(const vec3_t mins, const vec3_t maxs)
384 mnode_t *node, *stack[4096];
385 if (cl.worldmodel == NULL)
388 stack[stackpos++] = cl.worldmodel->nodes;
391 node = stack[--stackpos];
392 if (node->contents < 0)
394 if (((mleaf_t *)node)->pvsframe == cl.worldmodel->pvsframecount)
399 sides = BoxOnPlaneSide(mins, maxs, node->plane);
400 if (sides & 2 && stackpos < 4096)
401 stack[stackpos++] = node->children[1];
402 if (sides & 1 && stackpos < 4096)
403 stack[stackpos++] = node->children[0];
409 int VIS_CullBox(const vec3_t mins, const vec3_t maxs)
412 mnode_t *node, *stack[4096];
413 if (R_CullBox(mins, maxs))
415 if (cl.worldmodel == NULL)
418 stack[stackpos++] = cl.worldmodel->nodes;
421 node = stack[--stackpos];
422 if (node->contents < 0)
424 if (((mleaf_t *)node)->visframe == r_framecount)
429 sides = BoxOnPlaneSide(mins, maxs, node->plane);
430 if (sides & 2 && stackpos < 4096)
431 stack[stackpos++] = node->children[1];
432 if (sides & 1 && stackpos < 4096)
433 stack[stackpos++] = node->children[0];
439 int R_CullSphere(const vec3_t origin, vec_t radius)
441 return (DotProduct(frustum[0].normal, origin) + radius < frustum[0].dist
442 || DotProduct(frustum[1].normal, origin) + radius < frustum[1].dist
443 || DotProduct(frustum[2].normal, origin) + radius < frustum[2].dist
444 || DotProduct(frustum[3].normal, origin) + radius < frustum[3].dist);
447 int PVS_CullSphere(const vec3_t origin, vec_t radius)
450 mnode_t *node, *stack[4096];
452 if (cl.worldmodel == NULL)
455 stack[stackpos++] = cl.worldmodel->nodes;
458 node = stack[--stackpos];
459 if (node->contents < 0)
461 if (((mleaf_t *)node)->pvsframe == cl.worldmodel->pvsframecount)
466 dist = PlaneDiff(origin, node->plane);
468 stack[stackpos++] = node->children[1];
470 stack[stackpos++] = node->children[0];
476 int VIS_CullSphere(const vec3_t origin, vec_t radius)
479 mnode_t *node, *stack[4096];
481 if (R_CullSphere(origin, radius))
483 if (cl.worldmodel == NULL)
486 stack[stackpos++] = cl.worldmodel->nodes;
489 node = stack[--stackpos];
490 if (node->contents < 0)
492 if (((mleaf_t *)node)->visframe == r_framecount)
497 dist = PlaneDiff(origin, node->plane);
499 stack[stackpos++] = node->children[1];
501 stack[stackpos++] = node->children[0];
508 //==================================================================================
510 static void R_MarkEntities (void)
513 entity_render_t *ent;
515 ent = &cl_entities[0].render;
516 Matrix4x4_CreateIdentity(&ent->matrix);
517 Matrix4x4_CreateIdentity(&ent->inversematrix);
520 R_FarClip_Box(cl.worldmodel->normalmins, cl.worldmodel->normalmaxs);
522 if (!r_drawentities.integer)
525 for (i = 0;i < r_refdef.numentities;i++)
527 ent = r_refdef.entities[i];
528 Mod_CheckLoaded(ent->model);
529 // some of the renderer still relies on origin...
530 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
531 // some of the renderer still relies on scale...
532 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
533 R_LerpAnimation(ent);
534 R_UpdateEntLights(ent);
535 if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
536 && !VIS_CullSphere(ent->origin, (ent->model != NULL ? ent->model->radius : 16) * ent->scale)
537 && !VIS_CullBox(ent->mins, ent->maxs))
539 ent->visframe = r_framecount;
540 R_FarClip_Box(ent->mins, ent->maxs);
545 // only used if skyrendermasked, and normally returns false
546 int R_DrawBrushModelsSky (void)
549 entity_render_t *ent;
551 if (!r_drawentities.integer)
555 for (i = 0;i < r_refdef.numentities;i++)
557 ent = r_refdef.entities[i];
558 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
560 ent->model->DrawSky(ent);
573 void R_DrawViewModel (void)
575 entity_render_t *ent;
577 // FIXME: move these checks to client
578 if (!r_drawviewmodel.integer || chase_active.integer || envmap || !r_drawentities.integer || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model)
581 ent = &cl.viewent.render;
582 Mod_CheckLoaded(ent->model);
583 R_LerpAnimation(ent);
584 Matrix4x4_CreateFromQuakeEntity(&ent->matrix, ent->origin[0], ent->origin[1], ent->origin[2], -ent->angles[0], ent->angles[1], ent->angles[2], ent->scale);
585 Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix);
586 R_UpdateEntLights(ent);
587 ent->model->Draw(ent);
591 void R_DrawNoModel(entity_render_t *ent);
595 entity_render_t *ent;
597 if (!r_drawentities.integer)
600 for (i = 0;i < r_refdef.numentities;i++)
602 ent = r_refdef.entities[i];
603 if (ent->visframe == r_framecount)
605 if (ent->model && ent->model->Draw != NULL)
606 ent->model->Draw(ent);
613 void R_DrawFakeShadows (void)
616 entity_render_t *ent;
618 ent = &cl_entities[0].render;
619 if (ent->model && ent->model->DrawFakeShadow)
620 ent->model->DrawFakeShadow(ent);
622 if (!r_drawentities.integer)
624 for (i = 0;i < r_refdef.numentities;i++)
626 ent = r_refdef.entities[i];
627 if ((ent->flags & RENDER_SHADOW) && ent->model && ent->model->DrawFakeShadow)
628 ent->model->DrawFakeShadow(ent);
632 #include "r_shadow.h"
634 int shadowframecount = 0;
636 int Light_CullBox(const vec3_t mins, const vec3_t maxs)
639 mnode_t *node, *stack[4096];
640 if (cl.worldmodel == NULL)
643 stack[stackpos++] = cl.worldmodel->nodes;
646 node = stack[--stackpos];
647 if (node->contents < 0)
649 if (((mleaf_t *)node)->worldnodeframe == shadowframecount)
654 sides = BoxOnPlaneSide(mins, maxs, node->plane);
655 if (sides & 2 && stackpos < 4096)
656 stack[stackpos++] = node->children[1];
657 if (sides & 1 && stackpos < 4096)
658 stack[stackpos++] = node->children[0];
664 int LightAndVis_CullBox(const vec3_t mins, const vec3_t maxs)
667 mnode_t *node, *stack[4096];
668 if (R_CullBox(mins, maxs))
670 if (cl.worldmodel == NULL)
673 stack[stackpos++] = cl.worldmodel->nodes;
676 node = stack[--stackpos];
677 if (node->contents < 0)
679 if (((mleaf_t *)node)->visframe == r_framecount && ((mleaf_t *)node)->worldnodeframe == shadowframecount)
684 sides = BoxOnPlaneSide(mins, maxs, node->plane);
685 if (sides & 2 && stackpos < 4096)
686 stack[stackpos++] = node->children[1];
687 if (sides & 1 && stackpos < 4096)
688 stack[stackpos++] = node->children[0];
694 int LightAndVis_CullPointCloud(int numpoints, const float *points)
699 mnode_t *node, *stack[4096];
700 //if (R_CullBox(mins, maxs))
702 if (cl.worldmodel == NULL)
705 stack[stackpos++] = cl.worldmodel->nodes;
708 node = stack[--stackpos];
709 if (node->contents < 0)
711 if (((mleaf_t *)node)->visframe == r_framecount && ((mleaf_t *)node)->worldnodeframe == shadowframecount)
717 for (i = 0, p = points;i < numpoints && sides != 3;i++, p += 3)
719 if (DotProduct(p, node->plane->normal) < node->plane->dist)
724 if (sides & 2 && stackpos < 4096)
725 stack[stackpos++] = node->children[1];
726 if (sides & 1 && stackpos < 4096)
727 stack[stackpos++] = node->children[0];
734 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)
736 vec3_t relativelightorigin;
740 float dist, projectdistance;
744 if (!(ent->flags & RENDER_SHADOW) || ent->model == NULL || ent->model->DrawShadowVolume == NULL)
746 if (r_shadow_cull.integer)
748 if (ent->maxs[0] < lightmins[0] || ent->mins[0] > lightmaxs[0]
749 || ent->maxs[1] < lightmins[1] || ent->mins[1] > lightmaxs[1]
750 || ent->maxs[2] < lightmins[2] || ent->mins[2] > lightmaxs[2]
751 || (lightmarked && Light_CullBox(ent->mins, ent->maxs)))
755 if (r_shadow_cull.integer)
757 projectdistance = cullradius;
758 // calculate projected bounding box and decide if it is on-screen
759 for (i = 0;i < 8;i++)
761 temp[0] = i & 1 ? ent->model->normalmaxs[0] : ent->model->normalmins[0];
762 temp[1] = i & 2 ? ent->model->normalmaxs[1] : ent->model->normalmins[1];
763 temp[2] = i & 4 ? ent->model->normalmaxs[2] : ent->model->normalmins[2];
764 Matrix4x4_Transform(&ent->matrix, temp, points[i]);
765 VectorSubtract(points[i], lightorigin, temp);
766 dist = projectdistance / sqrt(DotProduct(temp, temp));
767 VectorMA(lightorigin, dist, temp, points[i+8]);
769 if (LightAndVis_CullPointCloud(16, points[0]))
772 for (i = 0;i < 8;i++)
774 p2[0] = i & 1 ? ent->model->normalmaxs[0] : ent->model->normalmins[0];
775 p2[1] = i & 2 ? ent->model->normalmaxs[1] : ent->model->normalmins[1];
776 p2[2] = i & 4 ? ent->model->normalmaxs[2] : ent->model->normalmins[2];
777 Matrix4x4_Transform(&ent->matrix, p2, p);
778 VectorSubtract(p, lightorigin, temp);
779 dist = projectdistance / sqrt(DotProduct(temp, temp));
780 VectorMA(p, dist, temp, p2);
783 if (mins[0] > p[0]) mins[0] = p[0];if (maxs[0] < p[0]) maxs[0] = p[0];
784 if (mins[1] > p[1]) mins[1] = p[1];if (maxs[1] < p[1]) maxs[1] = p[1];
785 if (mins[2] > p[2]) mins[2] = p[2];if (maxs[2] < p[2]) maxs[2] = p[2];
792 if (mins[0] > p2[0]) mins[0] = p2[0];if (maxs[0] < p2[0]) maxs[0] = p2[0];
793 if (mins[1] > p2[1]) mins[1] = p2[1];if (maxs[1] < p2[1]) maxs[1] = p2[1];
794 if (mins[2] > p2[2]) mins[2] = p2[2];if (maxs[2] < p2[2]) maxs[2] = p2[2];
796 if (mins[0] >= clipmaxs[0] || maxs[0] <= clipmins[0]
797 || mins[1] >= clipmaxs[1] || maxs[1] <= clipmins[1]
798 || mins[2] >= clipmaxs[2] || maxs[2] <= clipmins[2]
799 || LightAndVis_CullBox(mins, maxs))
804 Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin);
805 ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius);
808 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light);
810 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);
811 void R_ShadowVolumeLighting (int visiblevolumes)
814 entity_render_t *ent;
816 float f, lightradius, cullradius;
817 vec3_t relativelightorigin, relativeeyeorigin, lightcolor, clipmins, clipmaxs;
823 matrix4x4_t matrix_worldtofilter, matrix_worldtoattenuationxyz, matrix_worldtoattenuationz;
824 matrix4x4_t matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
828 memset(&m, 0, sizeof(m));
829 R_Mesh_State_Texture(&m);
831 GL_BlendFunc(GL_ONE, GL_ONE);
833 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
834 qglDisable(GL_CULL_FACE);
835 GL_Color(0.0 * r_colorscale, 0.0125 * r_colorscale, 0.1 * r_colorscale, 1);
838 R_Shadow_Stage_Begin();
840 if (r_shadow_realtime_world.integer)
842 R_Shadow_LoadWorldLightsIfNeeded();
843 for (lnum = 0, wl = r_shadow_worldlightchain;wl;wl = wl->next, lnum++)
845 if (d_lightstylevalue[wl->style] <= 0)
847 if (R_CullBox(wl->mins, wl->maxs))
848 //if (R_CullSphere(wl->origin, cullradius))
850 //if (R_CullBox(wl->mins, wl->maxs) || R_CullSphere(wl->origin, lightradius))
852 //if (VIS_CullBox(wl->mins, wl->maxs) || VIS_CullSphere(wl->origin, lightradius))
854 if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer)
857 cullradius = wl->cullradius;
858 lightradius = wl->lightradius;
860 if (cl.worldmodel != NULL)
862 for (i = 0;i < wl->numleafs;i++)
863 if (wl->leafs[i]->visframe == r_framecount)
865 if (i == wl->numleafs)
867 leaf = wl->leafs[i++];
868 VectorCopy(leaf->mins, clipmins);
869 VectorCopy(leaf->maxs, clipmaxs);
870 for (;i < wl->numleafs;i++)
873 if (leaf->visframe == r_framecount)
875 if (clipmins[0] > leaf->mins[0]) clipmins[0] = leaf->mins[0];
876 if (clipmaxs[0] < leaf->maxs[0]) clipmaxs[0] = leaf->maxs[0];
877 if (clipmins[1] > leaf->mins[1]) clipmins[1] = leaf->mins[1];
878 if (clipmaxs[1] < leaf->maxs[1]) clipmaxs[1] = leaf->maxs[1];
879 if (clipmins[2] > leaf->mins[2]) clipmins[2] = leaf->mins[2];
880 if (clipmaxs[2] < leaf->maxs[2]) clipmaxs[2] = leaf->maxs[2];
883 if (clipmins[0] < wl->mins[0]) clipmins[0] = wl->mins[0];
884 if (clipmaxs[0] > wl->maxs[0]) clipmaxs[0] = wl->maxs[0];
885 if (clipmins[1] < wl->mins[1]) clipmins[1] = wl->mins[1];
886 if (clipmaxs[1] > wl->maxs[1]) clipmaxs[1] = wl->maxs[1];
887 if (clipmins[2] < wl->mins[2]) clipmins[2] = wl->mins[2];
888 if (clipmaxs[2] > wl->maxs[2]) clipmaxs[2] = wl->maxs[2];
892 VectorCopy(wl->mins, clipmins);
893 VectorCopy(wl->maxs, clipmaxs);
896 //if (R_Shadow_ScissorForBBoxAndSphere(clipmins, clipmaxs, wl->origin, wl->cullradius))
897 if (R_CullBox(clipmins, clipmaxs) || R_Shadow_ScissorForBBox(clipmins, clipmaxs))
900 // mark the leafs we care about so only things in those leafs will matter
901 if (cl.worldmodel != NULL)
902 for (i = 0;i < wl->numleafs;i++)
903 wl->leafs[i]->worldnodeframe = shadowframecount;
905 f = d_lightstylevalue[wl->style] * (1.0f / 256.0f);
906 VectorScale(wl->light, f, lightcolor);
909 f = 2 + sin(realtime * M_PI * 4.0);
910 VectorScale(lightcolor, f, lightcolor);
913 if (wl->castshadows && (gl_stencil || visiblevolumes))
916 R_Shadow_Stage_ShadowVolumes();
917 ent = &cl_entities[0].render;
918 if (wl->shadowvolume && r_shadow_staticworldlights.integer)
919 R_Shadow_DrawWorldLightShadowVolume(&ent->matrix, wl);
921 R_TestAndDrawShadowVolume(ent, wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
922 if (r_drawentities.integer)
923 for (i = 0;i < r_refdef.numentities;i++)
924 R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
929 if (wl->castshadows && gl_stencil)
930 R_Shadow_Stage_LightWithShadows();
932 R_Shadow_Stage_LightWithoutShadows();
934 // calculate world to filter matrix
935 Matrix4x4_CreateFromQuakeEntity(&matrix, wl->origin[0], wl->origin[1], wl->origin[2], wl->angles[0], wl->angles[1], wl->angles[2], lightradius);
936 Matrix4x4_Invert_Simple(&matrix_worldtofilter, &matrix);
937 // calculate world to attenuationxyz/xy matrix
938 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5, 0.5, 0.5, 0, 0, 0, 0.5);
939 Matrix4x4_Concat(&matrix_worldtoattenuationxyz, &matrix, &matrix_worldtofilter);
940 // calculate world to attenuationz matrix
941 matrix.m[0][0] = 0;matrix.m[0][1] = 0;matrix.m[0][2] = 0.5;matrix.m[0][3] = 0.5;
942 matrix.m[1][0] = 0;matrix.m[1][1] = 0;matrix.m[1][2] = 0 ;matrix.m[1][3] = 0.5;
943 matrix.m[2][0] = 0;matrix.m[2][1] = 0;matrix.m[2][2] = 0 ;matrix.m[2][3] = 0.5;
944 matrix.m[3][0] = 0;matrix.m[3][1] = 0;matrix.m[3][2] = 0 ;matrix.m[3][3] = 1;
945 Matrix4x4_Concat(&matrix_worldtoattenuationz, &matrix, &matrix_worldtofilter);
947 ent = &cl_entities[0].render;
948 if (ent->model && ent->model->DrawLight)
950 Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
951 Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
952 Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
953 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
954 Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
956 R_Model_Brush_DrawLightForSurfaceList(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, wl->surfaces, wl->numsurfaces, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
958 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
960 if (r_drawentities.integer)
962 for (i = 0;i < r_refdef.numentities;i++)
964 ent = r_refdef.entities[i];
965 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
966 && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
967 && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
969 Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
970 Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
971 Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
972 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
973 Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
974 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
981 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
983 for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++)
985 lightradius = rd->cullradius;
986 clipmins[0] = rd->origin[0] - lightradius;
987 clipmins[1] = rd->origin[1] - lightradius;
988 clipmins[2] = rd->origin[2] - lightradius;
989 clipmaxs[0] = rd->origin[0] + lightradius;
990 clipmaxs[1] = rd->origin[1] + lightradius;
991 clipmaxs[2] = rd->origin[2] + lightradius;
992 if (VIS_CullBox(clipmins, clipmaxs) || R_Shadow_ScissorForBBox(clipmins, clipmaxs))
995 cullradius = RadiusFromBoundsAndOrigin(clipmins, clipmaxs, rd->origin);
996 VectorScale(rd->light, (1.0f / 4096.0f), lightcolor);
998 if (gl_stencil || visiblevolumes)
1000 if (!visiblevolumes)
1001 R_Shadow_Stage_ShadowVolumes();
1002 ent = &cl_entities[0].render;
1003 R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
1004 if (r_drawentities.integer)
1006 for (i = 0;i < r_refdef.numentities;i++)
1008 ent = r_refdef.entities[i];
1010 R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
1015 if (!visiblevolumes)
1018 R_Shadow_Stage_LightWithShadows();
1020 R_Shadow_Stage_LightWithoutShadows();
1022 // calculate world to filter matrix
1023 Matrix4x4_CreateFromQuakeEntity(&matrix, rd->origin[0], rd->origin[1], rd->origin[2], 0, 0, 0, lightradius);
1024 Matrix4x4_Invert_Simple(&matrix_worldtofilter, &matrix);
1025 // calculate world to attenuationxyz/xy matrix
1026 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5, 0.5, 0.5, 0, 0, 0, 0.5);
1027 Matrix4x4_Concat(&matrix_worldtoattenuationxyz, &matrix, &matrix_worldtofilter);
1028 // calculate world to attenuationz matrix
1029 matrix.m[0][0] = 0;matrix.m[0][1] = 0;matrix.m[0][2] = 0.5;matrix.m[0][3] = 0.5;
1030 matrix.m[1][0] = 0;matrix.m[1][1] = 0;matrix.m[1][2] = 0 ;matrix.m[1][3] = 0.5;
1031 matrix.m[2][0] = 0;matrix.m[2][1] = 0;matrix.m[2][2] = 0 ;matrix.m[2][3] = 0.5;
1032 matrix.m[3][0] = 0;matrix.m[3][1] = 0;matrix.m[3][2] = 0 ;matrix.m[3][3] = 1;
1033 Matrix4x4_Concat(&matrix_worldtoattenuationz, &matrix, &matrix_worldtofilter);
1035 ent = &cl_entities[0].render;
1036 if (ent->model && ent->model->DrawLight)
1038 Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
1039 Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
1040 Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
1041 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
1042 Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
1043 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
1045 if (r_drawentities.integer)
1047 for (i = 0;i < r_refdef.numentities;i++)
1049 ent = r_refdef.entities[i];
1050 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
1051 && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
1052 && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
1054 Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
1055 Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
1056 Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
1057 Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
1058 Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
1059 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
1068 qglEnable(GL_CULL_FACE);
1070 R_Shadow_Stage_End();
1071 qglDisable(GL_SCISSOR_TEST);
1074 static void R_SetFrustum (void)
1076 // LordHavoc: note to all quake engine coders, the special case for 90
1077 // degrees assumed a square view (wrong), so I removed it, Quake2 has it
1078 // disabled as well.
1080 // rotate VPN right by FOV_X/2 degrees
1081 RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
1082 frustum[0].dist = DotProduct (r_origin, frustum[0].normal);
1083 PlaneClassify(&frustum[0]);
1085 // rotate VPN left by FOV_X/2 degrees
1086 RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
1087 frustum[1].dist = DotProduct (r_origin, frustum[1].normal);
1088 PlaneClassify(&frustum[1]);
1090 // rotate VPN up by FOV_X/2 degrees
1091 RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
1092 frustum[2].dist = DotProduct (r_origin, frustum[2].normal);
1093 PlaneClassify(&frustum[2]);
1095 // rotate VPN down by FOV_X/2 degrees
1096 RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
1097 frustum[3].dist = DotProduct (r_origin, frustum[3].normal);
1098 PlaneClassify(&frustum[3]);
1106 static void R_SetupFrame (void)
1108 // don't allow cheats in multiplayer
1109 if (cl.maxclients > 1)
1111 if (r_fullbright.integer != 0)
1112 Cvar_Set ("r_fullbright", "0");
1113 if (r_ambient.value != 0)
1114 Cvar_Set ("r_ambient", "0");
1119 // build the transformation matrix for the given view angles
1120 VectorCopy (r_refdef.vieworg, r_origin);
1122 AngleVectors (r_refdef.viewangles, vpn, vright, vup);
1128 static void R_BlendView(void)
1132 float vertex3f[3*3];
1134 if (r_refdef.viewblend[3] < 0.01f)
1137 R_Mesh_Matrix(&r_identitymatrix);
1139 memset(&m, 0, sizeof(m));
1140 R_Mesh_State_Texture(&m);
1142 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1144 GL_DepthTest(false); // magic
1145 GL_VertexPointer(vertex3f);
1146 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
1148 vertex3f[0] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r - vup[0] * r;
1149 vertex3f[1] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r - vup[1] * r;
1150 vertex3f[2] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r - vup[2] * r;
1151 vertex3f[3] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r + vup[0] * r * 3;
1152 vertex3f[4] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r + vup[1] * r * 3;
1153 vertex3f[5] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r + vup[2] * r * 3;
1154 vertex3f[6] = r_origin[0] + vpn[0] * 1.5 + vright[0] * r * 3 - vup[0] * r;
1155 vertex3f[7] = r_origin[1] + vpn[1] * 1.5 + vright[1] * r * 3 - vup[1] * r;
1156 vertex3f[8] = r_origin[2] + vpn[2] * 1.5 + vright[2] * r * 3 - vup[2] * r;
1157 R_Mesh_Draw(3, 1, polygonelements);
1164 r_refdef must be set before the first call
1167 extern void R_DrawLightningBeams (void);
1168 void R_RenderView (void)
1170 entity_render_t *world;
1171 if (!r_refdef.entities/* || !cl.worldmodel*/)
1172 return; //Host_Error ("R_RenderView: NULL worldmodel");
1174 if (r_shadow_realtime_world.integer)
1178 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");
1179 Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
1183 world = &cl_entities[0].render;
1185 // FIXME: move to client
1187 R_TimeReport("mexplosion");
1195 R_TimeReport("setup");
1197 R_WorldVisibility(world);
1198 R_TimeReport("worldvis");
1200 R_FarClip_Start(r_origin, vpn, 768.0f);
1202 r_farclip = R_FarClip_Finish() + 256.0f;
1203 R_TimeReport("markentity");
1205 GL_SetupView_ViewPort(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
1206 if (r_shadow_realtime_world.integer || gl_stencil)
1207 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.fov_x, r_refdef.fov_y, 1.0f);
1209 GL_SetupView_Mode_Perspective(r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip);
1210 GL_SetupView_Orientation_FromEntity (r_refdef.vieworg, r_refdef.viewangles);
1211 qglDepthFunc(GL_LEQUAL);
1214 R_MeshQueue_BeginScene();
1216 R_Shadow_UpdateWorldLightSelection();
1218 if (R_DrawBrushModelsSky())
1219 R_TimeReport("bmodelsky");
1221 // must occur early because it can draw sky
1223 R_TimeReport("world");
1225 // don't let sound skip if going slow
1226 if (!intimerefresh && !r_speeds.integer)
1229 R_DrawModels(r_shadow_realtime_world.integer);
1230 R_TimeReport("models");
1232 if (r_shadows.integer == 1 && !r_shadow_realtime_world.integer)
1234 R_DrawFakeShadows();
1235 R_TimeReport("fakeshadow");
1238 if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
1240 R_ShadowVolumeLighting(false);
1241 R_TimeReport("dynlight");
1244 R_DrawLightningBeams();
1245 R_TimeReport("lightning");
1248 R_TimeReport("particles");
1251 R_TimeReport("explosions");
1253 R_MeshQueue_RenderTransparent();
1254 R_TimeReport("drawtrans");
1257 R_TimeReport("coronas");
1259 R_DrawWorldCrosshair();
1260 R_TimeReport("crosshair");
1263 R_TimeReport("blendview");
1265 R_MeshQueue_Render();
1266 R_MeshQueue_EndScene();
1268 if (r_shadow_visiblevolumes.integer)
1270 R_ShadowVolumeLighting(true);
1271 R_TimeReport("shadowvolume");
1275 R_TimeReport("meshfinish");
1279 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
1282 float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
1284 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1285 GL_DepthMask(false);
1287 R_Mesh_Matrix(&r_identitymatrix);
1289 memset(&m, 0, sizeof(m));
1290 R_Mesh_State_Texture(&m);
1293 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
1294 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
1295 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
1296 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
1297 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
1298 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
1299 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
1300 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
1301 GL_ColorPointer(color);
1302 R_FillColors(color, 8, cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
1305 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
1307 VectorSubtract(v, r_origin, diff);
1308 f2 = exp(fogdensity/DotProduct(diff, diff));
1311 c[0] = c[0] * f1 + fogcolor[0] * f2;
1312 c[1] = c[1] * f1 + fogcolor[1] * f2;
1313 c[2] = c[2] * f1 + fogcolor[2] * f2;
1320 int nomodelelements[24] =
1332 float nomodelvertex3f[6*3] =
1342 float nomodelcolor4f[6*4] =
1344 0.0f, 0.0f, 0.5f, 1.0f,
1345 0.0f, 0.0f, 0.5f, 1.0f,
1346 0.0f, 0.5f, 0.0f, 1.0f,
1347 0.0f, 0.5f, 0.0f, 1.0f,
1348 0.5f, 0.0f, 0.0f, 1.0f,
1349 0.5f, 0.0f, 0.0f, 1.0f
1352 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1354 const entity_render_t *ent = calldata1;
1356 float f1, f2, *c, diff[3];
1359 R_Mesh_Matrix(&ent->matrix);
1361 memset(&m, 0, sizeof(m));
1362 R_Mesh_State_Texture(&m);
1364 if (ent->flags & EF_ADDITIVE)
1366 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1367 GL_DepthMask(false);
1369 else if (ent->alpha < 1)
1371 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1372 GL_DepthMask(false);
1376 GL_BlendFunc(GL_ONE, GL_ZERO);
1380 GL_VertexPointer(nomodelvertex3f);
1383 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1384 GL_ColorPointer(color4f);
1385 VectorSubtract(ent->origin, r_origin, diff);
1386 f2 = exp(fogdensity/DotProduct(diff, diff));
1388 for (i = 0, c = color4f;i < 6;i++, c += 4)
1390 c[0] = (c[0] * f1 + fogcolor[0] * f2) * r_colorscale;
1391 c[1] = (c[1] * f1 + fogcolor[1] * f2) * r_colorscale;
1392 c[2] = (c[2] * f1 + fogcolor[2] * f2) * r_colorscale;
1396 else if (r_colorscale != 1 || ent->alpha != 1)
1398 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1399 GL_ColorPointer(color4f);
1400 for (i = 0, c = color4f;i < 6;i++, c += 4)
1402 c[0] *= r_colorscale;
1403 c[1] *= r_colorscale;
1404 c[2] *= r_colorscale;
1409 GL_ColorPointer(nomodelcolor4f);
1410 R_Mesh_Draw(6, 8, nomodelelements);
1413 void R_DrawNoModel(entity_render_t *ent)
1415 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1416 R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0);
1418 // R_DrawNoModelCallback(ent, 0);
1421 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1423 vec3_t right1, right2, diff, normal;
1425 VectorSubtract (org2, org1, normal);
1426 VectorNormalizeFast (normal);
1428 // calculate 'right' vector for start
1429 VectorSubtract (r_origin, org1, diff);
1430 VectorNormalizeFast (diff);
1431 CrossProduct (normal, diff, right1);
1433 // calculate 'right' vector for end
1434 VectorSubtract (r_origin, org2, diff);
1435 VectorNormalizeFast (diff);
1436 CrossProduct (normal, diff, right2);
1438 vert[ 0] = org1[0] + width * right1[0];
1439 vert[ 1] = org1[1] + width * right1[1];
1440 vert[ 2] = org1[2] + width * right1[2];
1441 vert[ 3] = org1[0] - width * right1[0];
1442 vert[ 4] = org1[1] - width * right1[1];
1443 vert[ 5] = org1[2] - width * right1[2];
1444 vert[ 6] = org2[0] - width * right2[0];
1445 vert[ 7] = org2[1] - width * right2[1];
1446 vert[ 8] = org2[2] - width * right2[2];
1447 vert[ 9] = org2[0] + width * right2[0];
1448 vert[10] = org2[1] + width * right2[1];
1449 vert[11] = org2[2] + width * right2[2];
1452 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1454 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)
1461 VectorSubtract(origin, r_origin, diff);
1462 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1465 R_Mesh_Matrix(&r_identitymatrix);
1466 GL_Color(cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
1467 GL_VertexPointer(varray_vertex3f);
1468 GL_BlendFunc(blendfunc1, blendfunc2);
1469 GL_DepthMask(false);
1470 GL_DepthTest(!depthdisable);
1472 memset(&m, 0, sizeof(m));
1473 m.tex[0] = R_GetTexture(texture);
1474 m.pointer_texcoord[0] = spritetexcoord2f;
1475 R_Mesh_State_Texture(&m);
1477 varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1478 varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1479 varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1480 varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1481 varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1482 varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1483 varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1484 varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1485 varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1486 varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1487 varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1488 varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1489 R_Mesh_Draw(4, 2, polygonelements);