+extern void R_SetupView(const matrix4x4_t *matrix);
+extern cvar_t r_shadows_throwdistance;
+void R_DrawModelShadows(void)
+{
+ int i;
+ float relativethrowdistance;
+ entity_render_t *ent;
+ vec3_t relativelightorigin;
+ vec3_t relativelightdirection;
+ vec3_t relativeshadowmins, relativeshadowmaxs;
+ float vertex3f[12];
+
+ if (!r_drawentities.integer || !gl_stencil)
+ return;
+
+ CHECKGLERROR
+ GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
+
+ r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
+
+ if (gl_ext_separatestencil.integer)
+ r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_SEPARATESTENCIL;
+ else if (gl_ext_stenciltwoside.integer)
+ r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
+ else
+ r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
+
+ R_Shadow_RenderMode_StencilShadowVolumes();
+
+ for (i = 0;i < r_refdef.numentities;i++)
+ {
+ ent = r_refdef.entities[i];
+ // cast shadows from anything that is not a submodel of the map
+ if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
+ {
+ relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
+ VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
+ VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
+ VectorNegate(ent->modellight_lightdir, relativelightdirection);
+ VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
+ R_Mesh_Matrix(&ent->matrix);
+ ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
+ }
+ }
+
+ // not really the right mode, but this will disable any silly stencil features
+ R_Shadow_RenderMode_VisibleLighting(true, true);
+
+ // vertex coordinates for a quad that covers the screen exactly
+ vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
+ vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
+ vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
+ vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
+
+ // set up ortho view for rendering this pass
+ GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
+ GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
+ GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
+ GL_ScissorTest(true);
+ R_Mesh_Matrix(&identitymatrix);
+ R_Mesh_ResetTextureState();
+ R_Mesh_VertexPointer(vertex3f);
+ R_Mesh_ColorPointer(NULL);
+
+ // set up a 50% darkening blend on shadowed areas
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GL_DepthTest(false);
+ GL_DepthMask(false);
+ qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
+ GL_Color(0, 0, 0, 0.5);
+ GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
+ qglDepthFunc(GL_ALWAYS);CHECKGLERROR
+ qglEnable(GL_STENCIL_TEST);CHECKGLERROR
+ qglStencilMask(~0);CHECKGLERROR
+ qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
+ qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
+
+ // apply the blend to the shadowed areas
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+
+ // restoring the perspective view is done by R_RenderScene
+ //R_SetupView(&r_view.matrix);
+
+ // restore other state to normal
+ R_Shadow_RenderMode_End();
+}
+
+