+ r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
+ if (r_shadow_rendermode == mode)
+ return;
+ CHECKGLERROR
+ R_Shadow_RenderMode_Reset();
+ GL_ColorMask(0, 0, 0, 0);
+ GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
+ R_SetupDepthOrShadowShader();
+ qglDepthFunc(GL_LESS);CHECKGLERROR
+ qglEnable(GL_STENCIL_TEST);CHECKGLERROR
+ r_shadow_rendermode = mode;
+ switch(mode)
+ {
+ default:
+ break;
+ case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
+ GL_CullFace(GL_NONE);
+ qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
+ qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
+ break;
+ case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
+ GL_CullFace(GL_NONE);
+ qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
+ qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
+ break;
+ case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
+ GL_CullFace(GL_NONE);
+ qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
+ qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
+ qglStencilMask(~0);CHECKGLERROR
+ qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
+ qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
+ qglStencilMask(~0);CHECKGLERROR
+ qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
+ break;
+ case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
+ GL_CullFace(GL_NONE);
+ qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
+ qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
+ qglStencilMask(~0);CHECKGLERROR
+ qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
+ qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
+ qglStencilMask(~0);CHECKGLERROR
+ qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
+ break;
+ }
+}
+
+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 status;
+ int maxsize;
+ float nearclip, farclip, bias;
+ r_viewport_t viewport;
+ GLuint fbo = 0;
+ CHECKGLERROR
+ maxsize = r_shadow_shadowmapmaxsize;
+ nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
+ farclip = 1.0f;
+ 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_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
+ R_Shadow_MakeVSDCT();
+ if (!r_shadow_shadowmap2dtexture)
+ {
+#if 1
+ 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
+ // 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 && r_shadow_shadowmapping.integer)
+ {
+ Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
+ Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
+ }
+#endif
+ }
+ 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_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_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
+ R_Shadow_MakeVSDCT();
+ if (!r_shadow_shadowmaprectangletexture)
+ {
+#if 1
+ 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
+ // 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 && r_shadow_shadowmapping.integer)
+ {
+ Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
+ Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
+ }
+#endif
+ }
+ 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_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, 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
+ qglDrawBuffer(GL_NONE);CHECKGLERROR
+ qglReadBuffer(GL_NONE);CHECKGLERROR
+ status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
+ 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);
+ }
+ #endif
+ }
+ 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
+ }