[vulkan] Move non-specific lighting code out of Vulkan

The parsing of light data from maps is now in the client library, and
basic light management is in scene. Putting the light loading code into
the Vulkan renderer was a mistake I've wanted to correct for a while.
The client code still needs a bit of cleanup, but the basics are working
nicely.
This commit is contained in:
Bill Currie 2022-05-05 14:58:47 +09:00
parent e9ad7b748b
commit 9ee0eada1f
20 changed files with 609 additions and 480 deletions

View file

@ -149,6 +149,7 @@ include_qf_scene = \
include/QF/scene/camera.h \
include/QF/scene/entity.h \
include/QF/scene/hierarchy.h \
include/QF/scene/light.h \
include/QF/scene/transform.h \
include/QF/scene/scene.h \
include/QF/scene/types.h

View file

@ -33,41 +33,23 @@
#include "QF/darray.h"
#include "QF/model.h"
#include "QF/modelgen.h"
#include "QF/scene/light.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/command.h"
#include "QF/Vulkan/image.h"
#include "QF/simd/types.h"
typedef struct qfv_light_s {
vec4f_t color;
vec4f_t position;
vec4f_t direction;
vec4f_t attenuation;
} qfv_light_t;
typedef struct qfv_lightset_s DARRAY_TYPE (qfv_light_t) qfv_lightset_t;
typedef struct qfv_lightleafset_s DARRAY_TYPE (int) qfv_lightintset_t;
typedef struct qfv_lightvisset_s DARRAY_TYPE (byte) qfv_lightvisset_t;
typedef struct qfv_lightmatset_s DARRAY_TYPE (mat4f_t) qfv_lightmatset_t;
#define MaxLights 256
#define LM_LINEAR 0 // light - dist (or radius + dist if -ve)
#define LM_INVERSE 1 // distFactor1 * light / dist
#define LM_INVERSE2 2 // distFactor2 * light / (dist * dist)
#define LM_INFINITE 3 // light
#define LM_AMBIENT 4 // light
#define LM_INVERSE3 5 // distFactor2 * light / (dist + distFactor2)**2
#define ST_NONE 0 // no shadows
#define ST_PLANE 1 // single plane shadow map (small spotlight)
#define ST_CASCADE 2 // cascaded shadow maps
#define ST_CUBE 3 // cubemap (omni, large spotlight)
#define NumStyles 64
typedef struct qfv_light_buffer_s {
qfv_light_t lights[MaxLights] __attribute__((aligned(16)));
light_t lights[MaxLights] __attribute__((aligned(16)));
int lightCount;
//mat4f_t shadowMat[MaxLights];
//vec4f_t shadowCascade[MaxLights];
@ -92,11 +74,6 @@ typedef struct lightingframe_s {
VkWriteDescriptorSet shadowWrite;
};
};
// A fat PVS of leafs visible from visible leafs so hidden lights can
// illuminate the leafs visible to the player
struct set_s *pvs;
struct mleaf_s *leaf; // the last leaf used to generate the pvs
qfv_lightvisset_t lightvis;
} lightingframe_t;
typedef struct lightingframeset_s
@ -109,14 +86,13 @@ typedef struct lightingctx_s {
VkSampler sampler;
VkDeviceMemory light_memory;
VkDeviceMemory shadow_memory;
qfv_lightset_t lights;
qfv_lightintset_t lightstyles;
qfv_lightintset_t lightleafs;
qfv_lightmatset_t lightmats;
qfv_imageset_t lightimages;
qfv_lightintset_t lightlayers;
lightintset_t lightlayers;
qfv_imageviewset_t lightviews;
struct set_s *sun_pvs;
struct lightingdata_s *ldata;
struct scene_s *scene;
} lightingctx_t;
struct vulkan_ctx_s;
@ -125,7 +101,6 @@ struct qfv_renderframe_s;
void Vulkan_Lighting_Init (struct vulkan_ctx_s *ctx);
void Vulkan_Lighting_Shutdown (struct vulkan_ctx_s *ctx);
void Vulkan_Lighting_Draw (struct qfv_renderframe_s *rFrame);
void Vulkan_LoadLights (model_t *model, const char *entity_data,
struct vulkan_ctx_s *ctx);
void Vulkan_LoadLights (struct scene_s *scene, struct vulkan_ctx_s *ctx);
#endif//__QF_Vulkan_qf_lighting_h

View file

@ -167,7 +167,6 @@ typedef struct {
int drawflat;
struct model_s *worldmodel;
struct mleaf_s *viewleaf;
} refdef_t;
// REFRESH ====================================================================

80
include/QF/scene/light.h Normal file
View file

