]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
reverse engineered md3 format and wrote struct declarations (this is *NOT* based...
[xonotic/darkplaces.git] / r_shadow.c
index 449e2a47373b7ac26623f2696cf4ec227025a155..582e7e4108d75aa958da78d913116c9a3b872a6b 100644 (file)
@@ -23,7 +23,6 @@ int maxtrianglefacinglight;
 qbyte *trianglefacinglight;
 
 rtexturepool_t *r_shadow_texturepool;
-rtexture_t *r_shadow_normalsattenuationtexture;
 rtexture_t *r_shadow_normalscubetexture;
 rtexture_t *r_shadow_attenuation2dtexture;
 rtexture_t *r_shadow_blankbumptexture;
@@ -33,7 +32,6 @@ rtexture_t *r_shadow_blankwhitetexture;
 cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "2"};
 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
 cvar_t r_shadow_realtime = {0, "r_shadow_realtime", "0"};
-cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "0"};
 cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
@@ -54,7 +52,6 @@ void r_shadow_start(void)
        shadowelements = NULL;
        maxtrianglefacinglight = 0;
        trianglefacinglight = NULL;
-       r_shadow_normalsattenuationtexture = NULL;
        r_shadow_normalscubetexture = NULL;
        r_shadow_attenuation2dtexture = NULL;
        r_shadow_blankbumptexture = NULL;
@@ -69,7 +66,6 @@ void r_shadow_shutdown(void)
 {
        R_Shadow_ClearWorldLights();
        r_shadow_reloadlights = true;
-       r_shadow_normalsattenuationtexture = NULL;
        r_shadow_normalscubetexture = NULL;
        r_shadow_attenuation2dtexture = NULL;
        r_shadow_blankbumptexture = NULL;
@@ -94,7 +90,6 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
        Cvar_RegisterVariable(&r_shadow_lightintensityscale);
        Cvar_RegisterVariable(&r_shadow_realtime);
-       Cvar_RegisterVariable(&r_shadow_texture3d);
        Cvar_RegisterVariable(&r_shadow_gloss);
        Cvar_RegisterVariable(&r_shadow_debuglight);
        Cvar_RegisterVariable(&r_shadow_scissor);
@@ -353,42 +348,6 @@ void R_Shadow_RenderShadowMeshVolume(shadowmesh_t *firstmesh)
 }
 
 float r_shadow_atten1;
-#define ATTEN3DSIZE 64
-static void R_Shadow_Make3DTextures(void)
-{
-       int x, y, z;
-       float v[3], intensity, ilen, bordercolor[4];
-       qbyte *data;
-       data = Mem_Alloc(tempmempool, ATTEN3DSIZE * ATTEN3DSIZE * ATTEN3DSIZE * 4);
-       for (z = 0;z < ATTEN3DSIZE;z++)
-       {
-               for (y = 0;y < ATTEN3DSIZE;y++)
-               {
-                       for (x = 0;x < ATTEN3DSIZE;x++)
-                       {
-                               v[0] = (x + 0.5f) * (2.0f / (float) ATTEN3DSIZE) - 1.0f;
-                               v[1] = (y + 0.5f) * (2.0f / (float) ATTEN3DSIZE) - 1.0f;
-                               v[2] = (z + 0.5f) * (2.0f / (float) ATTEN3DSIZE) - 1.0f;
-                               intensity = 1.0f - sqrt(DotProduct(v, v));
-                               if (intensity > 0)
-                                       intensity *= intensity;
-                               ilen = 127.0f * bound(0, intensity * r_shadow_atten1, 1) / sqrt(DotProduct(v, v));
-                               data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = 128.0f + ilen * v[0];
-                               data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = 128.0f + ilen * v[1];
-                               data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = 128.0f + ilen * v[2];
-                               data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = 255;
-                       }
-               }
-       }
-       r_shadow_normalsattenuationtexture = R_LoadTexture3D(r_shadow_texturepool, "normalsattenuation", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
-       Mem_Free(data);
-       bordercolor[0] = 0.5f;
-       bordercolor[1] = 0.5f;
-       bordercolor[2] = 0.5f;
-       bordercolor[3] = 1.0f;
-       qglTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, bordercolor);
-}
-
 static void R_Shadow_MakeTextures(void)
 {
        int x, y, d, side;
@@ -403,9 +362,9 @@ static void R_Shadow_MakeTextures(void)
        data[2] = 255;
        data[3] = 255;
        r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
-       data[0] = 255;
-       data[1] = 255;
-       data[2] = 255;
+       data[0] = 64;
+       data[1] = 64;
+       data[2] = 64;
        data[3] = 255;
        r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
        data[0] = 255;
@@ -483,26 +442,19 @@ static void R_Shadow_MakeTextures(void)
        }
        r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", 128, 128, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_MIPMAP, NULL);
        Mem_Free(data);
