2022-05-05 05:58:47 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#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
|
2023-06-28 12:45:41 +00:00
|
|
|
expand_pvs (set_t *pvs, mod_brush_t *brush)
|
2022-05-05 05:58:47 +00:00
|
|
|
{
|
2023-06-28 12:45:41 +00:00
|
|
|
set_t base_pvs = SET_STATIC_INIT (brush->visleafs, alloca);
|
2022-05-05 05:58:47 +00:00
|
|
|
set_assign (&base_pvs, pvs);
|
2023-06-28 12:45:41 +00:00
|
|
|
for (unsigned i = 0; i < brush->visleafs; i++) {
|
2022-05-05 05:58:47 +00:00
|
|
|
if (set_is_member (&base_pvs, i)) {
|
2023-06-28 12:45:41 +00:00
|
|
|
Mod_LeafPVS_mix (brush->leafs + i + 1, brush, 0, pvs);
|
2022-05-05 05:58:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-05-05 11:36:25 +00:00
|
|
|
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
|
2023-06-28 12:45:41 +00:00
|
|
|
mleaf_t *leaf = Mod_PointInLeaf (light->position, &model->brush);
|
2022-05-05 11:36:25 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-05-05 05:58:47 +00:00
|
|
|
void
|
|
|
|
Light_EnableSun (lightingdata_t *ldata)
|
|
|
|
{
|
|
|
|
scene_t *scene = ldata->scene;
|
2023-06-28 12:45:41 +00:00
|
|
|
auto brush = &scene->worldmodel->brush;
|
2022-05-05 05:58:47 +00:00
|
|
|
|
|
|
|
if (!ldata->sun_pvs) {
|
2023-06-28 12:45:41 +00:00
|
|
|
ldata->sun_pvs = set_new_size (brush->visleafs);
|
2022-05-05 05:58:47 +00:00
|
|
|
}
|
2023-06-28 12:45:41 +00:00
|
|
|
set_expand (ldata->sun_pvs, brush->visleafs);
|
2022-05-05 05:58:47 +00:00
|
|
|
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
|
2023-06-28 12:45:41 +00:00
|
|
|
for (unsigned l = 1; l < brush->modleafs; l++) {
|
|
|
|
if (brush->leaf_flags[l] & SURF_DRAWSKY) {
|
2022-05-05 05:58:47 +00:00
|
|
|
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
|
2023-06-28 12:45:41 +00:00
|
|
|
expand_pvs (ldata->sun_pvs, brush);
|
2022-05-05 05:58:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Light_FindVisibleLights (lightingdata_t *ldata)
|
|
|
|
{
|
|
|
|
scene_t *scene = ldata->scene;
|
|
|
|
mleaf_t *leaf = scene->viewleaf;
|
2023-06-28 12:45:41 +00:00
|
|
|
auto brush = &scene->worldmodel->brush;
|
2022-05-05 05:58:47 +00:00
|
|
|
|
|
|
|
if (!leaf) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!ldata->pvs) {
|
2023-06-28 12:45:41 +00:00
|
|
|
ldata->pvs = set_new_size (brush->visleafs);
|
2022-05-05 05:58:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (leaf != ldata->leaf) {
|
|
|
|
//double start = Sys_DoubleTime ();
|
|
|
|
int flags = 0;
|
|
|
|
|
2023-06-28 12:45:41 +00:00
|
|
|
if (leaf == brush->leafs) {
|
2022-05-05 05:58:47 +00:00
|
|
|
set_everything (ldata->pvs);
|
2022-05-10 01:57:48 +00:00
|
|
|
flags = SURF_DRAWSKY;
|
2022-05-05 05:58:47 +00:00
|
|
|
} else {
|
2023-06-28 12:45:41 +00:00
|
|
|
Mod_LeafPVS_set (leaf, brush, 0, ldata->pvs);
|
2022-05-10 01:57:48 +00:00
|
|
|
if (set_is_intersecting (ldata->pvs, ldata->sun_pvs)) {
|
|
|
|
flags |= SURF_DRAWSKY;
|
2022-05-05 05:58:47 +00:00
|
|
|
}
|
2023-06-28 12:45:41 +00:00
|
|
|
expand_pvs (ldata->pvs, brush);
|
2022-05-05 05:58:47 +00:00
|
|
|
}
|
|
|
|
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];
|
2022-05-05 10:53:20 +00:00
|
|
|
if ((l == -2) || (l == -1 && (flags & SURF_DRAWSKY))
|
2022-05-05 05:58:47 +00:00
|
|
|
|| set_is_member (ldata->pvs, l)) {
|
|
|
|
ldata->lightvis.a[i] = 1;
|
|
|
|
visible++;
|
|
|
|
}
|
|
|
|
}
|
2022-05-10 01:57:48 +00:00
|
|
|
Sys_MaskPrintf (SYS_lighting,
|
|
|
|
"find_visible_lights: %d / %zd visible\n", visible,
|
|
|
|
ldata->lightvis.size);
|
2022-05-05 05:58:47 +00:00
|
|
|
}
|
|
|
|
}
|