[client] Put dynamic lights on separate entities

Dynamic lights can't go directly on visible entities as one or the other
will fail to be queued. In addition, the number of lights on an entity
needs to be limited. For now, one general purpose light for various
effects (eg, quad damage etc) and one for the muzzle flash.
This commit is contained in:
Bill Currie 2023-08-05 01:39:15 +09:00
parent fb818d15d9
commit 7294a77356
4 changed files with 118 additions and 24 deletions

View File

@ -31,6 +31,17 @@
#define __client_effects_h #define __client_effects_h
#include "QF/simd/types.h" #include "QF/simd/types.h"
#include "QF/ecs/component.h"
enum {
effect_light, // light entity id
effect_muzzleflash, // light entity id
effect_comp_count,
};
extern const component_t effect_components[effect_comp_count];
extern struct ecs_system_s effect_system;
struct entity_s; struct entity_s;
struct entity_state_s; struct entity_state_s;

View File

@ -38,6 +38,7 @@
# include <strings.h> # include <strings.h>
#endif #endif
#include "QF/ecs.h"
#include "QF/render.h" #include "QF/render.h"
#include "QF/plugin/vid_render.h" //FIXME #include "QF/plugin/vid_render.h" //FIXME
@ -50,6 +51,53 @@
#include "client/particles.h" #include "client/particles.h"
#include "client/world.h" #include "client/world.h"
ecs_system_t effect_system;
const component_t effect_components[effect_comp_count] = {
[effect_light] = {
.size = sizeof (uint32_t),
.name = "effect light",
},
[effect_muzzleflash] = {
.size = sizeof (uint32_t),
.name = "muzzle flash",
},
};
#define c_light (effect_system.base + effect_light)
static bool
has_light (entity_t ent)
{
return Ent_HasComponent (ent.id, c_light, ent.reg);
}
static uint32_t
get_light (entity_t ent)
{
return *(uint32_t *) Ent_GetComponent (ent.id, c_light, ent.reg);
}
static void
set_light (entity_t ent, uint32_t light)
{
Ent_SetComponent (ent.id, c_light, ent.reg, &light);
}
static uint32_t
attach_light_ent (entity_t ent)
{
uint32_t light = nullent;
if (has_light (ent)) {
light = get_light (ent);
}
if (!ECS_EntValid (light, ent.reg)) {
light = ECS_NewEntity (ent.reg);
set_light (ent, light);
}
return light;
}
void void
CL_NewDlight (entity_t ent, vec4f_t org, int effects, byte glow_size, CL_NewDlight (entity_t ent, vec4f_t org, int effects, byte glow_size,
byte glow_color, double time) byte glow_color, double time)
@ -103,13 +151,14 @@ CL_NewDlight (entity_t ent, vec4f_t org, int effects, byte glow_size,
} }
} }
Ent_SetComponent (ent.id, scene_dynlight, ent.reg, &(dlight_t) { uint32_t light = attach_light_ent (ent);
Ent_SetComponent (light, scene_dynlight, ent.reg, &(dlight_t) {
.origin = org, .origin = org,
.color = color, .color = color,
.radius = radius, .radius = radius,
.die = die, .die = die,
}); });
Light_LinkLight (cl_world.scene->lights, ent.id); Light_LinkLight (cl_world.scene->lights, light);
} }
void void
@ -123,14 +172,15 @@ CL_ModelEffects (entity_t ent, int glow_color, double time)
// add automatic particle trails // add automatic particle trails
if (model->flags & EF_ROCKET) { if (model->flags & EF_ROCKET) {
Ent_SetComponent (ent.id, scene_dynlight, ent.reg, &(dlight_t) { uint32_t light = attach_light_ent (ent);
Ent_SetComponent (light, scene_dynlight, ent.reg, &(dlight_t) {
.origin = ent_origin, .origin = ent_origin,
//FIXME VectorCopy (r_firecolor, dl->color); //FIXME VectorCopy (r_firecolor, dl->color);
.color = { 0.9, 0.7, 0.0, 0.7 }, .color = { 0.9, 0.7, 0.0, 0.7 },
.radius = 200, .radius = 200,
.die = time + 0.1, .die = time + 0.1,
}); });
Light_LinkLight (cl_world.scene->lights, ent.id); Light_LinkLight (cl_world.scene->lights, light);
clp_funcs->RocketTrail (*old_origin, ent_origin); clp_funcs->RocketTrail (*old_origin, ent_origin);
} else if (model->flags & EF_GRENADE) } else if (model->flags & EF_GRENADE)
clp_funcs->GrenadeTrail (*old_origin, ent_origin); clp_funcs->GrenadeTrail (*old_origin, ent_origin);
@ -148,20 +198,6 @@ CL_ModelEffects (entity_t ent, int glow_color, double time)
clp_funcs->GlowTrail (*old_origin, ent_origin, glow_color); clp_funcs->GlowTrail (*old_origin, ent_origin, glow_color);
} }
void
CL_MuzzleFlash (entity_t ent, vec4f_t position, vec4f_t fv, float zoffset,
double time)
{
Ent_SetComponent (ent.id, scene_dynlight, ent.reg, &(dlight_t) {
.origin = position + 18 * fv + zoffset * (vec4f_t) {0, 0, 1, 0},
.color = { 0.2, 0.1, 0.05, 0.7 },
.radius = 200 + (rand () & 31),
.die = time + 0.1,
.minlight = 32,
});
Light_LinkLight (cl_world.scene->lights, ent.id);
}
void void
CL_EntityEffects (entity_t ent, entity_state_t *state, double time) CL_EntityEffects (entity_t ent, entity_state_t *state, double time)
{ {

View File

@ -749,3 +749,48 @@ CL_ParseProjectiles (qmsg_t *net_message, bool nail2, TEntContext_t *ctx)
*tail = cl_projectiles; *tail = cl_projectiles;
cl_projectiles = head; cl_projectiles = head;
} }
#define c_muzzleflash (effect_system.base + effect_muzzleflash)
static bool
has_muzzleflash (entity_t ent)
{
return Ent_HasComponent (ent.id, c_muzzleflash, ent.reg);
}
static uint32_t
get_muzzleflash (entity_t ent)
{
return *(uint32_t *) Ent_GetComponent (ent.id, c_muzzleflash, ent.reg);
}
static void
set_muzzleflash (entity_t ent, uint32_t light)
{
Ent_SetComponent (ent.id, c_muzzleflash, ent.reg, &light);
}
void
CL_MuzzleFlash (entity_t ent, vec4f_t position, vec4f_t fv, float zoffset,
double time)
{
// spawn a new entity so the light doesn't mess with the owner
uint32_t light = nullent;
if (has_muzzleflash (ent)) {
light = get_muzzleflash (ent);
}
if (!ECS_EntValid (light, ent.reg)) {
light = ECS_NewEntity (ent.reg);
set_muzzleflash (ent, light);
}
DARRAY_APPEND (&light_entities, ((entity_t) {.reg = ent.reg, .id = light}));
Ent_SetComponent (light, scene_dynlight, ent.reg, &(dlight_t) {
.origin = position + 18 * fv + zoffset * (vec4f_t) {0, 0, 1, 0},
.color = { 0.2, 0.1, 0.05, 0.7 },
.radius = 200 + (rand () & 31),
.die = time + 0.1,
.minlight = 32,
});
Light_LinkLight (cl_world.scene->lights, light);
}