-       if (r_shadow_texture3d.integer)
-               R_Shadow_Make3DTextures();
 }
 
 void R_Shadow_Stage_Begin(void)
 {
        rmeshstate_t m;
 
-       if (r_shadow_texture3d.integer && !gl_texture3d)
-       {
-               Con_Printf("3D texture support not detected, falling back on slower 2D + 1D + normalization lighting\n");
-               Cvar_SetValueQuick(&r_shadow_texture3d, 0);
-       }
        //cl.worldmodel->numlights = min(cl.worldmodel->numlights, 1);
        if (!r_shadow_attenuation2dtexture
-        || (r_shadow_texture3d.integer && !r_shadow_normalsattenuationtexture)
         || r_shadow_lightattenuationscale.value != r_shadow_atten1)
                R_Shadow_MakeTextures();
        if (r_shadow_reloadlights && cl.worldmodel)
        {
+               R_Shadow_ClearWorldLights();
                r_shadow_reloadlights = false;
                R_Shadow_LoadWorldLights();
                if (r_shadow_worldlightchain == NULL)
@@ -832,70 +784,7 @@ void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *element
        // mult is how many times the final pass of the lighting will be
        // performed to get more brightness than otherwise possible
        // limit mult to 64 for sanity sake
-       if (r_shadow_texture3d.integer)
-       {
-               if (r_textureunits.integer >= 4 && !lightcubemap)
-               {
-                       // 4 texture 3D combine path, one pass, no light cubemap support
-                       m.tex[0] = R_GetTexture(bumptexture);
-                       m.tex3d[1] = R_GetTexture(r_shadow_normalsattenuationtexture);
-                       m.tex[2] = R_GetTexture(basetexture);
-                       m.tex[3] = R_GetTexture(r_shadow_blankwhitetexture);
-                       m.texcombinergb[0] = GL_REPLACE;
-                       m.texcombinergb[1] = GL_DOT3_RGB_ARB;
-                       m.texcombinergb[2] = GL_MODULATE;
-                       m.texcombinergb[3] = GL_MODULATE;
-                       R_Mesh_TextureState(&m);
-                       memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
-                       memcpy(varray_texcoord[2], texcoords, numverts * sizeof(float[4]));
-                       R_Shadow_GenTexCoords_Diffuse_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
-                       qglActiveTexture(GL_TEXTURE3_ARB);
-                       qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
-                       colorscale = r_colorscale * r_shadow_lightintensityscale.value;
-                       for (mult = 1, scale = ixtable[mult];mult < 64 && (lightcolor[0] * scale * colorscale > 1 || lightcolor[1] * scale * colorscale > 1 || lightcolor[2] * scale * colorscale > 1);mult++, scale = ixtable[mult]);
-                       colorscale *= scale;
-                       GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
-                       for (renders = 0;renders < mult;renders++)
-                               R_Mesh_Draw(numverts, numtriangles, elements);
-                       qglActiveTexture(GL_TEXTURE3_ARB);
-                       qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
-               }
-               else
-               {
-                       // 2 texture no3D combine path, two pass
-                       m.tex[0] = R_GetTexture(bumptexture);
-                       m.tex3d[1] = R_GetTexture(r_shadow_normalsattenuationtexture);
-                       m.texcombinergb[0] = GL_REPLACE;
-                       m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
-                       R_Mesh_TextureState(&m);
-                       qglColorMask(0,0,0,1);
-                       qglDisable(GL_BLEND);
-                       GL_Color(1,1,1,1);
-                       memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
-                       R_Shadow_GenTexCoords_Diffuse_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
-                       R_Mesh_Draw(numverts, numtriangles, elements);
-
-                       m.tex[0] = R_GetTexture(basetexture);
-                       m.tex3d[1] = 0;
-                       m.texcubemap[1] = R_GetTexture(lightcubemap);
-                       m.texcombinergb[0] = GL_MODULATE;
-                       m.texcombinergb[1] = GL_MODULATE;
-                       R_Mesh_TextureState(&m);
-                       qglColorMask(1,1,1,1);
-                       qglBlendFunc(GL_DST_ALPHA, GL_ONE);
-                       qglEnable(GL_BLEND);
-                       if (lightcubemap)
-                               R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
-
-                       colorscale = r_colorscale * r_shadow_lightintensityscale.value;
-                       for (mult = 1, scale = ixtable[mult];mult < 64 && (lightcolor[0] * scale * colorscale > 1 || lightcolor[1] * scale * colorscale > 1 || lightcolor[2] * scale * colorscale > 1);mult++, scale = ixtable[mult]);
-                       colorscale *= scale;
-                       GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
-                       for (renders = 0;renders < mult;renders++)
-                               R_Mesh_Draw(numverts, numtriangles, elements);
-               }
-       }
-       else if (r_textureunits.integer >= 4)
+       if (r_textureunits.integer >= 4)
        {
                // 4 texture no3D combine path, two pass
                m.tex[0] = R_GetTexture(bumptexture);
@@ -1033,8 +922,7 @@ void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elemen
                if (lightcubemap)
                        R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
 
-               // the 0.25f makes specular lighting much dimmer than diffuse (intentionally)
-               colorscale = r_colorscale * 0.25f * r_shadow_lightintensityscale.value;
+               colorscale = r_colorscale * r_shadow_lightintensityscale.value;
                for (mult = 1, scale = ixtable[mult];mult < 64 && (lightcolor[0] * scale * colorscale > 1 || lightcolor[1] * scale * colorscale > 1 || lightcolor[2] * scale * colorscale > 1);mult++, scale = ixtable[mult]);
                colorscale *= scale;
                GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
@@ -1054,6 +942,7 @@ cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
 cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
 cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
+cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
 worldlight_t *r_shadow_worldlightchain;
 worldlight_t *r_shadow_selectedlight;
 vec3_t r_editlights_cursorlocation;
@@ -1071,6 +960,12 @@ void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style
        qbyte *pvs;
        surfmesh_t *surfmesh;
 
+       if (radius < 15 || DotProduct(color, color) < 0.03)
+       {
+               Con_Printf("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
+               return;
+       }
+
        e = Mem_Alloc(r_shadow_mempool, sizeof(worldlight_t));
        VectorCopy(origin, e->origin);
        VectorCopy(color, e->light);
@@ -1279,20 +1174,104 @@ void R_Shadow_FreeSelectedWorldLight(void)
        }
 }
 
+void R_DrawLightSprite(int texnum, const vec3_t origin, vec_t scale, float cr, float cg, float cb, float ca)
+{
+       rmeshstate_t m;
+       float diff[3];
+
+       if (fogenabled)
+       {
+               VectorSubtract(origin, r_origin, diff);
+               ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
+       }
+
+       memset(&m, 0, sizeof(m));
+       m.blendfunc1 = GL_SRC_ALPHA;
+       m.blendfunc2 = GL_ONE;
+       m.tex[0] = texnum;
+       R_Mesh_Matrix(&r_identitymatrix);
+       R_Mesh_State(&m);
+
+       GL_Color(cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
+       varray_texcoord[0][ 0] = 0;varray_texcoord[0][ 1] = 0;
+       varray_texcoord[0][ 4] = 0;varray_texcoord[0][ 5] = 1;
+       varray_texcoord[0][ 8] = 1;varray_texcoord[0][ 9] = 1;
+       varray_texcoord[0][12] = 1;varray_texcoord[0][13] = 0;
+       varray_vertex[0] = origin[0] - vright[0] * scale - vup[0] * scale;
+       varray_vertex[1] = origin[1] - vright[1] * scale - vup[1] * scale;
+       varray_vertex[2] = origin[2] - vright[2] * scale - vup[2] * scale;
+       varray_vertex[4] = origin[0] - vright[0] * scale + vup[0] * scale;
+       varray_vertex[5] = origin[1] - vright[1] * scale + vup[1] * scale;
+       varray_vertex[6] = origin[2] - vright[2] * scale + vup[2] * scale;
+       varray_vertex[8] = origin[0] + vright[0] * scale + vup[0] * scale;
+       varray_vertex[9] = origin[1] + vright[1] * scale + vup[1] * scale;
+       varray_vertex[10] = origin[2] + vright[2] * scale + vup[2] * scale;
+       varray_vertex[12] = origin[0] + vright[0] * scale - vup[0] * scale;
+       varray_vertex[13] = origin[1] + vright[1] * scale - vup[1] * scale;
+       varray_vertex[14] = origin[2] + vright[2] * scale - vup[2] * scale;
+       R_Mesh_Draw(4, 2, polygonelements);
+}
+
+void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
+{
+       cachepic_t *pic;
+       pic = Draw_CachePic("gfx/crosshair1.tga");
+       if (pic)
+               R_DrawLightSprite(R_GetTexture(pic->tex), r_editlights_cursorlocation, r_editlights_cursorgrid.value * 0.5f, 1, 1, 1, 0.5);
+}
+
+void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
+{
+       float intensity;
+       const worldlight_t *light;
+       light = calldata1;
+       intensity = 0.5;
+       if (light->selected)
+               intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
+       if (light->shadowvolume)
+               R_DrawLightSprite(calldata2, light->origin, 8, intensity, intensity, intensity, 0.5);
+       else
+               R_DrawLightSprite(calldata2, light->origin, 8, intensity * 0.5, intensity * 0.5, intensity * 0.5, 0.5);
+}
+
+void R_Shadow_DrawLightSprites(void)
+{
+       int i, texnums[5];
+       cachepic_t *pic;
+       worldlight_t *light;
+
+       for (i = 0;i < 5;i++)
+       {
+               pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1));
+               if (pic)
+                       texnums[i] = R_GetTexture(pic->tex);
+               else
+                       texnums[i] = 0;
+       }
+
+       for (light = r_shadow_worldlightchain;light;light = light->next)
+               R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, texnums[((int) light) % 5]);
+       R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
+}
+
 void R_Shadow_SelectLightInView(void)
 {
-       float bestrating, temp[3], dist;
+       float bestrating, rating, temp[3];
        worldlight_t *best, *light;
        best = NULL;
-       bestrating = 1e30;
+       bestrating = 0;
        for (light = r_shadow_worldlightchain;light;light = light->next)
        {
                VectorSubtract(light->origin, r_refdef.vieworg, temp);
-               dist = sqrt(DotProduct(temp, temp));
-               if (DotProduct(temp, vpn) >= 0.97 * dist && bestrating > dist && CL_TraceLine(light->origin, r_refdef.vieworg, NULL, NULL, 0, true, NULL) == 1.0f)
+               rating = (DotProduct(temp, vpn) / sqrt(DotProduct(temp, temp)));
+               if (rating >= 0.95)
                {
-                       bestrating = dist;
-                       best = light;
+                       rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
+                       if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.vieworg, NULL, NULL, 0, true, NULL) == 1.0f)
+                       {
+                               bestrating = rating;
+                               best = light;
+                       }
                }
        }
        R_Shadow_SelectLight(best);