@ -0,0 +1,80 @@
/*
light.h
Entity management
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2021/02/26
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifndef __QF_scene_light_h
#define __QF_scene_light_h
#include "QF/darray.h"
#include "QF/qtypes.h"
#include "QF/simd/types.h"
struct mod_brush_s;
#define NumStyles 64
#define NoStyle -1
#define LM_LINEAR 0 // light - dist (or radius + dist if -ve)
#define LM_INVERSE 1 // distFactor1 * light / dist
#define LM_INVERSE2 2 // distFactor2 * light / (dist * dist)
#define LM_INFINITE 3 // light
#define LM_AMBIENT 4 // light
#define LM_INVERSE3 5 // distFactor2 * light / (dist + distFactor2)**2
typedef struct light_s {
vec4f_t color;
vec4f_t position;
vec4f_t direction;
vec4f_t attenuation;
} light_t;
typedef struct lightset_s DARRAY_TYPE (light_t) lightset_t;
typedef struct lightleafset_s DARRAY_TYPE (int) lightintset_t;
typedef struct lightvisset_s DARRAY_TYPE (byte) lightvisset_t;
typedef struct lightingdata_s {
lightset_t lights;
lightintset_t lightstyles;
lightintset_t lightleafs;
lightvisset_t lightvis;
struct set_s *sun_pvs;
// A fat PVS of leafs visible from visible leafs so hidden lights can
// illuminate the leafs visible to the player
struct set_s *pvs;
struct mleaf_s *leaf; // the last leaf used to generate the pvs
struct scene_s *scene;
} lightingdata_t;
lightingdata_t *Light_CreateLightingData (struct scene_s *scene);
void Light_DestroyLightingData (lightingdata_t *ldata);
void Light_ClearLights (lightingdata_t *ldata);
void Light_EnableSun (lightingdata_t *ldata);
void Light_FindVisibleLights (lightingdata_t *ldata);
#endif//__QF_scene_light_h

View file

@ -46,6 +46,8 @@ typedef struct scene_s {
struct model_s *worldmodel;
int num_models;
struct model_s **models;
struct mleaf_s *viewleaf;
struct lightingdata_s *lights;
} scene_t;
scene_t *Scene_NewScene (void);

View file

@ -44,6 +44,7 @@ SYS_DEVELOPER (glt)
SYS_DEVELOPER (glsl)
SYS_DEVELOPER (skin)
SYS_DEVELOPER (model)
SYS_DEVELOPER (lighting)
SYS_DEVELOPER (vulkan)
SYS_DEVELOPER (vulkan_parse)

View file

@ -50,6 +50,7 @@ extern worldscene_t cl_world;
struct msg_s;
struct entity_state_s;
struct lightingdata_s;
void CL_World_Init (void);
@ -65,5 +66,7 @@ void CL_ParseBaseline (struct msg_s *msg, struct entity_state_s *baseline,
void CL_ParseStatic (struct msg_s *msg, int version);
void CL_MapCfg (const char *mapname);
void CL_World_NewMap (const char *mapname, const char *skyname);
void CL_LoadLights (struct model_s *model, const char *entity_data,
struct lightingdata_s *ldata);
#endif//__client_world_h

View file

@ -74,7 +74,7 @@ struct entity_s;
struct animation_s;
void R_DrawAliasModel (struct entity_s *e);
void R_MarkLeaves (void);
void R_MarkLeaves (struct mleaf_s *viewleaf);
void GL_SetPalette (void *data, const byte *palette);
void GLSL_SetPalette (void *data, const byte *palette);

View file

@ -7,6 +7,7 @@ libs_client_libQFclient_la_SOURCES= \
libs/client/cl_effects.c \
libs/client/cl_entities.c \
libs/client/cl_input.c \
libs/client/cl_light.c \
libs/client/cl_particles.c \
libs/client/cl_temp_entities.c \
libs/client/cl_view.c \

320
libs/client/cl_light.c Normal file
View file

@ -0,0 +1,320 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <string.h>
#include "QF/dstring.h"
#include "QF/mathlib.h"
#include "QF/model.h"
#include "QF/plist.h"
#include "QF/progs.h" //for ED_ConvertToPlist
#include "QF/script.h"
#include "QF/set.h"
#include "QF/scene/light.h"
#include "QF/simd/vec4f.h"
#include "client/world.h"
static void
dump_light (light_t *light, int leaf)
{
Sys_MaskPrintf (SYS_lighting,
"[%g, %g, %g] %g, "
"[%g, %g, %g, %g], [%g %g %g] %g, [%g, %g, %g, %g] %d\n",
VEC4_EXP (light->color),
VEC4_EXP (light->position),
VEC4_EXP (light->direction),
VEC4_EXP (light->attenuation),
leaf);
}
static float
parse_float (const char *str, float defval)
{
float val = defval;
if (str) {
char *end;
val = strtof (str, &end);
if (end == str) {
val = defval;
}
}
return val;
}
static void
parse_vector (const char *str, vec_t *val)
{
if (str) {
int num = sscanf (str, "%f %f %f", VectorExpandAddr (val));
while (num < 3) {
val[num++] = 0;
}
}
}
static float
ecos (float ang)
{
if (ang == 90 || ang == -90) {
return 0;
}
if (ang == 180 || ang == -180) {
return -1;
}
if (ang == 0 || ang == 360) {
return 1;
}
return cos (ang * M_PI / 180);
}
static float
esin (float ang)
{
if (ang == 90) {
return 1;
}
if (ang == -90) {
return -1;
}
if (ang == 180 || ang == -180) {
return 0;
}
if (ang == 0 || ang == 360) {
return 0;
}
return sin (ang * M_PI / 180);
}
static vec4f_t
sun_vector (const vec_t *ang)
{
// ang is yaw, pitch (maybe roll, but ignored
vec4f_t vec = {
ecos (ang[1]) * ecos (ang[0]),
ecos (ang[1]) * esin (ang[0]),
esin (ang[1]),
0,
};
return vec;
}
static void
parse_sun (lightingdata_t *ldata, plitem_t *entity)
{
light_t light = {};
float sunlight;
//float sunlight2;
vec3_t sunangle = { 0, -90, 0 };
Light_EnableSun (ldata);
sunlight = parse_float (PL_String (PL_ObjectForKey (entity,
"_sunlight")), 0);
//sunlight2 = parse_float (PL_String (PL_ObjectForKey (entity,
// "_sunlight2")), 0);
parse_vector (PL_String (PL_ObjectForKey (entity, "_sun_mangle")),
sunangle);
if (sunlight <= 0) {
return;
}
VectorSet (1, 1, 1, light.color);
light.color[3] = sunlight;
light.position = sun_vector (sunangle);
light.direction = light.position;
light.direction[3] = 1;
light.attenuation = (vec4f_t) { 0, 0, 1, 0 };
DARRAY_APPEND (&ldata->lights, light);
DARRAY_APPEND (&ldata->lightstyles, 0);
DARRAY_APPEND (&ldata->lightleafs, -1);
}
static vec4f_t
parse_position (const char *str)
{
vec3_t vec = {};
sscanf (str, "%f %f %f", VectorExpandAddr (vec));
return (vec4f_t) {vec[0], vec[1], vec[2], 1};
}
static void
parse_light (light_t *light, int *style, const plitem_t *entity,
const plitem_t *targets)
{
const char *str;
int model = 0;
/*Sys_Printf ("{\n");
for (int i = PL_D_NumKeys (entity); i-- > 0; ) {
const char *field = PL_KeyAtIndex (entity, i);
const char *value = PL_String (PL_ObjectForKey (entity, field));
Sys_Printf ("\t%s = %s\n", field, value);
}
Sys_Printf ("}\n");*/
// omnidirectional light (unit length xyz so not treated as ambient)
light->direction = (vec4f_t) { 0, 0, 1, 1 };
// bright white
light->color = (vec4f_t) { 1, 1, 1, 300 };
if ((str = PL_String (PL_ObjectForKey (entity, "origin")))) {
light->position = parse_position (str);
}
if ((str = PL_String (PL_ObjectForKey (entity, "target")))) {
plitem_t *target = PL_ObjectForKey (targets, str);
vec4f_t dir = { 1, 0, 0, 0 };
if (target) {
if ((str = PL_String (PL_ObjectForKey (target, "origin")))) {
dir = parse_position (str);
dir = normalf (dir - light->position);
}
}
float angle = 40;
if ((str = PL_String (PL_ObjectForKey (entity, "angle")))) {
angle = atof (str);
}
dir[3] = -cos (angle * M_PI / 360); // half angle
light->direction = dir;
}
if ((str = PL_String (PL_ObjectForKey (entity, "light_lev")))
|| (str = PL_String (PL_ObjectForKey (entity, "_light")))) {
light->color[3] = atof (str);
}
if ((str = PL_String (PL_ObjectForKey (entity, "style")))) {
*style = atoi (str) & 0x3f;
}
if ((str = PL_String (PL_ObjectForKey (entity, "delay")))) {
model = atoi (str) & 0x7;
if (model == LM_INVERSE2) {
model = LM_INVERSE3; //FIXME for marcher (need a map)
}
}
if ((str = PL_String (PL_ObjectForKey (entity, "color")))
|| (str = PL_String (PL_ObjectForKey (entity, "_color")))) {
sscanf (str, "%f %f %f", VectorExpandAddr (light->color));
VectorScale (light->color, 1/255.0, light->color);
}
vec4f_t attenuation = { 1, 0, 0, 0 }; // inverse square
switch (model) {
case LM_LINEAR:
attenuation = (vec4f_t) { 0, 0, 1, 1 / fabsf (light->color[3]) };
break;
case LM_INVERSE:
attenuation = (vec4f_t) { 0, 1.0 / 128, 0, 0 };
break;
case LM_INVERSE2:
attenuation = (vec4f_t) { 1.0 / 16384, 0, 0, 0 };
break;
case LM_INFINITE:
attenuation = (vec4f_t) { 0, 0, 1, 0 };
break;
case LM_AMBIENT:
attenuation = (vec4f_t) { 0, 0, 1, 0 };
light->direction = (vec4f_t) { 0, 0, 0, 1 };
break;
case LM_INVERSE3:
attenuation = (vec4f_t) { 1.0 / 16384, 2.0 / 128, 1, 0 };
break;
}
light->attenuation = attenuation;
}
static void
locate_lights (model_t *model, lightingdata_t *ldata)
{
light_t *lights = ldata->lights.a;
DARRAY_RESIZE (&ldata->lightleafs, ldata->lights.size);
for (size_t i = 0; i < ldata->lights.size; i++) {
mleaf_t *leaf = Mod_PointInLeaf (&lights[i].position[0], model);
ldata->lightleafs.a[i] = leaf - model->brush.leafs - 1;
}
}
void
CL_LoadLights (model_t *model, const char *entity_data, lightingdata_t *ldata)
{
plitem_t *entities = 0;
if (!entity_data) {
return;
}
Light_ClearLights (ldata);
ldata->sun_pvs = set_new_size (model->brush.visleafs);
script_t *script = Script_New ();
Script_Start (script, "ent data", entity_data);
if (Script_GetToken (script, 1)) {
if (!strcmp (script->token->str, "(")) {
// new style (plist) entity data
entities = PL_GetPropertyList (entity_data, 0);
} else {
// old style entity data
Script_UngetToken (script);
// FIXME ED_ConvertToPlist aborts if an error is encountered.
entities = ED_ConvertToPlist (script, 0, 0);
}
}
Script_Delete (script);
if (entities) {
plitem_t *targets = PL_NewDictionary (0);
// find all the targets so spotlights can be aimed
for (int i = 1; i < PL_A_NumObjects (entities); i++) {
plitem_t *entity = PL_ObjectAtIndex (entities, i);
const char *targetname = PL_String (PL_ObjectForKey (entity,
"targetname"));
if (targetname && !PL_ObjectForKey (targets, targetname)) {
PL_D_AddObject (targets, targetname, entity);
}
}
for (int i = 0; i < PL_A_NumObjects (entities); i++) {
plitem_t *entity = PL_ObjectAtIndex (entities, i);
const char *classname = PL_String (PL_ObjectForKey (entity,
"classname"));
if (!classname) {
continue;
}
if (!strcmp (classname, "worldspawn")) {
// parse_sun can add many lights
parse_sun (ldata, entity);
} else if (!strncmp (classname, "light", 5)) {
light_t light = {};
int style = 0;
parse_light (&light, &style, entity, targets);
// some lights have 0 output, so drop them
if (light.color[3]) {
DARRAY_APPEND (&ldata->lights, light);
DARRAY_APPEND (&ldata->lightstyles, style);
}
}
}
DARRAY_RESIZE (&ldata->lightvis, ldata->lights.size);
// targets does not own the objects, so need to remove them before
// freeing targets
for (int i = PL_D_NumKeys (targets); i-- > 0; ) {
PL_RemoveObjectForKey (targets, PL_KeyAtIndex (targets, i));
}
PL_Free (targets);
PL_Free (entities);
}
if (ldata->lights.size) {
locate_lights (model, ldata);
for (size_t i = 0; i < ldata->lights.size; i++) {
dump_light (&ldata->lights.a[i], ldata->lightleafs.a[i]);
}
}
Sys_MaskPrintf (SYS_lighting, "loaded %zd lights\n", ldata->lights.size);
}

