#ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include "QF/model.h" #include "QF/set.h" #include "QF/scene/light.h" #include "QF/scene/scene.h" #include "QF/simd/vec4f.h" static void expand_pvs (set_t *pvs, mod_brush_t *brush) { set_t base_pvs = SET_STATIC_INIT (brush->visleafs, alloca); set_assign (&base_pvs, pvs); for (unsigned i = 0; i < brush->visleafs; i++) { if (set_is_member (&base_pvs, i)) { Mod_LeafPVS_mix (brush->leafs + i + 1, brush, 0, pvs); } } } lightingdata_t * Light_CreateLightingData (scene_t *scene) { lightingdata_t *ldata = calloc (1, sizeof (lightingdata_t)); DARRAY_INIT (&ldata->lights, 16); DARRAY_INIT (&ldata->lightstyles, 16); DARRAY_INIT (&ldata->lightleafs, 16); DARRAY_INIT (&ldata->lightvis, 16); ldata->scene = scene; return ldata; } void Light_DestroyLightingData (lightingdata_t *ldata) { DARRAY_CLEAR (&ldata->lights); DARRAY_CLEAR (&ldata->lightstyles); DARRAY_CLEAR (&ldata->lightleafs); DARRAY_CLEAR (&ldata->lightvis); free (ldata); } void Light_ClearLights (lightingdata_t *ldata) { ldata->lights.size = 0; ldata->lightstyles.size = 0; ldata->lightleafs.size = 0; ldata->lightvis.size = 0; if (ldata->sun_pvs) { set_delete (ldata->sun_pvs); } ldata->sun_pvs = 0; if (ldata->pvs) { set_delete (ldata->pvs); } ldata->pvs = 0; ldata->leaf = 0; } void Light_AddLight (lightingdata_t *ldata, const light_t *light, int style) { scene_t *scene = ldata->scene; model_t *model = scene->worldmodel; DARRAY_APPEND (&ldata->lights, *light); DARRAY_APPEND (&ldata->lightstyles, style); int visleaf = -1; // directional light if (light->position[3]) { // positional light mleaf_t *leaf = Mod_PointInLeaf (light->position, &model->brush); visleaf = leaf - model->brush.leafs - 1; } else if (!DotProduct (light->direction, light->direction)) { // ambient light visleaf = -2; } DARRAY_APPEND (&ldata->lightleafs, visleaf); DARRAY_APPEND (&ldata->lightvis, 0); } void Light_EnableSun (lightingdata_t *ldata) { scene_t *scene = ldata->scene; auto brush = &scene->worldmodel->brush; if (!ldata->sun_pvs) { ldata->sun_pvs = set_new_size (brush->visleafs); } set_expand (ldata->sun_pvs, brush->visleafs); set_empty (ldata->sun_pvs); // Any leaf with sky surfaces can potentially see the sun, thus put // the sun "in" every leaf with a sky surface // however, skip leaf 0 as it is the exterior solid leaf for (unsigned l = 1; l < brush->modleafs; l++) { if (brush->leaf_flags[l] & SURF_DRAWSKY) { set_add (ldata->sun_pvs, l - 1); //pvs is 1-based } } // any leaf visible from a leaf with a sky surface (and thus the sun) // can receive shadows from the sun expand_pvs (ldata->sun_pvs, brush); } void Light_FindVisibleLights (lightingdata_t *ldata) { scene_t *scene = ldata->scene; mleaf_t *leaf = scene->viewleaf; auto brush = &scene->worldmodel->brush; if (!leaf) { return; } if (!ldata->pvs) { ldata->pvs = set_new_size (brush->visleafs); } if (leaf != ldata->leaf) { //double start = Sys_DoubleTime (); int flags = 0; if (leaf == brush->leafs) { set_everything (ldata->pvs); flags = SURF_DRAWSKY; } else { Mod_LeafPVS_set (leaf, brush, 0, ldata->pvs); if (set_is_intersecting (ldata->pvs, ldata->sun_pvs)) { flags |= SURF_DRAWSKY; } expand_pvs (ldata->pvs, brush); } ldata->leaf = leaf; //double end = Sys_DoubleTime (); //Sys_Printf ("find_visible_lights: %.5gus\n", (end - start) * 1e6); int visible = 0; memset (ldata->lightvis.a, 0, ldata->lightvis.size * sizeof (byte)); for (size_t i = 0; i < ldata->lightleafs.size; i++) { int l = ldata->lightleafs.a[i]; if ((l == -2) || (l == -1 && (flags & SURF_DRAWSKY)) || set_is_member (ldata->pvs, l)) { ldata->lightvis.a[i] = 1; visible++; } } Sys_MaskPrintf (SYS_lighting, "find_visible_lights: %d / %zd visible\n", visible, ldata->lightvis.size); } }