@@ -1537,8 +1516,8 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                }
                if (light <= 0 && islight)
                        light = 300;
-               radius = bound(0, light / scale, 1048576) + 15.0f;
-               light = bound(0, light, 1048576) * (1.0f / 256.0f);
+               radius = bound(15, light * r_editlights_quakelightsizescale.value / scale, 1048576);
+               light = sqrt(bound(0, light, 1048576)) * (1.0f / 16.0f);
                if (color[0] == 1 && color[1] == 1 && color[2] == 1)
                        VectorCopy(overridecolor, color);
                VectorScale(color, light, color);
@@ -1570,20 +1549,6 @@ void R_Shadow_SetCursorLocationForView(void)
        r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
 }
 
-extern void R_DrawCrosshairSprite(rtexture_t *texture, vec3_t origin, vec_t scale, float cr, float cg, float cb, float ca);
-void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
-{
-       cachepic_t *pic;
-       pic = Draw_CachePic("gfx/crosshair1.tga");
-       if (pic)
-               R_DrawCrosshairSprite(pic->tex, r_editlights_cursorlocation, r_editlights_cursorgrid.value * 0.5f, 1, 1, 1, 1);
-}
-
-void R_Shadow_DrawCursor(void)
-{
-       R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
-}
-
 void R_Shadow_UpdateLightingMode(void)
 {
        r_shadow_lightingmode = 0;
@@ -1600,9 +1565,9 @@ void R_Shadow_UpdateWorldLightSelection(void)
 {
        if (r_editlights.integer)
        {
-               R_Shadow_SelectLightInView();
                R_Shadow_SetCursorLocationForView();
-               R_Shadow_DrawCursor();
+               R_Shadow_SelectLightInView();
+               R_Shadow_DrawLightSprites();
        }
        else
                R_Shadow_SelectLight(NULL);
@@ -1615,11 +1580,7 @@ void R_Shadow_EditLights_Clear_f(void)
 
 void R_Shadow_EditLights_Reload_f(void)
 {
-       if (cl.worldmodel)
-       {
-               R_Shadow_ClearWorldLights();
-               R_Shadow_LoadWorldLights();
-       }
+       r_shadow_reloadlights = true;
 }
 
 void R_Shadow_EditLights_Save_f(void)
@@ -1769,6 +1730,7 @@ void R_Shadow_EditLights_Init(void)
        Cvar_RegisterVariable(&r_editlights_cursorpushback);
        Cvar_RegisterVariable(&r_editlights_cursorpushoff);
        Cvar_RegisterVariable(&r_editlights_cursorgrid);
+       Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
        Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
        Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
        Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);