+ unsigned int perm, prog;
+ // GLSL shader path (GFFX5200, Radeon 9500)
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = vertex3f;
+ m.pointer_texcoord[0] = texcoord2f;
+ m.pointer_texcoord3f[1] = svector3f;
+ m.pointer_texcoord3f[2] = tvector3f;
+ m.pointer_texcoord3f[3] = normal3f;
+ m.tex[0] = R_GetTexture(bumptexture);
+ m.tex[1] = R_GetTexture(basetexture);
+ m.tex[2] = R_GetTexture(glosstexture);
+ m.texcubemap[3] = R_GetTexture(lightcubemap);
+ // TODO: support fog (after renderer is converted to texture fog)
+ m.tex[4] = R_GetTexture(r_texture_white);
+ m.texmatrix[3] = *matrix_modeltolight;
+ R_Mesh_State(&m);
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
+ CHECKGLERROR
+ perm = 0;
+ // only add a feature to the permutation if that permutation exists
+ // (otherwise it might end up not using a shader at all, which looks
+ // worse than using less features)
+ if (specularscale && r_shadow_program_light[perm | SHADERPERMUTATION_SPECULAR])
+ perm |= SHADERPERMUTATION_SPECULAR;
+ //if (fog && r_shadow_program_light[perm | SHADERPERMUTATION_FOG])
+ // perm |= SHADERPERMUTATION_FOG;
+ if (lightcubemap && r_shadow_program_light[perm | SHADERPERMUTATION_CUBEFILTER])
+ perm |= SHADERPERMUTATION_CUBEFILTER;
+ if (r_shadow_glsl_offsetmapping.integer && r_shadow_program_light[perm | SHADERPERMUTATION_OFFSETMAPPING])
+ perm |= SHADERPERMUTATION_OFFSETMAPPING;
+ prog = r_shadow_program_light[perm];
+ qglUseProgramObjectARB(prog);CHECKGLERROR
+ // TODO: support fog (after renderer is converted to texture fog)
+ if (perm & SHADERPERMUTATION_FOG)
+ {
+ qglUniform1fARB(qglGetUniformLocationARB(prog, "FogRangeRecip"), 0);CHECKGLERROR
+ }
+ qglUniform1fARB(qglGetUniformLocationARB(prog, "AmbientScale"), ambientscale);CHECKGLERROR
+ qglUniform1fARB(qglGetUniformLocationARB(prog, "DiffuseScale"), diffusescale);CHECKGLERROR
+ if (perm & SHADERPERMUTATION_SPECULAR)
+ {
+ qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularPower"), 8);CHECKGLERROR
+ qglUniform1fARB(qglGetUniformLocationARB(prog, "SpecularScale"), specularscale);CHECKGLERROR
+ }
+ qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);CHECKGLERROR
+ qglUniform3fARB(qglGetUniformLocationARB(prog, "LightPosition"), relativelightorigin[0], relativelightorigin[1], relativelightorigin[2]);CHECKGLERROR
+ if (perm & (SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_FOG | SHADERPERMUTATION_OFFSETMAPPING))
+ {
+ qglUniform3fARB(qglGetUniformLocationARB(prog, "EyePosition"), relativeeyeorigin[0], relativeeyeorigin[1], relativeeyeorigin[2]);CHECKGLERROR
+ }
+ if (perm & SHADERPERMUTATION_OFFSETMAPPING)
+ {
+ qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Scale"), r_shadow_glsl_offsetmapping_scale.value);CHECKGLERROR
+ qglUniform1fARB(qglGetUniformLocationARB(prog, "OffsetMapping_Bias"), r_shadow_glsl_offsetmapping_bias.value);CHECKGLERROR
+ }
+ CHECKGLERROR
+ GL_LockArrays(firstvertex, numvertices);
+ R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
+ // TODO: add direct pants/shirt rendering
+ if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
+ {
+ R_Mesh_TexBind(1, R_GetTexture(pantstexture));
+ qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorpants[0], lightcolorpants[1], lightcolorpants[2]);CHECKGLERROR
+ R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
+ }
+ if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
+ {
+ R_Mesh_TexBind(1, R_GetTexture(shirttexture));
+ qglUniform3fARB(qglGetUniformLocationARB(prog, "LightColor"), lightcolorshirt[0], lightcolorshirt[1], lightcolorshirt[2]);CHECKGLERROR
+ R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
+ }
+ GL_LockArrays(0, 0);
+ qglUseProgramObjectARB(0);
+ // HACK HACK HACK: work around for stupid NVIDIA bug that causes GL_OUT_OF_MEMORY and/or software rendering
+ qglBegin(GL_TRIANGLES);
+ qglEnd();
+ CHECKGLERROR
+ }
+ else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
+ {
+ // TODO: add direct pants/shirt rendering
+ if (pantstexture && (ambientscale + diffusescale) * VectorLength2(lightcolorpants) > 0.001)
+ R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorpants, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, pantstexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
+ if (shirttexture && (ambientscale + diffusescale) * VectorLength2(lightcolorshirt) > 0.001)
+ R_Shadow_RenderLighting(firstvertex, numvertices, numtriangles, elements, vertex3f, svector3f, tvector3f, normal3f, texcoord2f, relativelightorigin, relativeeyeorigin, lightcolorshirt, NULL, NULL, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, shirttexture, NULL, NULL, bumptexture, NULL, lightcubemap, ambientscale, diffusescale, specularscale, visiblelighting);
+ if (!bumptexture)
+ bumptexture = r_texture_blanknormalmap;
+ if (!glosstexture)
+ glosstexture = r_texture_white;
+ if (ambientscale)
+ {
+ GL_Color(1,1,1,1);
+ colorscale = ambientscale;
+ // colorscale accounts for how much we multiply the brightness
+ // during combine.
+ //
+ // mult is how many times the final pass of the lighting will be
+ // performed to get more brightness than otherwise possible.
+ //
+ // Limit mult to 64 for sanity sake.
+ if (r_shadow_texture3d.integer && lightcubemap && r_textureunits.integer >= 4)
+ {
+ // 3 3D combine path (Geforce3, Radeon 8500)
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = vertex3f;
+ m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
+#ifdef USETEXMATRIX
+ m.pointer_texcoord3f[0] = vertex3f;
+ m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+#else
+ m.pointer_texcoord3f[0] = varray_texcoord3f[0];
+ R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+#endif
+ m.tex[1] = R_GetTexture(basetexture);
+ m.pointer_texcoord[1] = texcoord2f;
+ m.texcubemap[2] = R_GetTexture(lightcubemap);
+#ifdef USETEXMATRIX
+ m.pointer_texcoord3f[2] = vertex3f;
+ m.texmatrix[2] = *matrix_modeltolight;
+#else
+ m.pointer_texcoord3f[2] = varray_texcoord3f[2];
+ R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[2] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
+#endif
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ }
+ else if (r_shadow_texture3d.integer && !lightcubemap && r_textureunits.integer >= 2)
+ {
+ // 2 3D combine path (Geforce3, original Radeon)
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = vertex3f;
+ m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
+#ifdef USETEXMATRIX
+ m.pointer_texcoord3f[0] = vertex3f;
+ m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+#else
+ m.pointer_texcoord3f[0] = varray_texcoord3f[0];
+ R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+#endif
+ m.tex[1] = R_GetTexture(basetexture);
+ m.pointer_texcoord[1] = texcoord2f;
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ }
+ else if (r_textureunits.integer >= 4 && lightcubemap)
+ {
+ // 4 2D combine path (Geforce3, Radeon 8500)
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = vertex3f;
+ m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+#ifdef USETEXMATRIX
+ m.pointer_texcoord3f[0] = vertex3f;
+ m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+#else
+ m.pointer_texcoord[0] = varray_texcoord2f[0];
+ R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+#endif
+ m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+#ifdef USETEXMATRIX
+ m.pointer_texcoord3f[1] = vertex3f;
+ m.texmatrix[1] = *matrix_modeltoattenuationz;
+#else
+ m.pointer_texcoord[1] = varray_texcoord2f[1];
+ R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
+#endif
+ m.tex[2] = R_GetTexture(basetexture);
+ m.pointer_texcoord[2] = texcoord2f;
+ if (lightcubemap)
+ {
+ m.texcubemap[3] = R_GetTexture(lightcubemap);
+#ifdef USETEXMATRIX
+ m.pointer_texcoord3f[3] = vertex3f;
+ m.texmatrix[3] = *matrix_modeltolight;
+#else
+ m.pointer_texcoord3f[3] = varray_texcoord3f[3];
+ R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[3] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
+#endif
+ }
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ }
+ else if (r_textureunits.integer >= 3 && !lightcubemap)
+ {
+ // 3 2D combine path (Geforce3, original Radeon)
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = vertex3f;
+ m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+#ifdef USETEXMATRIX
+ m.pointer_texcoord3f[0] = vertex3f;
+ m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+#else
+ m.pointer_texcoord[0] = varray_texcoord2f[0];
+ R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+#endif
+ m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+#ifdef USETEXMATRIX
+ m.pointer_texcoord3f[1] = vertex3f;
+ m.texmatrix[1] = *matrix_modeltoattenuationz;
+#else
+ m.pointer_texcoord[1] = varray_texcoord2f[1];
+ R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
+#endif
+ m.tex[2] = R_GetTexture(basetexture);
+ m.pointer_texcoord[2] = texcoord2f;
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ }
+ else
+ {
+ // 2/2/2 2D combine path (any dot3 card)
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = vertex3f;
+ m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+#ifdef USETEXMATRIX
+ m.pointer_texcoord3f[0] = vertex3f;
+ m.texmatrix[0] = *matrix_modeltoattenuationxyz;
+#else
+ m.pointer_texcoord[0] = varray_texcoord2f[0];
+ R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[0] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationxyz);
+#endif
+ m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+#ifdef USETEXMATRIX
+ m.pointer_texcoord3f[1] = vertex3f;
+ m.texmatrix[1] = *matrix_modeltoattenuationz;
+#else
+ m.pointer_texcoord[1] = varray_texcoord2f[1];
+ R_Shadow_Transform_Vertex3f_TexCoord2f(varray_texcoord2f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltoattenuationz);
+#endif
+ R_Mesh_State(&m);
+ GL_ColorMask(0,0,0,1);
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_LockArrays(firstvertex, numvertices);
+ R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
+ GL_LockArrays(0, 0);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
+
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = vertex3f;
+ m.tex[0] = R_GetTexture(basetexture);
+ m.pointer_texcoord[0] = texcoord2f;
+ if (lightcubemap)
+ {
+ m.texcubemap[1] = R_GetTexture(lightcubemap);
+#ifdef USETEXMATRIX
+ m.pointer_texcoord3f[1] = vertex3f;
+ m.texmatrix[1] = *matrix_modeltolight;
+#else
+ m.pointer_texcoord3f[1] = varray_texcoord3f[1];
+ R_Shadow_Transform_Vertex3f_TexCoord3f(varray_texcoord3f[1] + 3 * firstvertex, numvertices, vertex3f + 3 * firstvertex, matrix_modeltolight);
+#endif
+ }
+ GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
+ }
+ // this final code is shared
+ R_Mesh_State(&m);
+ GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 0);
+ VectorScale(lightcolorbase, colorscale, color2);
+ GL_LockArrays(firstvertex, numvertices);
+ for (renders = 0;renders < 64 && (color2[0] > 0 || color2[1] > 0 || color2[2] > 0);renders++, color2[0]--, color2[1]--, color2[2]--)
+ {
+ GL_Color(bound(0, color2[0], 1), bound(0, color2[1], 1), bound(0, color2[2], 1), 1);
+ R_Mesh_Draw(firstvertex, numvertices, numtriangles, elements);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
+ }
+ GL_LockArrays(0, 0);
+ }
+ if (diffusescale)