View File

@ -43,16 +43,12 @@
#include "QF/idparse.h" #include "QF/idparse.h"
#include "QF/quakefs.h" #include "QF/quakefs.h"
#include "QF/plist.h" #include "QF/plist.h"
#include "QF/progs.h"
#include "QF/msg.h"
#include "QF/scene/entity.h"
#include "QF/scene/light.h" #include "QF/scene/light.h"
#include "QF/scene/scene.h"
#include "QF/simd/vec4f.h"
#include "QF/plugin/vid_render.h" //FIXME #include "QF/plugin/vid_render.h" //FIXME
#include "client/effects.h"
#include "client/entities.h" #include "client/entities.h"
#include "client/temp_entities.h" #include "client/temp_entities.h"
#include "client/world.h" #include "client/world.h"
@ -64,7 +60,13 @@ worldscene_t cl_world = {
void void
CL_World_Init (void) CL_World_Init (void)
{ {
cl_world.scene = Scene_NewScene (0); scene_system_t extra_systems[] = {
{ .system = &effect_system,
.components = effect_components,
.component_count = effect_comp_count },
{}
};
cl_world.scene = Scene_NewScene (extra_systems);
cl_world.scene->lights = Light_CreateLightingData (cl_world.scene); cl_world.scene->lights = Light_CreateLightingData (cl_world.scene);
} }