From d69355f521f00f32cc3e6e57fc1eb416a988aa01 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 5 Mar 2022 01:48:10 +0900 Subject: [PATCH] [renderer] Support multiple entity queues While there's currently only the one still, this will allow the entities to be multiply queued for multi-pass rendering (eg, shadows). As the avoidance of putting an entity in the same queue more than once relies on the entity id, all entities now come from the scene (which is stored in cl_world in the client code for nq and qw), thus the extensive changes in the clients. --- include/QF/plugin/vid_render.h | 1 - include/QF/render.h | 1 - include/QF/scene/entity.h | 33 ++++ include/client/entities.h | 7 + include/client/temp_entities.h | 3 - include/client/world.h | 70 +++++++ include/r_internal.h | 4 - include/r_local.h | 2 +- libs/client/Makemodule.am | 1 + libs/client/cl_entities.c | 9 +- libs/client/cl_temp_entities.c | 54 +++--- libs/client/cl_view.c | 4 +- libs/client/cl_world.c | 224 +++++++++++++++++++++++ libs/scene/Makemodule.am | 1 + libs/scene/entity.c | 71 +++++++ libs/video/renderer/gl/gl_lightmap.c | 4 +- libs/video/renderer/gl/gl_rmain.c | 13 +- libs/video/renderer/gl/gl_rmisc.c | 5 +- libs/video/renderer/gl/gl_rsurf.c | 4 +- libs/video/renderer/glsl/glsl_bsp.c | 4 +- libs/video/renderer/glsl/glsl_main.c | 11 +- libs/video/renderer/r_efrag.c | 6 +- libs/video/renderer/r_ent.c | 95 +--------- libs/video/renderer/sw/sw_rmain.c | 23 ++- libs/video/renderer/sw/sw_rmisc.c | 4 +- libs/video/renderer/sw32/sw32_rmain.c | 23 ++- libs/video/renderer/sw32/sw32_rmisc.c | 4 +- libs/video/renderer/vid_render_gl.c | 1 - libs/video/renderer/vid_render_glsl.c | 1 - libs/video/renderer/vid_render_sw.c | 1 - libs/video/renderer/vid_render_sw32.c | 1 - libs/video/renderer/vid_render_vulkan.c | 4 +- libs/video/renderer/vulkan/vulkan_bsp.c | 4 +- libs/video/renderer/vulkan/vulkan_main.c | 12 +- nq/include/client.h | 13 +- nq/source/cl_demo.c | 6 +- nq/source/cl_ents.c | 73 +++++--- nq/source/cl_main.c | 34 ++-- nq/source/cl_parse.c | 190 +++---------------- nq/source/cl_screen.c | 6 +- nq/source/host.c | 3 +- nq/source/host_cmd.c | 10 +- nq/source/sv_ded.c | 4 + qw/include/cl_ents.h | 5 +- qw/include/client.h | 11 +- qw/source/cl_demo.c | 6 +- qw/source/cl_entparse.c | 13 +- qw/source/cl_ents.c | 74 +++++--- qw/source/cl_main.c | 20 +- qw/source/cl_parse.c | 165 +++-------------- qw/source/cl_screen.c | 5 +- qw/source/sbar.c | 5 +- qw/source/teamplay.c | 11 +- 53 files changed, 741 insertions(+), 618 deletions(-) create mode 100644 include/client/world.h create mode 100644 libs/client/cl_world.c create mode 100644 libs/scene/entity.c diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index 46e48a040..41a889bec 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -119,7 +119,6 @@ typedef struct vid_render_funcs_s { void (*R_RemoveEfrags) (entity_t *ent); void (*R_LineGraph) (int x, int y, int *h_vals, int count, int height); dlight_t *(*R_AllocDlight) (int key); - entity_t *(*R_AllocEntity) (void); void (*R_MaxDlightsCheck) (struct cvar_s *var); void (*R_DecayLights) (double frametime); diff --git a/include/QF/render.h b/include/QF/render.h index 3668a157f..fa36bff67 100644 --- a/include/QF/render.h +++ b/include/QF/render.h @@ -155,7 +155,6 @@ typedef struct visibility_s { struct mnode_s *topnode; // bmodels, first world node that // splits bmodel, or NULL if not split // applies to other models, too - int visframe; // last frame this entity was // found in an active leaf int trivial_accept; // view clipping (frustum and depth) } visibility_t; diff --git a/include/QF/scene/entity.h b/include/QF/scene/entity.h index f6bd82e4b..fd5ca8bc0 100644 --- a/include/QF/scene/entity.h +++ b/include/QF/scene/entity.h @@ -33,6 +33,7 @@ #include "QF/darray.h" #include "QF/qtypes.h" +#include "QF/set.h" #include "QF/simd/vec4f.h" #include "QF/simd/mat4f.h" @@ -46,6 +47,38 @@ #include "QF/render.h" //FIXME move entity_t here +typedef struct entqueue_s { + set_t *queued_ents; + entityset_t *ent_queues; + int num_queues; +} entqueue_t; + +#define ENTINLINE GNU89INLINE inline + +entqueue_t *EntQueue_New (int num_queues); +void EntQueue_Delete (entqueue_t *queue); +ENTINLINE void EntQueue_AddEntity (entqueue_t *queue, entity_t *ent, + int queue_num); +void EntQueue_Clear (entqueue_t *queue); + +#undef ENTINLINE +#ifndef IMPLEMENT_ENTITY_Funcs +#define ENTINLINE GNU89INLINE inline +#else +#define ENTINLINE VISIBLE +#endif + +ENTINLINE +void +EntQueue_AddEntity (entqueue_t *queue, entity_t *ent, int queue_num) +{ + if (!set_is_member (queue->queued_ents, ent->id)) { + // entity ids are negative (ones-complement) + set_add (queue->queued_ents, -ent->id);//FIXME use ~ + DARRAY_APPEND (&queue->ent_queues[queue_num], ent); + } +} + ///@} #endif//__QF_scene_entity_h diff --git a/include/client/entities.h b/include/client/entities.h index 5981d1c9d..d93107bec 100644 --- a/include/client/entities.h +++ b/include/client/entities.h @@ -31,9 +31,16 @@ #ifndef __client_entities_h #define __client_entities_h +#include "QF/darray.h" +#include "QF/msg.h" #include "QF/qtypes.h" + #include "QF/simd/types.h" +typedef struct entitystateset_s DARRAY_TYPE (struct entity_state_s) + entitystateset_t; +extern entitystateset_t cl_static_entities; + // entity_state_t is the information conveyed from the server // in an update message typedef struct entity_state_s { diff --git a/include/client/temp_entities.h b/include/client/temp_entities.h index f7f9477cf..e88a07331 100644 --- a/include/client/temp_entities.h +++ b/include/client/temp_entities.h @@ -96,15 +96,12 @@ typedef enum TE_qwEffect { //FIXME find a better way to get this info from the parser typedef struct TEntContext_s { vec4f_t simorg; - struct model_s *worldModel; int playerEntity; } TEntContext_t; struct msg_s; struct entity_s; -extern struct scene_s *cl_scene; - void CL_TEnts_Init (void); void CL_Init_Entity (struct entity_s *ent); void CL_ClearTEnts (void); diff --git a/include/client/world.h b/include/client/world.h new file mode 100644 index 000000000..191e313d8 --- /dev/null +++ b/include/client/world.h @@ -0,0 +1,70 @@ +/* + world.h + + Client world scene management + + Copyright (C) 2022 Bill Currie + + Author: Bill Currie + Date: 2022/3/4 + + 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 __client_world_h +#define __client_world_h + +#include "QF/darray.h" +#include "QF/msg.h" +#include "QF/qtypes.h" + +#include "QF/simd/types.h" + +typedef struct modelset_s DARRAY_TYPE (struct model_s *) modelset_t; + +typedef struct worldscene_s { + struct scene_s *scene; + struct plitem_s *edicts; + struct plitem_s *worldspawn; + struct model_s *worldmodel; + modelset_t models; +} worldscene_t; + +extern worldscene_t cl_world; + +struct msg_s; +struct entity_state_s; + +void CL_World_Init (void); + +// PROTOCOL_FITZQUAKE -- flags for entity baseline messages +#define B_LARGEMODEL (1<<0) // modelindex is short instead of byte +#define B_LARGEFRAME (1<<1) // frame is short instead of byte +#define B_ALPHA (1<<2) // 1 byte, uses ENTALPHA_ENCODE, not sent if ENTALPHA_DEFAULT +void CL_ParseBaseline (struct msg_s *msg, struct entity_state_s *baseline, + int version); +/* + Static entities are non-interactive world objects like torches +*/ +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); + +#endif//__client_world_h diff --git a/include/r_internal.h b/include/r_internal.h index bc2b2b464..e2924f047 100644 --- a/include/r_internal.h +++ b/include/r_internal.h @@ -81,10 +81,6 @@ void R_SetVrect (const vrect_t *pvrect, vrect_t *pvrectin, int lineadj); void R_LoadSkys (const char *); void R_ClearEfrags (void); -void R_ClearEnts (void); -void R_EnqueueEntity (struct entity_s *ent); -entity_t *R_AllocEntity (void); -void R_FreeAllEntities (void); void R_FindNearLights (const vec3_t pos, int count, dlight_t **lights); dlight_t *R_AllocDlight (int key); diff --git a/include/r_local.h b/include/r_local.h index 4e4e00bfd..d6d7b35a9 100644 --- a/include/r_local.h +++ b/include/r_local.h @@ -292,7 +292,7 @@ extern mleaf_t *r_viewleaf; extern int r_clipflags; extern int r_dlightframecount; -extern struct entity_s *r_ent_queue[mod_num_types]; +extern struct entqueue_s *r_ent_queue; struct dlight_s; extern vec3_t lightspot; diff --git a/libs/client/Makemodule.am b/libs/client/Makemodule.am index 14e52a315..95664df07 100644 --- a/libs/client/Makemodule.am +++ b/libs/client/Makemodule.am @@ -10,6 +10,7 @@ libs_client_libQFclient_la_SOURCES= \ libs/client/cl_particles.c \ libs/client/cl_temp_entities.c \ libs/client/cl_view.c \ + libs/client/cl_world.c \ libs/client/hud.c \ libs/client/locs.c \ libs/client/old_keys.c diff --git a/libs/client/cl_entities.c b/libs/client/cl_entities.c index 4403a49bd..d4cac0dfa 100644 --- a/libs/client/cl_entities.c +++ b/libs/client/cl_entities.c @@ -31,11 +31,18 @@ # include "config.h" #endif -#include "QF/render.h" //FIXME for entity_t +#include "QF/msg.h" + #include "QF/scene/entity.h" +#include "QF/scene/scene.h" #include "QF/simd/vec4f.h" +#include "QF/plugin/vid_render.h" //FIXME + #include "client/entities.h" +#include "client/temp_entities.h" + +entitystateset_t cl_static_entities = DARRAY_STATIC_INIT (32); /* QW has a max of 512 entities and wants 64 frames of data per entity, plus the baseline data (512 * (64 + 1) = 33280), but NQ has a max of 32000 diff --git a/libs/client/cl_temp_entities.c b/libs/client/cl_temp_entities.c index de6233556..86f41a339 100644 --- a/libs/client/cl_temp_entities.c +++ b/libs/client/cl_temp_entities.c @@ -52,10 +52,11 @@ #include "client/entities.h" #include "client/particles.h" #include "client/temp_entities.h" +#include "client/world.h" typedef struct tent_s { struct tent_s *next; - entity_t ent; + entity_t *ent; } tent_t; typedef struct { @@ -86,7 +87,6 @@ typedef struct tent_obj_s { static PR_RESMAP (tent_t) temp_entities; static PR_RESMAP (tent_obj_t) tent_objects; -scene_t *cl_scene; static tent_obj_t *cl_beams; static tent_obj_t *cl_explosions; @@ -137,8 +137,6 @@ CL_TEnts_Precache (int phase) void CL_TEnts_Init (void) { - cl_scene = Scene_NewScene (); - QFS_GamedirCallback (CL_TEnts_Precache); CL_TEnts_Precache (1); for (int i = 0; i < 360; i++) { @@ -150,12 +148,12 @@ CL_TEnts_Init (void) void CL_Init_Entity (entity_t *ent) { - if (ent->transform) { - Transform_Delete (ent->transform); - } - memset (ent, 0, sizeof (*ent)); + memset (&ent->animation, 0, sizeof (ent->animation)); + memset (&ent->visibility, 0, sizeof (ent->visibility)); + memset (&ent->renderer, 0, sizeof (ent->renderer)); + ent->active = 1; + ent->old_origin = (vec4f_t) {}; - ent->transform = Transform_New (cl_scene, 0); ent->renderer.skin = 0; QuatSet (1.0, 1.0, 1.0, 1.0, ent->renderer.colormod); ent->animation.pose1 = ent->animation.pose2 = -1; @@ -165,9 +163,9 @@ static tent_t * new_temp_entity (void) { tent_t *tent = PR_RESNEW_NC (temp_entities); - tent->ent.transform = 0; + tent->ent = Scene_CreateEntity (cl_world.scene); tent->next = 0; - CL_Init_Entity (&tent->ent); + CL_Init_Entity (tent->ent); return tent; } @@ -177,7 +175,7 @@ free_temp_entities (tent_t *tents) tent_t **t = &tents; while (*t) { - Transform_Delete ((*t)->ent.transform);//FIXME reuse? + Scene_DestroyEntity (cl_world.scene, (*t)->ent);//FIXME reuse? t = &(*t)->next; } *t = temp_entities._free; @@ -215,8 +213,8 @@ beam_clear (beam_t *b) tent_t *t; for (t = b->tents; t; t = t->next) { - r_funcs->R_RemoveEfrags (&t->ent); - t->ent.visibility.efrag = 0; + r_funcs->R_RemoveEfrags (t->ent); + t->ent->visibility.efrag = 0; } free_temp_entities (b->tents); b->tents = 0; @@ -263,17 +261,17 @@ beam_setup (beam_t *b, qboolean transform, double time, TEntContext_t *ctx) vec4f_t position = org + d * dist; d += 1.0; - tent->ent.renderer.model = b->model; + tent->ent->renderer.model = b->model; if (transform) { seed = seed * BEAM_SEED_PRIME; - Transform_SetLocalTransform (tent->ent.transform, scale, + Transform_SetLocalTransform (tent->ent->transform, scale, qmulf (rotation, beam_rolls[seed % 360]), position); } else { - Transform_SetLocalPosition (tent->ent.transform, position); + Transform_SetLocalPosition (tent->ent->transform, position); } - r_funcs->R_AddEfrags (&ctx->worldModel->brush, &tent->ent); + r_funcs->R_AddEfrags (&cl_world.worldmodel->brush, tent->ent); } } @@ -377,8 +375,8 @@ parse_tent (qmsg_t *net_message, double time, TEntContext_t *ctx, if (!cl_spr_explod->cache.data) { cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); } - ex->tent->ent.renderer.model = cl_spr_explod; - Transform_SetLocalPosition (ex->tent->ent.transform,//FIXME + ex->tent->ent->renderer.model = cl_spr_explod; + Transform_SetLocalPosition (ex->tent->ent->transform,//FIXME (vec4f_t) {VectorExpand (position), 1}); break; case TE_Explosion2: @@ -601,7 +599,7 @@ CL_UpdateBeams (double time, TEntContext_t *ctx) // add new entities for the lightning for (t = b->tents; t; t = t->next) { seed = seed * BEAM_SEED_PRIME; - Transform_SetLocalRotation (t->ent.transform, + Transform_SetLocalRotation (t->ent->transform, qmulf (b->rotation, beam_rolls[seed % 360])); } @@ -618,7 +616,7 @@ CL_UpdateExplosions (double time, TEntContext_t *ctx) for (to = &cl_explosions; *to; ) { ex = &(*to)->to.ex; - ent = &ex->tent->ent; + ent = ex->tent->ent; f = 10 * (time - ex->start); if (f >= ent->renderer.model->numframes) { tent_obj_t *_to; @@ -634,7 +632,7 @@ CL_UpdateExplosions (double time, TEntContext_t *ctx) ent->animation.frame = f; if (!ent->visibility.efrag) { - r_funcs->R_AddEfrags (&ctx->worldModel->brush, ent); + r_funcs->R_AddEfrags (&cl_world.worldmodel->brush, ent); } } } @@ -675,8 +673,8 @@ CL_ClearProjectiles (void) tent_t *tent; for (tent = cl_projectiles; tent; tent = tent->next) { - r_funcs->R_RemoveEfrags (&tent->ent); - tent->ent.visibility.efrag = 0; + r_funcs->R_RemoveEfrags (tent->ent); + tent->ent->visibility.efrag = 0; } free_temp_entities (cl_projectiles); cl_projectiles = 0; @@ -712,7 +710,7 @@ CL_ParseProjectiles (qmsg_t *net_message, qboolean nail2, TEntContext_t *ctx) *tail = tent; tail = &tent->next; - pr = &tent->ent; + pr = tent->ent; pr->renderer.model = cl_spike; pr->renderer.skin = 0; position[0] = ((bits[0] + ((bits[1] & 15) << 8)) << 1) - 4096; @@ -721,9 +719,9 @@ CL_ParseProjectiles (qmsg_t *net_message, qboolean nail2, TEntContext_t *ctx) angles[0] = (bits[4] >> 4) * (360.0 / 16.0); angles[1] = bits[5] * (360.0 / 256.0); angles[2] = 0; - CL_TransformEntity (&tent->ent, 1, angles, position); + CL_TransformEntity (tent->ent, 1, angles, position); - r_funcs->R_AddEfrags (&ctx->worldModel->brush, &tent->ent); + r_funcs->R_AddEfrags (&cl_world.worldmodel->brush, tent->ent); } *tail = cl_projectiles; diff --git a/libs/client/cl_view.c b/libs/client/cl_view.c index f6371e69e..a1ab36e82 100644 --- a/libs/client/cl_view.c +++ b/libs/client/cl_view.c @@ -43,8 +43,8 @@ #include "client/entities.h" #include "client/hud.h" #include "client/input.h" -#include "client/temp_entities.h"//FIXME for cl_scene #include "client/view.h" +#include "client/world.h" /* The view is allowed to move slightly from it's true position for bobbing, @@ -763,7 +763,7 @@ V_Init (viewstate_t *viewstate) "Used when you are underwater, hit, have the Ring of " "Shadows, or Quad Damage. (v_cshift r g b intensity)"); - viewstate->camera_transform = Transform_New (cl_scene, 0); + viewstate->camera_transform = Transform_New (cl_world.scene, 0); } void diff --git a/libs/client/cl_world.c b/libs/client/cl_world.c new file mode 100644 index 000000000..f0ef82072 --- /dev/null +++ b/libs/client/cl_world.c @@ -0,0 +1,224 @@ +/* + cl_entities.c + + Client side entity management + + Copyright (C) 2012 Bill Currie + + Author: Bill Currie + Date: 2012/6/28 + + 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 + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cbuf.h" +#include "QF/cmd.h" +#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/scene.h" +#include "QF/simd/vec4f.h" + +#include "QF/plugin/vid_render.h" //FIXME + +#include "client/entities.h" +#include "client/temp_entities.h" +#include "client/world.h" + +worldscene_t cl_world = { + .models = DARRAY_STATIC_INIT (32), +}; + +void +CL_World_Init (void) +{ + cl_world.scene = Scene_NewScene (); +} + +void +CL_ParseBaseline (qmsg_t *msg, entity_state_t *baseline, int version) +{ + int bits = 0; + + if (version == 2) + bits = MSG_ReadByte (msg); + + if (bits & B_LARGEMODEL) + baseline->modelindex = MSG_ReadShort (msg); + else + baseline->modelindex = MSG_ReadByte (msg); + + if (bits & B_LARGEFRAME) + baseline->frame = MSG_ReadShort (msg); + else + baseline->frame = MSG_ReadByte (msg); + + baseline->colormap = MSG_ReadByte (msg); + baseline->skinnum = MSG_ReadByte (msg); + + MSG_ReadCoordAngleV (msg, &baseline->origin[0], baseline->angles); + baseline->origin[3] = 1;//FIXME + + if (bits & B_ALPHA) + baseline->alpha = MSG_ReadByte (msg); + else + baseline->alpha = 255;//FIXME alpha + baseline->scale = 16; + baseline->glow_size = 0; + baseline->glow_color = 254; + baseline->colormod = 255; +} + +void +CL_ParseStatic (qmsg_t *msg, int version) +{ + entity_t *ent; + entity_state_t es; + + ent = Scene_CreateEntity (cl_world.scene); + CL_Init_Entity (ent); + + CL_ParseBaseline (msg, &es, version); + DARRAY_APPEND (&cl_static_entities, es); + + // copy it to the current state + ent->renderer.model = cl_world.models.a[es.modelindex]; + ent->animation.frame = es.frame; + ent->renderer.skinnum = es.skinnum; + + CL_TransformEntity (ent, es.scale / 16.0, es.angles, es.origin); + + r_funcs->R_AddEfrags (&cl_world.worldmodel->brush, ent); +} + +static void +map_cfg (const char *mapname, int all) +{ + char *name = malloc (strlen (mapname) + 4 + 1); + cbuf_t *cbuf = Cbuf_New (&id_interp); + QFile *f; + + QFS_StripExtension (mapname, name); + strcat (name, ".cfg"); + f = QFS_FOpenFile (name); + if (f) { + Qclose (f); + Cmd_Exec_File (cbuf, name, 1); + } else { + Cmd_Exec_File (cbuf, "maps_default.cfg", 1); + } + if (all) { + Cbuf_Execute_Stack (cbuf); + } else { + Cbuf_Execute_Sets (cbuf); + } + free (name); + Cbuf_Delete (cbuf); +} + +void +CL_MapCfg (const char *mapname) +{ + map_cfg (mapname, 0); +} + +static plitem_t * +map_ent (const char *mapname) +{ + static progs_t edpr; + char *name = malloc (strlen (mapname) + 4 + 1); + char *buf; + plitem_t *edicts = 0; + QFile *ent_file; + + QFS_StripExtension (mapname, name); + strcat (name, ".ent"); + ent_file = QFS_VOpenFile (name, 0, cl_world.models.a[1]->vpath); + if ((buf = (char *) QFS_LoadFile (ent_file, 0))) { + edicts = ED_Parse (&edpr, buf); + free (buf); + } else { + edicts = ED_Parse (&edpr, cl_world.models.a[1]->brush.entities); + } + free (name); + return edicts; +} + +static void +CL_LoadSky (const char *name) +{ + plitem_t *worldspawn = cl_world.worldspawn; + plitem_t *item; + static const char *sky_keys[] = { + "sky", // Q2/DarkPlaces + "skyname", // old QF + "qlsky", // QuakeLives + 0 + }; + + if (!name) { + if (!worldspawn) { + r_funcs->R_LoadSkys (0); + return; + } + for (const char **key = sky_keys; *key; key++) { + if ((item = PL_ObjectForKey (cl_world.worldspawn, *key))) { + name = PL_String (item); + break; + } + } + } + r_funcs->R_LoadSkys (name); +} + +void +CL_World_NewMap (const char *mapname, const char *skyname) +{ + cl_static_entities.size = 0; + r_funcs->R_NewMap (cl_world.worldmodel, + cl_world.models.a, cl_world.models.size); + if (cl_world.models.a[1] && cl_world.models.a[1]->brush.entities) { + if (cl_world.edicts) { + PL_Free (cl_world.edicts); + } + cl_world.edicts = map_ent (mapname); + if (cl_world.edicts) { + cl_world.worldspawn = PL_ObjectAtIndex (cl_world.edicts, 0); + CL_LoadSky (skyname); + if (r_funcs->Fog_ParseWorldspawn) + r_funcs->Fog_ParseWorldspawn (cl_world.worldspawn); + } + } + map_cfg (mapname, 1); +} diff --git a/libs/scene/Makemodule.am b/libs/scene/Makemodule.am index 060e1d31d..25b3e7562 100644 --- a/libs/scene/Makemodule.am +++ b/libs/scene/Makemodule.am @@ -9,6 +9,7 @@ libs_scene_libQFscene_la_LIBADD= $(scene_deps) libs_scene_libQFscene_la_DEPENDENCIES= $(scene_deps) libs_scene_libQFscene_la_SOURCES= \ libs/scene/camera.c \ + libs/scene/entity.c \ libs/scene/hierarchy.c \ libs/scene/scene.c \ libs/scene/transform.c diff --git a/libs/scene/entity.c b/libs/scene/entity.c new file mode 100644 index 000000000..92e5099d7 --- /dev/null +++ b/libs/scene/entity.c @@ -0,0 +1,71 @@ +/* + entity.c + + Entity management + + Copyright (C) 2022 Bill Currke + + 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 + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "QF/set.h" + +#define IMPLEMENT_ENTITY_Funcs + +#include "QF/scene/entity.h" +#include "QF/scene/scene.h" + +#include "scn_internal.h" + +entqueue_t * +EntQueue_New (int num_queues) +{ + int size = sizeof (entqueue_t) + num_queues * sizeof (entityset_t); + entqueue_t *queue = calloc (1, size); + queue->queued_ents = set_new (); + queue->ent_queues = (entityset_t *) (queue + 1); + queue->num_queues = num_queues; + for (int i = 0; i < num_queues; i++) { + queue->ent_queues[i].grow = 64; + } + return queue; +} + +void +EntQueue_Delete (entqueue_t *queue) +{ + for (int i = 0; i < queue->num_queues; i++) { + DARRAY_CLEAR (&queue->ent_queues[i]); + } + set_delete (queue->queued_ents); + free (queue); +} + +void +EntQueue_Clear (entqueue_t *queue) +{ + for (int i = 0; i < queue->num_queues; i++) { + queue->ent_queues[i].size = 0; + } + set_empty (queue->queued_ents); +} diff --git a/libs/video/renderer/gl/gl_lightmap.c b/libs/video/renderer/gl/gl_lightmap.c index c7ec6d042..f601e2755 100644 --- a/libs/video/renderer/gl/gl_lightmap.c +++ b/libs/video/renderer/gl/gl_lightmap.c @@ -551,7 +551,6 @@ gl_overbright_f (cvar_t *var) { int num; model_t *m; - entity_t *ent; mod_brush_t *brush; if (!var) @@ -598,7 +597,8 @@ gl_overbright_f (cvar_t *var) if (!gl_R_BuildLightMap) return; - for (ent = r_ent_queue[mod_brush]; ent; ent = ent->next) { + for (size_t i = 0; i < r_ent_queue->ent_queues[mod_brush].size; i++) { \ + entity_t *ent = r_ent_queue->ent_queues[mod_brush].a[i]; \ m = ent->renderer.model; if (m->path[0] == '*') continue; diff --git a/libs/video/renderer/gl/gl_rmain.c b/libs/video/renderer/gl/gl_rmain.c index 1c9fa7f00..07dd2a8b2 100644 --- a/libs/video/renderer/gl/gl_rmain.c +++ b/libs/video/renderer/gl/gl_rmain.c @@ -193,8 +193,6 @@ gl_R_RotateForEntity (entity_t *e) static void R_DrawEntitiesOnList (void) { - entity_t *ent; - if (!r_drawentities->int_val) return; @@ -220,7 +218,8 @@ R_DrawEntitiesOnList (void) qfglEnable (GL_NORMALIZE); } - for (ent = r_ent_queue[mod_alias]; ent; ent = ent->next) { + for (size_t i = 0; i < r_ent_queue->ent_queues[mod_alias].size; i++) { \ + entity_t *ent = r_ent_queue->ent_queues[mod_alias].a[i]; \ gl_R_DrawAliasModel (ent); } qfglColor3ubv (color_white); @@ -248,7 +247,8 @@ R_DrawEntitiesOnList (void) qglActiveTexture (gl_mtex_enum + 0); } - for (ent = r_ent_queue[mod_iqm]; ent; ent = ent->next) { + for (size_t i = 0; i < r_ent_queue->ent_queues[mod_iqm].size; i++) { \ + entity_t *ent = r_ent_queue->ent_queues[mod_iqm].a[i]; \ gl_R_DrawIQMModel (ent); } qfglColor3ubv (color_white); @@ -257,7 +257,8 @@ R_DrawEntitiesOnList (void) qfglEnable (GL_ALPHA_TEST); if (gl_va_capable) qfglInterleavedArrays (GL_T2F_C4UB_V3F, 0, gl_spriteVertexArray); - for (ent = r_ent_queue[mod_sprite]; ent; ent = ent->next) { + for (size_t i = 0; i < r_ent_queue->ent_queues[mod_sprite].size; i++) { \ + entity_t *ent = r_ent_queue->ent_queues[mod_sprite].a[i]; \ R_DrawSpriteModel (ent); } qfglDisable (GL_ALPHA_TEST); @@ -328,7 +329,7 @@ void gl_R_SetupFrame (void) { R_AnimateLight (); - R_ClearEnts (); + EntQueue_Clear (r_ent_queue); r_framecount++; gl_Fog_SetupFrame (); diff --git a/libs/video/renderer/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index f035be9dd..90bfc1b10 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -61,6 +61,8 @@ #include "QF/GL/qf_textures.h" #include "QF/GL/qf_vid.h" +#include "QF/scene/entity.h" + #include "mod_internal.h" #include "r_internal.h" #include "varrays.h" @@ -140,6 +142,7 @@ gl_R_LoadSky_f (void) void gl_R_Init (void) { + r_ent_queue = EntQueue_New (mod_num_types); R_Init_Cvars (); gl_R_Particles_Init_Cvars (); @@ -191,8 +194,6 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) r_worldentity.renderer.model = worldmodel; brush = &worldmodel->brush; - R_FreeAllEntities (); - // clear out efrags in case the level hasn't been reloaded for (unsigned i = 0; i < brush->modleafs; i++) brush->leafs[i].efrags = NULL; diff --git a/libs/video/renderer/gl/gl_rsurf.c b/libs/video/renderer/gl/gl_rsurf.c index 77a4e0349..5d32d9c5e 100644 --- a/libs/video/renderer/gl/gl_rsurf.c +++ b/libs/video/renderer/gl/gl_rsurf.c @@ -740,8 +740,8 @@ gl_R_DrawWorld (void) R_VisitWorldNodes (&bctx); if (r_drawentities->int_val) { - entity_t *ent; - for (ent = r_ent_queue[mod_brush]; ent; ent = ent->next) { + for (size_t i = 0; i < r_ent_queue->ent_queues[mod_brush].size; i++) { \ + entity_t *ent = r_ent_queue->ent_queues[mod_brush].a[i]; \ gl_R_DrawBrushModel (ent); } } diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index 2ee30363a..0605d81b4 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -1149,8 +1149,8 @@ glsl_R_DrawWorld (void) R_VisitWorldNodes (&bctx); if (r_drawentities->int_val) { - entity_t *ent; - for (ent = r_ent_queue[mod_brush]; ent; ent = ent->next) { + for (size_t i = 0; i < r_ent_queue->ent_queues[mod_brush].size; i++) { + entity_t *ent = r_ent_queue->ent_queues[mod_brush].a[i]; R_DrawBrushModel (ent); } } diff --git a/libs/video/renderer/glsl/glsl_main.c b/libs/video/renderer/glsl/glsl_main.c index 7dad33b8d..d7cf28aa2 100644 --- a/libs/video/renderer/glsl/glsl_main.c +++ b/libs/video/renderer/glsl/glsl_main.c @@ -48,6 +48,8 @@ #include "QF/screen.h" #include "QF/sys.h" +#include "QF/scene/entity.h" + #include "QF/GLSL/defines.h" #include "QF/GLSL/funcs.h" #include "QF/GLSL/qf_alias.h" @@ -95,7 +97,7 @@ void glsl_R_SetupFrame (void) { R_AnimateLight (); - R_ClearEnts (); + EntQueue_Clear (r_ent_queue); r_framecount++; VectorCopy (r_refdef.viewposition, r_origin); @@ -141,7 +143,6 @@ R_SetupView (void) static void R_RenderEntities (void) { - entity_t *ent; int begun; if (!r_drawentities->int_val) @@ -149,7 +150,9 @@ R_RenderEntities (void) #define RE_LOOP(type_name, Type) \ do { \ begun = 0; \ - for (ent = r_ent_queue[mod_##type_name]; ent; ent = ent->next) { \ + for (size_t i = 0; i < r_ent_queue->ent_queues[mod_##type_name].size; \ + i++) { \ + entity_t *ent = r_ent_queue->ent_queues[mod_##type_name].a[i]; \ if (!begun) { \ glsl_R_##Type##Begin (); \ begun = 1; \ @@ -237,6 +240,7 @@ glsl_R_RenderView (void) void glsl_R_Init (void) { + r_ent_queue = EntQueue_New (mod_num_types); Cmd_AddCommand ("timerefresh", glsl_R_TimeRefresh_f, "Test the current refresh rate for the current location."); R_Init_Cvars (); @@ -267,7 +271,6 @@ glsl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) r_viewleaf = NULL; R_MarkLeaves (); - R_FreeAllEntities (); R_ClearParticles (); glsl_R_RegisterTextures (models, num_models); glsl_R_BuildLightmaps (models, num_models); diff --git a/libs/video/renderer/r_efrag.c b/libs/video/renderer/r_efrag.c index 3766f681d..6c2bd3a70 100644 --- a/libs/video/renderer/r_efrag.c +++ b/libs/video/renderer/r_efrag.c @@ -235,11 +235,7 @@ R_StoreEfrags (const efrag_t *efrag) case mod_brush: case mod_sprite: case mod_iqm: - if (ent->visibility.visframe != r_framecount) { - R_EnqueueEntity (ent); - // mark that we've recorded this entity for this frame - ent->visibility.visframe = r_framecount; - } + EntQueue_AddEntity (r_ent_queue, ent, model->type); efrag = efrag->leafnext; break; diff --git a/libs/video/renderer/r_ent.c b/libs/video/renderer/r_ent.c index 9dcba8401..fb133d388 100644 --- a/libs/video/renderer/r_ent.c +++ b/libs/video/renderer/r_ent.c @@ -48,100 +48,7 @@ #include "r_internal.h" -#define ENT_POOL_SIZE 32 - -typedef struct entity_pool_s { - struct entity_pool_s *next; - entity_t entities[ENT_POOL_SIZE]; -} entity_pool_t; - -entity_t *r_ent_queue[mod_num_types]; -static entity_t **vis_tail[mod_num_types] = { - [mod_brush] &r_ent_queue[mod_brush], - [mod_sprite] &r_ent_queue[mod_sprite], - [mod_alias] &r_ent_queue[mod_alias], - [mod_iqm] &r_ent_queue[mod_iqm], -}; - -static entity_pool_t *entity_pools = 0; -static entity_pool_t **entpool_tail = &entity_pools; -static entity_t *free_entities; - -entity_t * -R_AllocEntity (void) -{ - entity_pool_t *pool; - entity_t *ent; - int i; - - if ((ent = free_entities)) { - free_entities = ent->next; - ent->next = 0; - ent->transform = 0; - return ent; - } - - pool = malloc (sizeof (entity_pool_t)); - pool->next = 0; - *entpool_tail = pool; - entpool_tail = &pool->next; - - for (ent = pool->entities, i = 0; i < ENT_POOL_SIZE - 1; i++, ent++) { - ent->next = ent + 1; - ent->transform = 0; - } - ent->next = 0; - ent->transform = 0; - free_entities = pool->entities; - - return R_AllocEntity (); -} - -void -R_FreeAllEntities (void) -{ - entity_pool_t *pool; - entity_t *ent; - int i; - - for (pool = entity_pools; pool; pool = pool->next) { - for (ent = pool->entities, i = 0; i < ENT_POOL_SIZE - 1; i++, ent++) { - ent->next = ent + 1; - if (ent->transform) { - Transform_Delete (ent->transform); - ent->transform = 0; - } - } - ent->next = pool->next ? pool->next->entities : 0; - if (ent->transform) { - Transform_Delete (ent->transform); - ent->transform = 0; - } - } - free_entities = entity_pools ? entity_pools->entities : 0; -} - -void -R_ClearEnts (void) -{ - for (int i = 0; i < mod_num_types; i++) { - r_ent_queue[i] = 0; - vis_tail[i] = &r_ent_queue[i]; - } -} - -void -R_EnqueueEntity (entity_t *ent) -{ - modtype_t type = ent->renderer.model->type; - - if (type < 0 || type >= mod_num_types) { - Sys_Error ("R_EnqueueEntity: Bad entity model type %d", type); - } - ent->next = 0; - *vis_tail[type] = ent; - vis_tail[type] = &ent->next; -} +entqueue_t *r_ent_queue; float R_EntityBlend (animation_t *animation, int pose, float interval) diff --git a/libs/video/renderer/sw/sw_rmain.c b/libs/video/renderer/sw/sw_rmain.c index d28b60b27..e482d7617 100644 --- a/libs/video/renderer/sw/sw_rmain.c +++ b/libs/video/renderer/sw/sw_rmain.c @@ -117,6 +117,8 @@ sw_R_Init (void) { int dummy; + r_ent_queue = EntQueue_New (mod_num_types); + // get stack position so we can guess if we are going to overflow r_stack_start = (byte *) & dummy; @@ -167,8 +169,6 @@ R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) memset (&r_worldentity, 0, sizeof (r_worldentity)); r_worldentity.renderer.model = worldmodel; - R_FreeAllEntities (); - // clear out efrags in case the level hasn't been reloaded for (unsigned i = 0; i < brush->modleafs; i++) brush->leafs[i].efrags = NULL; @@ -418,14 +418,14 @@ draw_iqm_entity (entity_t *ent) static void R_DrawEntitiesOnList (void) { - entity_t *ent; - if (!r_drawentities->int_val) return; #define RE_LOOP(type_name) \ do { \ - for (ent = r_ent_queue[mod_##type_name]; ent; ent = ent->next) { \ + for (size_t i = 0; i < r_ent_queue->ent_queues[mod_##type_name].size; \ + i++) { \ + entity_t *ent = r_ent_queue->ent_queues[mod_##type_name].a[i]; \ VectorCopy (Transform_GetWorldPosition (ent->transform), \ r_entorigin); \ currententity = ent; \ @@ -566,7 +566,6 @@ R_DrawBEntitiesOnList (void) vec3_t origin; model_t *clmodel; float minmaxs[6]; - entity_t *ent; if (!r_drawentities->int_val) return; @@ -574,12 +573,12 @@ R_DrawBEntitiesOnList (void) VectorCopy (modelorg, oldorigin); insubmodel = true; - for (ent = r_ent_queue[mod_brush]; ent; ent = ent->next) { + for (size_t i = 0; i < r_ent_queue->ent_queues[mod_brush].size; i++) { + entity_t *ent = r_ent_queue->ent_queues[mod_brush].a[i]; currententity = ent; - VectorCopy (Transform_GetWorldPosition (currententity->transform), - origin); - clmodel = currententity->renderer.model; + VectorCopy (Transform_GetWorldPosition (ent->transform), origin); + clmodel = ent->renderer.model; // see if the bounding box lets us trivially reject, also // sets trivial accept status @@ -626,8 +625,8 @@ R_DrawBEntitiesOnList (void) if (r_drawpolys | r_drawculledpolys) { R_ZDrawSubmodelPolys (clmodel); } else { - if (currententity->visibility.topnode) { - mnode_t *topnode = currententity->visibility.topnode; + if (ent->visibility.topnode) { + mnode_t *topnode = ent->visibility.topnode; if (topnode->contents >= 0) { // not a leaf; has to be clipped to the world diff --git a/libs/video/renderer/sw/sw_rmisc.c b/libs/video/renderer/sw/sw_rmisc.c index f0ab9c9bb..481a3f64d 100644 --- a/libs/video/renderer/sw/sw_rmisc.c +++ b/libs/video/renderer/sw/sw_rmisc.c @@ -35,6 +35,8 @@ #include "QF/sys.h" #include "QF/ui/view.h" +#include "QF/scene/entity.h" + #include "compat.h" #include "r_internal.h" #include "vid_internal.h" @@ -224,7 +226,7 @@ R_SetupFrame (void) R_CheckVariables (); R_AnimateLight (); - R_ClearEnts (); + EntQueue_Clear (r_ent_queue); r_framecount++; numbtofpolys = 0; diff --git a/libs/video/renderer/sw32/sw32_rmain.c b/libs/video/renderer/sw32/sw32_rmain.c index 3c147862b..517f471c3 100644 --- a/libs/video/renderer/sw32/sw32_rmain.c +++ b/libs/video/renderer/sw32/sw32_rmain.c @@ -142,6 +142,8 @@ sw32_R_Init (void) { int dummy; + r_ent_queue = EntQueue_New (mod_num_types); + // get stack position so we can guess if we are going to overflow r_stack_start = (byte *) & dummy; @@ -182,8 +184,6 @@ sw32_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) memset (&r_worldentity, 0, sizeof (r_worldentity)); r_worldentity.renderer.model = worldmodel; - R_FreeAllEntities (); - // clear out efrags in case the level hasn't been reloaded for (unsigned i = 0; i < brush->modleafs; i++) brush->leafs[i].efrags = NULL; @@ -425,14 +425,14 @@ draw_iqm_entity (entity_t *ent) static void R_DrawEntitiesOnList (void) { - entity_t *ent; - if (!r_drawentities->int_val) return; #define RE_LOOP(type_name) \ do { \ - for (ent = r_ent_queue[mod_##type_name]; ent; ent = ent->next) { \ + for (size_t i = 0; i < r_ent_queue->ent_queues[mod_##type_name].size; \ + i++) { \ + entity_t *ent = r_ent_queue->ent_queues[mod_##type_name].a[i]; \ VectorCopy (Transform_GetWorldPosition (ent->transform), \ r_entorigin); \ currententity = ent; \ @@ -572,7 +572,6 @@ R_DrawBEntitiesOnList (void) vec3_t origin; model_t *clmodel; float minmaxs[6]; - entity_t *ent; if (!r_drawentities->int_val) return; @@ -580,12 +579,12 @@ R_DrawBEntitiesOnList (void) VectorCopy (modelorg, oldorigin); insubmodel = true; - for (ent = r_ent_queue[mod_brush]; ent; ent = ent->next) { + for (size_t i = 0; i < r_ent_queue->ent_queues[mod_brush].size; i++) { + entity_t *ent = r_ent_queue->ent_queues[mod_brush].a[i]; currententity = ent; - VectorCopy (Transform_GetWorldPosition (currententity->transform), - origin); - clmodel = currententity->renderer.model; + VectorCopy (Transform_GetWorldPosition (ent->transform), origin); + clmodel = ent->renderer.model; // see if the bounding box lets us trivially reject, also // sets trivial accept status @@ -632,8 +631,8 @@ R_DrawBEntitiesOnList (void) if (sw32_r_drawpolys | sw32_r_drawculledpolys) { sw32_R_ZDrawSubmodelPolys (clmodel); } else { - if (currententity->visibility.topnode) { - mnode_t *topnode = currententity->visibility.topnode; + if (ent->visibility.topnode) { + mnode_t *topnode = ent->visibility.topnode; if (topnode->contents >= 0) { // not a leaf; has to be clipped to the world diff --git a/libs/video/renderer/sw32/sw32_rmisc.c b/libs/video/renderer/sw32/sw32_rmisc.c index 1845fe06e..5b4092250 100644 --- a/libs/video/renderer/sw32/sw32_rmisc.c +++ b/libs/video/renderer/sw32/sw32_rmisc.c @@ -38,6 +38,8 @@ #include "QF/sys.h" #include "QF/ui/view.h" +#include "QF/scene/entity.h" + #include "compat.h" #include "r_internal.h" #include "vid_internal.h" @@ -220,7 +222,7 @@ sw32_R_SetupFrame (void) R_CheckVariables (); R_AnimateLight (); - R_ClearEnts (); + EntQueue_Clear (r_ent_queue); r_framecount++; sw32_numbtofpolys = 0; diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index d95f53a3c..d56d065e3 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -152,7 +152,6 @@ vid_render_funcs_t gl_vid_render_funcs = { R_RemoveEfrags, gl_R_LineGraph, R_AllocDlight, - R_AllocEntity, R_MaxDlightsCheck, R_DecayLights, gl_R_ViewChanged, diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index 8b98654a1..b611eb25e 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -151,7 +151,6 @@ vid_render_funcs_t glsl_vid_render_funcs = { R_RemoveEfrags, glsl_R_LineGraph, R_AllocDlight, - R_AllocEntity, R_MaxDlightsCheck, R_DecayLights, glsl_R_ViewChanged, diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index 45f961f6b..325371a07 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -148,7 +148,6 @@ vid_render_funcs_t sw_vid_render_funcs = { R_RemoveEfrags, R_LineGraph, R_AllocDlight, - R_AllocEntity, R_MaxDlightsCheck, R_DecayLights, R_ViewChanged, diff --git a/libs/video/renderer/vid_render_sw32.c b/libs/video/renderer/vid_render_sw32.c index d24da6128..95f81a8e1 100644 --- a/libs/video/renderer/vid_render_sw32.c +++ b/libs/video/renderer/vid_render_sw32.c @@ -153,7 +153,6 @@ vid_render_funcs_t sw32_vid_render_funcs = { R_RemoveEfrags, sw32_R_LineGraph, R_AllocDlight, - R_AllocEntity, R_MaxDlightsCheck, R_DecayLights, sw32_R_ViewChanged, diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index ef35d022a..cb05aea8c 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -61,6 +61,8 @@ #include "QF/Vulkan/swapchain.h" #include "QF/ui/view.h" +#include "QF/scene/entity.h" + #include "mod_internal.h" #include "r_internal.h" #include "vid_internal.h" @@ -100,6 +102,7 @@ vulkan_ParticleSystem (void) static void vulkan_R_Init (void) { + r_ent_queue = EntQueue_New (mod_num_types); Vulkan_CreateStagingBuffers (vulkan_ctx); Vulkan_CreateSwapchain (vulkan_ctx); Vulkan_CreateFrames (vulkan_ctx); @@ -679,7 +682,6 @@ vid_render_funcs_t vulkan_vid_render_funcs = { R_RemoveEfrags, vulkan_R_LineGraph, R_AllocDlight, - R_AllocEntity, R_MaxDlightsCheck, R_DecayLights, vulkan_R_ViewChanged, diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index c4ad3dc3e..040f7db91 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -1039,8 +1039,8 @@ Vulkan_DrawWorld (qfv_renderframe_t *rFrame) R_VisitWorldNodes (brush, ctx); if (r_drawentities->int_val) { - entity_t *ent; - for (ent = r_ent_queue[mod_brush]; ent; ent = ent->next) { + for (size_t i = 0; i < r_ent_queue->ent_queues[mod_brush].size; i++) { + entity_t *ent = r_ent_queue->ent_queues[mod_brush].a[i]; R_DrawBrushModel (ent, ctx); } } diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c index 4eb55f08c..2059a5b66 100644 --- a/libs/video/renderer/vulkan/vulkan_main.c +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -45,6 +45,8 @@ #include "QF/screen.h" #include "QF/sys.h" +#include "QF/scene/entity.h" + #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/qf_alias.h" #include "QF/Vulkan/qf_bsp.h" @@ -65,7 +67,7 @@ static void setup_frame (vulkan_ctx_t *ctx) { R_AnimateLight (); - R_ClearEnts (); + EntQueue_Clear (r_ent_queue); r_framecount++; VectorCopy (r_refdef.viewposition, r_origin); @@ -85,9 +87,10 @@ Vulkan_RenderEntities (qfv_renderframe_t *rFrame) return; #define RE_LOOP(type_name, Type) \ do { \ - entity_t *ent; \ int begun = 0; \ - for (ent = r_ent_queue[mod_##type_name]; ent; ent = ent->next) { \ + for (size_t i = 0; i < r_ent_queue->ent_queues[mod_##type_name].size; \ + i++) { \ + entity_t *ent = r_ent_queue->ent_queues[mod_##type_name].a[i]; \ if (!begun) { \ Vulkan_##Type##Begin (rFrame); \ begun = 1; \ @@ -122,7 +125,7 @@ Vulkan_DrawViewModel (vulkan_ctx_t *ctx) || !ent->renderer.model) return; - R_EnqueueEntity (ent); + EntQueue_AddEntity (r_ent_queue, ent, ent->renderer.model->type); } void @@ -195,7 +198,6 @@ Vulkan_NewMap (model_t *worldmodel, struct model_s **models, int num_models, r_viewleaf = NULL; R_MarkLeaves (); - R_FreeAllEntities (); R_ClearParticles (); Vulkan_RegisterTextures (models, num_models, ctx); //Vulkan_BuildLightmaps (models, num_models, ctx); diff --git a/nq/include/client.h b/nq/include/client.h index 6437cf81f..62b24a4d4 100644 --- a/nq/include/client.h +++ b/nq/include/client.h @@ -180,14 +180,9 @@ typedef struct client_state_s { /* information that is static for the entire time connected to a server */ - struct model_s *model_precache[MAX_MODELS]; struct sfx_s *sound_precache[MAX_SOUNDS]; - int nummodels; int numsounds; - struct plitem_s *edicts; - struct plitem_s *worldspawn; - char levelname[40]; // for display on solo scoreboard int spectator; int playernum; @@ -205,9 +200,7 @@ typedef struct client_state_s { int fbskins; // refresh related state - struct model_s *worldmodel; // cl_entitites[0].model int num_entities; // held in cl_entities array - entity_t viewent; // the weapon model int cdtrack; // cd audio @@ -240,10 +233,9 @@ extern struct cvar_s *noskins; extern client_state_t cl; -// FIXME, allocate dynamically -extern entity_t cl_entities[MAX_EDICTS]; +extern entity_t *cl_entities[MAX_EDICTS]; extern double cl_msgtime[MAX_EDICTS]; -extern byte cl_forcelink[MAX_EDICTS]; +extern struct set_s cl_forcelink; extern int fps_count; @@ -299,6 +291,7 @@ void CL_NewTranslation (int slot, struct skin_s *skin); void CL_SignonReply (void); void CL_RelinkEntities (void); void CL_ClearEnts (void); +entity_t *CL_GetEntity (int num); extern double realtime; diff --git a/nq/source/cl_demo.c b/nq/source/cl_demo.c index bdcf684a8..b4d47eebe 100644 --- a/nq/source/cl_demo.c +++ b/nq/source/cl_demo.c @@ -48,6 +48,8 @@ #include "compat.h" +#include "client/world.h" + #include "nq/include/client.h" #include "nq/include/host.h" @@ -338,8 +340,8 @@ demo_default_name (const char *argv1) time (&tim); strftime (timestring, 19, "%Y-%m-%d-%H-%M", localtime (&tim)); - // the leading path-name is to be removed from cl.worldmodel->name - mapname = QFS_SkipPath (cl.worldmodel->path); + // the leading path-name is to be removed from cl_world.worldmodel->name + mapname = QFS_SkipPath (cl_world.worldmodel->path); // the map name is cut off after any "." because this would prevent // an extension being appended diff --git a/nq/source/cl_ents.c b/nq/source/cl_ents.c index 16c590061..a85b46c56 100644 --- a/nq/source/cl_ents.c +++ b/nq/source/cl_ents.c @@ -44,11 +44,13 @@ #include "QF/plugin/vid_render.h" #include "QF/scene/entity.h" +#include "QF/scene/scene.h" #include "compat.h" #include "client/effects.h" #include "client/temp_entities.h" +#include "client/world.h" #include "client/chase.h" @@ -57,9 +59,12 @@ #include "nq/include/host.h" #include "nq/include/server.h" -entity_t cl_entities[MAX_EDICTS]; -double cl_msgtime[MAX_EDICTS]; -byte cl_forcelink[MAX_EDICTS]; +entity_t *cl_entities[MAX_EDICTS]; +double cl_msgtime[MAX_EDICTS]; +static byte forcelink_bytes[SET_SIZE(MAX_EDICTS)]; +#define alloc_forcelink(s) (set_bits_t *)forcelink_bytes +set_t cl_forcelink = SET_STATIC_INIT (MAX_EDICTS, alloc_forcelink); +#undef alloc_forcelink void CL_ClearEnts (void) @@ -67,14 +72,27 @@ CL_ClearEnts (void) size_t i; for (i = 0; i < MAX_EDICTS; i++) { - CL_Init_Entity (cl_entities + i); + if (cl_entities[i]) { + Scene_DestroyEntity (cl_world.scene, cl_entities[i]); + cl_entities[i] = 0; + } } // clear other arrays i = nq_entstates.num_frames * nq_entstates.num_entities; memset (nq_entstates.frame[0], 0, i * sizeof (entity_state_t)); memset (cl_msgtime, 0, sizeof (cl_msgtime)); - memset (cl_forcelink, 0, sizeof (cl_forcelink)); + set_empty (&cl_forcelink); +} + +entity_t * +CL_GetEntity (int num) +{ + if (!cl_entities[num]) { + cl_entities[num] = Scene_CreateEntity (cl_world.scene); + CL_Init_Entity (cl_entities[num]); + } + return cl_entities[num]; } /* @@ -115,12 +133,12 @@ CL_LerpPoint (void) } static void -set_entity_model (entity_t *ent, int modelindex) +set_entity_model (int ent_ind, int modelindex) { - int i = ent - cl_entities; + entity_t *ent = cl_entities[ent_ind]; renderer_t *renderer = &ent->renderer; animation_t *animation = &ent->animation; - renderer->model = cl.model_precache[modelindex]; + renderer->model = cl_world.models.a[modelindex]; // automatic animation (torches, etc) can be either all together // or randomized if (renderer->model) { @@ -130,11 +148,12 @@ set_entity_model (entity_t *ent, int modelindex) animation->syncbase = 0.0; } } else { - cl_forcelink[i] = true; // hack to make null model players work + // hack to make null model players work + SET_ADD (&cl_forcelink, ent_ind); } animation->nolerp = 1; // don't try to lerp when the model has changed - if (i <= cl.maxclients) { - renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, i); + if (ent_ind <= cl.maxclients) { + renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, ent_ind); } } @@ -150,8 +169,6 @@ CL_RelinkEntities (void) int entvalid; int model_flags; - r_data->player_entity = &cl_entities[cl.viewentity]; - // determine partial update time frac = CL_LerpPoint (); @@ -180,7 +197,7 @@ CL_RelinkEntities (void) for (i = 1; i < cl.num_entities; i++) { new = &nq_entstates.frame[0 + cl.frameIndex][i]; old = &nq_entstates.frame[1 - cl.frameIndex][i]; - ent = &cl_entities[i]; + ent = CL_GetEntity (i); renderer = &ent->renderer; animation = &ent->animation; @@ -200,20 +217,24 @@ CL_RelinkEntities (void) continue; } - if (cl_forcelink[i]) + if (SET_TEST_MEMBER (&cl_forcelink, i)) { *old = *new; + } - if (cl_forcelink[i] || new->modelindex != old->modelindex) { + if (SET_TEST_MEMBER (&cl_forcelink, i) + || new->modelindex != old->modelindex) { old->modelindex = new->modelindex; - set_entity_model (ent, new->modelindex); + set_entity_model (i, new->modelindex); } animation->frame = new->frame; - if (cl_forcelink[i] || new->colormap != old->colormap) { + if (SET_TEST_MEMBER (&cl_forcelink, i) + || new->colormap != old->colormap) { old->colormap = new->colormap; renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, new->colormap); } - if (cl_forcelink[i] || new->skinnum != old->skinnum) { + if (SET_TEST_MEMBER (&cl_forcelink, i) + || new->skinnum != old->skinnum) { old->skinnum = new->skinnum; renderer->skinnum = new->skinnum; if (i <= cl.maxclients) { @@ -232,7 +253,7 @@ CL_RelinkEntities (void) model_flags = renderer->model->flags; } - if (cl_forcelink[i]) { + if (SET_TEST_MEMBER (&cl_forcelink, i)) { // The entity was not updated in the last message so move to the // final spot animation->pose1 = animation->pose2 = -1; @@ -242,7 +263,7 @@ CL_RelinkEntities (void) if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); } - r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); + r_funcs->R_AddEfrags (&cl_world.worldmodel->brush, ent); } ent->old_origin = new->origin; } else { @@ -278,10 +299,10 @@ CL_RelinkEntities (void) = Transform_GetWorldPosition (ent->transform); if (!VectorCompare (org, ent->old_origin)) {//FIXME r_funcs->R_RemoveEfrags (ent); - r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); + r_funcs->R_AddEfrags (&cl_world.worldmodel->brush, ent); } } else { - r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); + r_funcs->R_AddEfrags (&cl_world.worldmodel->brush, ent); } } } @@ -303,8 +324,10 @@ CL_RelinkEntities (void) if (model_flags & ~EF_ROTATE) CL_ModelEffects (ent, i, new->glow_color, cl.time); - cl_forcelink[i] = false; + SET_REMOVE (&cl_forcelink, i); } + r_data->player_entity = CL_GetEntity (cl.viewentity); + cl.viewstate.player_entity = CL_GetEntity (cl.viewentity); cl.viewstate.player_origin - = Transform_GetWorldPosition (cl_entities[cl.viewentity].transform); + = Transform_GetWorldPosition (cl.viewstate.player_entity->transform); } diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index 2618706f9..e789b66ac 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -48,14 +48,16 @@ #include "QF/plugin/console.h" #include "QF/plugin/vid_render.h" #include "QF/scene/entity.h" +#include "QF/scene/scene.h" #include "compat.h" #include "sbar.h" +#include "client/chase.h" #include "client/particles.h" #include "client/temp_entities.h" +#include "client/world.h" -#include "client/chase.h" #include "nq/include/cl_skin.h" #include "nq/include/client.h" #include "nq/include/host.h" @@ -188,9 +190,9 @@ CL_ClearState (void) if (!sv.active) Host_ClearMemory (); - if (cl.edicts) - PL_Free (cl.edicts); - + if (cl.viewstate.weapon_entity) { + Scene_DestroyEntity (cl_world.scene, cl.viewstate.weapon_entity); + } if (cl.players) { int i; @@ -202,6 +204,7 @@ CL_ClearState (void) __auto_type cam = cl.viewstate.camera_transform; memset (&cl, 0, sizeof (cl)); cl.viewstate.camera_transform = cam; + cl.viewstate.player_origin = (vec4f_t) {0, 0, 0, 1}; cl.viewstate.chase = 1; cl.viewstate.chasestate = &cl.chasestate; @@ -210,10 +213,6 @@ CL_ClearState (void) r_data->force_fullscreen = 0; r_data->lightstyle = cl.lightstyle; - CL_Init_Entity (&cl.viewent); - cl.viewstate.weapon_entity = &cl.viewent; - r_data->view_model = &cl.viewent; - SZ_Clear (&cls.message); CL_ClearTEnts (); @@ -221,6 +220,10 @@ CL_ClearState (void) r_funcs->R_ClearState (); CL_ClearEnts (); + + cl.viewstate.weapon_entity = Scene_CreateEntity (cl_world.scene); + CL_Init_Entity (cl.viewstate.weapon_entity); + r_data->view_model = cl.viewstate.weapon_entity; } /* @@ -276,7 +279,7 @@ CL_Disconnect (void) Host_ShutdownServer (false); } - cl.worldmodel = NULL; + cl_world.worldmodel = NULL; cl.intermission = 0; cl.viewstate.intermission = 0; } @@ -389,18 +392,18 @@ CL_NextDemo (void) static void pointfile_f (void) { - CL_LoadPointFile (cl.worldmodel); + CL_LoadPointFile (cl_world.worldmodel); } static void CL_PrintEntities_f (void) { - entity_t *ent; int i; - for (i = 0, ent = cl_entities; i < cl.num_entities; i++, ent++) { + for (i = 0; i < cl.num_entities; i++) { + entity_t *ent = cl_entities[i]; Sys_Printf ("%3i:", i); - if (!ent->renderer.model) { + if (!ent || !ent->renderer.model) { Sys_Printf ("EMPTY\n"); continue; } @@ -422,8 +425,8 @@ CL_ReadFromServer (void) { int ret; TEntContext_t tentCtx = { - Transform_GetWorldPosition (cl_entities[cl.viewentity].transform), - cl.worldmodel, cl.viewentity + cl.viewstate.player_origin, + cl.viewentity }; cl.oldtime = cl.time; @@ -571,6 +574,7 @@ CL_Init (cbuf_t *cbuf) CL_Init_Input (cbuf); CL_Particles_Init (); CL_TEnts_Init (); + CL_World_Init (); CL_ClearState (); V_Init (&cl.viewstate); diff --git a/nq/source/cl_parse.c b/nq/source/cl_parse.c index f8e052151..b6bcba5b9 100644 --- a/nq/source/cl_parse.c +++ b/nq/source/cl_parse.c @@ -51,10 +51,13 @@ #include "QF/sound.h" // FIXME: DEFAULT_SOUND_PACKET_* #include "QF/va.h" +#include "QF/scene/scene.h" + #include "QF/plugin/vid_render.h" #include "QF/scene/entity.h" #include "client/temp_entities.h" +#include "client/world.h" #include "compat.h" #include "sbar.h" @@ -125,24 +128,6 @@ const char *svc_strings[] = { dstring_t *centerprint; -static void -CL_LoadSky (void) -{ - plitem_t *item; - const char *name = 0; - - if (!cl.worldspawn) { - r_funcs->R_LoadSkys (0); - return; - } - if ((item = PL_ObjectForKey (cl.worldspawn, "sky")) // Q2/DarkPlaces - || (item = PL_ObjectForKey (cl.worldspawn, "skyname")) // old QF - || (item = PL_ObjectForKey (cl.worldspawn, "qlsky"))) /* QuakeLives */ { - name = PL_String (item); - } - r_funcs->R_LoadSkys (name); -} - /* CL_EntityNum @@ -263,72 +248,13 @@ CL_KeepaliveMessage (void) SZ_Clear (&cls.message); } -static void -map_cfg (const char *mapname, int all) -{ - char *name = malloc (strlen (mapname) + 4 + 1); - cbuf_t *cbuf = Cbuf_New (&id_interp); - QFile *f; - - QFS_StripExtension (mapname, name); - strcat (name, ".cfg"); - f = QFS_FOpenFile (name); - if (f) { - Qclose (f); - Cmd_Exec_File (cbuf, name, 1); - } else { - Cmd_Exec_File (cbuf, "maps_default.cfg", 1); - } - if (all) { - Cbuf_Execute_Stack (cbuf); - } else { - Cbuf_Execute_Sets (cbuf); - } - free (name); - Cbuf_Delete (cbuf); -} - -static plitem_t * -map_ent (const char *mapname) -{ - static progs_t edpr; - char *name = malloc (strlen (mapname) + 4 + 1); - char *buf; - plitem_t *edicts = 0; - QFile *ent_file; - - QFS_StripExtension (mapname, name); - strcat (name, ".ent"); - ent_file = QFS_VOpenFile (name, 0, cl.model_precache[1]->vpath); - if ((buf = (char *) QFS_LoadFile (ent_file, 0))) { - edicts = ED_Parse (&edpr, buf); - free (buf); - } else { - edicts = ED_Parse (&edpr, cl.model_precache[1]->brush.entities); - } - free (name); - return edicts; -} - static void CL_NewMap (const char *mapname) { - r_funcs->R_NewMap (cl.worldmodel, cl.model_precache, cl.nummodels); Con_NewMap (); Hunk_Check (0); // make sure nothing is hurt Sbar_CenterPrint (0); - - if (cl.model_precache[1] && cl.model_precache[1]->brush.entities) { - cl.edicts = map_ent (mapname); - if (cl.edicts) { - cl.worldspawn = PL_ObjectAtIndex (cl.edicts, 0); - CL_LoadSky (); - if (r_funcs->Fog_ParseWorldspawn) - r_funcs->Fog_ParseWorldspawn (cl.worldspawn); - } - } - - map_cfg (mapname, 1); + CL_World_NewMap (mapname, 0); } static void @@ -338,6 +264,7 @@ CL_ParseServerInfo (void) char sound_precache[MAX_SOUNDS][MAX_QPATH]; const char *str; int i; + int nummodels; Sys_MaskPrintf (SYS_dev, "Serverinfo packet received.\n"); @@ -394,16 +321,17 @@ CL_ParseServerInfo (void) // needlessly purge it // precache models - memset (cl.model_precache, 0, sizeof (cl.model_precache)); - for (cl.nummodels = 1;; cl.nummodels++) { + cl_world.models.size = 0; + DARRAY_APPEND (&cl_world.models, 0); // ind 0 is null model + for (nummodels = 1;; nummodels++) { str = MSG_ReadString (net_message); if (!str[0]) break; - if (cl.nummodels >= MAX_MODELS) { + if (nummodels >= MAX_MODELS) { Sys_Printf ("Server sent too many model precaches\n"); goto done; } - strcpy (model_precache[cl.nummodels], str); + strcpy (model_precache[nummodels], str); Mod_TouchModel (str); } @@ -421,12 +349,12 @@ CL_ParseServerInfo (void) } // now we try to load everything else until a cache allocation fails - if (model_precache[1]) - map_cfg (model_precache[1], 0); + CL_MapCfg (model_precache[1]); - for (i = 1; i < cl.nummodels; i++) { - cl.model_precache[i] = Mod_ForName (model_precache[i], false); - if (cl.model_precache[i] == NULL) { + for (i = 1; i < nummodels; i++) { + DARRAY_APPEND (&cl_world.models, + Mod_ForName (model_precache[i], false)); + if (cl_world.models.a[i] == NULL) { Sys_Printf ("Model %s not found\n", model_precache[i]); goto done; } @@ -439,8 +367,8 @@ CL_ParseServerInfo (void) } // local state - cl_entities[0].renderer.model = cl.worldmodel = cl.model_precache[1]; - cl.chasestate.worldmodel = cl.worldmodel; + cl_world.worldmodel = cl_world.models.a[1]; + cl.chasestate.worldmodel = cl_world.worldmodel; if (!centerprint) centerprint = dstring_newstr (); else @@ -600,44 +528,10 @@ CL_ParseUpdate (int bits) //VectorCopy (state->msg_angles[0], state->msg_angles[1]); //CL_TransformEntity (ent, state->msg_angles[0]); //state->forcelink = true; - cl_forcelink[num] = true; + SET_ADD (&cl_forcelink, num); } } -static void -CL_ParseBaseline (entity_state_t *baseline, int version) -{ - int bits = 0; - - if (version == 2) - bits = MSG_ReadByte (net_message); - - if (bits & B_LARGEMODEL) - baseline->modelindex = MSG_ReadShort (net_message); - else - baseline->modelindex = MSG_ReadByte (net_message); - - if (bits & B_LARGEFRAME) - baseline->frame = MSG_ReadShort (net_message); - else - baseline->frame = MSG_ReadByte (net_message); - - baseline->colormap = MSG_ReadByte (net_message); - baseline->skinnum = MSG_ReadByte (net_message); - - MSG_ReadCoordAngleV (net_message, &baseline->origin[0], baseline->angles); - baseline->origin[3] = 1;//FIXME - - if (bits & B_ALPHA) - baseline->alpha = MSG_ReadByte (net_message); - else - baseline->alpha = 255;//FIXME alpha - baseline->scale = 16; - baseline->glow_size = 0; - baseline->glow_color = 254; - baseline->colormod = 255; -} - /* CL_ParseClientdata @@ -723,7 +617,7 @@ CL_ParseClientdata (void) if (cl.stats[STAT_WEAPON] != i) { cl.stats[STAT_WEAPON] = i; Sbar_Changed (); - cl.viewstate.weapon_model = cl.model_precache[cl.stats[STAT_WEAPON]]; + cl.viewstate.weapon_model = cl_world.models.a[cl.stats[STAT_WEAPON]]; } i = (short) MSG_ReadShort (net_message); @@ -779,38 +673,13 @@ CL_ParseClientdata (void) cl.stats[STAT_WEAPONFRAME] |= MSG_ReadByte (net_message) << 8; if (bits & SU_WEAPONALPHA) { byte alpha = MSG_ReadByte (net_message); - cl.viewent.renderer.colormod[3] = ENTALPHA_DECODE (alpha); + float a = ENTALPHA_DECODE (alpha); + cl.viewstate.weapon_entity->renderer.colormod[3] = a; } else { - cl.viewent.renderer.colormod[3] = 1.0; + cl.viewstate.weapon_entity->renderer.colormod[3] = 1; } } -static void -CL_ParseStatic (int version) -{ - entity_state_t baseline; - entity_t *ent; - - ent = r_funcs->R_AllocEntity (); - CL_Init_Entity (ent); - - CL_ParseBaseline (&baseline, version); - - // copy it to the current state - //FIXME alpha & lerp - ent->renderer.model = cl.model_precache[baseline.modelindex]; - ent->animation.frame = baseline.frame; - ent->renderer.skin = 0; - ent->renderer.skinnum = baseline.skinnum; - VectorCopy (ent_colormod[baseline.colormod], ent->renderer.colormod); - ent->renderer.colormod[3] = ENTALPHA_DECODE (baseline.alpha); - - CL_TransformEntity (ent, baseline.scale / 16.0, baseline.angles, - baseline.origin); - - r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); -} - static void CL_ParseStaticSound (int version) { @@ -850,8 +719,8 @@ CL_ParseServerMessage (void) cl.last_servermessage = realtime; TEntContext_t tentCtx = { - Transform_GetWorldPosition (cl_entities[cl.viewentity].transform), - cl.worldmodel, cl.viewentity + cl.viewstate.player_origin, + cl.viewentity }; // if recording demos, copy the message out @@ -921,7 +790,6 @@ CL_ParseServerMessage (void) case svc_setview: cl.viewentity = MSG_ReadShort (net_message); - cl.viewstate.player_entity = &cl_entities[cl.viewentity]; break; case svc_sound: @@ -1035,7 +903,7 @@ CL_ParseServerMessage (void) Host_Error ("CL_ParseServerMessage: svc_updatecolors > " "MAX_SCOREBOARD"); } else { - entity_t *ent = &cl_entities[i+1]; + entity_t *ent = CL_GetEntity (i + 1); byte col = MSG_ReadByte (net_message); byte top = col >> 4; byte bot = col & 0xf; @@ -1061,7 +929,7 @@ CL_ParseServerMessage (void) break; case svc_spawnstatic: - CL_ParseStatic (1); + CL_ParseStatic (net_message, 1); break; // svc_spawnbinary @@ -1069,7 +937,7 @@ CL_ParseServerMessage (void) case svc_spawnbaseline: i = MSG_ReadShort (net_message); // must use CL_EntityNum () to force cl.num_entities up - CL_ParseBaseline (CL_EntityNum (i), 1); + CL_ParseBaseline (net_message, CL_EntityNum (i), 1); break; case svc_temp_entity: @@ -1205,10 +1073,10 @@ CL_ParseServerMessage (void) case svc_spawnbaseline2: i = MSG_ReadShort (net_message); // must use CL_EntityNum() to force cl.num_entities up - CL_ParseBaseline (CL_EntityNum(i), 2); + CL_ParseBaseline (net_message, CL_EntityNum(i), 2); break; case svc_spawnstatic2: - CL_ParseStatic (2); + CL_ParseStatic (net_message, 2); break; case svc_spawnstaticsound2: CL_ParseStaticSound (2); diff --git a/nq/source/cl_screen.c b/nq/source/cl_screen.c index 927608352..7c2a033f7 100644 --- a/nq/source/cl_screen.c +++ b/nq/source/cl_screen.c @@ -51,6 +51,8 @@ #include "sbar.h" +#include "client/world.h" + #include "nq/include/client.h" static view_t *net_view; @@ -75,11 +77,11 @@ SCR_CShift (void) mleaf_t *leaf; int contents = CONTENTS_EMPTY; - if (cls.state == ca_active && cl.worldmodel) { + if (cls.state == ca_active && cl_world.worldmodel) { vec4f_t origin; origin = Transform_GetWorldPosition (cl.viewstate.camera_transform); //FIXME - leaf = Mod_PointInLeaf (&origin[0], cl.worldmodel); + leaf = Mod_PointInLeaf (&origin[0], cl_world.worldmodel); contents = leaf->contents; } V_SetContentsColor (&cl.viewstate, contents); diff --git a/nq/source/host.c b/nq/source/host.c index 9ecc52069..e4007dd37 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -60,6 +60,7 @@ #include "compat.h" #include "client/chase.h" +#include "client/world.h" #include "nq/include/host.h" #include "nq/include/server.h" @@ -612,7 +613,7 @@ Host_ClientFrame (void) vec4f_t origin; origin = Transform_GetWorldPosition (cl.viewstate.camera_transform); - l = Mod_PointInLeaf (&origin[0], cl.worldmodel);//FIXME + l = Mod_PointInLeaf (&origin[0], cl_world.worldmodel);//FIXME if (l) asl = l->ambient_sound_level; S_Update (cl.viewstate.camera_transform, asl); diff --git a/nq/source/host_cmd.c b/nq/source/host_cmd.c index 3c51cb894..e58098241 100644 --- a/nq/source/host_cmd.c +++ b/nq/source/host_cmd.c @@ -50,6 +50,8 @@ #include "QF/sys.h" #include "QF/va.h" +#include "client/world.h" + #include "compat.h" #include "world.h" @@ -1320,7 +1322,7 @@ Host_Viewmodel_f (void) } SVfloat (e, frame) = 0; - cl.model_precache[(int) SVfloat (e, modelindex)] = m; + cl_world.models.a[(int) SVfloat (e, modelindex)] = m; } static void @@ -1333,7 +1335,7 @@ Host_Viewframe_f (void) e = FindViewthing (); if (!e) return; - m = cl.model_precache[(int) SVfloat (e, modelindex)]; + m = cl_world.models.a[(int) SVfloat (e, modelindex)]; f = atoi (Cmd_Argv (1)); if (f >= m->numframes) @@ -1366,7 +1368,7 @@ Host_Viewnext_f (void) e = FindViewthing (); if (!e) return; - m = cl.model_precache[(int) SVfloat (e, modelindex)]; + m = cl_world.models.a[(int) SVfloat (e, modelindex)]; SVfloat (e, frame) = SVfloat (e, frame) + 1; if (SVfloat (e, frame) >= m->numframes) @@ -1385,7 +1387,7 @@ Host_Viewprev_f (void) if (!e) return; - m = cl.model_precache[(int) SVfloat (e, modelindex)]; + m = cl_world.models.a[(int) SVfloat (e, modelindex)]; SVfloat (e, frame) = SVfloat (e, frame) - 1; if (SVfloat (e, frame) < 0) diff --git a/nq/source/sv_ded.c b/nq/source/sv_ded.c index 50dd443d9..d8a0a601e 100644 --- a/nq/source/sv_ded.c +++ b/nq/source/sv_ded.c @@ -36,12 +36,16 @@ #include "QF/plugin/vid_render.h" +#include "client/world.h" + #include "nq/include/host.h" #include "nq/include/server.h" client_state_t cl; client_static_t cls; +worldscene_t cl_world; + cvar_t *cl_name; cvar_t *cl_writecfg; cvar_t *demo_speed; diff --git a/qw/include/cl_ents.h b/qw/include/cl_ents.h index b56e162d9..53ec080f7 100644 --- a/qw/include/cl_ents.h +++ b/qw/include/cl_ents.h @@ -41,12 +41,9 @@ void CL_ParsePacketEntities (qboolean delta); void CL_SetSolidEntities (void); void CL_ParsePlayerinfo (void); void CL_Ents_Init (void); +entity_t *CL_GetEntity (int num); extern struct cvar_s *cl_deadbodyfilter; extern struct cvar_s *cl_gibfilter; -extern entity_t cl_player_ents[]; -extern entity_t cl_flag_ents[]; -extern entity_t cl_packet_ents[]; - #endif diff --git a/qw/include/client.h b/qw/include/client.h index e6410ecaa..6355b1921 100644 --- a/qw/include/client.h +++ b/qw/include/client.h @@ -222,14 +222,10 @@ typedef struct client_state_s { char model_name[MAX_MODELS][MAX_QPATH]; char sound_name[MAX_SOUNDS][MAX_QPATH]; - struct model_s *model_precache[MAX_MODELS]; struct sfx_s *sound_precache[MAX_SOUNDS]; int nummodels; int numsounds; - struct plitem_s *edicts; - struct plitem_s *worldspawn; - char levelname[40]; // for display on solo scoreboard int spectator; int playernum; @@ -247,9 +243,7 @@ typedef struct client_state_s { int fbskins; // refresh related state - struct model_s *worldmodel; // cl_entitites[0].model int num_entities; // held in cl_entities array - entity_t viewent; // the weapon model int cdtrack; // cd audio @@ -288,10 +282,7 @@ extern struct cvar_s *cl_fb_players; extern client_state_t cl; -typedef struct entitystateset_s DARRAY_TYPE (struct entity_state_s) - entitystateset_t; -extern entitystateset_t cl_static_entities; -extern entity_t cl_entities[512]; +extern entity_t *cl_entities[512]; extern byte cl_entity_valid[2][512]; extern qboolean nomaster; diff --git a/qw/source/cl_demo.c b/qw/source/cl_demo.c index d03e7b4b5..2a5069db4 100644 --- a/qw/source/cl_demo.c +++ b/qw/source/cl_demo.c @@ -56,6 +56,8 @@ #include "compat.h" +#include "client/world.h" + #include "qw/include/cl_cam.h" #include "qw/include/cl_demo.h" #include "qw/include/cl_ents.h" @@ -633,8 +635,8 @@ demo_default_name (const char *argv1) time (&tim); strftime (timestring, 19, "%Y-%m-%d-%H-%M", localtime (&tim)); - // the leading path-name is to be removed from cl.worldmodel->name - mapname = QFS_SkipPath (cl.worldmodel->path); + // the leading path-name is to be removed from cl_world.worldmodel->name + mapname = QFS_SkipPath (cl_world.worldmodel->path); // the map name is cut off after any "." because this would prevent // an extension being appended diff --git a/qw/source/cl_entparse.c b/qw/source/cl_entparse.c index a47edb4af..550a8b308 100644 --- a/qw/source/cl_entparse.c +++ b/qw/source/cl_entparse.c @@ -45,6 +45,7 @@ #include "client/temp_entities.h" #include "client/view.h" +#include "client/world.h" #include "qw/msg_ucmd.h" #include "qw/pmove.h" @@ -481,7 +482,7 @@ CL_ParsePlayerinfo (void) byte val; entity_t *ent; - ent = &cl_player_ents[num]; + ent = CL_GetEntity (num + 1); bits = MSG_ReadByte (net_message); if (bits & PF_ALPHA) { val = MSG_ReadByte (net_message); @@ -529,7 +530,7 @@ CL_SetSolidEntities (void) frame_t *frame; packet_entities_t *pak; - pmove.physents[0].model = cl.worldmodel; + pmove.physents[0].model = cl_world.worldmodel; VectorZero (pmove.physents[0].origin); VectorZero (pmove.physents[0].angles); pmove.physents[0].info = 0; @@ -543,17 +544,17 @@ CL_SetSolidEntities (void) if (!state->modelindex) continue; - if (!cl.model_precache[state->modelindex]) + if (!cl_world.models.a[state->modelindex]) continue; - if (cl.model_precache[state->modelindex]->brush.hulls[1].firstclipnode - || cl.model_precache[state->modelindex]->clipbox) { + if (cl_world.models.a[state->modelindex]->brush.hulls[1].firstclipnode + || cl_world.models.a[state->modelindex]->clipbox) { if (pmove.numphysent == MAX_PHYSENTS) { Sys_Printf ("WARNING: entity physent overflow, email " "quakeforge-devel@lists.quakeforge.net\n"); break; } pmove.physents[pmove.numphysent].model = - cl.model_precache[state->modelindex]; + cl_world.models.a[state->modelindex]; VectorCopy (state->origin, pmove.physents[pmove.numphysent].origin); VectorCopy (state->angles, diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index 84bd9ba72..19cc8f9ac 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -42,6 +42,7 @@ #include "QF/sys.h" #include "QF/scene/entity.h" +#include "QF/scene/scene.h" #include "compat.h" #include "d_iface.h" @@ -50,6 +51,7 @@ #include "client/locs.h" #include "client/temp_entities.h" #include "client/view.h" +#include "client/world.h" #include "qw/bothdefs.h" #include "qw/msg_ucmd.h" @@ -62,9 +64,8 @@ #include "qw/include/cl_pred.h" #include "qw/include/host.h" -entity_t cl_player_ents[MAX_CLIENTS]; -entity_t cl_flag_ents[MAX_CLIENTS]; -entity_t cl_entities[512]; // FIXME: magic number +entity_t *cl_flag_ents[MAX_CLIENTS]; +entity_t *cl_entities[512]; // FIXME: magic number byte cl_entity_valid[2][512]; void @@ -72,15 +73,32 @@ CL_ClearEnts (void) { size_t i; + for (i = 0; i < MAX_CLIENTS; i++) { + if (cl_flag_ents[i]) { + Scene_DestroyEntity (cl_world.scene, cl_flag_ents[i]); + cl_flag_ents[i] = 0; + } + } + + for (i = 0; i < 512; i++) { + if (cl_entities[i]) { + Scene_DestroyEntity (cl_world.scene, cl_entities[i]); + cl_entities[i] = 0; + } + } i = qw_entstates.num_frames * qw_entstates.num_entities; memset (qw_entstates.frame[0], 0, i * sizeof (entity_state_t)); memset (cl_entity_valid, 0, sizeof (cl_entity_valid)); - for (i = 0; i < sizeof (cl_entities) / sizeof (cl_entities[0]); i++) - CL_Init_Entity (&cl_entities[i]); - for (i = 0; i < sizeof (cl_flag_ents) / sizeof (cl_flag_ents[0]); i++) - CL_Init_Entity (&cl_flag_ents[i]); - for (i = 0; i < sizeof (cl_player_ents) / sizeof (cl_player_ents[0]); i++) - CL_Init_Entity (&cl_player_ents[i]); +} + +entity_t * +CL_GetEntity (int num) +{ + if (!cl_entities[num]) { + cl_entities[num] = Scene_CreateEntity (cl_world.scene); + CL_Init_Entity (cl_entities[num]); + } + return cl_entities[num]; } // Hack hack hack @@ -110,7 +128,7 @@ set_entity_model (entity_t *ent, int modelindex) { renderer_t *renderer = &ent->renderer; animation_t *animation = &ent->animation; - renderer->model = cl.model_precache[modelindex]; + renderer->model = cl_world.models.a[modelindex]; // automatic animation (torches, etc) can be either all together // or randomized if (renderer->model) { @@ -134,10 +152,10 @@ CL_LinkPacketEntities (void) animation_t *animation; frac = 1; - for (i = 0; i < 512; i++) { + for (i = MAX_CLIENTS + 1; i < 512; i++) { new = &qw_entstates.frame[cl.link_sequence & UPDATE_MASK][i]; old = &qw_entstates.frame[cl.prev_sequence & UPDATE_MASK][i]; - ent = &cl_entities[i]; + ent = CL_GetEntity (i); renderer = &ent->renderer; animation = &ent->animation; forcelink = cl_entity_valid[0][i] != cl_entity_valid[1][i]; @@ -216,7 +234,7 @@ CL_LinkPacketEntities (void) if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); } - r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); + r_funcs->R_AddEfrags (&cl_world.worldmodel->brush, ent); } } else { vec4f_t delta = new->origin - old->origin; @@ -248,15 +266,15 @@ CL_LinkPacketEntities (void) = Transform_GetWorldPosition (ent->transform); if (!VectorCompare (org, ent->old_origin)) {//FIXME r_funcs->R_RemoveEfrags (ent); - r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); + r_funcs->R_AddEfrags (&cl_world.worldmodel->brush, ent); } } else { - r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); + r_funcs->R_AddEfrags (&cl_world.worldmodel->brush, ent); } } } if (!ent->visibility.efrag) { - r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); + r_funcs->R_AddEfrags (&cl_world.worldmodel->brush, ent); } // rotate binary objects locally @@ -288,7 +306,7 @@ CL_UpdateFlagModels (entity_t *ent, int key) float f; entity_t *fent; - fent = &cl_flag_ents[key]; + fent = cl_flag_ents[key]; if (!fent->active) { return; @@ -322,7 +340,7 @@ CL_AddFlagModels (entity_t *ent, int team, int key) { entity_t *fent; - fent = &cl_flag_ents[key]; + fent = cl_flag_ents[key]; if (cl_flagindex == -1) { fent->active = 0; @@ -336,7 +354,7 @@ CL_AddFlagModels (entity_t *ent, int team, int key) } CL_UpdateFlagModels (ent, key); - fent->renderer.model = cl.model_precache[cl_flagindex]; + fent->renderer.model = cl_world.models.a[cl_flagindex]; fent->renderer.skinnum = team; return fent; @@ -347,7 +365,7 @@ CL_RemoveFlagModels (int key) { entity_t *fent; - fent = &cl_flag_ents[key]; + fent = cl_flag_ents[key]; fent->active = 0; Transform_SetParent (fent->transform, 0); } @@ -380,7 +398,7 @@ CL_LinkPlayers (void) for (j = 0, player = cl.players, state = frame->playerstate; j < MAX_CLIENTS; j++, player++, state++) { - ent = &cl_player_ents[j]; + ent = CL_GetEntity (j + 1); if (ent->visibility.efrag) r_funcs->R_RemoveEfrags (ent); if (player->flag_ent && player->flag_ent->visibility.efrag) { @@ -395,7 +413,8 @@ CL_LinkPlayers (void) // spawn light flashes, even ones coming from invisible objects if (j == cl.playernum) { org = cl.viewstate.player_origin; - r_data->player_entity = &cl_player_ents[j]; + r_data->player_entity = ent; + cl.viewstate.player_entity = ent; clientplayer = true; } else { org = state->pls.es.origin; @@ -453,8 +472,8 @@ CL_LinkPlayers (void) ang[ROLL] = V_CalcRoll (ang, state->pls.es.velocity) * 4.0; if (ent->renderer.model - != cl.model_precache[state->pls.es.modelindex]) { - ent->renderer.model = cl.model_precache[state->pls.es.modelindex]; + != cl_world.models.a[state->pls.es.modelindex]) { + ent->renderer.model = cl_world.models.a[state->pls.es.modelindex]; ent->animation.nolerp = 1; } ent->animation.frame = state->pls.es.frame; @@ -492,10 +511,10 @@ CL_LinkPlayers (void) } // stuff entity in map - r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); + r_funcs->R_AddEfrags (&cl_world.worldmodel->brush, ent); if (player->flag_ent) { CL_UpdateFlagModels (ent, j); - r_funcs->R_AddEfrags (&cl.worldmodel->brush, player->flag_ent); + r_funcs->R_AddEfrags (&cl_world.worldmodel->brush, player->flag_ent); } } } @@ -516,7 +535,7 @@ CL_EmitEntities (void) return; TEntContext_t tentCtx = { - cl.viewstate.player_origin, cl.worldmodel, cl.viewentity + cl.viewstate.player_origin, cl.viewentity }; CL_LinkPlayers (); @@ -530,5 +549,4 @@ CL_EmitEntities (void) void CL_Ents_Init (void) { - r_data->view_model = &cl.viewent; } diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index 3724a5a41..6b4bb9f18 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -91,6 +91,7 @@ #include "QF/plugin/console.h" #include "QF/scene/transform.h" +#include "QF/scene/scene.h" #include "buildnum.h" #include "compat.h" @@ -99,6 +100,7 @@ #include "client/particles.h" #include "client/temp_entities.h" #include "client/view.h" +#include "client/world.h" #include "qw/bothdefs.h" #include "qw/pmove.h" @@ -229,7 +231,7 @@ CL_Quit_f (void) static void pointfile_f (void) { - CL_LoadPointFile (cl.worldmodel); + CL_LoadPointFile (cl_world.worldmodel); } static void @@ -385,6 +387,9 @@ CL_ClearState (void) S_StopAllSounds (); + if (cl.viewstate.weapon_entity) { + Scene_DestroyEntity (cl_world.scene, cl.viewstate.weapon_entity); + } // wipe the entire cl structure if (cl.serverinfo) Info_Destroy (cl.serverinfo); @@ -402,7 +407,6 @@ CL_ClearState (void) cl.chasestate.viewstate = &cl.viewstate; cl.viewstate.punchangle = (vec4f_t) {0, 0, 0, 1}; - // Note: we should probably hack around this and give diff values for // diff gamedirs cl.fpd = FPD_DEFAULT; @@ -412,9 +416,6 @@ CL_ClearState (void) cl.frames[i].packet_entities.entities = qw_entstates.frame[i]; cl.serverinfo = Info_ParseString ("", MAX_INFO_STRING, 0); - CL_Init_Entity (&cl.viewent); - cl.viewstate.weapon_entity = &cl.viewent; - Sys_MaskPrintf (SYS_dev, "Clearing memory\n"); VID_ClearMemory (); Mod_ClearAll (); @@ -424,6 +425,10 @@ CL_ClearState (void) CL_ClearEnts (); CL_ClearTEnts (); + cl.viewstate.weapon_entity = Scene_CreateEntity (cl_world.scene); + CL_Init_Entity (cl.viewstate.weapon_entity); + r_data->view_model = cl.viewstate.weapon_entity; + r_funcs->R_ClearState (); SZ_Clear (&cls.netchan.message); @@ -519,7 +524,7 @@ CL_Disconnect (void) Info_Destroy (cl.players[i].userinfo); memset (&cl.players[i], 0, sizeof (cl.players[i])); } - cl.worldmodel = NULL; + cl_world.worldmodel = NULL; cl.validsequence = 0; } @@ -1216,6 +1221,7 @@ CL_Init (void) CL_Ents_Init (); CL_Particles_Init (); CL_TEnts_Init (); + CL_World_Init (); CL_ClearState (); Pmove_Init (); @@ -1725,7 +1731,7 @@ Host_Frame (float time) vec4f_t origin; origin = Transform_GetWorldPosition (cl.viewstate.camera_transform); - l = Mod_PointInLeaf (&origin[0], cl.worldmodel);//FIXME + l = Mod_PointInLeaf (&origin[0], cl_world.worldmodel);//FIXME if (l) asl = l->ambient_sound_level; S_Update (cl.viewstate.camera_transform, asl); diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index e73c7ad3d..e585dbc48 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -61,12 +61,15 @@ #include "QF/teamplay.h" #include "QF/va.h" +#include "QF/scene/scene.h" + #include "compat.h" #include "sbar.h" #include "client/effects.h" #include "client/temp_entities.h" #include "client/view.h" +#include "client/world.h" #include "qw/bothdefs.h" #include "qw/pmove.h" @@ -170,40 +173,6 @@ int packet_latency[NET_TIMINGS]; extern cvar_t *hud_scoreboard_uid; -entitystateset_t cl_static_entities = DARRAY_STATIC_INIT (32); - -static void -CL_LoadSky (void) -{ - plitem_t *item; - const char *name = 0; - static const char *sky_keys[] = { - "sky", // Q2/DarkPlaces - "skyname", // old QF - "qlsky", // QuakeLives - 0 - }; - - // R_LoadSkys does the right thing with null pointers. - if (cl.serverinfo) { - name = Info_ValueForKey (cl.serverinfo, "sky"); - } - - if (!name) { - if (!cl.worldspawn) { - r_funcs->R_LoadSkys (0); - return; - } - for (const char **key = sky_keys; *key; key++) { - if ((item = PL_ObjectForKey (cl.worldspawn, *key))) { - name = PL_String (item); - break; - } - } - } - r_funcs->R_LoadSkys (name); -} - int CL_CalcNet (void) { @@ -290,49 +259,20 @@ CL_CheckOrDownloadFile (const char *filename) return false; } -static plitem_t * -map_ent (const char *mapname) -{ - static progs_t edpr; - char *name = malloc (strlen (mapname) + 4 + 1); - char *buf; - plitem_t *edicts = 0; - QFile *ent_file; - - QFS_StripExtension (mapname, name); - strcat (name, ".ent"); - ent_file = QFS_VOpenFile (name, 0, cl.model_precache[1]->vpath); - if ((buf = (char *) QFS_LoadFile (ent_file, 0))) { - edicts = ED_Parse (&edpr, buf); - free (buf); - } else { - edicts = ED_Parse (&edpr, cl.model_precache[1]->brush.entities); - } - free (name); - return edicts; -} - static void CL_NewMap (const char *mapname) { - cl_static_entities.size = 0; - r_funcs->R_NewMap (cl.worldmodel, cl.model_precache, cl.nummodels); Team_NewMap (); Con_NewMap (); Hunk_Check (0); // make sure nothing is hurt Sbar_CenterPrint (0); - if (cl.model_precache[1] && cl.model_precache[1]->brush.entities) { - cl.edicts = map_ent (mapname); - if (cl.edicts) { - cl.worldspawn = PL_ObjectAtIndex (cl.edicts, 0); - CL_LoadSky (); - if (r_funcs->Fog_ParseWorldspawn) - r_funcs->Fog_ParseWorldspawn (cl.worldspawn); - } + const char *skyname = 0; + // R_LoadSkys does the right thing with null pointers. + if (cl.serverinfo) { + skyname = Info_ValueForKey (cl.serverinfo, "sky"); } - - map_cfg (mapname, 1); + CL_World_NewMap (mapname, skyname); } static void @@ -357,7 +297,7 @@ Model_NextDownload (void) } if (cl.model_name[1]) - map_cfg (cl.model_name[1], 0); + CL_MapCfg (cl.model_name[1]); for (i = 1; i < cl.nummodels; i++) { const char *info_key = 0; @@ -365,9 +305,10 @@ Model_NextDownload (void) if (!cl.model_name[i][0]) break; - cl.model_precache[i] = Mod_ForName (cl.model_name[i], false); + DARRAY_APPEND (&cl_world.models, + Mod_ForName (cl.model_name[i], false)); - if (!cl.model_precache[i]) { + if (!cl_world.models.a[i]) { Sys_Printf ("\nThe required model file '%s' could not be found or " "downloaded.\n\n", cl.model_name[i]); Sys_Printf ("You may need to download or purchase a %s client " @@ -378,18 +319,18 @@ Model_NextDownload (void) } if (strequal (cl.model_name[i], "progs/player.mdl") - && cl.model_precache[i]->type == mod_alias) { + && cl_world.models.a[i]->type == mod_alias) { info_key = pmodel_name; - //XXX mod_funcs->Skin_Player_Model (cl.model_precache[i]); + //XXX mod_funcs->Skin_Player_Model (cl_world.models.a[i]); } if (strequal (cl.model_name[i], "progs/eyes.mdl") - && cl.model_precache[i]->type == mod_alias) + && cl_world.models.a[i]->type == mod_alias) info_key = emodel_name; if (info_key && cl_model_crcs->int_val) { - aliashdr_t *ahdr = cl.model_precache[i]->aliashdr; + aliashdr_t *ahdr = cl_world.models.a[i]->aliashdr; if (!ahdr) - ahdr = Cache_Get (&cl.model_precache[i]->cache); + ahdr = Cache_Get (&cl_world.models.a[i]->cache); Info_SetValueForKey (cls.userinfo, info_key, va (0, "%d", ahdr->crc), 0); @@ -398,14 +339,14 @@ Model_NextDownload (void) SZ_Print (&cls.netchan.message, va (0, "setinfo %s %d", info_key, ahdr->crc)); } - if (!cl.model_precache[i]->aliashdr) - Cache_Release (&cl.model_precache[i]->cache); + if (!cl_world.models.a[i]->aliashdr) + Cache_Release (&cl_world.models.a[i]->cache); } } // Something went wrong (probably in the server, probably a TF server) // We need to disconnect gracefully. - if (!cl.model_precache[1]) { + if (!cl_world.models.a[1]) { Sys_Printf ("\nThe server has failed to provide the map name.\n\n"); Sys_Printf ("Disconnecting to prevent a crash.\n\n"); CL_Disconnect (); @@ -413,8 +354,8 @@ Model_NextDownload (void) } // all done - cl.worldmodel = cl.model_precache[1]; - cl.chasestate.worldmodel = cl.worldmodel; + cl_world.worldmodel = cl_world.models.a[1]; + cl.chasestate.worldmodel = cl_world.worldmodel; CL_NewMap (cl.model_name[1]); // done with modellist, request first of static signon messages @@ -422,7 +363,7 @@ Model_NextDownload (void) MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, va (0, prespawn_name, cl.servercount, - cl.worldmodel->brush.checksum2)); + cl_world.worldmodel->brush.checksum2)); } } @@ -453,7 +394,8 @@ Sound_NextDownload (void) } // done with sounds, request models now - memset (cl.model_precache, 0, sizeof (cl.model_precache)); + cl_world.models.size = 0; + DARRAY_APPEND (&cl_world.models, 0);// ind 0 is null model cl_playerindex = -1; cl_flagindex = -1; cl_h_playerindex = -1; @@ -832,7 +774,6 @@ CL_ParseServerData (void) } cl.viewentity = cl.playernum + 1; - cl.viewstate.player_entity = &cl_entities[cl.viewentity]; cl.viewstate.bob_enabled = !cl.spectator; // get the full level name @@ -957,54 +898,6 @@ CL_ParseModellist (void) Model_NextDownload (); } -static void -CL_ParseBaseline (entity_state_t *es) -{ - es->modelindex = MSG_ReadByte (net_message); - es->frame = MSG_ReadByte (net_message); - es->colormap = MSG_ReadByte (net_message); - es->skinnum = MSG_ReadByte (net_message); - - MSG_ReadCoordAngleV (net_message, &es->origin[0], es->angles);//FIXME - es->origin[3] = 1; - - // LordHavoc: set up baseline to for new effects (alpha, colormod, etc) - es->colormod = 255; - es->alpha = 255; - es->scale = 16; - es->glow_size = 0; - es->glow_color = 254; -} - -/* - CL_ParseStatic - - Static entities are non-interactive world objects - like torches -*/ -static void -CL_ParseStatic (void) -{ - entity_t *ent; - entity_state_t es; - - CL_ParseBaseline (&es); - - ent = r_funcs->R_AllocEntity (); - CL_Init_Entity (ent); - - DARRAY_APPEND (&cl_static_entities, es); - - // copy it to the current state - ent->renderer.model = cl.model_precache[es.modelindex]; - ent->animation.frame = es.frame; - ent->renderer.skinnum = es.skinnum; - - CL_TransformEntity (ent, es.scale / 16.0, es.angles, es.origin); - - r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); -} - static void CL_ParseStaticSound (void) { @@ -1275,7 +1168,7 @@ CL_SetStat (int stat, int value) break; } cl.stats[stat] = value; - cl.viewstate.weapon_model = cl.model_precache[cl.stats[STAT_WEAPON]]; + cl.viewstate.weapon_model = cl_world.models.a[cl.stats[STAT_WEAPON]]; } static void @@ -1318,7 +1211,7 @@ CL_ParseServerMessage (void) const char *str; static dstring_t *stuffbuf; TEntContext_t tentCtx = { - cl.viewstate.player_origin, cl.worldmodel, cl.viewentity + cl.viewstate.player_origin, cl.viewentity }; received_framecount = host_framecount; @@ -1513,14 +1406,14 @@ CL_ParseServerMessage (void) break; case svc_spawnstatic: - CL_ParseStatic (); + CL_ParseStatic (net_message, 1); break; // svc_spawnbinary case svc_spawnbaseline: i = MSG_ReadShort (net_message); - CL_ParseBaseline (&qw_entstates.baseline[i]); + CL_ParseBaseline (net_message, &qw_entstates.baseline[i], 1); break; case svc_temp_entity: diff --git a/qw/source/cl_screen.c b/qw/source/cl_screen.c index 3bdef1963..5e3978e5b 100644 --- a/qw/source/cl_screen.c +++ b/qw/source/cl_screen.c @@ -51,6 +51,7 @@ #include "client/hud.h" #include "client/view.h" +#include "client/world.h" #include "qw/include/client.h" #include "qw/include/cl_parse.h" @@ -77,11 +78,11 @@ SCR_CShift (void) mleaf_t *leaf; int contents = CONTENTS_EMPTY; - if (cls.state == ca_active && cl.worldmodel) { + if (cls.state == ca_active && cl_world.worldmodel) { vec4f_t origin; origin = Transform_GetWorldPosition (cl.viewstate.camera_transform); //FIXME - leaf = Mod_PointInLeaf (&origin[0], cl.worldmodel); + leaf = Mod_PointInLeaf (&origin[0], cl_world.worldmodel); contents = leaf->contents; } V_SetContentsColor (&cl.viewstate, contents); diff --git a/qw/source/sbar.c b/qw/source/sbar.c index 6f60de764..3cf903cf7 100644 --- a/qw/source/sbar.c +++ b/qw/source/sbar.c @@ -58,6 +58,7 @@ #include "compat.h" #include "client/hud.h" +#include "client/world.h" #include "qw/bothdefs.h" #include "qw/include/cl_cam.h" @@ -1109,8 +1110,8 @@ Sbar_LogFrags (void) if (t) Qwrite (file, t, strlen (t)); - Qprintf (file, "%s\n%s %s\n", cls.servername->str, cl.worldmodel->path, - cl.levelname); + Qprintf (file, "%s\n%s %s\n", cls.servername->str, + cl_world.worldmodel->path, cl.levelname); // scores Sbar_SortFrags (true); diff --git a/qw/source/teamplay.c b/qw/source/teamplay.c index 3bc9894f5..731ac279a 100644 --- a/qw/source/teamplay.c +++ b/qw/source/teamplay.c @@ -52,6 +52,7 @@ #include "compat.h" #include "client/locs.h" +#include "client/world.h" #include "qw/bothdefs.h" #include "qw/include/cl_input.h" @@ -289,8 +290,8 @@ Team_NewMap (void) died = false; recorded_location = false; - mapname = strdup (cl.worldmodel->path); - t2 = malloc (sizeof (cl.worldmodel->path)); + mapname = strdup (cl_world.worldmodel->path); + t2 = malloc (sizeof (cl_world.worldmodel->path)); if (!mapname || !t2) Sys_Error ("Can't duplicate mapname!"); map_to_loc (mapname,t2); @@ -340,16 +341,16 @@ locs_loc (void) "parameter\n"); return; } - if (!cl.worldmodel) { + if (!cl_world.worldmodel) { Sys_Printf ("No map loaded. Unable to work with location markers.\n"); return; } if (Cmd_Argc () >= 3) desc = Cmd_Args (2); - mapname = malloc (sizeof (cl.worldmodel->path)); + mapname = malloc (sizeof (cl_world.worldmodel->path)); if (!mapname) Sys_Error ("Can't duplicate mapname!"); - map_to_loc (cl.worldmodel->path, mapname); + map_to_loc (cl_world.worldmodel->path, mapname); snprintf (locfile, sizeof (locfile), "%s/%s", qfs_gamedir->dir.def, mapname); free (mapname);