]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - r_shadow.c
safety checked lightmap access in Mod_Q1BSP_RecursiveLightPoint as one map Sajt uses...
[xonotic/darkplaces.git] / r_shadow.c
index 060ab75280bbaa92edea79d48d06587d7d620881..8c083ece236e4fa1b9bfdd4671bd5ac62cf8f45f 100644 (file)
@@ -297,6 +297,11 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_worldshadows);
        Cvar_RegisterVariable(&r_shadow_dlightshadows);
        Cvar_RegisterVariable(&r_shadow_showtris);
+       if (gamemode == GAME_TENEBRAE)
+       {
+               Cvar_SetValue("r_shadow_gloss", 2);
+               Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
+       }
        Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f);
        R_Shadow_EditLights_Init();
        R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
@@ -863,7 +868,7 @@ void R_Shadow_Stage_Begin(void)
        R_Mesh_State_Texture(&m);
        GL_Color(0, 0, 0, 1);
        qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
-       qglDisable(GL_SCISSOR_TEST);
+       GL_Scissor(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
        r_shadowstage = SHADOWSTAGE_NONE;
 
        c_rt_lights = c_rt_clears = c_rt_scissored = 0;
@@ -978,7 +983,7 @@ void R_Shadow_Stage_End(void)
        //qglDisable(GL_POLYGON_OFFSET_FILL);
        GL_Color(1, 1, 1, 1);
        qglColorMask(1, 1, 1, 1);
-       qglDisable(GL_SCISSOR_TEST);
+       GL_Scissor(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
        qglDepthFunc(GL_LEQUAL);
        qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
        qglDisable(GL_STENCIL_TEST);
@@ -1000,7 +1005,7 @@ int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        // (?!?  seems like a driver bug) so abort if gl_stencil is false
        if (!gl_stencil || BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
        {
-               qglDisable(GL_SCISSOR_TEST);
+               GL_Scissor(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
                return false;
        }
        for (i = 0;i < 3;i++)
@@ -1153,8 +1158,9 @@ int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        if (ix2 <= ix1 || iy2 <= iy1)
                return true;
        // set up the scissor rectangle
-       qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
-       qglEnable(GL_SCISSOR_TEST);
+       GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
+       //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
+       //qglEnable(GL_SCISSOR_TEST);
        c_rt_scissored++;
        return false;
 }
@@ -1862,6 +1868,7 @@ vec3_t r_editlights_cursorlocation;
 
 static int lightpvsbytes;
 static qbyte lightpvs[(MAX_MAP_LEAFS + 7)/ 8];
+static qbyte lightfullpvs[(MAX_MAP_LEAFS + 7)/ 8];
 
 typedef struct cubemapinfo_s
 {
@@ -2036,18 +2043,34 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra
        e->meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true);
        if (cl.worldmodel)
        {
+               lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, origin, 0, lightfullpvs, sizeof(lightfullpvs));
+               memset(lightpvs, 0, lightpvsbytes);
                if (cl.worldmodel->brushq3.num_leafs)
                {
                        q3mleaf_t *leaf;
                        q3mface_t *face;
-                       lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, origin, 0, lightpvs, sizeof(lightpvs));
+
+                       // make a pvs that only includes things within the box
+                       for (i = 0, leaf = cl.worldmodel->brushq3.data_leafs;i < cl.worldmodel->brushq3.num_leafs;i++, leaf++)
+                               if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
+                                       SETPVSBIT(lightpvs, leaf->clusterindex);
+
+                       // make a cluster list for fast visibility checking during rendering
+                       for (i = 0, e->numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
+                               if (CHECKPVSBIT(lightpvs, i))
+                                       e->numclusters++;
+                       e->clusterindices = Mem_Alloc(r_shadow_mempool, e->numclusters * sizeof(int));
+                       for (i = 0, e->numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
+                               if (CHECKPVSBIT(lightpvs, i))
+                                       e->clusterindices[e->numclusters++] = i;
+
                        VectorCopy(e->origin, e->mins);
                        VectorCopy(e->origin, e->maxs);
                        for (i = 0, face = cl.worldmodel->brushq3.data_thismodel->firstface;i < cl.worldmodel->brushq3.data_thismodel->numfaces;i++, face++)
                                face->lighttemp_castshadow = false;
                        for (i = 0, leaf = cl.worldmodel->brushq3.data_leafs;i < cl.worldmodel->brushq3.num_leafs;i++, leaf++)
                        {
-                               if ((leaf->clusterindex < 0 || lightpvs[leaf->clusterindex >> 3] & (1 << (leaf->clusterindex & 7))) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
+                               if (CHECKPVSBIT(lightpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
                                {
                                        for (k = 0;k < 3;k++)
                                        {
@@ -2080,7 +2103,7 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra
                                }
                        }
                }
-               else if (cl.worldmodel->brushq1.numleafs)
+               else if (cl.worldmodel->brushq1.num_leafs)
                {
                        mleaf_t *leaf;
                        msurface_t *surf;
@@ -2096,15 +2119,17 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra
                                qbyte *byteleafpvs;
                                qbyte *bytesurfacepvs;
 
-                               byteleafpvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.numleafs);
+                               byteleafpvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.num_leafs);
                                bytesurfacepvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.numsurfaces);
 
                                Portal_Visibility(cl.worldmodel, e->origin, byteleafpvs, bytesurfacepvs, NULL, 0, true, mins, maxs, e->mins, e->maxs);
 
-                               for (i = 0, leaf = cl.worldmodel->brushq1.leafs;i < cl.worldmodel->brushq1.numleafs;i++, leaf++)
+                               // make a pvs that only includes things within the box
+                               for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++)
                                {
                                        if (byteleafpvs[i] && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
                                        {
+                                               SETPVSBIT(lightpvs, leaf->clusterindex);
                                                for (k = 0;k < 3;k++)
                                                {
                                                        if (e->mins[k] > leaf->mins[k]) e->mins[k] = leaf->mins[k];
@@ -2112,21 +2137,31 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra
                                                }
                                        }
                                }
-
+       
                                for (i = 0, surf = cl.worldmodel->brushq1.surfaces;i < cl.worldmodel->brushq1.numsurfaces;i++, surf++)
                                        if (bytesurfacepvs[i] && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs))
                                                surf->lighttemp_castshadow = true;
 
                                Mem_Free(byteleafpvs);
                                Mem_Free(bytesurfacepvs);
+       
+                               // make a cluster list for fast visibility checking during rendering
+                               for (i = 0, e->numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
+                                       if (CHECKPVSBIT(lightpvs, i))
+                                               e->numclusters++;
+                               e->clusterindices = Mem_Alloc(r_shadow_mempool, e->numclusters * sizeof(int));
+                               for (i = 0, e->numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
+                                       if (CHECKPVSBIT(lightpvs, i))
+                                               e->clusterindices[e->numclusters++] = i;
                        }
                        else
                        {
-                               lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, origin, 0, lightpvs, sizeof(lightpvs));
-                               for (i = 0, leaf = cl.worldmodel->brushq1.leafs + 1;i < cl.worldmodel->brushq1.visleafs;i++, leaf++)
+                               for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++)
                                {
-                                       if (lightpvs[i >> 3] & (1 << (i & 7)) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
+                                       if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
                                        {
+                                               // make a pvs that only includes things within the box
+                                               SETPVSBIT(lightpvs, leaf->clusterindex);
                                                for (k = 0;k < 3;k++)
                                                {
                                                        if (e->mins[k] > leaf->mins[k]) e->mins[k] = leaf->mins[k];
@@ -2140,6 +2175,20 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra
                                                }
                                        }
                                }
+
+                               // make a pvs that only includes things within the box
+                               for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++)
+                                       if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs))
+                                               SETPVSBIT(lightpvs, leaf->clusterindex);
+
+                               // make a cluster list for fast visibility checking during rendering
+                               for (i = 0, e->numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
+                                       if (CHECKPVSBIT(lightpvs, i))
+                                               e->numclusters++;
+                               e->clusterindices = Mem_Alloc(r_shadow_mempool, e->numclusters * sizeof(int));
+                               for (i = 0, e->numclusters = 0;i < cl.worldmodel->brush.num_pvsclusters;i++)
+                                       if (CHECKPVSBIT(lightpvs, i))
+                                               e->clusterindices[e->numclusters++] = i;
                        }
 
                        // add surfaces to shadow casting mesh and light mesh
@@ -2207,7 +2256,7 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra
        if (e->meshchain_light)
                for (mesh = e->meshchain_light;mesh;mesh = mesh->next)
                        l += mesh->numtriangles;
-       Con_Printf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles, %i light triangles\n", e->mins[0], e->mins[1], e->mins[2], e->maxs[0], e->maxs[1], e->maxs[2], k, l);
+       Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i shadow volume triangles, %i light triangles\n", e->mins[0], e->mins[1], e->mins[2], e->maxs[0], e->maxs[1], e->maxs[2], k, l);
 }
 
 void R_Shadow_FreeWorldLight(worldlight_t *light)
@@ -2455,9 +2504,9 @@ void R_Shadow_LoadLightsFile(void)
 
 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
 {
-       int entnum, style, islight;
+       int entnum, style, islight, skin, pflags;
        char key[256], value[1024];
-       float origin[3], radius, color[3], light, fadescale, lightscale, originhack[3], overridecolor[3];
+       float origin[3], angles[3], radius, color[3], light, fadescale, lightscale, originhack[3], overridecolor[3];
        const char *data;
 
        if (cl.worldmodel == NULL)
@@ -2473,11 +2522,14 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                light = 0;
                origin[0] = origin[1] = origin[2] = 0;
                originhack[0] = originhack[1] = originhack[2] = 0;
+               angles[0] = angles[1] = angles[2] = 0;
                color[0] = color[1] = color[2] = 1;
                overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
                fadescale = 1;
                lightscale = 1;
                style = 0;
+               skin = 0;
+               pflags = 0;
                islight = false;
                while (1)
                {
@@ -2500,6 +2552,10 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                                light = atof(value);
                        else if (!strcmp("origin", key))
                                sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
+                       else if (!strcmp("angle", key))
+                               angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
+                       else if (!strcmp("angles", key))
+                               sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
                        else if (!strcmp("color", key))
                                sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
                        else if (!strcmp("wait", key))
@@ -2583,6 +2639,10 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                                if (!strcmp("fade", key))
                                        fadescale = atof(value);
                        }
+                       else if (!strcmp("skin", key))
+                               skin = (int)atof(value);
+                       else if (!strcmp("pflags", key))
+                               pflags = (int)atof(value);
                }
                if (light <= 0 && islight)
                        light = 300;
@@ -2597,7 +2657,7 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
                VectorScale(color, light, color);
                VectorAdd(origin, originhack, origin);
                if (radius >= 15)
-                       R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
+                       R_Shadow_NewWorldLight(origin, angles, color, radius, !!(pflags & 2), style, !(pflags & 1), skin >= 16 ? va("cubemaps/%i", skin) : NULL);
        }
 }