mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-22 20:41:20 +00:00
[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:
parent
e9ad7b748b
commit
9ee0eada1f
20 changed files with 609 additions and 480 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
80
include/QF/scene/light.h
Normal 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
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
320
libs/client/cl_light.c
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
140
libs/scene/light.c
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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 ();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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 ();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue