+
+void R_Shadow_Stage_End(void)
+{
+ // attempt to restore state to what Mesh_State thinks it is
+ qglDisable(GL_BLEND);
+ qglBlendFunc(GL_ONE, GL_ZERO);
+ qglDepthMask(1);
+ // now restore the rest of the state to normal
+ GL_Color(1, 1, 1, 1);
+ qglColorMask(1, 1, 1, 1);
+ qglDepthFunc(GL_LEQUAL);
+ qglDisable(GL_STENCIL_TEST);
+ qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ qglStencilFunc(GL_ALWAYS, 0, 0xFF);
+ qglEnable(GL_CULL_FACE);
+ qglEnable(GL_DEPTH_TEST);
+ r_shadowstage = SHADOWSTAGE_NONE;
+}
+
+void R_Shadow_GenTexCoords_Attenuation2D1D(float *out2d, float *out1d, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin, float lightradius)
+{
+ int i;
+ float lightvec[3], iradius;
+ iradius = 0.5f / lightradius;
+ for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out2d += 4, out1d += 4)
+ {
+ VectorSubtract(vertex, relativelightorigin, lightvec);
+ out2d[0] = 0.5f + DotProduct(svectors, lightvec) * iradius;
+ out2d[1] = 0.5f + DotProduct(tvectors, lightvec) * iradius;
+ out2d[2] = 0;
+ out1d[0] = 0.5f + DotProduct(normals, lightvec) * iradius;
+ out1d[1] = 0.5f;
+ out1d[2] = 0;
+ }
+}
+
+void R_Shadow_GenTexCoords_Diffuse_Attenuation3D(float *out, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin, float lightradius)
+{
+ int i;
+ float lightvec[3], iradius;
+ iradius = 0.5f / lightradius;
+ for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out += 4)
+ {
+ VectorSubtract(vertex, relativelightorigin, lightvec);
+ out[0] = 0.5f + DotProduct(svectors, lightvec) * iradius;
+ out[1] = 0.5f + DotProduct(tvectors, lightvec) * iradius;
+ out[2] = 0.5f + DotProduct(normals, lightvec) * iradius;
+ }
+}
+
+void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(float *out, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin)
+{
+ int i;
+ float lightdir[3], iradius;
+ for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out += 4)
+ {
+ VectorSubtract(vertex, relativelightorigin, lightdir);
+ // the cubemap normalizes this for us
+ out[0] = DotProduct(svectors, lightdir);
+ out[1] = DotProduct(tvectors, lightdir);
+ out[2] = DotProduct(normals, lightdir);
+ }
+}
+
+void R_Shadow_GenTexCoords_Specular_Attenuation3D(float *out, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin, const vec3_t relativeeyeorigin, float lightradius)
+{
+ int i;
+ float lightdir[3], eyedir[3], halfdir[3], lightdirlen, ilen, iradius;
+ iradius = 0.5f / lightradius;
+ for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out += 4)
+ {
+ VectorSubtract(vertex, relativelightorigin, lightdir);
+ // this is used later to make the attenuation correct
+ lightdirlen = sqrt(DotProduct(lightdir, lightdir)) * iradius;
+ VectorNormalizeFast(lightdir);
+ VectorSubtract(vertex, relativeeyeorigin, eyedir);
+ VectorNormalizeFast(eyedir);
+ VectorAdd(lightdir, eyedir, halfdir);
+ VectorNormalizeFast(halfdir);
+ out[0] = 0.5f + DotProduct(svectors, halfdir) * lightdirlen;
+ out[1] = 0.5f + DotProduct(tvectors, halfdir) * lightdirlen;
+ out[2] = 0.5f + DotProduct(normals, halfdir) * lightdirlen;
+ }
+}
+
+void R_Shadow_GenTexCoords_Specular_NormalCubeMap(float *out, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin, const vec3_t relativeeyeorigin)
+{
+ int i;
+ float lightdir[3], eyedir[3], halfdir[3], lightdirlen, ilen, iradius;
+ for (i = 0;i < numverts;i++, vertex += 4, svectors += 4, tvectors += 4, normals += 4, out += 4)
+ {
+ VectorSubtract(vertex, relativelightorigin, lightdir);
+ VectorNormalizeFast(lightdir);
+ VectorSubtract(vertex, relativeeyeorigin, eyedir);
+ VectorNormalizeFast(eyedir);
+ VectorAdd(lightdir, eyedir, halfdir);
+ // the cubemap normalizes this for us
+ out[0] = DotProduct(svectors, halfdir);
+ out[1] = DotProduct(tvectors, halfdir);
+ out[2] = DotProduct(normals, halfdir);
+ }
+}
+
+void R_Shadow_GenTexCoords_LightCubeMap(float *out, int numverts, const float *vertex, const vec3_t relativelightorigin)
+{
+ int i;
+ // FIXME: this needs to be written
+ // this code assumes the vertices are in worldspace (a false assumption)
+ for (i = 0;i < numverts;i++, vertex += 4, out += 4)
+ VectorSubtract(vertex, relativelightorigin, out);
+}
+
+void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *relativeeyeorigin, float lightradius, const float *lightcolor, rtexture_t *basetexture, rtexture_t *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap)
+{
+ int mult;
+ float scale, colorscale;
+ rmeshstate_t m;
+ memset(&m, 0, sizeof(m));
+ if (!bumptexture)
+ bumptexture = r_shadow_blankbumptexture;
+ // colorscale accounts for how much we multiply the brightness during combine
+ if (r_light_quality.integer == 1)
+ {
+ if (r_textureunits.integer >= 4)
+ colorscale = r_colorscale * 0.125f / r_shadow3.value;
+ else
+ colorscale = r_colorscale * 0.5f / r_shadow3.value;
+ }
+ else
+ colorscale = r_colorscale * 0.5f / r_shadow3.value;
+ // limit mult to 64 for sanity sake
+ for (mult = 1, scale = ixtable[mult];mult < 64 && (lightcolor[0] * scale * colorscale > 1 || lightcolor[1] * scale * colorscale > 1 || lightcolor[2] * scale * colorscale > 1);mult++, scale = ixtable[mult]);
+ colorscale *= scale;
+ for (;mult > 0;mult--)
+ {
+ if (r_light_quality.integer == 1)
+ {
+ if (r_textureunits.integer >= 4)
+ {
+ // 4 texture 3D path, two pass
+ m.tex[0] = R_GetTexture(bumptexture);
+ m.tex3d[1] = R_GetTexture(r_shadow_normalsattenuationtexture);
+ m.tex[2] = R_GetTexture(basetexture);
+ m.texcubemap[3] = R_GetTexture(lightcubemap);
+ m.tex[3] = R_GetTexture(r_notexture);
+ m.texcombinergb[0] = GL_REPLACE;
+ m.texcombinergb[1] = GL_DOT3_RGB_ARB;
+ m.texcombinergb[2] = GL_MODULATE;
+ m.texcombinergb[3] = GL_MODULATE;
+ m.texrgbscale[1] = 2;
+ m.texrgbscale[3] = 4;
+ R_Mesh_TextureState(&m);
+ GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
+ memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
+ memcpy(varray_texcoord[2], texcoords, numverts * sizeof(float[4]));
+ if (lightcubemap)
+ R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[3], numverts, varray_vertex, relativelightorigin);
+ else
+ {
+ qglActiveTexture(GL_TEXTURE3_ARB);
+ qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
+ }
+ R_Shadow_GenTexCoords_Diffuse_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
+ R_Mesh_Draw(numverts, numtriangles, elements);
+ if (!lightcubemap)
+ {
+ qglActiveTexture(GL_TEXTURE3_ARB);
+ qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
+ }
+ if (r_light_gloss.integer && glosstexture)
+ {
+ m.tex[2] = R_GetTexture(glosstexture);
+ R_Mesh_TextureState(&m);
+ R_Shadow_GenTexCoords_Specular_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, relativeeyeorigin, lightradius);
+ if (!lightcubemap)
+ {
+ qglActiveTexture(GL_TEXTURE3_ARB);
+ qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
+ }
+ R_Mesh_Draw(numverts, numtriangles, elements);
+ if (!lightcubemap)
+ {
+ qglActiveTexture(GL_TEXTURE3_ARB);
+ qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
+ }
+ }
+ }
+ else
+ {
+ // 2 texture 3D path, four pass
+ m.tex[0] = R_GetTexture(bumptexture);
+ m.tex3d[1] = R_GetTexture(r_shadow_normalsattenuationtexture);
+ m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+ m.texalphascale[1] = 2;
+ R_Mesh_TextureState(&m);
+ qglColorMask(0,0,0,1);
+ qglDisable(GL_BLEND);
+ GL_Color(1,1,1,1);
+ memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
+ R_Shadow_GenTexCoords_Diffuse_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
+ R_Mesh_Draw(numverts, numtriangles, elements);
+
+ m.tex[0] = R_GetTexture(basetexture);
+ m.tex3d[1] = 0;
+ m.texcubemap[1] = R_GetTexture(lightcubemap);
+ m.texcombinergb[1] = GL_MODULATE;
+ m.texrgbscale[1] = 1;
+ m.texalphascale[1] = 1;
+ R_Mesh_TextureState(&m);
+ qglColorMask(1,1,1,1);
+ qglBlendFunc(GL_DST_ALPHA, GL_ONE);
+ qglEnable(GL_BLEND);
+ GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
+ if (lightcubemap)
+ R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
+ R_Mesh_Draw(numverts, numtriangles, elements);
+ }
+ }
+ else
+ {
+ // 2 texture no3D path, six pass
+ m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+ m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+ R_Mesh_TextureState(&m);
+ qglColorMask(0,0,0,1);
+ qglDisable(GL_BLEND);
+ GL_Color(1,1,1,1);
+ R_Shadow_GenTexCoords_Attenuation2D1D(varray_texcoord[0], varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
+ R_Mesh_Draw(numverts, numtriangles, elements);
+
+ m.tex[0] = R_GetTexture(bumptexture);
+ m.tex[1] = 0;
+ m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
+ m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+ m.texalphascale[1] = 2;
+ R_Mesh_TextureState(&m);
+ qglBlendFunc(GL_DST_ALPHA, GL_ZERO);
+ qglEnable(GL_BLEND);
+ memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
+ R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin);
+ R_Mesh_Draw(numverts, numtriangles, elements);
+
+ m.tex[0] = R_GetTexture(basetexture);
+ m.texcubemap[1] = R_GetTexture(lightcubemap);
+ m.texcombinergb[1] = GL_MODULATE;
+ m.texrgbscale[1] = 1;
+ m.texalphascale[1] = 1;
+ R_Mesh_TextureState(&m);
+ qglColorMask(1,1,1,1);
+ qglBlendFunc(GL_DST_ALPHA, GL_ONE);
+ GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
+ if (lightcubemap)
+ R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
+ R_Mesh_Draw(numverts, numtriangles, elements);
+ }
+ }
+}
+