X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=r_shadow.c;h=893a058aa16595537435b1db7f5e6e6306981862;hb=3bddef8837924e402d275a0201ae25ecf3767b09;hp=98b21ee63e05edaf51a6576db3054b185099c3b1;hpb=ba0396abf2259b73e83a5871e1fbb4c26f90764d;p=xonotic%2Fdarkplaces.git diff --git a/r_shadow.c b/r_shadow.c index 98b21ee6..893a058a 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -193,8 +193,12 @@ unsigned char *r_shadow_buffer_lighttrispvs; // current light's cull box (copied out of an rtlight or calculated by GetLightInfo) vec3_t r_shadow_rtlight_cullmins; vec3_t r_shadow_rtlight_cullmaxs; +// current light's culling planes +int r_shadow_rtlight_numfrustumplanes; +mplane_t r_shadow_rtlight_frustumplanes[12+6+6]; // see R_Shadow_ComputeShadowCasterCullingPlanes rtexturepool_t *r_shadow_texturepool; +rtexture_t *r_shadow_attenuationgradienttexture; rtexture_t *r_shadow_attenuation2dtexture; rtexture_t *r_shadow_attenuation3dtexture; @@ -207,12 +211,13 @@ rtexturepool_t *r_shadow_filters_texturepool; cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"}; cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"}; cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"}; +cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"}; cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"}; cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"}; cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"}; cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"}; -cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_glsl lighting)"}; -cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_glsl lighting)"}; +cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"}; +cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"}; cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"}; cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"}; cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"}; @@ -235,7 +240,7 @@ cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs mor cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"}; cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"}; cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"}; -cvar_t gl_ext_separatestencil = {0, "gl_ext_separatetencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"}; +cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"}; cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"}; cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"}; cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"}; @@ -244,7 +249,16 @@ cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"}; cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"}; -float r_shadow_attenpower, r_shadow_attenscale; +// note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error +#define ATTENTABLESIZE 256 +// 1D gradient, 2D circle and 3D sphere attenuation textures +#define ATTEN1DSIZE 32 +#define ATTEN2DSIZE 64 +#define ATTEN3DSIZE 32 + +static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias +static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale +static float r_shadow_attentable[ATTENTABLESIZE+1]; rtlight_t *r_shadow_compilingrtlight; dlight_t *r_shadow_worldlightchain; @@ -279,6 +293,7 @@ void r_shadow_start(void) { // allocate vertex processing arrays numcubemaps = 0; + r_shadow_attenuationgradienttexture = NULL; r_shadow_attenuation2dtexture = NULL; r_shadow_attenuation3dtexture = NULL; r_shadow_texturepool = NULL; @@ -314,6 +329,7 @@ void r_shadow_shutdown(void) { R_Shadow_UncompileWorldLights(); numcubemaps = 0; + r_shadow_attenuationgradienttexture = NULL; r_shadow_attenuation2dtexture = NULL; r_shadow_attenuation3dtexture = NULL; R_FreeTexturePool(&r_shadow_texturepool); @@ -379,8 +395,8 @@ void R_Shadow_Help_f(void) "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n" "r_shadow_gloss2intensity : brightness of forced gloss\n" "r_shadow_glossintensity : brightness of textured gloss\n" -"r_shadow_lightattenuationpower : used to generate attenuation texture\n" -"r_shadow_lightattenuationscale : used to generate attenuation texture\n" +"r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n" +"r_shadow_lightattenuationdividebias : used to generate attenuation texture\n" "r_shadow_lightintensityscale : scale rendering brightness of all lights\n" "r_shadow_lightradiusscale : scale rendering radius of all lights\n" "r_shadow_portallight : use portal visibility for static light precomputation\n" @@ -408,13 +424,14 @@ void R_Shadow_Init(void) { Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture); Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap); + Cvar_RegisterVariable(&r_shadow_usenormalmap); Cvar_RegisterVariable(&r_shadow_debuglight); Cvar_RegisterVariable(&r_shadow_gloss); Cvar_RegisterVariable(&r_shadow_gloss2intensity); Cvar_RegisterVariable(&r_shadow_glossintensity); Cvar_RegisterVariable(&r_shadow_glossexponent); - Cvar_RegisterVariable(&r_shadow_lightattenuationpower); - Cvar_RegisterVariable(&r_shadow_lightattenuationscale); + Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias); + Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale); Cvar_RegisterVariable(&r_shadow_lightintensityscale); Cvar_RegisterVariable(&r_shadow_lightradiusscale); Cvar_RegisterVariable(&r_shadow_portallight); @@ -883,77 +900,71 @@ void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *verte } r_refdef.stats.lights_shadowtriangles += numtriangles; CHECKGLERROR - R_Mesh_VertexPointer(vertex3f); + R_Mesh_VertexPointer(vertex3f, 0, 0); GL_LockArrays(0, numvertices); if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL) { // decrement stencil if backface is behind depthbuffer GL_CullFace(GL_BACK); // quake is backwards, this culls front faces qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR - R_Mesh_Draw(0, numvertices, numtriangles, element3i); + R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0); // increment stencil if frontface is behind depthbuffer GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR } - R_Mesh_Draw(0, numvertices, numtriangles, element3i); + R_Mesh_Draw(0, numvertices, numtriangles, element3i, 0, 0); GL_LockArrays(0, 0); CHECKGLERROR } +static unsigned char R_Shadow_MakeTextures_SamplePoint(float x, float y, float z) +{ + float dist = sqrt(x*x+y*y+z*z); + float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0; + return (unsigned char)bound(0, intensity * 256.0f, 255); +} + static void R_Shadow_MakeTextures(void) { - int x, y, z, d; - float v[3], intensity; + int x, y, z; + float intensity, dist; unsigned char *data; + unsigned int palette[256]; R_FreeTexturePool(&r_shadow_texturepool); r_shadow_texturepool = R_AllocTexturePool(); - r_shadow_attenpower = r_shadow_lightattenuationpower.value; - r_shadow_attenscale = r_shadow_lightattenuationscale.value; -#define ATTEN2DSIZE 64 -#define ATTEN3DSIZE 32 - data = (unsigned char *)Mem_Alloc(tempmempool, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4)); + r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value; + r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value; + // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways + for (x = 0;x < 256;x++) + palette[x] = x * 0x01010101; + data = (unsigned char *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE)); + // the table includes one additional value to avoid the need to clamp indexing due to minor math errors + for (x = 0;x <= ATTENTABLESIZE;x++) + { + dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375); + intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0; + r_shadow_attentable[x] = bound(0, intensity, 1); + } + // 1D gradient texture + for (x = 0;x < ATTEN1DSIZE;x++) + data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0); + r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette); + // 2D circle texture for (y = 0;y < ATTEN2DSIZE;y++) - { for (x = 0;x < ATTEN2DSIZE;x++) - { - v[0] = ((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375); - v[1] = ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375); - v[2] = 0; - intensity = 1.0f - sqrt(DotProduct(v, v)); - if (intensity > 0) - intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f; - d = (int)bound(0, intensity, 255); - data[(y*ATTEN2DSIZE+x)*4+0] = d; - data[(y*ATTEN2DSIZE+x)*4+1] = d; - data[(y*ATTEN2DSIZE+x)*4+2] = d; - data[(y*ATTEN2DSIZE+x)*4+3] = d; - } - } - r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL); + data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0); + r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette); + // 3D sphere texture if (r_shadow_texture3d.integer && gl_texture3d) { for (z = 0;z < ATTEN3DSIZE;z++) - { for (y = 0;y < ATTEN3DSIZE;y++) - { for (x = 0;x < ATTEN3DSIZE;x++) - { - v[0] = ((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375); - v[1] = ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375); - v[2] = ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375); - intensity = 1.0f - sqrt(DotProduct(v, v)); - if (intensity > 0) - intensity = pow(intensity, r_shadow_attenpower) * r_shadow_attenscale * 256.0f; - d = (int)bound(0, intensity, 255); - data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = d; - data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = d; - data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = d; - data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = d; - } - } - } - r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, NULL); + data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375)); + r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_PALETTE, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA, palette); } + else + r_shadow_attenuation3dtexture = NULL; Mem_Free(data); } @@ -987,14 +998,15 @@ void R_Shadow_RenderMode_Begin(void) if (!r_shadow_attenuation2dtexture || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer) - || r_shadow_lightattenuationpower.value != r_shadow_attenpower - || r_shadow_lightattenuationscale.value != r_shadow_attenscale) + || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias + || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale) R_Shadow_MakeTextures(); CHECKGLERROR - R_Mesh_ColorPointer(NULL); + R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthRange(0, 1); GL_DepthTest(true); GL_DepthMask(false); GL_Color(0, 0, 0, 1); @@ -1033,8 +1045,9 @@ void R_Shadow_RenderMode_Reset(void) { qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR } - R_Mesh_ColorPointer(NULL); + R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); + GL_DepthRange(0, 1); GL_DepthTest(true); GL_DepthMask(false); qglDepthFunc(GL_LEQUAL);CHECKGLERROR @@ -1049,7 +1062,7 @@ void R_Shadow_RenderMode_Reset(void) GL_BlendFunc(GL_ONE, GL_ZERO); } -void R_Shadow_RenderMode_StencilShadowVolumes(void) +void R_Shadow_RenderMode_StencilShadowVolumes(qboolean clearstencil) { CHECKGLERROR R_Shadow_RenderMode_Reset(); @@ -1075,7 +1088,8 @@ void R_Shadow_RenderMode_StencilShadowVolumes(void) qglStencilMask(~0);CHECKGLERROR qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR } - GL_Clear(GL_STENCIL_BUFFER_BIT); + if (clearstencil) + GL_Clear(GL_STENCIL_BUFFER_BIT); r_refdef.stats.lights_clears++; } @@ -1121,6 +1135,7 @@ void R_Shadow_RenderMode_VisibleShadowVolumes(void) CHECKGLERROR R_Shadow_RenderMode_Reset(); GL_BlendFunc(GL_ONE, GL_ONE); + GL_DepthRange(0, 1); GL_DepthTest(r_showshadowvolumes.integer < 2); GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1); qglPolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR @@ -1133,6 +1148,7 @@ void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transpar CHECKGLERROR R_Shadow_RenderMode_Reset(); GL_BlendFunc(GL_ONE, GL_ONE); + GL_DepthRange(0, 1); GL_DepthTest(r_showlighting.integer < 2); GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1); if (!transparent) @@ -1256,92 +1272,160 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu float dist, dot, distintensity, shadeintensity, v[3], n[3]; if (r_textureunits.integer >= 3) { - for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4) + if (VectorLength2(diffusecolor) > 0) { - Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v); - Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n); - if ((dot = DotProduct(n, v)) < 0) + for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4) { - shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n)); - color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]); - color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]); - color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]); + Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v); + Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n); + if ((dot = DotProduct(n, v)) < 0) + { + shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n)); + VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f); + } + else + VectorCopy(ambientcolor, color4f); if (r_refdef.fogenabled) { - float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg)); + float f; + f = FogPoint_Model(vertex3f); VectorScale(color4f, f, color4f); } + color4f[3] = 1; + } + } + else + { + for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4) + { + VectorCopy(ambientcolor, color4f); + if (r_refdef.fogenabled) + { + float f; + Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v); + f = FogPoint_Model(vertex3f); + VectorScale(color4f, f, color4f); + } + color4f[3] = 1; } - else - VectorClear(color4f); - color4f[3] = 1; } } else if (r_textureunits.integer >= 2) { - for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4) + if (VectorLength2(diffusecolor) > 0) { - Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v); - if ((dist = fabs(v[2])) < 1) + for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4) { - distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale; - Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n); - if ((dot = DotProduct(n, v)) < 0) + Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v); + if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)])) { - shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n)); - color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity; - color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity; - color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity; + Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n); + if ((dot = DotProduct(n, v)) < 0) + { + shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n)); + color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity; + color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity; + color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity; + } + else + { + color4f[0] = ambientcolor[0] * distintensity; + color4f[1] = ambientcolor[1] * distintensity; + color4f[2] = ambientcolor[2] * distintensity; + } + if (r_refdef.fogenabled) + { + float f; + f = FogPoint_Model(vertex3f); + VectorScale(color4f, f, color4f); + } } else + VectorClear(color4f); + color4f[3] = 1; + } + } + else + { + for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4) + { + Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v); + if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)])) { color4f[0] = ambientcolor[0] * distintensity; color4f[1] = ambientcolor[1] * distintensity; color4f[2] = ambientcolor[2] * distintensity; + if (r_refdef.fogenabled) + { + float f; + f = FogPoint_Model(vertex3f); + VectorScale(color4f, f, color4f); + } } - if (r_refdef.fogenabled) - { - float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg)); - VectorScale(color4f, f, color4f); - } + else + VectorClear(color4f); + color4f[3] = 1; } - else - VectorClear(color4f); - color4f[3] = 1; } } else { - for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4) + if (VectorLength2(diffusecolor) > 0) { - Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v); - if ((dist = DotProduct(v, v)) < 1) + for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4) { - dist = sqrt(dist); - distintensity = pow(1 - dist, r_shadow_attenpower) * r_shadow_attenscale; - Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n); - if ((dot = DotProduct(n, v)) < 0) + Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v); + if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)])) { - shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n)); - color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity; - color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity; - color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity; + distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist); + Matrix4x4_Transform3x3(&r_shadow_entitytolight, normal3f, n); + if ((dot = DotProduct(n, v)) < 0) + { + shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n)); + color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity; + color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity; + color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity; + } + else + { + color4f[0] = ambientcolor[0] * distintensity; + color4f[1] = ambientcolor[1] * distintensity; + color4f[2] = ambientcolor[2] * distintensity; + } + if (r_refdef.fogenabled) + { + float f; + f = FogPoint_Model(vertex3f); + VectorScale(color4f, f, color4f); + } } else + VectorClear(color4f); + color4f[3] = 1; + } + } + else + { + for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4) + { + Matrix4x4_Transform(&r_shadow_entitytolight, vertex3f, v); + if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)])) { + distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist); color4f[0] = ambientcolor[0] * distintensity; color4f[1] = ambientcolor[1] * distintensity; color4f[2] = ambientcolor[2] * distintensity; + if (r_refdef.fogenabled) + { + float f; + f = FogPoint_Model(vertex3f); + VectorScale(color4f, f, color4f); + } } - if (r_refdef.fogenabled) - { - float f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg)); - VectorScale(color4f, f, color4f); - } + else + VectorClear(color4f); + color4f[3] = 1; } - else - VectorClear(color4f); - color4f[3] = 1; } } } @@ -1390,35 +1474,35 @@ static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int nu } } -static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt) +static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt) { // used to display how many times a surface is lit for level design purposes GL_Color(0.1 * r_view.colorscale, 0.025 * r_view.colorscale, 0, 1); - R_Mesh_ColorPointer(NULL); + R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); } -static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt) +static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt) { // ARB2 GLSL shader path (GFFX5200, Radeon 9500) - R_SetupSurfaceShader(lightcolorbase, false); - R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f); - R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f); - R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f); - R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f); + R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale); + R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f, rsurface_model->surfmesh.vbo, rsurface_model->surfmesh.vbooffset_texcoordtexture2f); + R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f, rsurface_svector3f_bufferobject, rsurface_svector3f_bufferoffset); + R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f, rsurface_tvector3f_bufferobject, rsurface_tvector3f_bufferoffset); + R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f, rsurface_normal3f_bufferobject, rsurface_normal3f_bufferoffset); if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) { qglDepthFunc(GL_EQUAL);CHECKGLERROR } - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) { qglDepthFunc(GL_LEQUAL);CHECKGLERROR } } -static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int numvertices, int numtriangles, const int *element3i, float r, float g, float b) +static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, float r, float g, float b) { // shared final code for all the dot3 layers int renders; @@ -1426,11 +1510,11 @@ static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int num for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--) { GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1); - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); } } -static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale) +static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale) { rmeshstate_t m; // colorscale accounts for how much we multiply the brightness @@ -1447,12 +1531,18 @@ static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int memset(&m, 0, sizeof(m)); m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture); m.pointer_texcoord3f[0] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset; m.texmatrix[0] = r_shadow_entitytoattenuationxyz; m.tex[1] = R_GetTexture(basetexture); m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[1] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[1] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[1] = rsurface_texture->currenttexmatrix; m.texcubemap[2] = R_GetTexture(r_shadow_rtlight->currentcubemap); m.pointer_texcoord3f[2] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset; m.texmatrix[2] = r_shadow_entitytolight; GL_BlendFunc(GL_ONE, GL_ONE); } @@ -1462,9 +1552,13 @@ static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int memset(&m, 0, sizeof(m)); m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture); m.pointer_texcoord3f[0] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset; m.texmatrix[0] = r_shadow_entitytoattenuationxyz; m.tex[1] = R_GetTexture(basetexture); m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[1] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[1] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[1] = rsurface_texture->currenttexmatrix; GL_BlendFunc(GL_ONE, GL_ONE); } @@ -1474,17 +1568,25 @@ static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture); m.pointer_texcoord3f[0] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset; m.texmatrix[0] = r_shadow_entitytoattenuationxyz; m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture); m.pointer_texcoord3f[1] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset; m.texmatrix[1] = r_shadow_entitytoattenuationz; m.tex[2] = R_GetTexture(basetexture); m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[2] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[2] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[2] = rsurface_texture->currenttexmatrix; if (r_shadow_rtlight->currentcubemap != r_texture_whitecube) { m.texcubemap[3] = R_GetTexture(r_shadow_rtlight->currentcubemap); m.pointer_texcoord3f[3] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[3] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[3] = rsurface_vertex3f_bufferoffset; m.texmatrix[3] = r_shadow_entitytolight; } GL_BlendFunc(GL_ONE, GL_ONE); @@ -1495,12 +1597,18 @@ static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture); m.pointer_texcoord3f[0] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset; m.texmatrix[0] = r_shadow_entitytoattenuationxyz; m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture); m.pointer_texcoord3f[1] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset; m.texmatrix[1] = r_shadow_entitytoattenuationz; m.tex[2] = R_GetTexture(basetexture); m.pointer_texcoord[2] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[2] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[2] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[2] = rsurface_texture->currenttexmatrix; GL_BlendFunc(GL_ONE, GL_ONE); } @@ -1510,34 +1618,42 @@ static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture); m.pointer_texcoord3f[0] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset; m.texmatrix[0] = r_shadow_entitytoattenuationxyz; m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture); m.pointer_texcoord3f[1] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset; m.texmatrix[1] = r_shadow_entitytoattenuationz; R_Mesh_TextureState(&m); GL_ColorMask(0,0,0,1); GL_BlendFunc(GL_ONE, GL_ZERO); - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // second pass memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(basetexture); m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; if (r_shadow_rtlight->currentcubemap != r_texture_whitecube) { m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap); m.pointer_texcoord3f[1] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset; m.texmatrix[1] = r_shadow_entitytolight; } GL_BlendFunc(GL_DST_ALPHA, GL_ONE); } // this final code is shared R_Mesh_TextureState(&m); - R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale); + R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale); } -static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale) +static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale) { rmeshstate_t m; // colorscale accounts for how much we multiply the brightness @@ -1557,27 +1673,37 @@ static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int m.tex[0] = R_GetTexture(normalmaptexture); m.texcombinergb[0] = GL_REPLACE; m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube); m.texcombinergb[1] = GL_DOT3_RGBA_ARB; m.pointer_texcoord3f[1] = rsurface_array_texcoord3f; + m.pointer_texcoord_bufferobject[1] = 0; + m.pointer_texcoord_bufferoffset[1] = 0; m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture); m.pointer_texcoord3f[2] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset; m.texmatrix[2] = r_shadow_entitytoattenuationxyz; R_Mesh_TextureState(&m); GL_ColorMask(0,0,0,1); GL_BlendFunc(GL_ONE, GL_ZERO); - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // second pass memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(basetexture); m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; if (r_shadow_rtlight->currentcubemap != r_texture_whitecube) { m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap); m.pointer_texcoord3f[1] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset; m.texmatrix[1] = r_shadow_entitytolight; } GL_BlendFunc(GL_DST_ALPHA, GL_ONE); @@ -1588,34 +1714,44 @@ static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int memset(&m, 0, sizeof(m)); m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture); m.pointer_texcoord3f[0] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset; m.texmatrix[0] = r_shadow_entitytoattenuationxyz; R_Mesh_TextureState(&m); GL_ColorMask(0,0,0,1); GL_BlendFunc(GL_ONE, GL_ZERO); - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // second pass memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(normalmaptexture); m.texcombinergb[0] = GL_REPLACE; m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube); m.texcombinergb[1] = GL_DOT3_RGBA_ARB; m.pointer_texcoord3f[1] = rsurface_array_texcoord3f; + m.pointer_texcoord_bufferobject[1] = 0; + m.pointer_texcoord_bufferoffset[1] = 0; R_Mesh_TextureState(&m); GL_BlendFunc(GL_DST_ALPHA, GL_ZERO); - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // second pass memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(basetexture); m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; if (r_shadow_rtlight->currentcubemap != r_texture_whitecube) { m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap); m.pointer_texcoord3f[1] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset; m.texmatrix[1] = r_shadow_entitytolight; } GL_BlendFunc(GL_DST_ALPHA, GL_ONE); @@ -1627,22 +1763,30 @@ static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int m.tex[0] = R_GetTexture(normalmaptexture); m.texcombinergb[0] = GL_REPLACE; m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube); m.texcombinergb[1] = GL_DOT3_RGBA_ARB; m.pointer_texcoord3f[1] = rsurface_array_texcoord3f; + m.pointer_texcoord_bufferobject[1] = 0; + m.pointer_texcoord_bufferoffset[1] = 0; R_Mesh_TextureState(&m); GL_ColorMask(0,0,0,1); GL_BlendFunc(GL_ONE, GL_ZERO); - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // second pass memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(basetexture); m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture); m.pointer_texcoord3f[1] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset; m.texmatrix[1] = r_shadow_entitytoattenuationxyz; GL_BlendFunc(GL_DST_ALPHA, GL_ONE); } @@ -1653,30 +1797,42 @@ static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int m.tex[0] = R_GetTexture(normalmaptexture); m.texcombinergb[0] = GL_REPLACE; m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube); m.texcombinergb[1] = GL_DOT3_RGBA_ARB; m.pointer_texcoord3f[1] = rsurface_array_texcoord3f; + m.pointer_texcoord_bufferobject[1] = 0; + m.pointer_texcoord_bufferoffset[1] = 0; m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture); m.pointer_texcoord3f[2] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset; m.texmatrix[2] = r_shadow_entitytoattenuationxyz; m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture); m.pointer_texcoord3f[3] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[3] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[3] = rsurface_vertex3f_bufferoffset; m.texmatrix[3] = r_shadow_entitytoattenuationz; R_Mesh_TextureState(&m); GL_ColorMask(0,0,0,1); GL_BlendFunc(GL_ONE, GL_ZERO); - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // second pass memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(basetexture); m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; if (r_shadow_rtlight->currentcubemap != r_texture_whitecube) { m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap); m.pointer_texcoord3f[1] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset; m.texmatrix[1] = r_shadow_entitytolight; } GL_BlendFunc(GL_DST_ALPHA, GL_ONE); @@ -1687,47 +1843,59 @@ static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture); m.pointer_texcoord3f[0] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset; m.texmatrix[0] = r_shadow_entitytoattenuationxyz; m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture); m.pointer_texcoord3f[1] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset; m.texmatrix[1] = r_shadow_entitytoattenuationz; R_Mesh_TextureState(&m); GL_ColorMask(0,0,0,1); GL_BlendFunc(GL_ONE, GL_ZERO); - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // second pass memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(normalmaptexture); m.texcombinergb[0] = GL_REPLACE; m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube); m.texcombinergb[1] = GL_DOT3_RGBA_ARB; m.pointer_texcoord3f[1] = rsurface_array_texcoord3f; + m.pointer_texcoord_bufferobject[1] = 0; + m.pointer_texcoord_bufferoffset[1] = 0; R_Mesh_TextureState(&m); GL_BlendFunc(GL_DST_ALPHA, GL_ZERO); - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // second pass memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(basetexture); m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; if (r_shadow_rtlight->currentcubemap != r_texture_whitecube) { m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap); m.pointer_texcoord3f[1] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset; m.texmatrix[1] = r_shadow_entitytolight; } GL_BlendFunc(GL_DST_ALPHA, GL_ONE); } // this final code is shared R_Mesh_TextureState(&m); - R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale); + R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale); } -static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale) +static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale) { float glossexponent; rmeshstate_t m; @@ -1743,41 +1911,51 @@ static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(normalmaptexture); m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube); m.texcombinergb[1] = GL_DOT3_RGBA_ARB; m.pointer_texcoord3f[1] = rsurface_array_texcoord3f; + m.pointer_texcoord_bufferobject[1] = 0; + m.pointer_texcoord_bufferoffset[1] = 0; R_Mesh_TextureState(&m); GL_ColorMask(0,0,0,1); // this squares the result GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO); - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // second and third pass R_Mesh_ResetTextureState(); // square alpha in framebuffer a few times to make it shiny GL_BlendFunc(GL_ZERO, GL_DST_ALPHA); for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2) - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // fourth pass memset(&m, 0, sizeof(m)); m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture); m.pointer_texcoord3f[0] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset; m.texmatrix[0] = r_shadow_entitytoattenuationxyz; R_Mesh_TextureState(&m); GL_BlendFunc(GL_DST_ALPHA, GL_ZERO); - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // fifth pass memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(glosstexture); m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; if (r_shadow_rtlight->currentcubemap != r_texture_whitecube) { m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap); m.pointer_texcoord3f[1] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset; m.texmatrix[1] = r_shadow_entitytolight; } GL_BlendFunc(GL_DST_ALPHA, GL_ONE); @@ -1788,30 +1966,38 @@ static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(normalmaptexture); m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube); m.texcombinergb[1] = GL_DOT3_RGBA_ARB; m.pointer_texcoord3f[1] = rsurface_array_texcoord3f; + m.pointer_texcoord_bufferobject[1] = 0; + m.pointer_texcoord_bufferoffset[1] = 0; R_Mesh_TextureState(&m); GL_ColorMask(0,0,0,1); // this squares the result GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO); - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // second and third pass R_Mesh_ResetTextureState(); // square alpha in framebuffer a few times to make it shiny GL_BlendFunc(GL_ZERO, GL_DST_ALPHA); for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2) - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // fourth pass memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(glosstexture); m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture); m.pointer_texcoord3f[1] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset; m.texmatrix[1] = r_shadow_entitytoattenuationxyz; GL_BlendFunc(GL_DST_ALPHA, GL_ONE); } @@ -1821,85 +2007,97 @@ static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(normalmaptexture); m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube); m.texcombinergb[1] = GL_DOT3_RGBA_ARB; m.pointer_texcoord3f[1] = rsurface_array_texcoord3f; + m.pointer_texcoord_bufferobject[1] = 0; + m.pointer_texcoord_bufferoffset[1] = 0; R_Mesh_TextureState(&m); GL_ColorMask(0,0,0,1); // this squares the result GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO); - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // second and third pass R_Mesh_ResetTextureState(); // square alpha in framebuffer a few times to make it shiny GL_BlendFunc(GL_ZERO, GL_DST_ALPHA); for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2) - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // fourth pass memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture); m.pointer_texcoord3f[0] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[0] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[0] = rsurface_vertex3f_bufferoffset; m.texmatrix[0] = r_shadow_entitytoattenuationxyz; m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture); m.pointer_texcoord3f[1] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset; m.texmatrix[1] = r_shadow_entitytoattenuationz; R_Mesh_TextureState(&m); GL_BlendFunc(GL_DST_ALPHA, GL_ZERO); - R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i); + R_Mesh_Draw(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); // fifth pass memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(glosstexture); m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; m.texmatrix[0] = rsurface_texture->currenttexmatrix; if (r_shadow_rtlight->currentcubemap != r_texture_whitecube) { m.texcubemap[1] = R_GetTexture(r_shadow_rtlight->currentcubemap); m.pointer_texcoord3f[1] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset; m.texmatrix[1] = r_shadow_entitytolight; } GL_BlendFunc(GL_DST_ALPHA, GL_ONE); } // this final code is shared R_Mesh_TextureState(&m); - R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale); + R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale); } -static void R_Shadow_RenderLighting_Light_Dot3(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt) +static void R_Shadow_RenderLighting_Light_Dot3(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt) { // ARB path (any Geforce, any Radeon) - qboolean doambient = r_shadow_rtlight->ambientscale > 0; - qboolean dodiffuse = r_shadow_rtlight->diffusescale > 0; + qboolean doambient = ambientscale > 0; + qboolean dodiffuse = diffusescale > 0; qboolean dospecular = specularscale > 0; if (!doambient && !dodiffuse && !dospecular) return; - R_Mesh_ColorPointer(NULL); + R_Mesh_ColorPointer(NULL, 0, 0); if (doambient) - R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, basetexture, r_shadow_rtlight->ambientscale * r_view.colorscale); + R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, ambientscale * r_view.colorscale); if (dodiffuse) - R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, basetexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale); + R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_view.colorscale); if (dopants) { if (doambient) - R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, lightcolorpants, pantstexture, r_shadow_rtlight->ambientscale * r_view.colorscale); + R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, ambientscale * r_view.colorscale); if (dodiffuse) - R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, lightcolorpants, pantstexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale); + R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_view.colorscale); } if (doshirt) { if (doambient) - R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, lightcolorshirt, shirttexture, r_shadow_rtlight->ambientscale * r_view.colorscale); + R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, ambientscale * r_view.colorscale); if (dodiffuse) - R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, lightcolorshirt, shirttexture, normalmaptexture, r_shadow_rtlight->diffusescale * r_view.colorscale); + R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_view.colorscale); } if (dospecular) - R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale); + R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_view.colorscale); } -void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2) +void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, vec3_t diffusecolor2, vec3_t ambientcolor2) { int renders; int i; @@ -1910,7 +2108,7 @@ void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstve int *newe; const int *e; float *c; - int newelements[3072]; + int newelements[4096*3]; R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2); for (renders = 0;renders < 64;renders++) { @@ -1947,9 +2145,9 @@ void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstve newe[2] = e[2]; newnumtriangles++; newe += 3; - if (newnumtriangles >= 1024) + if (newnumtriangles >= (int)(sizeof(newelements)/sizeof(float[3]))) { - R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements); + R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0); newnumtriangles = 0; newe = newelements; stop = false; @@ -1958,7 +2156,11 @@ void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstve } if (newnumtriangles >= 1) { - R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements); + // if all triangles are included, use the original array to take advantage of the bufferobject if possible + if (newnumtriangles == numtriangles) + R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset); + else + R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, newnumtriangles, newelements, 0, 0); stop = false; } // if we couldn't find any lit triangles, exit early @@ -1987,7 +2189,7 @@ void R_Shadow_RenderLighting_Light_Vertex_Pass(const model_t *model, int firstve } } -static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float specularscale, qboolean dopants, qboolean doshirt) +static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt) { // OpenGL 1.1 path (anything) model_t *model = rsurface_entity->model; @@ -1995,57 +2197,73 @@ static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertice float ambientcolorpants[3], diffusecolorpants[3]; float ambientcolorshirt[3], diffusecolorshirt[3]; rmeshstate_t m; - VectorScale(lightcolorbase, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorbase); - VectorScale(lightcolorbase, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorbase); - VectorScale(lightcolorpants, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorpants); - VectorScale(lightcolorpants, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorpants); - VectorScale(lightcolorshirt, r_shadow_rtlight->ambientscale * 2 * r_view.colorscale, ambientcolorshirt); - VectorScale(lightcolorshirt, r_shadow_rtlight->diffusescale * 2 * r_view.colorscale, diffusecolorshirt); + VectorScale(lightcolorbase, ambientscale * 2 * r_view.colorscale, ambientcolorbase); + VectorScale(lightcolorbase, diffusescale * 2 * r_view.colorscale, diffusecolorbase); + VectorScale(lightcolorpants, ambientscale * 2 * r_view.colorscale, ambientcolorpants); + VectorScale(lightcolorpants, diffusescale * 2 * r_view.colorscale, diffusecolorpants); + VectorScale(lightcolorshirt, ambientscale * 2 * r_view.colorscale, ambientcolorshirt); + VectorScale(lightcolorshirt, diffusescale * 2 * r_view.colorscale, diffusecolorshirt); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); - R_Mesh_ColorPointer(rsurface_array_color4f); + R_Mesh_ColorPointer(rsurface_array_color4f, 0, 0); memset(&m, 0, sizeof(m)); m.tex[0] = R_GetTexture(basetexture); m.texmatrix[0] = rsurface_texture->currenttexmatrix; m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f; + m.pointer_texcoord_bufferobject[0] = rsurface_model->surfmesh.vbo; + m.pointer_texcoord_bufferoffset[0] = rsurface_model->surfmesh.vbooffset_texcoordtexture2f; if (r_textureunits.integer >= 2) { // voodoo2 or TNT m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture); m.texmatrix[1] = r_shadow_entitytoattenuationxyz; m.pointer_texcoord3f[1] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[1] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[1] = rsurface_vertex3f_bufferoffset; if (r_textureunits.integer >= 3) { // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off) m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture); m.texmatrix[2] = r_shadow_entitytoattenuationz; m.pointer_texcoord3f[2] = rsurface_vertex3f; + m.pointer_texcoord_bufferobject[2] = rsurface_vertex3f_bufferobject; + m.pointer_texcoord_bufferoffset[2] = rsurface_vertex3f_bufferoffset; } } R_Mesh_TextureState(&m); - R_Mesh_TexBind(0, R_GetTexture(basetexture)); - R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase); + //R_Mesh_TexBind(0, R_GetTexture(basetexture)); + R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorbase, ambientcolorbase); if (dopants) { R_Mesh_TexBind(0, R_GetTexture(pantstexture)); - R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants); + R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorpants, ambientcolorpants); } if (doshirt) { R_Mesh_TexBind(0, R_GetTexture(shirttexture)); - R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt); + R_Shadow_RenderLighting_Light_Vertex_Pass(model, firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, diffusecolorshirt, ambientcolorshirt); } } -void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i) +void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *element3i, int element3i_bufferobject, size_t element3i_bufferoffset) { - // FIXME: support MATERIALFLAG_NODEPTHTEST + float ambientscale, diffusescale, specularscale; vec3_t lightcolorbase, lightcolorpants, lightcolorshirt; // calculate colors to render this texture with lightcolorbase[0] = r_shadow_rtlight->currentcolor[0] * rsurface_entity->colormod[0] * rsurface_texture->currentalpha; lightcolorbase[1] = r_shadow_rtlight->currentcolor[1] * rsurface_entity->colormod[1] * rsurface_texture->currentalpha; lightcolorbase[2] = r_shadow_rtlight->currentcolor[2] * rsurface_entity->colormod[2] * rsurface_texture->currentalpha; - if ((r_shadow_rtlight->ambientscale + r_shadow_rtlight->diffusescale) * VectorLength2(lightcolorbase) + (r_shadow_rtlight->specularscale * rsurface_texture->specularscale) * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f)) + ambientscale = r_shadow_rtlight->ambientscale; + diffusescale = r_shadow_rtlight->diffusescale; + specularscale = r_shadow_rtlight->specularscale * rsurface_texture->specularscale; + if (!r_shadow_usenormalmap.integer) + { + ambientscale += 1.0f * diffusescale; + diffusescale = 0; + specularscale = 0; + } + if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f)) return; + GL_DepthRange(0, (rsurface_texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1); GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST)); GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces if (rsurface_texture->colormapping) @@ -2072,16 +2290,16 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, { case R_SHADOW_RENDERMODE_VISIBLELIGHTING: GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer); - R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt); + R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt); break; case R_SHADOW_RENDERMODE_LIGHT_GLSL: - R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt); + R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt); break; case R_SHADOW_RENDERMODE_LIGHT_DOT3: - R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt); + R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt); break; case R_SHADOW_RENDERMODE_LIGHT_VERTEX: - R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, dopants, doshirt); + R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface_texture->basetexture, rsurface_texture->currentskinframe->pants, rsurface_texture->currentskinframe->shirt, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt); break; default: Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode); @@ -2094,16 +2312,16 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, { case R_SHADOW_RENDERMODE_VISIBLELIGHTING: GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer); - R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false); + R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, false, false); break; case R_SHADOW_RENDERMODE_LIGHT_GLSL: - R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false); + R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, false, false); break; case R_SHADOW_RENDERMODE_LIGHT_DOT3: - R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false); + R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, false, false); break; case R_SHADOW_RENDERMODE_LIGHT_VERTEX: - R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, r_shadow_rtlight->specularscale * rsurface_texture->specularscale, false, false); + R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i, element3i_bufferobject, element3i_bufferoffset, lightcolorbase, vec3_origin, vec3_origin, rsurface_texture->basetexture, r_texture_black, r_texture_black, rsurface_texture->currentskinframe->nmap, rsurface_texture->glosstexture, ambientscale, diffusescale, specularscale, false, false); break; default: Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode); @@ -2124,6 +2342,7 @@ void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec memset(rtlight, 0, sizeof(*rtlight)); // copy the properties + rtlight->matrix_lighttoworld = tempmatrix; Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix); Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin); rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix); @@ -2278,6 +2497,159 @@ void R_Shadow_UncompileWorldLights(void) R_RTLight_Uncompile(&light->rtlight); } +void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight) +{ + int i, j; + mplane_t plane; + // reset the count of frustum planes + // see r_shadow_rtlight_frustumplanes definition for how much this array + // can hold + r_shadow_rtlight_numfrustumplanes = 0; + +#if 1 + // generate a deformed frustum that includes the light origin, this is + // used to cull shadow casting surfaces that can not possibly cast a + // shadow onto the visible light-receiving surfaces, which can be a + // performance gain + // + // if the light origin is onscreen the result will be 4 planes exactly + // if the light origin is offscreen on only one axis the result will + // be exactly 5 planes (split-side case) + // if the light origin is offscreen on two axes the result will be + // exactly 4 planes (stretched corner case) + for (i = 0;i < 4;i++) + { + // quickly reject standard frustum planes that put the light + // origin outside the frustum + if (PlaneDiff(rtlight->shadoworigin, &r_view.frustum[i]) < -0.03125) + continue; + // copy the plane + r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = r_view.frustum[i]; + } + // if all the standard frustum planes were accepted, the light is onscreen + // otherwise we need to generate some more planes below... + if (r_shadow_rtlight_numfrustumplanes < 4) + { + // at least one of the stock frustum planes failed, so we need to + // create one or two custom planes to enclose the light origin + for (i = 0;i < 4;i++) + { + // create a plane using the view origin and light origin, and a + // single point from the frustum corner set + TriangleNormal(r_view.origin, r_view.frustumcorner[i], rtlight->shadoworigin, plane.normal); + VectorNormalize(plane.normal); + plane.dist = DotProduct(r_view.origin, plane.normal); + // see if this plane is backwards and flip it if so + for (j = 0;j < 4;j++) + if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125) + break; + if (j < 4) + { + VectorNegate(plane.normal, plane.normal); + plane.dist *= -1; + // flipped plane, test again to see if it is now valid + for (j = 0;j < 4;j++) + if (j != i && DotProduct(r_view.frustumcorner[j], plane.normal) - plane.dist < -0.03125) + break; + // if the plane is still not valid, then it is dividing the + // frustum and has to be rejected + if (j < 4) + continue; + } + // we have created a valid plane, compute extra info + PlaneClassify(&plane); + // copy the plane + r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane; +#if 1 + // if we've found 5 frustum planes then we have constructed a + // proper split-side case and do not need to keep searching for + // planes to enclose the light origin + if (r_shadow_rtlight_numfrustumplanes == 5) + break; +#endif + } + } +#endif + +#if 0 + for (i = 0;i < r_shadow_rtlight_numfrustumplanes;i++) + { + plane = r_shadow_rtlight_frustumplanes[i]; + Con_Printf("light %p plane #%i %f %f %f : %f (%f %f %f %f %f)\n", rtlight, i, plane.normal[0], plane.normal[1], plane.normal[2], plane.dist, PlaneDiff(r_view.frustumcorner[0], &plane), PlaneDiff(r_view.frustumcorner[1], &plane), PlaneDiff(r_view.frustumcorner[2], &plane), PlaneDiff(r_view.frustumcorner[3], &plane), PlaneDiff(rtlight->shadoworigin, &plane)); + } +#endif + +#if 0 + // now add the light-space box planes if the light box is rotated, as any + // caster outside the oriented light box is irrelevant (even if it passed + // the worldspace light box, which is axial) + if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1) + { + for (i = 0;i < 6;i++) + { + vec3_t v; + VectorClear(v); + v[i >> 1] = (i & 1) ? -1 : 1; + Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal); + VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal); + plane.dist = VectorNormalizeLength(plane.normal); + plane.dist += DotProduct(plane.normal, rtlight->shadoworigin); + r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane; + } + } +#endif + +#if 0 + // add the world-space reduced box planes + for (i = 0;i < 6;i++) + { + VectorClear(plane.normal); + plane.normal[i >> 1] = (i & 1) ? -1 : 1; + plane.dist = (i & 1) ? -r_shadow_rtlight_cullmaxs[i >> 1] : r_shadow_rtlight_cullmins[i >> 1]; + r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = plane; + } +#endif + +#if 0 + { + int j, oldnum; + vec3_t points[8]; + vec_t bestdist; + // reduce all plane distances to tightly fit the rtlight cull box, which + // is in worldspace + VectorSet(points[0], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmins[2]); + VectorSet(points[1], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmins[2]); + VectorSet(points[2], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmins[2]); + VectorSet(points[3], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmins[2]); + VectorSet(points[4], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmaxs[2]); + VectorSet(points[5], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmins[1], r_shadow_rtlight_cullmaxs[2]); + VectorSet(points[6], r_shadow_rtlight_cullmins[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmaxs[2]); + VectorSet(points[7], r_shadow_rtlight_cullmaxs[0], r_shadow_rtlight_cullmaxs[1], r_shadow_rtlight_cullmaxs[2]); + oldnum = r_shadow_rtlight_numfrustumplanes; + r_shadow_rtlight_numfrustumplanes = 0; + for (j = 0;j < oldnum;j++) + { + // find the nearest point on the box to this plane + bestdist = DotProduct(r_shadow_rtlight_frustumplanes[j].normal, points[0]); + for (i = 1;i < 8;i++) + { + dist = DotProduct(r_shadow_rtlight_frustumplanes[j].normal, points[i]); + if (bestdist > dist) + bestdist = dist; + } + Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, r_shadow_rtlight_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, r_shadow_rtlight_frustumplanes[j].normal[0], r_shadow_rtlight_frustumplanes[j].normal[1], r_shadow_rtlight_frustumplanes[j].normal[2], r_shadow_rtlight_frustumplanes[j].dist, bestdist); + // if the nearest point is near or behind the plane, we want this + // plane, otherwise the plane is useless as it won't cull anything + if (r_shadow_rtlight_frustumplanes[j].dist < bestdist + 0.03125) + { + PlaneClassify(&r_shadow_rtlight_frustumplanes[j]); + r_shadow_rtlight_frustumplanes[r_shadow_rtlight_numfrustumplanes++] = r_shadow_rtlight_frustumplanes[j]; + } + } + } +#endif +} + void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs) { RSurf_ActiveWorldEntity(); @@ -2288,19 +2660,19 @@ void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned for (mesh = r_shadow_rtlight->static_meshchain_shadow;mesh;mesh = mesh->next) { r_refdef.stats.lights_shadowtriangles += mesh->numtriangles; - R_Mesh_VertexPointer(mesh->vertex3f); + R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f); GL_LockArrays(0, mesh->numverts); if (r_shadow_rendermode == R_SHADOW_RENDERMODE_STENCIL) { // decrement stencil if backface is behind depthbuffer GL_CullFace(GL_BACK); // quake is backwards, this culls front faces qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR - R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i); + R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0); // increment stencil if frontface is behind depthbuffer GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR } - R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i); + R_Mesh_Draw(0, mesh->numverts, mesh->numtriangles, mesh->element3i, mesh->ebo, 0); GL_LockArrays(0, 0); } CHECKGLERROR @@ -2382,15 +2754,19 @@ void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfac void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) { - int i, usestencil; + int i; float f; int numleafs, numsurfaces; int *leaflist, *surfacelist; unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs; int numlightentities; + int numlightentities_noselfshadow; int numshadowentities; + int numshadowentities_noselfshadow; entity_render_t *lightentities[MAX_EDICTS]; + entity_render_t *lightentities_noselfshadow[MAX_EDICTS]; entity_render_t *shadowentities[MAX_EDICTS]; + entity_render_t *shadowentities_noselfshadow[MAX_EDICTS]; // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights) // skip lights that are basically invisible (color 0 0 0) @@ -2479,9 +2855,13 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) if (R_Shadow_ScissorForBBox(r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs)) return; + R_Shadow_ComputeShadowCasterCullingPlanes(rtlight); + // make a list of lit entities and shadow casting entities numlightentities = 0; + numlightentities_noselfshadow = 0; numshadowentities = 0; + numshadowentities_noselfshadow = 0; // add dynamic entities that are lit by the light if (r_drawentities.integer) { @@ -2492,6 +2872,10 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) vec3_t org; if (!BoxesOverlap(ent->mins, ent->maxs, r_shadow_rtlight_cullmins, r_shadow_rtlight_cullmaxs)) continue; + // skip the object entirely if it is not within the valid + // shadow-casting region (which includes the lit region) + if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, r_shadow_rtlight_numfrustumplanes, r_shadow_rtlight_frustumplanes)) + continue; if (!(model = ent->model)) continue; if (r_viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT)) @@ -2502,12 +2886,26 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) // so now check if it's in a leaf seen by the light if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)) continue; - lightentities[numlightentities++] = ent; + if (ent->flags & RENDER_NOSELFSHADOW) + lightentities_noselfshadow[numlightentities_noselfshadow++] = ent; + else + lightentities[numlightentities++] = ent; // since it is lit, it probably also casts a shadow... // about the VectorDistance2 - light emitting entities should not cast their own shadow Matrix4x4_OriginFromMatrix(&ent->matrix, org); if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1) - shadowentities[numshadowentities++] = ent; + { + // note: exterior models without the RENDER_NOSELFSHADOW + // flag still create a RENDER_NOSELFSHADOW shadow but + // are lit normally, this means that they are + // self-shadowing but do not shadow other + // RENDER_NOSELFSHADOW entities such as the gun + // (very weird, but keeps the player shadow off the gun) + if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL)) + shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent; + else + shadowentities[numshadowentities++] = ent; + } } else if (ent->flags & RENDER_SHADOW) { @@ -2520,7 +2918,12 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) // about the VectorDistance2 - light emitting entities should not cast their own shadow Matrix4x4_OriginFromMatrix(&ent->matrix, org); if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1) - shadowentities[numshadowentities++] = ent; + { + if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL)) + shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent; + else + shadowentities[numshadowentities++] = ent; + } } } } @@ -2538,51 +2941,95 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) // count this light in the r_speeds r_refdef.stats.lights++; - usestencil = false; - if (numsurfaces + numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows)) + if (r_showshadowvolumes.integer && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows)) + { + // optionally draw visible shape of the shadow volumes + // for performance analysis by level designers + R_Shadow_RenderMode_VisibleShadowVolumes(); + if (numsurfaces) + R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs); + for (i = 0;i < numshadowentities;i++) + R_Shadow_DrawEntityShadow(shadowentities[i]); + for (i = 0;i < numshadowentities_noselfshadow;i++) + R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]); + } + + if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows)) { // draw stencil shadow volumes to mask off pixels that are in shadow // so that they won't receive lighting - if (gl_stencil) + R_Shadow_RenderMode_StencilShadowVolumes(true); + if (numsurfaces) + R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs); + for (i = 0;i < numshadowentities;i++) + R_Shadow_DrawEntityShadow(shadowentities[i]); + if (numlightentities_noselfshadow) { - usestencil = true; - R_Shadow_RenderMode_StencilShadowVolumes(); - if (numsurfaces) - R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs); - for (i = 0;i < numshadowentities;i++) - R_Shadow_DrawEntityShadow(shadowentities[i]); + // draw lighting in the unmasked areas + R_Shadow_RenderMode_Lighting(true, false); + for (i = 0;i < numlightentities_noselfshadow;i++) + R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist); + + // optionally draw the illuminated areas + // for performance analysis by level designers + if (r_showlighting.integer) + { + R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false); + for (i = 0;i < numlightentities_noselfshadow;i++) + R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist); + } + + R_Shadow_RenderMode_StencilShadowVolumes(false); } + for (i = 0;i < numshadowentities_noselfshadow;i++) + R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]); - // optionally draw visible shape of the shadow volumes - // for performance analysis by level designers - if (r_showshadowvolumes.integer) + if (numsurfaces + numlightentities) { - R_Shadow_RenderMode_VisibleShadowVolumes(); + // draw lighting in the unmasked areas + R_Shadow_RenderMode_Lighting(true, false); if (numsurfaces) - R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs); - for (i = 0;i < numshadowentities;i++) - R_Shadow_DrawEntityShadow(shadowentities[i]); + R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs); + for (i = 0;i < numlightentities;i++) + R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist); + + // optionally draw the illuminated areas + // for performance analysis by level designers + if (r_showlighting.integer) + { + R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false); + if (numsurfaces) + R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs); + for (i = 0;i < numlightentities;i++) + R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist); + } } } - - if (numsurfaces + numlightentities) + else { - // draw lighting in the unmasked areas - R_Shadow_RenderMode_Lighting(usestencil, false); - if (numsurfaces) - R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs); - for (i = 0;i < numlightentities;i++) - R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist); - - // optionally draw the illuminated areas - // for performance analysis by level designers - if (r_showlighting.integer) + if (numsurfaces + numlightentities) { - R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false); + // draw lighting in the unmasked areas + R_Shadow_RenderMode_Lighting(false, false); if (numsurfaces) R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs); for (i = 0;i < numlightentities;i++) R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist); + for (i = 0;i < numlightentities_noselfshadow;i++) + R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist); + + // optionally draw the illuminated areas + // for performance analysis by level designers + if (r_showlighting.integer) + { + R_Shadow_RenderMode_VisibleLighting(false, false); + if (numsurfaces) + R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs); + for (i = 0;i < numlightentities;i++) + R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist); + for (i = 0;i < numlightentities_noselfshadow;i++) + R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist); + } } } } @@ -2646,7 +3093,7 @@ void R_DrawModelShadows(void) else r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL; - R_Shadow_RenderMode_StencilShadowVolumes(); + R_Shadow_RenderMode_StencilShadowVolumes(true); for (i = 0;i < r_refdef.numentities;i++) { @@ -2680,11 +3127,12 @@ void R_DrawModelShadows(void) GL_ScissorTest(true); R_Mesh_Matrix(&identitymatrix); R_Mesh_ResetTextureState(); - R_Mesh_VertexPointer(vertex3f); - R_Mesh_ColorPointer(NULL); + R_Mesh_VertexPointer(vertex3f, 0, 0); + R_Mesh_ColorPointer(NULL, 0, 0); // set up a 50% darkening blend on shadowed areas GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_DepthRange(0, 1); GL_DepthTest(false); GL_DepthMask(false); qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR @@ -2697,7 +3145,7 @@ void R_DrawModelShadows(void) qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR // apply the blend to the shadowed areas - R_Mesh_Draw(0, 4, 2, polygonelements); + R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0); // restoring the perspective view is done by R_RenderScene //R_SetupView(&r_view.matrix); @@ -2904,7 +3352,7 @@ void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const r { // this is never batched (there can be only one) float scale = r_editlights_cursorgrid.value * 0.5f; - R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[1]->tex, NULL, false, r_editlights_cursorlocation, r_view.right, r_view.up, scale, -scale, -scale, scale, 1, 1, 1, 0.5f); + R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[1]->tex, NULL, false, false, r_editlights_cursorlocation, r_view.right, r_view.up, scale, -scale, -scale, scale, 1, 1, 1, 0.5f); } void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) @@ -2918,7 +3366,7 @@ void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, co intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0); if (!light->shadow) intensity *= 0.5f; - R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacelist[0]]->tex, NULL, false, light->origin, r_view.right, r_view.up, 8, -8, -8, 8, intensity, intensity, intensity, 0.5); + R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacelist[0]]->tex, NULL, false, false, light->origin, r_view.right, r_view.up, 8, -8, -8, 8, intensity, intensity, intensity, 0.5f); } void R_Shadow_DrawLightSprites(void) @@ -3171,7 +3619,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void) data = r_refdef.worldmodel->brush.entities; if (!data) return; - for (entnum = 0;COM_ParseTokenConsole(&data) && com_token[0] == '{';entnum++) + for (entnum = 0;COM_ParseToken_Simple(&data, false) && com_token[0] == '{';entnum++) { type = LIGHTTYPE_MINUSX; origin[0] = origin[1] = origin[2] = 0; @@ -3189,7 +3637,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void) islight = false; while (1) { - if (!COM_ParseTokenConsole(&data)) + if (!COM_ParseToken_Simple(&data, false)) break; // error if (com_token[0] == '}') break; // end of entity @@ -3199,7 +3647,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void) strlcpy(key, com_token, sizeof(key)); while (key[strlen(key)-1] == ' ') // remove trailing spaces key[strlen(key)-1] = 0; - if (!COM_ParseTokenConsole(&data)) + if (!COM_ParseToken_Simple(&data, false)) break; // error strlcpy(value, com_token, sizeof(value)); @@ -3807,24 +4255,24 @@ void R_Shadow_EditLights_DrawSelectedLightProperties(void) for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next) if (light == r_shadow_selectedlight) lightnumber = lightcount; - sprintf(temp, "Cursor %f %f %f Total Lights %i", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2], lightcount);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; + sprintf(temp, "Cursor %f %f %f Total Lights %i", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2], lightcount);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; if (r_shadow_selectedlight == NULL) return; - sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; - sprintf(temp, "Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; - sprintf(temp, "Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; - sprintf(temp, "Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; - sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; - sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; - sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; - sprintf(temp, "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; - sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; - sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; - sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; - sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; - sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; - sprintf(temp, "NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; - sprintf(temp, "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; + sprintf(temp, "Light #%i properties", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; + sprintf(temp, "Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; + sprintf(temp, "Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; + sprintf(temp, "Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; + sprintf(temp, "Radius : %f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; + sprintf(temp, "Corona : %f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; + sprintf(temp, "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; + sprintf(temp, "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; + sprintf(temp, "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; + sprintf(temp, "CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; + sprintf(temp, "Ambient : %f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; + sprintf(temp, "Diffuse : %f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; + sprintf(temp, "Specular : %f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; + sprintf(temp, "NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; + sprintf(temp, "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8; } void R_Shadow_EditLights_ToggleShadow_f(void)