+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, bias;
+ r_viewport_t viewport;
+ 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 == 1)
+ {
+ // 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_shadowmapprecision, 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
+ qglDrawBuffer(GL_NONE);CHECKGLERROR
+ qglReadBuffer(GL_NONE);CHECKGLERROR
+ status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+ {
+ 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
+ }
+ R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
+ 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_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
+ r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
+ r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
+ }
+ else if (r_shadow_shadowmode == 2)
+ {
+ // 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_shadowmapprecision, 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)
+ {
+ 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
+ }
+ R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
+ r_shadow_shadowmap_texturescale[0] = 1.0f;
+ r_shadow_shadowmap_texturescale[1] = 1.0f;
+ r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
+ r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
+ r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
+ }
+ else if (r_shadow_shadowmode == 3)
+ {
+ // 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_shadowmapprecision, r_shadow_shadowmapsampler);
+ 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])
+ {
+ // 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)
+ {
+ 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
+ }
+ 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]);
+ r_shadow_shadowmap_parameters[0] = 1.0f;
+ r_shadow_shadowmap_parameters[1] = 1.0f;
+ r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
+ }
+ CHECKGLERROR
+ R_SetViewport(&viewport);
+ GL_PolygonOffset(0, 0);
+ if(r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 2)
+ {
+ static qboolean cullfront[6] = { false, true, false, true, true, false };
+ if(cullfront[side]) r_refdef.view.cullface_back = r_refdef.view.cullface_front;
+ }
+ GL_CullFace(r_refdef.view.cullface_back);
+ GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
+ GL_DepthMask(true);
+ GL_DepthTest(true);
+ qglClearDepth(1);CHECKGLERROR
+ CHECKGLERROR
+ if (clear)
+ qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ CHECKGLERROR
+}
+
+void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)