View file

@ -47,6 +47,7 @@
#include "QF/msg.h"
#include "QF/scene/entity.h"
#include "QF/scene/light.h"
#include "QF/scene/scene.h"
#include "QF/simd/vec4f.h"
@ -64,6 +65,7 @@ void
CL_World_Init (void)
{
cl_world.scene = Scene_NewScene ();
cl_world.scene->lights = Light_CreateLightingData (cl_world.scene);
}
void
@ -210,6 +212,9 @@ CL_World_NewMap (const char *mapname, const char *skyname)
cl_static_entities.size = 0;
const char *entity_data = worldmodel->brush.entities;
CL_LoadLights (worldmodel, entity_data, cl_world.scene->lights);
cl_world.scene->models = cl_world.models.a;
cl_world.scene->num_models = cl_world.models.size;
SCR_NewScene (cl_world.scene);

View file

@ -11,5 +11,6 @@ libs_scene_libQFscene_la_SOURCES= \
libs/scene/camera.c \
libs/scene/entity.c \
libs/scene/hierarchy.c \
libs/scene/light.c \
libs/scene/scene.c \
libs/scene/transform.c

140
libs/scene/light.c Normal file
View file

@ -0,0 +1,140 @@
#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
expand_pvs (set_t *pvs, model_t *model)
{
set_t base_pvs = SET_STATIC_INIT (model->brush.visleafs, alloca);
set_assign (&base_pvs, pvs);
for (unsigned i = 0; i < model->brush.visleafs; i++) {
if (set_is_member (&base_pvs, i)) {
Mod_LeafPVS_mix (model->brush.leafs + i + 1, model, 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_EnableSun (lightingdata_t *ldata)
{
scene_t *scene = ldata->scene;
model_t *model = scene->worldmodel;
if (!ldata->sun_pvs) {
ldata->sun_pvs = set_new_size (model->brush.visleafs);
}
set_expand (ldata->sun_pvs, model->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 < model->brush.modleafs; l++) {
if (model->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, model);
}
void
Light_FindVisibleLights (lightingdata_t *ldata)
{
scene_t *scene = ldata->scene;
mleaf_t *leaf = scene->viewleaf;
model_t *model = scene->worldmodel;
if (!leaf) {
return;
}
if (!ldata->pvs) {
ldata->pvs = set_new_size (model->brush.visleafs);
}
if (leaf != ldata->leaf) {
//double start = Sys_DoubleTime ();
int flags = 0;
if (leaf == model->brush.leafs) {
set_everything (ldata->pvs);
} else {
Mod_LeafPVS_set (leaf, model, 0, ldata->pvs);
expand_pvs (ldata->pvs, model);
}
for (unsigned i = 0; i < model->brush.visleafs; i++) {
if (set_is_member (ldata->pvs, i)) {
flags |= model->brush.leaf_flags[i + 1];
}
}
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 == -1 && (flags & SURF_DRAWSKY))
|| set_is_member (ldata->pvs, l)) {
ldata->lightvis.a[i] = 1;
visible++;
}
}
//Sys_Printf ("find_visible_lights: %d / %zd visible\n", visible,
// ldata->lightvis.size);
}
}

View file

@ -169,8 +169,7 @@ gl_R_NewScene (scene_t *scene)
brush->leafs[i].efrags = NULL;
// Force a vis update
r_refdef.viewleaf = NULL;
R_MarkLeaves ();
R_MarkLeaves (0);
R_ClearParticles ();

View file

@ -199,8 +199,7 @@ glsl_R_NewScene (scene_t *scene)
r_refdef.worldmodel = scene->worldmodel;
// Force a vis update
r_refdef.viewleaf = NULL;
R_MarkLeaves ();
R_MarkLeaves (0);
R_ClearParticles ();
glsl_R_RegisterTextures (scene->models, scene->num_models);

View file

@ -47,7 +47,7 @@ static mleaf_t *r_oldviewleaf;
static set_t *solid;
void
R_MarkLeaves (void)
R_MarkLeaves (mleaf_t *viewleaf)
{
set_t *vis;
int c;
@ -56,12 +56,12 @@ R_MarkLeaves (void)
msurface_t **mark;
mod_brush_t *brush = &r_refdef.worldmodel->brush;
if (r_oldviewleaf == r_refdef.viewleaf && !r_novis)
if (r_oldviewleaf == viewleaf && !r_novis)
return;
r_visframecount++;
r_oldviewleaf = r_refdef.viewleaf;
if (!r_refdef.viewleaf)
r_oldviewleaf = viewleaf;
if (!viewleaf)
return;
if (r_novis) {
@ -73,7 +73,7 @@ R_MarkLeaves (void)
}
vis = solid;
} else
vis = Mod_LeafPVS (r_refdef.viewleaf, r_refdef.worldmodel);
vis = Mod_LeafPVS (viewleaf, r_refdef.worldmodel);
for (unsigned i = 0; i < brush->visleafs; i++) {
if (set_is_member (vis, i)) {

View file

@ -270,20 +270,21 @@ SCR_UpdateScreen (transform_t *camera, double realtime, SCR_Func *scr_funcs)
R_RunParticles (r_data->frametime);
R_AnimateLight ();
refdef->viewleaf = 0;
if (refdef->worldmodel) {
if (scr_scene && scr_scene->worldmodel) {
scr_scene->viewleaf = 0;
vec4f_t position = refdef->frame.position;
refdef->viewleaf = Mod_PointInLeaf ((vec_t*)&position, refdef->worldmodel);//FIXME
scr_scene->viewleaf = Mod_PointInLeaf ((vec_t*)&position,
scr_scene->worldmodel);//FIXME
r_dowarpold = r_dowarp;
if (r_waterwarp) {
r_dowarp = refdef->viewleaf->contents <= CONTENTS_WATER;
r_dowarp = scr_scene->viewleaf->contents <= CONTENTS_WATER;
}
if (r_dowarp && !warp_buffer) {
warp_buffer = r_funcs->create_frame_buffer (r_data->vid->width,
r_data->vid->height);
}
R_MarkLeaves (scr_scene->viewleaf);
}
R_MarkLeaves ();
R_PushDlights (vec3_origin);
r_funcs->begin_frame ();

View file

@ -167,8 +167,7 @@ R_NewScene (scene_t *scene)
R_InitSky (brush->skytexture);
// Force a vis update
r_refdef.viewleaf = NULL;
R_MarkLeaves ();
R_MarkLeaves (0);
R_ClearParticles ();

View file

@ -50,6 +50,8 @@
#include "QF/sys.h"
#include "QF/va.h"
#include "QF/scene/scene.h"
#include "QF/Vulkan/qf_lighting.h"
#include "QF/Vulkan/qf_texture.h"
#include "QF/Vulkan/barrier.h"
@ -68,79 +70,16 @@
#include "r_internal.h"
#include "vid_vulkan.h"
static vec4f_t ref_direction = { 0, 0, 1, 0 };
static void
expand_pvs (set_t *pvs, model_t *model)
{
set_t base_pvs = SET_STATIC_INIT (model->brush.visleafs, alloca);
set_assign (&base_pvs, pvs);
for (unsigned i = 0; i < model->brush.visleafs; i++) {
if (set_is_member (&base_pvs, i)) {
Mod_LeafPVS_mix (model->brush.leafs + i + 1, model, 0, pvs);
}
}
}
static void
find_visible_lights (vulkan_ctx_t *ctx)
{
//qfv_device_t *device = ctx->device;
//qfv_devfuncs_t *dfunc = device->funcs;
lightingctx_t *lctx = ctx->lighting_context;
lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame];
mleaf_t *leaf = r_refdef.viewleaf;
model_t *model = r_refdef.worldmodel;
if (!leaf || !model) {
return;
}
if (leaf != lframe->leaf) {
//double start = Sys_DoubleTime ();
int flags = 0;
if (leaf == model->brush.leafs) {
set_everything (lframe->pvs);
} else {
Mod_LeafPVS_set (leaf, model, 0, lframe->pvs);
expand_pvs (lframe->pvs, model);
}
for (unsigned i = 0; i < model->brush.visleafs; i++) {
if (set_is_member (lframe->pvs, i)) {
flags |= model->brush.leaf_flags[i + 1];
}
}
lframe->leaf = leaf;
//double end = Sys_DoubleTime ();
//Sys_Printf ("find_visible_lights: %.5gus\n", (end - start) * 1e6);
int visible = 0;
memset (lframe->lightvis.a, 0, lframe->lightvis.size * sizeof (byte));
for (size_t i = 0; i < lctx->lightleafs.size; i++) {
int l = lctx->lightleafs.a[i];
if ((l == -1 && (flags & SURF_DRAWSKY))
|| set_is_member (lframe->pvs, l)) {
lframe->lightvis.a[i] = 1;
visible++;
}
}
//Sys_Printf ("find_visible_lights: %d / %zd visible\n", visible,
// lframe->lightvis.size);
}
}
static void
update_lights (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
lightingctx_t *lctx = ctx->lighting_context;
lightingdata_t *ldata = lctx->ldata;
lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame];
find_visible_lights (ctx);
Light_FindVisibleLights (ldata);
dlight_t *lights[MaxLights];
qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging);
@ -168,12 +107,12 @@ update_lights (vulkan_ctx_t *ctx)
light_data->lights[i].direction =
(vec4f_t) { 0, 0, 1, 1 };
}
for (size_t i = 0; (i < lframe->lightvis.size
for (size_t i = 0; (i < ldata->lightvis.size
&& light_data->lightCount < MaxLights); i++) {
if (lframe->lightvis.a[i]) {
qfv_light_t *light = &light_data->lights[light_data->lightCount++];
*light = lctx->lights.a[i];
light->color[3] *= style_intensities[lctx->lightstyles.a[i]];
if (ldata->lightvis.a[i]) {
light_t *light = &light_data->lights[light_data->lightCount++];
*light = ldata->lights.a[i];
light->color[3] *= style_intensities[ldata->lightstyles.a[i]];
}
}
@ -202,10 +141,13 @@ Vulkan_Lighting_Draw (qfv_renderframe_t *rFrame)
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
qfv_renderpass_t *renderpass = rFrame->renderpass;
lightingctx_t *lctx = ctx->lighting_context;
if (!lctx->scene) {
return;
}
update_lights (ctx);
lightingctx_t *lctx = ctx->lighting_context;
__auto_type cframe = &ctx->frames.a[ctx->curFrame];
lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame];
VkCommandBuffer cmd = lframe->cmd;
@ -299,9 +241,6 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx)
lightingctx_t *lctx = calloc (1, sizeof (lightingctx_t));
ctx->lighting_context = lctx;
DARRAY_INIT (&lctx->lights, 16);
DARRAY_INIT (&lctx->lightstyles, 16);
DARRAY_INIT (&lctx->lightleafs, 16);
DARRAY_INIT (&lctx->lightmats, 16);
DARRAY_INIT (&lctx->lightlayers, 16);
DARRAY_INIT (&lctx->lightimages, 16);
@ -376,10 +315,6 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx)
shadow_set->a[i],
va (ctx->va_ctx, "lighting:shadow_set:%zd", i));
DARRAY_INIT (&lframe->lightvis, 16);
lframe->pvs = 0;
lframe->leaf = 0;
QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdSet);
lframe->cmd = cmdSet->a[0];
@ -455,13 +390,9 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx)
for (size_t i = 0; i < lctx->frames.size; i++) {
lightingframe_t *lframe = &lctx->frames.a[i];
dfunc->vkDestroyBuffer (device->dev, lframe->light_buffer, 0);
DARRAY_CLEAR (&lframe->lightvis);
}
dfunc->vkFreeMemory (device->dev, lctx->light_memory, 0);
dfunc->vkDestroyPipeline (device->dev, lctx->pipeline, 0);
DARRAY_CLEAR (&lctx->lights);
DARRAY_CLEAR (&lctx->lightstyles);
DARRAY_CLEAR (&lctx->lightleafs);
DARRAY_CLEAR (&lctx->lightmats);
DARRAY_CLEAR (&lctx->lightimages);
DARRAY_CLEAR (&lctx->lightlayers);
@ -469,240 +400,16 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx)
free (lctx->frames.a);
free (lctx);
}
static void
dump_light (qfv_light_t *light, int leaf, mat4f_t mat)
{
Sys_MaskPrintf (SYS_vulkan,
"[%g, %g, %g] %g, "
"[%g, %g, %g, %g], [%g %g %g] %g, [%g, %g, %g, %g] %d\n",
VEC4_EXP (light->color),
VEC4_EXP (light->position),
VEC4_EXP (light->direction),
VEC4_EXP (light->attenuation),
leaf);
// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 0));
// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 1));
// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 2));
// Sys_MaskPrintf (SYS_vulkan, " " VEC4F_FMT "\n", MAT4_ROW (mat, 3));
}
static float
parse_float (const char *str, float defval)
{
float val = defval;
if (str) {
char *end;
val = strtof (str, &end);
if (end == str) {
val = defval;
}
}
return val;
}
static void
parse_vector (const char *str, vec_t *val)
{
if (str) {
int num = sscanf (str, "%f %f %f", VectorExpandAddr (val));
while (num < 3) {
val[num++] = 0;
}
}
}
static float
ecos (float ang)
{
if (ang == 90 || ang == -90) {
return 0;
}
if (ang == 180 || ang == -180) {
return -1;
}
if (ang == 0 || ang == 360) {
return 1;
}
return cos (ang * M_PI / 180);
}
static float
esin (float ang)
{
if (ang == 90) {
return 1;
}
if (ang == -90) {
return -1;
}
if (ang == 180 || ang == -180) {
return 0;
}
if (ang == 0 || ang == 360) {
return 0;
}
return sin (ang * M_PI / 180);
}
static vec4f_t
sun_vector (const vec_t *ang)
{
// ang is yaw, pitch (maybe roll, but ignored
vec4f_t vec = {
ecos (ang[1]) * ecos (ang[0]),
ecos (ang[1]) * esin (ang[0]),
esin (ang[1]),
0,
};
return vec;
}
static void
parse_sun (lightingctx_t *lctx, plitem_t *entity, model_t *model)
{
qfv_light_t light = {};
float sunlight;
//float sunlight2;
vec3_t sunangle = { 0, -90, 0 };
set_expand (lctx->sun_pvs, model->brush.visleafs);
set_empty (lctx->sun_pvs);
sunlight = parse_float (PL_String (PL_ObjectForKey (entity,
"_sunlight")), 0);
//sunlight2 = parse_float (PL_String (PL_ObjectForKey (entity,
// "_sunlight2")), 0);
parse_vector (PL_String (PL_ObjectForKey (entity, "_sun_mangle")),
sunangle);
if (sunlight <= 0) {
return;
}
VectorSet (1, 1, 1, light.color);
light.color[3] = sunlight;
light.position = sun_vector (sunangle);
light.direction = light.position;
light.direction[3] = 1;
light.attenuation = (vec4f_t) { 0, 0, 1, 0 };
DARRAY_APPEND (&lctx->lights, light);
DARRAY_APPEND (&lctx->lightstyles, 0);
DARRAY_APPEND (&lctx->lightleafs, -1);
// 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 < model->brush.modleafs; l++) {
if (model->brush.leaf_flags[l] & SURF_DRAWSKY) {
set_add (lctx->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 (lctx->sun_pvs, model);
}
static vec4f_t
parse_position (const char *str)
{
vec3_t vec = {};
sscanf (str, "%f %f %f", VectorExpandAddr (vec));
return (vec4f_t) {vec[0], vec[1], vec[2], 1};
}
static void
parse_light (qfv_light_t *light, int *style, const plitem_t *entity,
const plitem_t *targets)
{
const char *str;
int model = 0;
/*Sys_Printf ("{\n");
for (int i = PL_D_NumKeys (entity); i-- > 0; ) {
const char *field = PL_KeyAtIndex (entity, i);
const char *value = PL_String (PL_ObjectForKey (entity, field));
Sys_Printf ("\t%s = %s\n", field, value);
}
Sys_Printf ("}\n");*/
// omnidirectional light (unit length xyz so not treated as ambient)
light->direction = (vec4f_t) { 0, 0, 1, 1 };
// bright white
light->color = (vec4f_t) { 1, 1, 1, 300 };
if ((str = PL_String (PL_ObjectForKey (entity, "origin")))) {
light->position = parse_position (str);
}
if ((str = PL_String (PL_ObjectForKey (entity, "target")))) {
plitem_t *target = PL_ObjectForKey (targets, str);
vec4f_t dir = { 1, 0, 0, 0 };
if (target) {
if ((str = PL_String (PL_ObjectForKey (target, "origin")))) {
dir = parse_position (str);
dir = normalf (dir - light->position);
}
}
float angle = 40;
if ((str = PL_String (PL_ObjectForKey (entity, "angle")))) {
angle = atof (str);
}
dir[3] = -cos (angle * M_PI / 360); // half angle
light->direction = dir;
}
if ((str = PL_String (PL_ObjectForKey (entity, "light_lev")))
|| (str = PL_String (PL_ObjectForKey (entity, "_light")))) {
light->color[3] = atof (str);
}
if ((str = PL_String (PL_ObjectForKey (entity, "style")))) {
*style = atoi (str) & 0x3f;
}
if ((str = PL_String (PL_ObjectForKey (entity, "delay")))) {
model = atoi (str) & 0x7;
if (model == LM_INVERSE2) {
model = LM_INVERSE3; //FIXME for marcher (need a map)
}
}
if ((str = PL_String (PL_ObjectForKey (entity, "color")))
|| (str = PL_String (PL_ObjectForKey (entity, "_color")))) {
sscanf (str, "%f %f %f", VectorExpandAddr (light->color));
VectorScale (light->color, 1/255.0, light->color);
}
vec4f_t attenuation = { 1, 0, 0, 0 }; // inverse square
switch (model) {
case LM_LINEAR:
attenuation = (vec4f_t) { 0, 0, 1, 1 / fabsf (light->color[3]) };
break;
case LM_INVERSE:
attenuation = (vec4f_t) { 0, 1.0 / 128, 0, 0 };
break;
case LM_INVERSE2:
attenuation = (vec4f_t) { 1.0 / 16384, 0, 0, 0 };
break;
case LM_INFINITE:
attenuation = (vec4f_t) { 0, 0, 1, 0 };
break;
case LM_AMBIENT:
attenuation = (vec4f_t) { 0, 0, 1, 0 };
light->direction = (vec4f_t) { 0, 0, 0, 1 };
break;
case LM_INVERSE3:
attenuation = (vec4f_t) { 1.0 / 16384, 2.0 / 128, 1, 0 };
break;
}
light->attenuation = attenuation;
}
#if 0
static vec4f_t ref_direction = { 0, 0, 1, 0 };
static void
create_light_matrices (lightingctx_t *lctx)
{
DARRAY_RESIZE (&lctx->lightmats, lctx->lights.size);
for (size_t i = 0; i < lctx->lights.size; i++) {
qfv_light_t *light = &lctx->lights.a[i];
lightingdata_t *ldata = lctx->ldata;
DARRAY_RESIZE (&lctx->lightmats, ldata->lights.size);
for (size_t i = 0; i < ldata->lights.size; i++) {
light_t *light = &ldata->lights.a[i];
mat4f_t view;
mat4f_t proj;
int mode = ST_NONE;
@ -754,8 +461,8 @@ create_light_matrices (lightingctx_t *lctx)
static int
light_compare (const void *_l2, const void *_l1)
{
const qfv_light_t *l1 = _l1;
const qfv_light_t *l2 = _l2;
const light_t *l1 = _l1;
const light_t *l2 = _l2;
if (l1->color[3] == l2->color[3]) {
return (l1->position[3] == l2->position[3])
@ -852,8 +559,9 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
qfv_devfuncs_t *dfunc = device->funcs;
qfv_physdev_t *physDev = device->physDev;
int maxLayers = physDev->properties.limits.maxImageArrayLayers;
qfv_light_t *lights = lctx->lights.a;
int numLights = lctx->lights.size;
lightingdata_t *ldata = lctx->ldata;
light_t *lights = ldata->lights.a;
int numLights = ldata->lights.size;
int size = -1;
int numLayers = 0;
int totalLayers = 0;
@ -861,7 +569,7 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
size_t memsize = 0;
DARRAY_RESIZE (&lctx->lightlayers, numLights);
qsort (lights, numLights, sizeof (qfv_light_t), light_compare);
qsort (lights, numLights, sizeof (light_t), light_compare);
for (int i = 0; i < numLights; i++) {
int layers = 1;
int shadow = ST_NONE;
@ -961,10 +669,10 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
}
int mode = ST_NONE;
if (!lctx->lights.a[i].position[3]) {
if (!ldata->lights.a[i].position[3]) {
mode = ST_CASCADE;
} else {
if (lctx->lights.a[i].direction[3] > -0.5) {
if (ldata->lights.a[i].direction[3] > -0.5) {
mode = ST_CUBE;
} else {
mode = ST_PLANE;
@ -977,117 +685,13 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
Sys_MaskPrintf (SYS_vulkan, "shadow maps: %d layers in %zd images: %zd\n",
totalLayers, lctx->lightimages.size, memsize);
}
static void
locate_lights (model_t *model, lightingctx_t *lctx)
{
qfv_light_t *lights = lctx->lights.a;
DARRAY_RESIZE (&lctx->lightleafs, lctx->lights.size);
for (size_t i = 0; i < lctx->lights.size; i++) {
mleaf_t *leaf = Mod_PointInLeaf (&lights[i].position[0], model);
lctx->lightleafs.a[i] = leaf - model->brush.leafs - 1;
}
}
#endif
void
Vulkan_LoadLights (model_t *model, const char *entity_data, vulkan_ctx_t *ctx)
Vulkan_LoadLights (scene_t *scene, vulkan_ctx_t *ctx)
{
lightingctx_t *lctx = ctx->lighting_context;
plitem_t *entities = 0;
if (!entity_data) {
return;
}
lctx->lights.size = 0;
lctx->lightstyles.size = 0;
lctx->lightleafs.size = 0;
lctx->lightmats.size = 0;
if (lctx->sun_pvs) {
set_delete (lctx->sun_pvs);
}
lctx->sun_pvs = set_new_size (model->brush.visleafs);
for (size_t i = 0; i < ctx->frames.size; i++) {
__auto_type lframe = &lctx->frames.a[i];
if (lframe->pvs) {
set_delete (lframe->pvs);
}
lframe->pvs = set_new_size (model->brush.visleafs);
}
clear_shadows (ctx);
script_t *script = Script_New ();
Script_Start (script, "ent data", entity_data);
if (Script_GetToken (script, 1)) {
if (strequal (script->token->str, "(")) {
// new style (plist) entity data
entities = PL_GetPropertyList (entity_data, &ctx->hashlinks);
} else {
// old style entity data
Script_UngetToken (script);
// FIXME ED_ConvertToPlist aborts if an error is encountered.
entities = ED_ConvertToPlist (script, 0, &ctx->hashlinks);
}
}
Script_Delete (script);
if (entities) {
plitem_t *targets = PL_NewDictionary (&ctx->hashlinks);
// find all the targets so spotlights can be aimed
for (int i = 1; i < PL_A_NumObjects (entities); i++) {
plitem_t *entity = PL_ObjectAtIndex (entities, i);
const char *targetname = PL_String (PL_ObjectForKey (entity,
"targetname"));
if (targetname && !PL_ObjectForKey (targets, targetname)) {
PL_D_AddObject (targets, targetname, entity);
}
}
for (int i = 0; i < PL_A_NumObjects (entities); i++) {
plitem_t *entity = PL_ObjectAtIndex (entities, i);
const char *classname = PL_String (PL_ObjectForKey (entity,
"classname"));
if (!classname) {
continue;
}
if (strequal (classname, "worldspawn")) {
// parse_sun can add many lights
parse_sun (lctx, entity, model);
} else if (strnequal (classname, "light", 5)) {
qfv_light_t light = {};
int style = 0;
parse_light (&light, &style, entity, targets);
// some lights have 0 output, so drop them
if (light.color[3]) {
DARRAY_APPEND (&lctx->lights, light);
DARRAY_APPEND (&lctx->lightstyles, style);
}
}
}
for (size_t i = 0; i < ctx->frames.size; i++) {
lightingframe_t *lframe = &lctx->frames.a[i];
DARRAY_RESIZE (&lframe->lightvis, lctx->lights.size);
}
// targets does not own the objects, so need to remove them before
// freeing targets
for (int i = PL_D_NumKeys (targets); i-- > 0; ) {
PL_RemoveObjectForKey (targets, PL_KeyAtIndex (targets, i));
}
PL_Free (targets);
PL_Free (entities);
}
Sys_MaskPrintf (SYS_vulkan, "loaded %zd lights\n", lctx->lights.size);
if (lctx->lights.size) {
build_shadow_maps (lctx, ctx);
create_light_matrices (lctx);
locate_lights (model, lctx);
for (size_t i = 0; i < lctx->lights.size; i++) {
dump_light (&lctx->lights.a[i], lctx->lightleafs.a[i],
lctx->lightmats.a[i]);
}
}
lctx->scene = scene;
lctx->ldata = scene->lights;
}

View file

@ -142,14 +142,13 @@ Vulkan_NewScene (scene_t *scene, vulkan_ctx_t *ctx)
r_refdef.worldmodel = scene->worldmodel;
// Force a vis update
r_refdef.viewleaf = NULL;
R_MarkLeaves ();
R_MarkLeaves (0);
R_ClearParticles ();
Vulkan_RegisterTextures (scene->models, scene->num_models, ctx);
//Vulkan_BuildLightmaps (scene->models, scene->num_models, ctx);
Vulkan_BuildDisplayLists (scene->models, scene->num_models, ctx);
Vulkan_LoadLights (scene->worldmodel, scene->worldmodel->brush.entities, ctx);
Vulkan_LoadLights (scene, ctx);
}
/*void