X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=r_shadow.c;h=03e064440070b3b1bf7f07ba36b8a08bb018a6f3;hp=66ff022ee06ee7352b856abddb431d4952101511;hb=59158546b21b9ef4b9f7ead745ad544363907af6;hpb=66afccaa60735a237612d08ea9b01d7fe8115b0d diff --git a/r_shadow.c b/r_shadow.c index 66ff022e..03e06444 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -158,12 +158,21 @@ typedef enum r_shadow_rendermode_e R_SHADOW_RENDERMODE_LIGHT_GLSL, R_SHADOW_RENDERMODE_VISIBLEVOLUMES, R_SHADOW_RENDERMODE_VISIBLELIGHTING, - R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE, R_SHADOW_RENDERMODE_SHADOWMAP2D, + R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE, R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE, } r_shadow_rendermode_t; +typedef enum r_shadow_shadowmode_e +{ + R_SHADOW_SHADOWMODE_STENCIL, + R_SHADOW_SHADOWMODE_SHADOWMAP2D, + R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE, + R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE +} +r_shadow_shadowmode_t; + r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE; r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE; r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE; @@ -171,16 +180,26 @@ r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_N qboolean r_shadow_usingshadowmaprect; qboolean r_shadow_usingshadowmap2d; qboolean r_shadow_usingshadowmapcube; -float r_shadow_shadowmap_bias; +int r_shadow_shadowmapside; float r_shadow_shadowmap_texturescale[2]; float r_shadow_shadowmap_parameters[4]; +#if 0 int r_shadow_drawbuffer; int r_shadow_readbuffer; +#endif +int r_shadow_cullface_front, r_shadow_cullface_back; GLuint r_shadow_fborectangle; -GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS][6]; +GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS]; GLuint r_shadow_fbo2d; -int r_shadow_shadowmode; +r_shadow_shadowmode_t r_shadow_shadowmode; +int r_shadow_shadowmapfilterquality; +int r_shadow_shadowmaptexturetype; +int r_shadow_shadowmapdepthbits; int r_shadow_shadowmapmaxsize; +qboolean r_shadow_shadowmapvsdct; +qboolean r_shadow_shadowmapsampler; +int r_shadow_shadowmappcf; +int r_shadow_shadowmapborder; int r_shadow_lightscissor[4]; int maxshadowtriangles; @@ -195,6 +214,11 @@ int *shadowmark; int *shadowmarklist; int shadowmarkcount; +int maxshadowsides; +int numshadowsides; +unsigned char *shadowsides; +int *shadowsideslist; + int maxvertexupdate; int *vertexupdate; int *vertexremap; @@ -208,6 +232,7 @@ int *r_shadow_buffer_leaflist; int r_shadow_buffer_numsurfacepvsbytes; unsigned char *r_shadow_buffer_surfacepvs; int *r_shadow_buffer_surfacelist; +unsigned char *r_shadow_buffer_surfacesides; int r_shadow_buffer_numshadowtrispvsbytes; unsigned char *r_shadow_buffer_shadowtrispvs; @@ -218,11 +243,11 @@ rtexturepool_t *r_shadow_texturepool; rtexture_t *r_shadow_attenuationgradienttexture; rtexture_t *r_shadow_attenuation2dtexture; rtexture_t *r_shadow_attenuation3dtexture; -rtexture_t *r_shadow_lightcorona; +skinframe_t *r_shadow_lightcorona; rtexture_t *r_shadow_shadowmaprectangletexture; rtexture_t *r_shadow_shadowmap2dtexture; -rtexture_t *r_shadow_shadowmapcubeprojectiontexture; rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS]; +rtexture_t *r_shadow_shadowmapvsdcttexture; int r_shadow_shadowmapsize; // changes for each light based on distance int r_shadow_shadowmaplod; // changes for each light based on distance @@ -235,11 +260,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_dot3 = {CVAR_SAVE, "r_shadow_dot3", "0", "enables use of (slow) per pixel lighting on GL1.3 hardware"}; 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_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"}; cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"}; 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"}; @@ -261,14 +288,20 @@ cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compi cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"}; cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"}; cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"}; -cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "0", "shadowmap filter modes: 0 = no filtering, 1 = bilinear, 2 = bilinear small blur (fast), 3 = bilinear large blur (slow)"}; +cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"}; +cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"}; +cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"}; +cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"}; cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"}; -cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "1024", "shadowmap size limit"}; -cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"}; -cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"}; -cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "6", "shadowmap size bias for filtering"}; +cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"}; +cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"}; +//cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"}; +//cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"}; +cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"}; cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"}; cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"}; +cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"}; +cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"}; cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"}; cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"}; cvar_t r_shadow_polygonoffset = {0, "r_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)"}; @@ -326,24 +359,92 @@ void R_Shadow_EditLights_Reload_f(void); void R_Shadow_ValidateCvars(void); static void R_Shadow_MakeTextures(void); -// VorteX: custom editor light sprites #define EDLIGHTSPRSIZE 8 -cachepic_t *r_editlights_sprcursor; -cachepic_t *r_editlights_sprlight; -cachepic_t *r_editlights_sprnoshadowlight; -cachepic_t *r_editlights_sprcubemaplight; -cachepic_t *r_editlights_sprcubemapnoshadowlight; -cachepic_t *r_editlights_sprselection; +skinframe_t *r_editlights_sprcursor; +skinframe_t *r_editlights_sprlight; +skinframe_t *r_editlights_sprnoshadowlight; +skinframe_t *r_editlights_sprcubemaplight; +skinframe_t *r_editlights_sprcubemapnoshadowlight; +skinframe_t *r_editlights_sprselection; +extern cvar_t gl_max_size; + +void R_Shadow_SetShadowMode(void) +{ + r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, gl_max_size.integer / 4); + r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0; + r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer; + r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer; + r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer; + r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16); + r_shadow_shadowmaplod = -1; + r_shadow_shadowmapsize = 0; + r_shadow_shadowmapsampler = false; + r_shadow_shadowmappcf = 0; + r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL; + if(r_shadow_shadowmapping.integer && r_glsl.integer && gl_support_fragment_shader && gl_support_ext_framebuffer_object) + { + if(r_shadow_shadowmapfilterquality < 0) + { + if(strstr(gl_vendor, "NVIDIA")) + { + r_shadow_shadowmapsampler = gl_support_arb_shadow; + r_shadow_shadowmappcf = 1; + } + else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) + r_shadow_shadowmappcf = 1; + else if(strstr(gl_vendor, "ATI")) + r_shadow_shadowmappcf = 1; + else + r_shadow_shadowmapsampler = gl_support_arb_shadow; + } + else + { + switch (r_shadow_shadowmapfilterquality) + { + case 1: + r_shadow_shadowmapsampler = gl_support_arb_shadow; + break; + case 2: + r_shadow_shadowmapsampler = gl_support_arb_shadow; + r_shadow_shadowmappcf = 1; + break; + case 3: + r_shadow_shadowmappcf = 1; + break; + case 4: + r_shadow_shadowmappcf = 2; + break; + } + } + switch (r_shadow_shadowmaptexturetype) + { + case 0: + r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D; + break; + case 1: + r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE; + break; + case 2: + r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE; + break; + default: + if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler) + r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D; + else if(gl_texturerectangle) + r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE; + else + r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D; + break; + } + } +} void R_Shadow_FreeShadowMaps(void) { int i; - r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048); - r_shadow_shadowmode = r_shadow_shadowmapping.integer; - r_shadow_shadowmaplod = -1; + R_Shadow_SetShadowMode(); - CHECKGLERROR if (r_shadow_fborectangle) qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle); r_shadow_fborectangle = 0; @@ -353,10 +454,9 @@ void R_Shadow_FreeShadowMaps(void) qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d); r_shadow_fbo2d = 0; CHECKGLERROR - for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++) - if (r_shadow_fbocubeside[i][0]) - qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]); + if (r_shadow_fbocubeside[i]) + qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]); memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside)); CHECKGLERROR @@ -368,15 +468,15 @@ void R_Shadow_FreeShadowMaps(void) R_FreeTexture(r_shadow_shadowmap2dtexture); r_shadow_shadowmap2dtexture = NULL; - if (r_shadow_shadowmapcubeprojectiontexture) - R_FreeTexture(r_shadow_shadowmapcubeprojectiontexture); - r_shadow_shadowmapcubeprojectiontexture = NULL; - for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++) if (r_shadow_shadowmapcubetexture[i]) R_FreeTexture(r_shadow_shadowmapcubetexture[i]); memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture)); + if (r_shadow_shadowmapvsdcttexture) + R_FreeTexture(r_shadow_shadowmapvsdcttexture); + r_shadow_shadowmapvsdcttexture = NULL; + CHECKGLERROR } @@ -387,16 +487,23 @@ void r_shadow_start(void) r_shadow_attenuationgradienttexture = NULL; r_shadow_attenuation2dtexture = NULL; r_shadow_attenuation3dtexture = NULL; + r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL; r_shadow_shadowmaprectangletexture = NULL; - memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture)); - r_shadow_shadowmapcubeprojectiontexture = NULL; r_shadow_shadowmap2dtexture = NULL; + memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture)); + r_shadow_shadowmapvsdcttexture = NULL; r_shadow_shadowmapmaxsize = 0; r_shadow_shadowmapsize = 0; r_shadow_shadowmaplod = 0; + r_shadow_shadowmapfilterquality = -1; + r_shadow_shadowmaptexturetype = -1; + r_shadow_shadowmapdepthbits = 0; + r_shadow_shadowmapvsdct = false; + r_shadow_shadowmapsampler = false; + r_shadow_shadowmappcf = 0; r_shadow_fborectangle = 0; - memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside)); r_shadow_fbo2d = 0; + memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside)); R_Shadow_FreeShadowMaps(); @@ -417,6 +524,10 @@ void r_shadow_start(void) shadowmark = NULL; shadowmarklist = NULL; shadowmarkcount = 0; + maxshadowsides = 0; + numshadowsides = 0; + shadowsides = NULL; + shadowsideslist = NULL; r_shadow_buffer_numleafpvsbytes = 0; r_shadow_buffer_visitingleafpvs = NULL; r_shadow_buffer_leafpvs = NULL; @@ -424,6 +535,7 @@ void r_shadow_start(void) r_shadow_buffer_numsurfacepvsbytes = 0; r_shadow_buffer_surfacepvs = NULL; r_shadow_buffer_surfacelist = NULL; + r_shadow_buffer_surfacesides = NULL; r_shadow_buffer_numshadowtrispvsbytes = 0; r_shadow_buffer_shadowtrispvs = NULL; r_shadow_buffer_numlighttrispvsbytes = 0; @@ -468,6 +580,14 @@ void r_shadow_shutdown(void) Mem_Free(shadowmarklist); shadowmarklist = NULL; shadowmarkcount = 0; + maxshadowsides = 0; + numshadowsides = 0; + if (shadowsides) + Mem_Free(shadowsides); + shadowsides = NULL; + if (shadowsideslist) + Mem_Free(shadowsideslist); + shadowsideslist = NULL; r_shadow_buffer_numleafpvsbytes = 0; if (r_shadow_buffer_visitingleafpvs) Mem_Free(r_shadow_buffer_visitingleafpvs); @@ -485,6 +605,9 @@ void r_shadow_shutdown(void) if (r_shadow_buffer_surfacelist) Mem_Free(r_shadow_buffer_surfacelist); r_shadow_buffer_surfacelist = NULL; + if (r_shadow_buffer_surfacesides) + Mem_Free(r_shadow_buffer_surfacesides); + r_shadow_buffer_surfacesides = NULL; r_shadow_buffer_numshadowtrispvsbytes = 0; if (r_shadow_buffer_shadowtrispvs) Mem_Free(r_shadow_buffer_shadowtrispvs); @@ -495,6 +618,13 @@ void r_shadow_shutdown(void) void r_shadow_newmap(void) { + if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona); + if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor); + if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight); + if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight); + if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight); + if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight); + if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection); if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname))) R_Shadow_EditLights_Reload_f(); } @@ -538,12 +668,14 @@ void R_Shadow_Init(void) { Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture); Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap); + Cvar_RegisterVariable(&r_shadow_dot3); 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_gloss2exponent); Cvar_RegisterVariable(&r_shadow_glossexact); Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias); Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale); @@ -565,14 +697,20 @@ void R_Shadow_Init(void) Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling); Cvar_RegisterVariable(&r_shadow_scissor); Cvar_RegisterVariable(&r_shadow_shadowmapping); + Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct); + Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype); Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality); + Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits); + Cvar_RegisterVariable(&r_shadow_shadowmapping_precision); Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize); Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize); - Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias); - Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale); +// Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias); +// Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale); Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize); Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip); Cvar_RegisterVariable(&r_shadow_shadowmapping_bias); + Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor); + Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset); Cvar_RegisterVariable(&r_shadow_culltriangles); Cvar_RegisterVariable(&r_shadow_polygonfactor); Cvar_RegisterVariable(&r_shadow_polygonoffset); @@ -604,6 +742,10 @@ void R_Shadow_Init(void) shadowmark = NULL; shadowmarklist = NULL; shadowmarkcount = 0; + maxshadowsides = 0; + numshadowsides = 0; + shadowsides = NULL; + shadowsideslist = NULL; r_shadow_buffer_numleafpvsbytes = 0; r_shadow_buffer_visitingleafpvs = NULL; r_shadow_buffer_leafpvs = NULL; @@ -611,6 +753,7 @@ void R_Shadow_Init(void) r_shadow_buffer_numsurfacepvsbytes = 0; r_shadow_buffer_surfacepvs = NULL; r_shadow_buffer_surfacelist = NULL; + r_shadow_buffer_surfacesides = NULL; r_shadow_buffer_shadowtrispvs = NULL; r_shadow_buffer_lighttrispvs = NULL; R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap); @@ -636,15 +779,17 @@ matrix4x4_t matrix_attenuationz = } }; -void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles) +void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale) { + numvertices = ((numvertices + 255) & ~255) * vertscale; + numtriangles = ((numtriangles + 255) & ~255) * triscale; // make sure shadowelements is big enough for this volume if (maxshadowtriangles < numtriangles) { maxshadowtriangles = numtriangles; if (shadowelements) Mem_Free(shadowelements); - shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24])); + shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3])); } // make sure shadowvertex3f is big enough for this volume if (maxshadowvertices < numvertices) @@ -652,7 +797,7 @@ void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles) maxshadowvertices = numvertices; if (shadowvertex3f) Mem_Free(shadowvertex3f); - shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6])); + shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3])); } } @@ -681,9 +826,12 @@ static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, Mem_Free(r_shadow_buffer_surfacepvs); if (r_shadow_buffer_surfacelist) Mem_Free(r_shadow_buffer_surfacelist); + if (r_shadow_buffer_surfacesides) + Mem_Free(r_shadow_buffer_surfacesides); r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes; r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes); r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist)); + r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist)); } if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes) { @@ -725,6 +873,21 @@ void R_Shadow_PrepareShadowMark(int numtris) numshadowmark = 0; } +void R_Shadow_PrepareShadowSides(int numtris) +{ + if (maxshadowsides < numtris) + { + maxshadowsides = numtris; + if (shadowsides) + Mem_Free(shadowsides); + if (shadowsideslist) + Mem_Free(shadowsideslist); + shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides)); + shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist)); + } + numshadowsides = 0; +} + static int R_Shadow_ConstructShadowVolume_ZFail(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris) { int i, j; @@ -1120,8 +1283,8 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, if (!numverts || !nummarktris) return; // make sure shadowelements is big enough for this volume - if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts) - R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255); + if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2) + R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8); if (maxvertexupdate < numverts) { @@ -1193,32 +1356,313 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, } } -void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, int vertex3f_bufferobject, int vertex3f_bufferoffset, const int *elements, int nummarktris, const int *marktris) +int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias) { - int i, tris = nummarktris; - int *outelement3i; - const int *element; - if (!numverts || !nummarktris) + // p1, p2, p3 are in the cubemap's local coordinate system + // bias = border/(size - border) + int mask = 0x3F; + + float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1), + dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2), + dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3); + if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3) + mask &= (3<<4) + | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2)) + | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2)) + | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2)); + if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3) + mask &= (3<<4) + | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2)) + | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2)) + | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2)); + + dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1), + dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2), + dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3); + if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3) + mask &= (3<<0) + | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4)) + | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4)) + | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4)); + if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3) + mask &= (3<<0) + | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4)) + | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4)) + | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4)); + + dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1), + dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2), + dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3); + if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3) + mask &= (3<<2) + | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0)) + | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0)) + | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0)); + if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3) + mask &= (3<<2) + | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0)) + | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0)) + | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0)); + + return mask; +} + +int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias) +{ + vec3_t center, radius, lightcenter, lightradius, pmin, pmax; + float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2; + int mask = 0x3F; + + VectorSubtract(maxs, mins, radius); + VectorScale(radius, 0.5f, radius); + VectorAdd(mins, radius, center); + Matrix4x4_Transform(worldtolight, center, lightcenter); + Matrix4x4_Transform3x3(radiustolight, radius, lightradius); + VectorSubtract(lightcenter, lightradius, pmin); + VectorAdd(lightcenter, lightradius, pmax); + + dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1), + dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2); + if(ap1 > bias*an1 && ap2 > bias*an2) + mask &= (3<<4) + | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2)) + | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2)); + if(an1 > bias*ap1 && an2 > bias*ap2) + mask &= (3<<4) + | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2)) + | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2)); + + dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1), + dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2); + if(ap1 > bias*an1 && ap2 > bias*an2) + mask &= (3<<0) + | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4)) + | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4)); + if(an1 > bias*ap1 && an2 > bias*ap2) + mask &= (3<<0) + | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4)) + | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4)); + + dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1), + dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2); + if(ap1 > bias*an1 && ap2 > bias*an2) + mask &= (3<<2) + | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0)) + | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0)); + if(an1 > bias*ap1 && an2 > bias*ap2) + mask &= (3<<2) + | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0)) + | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0)); + + return mask; +} + +#define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias) + +int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias) +{ + // p is in the cubemap's local coordinate system + // bias = border/(size - border) + float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn); + float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn); + float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn); + int mask = 0x3F; + if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2)); + if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2)); + if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4)); + if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4)); + if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0)); + if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0)); + return mask; +} + +int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border) +{ + int i; + vec3_t p, n; + int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 }; + float scale = (size - 2*border)/size, len; + float bias = border / (float)(size - border), dp, dn, ap, an; + // check if cone enclosing side would cross frustum plane + scale = 2 / (scale*scale + 2); + for (i = 0;i < 5;i++) + { + if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125) + continue; + Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n); + len = scale*VectorLength2(n); + if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0); + if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2); + if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4); + } + if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125) + { + Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n); + len = scale*VectorLength(n); + if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0); + if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2); + if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4); + } + // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results + // check if frustum corners/origin cross plane sides + for (i = 0;i < 5;i++) + { + Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p); + dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn), + masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2)); + masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2)); + dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn), + masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4)); + masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4)); + dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn), + masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0)); + masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0)); + } + return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5]; +} + +int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals) +{ + int t, tend; + const int *e; + const float *v[3]; + float normal[3]; + vec3_t p[3]; + float bias; + int mask, surfacemask = 0; + if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs)) + return 0; + bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder); + tend = firsttriangle + numtris; + if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs)) + { + // surface box entirely inside light box, no box cull + if (projectdirection) + { + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + { + v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3; + TriangleNormal(v[0], v[1], v[2], normal); + if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)) + { + Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]); + mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias); + surfacemask |= mask; + if(totals) + { + totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5; + shadowsides[numshadowsides] = mask; + shadowsideslist[numshadowsides++] = t; + } + } + } + } + else + { + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + { + v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3; + if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])) + { + Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]); + mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias); + surfacemask |= mask; + if(totals) + { + totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5; + shadowsides[numshadowsides] = mask; + shadowsideslist[numshadowsides++] = t; + } + } + } + } + } + else + { + // surface box not entirely inside light box, cull each triangle + if (projectdirection) + { + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + { + v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3; + TriangleNormal(v[0], v[1], v[2], normal); + if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0) + && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs)) + { + Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]); + mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias); + surfacemask |= mask; + if(totals) + { + totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5; + shadowsides[numshadowsides] = mask; + shadowsideslist[numshadowsides++] = t; + } + } + } + } + else + { + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + { + v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3; + if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]) + && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs)) + { + Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]); + mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias); + surfacemask |= mask; + if(totals) + { + totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5; + shadowsides[numshadowsides] = mask; + shadowsideslist[numshadowsides++] = t; + } + } + } + } + } + return surfacemask; +} + +void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, const int *elements, int numsidetris, const int *sidetotals, const unsigned char *sides, const int *sidetris) +{ + int i, j, outtriangles = 0; + int *outelement3i[6]; + if (!numverts || !numsidetris || !r_shadow_compilingrtlight) return; + outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5]; // make sure shadowelements is big enough for this mesh - if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts) - R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255); + if (maxshadowtriangles < outtriangles) + R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1); - // gather up the (sparse) triangles into one array - outelement3i = shadowelements; - for (i = 0;i < nummarktris;i++) + // compute the offset and size of the separate index lists for each cubemap side + outtriangles = 0; + for (i = 0;i < 6;i++) { - element = elements + marktris[i] * 3; - outelement3i[0] = element[0]; - outelement3i[1] = element[1]; - outelement3i[2] = element[2]; - outelement3i += 3; + outelement3i[i] = shadowelements + outtriangles * 3; + r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles; + r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i]; + outtriangles += sidetotals[i]; } - r_refdef.stats.lights_dynamicshadowtriangles += tris; - r_refdef.stats.lights_shadowtriangles += tris; - R_Mesh_VertexPointer(vertex3f, vertex3f_bufferobject, vertex3f_bufferoffset); - R_Mesh_Draw(0, numverts, 0, tris, shadowelements, NULL, 0, 0); + // gather up the (sparse) triangles into separate index lists for each cubemap side + for (i = 0;i < numsidetris;i++) + { + const int *element = elements + sidetris[i] * 3; + for (j = 0;j < 6;j++) + { + if (sides[i] & (1 << j)) + { + outelement3i[j][0] = element[0]; + outelement3i[j][1] = element[1]; + outelement3i[j][2] = element[2]; + outelement3i[j] += 3; + } + } + } + + Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements); } static void R_Shadow_MakeTextures_MakeCorona(void) @@ -1240,7 +1684,7 @@ static void R_Shadow_MakeTextures_MakeCorona(void) pixels[y][x][3] = 255; } } - r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL); + r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_PRECACHE | TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32); } static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z) @@ -1256,6 +1700,7 @@ static void R_Shadow_MakeTextures(void) int x, y, z; float intensity, dist; unsigned int *data; + R_Shadow_FreeShadowMaps(); R_FreeTexturePool(&r_shadow_texturepool); r_shadow_texturepool = R_AllocTexturePool(); r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value; @@ -1293,12 +1738,114 @@ static void R_Shadow_MakeTextures(void) R_Shadow_MakeTextures_MakeCorona(); // Editor light sprites - r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor"); - r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light"); - r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow"); - r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight"); - r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight"); - r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection"); + r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) + "................" + ".3............3." + "..5...2332...5.." + "...7.3....3.7..." + "....7......7...." + "...3.7....7.3..." + "..2...7..7...2.." + "..3..........3.." + "..3..........3.." + "..2...7..7...2.." + "...3.7....7.3..." + "....7......7...." + "...7.3....3.7..." + "..5...2332...5.." + ".3............3." + "................" + , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); + r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) + "................" + "................" + "......1111......" + "....11233211...." + "...1234554321..." + "...1356776531..." + "..124677776421.." + "..135777777531.." + "..135777777531.." + "..124677776421.." + "...1356776531..." + "...1234554321..." + "....11233211...." + "......1111......" + "................" + "................" + , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); + r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) + "................" + "................" + "......1111......" + "....11233211...." + "...1234554321..." + "...1356226531..." + "..12462..26421.." + "..1352....2531.." + "..1352....2531.." + "..12462..26421.." + "...1356226531..." + "...1234554321..." + "....11233211...." + "......1111......" + "................" + "................" + , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); + r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) + "................" + "................" + "......2772......" + "....27755772...." + "..277533335772.." + "..753333333357.." + "..777533335777.." + "..735775577537.." + "..733357753337.." + "..733337733337.." + "..753337733357.." + "..277537735772.." + "....27777772...." + "......2772......" + "................" + "................" + , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); + r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *) + "................" + "................" + "......2772......" + "....27722772...." + "..2772....2772.." + "..72........27.." + "..7772....2777.." + "..7.27722772.7.." + "..7...2772...7.." + "..7....77....7.." + "..72...77...27.." + "..2772.77.2772.." + "....27777772...." + "......2772......" + "................" + "................" + , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); + r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *) + "................" + ".777752..257777." + ".742........247." + ".72..........27." + ".7............7." + ".5............5." + ".2............2." + "................" + "................" + ".2............2." + ".5............5." + ".7............7." + ".72..........27." + ".742........247." + ".777752..257777." + "................" + , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic); } void R_Shadow_ValidateCvars(void) @@ -1313,8 +1860,10 @@ void R_Shadow_ValidateCvars(void) void R_Shadow_RenderMode_Begin(void) { +#if 0 GLint drawbuffer; GLint readbuffer; +#endif R_Shadow_ValidateCvars(); if (!r_shadow_attenuation2dtexture @@ -1332,7 +1881,7 @@ void R_Shadow_RenderMode_Begin(void) GL_DepthTest(true); GL_DepthMask(false); GL_Color(0, 0, 0, 1); - GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height); + GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE; @@ -1354,16 +1903,20 @@ void R_Shadow_RenderMode_Begin(void) if (r_glsl.integer && gl_support_fragment_shader) r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL; - else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil) + else if (gl_dot3arb && gl_texturecubemap && r_shadow_dot3.integer && gl_stencil) r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3; else r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX; CHECKGLERROR +#if 0 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR r_shadow_drawbuffer = drawbuffer; r_shadow_readbuffer = readbuffer; +#endif + r_shadow_cullface_front = r_refdef.view.cullface_front; + r_shadow_cullface_back = r_refdef.view.cullface_back; } void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight) @@ -1382,8 +1935,10 @@ void R_Shadow_RenderMode_Reset(void) { qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR } +#if 0 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR +#endif R_SetViewport(&r_refdef.view.viewport); GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]); R_Mesh_ColorPointer(NULL, 0, 0); @@ -1397,6 +1952,8 @@ void R_Shadow_RenderMode_Reset(void) qglStencilMask(~0);CHECKGLERROR qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR + r_refdef.view.cullface_front = r_shadow_cullface_front; + r_refdef.view.cullface_back = r_shadow_cullface_back; GL_CullFace(r_refdef.view.cullface_back); GL_Color(1, 1, 1, 1); GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); @@ -1465,152 +2022,176 @@ void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass) } } +static void R_Shadow_MakeVSDCT(void) +{ + // maps to a 2x3 texture rectangle with normalized coordinates + // +- + // XX + // YY + // ZZ + // stores abs(dir.xy), offset.xy/2.5 + unsigned char data[4*6] = + { + 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5> + 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5> + 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5> + 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5> + 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5> + 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5> + }; + r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL); +} + void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size) { - int i; int status; int maxsize; - float nearclip, farclip; + float nearclip, farclip, bias; r_viewport_t viewport; + GLuint fbo = 0; CHECKGLERROR - maxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048); + maxsize = r_shadow_shadowmapmaxsize; nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius; farclip = 1.0f; - r_shadow_shadowmap_bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius; - r_shadow_shadowmap_parameters[0] = 1.0f - r_shadow_shadowmapping_bordersize.value / size; - r_shadow_shadowmap_parameters[1] = 1.0f - r_shadow_shadowmapping_bordersize.value / size; - r_shadow_shadowmap_parameters[2] = -(farclip + nearclip) / (farclip - nearclip); - r_shadow_shadowmap_parameters[3] = -2.0f * nearclip * farclip / (farclip - nearclip); - if (r_shadow_shadowmapping.integer == 1) - { + bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius; + r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip); + r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias; + r_shadow_shadowmapside = side; + r_shadow_shadowmapsize = size; + if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D) + { + r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder); + r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size; + R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL); + if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done; + // complex unrolled cube approach (more flexible) - //if (!r_shadow_shadowmapcubeprojectiontexture) - // r_shadow_shadowmapcubeprojectiontexture = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection"); + if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture) + R_Shadow_MakeVSDCT(); if (!r_shadow_shadowmap2dtexture) { #if 1 - r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*4); + int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4; + r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler); qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR -#endif - } - CHECKGLERROR - R_Shadow_RenderMode_Reset(); - if (r_shadow_shadowmap2dtexture) - { - // render depth into the fbo, do not render color at all - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR + // render depth into the fbo, do not render color at all qglDrawBuffer(GL_NONE);CHECKGLERROR qglReadBuffer(GL_NONE);CHECKGLERROR status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer) { Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status); Cvar_SetValueQuick(&r_shadow_shadowmapping, 0); } - R_SetupDepthOrShadowShader(); - } - else - { - R_SetupShowDepthShader(); - qglClearColor(1,1,1,1);CHECKGLERROR +#endif } - R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL); - r_shadow_shadowmap_texturescale[0] = (float)size / R_TextureWidth(r_shadow_shadowmap2dtexture); - r_shadow_shadowmap_texturescale[1] = (float)size / R_TextureHeight(r_shadow_shadowmap2dtexture); + CHECKGLERROR + if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d; + r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture); + r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture); r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D; } - else if (r_shadow_shadowmapping.integer == 2) + else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE) { + r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder); + r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size; + R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL); + if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done; + // complex unrolled cube approach (more flexible) - //if (!r_shadow_shadowmapcubeprojectiontexture) - // r_shadow_shadowmapcubeprojectiontexture = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection"); + if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture) + R_Shadow_MakeVSDCT(); if (!r_shadow_shadowmaprectangletexture) { #if 1 - r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*4); + r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler); qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR -#endif - } - CHECKGLERROR - R_Shadow_RenderMode_Reset(); - if (r_shadow_shadowmaprectangletexture) - { // render depth into the fbo, do not render color at all - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR qglDrawBuffer(GL_NONE);CHECKGLERROR qglReadBuffer(GL_NONE);CHECKGLERROR status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer) { Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status); Cvar_SetValueQuick(&r_shadow_shadowmapping, 0); } - R_SetupDepthOrShadowShader(); - } - else - { - R_SetupShowDepthShader(); - qglClearColor(1,1,1,1);CHECKGLERROR +#endif } - R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL); - r_shadow_shadowmap_texturescale[0] = size; - r_shadow_shadowmap_texturescale[1] = size; + CHECKGLERROR + if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle; + r_shadow_shadowmap_texturescale[0] = 1.0f; + r_shadow_shadowmap_texturescale[1] = 1.0f; r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE; } - else if (r_shadow_shadowmapping.integer == 3) + else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE) { + r_shadow_shadowmap_parameters[0] = 1.0f; + r_shadow_shadowmap_parameters[1] = 1.0f; + R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL); + if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done; + // simple cube approach if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) { -#if 1 - r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size); - qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR - for (i = 0;i < 6;i++) - { - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + i, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR - } -#endif - } - CHECKGLERROR - R_Shadow_RenderMode_Reset(); - if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) - { + #if 1 + r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler); + qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR + qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR + qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR // render depth into the fbo, do not render color at all - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR qglDrawBuffer(GL_NONE);CHECKGLERROR qglReadBuffer(GL_NONE);CHECKGLERROR status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) + if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer) { Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status); Cvar_SetValueQuick(&r_shadow_shadowmapping, 0); } - R_SetupDepthOrShadowShader(); - } - else - { - R_SetupShowDepthShader(); - qglClearColor(1,1,1,1);CHECKGLERROR + #endif } - R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL); - r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]); - r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]); + CHECKGLERROR + if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod]; + r_shadow_shadowmap_texturescale[0] = 0.0f; + r_shadow_shadowmap_texturescale[1] = 0.0f; r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE; } + + R_Shadow_RenderMode_Reset(); + if (fbo) + { + qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR + R_SetupDepthOrShadowShader(); + } + else + { + R_SetupShowDepthShader(); + qglClearColor(1,1,1,1);CHECKGLERROR + } CHECKGLERROR - R_SetViewport(&viewport); - GL_PolygonOffset(0, 0); - GL_CullFace(GL_NONE); // quake is backwards - GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height); + GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value); GL_DepthMask(true); GL_DepthTest(true); - qglClearDepth(1);CHECKGLERROR + qglClearDepth(1); CHECKGLERROR + +init_done: + R_SetViewport(&viewport); + GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height); + if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) + { + int flipped = (side&1)^(side>>2); + r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front; + r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back; + GL_CullFace(r_refdef.view.cullface_back); + } + else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) + { + qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR + } if (clear) qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); CHECKGLERROR @@ -1618,6 +2199,13 @@ void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size) void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping) { + if (transparent) + { + r_shadow_lightscissor[0] = r_refdef.view.viewport.x; + r_shadow_lightscissor[1] = r_refdef.view.viewport.y; + r_shadow_lightscissor[2] = r_refdef.view.viewport.width; + r_shadow_lightscissor[3] = r_refdef.view.viewport.height; + } CHECKGLERROR R_Shadow_RenderMode_Reset(); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); @@ -1641,29 +2229,35 @@ void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qb CHECKGLERROR if (shadowmapping) { - if (r_shadow_shadowmapping.integer == 1) + if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D) { r_shadow_usingshadowmap2d = true; R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture)); CHECKGLERROR } - else if (r_shadow_shadowmapping.integer == 2) + else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE) { r_shadow_usingshadowmaprect = true; R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture)); CHECKGLERROR } - else if (r_shadow_shadowmapping.integer == 3) + else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE) { r_shadow_usingshadowmapcube = true; R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])); CHECKGLERROR } + + if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect)) + { + R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture)); + CHECKGLERROR + } } } else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX) R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0); - GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + //GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); CHECKGLERROR } @@ -1706,7 +2300,7 @@ void R_Shadow_RenderMode_End(void) R_Shadow_RenderMode_Reset(); R_Shadow_RenderMode_ActiveLight(NULL); GL_DepthMask(true); - GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height); + GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE; } @@ -1743,10 +2337,10 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs) int sign[8]; float f; - r_shadow_lightscissor[0] = r_refdef.view.x; - r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height; - r_shadow_lightscissor[2] = r_refdef.view.width; - r_shadow_lightscissor[3] = r_refdef.view.height; + r_shadow_lightscissor[0] = r_refdef.view.viewport.x; + r_shadow_lightscissor[1] = r_refdef.view.viewport.y; + r_shadow_lightscissor[2] = r_refdef.view.viewport.width; + r_shadow_lightscissor[3] = r_refdef.view.viewport.height; if (!r_shadow_scissor.integer) return false; @@ -1819,16 +2413,16 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs) // now convert the scissor rectangle to integer screen coordinates ix1 = (int)(x1 - 1.0f); - iy1 = (int)(y1 - 1.0f); + iy1 = vid.height - (int)(y2 - 1.0f); ix2 = (int)(x2 + 1.0f); - iy2 = (int)(y2 + 1.0f); + iy2 = vid.height - (int)(y1 + 1.0f); //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2); // clamp it to the screen - if (ix1 < r_refdef.view.x) ix1 = r_refdef.view.x; - if (iy1 < r_refdef.view.y) iy1 = r_refdef.view.y; - if (ix2 > r_refdef.view.x + r_refdef.view.width) ix2 = r_refdef.view.x + r_refdef.view.width; - if (iy2 > r_refdef.view.y + r_refdef.view.height) iy2 = r_refdef.view.y + r_refdef.view.height; + if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x; + if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y; + if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width; + if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height; // if it is inside out, it's not visible if (ix2 <= ix1 || iy2 <= iy1) @@ -1836,7 +2430,7 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs) // the light area is visible, set up the scissor rectangle r_shadow_lightscissor[0] = ix1; - r_shadow_lightscissor[1] = vid.height - iy2; + r_shadow_lightscissor[1] = iy1; r_shadow_lightscissor[2] = ix2 - ix1; r_shadow_lightscissor[3] = iy2 - iy1; @@ -1846,8 +2440,8 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs) static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor) { - float *vertex3f = rsurface.vertex3f + 3 * firstvertex; - float *normal3f = rsurface.normal3f + 3 * firstvertex; + const float *vertex3f = rsurface.vertex3f + 3 * firstvertex; + const float *normal3f = rsurface.normal3f + 3 * firstvertex; float *color4f = rsurface.array_color4f + 4 * firstvertex; float dist, dot, distintensity, shadeintensity, v[3], n[3]; if (r_textureunits.integer >= 3) @@ -1868,7 +2462,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu if (r_refdef.fogenabled) { float f; - f = FogPoint_Model(vertex3f); + f = RSurf_FogVertex(vertex3f); VectorScale(color4f, f, color4f); } color4f[3] = 1; @@ -1883,7 +2477,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu { float f; Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v); - f = FogPoint_Model(vertex3f); + f = RSurf_FogVertex(vertex3f); VectorScale(color4f, f, color4f); } color4f[3] = 1; @@ -1916,7 +2510,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu if (r_refdef.fogenabled) { float f; - f = FogPoint_Model(vertex3f); + f = RSurf_FogVertex(vertex3f); VectorScale(color4f, f, color4f); } } @@ -1938,7 +2532,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu if (r_refdef.fogenabled) { float f; - f = FogPoint_Model(vertex3f); + f = RSurf_FogVertex(vertex3f); VectorScale(color4f, f, color4f); } } @@ -1975,7 +2569,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu if (r_refdef.fogenabled) { float f; - f = FogPoint_Model(vertex3f); + f = RSurf_FogVertex(vertex3f); VectorScale(color4f, f, color4f); } } @@ -1998,7 +2592,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu if (r_refdef.fogenabled) { float f; - f = FogPoint_Model(vertex3f); + f = RSurf_FogVertex(vertex3f); VectorScale(color4f, f, color4f); } } @@ -2044,7 +2638,7 @@ static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int nu { VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir); VectorNormalize(lightdir); - VectorSubtract(rsurface.modelorg, vertex3f, eyedir); + VectorSubtract(rsurface.localvieworigin, vertex3f, eyedir); VectorNormalize(eyedir); VectorAdd(lightdir, eyedir, halfdir); // the cubemap normalizes this for us @@ -2816,7 +3410,7 @@ static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertice m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset; if (r_textureunits.integer >= 3) { - // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off) + // Voodoo4 or Kyro (or Geforce3/Radeon with r_shadow_dot3 off) m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture); m.texmatrix[2] = rsurface.entitytoattenuationz; m.pointer_texcoord3f[2] = rsurface.vertex3f; @@ -2843,6 +3437,7 @@ extern cvar_t gl_lightmaps; void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject) { float ambientscale, diffusescale, specularscale; + qboolean negated; vec3_t lightcolorbase, lightcolorpants, lightcolorshirt; rtexture_t *nmap; // calculate colors to render this texture with @@ -2860,6 +3455,12 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle } if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f)) return; + negated = (lightcolorbase[0] + lightcolorbase[1] + lightcolorbase[2] < 0) && gl_support_ext_blend_subtract; + if(negated) + { + VectorNegate(lightcolorbase, lightcolorbase); + qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT); + } RSurf_SetupDepthAndCulling(); nmap = rsurface.texture->currentskinframe->nmap; if (gl_lightmaps.integer) @@ -2926,6 +3527,8 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle break; } } + if(negated) + qglBlendEquationEXT(GL_FUNC_ADD_EXT); } void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, int shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags) @@ -2983,12 +3586,15 @@ void R_RTLight_Compile(rtlight_t *rtlight) // compile the light rtlight->compiled = true; + rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1; rtlight->static_numleafs = 0; rtlight->static_numleafpvsbytes = 0; rtlight->static_leaflist = NULL; rtlight->static_leafpvs = NULL; rtlight->static_numsurfaces = 0; rtlight->static_surfacelist = NULL; + rtlight->static_shadowmap_receivers = 0x3F; + rtlight->static_shadowmap_casters = 0x3F; rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius; rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius; rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius; @@ -2998,7 +3604,7 @@ void R_RTLight_Compile(rtlight_t *rtlight) if (model && model->GetLightInfo) { - // this variable must be set for the CompileShadowVolume code + // this variable must be set for the CompileShadowVolume/CompileShadowMap code r_shadow_compilingrtlight = rtlight; R_Shadow_EnlargeLeafSurfaceTrisBuffer(model->brush.num_leafs, model->num_surfaces, model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles, model->surfmesh.num_triangles); model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs); @@ -3026,8 +3632,19 @@ void R_RTLight_Compile(rtlight_t *rtlight) memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes); if (rtlight->static_numlighttrispvsbytes) memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes); - if (model->CompileShadowVolume && rtlight->shadow) - model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist); + switch (rtlight->shadowmode) + { + case R_SHADOW_SHADOWMODE_SHADOWMAP2D: + case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE: + case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE: + if (model->CompileShadowMap && rtlight->shadow) + model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist); + break; + default: + if (model->CompileShadowVolume && rtlight->shadow) + model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist); + break; + } // now we're done compiling the rtlight r_shadow_compilingrtlight = NULL; } @@ -3073,6 +3690,9 @@ void R_RTLight_Uncompile(rtlight_t *rtlight) if (rtlight->static_meshchain_shadow_zfail) Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail); rtlight->static_meshchain_shadow_zfail = NULL; + if (rtlight->static_meshchain_shadow_shadowmap) + Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap); + rtlight->static_meshchain_shadow_shadowmap = NULL; // these allocations are grouped if (rtlight->static_surfacelist) Mem_Free(rtlight->static_surfacelist); @@ -3270,7 +3890,34 @@ void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight) #endif } -void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs) +void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides) +{ + shadowmesh_t *mesh; + + RSurf_ActiveWorldEntity(); + + if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer) + { + CHECKGLERROR + GL_CullFace(GL_NONE); + mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap; + for (;mesh;mesh = mesh->next) + { + if (!mesh->sidetotals[r_shadow_shadowmapside]) + continue; + r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside]; + R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f); + R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s); + } + CHECKGLERROR + } + else if (r_refdef.scene.worldentity->model) + r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, surfacesides, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs); + + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity +} + +void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs) { qboolean zpass; shadowmesh_t *mesh; @@ -3279,13 +3926,6 @@ void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned msurface_t *surface; RSurf_ActiveWorldEntity(); - if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) - { - if (r_refdef.scene.worldentity->model) - r_refdef.scene.worldmodel->DrawShadowMap(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs); - rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity - return; - } if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer) { @@ -3355,7 +3995,9 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent) relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius; relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius; if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) - ent->model->DrawShadowMap(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs); + { + ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs); + } else ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs); rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity @@ -3407,70 +4049,22 @@ void R_Shadow_DrawEntityLight(entity_render_t *ent) rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity } -/* -{{ 0, 0, 0}, "px", true, true, true}, -{{ 0, 90, 0}, "py", false, true, false}, -{{ 0, 180, 0}, "nx", false, false, true}, -{{ 0, 270, 0}, "ny", true, false, false}, -{{-90, 180, 0}, "pz", false, false, true}, -{{ 90, 180, 0}, "nz", false, false, true} -*/ - -static const double shadowviewmat16[6][4][4] = -{ - { - {-1, 0, 0, 0}, - { 0, -1, 0, 0}, - { 0, 0, 1, 0}, - { 0, 0, 0, 1}, - }, - { - { 0, -1, 0, 0}, - {-1, 0, 0, 0}, - { 0, 0, 1, 0}, - { 0, 0, 0, 1}, - }, - { - {-1, 0, 0, 0}, - { 0, -1, 0, 0}, - { 0, 0, 1, 0}, - { 0, 0, 0, 1}, - }, - { - { 0, -1, 0, 0}, - {-1, 0, 0, 0}, - { 0, 0, 1, 0}, - { 0, 0, 0, 1}, - }, - { - { 0, 0, 1, 0}, - { 0, -1, 0, 0}, - { 1, 0, 0, 0}, - { 0, 0, 0, 1}, - }, - { - { 0, 0, -1, 0}, - { 0, -1, 0, 0}, - {-1, 0, 0, 0}, - { 0, 0, 0, 1}, - }, -}; - void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) { int i; float f; int numleafs, numsurfaces; int *leaflist, *surfacelist; - unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs; + unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides; int numlightentities; int numlightentities_noselfshadow; int numshadowentities; int numshadowentities_noselfshadow; static entity_render_t *lightentities[MAX_EDICTS]; - static entity_render_t *lightentities_noselfshadow[MAX_EDICTS]; static entity_render_t *shadowentities[MAX_EDICTS]; - static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS]; + static unsigned char entitysides[MAX_EDICTS]; + int lightentities_noselfshadow; + int shadowentities_noselfshadow; vec3_t nearestpoint; vec_t distance; qboolean castshadows; @@ -3485,8 +4079,13 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) // all at once at the start of a level, not when it stalls gameplay. // (especially important to benchmarks) // compile light - if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer) + if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer) + { + if (rtlight->compiled) + R_RTLight_Uncompile(rtlight); R_RTLight_Compile(rtlight); + } + // load cubemap rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube; @@ -3521,6 +4120,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) leafpvs = rtlight->static_leafpvs; numsurfaces = rtlight->static_numsurfaces; surfacelist = rtlight->static_surfacelist; + surfacesides = NULL; shadowtrispvs = rtlight->static_shadowtrispvs; lighttrispvs = rtlight->static_lighttrispvs; } @@ -3533,6 +4133,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) leaflist = r_shadow_buffer_leaflist; leafpvs = r_shadow_buffer_leafpvs; surfacelist = r_shadow_buffer_surfacelist; + surfacesides = r_shadow_buffer_surfacesides; shadowtrispvs = r_shadow_buffer_shadowtrispvs; lighttrispvs = r_shadow_buffer_lighttrispvs; // if the reduced leaf bounds are offscreen, skip it @@ -3547,6 +4148,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) leafpvs = NULL; numsurfaces = 0; surfacelist = NULL; + surfacesides = NULL; shadowtrispvs = NULL; lighttrispvs = NULL; } @@ -3568,8 +4170,11 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) // make a list of lit entities and shadow casting entities numlightentities = 0; numlightentities_noselfshadow = 0; + lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1; numshadowentities = 0; numshadowentities_noselfshadow = 0; + shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1; + // add dynamic entities that are lit by the light if (r_drawentities.integer) { @@ -3595,7 +4200,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs)) continue; if (ent->flags & RENDER_NOSELFSHADOW) - lightentities_noselfshadow[numlightentities_noselfshadow++] = ent; + lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent; else lightentities[numlightentities++] = ent; // since it is lit, it probably also casts a shadow... @@ -3610,7 +4215,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) // 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; + shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent; else shadowentities[numshadowentities++] = ent; } @@ -3628,7 +4233,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1) { if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL)) - shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent; + shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent; else shadowentities[numshadowentities++] = ent; } @@ -3655,11 +4260,11 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) // for performance analysis by level designers R_Shadow_RenderMode_VisibleShadowVolumes(); if (numsurfaces) - R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs); + R_Shadow_DrawWorldShadow_ShadowVolume(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]); + R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]); } if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow) @@ -3672,7 +4277,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) for (i = 0;i < numlightentities;i++) R_Shadow_DrawEntityLight(lightentities[i]); for (i = 0;i < numlightentities_noselfshadow;i++) - R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]); + R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]); } castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows); @@ -3681,33 +4286,80 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]); nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]); distance = VectorDistance(nearestpoint, r_refdef.view.origin); - lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance)); - lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer); - if (castshadows && r_shadow_shadowmapping.integer >= 1 && r_shadow_shadowmapping.integer <= 3 && r_glsl.integer && gl_support_fragment_shader) + lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius)); + //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance)); + lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize); + + if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)) { + float borderbias; int side; int size; + int castermask = 0; + int receivermask = 0; + matrix4x4_t radiustolight = rtlight->matrix_worldtolight; + Matrix4x4_Abs(&radiustolight); r_shadow_shadowmaplod = 0; for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++) - if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear) + if ((r_shadow_shadowmapmaxsize >> i) > lodlinear) r_shadow_shadowmaplod = i; - size = lodlinear; - if (r_shadow_shadowmapping.integer == 3) - size = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) >> r_shadow_shadowmaplod; - size = bound(1, size, 2048); + if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE) + size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod); + else + size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize); + + borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder); + + if (numsurfaces) + { + if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer) + { + castermask = rtlight->static_shadowmap_casters; + receivermask = rtlight->static_shadowmap_receivers; + } + else + { + for(i = 0;i < numsurfaces;i++) + { + msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i]; + surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias); + castermask |= surfacesides[i]; + receivermask |= surfacesides[i]; + } + } + } + if (receivermask < 0x3F) + { + for (i = 0;i < numlightentities;i++) + receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias); + if (receivermask < 0x3F) + for(i = 0; i < numlightentities_noselfshadow;i++) + receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias); + } + + receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder); + + if (receivermask) + { + for (i = 0;i < numshadowentities;i++) + castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); + for (i = 0;i < numshadowentities_noselfshadow;i++) + castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); + } //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size); // render shadow casters into 6 sided depth texture - for (side = 0;side < 6;side++) + for (side = 0;side < 6;side++) if (receivermask & (1 << side)) { R_Shadow_RenderMode_ShadowMap(side, true, size); + if (! (castermask & (1 << side))) continue; if (numsurfaces) - R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs); - for (i = 0;i < numshadowentities;i++) + R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides); + for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side)) R_Shadow_DrawEntityShadow(shadowentities[i]); } @@ -3717,31 +4369,18 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) // draw lighting in the unmasked areas R_Shadow_RenderMode_Lighting(false, false, true); for (i = 0;i < numlightentities_noselfshadow;i++) - R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]); + R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]); } // render shadow casters into 6 sided depth texture - for (side = 0;side < 6;side++) + if (numshadowentities_noselfshadow) { - R_Shadow_RenderMode_ShadowMap(side, false, size); - for (i = 0;i < numshadowentities_noselfshadow;i++) - R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]); -#if 0 - if (r_shadow_shadowmapping.integer == 1) + for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side)) { - int w = R_TextureWidth(r_shadow_shadowmap2dtexture); - int h = R_TextureHeight(r_shadow_shadowmap2dtexture); - static int once = true; - if (once) - { - unsigned char *blah = Z_Malloc(w*h*4); - qglReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, blah);CHECKGLERROR - FS_WriteFile("testshadowmap.bin", blah, w*h*4); - Z_Free(blah); - } - once = false; + R_Shadow_RenderMode_ShadowMap(side, false, size); + for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] & (1 << side)) + R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]); } -#endif } // render lighting using the depth texture as shadowmap @@ -3757,9 +4396,10 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) { // draw stencil shadow volumes to mask off pixels that are in shadow // so that they won't receive lighting + GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]); R_Shadow_ClearStencil(); if (numsurfaces) - R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs); + R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs); for (i = 0;i < numshadowentities;i++) R_Shadow_DrawEntityShadow(shadowentities[i]); if (numlightentities_noselfshadow) @@ -3767,7 +4407,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) // draw lighting in the unmasked areas R_Shadow_RenderMode_Lighting(true, false, false); for (i = 0;i < numlightentities_noselfshadow;i++) - R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]); + R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]); // optionally draw the illuminated areas // for performance analysis by level designers @@ -3775,11 +4415,11 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) { R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false); for (i = 0;i < numlightentities_noselfshadow;i++) - R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]); + R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]); } } for (i = 0;i < numshadowentities_noselfshadow;i++) - R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]); + R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]); if (numsurfaces + numlightentities) { @@ -3802,7 +4442,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) for (i = 0;i < numlightentities;i++) R_Shadow_DrawEntityLight(lightentities[i]); for (i = 0;i < numlightentities_noselfshadow;i++) - R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]); + R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]); } } } @@ -3815,8 +4455,15 @@ void R_ShadowVolumeLighting(qboolean visible) size_t lightindex; dlight_t *light; size_t range; + float f; - if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) || r_shadow_shadowmode != r_shadow_shadowmapping.integer) + if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, gl_max_size.integer / 4) || + (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer && r_glsl.integer && gl_support_fragment_shader && gl_support_ext_framebuffer_object) || + r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) || + r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer || + r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || + r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || + r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16)) R_Shadow_FreeShadowMaps(); if (r_editlights.integer) @@ -3843,16 +4490,30 @@ void R_ShadowVolumeLighting(qboolean visible) } } if (r_refdef.scene.rtdlight) + { for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++) R_DrawRTLight(r_refdef.scene.lights[lnum], visible); + } + else if(gl_flashblend.integer) + { + for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++) + { + rtlight_t *rtlight = r_refdef.scene.lights[lnum]; + f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value; + VectorScale(rtlight->color, f, rtlight->currentcolor); + } + } R_Shadow_RenderMode_End(); } +extern const float r_screenvertex3f[12]; extern void R_SetupView(qboolean allowwaterclippingplane); +extern void R_ResetViewRendering3D(void); +extern void R_ResetViewRendering2D(void); extern cvar_t r_shadows; extern cvar_t r_shadows_darken; -extern cvar_t r_shadows_drawafterrtlightning; +extern cvar_t r_shadows_drawafterrtlighting; extern cvar_t r_shadows_castfrombmodels; extern cvar_t r_shadows_throwdistance; extern cvar_t r_shadows_throwdirection; @@ -3865,36 +4526,21 @@ void R_DrawModelShadows(void) vec3_t relativelightdirection; vec3_t relativeshadowmins, relativeshadowmaxs; vec3_t tmp, shadowdir; - float vertex3f[12]; - r_viewport_t viewport; if (!r_drawentities.integer || !gl_stencil) return; CHECKGLERROR - GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height); - - r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE; + R_ResetViewRendering3D(); + //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height); + R_Shadow_RenderMode_Begin(); + R_Shadow_RenderMode_ActiveLight(NULL); r_shadow_lightscissor[0] = r_refdef.view.x; r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height; r_shadow_lightscissor[2] = r_refdef.view.width; r_shadow_lightscissor[3] = r_refdef.view.height; - - if (gl_ext_separatestencil.integer) - { - r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL; - r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL; - } - else if (gl_ext_stenciltwoside.integer) - { - r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE; - r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE; - } - else - { - r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL; - r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL; - } + R_Shadow_RenderMode_StencilShadowVolumes(false); // get shadow dir if (r_shadows.integer == 2) @@ -3954,55 +4600,50 @@ void R_DrawModelShadows(void) } // not really the right mode, but this will disable any silly stencil features - R_Shadow_RenderMode_VisibleLighting(true, true); - - // vertex coordinates for a quad that covers the screen exactly - vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0; - vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0; - vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0; - vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0; + R_Shadow_RenderMode_End(); // set up ortho view for rendering this pass - R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, 0, 0, 1, 1, -10, 100, NULL); - R_SetViewport(&viewport); - GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height); - GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); - GL_ScissorTest(true); - R_Mesh_Matrix(&identitymatrix); - R_Mesh_ResetTextureState(); - R_Mesh_VertexPointer(vertex3f, 0, 0); + //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height); + //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); + //GL_ScissorTest(true); + //R_Mesh_Matrix(&identitymatrix); + //R_Mesh_ResetTextureState(); + R_ResetViewRendering2D(); + R_Mesh_VertexPointer(r_screenvertex3f, 0, 0); R_Mesh_ColorPointer(NULL, 0, 0); + R_SetupGenericShader(false); // set up a 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); - GL_PolygonOffset(0, 0);CHECKGLERROR + //GL_DepthRange(0, 1); + //GL_DepthTest(false); + //GL_DepthMask(false); + //GL_PolygonOffset(0, 0);CHECKGLERROR GL_Color(0, 0, 0, r_shadows_darken.value); - GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); - qglDepthFunc(GL_ALWAYS);CHECKGLERROR + //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); + //qglDepthFunc(GL_ALWAYS);CHECKGLERROR qglEnable(GL_STENCIL_TEST);CHECKGLERROR qglStencilMask(~0);CHECKGLERROR qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR // apply the blend to the shadowed areas - R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); // restore the viewport R_SetViewport(&r_refdef.view.viewport); // restore other state to normal - R_Shadow_RenderMode_End(); + //R_Shadow_RenderMode_End(); } void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery) { float zdist; vec3_t centerorigin; + float vertex3f[12]; // if it's too close, skip it - if (VectorLength(rtlight->color) < (1.0f / 256.0f)) + if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f)) return; zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward)); if (zdist < 32) @@ -4011,23 +4652,30 @@ void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery) { rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++]; rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++]; + // we count potential samples in the middle of the screen, we count actual samples at the light location, this allows counting potential samples of off-screen lights VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin); CHECKGLERROR - // NOTE: we can't disable depth testing using R_DrawSprite's depthdisable argument, which calls GL_DepthTest, as that's broken in the ATI drivers + // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels); qglDepthFunc(GL_ALWAYS); - R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, false, false, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1); + R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale); + R_Mesh_VertexPointer(vertex3f, 0, 0); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); qglEndQueryARB(GL_SAMPLES_PASSED_ARB); qglDepthFunc(GL_LEQUAL); qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels); - R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, false, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1); + R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale); + R_Mesh_VertexPointer(vertex3f, 0, 0); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); qglEndQueryARB(GL_SAMPLES_PASSED_ARB); CHECKGLERROR } rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1); } +static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1}; + void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale) { vec3_t color; @@ -4048,12 +4696,25 @@ void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale) else { // FIXME: these traces should scan all render entities instead of cl.world - if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1) + if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1) return; } - VectorScale(rtlight->color, cscale, color); + VectorScale(rtlight->currentcolor, cscale, color); if (VectorLength(color) > (1.0f / 256.0f)) - R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, color[0], color[1], color[2], 1); + { + float vertex3f[12]; + qboolean negated = (color[0] + color[1] + color[2] < 0) && gl_support_ext_blend_subtract; + if(negated) + { + VectorNegate(color, color); + qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT); + } + R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale); + RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, RENDER_NODEPTHTEST, 0, color[0], color[1], color[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false); + R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false); + if(negated) + qglBlendEquationEXT(GL_FUNC_ADD_EXT); + } } void R_DrawCoronas(void) @@ -4091,6 +4752,16 @@ void R_DrawCoronas(void) qglGenQueriesARB(r_maxqueries - i, r_queries + i); CHECKGLERROR } + RSurf_ActiveWorldEntity(); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_CullFace(GL_NONE); + GL_DepthMask(false); + GL_DepthRange(0, 1); + GL_PolygonOffset(0, 0); + GL_DepthTest(true); + R_Mesh_ColorPointer(NULL, 0, 0); + R_Mesh_ResetTextureState(); + R_SetupGenericShader(false); } for (lightindex = 0;lightindex < range;lightindex++) { @@ -4305,9 +4976,14 @@ void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, ve light->angles[0] = angles[0] - 360 * floor(angles[0] / 360); light->angles[1] = angles[1] - 360 * floor(angles[1] / 360); light->angles[2] = angles[2] - 360 * floor(angles[2] / 360); + /* light->color[0] = max(color[0], 0); light->color[1] = max(color[1], 0); light->color[2] = max(color[2], 0); + */ + light->color[0] = color[0]; + light->color[1] = color[1]; + light->color[2] = color[2]; light->radius = max(radius, 0); light->style = style; light->shadow = shadowenable; @@ -4359,7 +5035,10 @@ void R_Shadow_SelectLight(dlight_t *light) void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) { // this is never batched (there can be only one) - R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprcursor->tex, r_editlights_sprcursor->tex, false, false, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE, 1, 1, 1, 1); + float vertex3f[12]; + R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE); + RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false); + R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false); } void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) @@ -4367,12 +5046,16 @@ void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, co float intensity; float s; vec3_t spritecolor; - cachepic_t *pic; + skinframe_t *skinframe; + float vertex3f[12]; // this is never batched (due to the ent parameter changing every time) // so numsurfaces == 1 and surfacelist[0] == lightnumber const dlight_t *light = (dlight_t *)ent; s = EDLIGHTSPRSIZE; + + R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s); + intensity = 0.5f; VectorScale(light->color, intensity, spritecolor); if (VectorLength(spritecolor) < 0.1732f) @@ -4382,18 +5065,24 @@ void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, co // draw light sprite if (light->cubemapname[0] && !light->shadow) - pic = r_editlights_sprcubemapnoshadowlight; + skinframe = r_editlights_sprcubemapnoshadowlight; else if (light->cubemapname[0]) - pic = r_editlights_sprcubemaplight; + skinframe = r_editlights_sprcubemaplight; else if (!light->shadow) - pic = r_editlights_sprnoshadowlight; + skinframe = r_editlights_sprnoshadowlight; else - pic = r_editlights_sprlight; - R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, pic->tex, pic->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, spritecolor[0], spritecolor[1], spritecolor[2], 1); + skinframe = r_editlights_sprlight; + + RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, spritecolor[0], spritecolor[1], spritecolor[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false); + R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false); + // draw selection sprite if light is selected if (light->selected) - R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprselection->tex, r_editlights_sprselection->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, 1, 1, 1, 1); - // VorteX todo: add normalmode/realtime mode light overlay sprites? + { + RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false); + R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false); + // VorteX todo: add normalmode/realtime mode light overlay sprites? + } } void R_Shadow_DrawLightSprites(void) @@ -4429,7 +5118,7 @@ void R_Shadow_SelectLightInView(void) if (rating >= 0.95) { rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp))); - if (bestrating < rating && CL_Move(light->origin, vec3_origin, vec3_origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f) + if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f) { bestrating = rating; best = light; @@ -4875,7 +5564,7 @@ void R_Shadow_SetCursorLocationForView(void) vec3_t dest, endpos; trace_t trace; VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest); - trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false); + trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false); if (trace.fraction < 1) { dist = trace.fraction * r_editlights_cursordistance.value; @@ -5549,7 +6238,7 @@ void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffu light = r_refdef.scene.lights[i]; Matrix4x4_Transform(&light->matrix_worldtolight, p, v); f = 1 - VectorLength2(v); - if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1) + if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1) VectorMA(ambientcolor, f, light->currentcolor, ambientcolor); } }