diff --git a/include/client/effects.h b/include/client/effects.h index e545e2ccb..16214742a 100644 --- a/include/client/effects.h +++ b/include/client/effects.h @@ -31,6 +31,17 @@ #define __client_effects_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_state_s; diff --git a/libs/client/cl_effects.c b/libs/client/cl_effects.c index 3057bd5ea..f407fbd1c 100644 --- a/libs/client/cl_effects.c +++ b/libs/client/cl_effects.c @@ -38,6 +38,7 @@ # include #endif +#include "QF/ecs.h" #include "QF/render.h" #include "QF/plugin/vid_render.h" //FIXME @@ -50,6 +51,53 @@ #include "client/particles.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 CL_NewDlight (entity_t ent, vec4f_t org, int effects, byte glow_size, 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, .color = color, .radius = radius, .die = die, }); - Light_LinkLight (cl_world.scene->lights, ent.id); + Light_LinkLight (cl_world.scene->lights, light); } void @@ -123,14 +172,15 @@ CL_ModelEffects (entity_t ent, int glow_color, double time) // add automatic particle trails 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, //FIXME VectorCopy (r_firecolor, dl->color); .color = { 0.9, 0.7, 0.0, 0.7 }, .radius = 200, .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); } else if (model->flags & EF_GRENADE) 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); } -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 CL_EntityEffects (entity_t ent, entity_state_t *state, double time) { diff --git a/libs/client/cl_temp_entities.c b/libs/client/cl_temp_entities.c index 854f5d2a2..81dcfc82d 100644 --- a/libs/client/cl_temp_entities.c +++ b/libs/client/cl_temp_entities.c @@ -749,3 +749,48 @@ CL_ParseProjectiles (qmsg_t *net_message, bool nail2, TEntContext_t *ctx) *tail = cl_projectiles; 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); +} diff --git a/libs/client/cl_world.c b/libs/client/cl_world.c index d2cfe2cee..d30fc101c 100644 --- a/libs/client/cl_world.c +++ b/libs/client/cl_world.c @@ -43,16 +43,12 @@ #include "QF/idparse.h" #include "QF/quakefs.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/scene.h" -#include "QF/simd/vec4f.h" #include "QF/plugin/vid_render.h" //FIXME +#include "client/effects.h" #include "client/entities.h" #include "client/temp_entities.h" #include "client/world.h" @@ -64,7 +60,13 @@ worldscene_t cl_world = { 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); }