mirror of
https://github.com/w23/xash3d-fwgs
synced 2024-12-14 13:10:09 +01:00
vk: patch func_wall ents by their index, not model name
Note that referencing them by ent->index inside the engine is not possible, as this index is not stable enough.
This commit is contained in:
parent
ca2a794341
commit
d7660cf358
@ -853,7 +853,7 @@ void R_VkBrushModelCollectEmissiveSurfaces( const struct model_s *mod, qboolean
|
||||
polylight.dynamic = true;
|
||||
matrix3x4 m;
|
||||
Matrix3x4_LoadIdentity(m);
|
||||
Matrix3x4_SetOrigin(m, func_wall->offset[0], func_wall->offset[1], func_wall->offset[2]);
|
||||
Matrix3x4_SetOrigin(m, func_wall->origin[0], func_wall->origin[1], func_wall->origin[2]);
|
||||
polylight.transform_row = &m;
|
||||
}
|
||||
|
||||
|
@ -299,6 +299,10 @@ static void addLightEntity( const entity_props_t *props, unsigned have_fields )
|
||||
fillLightFromProps(le, props, have_fields, false, g_map_entities.entity_count);
|
||||
|
||||
le->entity_index = g_map_entities.entity_count;
|
||||
g_map_entities.refs[g_map_entities.entity_count] = (xvk_mapent_ref_t){
|
||||
.class = props->classname,
|
||||
.index = g_map_entities.num_lights,
|
||||
};
|
||||
g_map_entities.num_lights++;
|
||||
}
|
||||
|
||||
@ -316,25 +320,35 @@ static void addTargetEntity( const entity_props_t *props ) {
|
||||
Q_strcpy(target->targetname, props->targetname);
|
||||
VectorCopy(props->origin, target->origin);
|
||||
|
||||
g_map_entities.refs[g_map_entities.entity_count] = (xvk_mapent_ref_t){
|
||||
.class = Xvk_Target,
|
||||
.index = g_map_entities.num_targets,
|
||||
};
|
||||
|
||||
++g_map_entities.num_targets;
|
||||
}
|
||||
|
||||
static void readWorldspawn( const entity_props_t *props ) {
|
||||
Q_strcpy(g_map_entities.wadlist, props->wad);
|
||||
g_map_entities.refs[g_map_entities.entity_count] = (xvk_mapent_ref_t){
|
||||
.class = Worldspawn,
|
||||
.index = -1,
|
||||
};
|
||||
}
|
||||
|
||||
static void readFuncWall( const entity_props_t *const props, uint32_t have_fields, int props_count ) {
|
||||
gEngine.Con_Reportf("func_wall entity model=\"%s\", props_count=%d\n", (have_fields & Field_model) ? props->model : "N/A", props_count);
|
||||
gEngine.Con_Reportf("func_wall entity=%d model=\"%s\", props_count=%d\n", g_map_entities.entity_count, (have_fields & Field_model) ? props->model : "N/A", props_count);
|
||||
|
||||
if (g_map_entities.func_walls_count >= MAX_FUNC_WALL_ENTITIES) {
|
||||
gEngine.Con_Printf(S_ERROR "Too many func_wall entities, max supported = %d\n", MAX_FUNC_WALL_ENTITIES);
|
||||
return;
|
||||
}
|
||||
|
||||
xvk_mapent_func_wall_t *const e = g_map_entities.func_walls + (g_map_entities.func_walls_count++);
|
||||
xvk_mapent_func_wall_t *const e = g_map_entities.func_walls + g_map_entities.func_walls_count;
|
||||
|
||||
*e = (xvk_mapent_func_wall_t){0};
|
||||
|
||||
/* NOTE: not used
|
||||
e->rendercolor.r = 255;
|
||||
e->rendercolor.g = 255;
|
||||
e->rendercolor.b = 255;
|
||||
@ -355,8 +369,14 @@ static void readFuncWall( const entity_props_t *const props, uint32_t have_field
|
||||
e->rendercolor.g = props->rendercolor[1];
|
||||
e->rendercolor.b = props->rendercolor[2];
|
||||
}
|
||||
*/
|
||||
|
||||
e->entity_index = g_map_entities.entity_count;
|
||||
g_map_entities.refs[g_map_entities.entity_count] = (xvk_mapent_ref_t){
|
||||
.class = FuncWall,
|
||||
.index = g_map_entities.func_walls_count,
|
||||
};
|
||||
++g_map_entities.func_walls_count;
|
||||
}
|
||||
|
||||
static void addPatchSurface( const entity_props_t *props, uint32_t have_fields ) {
|
||||
@ -443,47 +463,62 @@ static void addPatchSurface( const entity_props_t *props, uint32_t have_fields )
|
||||
}
|
||||
}
|
||||
|
||||
int findLightEntityWithIndex( int index ) {
|
||||
// TODO could do binary search (entities are sorted by index) but why
|
||||
for (int i = 0; i < g_map_entities.num_lights; ++i) {
|
||||
if (g_map_entities.lights[i].entity_index == index)
|
||||
return i;
|
||||
}
|
||||
static void patchLightEntity( const entity_props_t *props, int ent_id, uint32_t have_fields, int index ) {
|
||||
ASSERT(index >= 0);
|
||||
ASSERT(index < g_map_entities.num_lights);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void addPatchLightEntity( const entity_props_t *props, uint32_t have_fields ) {
|
||||
for (int i = 0; i < props->_xvk_ent_id.num; ++i) {
|
||||
const int ent_id = props->_xvk_ent_id.values[i];
|
||||
const int light_index = findLightEntityWithIndex( ent_id );
|
||||
if (light_index < 0) {
|
||||
gEngine.Con_Printf(S_ERROR "Patch light entity with index=%d not found\n", ent_id);
|
||||
continue;
|
||||
}
|
||||
vk_light_entity_t *const light = g_map_entities.lights + index;
|
||||
|
||||
if (have_fields == Field__xvk_ent_id) {
|
||||
gEngine.Con_Reportf("Deleting light entity (%d of %d) with index=%d\n", light_index, g_map_entities.num_lights, ent_id);
|
||||
g_map_entities.num_lights--;
|
||||
memmove(g_map_entities.lights + light_index, g_map_entities.lights + light_index + 1, sizeof(*g_map_entities.lights) * g_map_entities.num_lights - light_index);
|
||||
gEngine.Con_Reportf("Deleting light entity (%d of %d) with index=%d\n", index, g_map_entities.num_lights, ent_id);
|
||||
|
||||
// Mark it as deleted
|
||||
light->entity_index = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
fillLightFromProps(light, props, have_fields, true, ent_id);
|
||||
}
|
||||
|
||||
static void patchFuncWallEntity( const entity_props_t *props, uint32_t have_fields, int index ) {
|
||||
ASSERT(index >= 0);
|
||||
ASSERT(index < g_map_entities.func_walls_count);
|
||||
xvk_mapent_func_wall_t *const fw = g_map_entities.func_walls + index;
|
||||
|
||||
if (have_fields & Field_origin)
|
||||
VectorCopy(props->origin, fw->origin);
|
||||
|
||||
gEngine.Con_Reportf("Patching ent=%d func_wall=%d %f %f %f\n", fw->entity_index, index, fw->origin[0], fw->origin[1], fw->origin[2]);
|
||||
}
|
||||
|
||||
static void patchEntity( const entity_props_t *props, uint32_t have_fields ) {
|
||||
ASSERT(have_fields & Field__xvk_ent_id);
|
||||
|
||||
for (int i = 0; i < props->_xvk_ent_id.num; ++i) {
|
||||
const int ei = props->_xvk_ent_id.values[i];
|
||||
if (ei < 0 || ei >= g_map_entities.entity_count) {
|
||||
gEngine.Con_Printf(S_ERROR "_xvk_ent_id value %d is out of bounds, max=%d\n", ei, g_map_entities.entity_count);
|
||||
continue;
|
||||
}
|
||||
|
||||
fillLightFromProps(g_map_entities.lights + light_index, props, have_fields, true, props->_xvk_ent_id.values[i]);
|
||||
const xvk_mapent_ref_t *const ref = g_map_entities.refs + ei;
|
||||
switch (ref->class) {
|
||||
case Light:
|
||||
case LightSpot:
|
||||
case LightEnvironment:
|
||||
patchLightEntity(props, ei, have_fields, ref->index);
|
||||
break;
|
||||
case FuncWall:
|
||||
patchFuncWallEntity(props, have_fields, ref->index);
|
||||
break;
|
||||
default:
|
||||
gEngine.Con_Printf(S_WARN "vk_mapents: trying to patch unsupported entity %d class %d\n", ei, ref->class);
|
||||
}
|
||||
}
|
||||
|
||||
static void patchFuncWallEntity( const entity_props_t *props ) {
|
||||
for (int i = 0; i < g_map_entities.func_walls_count; ++i) {
|
||||
xvk_mapent_func_wall_t *const fw = g_map_entities.func_walls + i;
|
||||
if (Q_strcmp(props->model, fw->model) != 0)
|
||||
continue;
|
||||
|
||||
VectorCopy(props->_xvk_offset, fw->offset);
|
||||
}
|
||||
}
|
||||
|
||||
static void parseEntities( char *string ) {
|
||||
static void parseEntities( char *string, qboolean is_patch ) {
|
||||
unsigned have_fields = 0;
|
||||
int props_count = 0;
|
||||
entity_props_t values;
|
||||
@ -502,6 +537,10 @@ static void parseEntities( char *string ) {
|
||||
have_fields = None;
|
||||
values = (entity_props_t){0};
|
||||
props_count = 0;
|
||||
g_map_entities.refs[g_map_entities.entity_count] = (xvk_mapent_ref_t){
|
||||
.class = Unknown,
|
||||
.index = -1,
|
||||
};
|
||||
continue;
|
||||
} else if (key[0] == '}') {
|
||||
const int target_fields = Field_targetname | Field_origin;
|
||||
@ -523,20 +562,25 @@ static void parseEntities( char *string ) {
|
||||
break;
|
||||
|
||||
case Unknown:
|
||||
if (is_patch) {
|
||||
if (have_fields & Field__xvk_surface_id) {
|
||||
addPatchSurface( &values, have_fields );
|
||||
} else if (have_fields & Field__xvk_ent_id) {
|
||||
addPatchLightEntity( &values, have_fields );
|
||||
} else if ((have_fields & Field__xvk_offset) && (have_fields & Field_model)) {
|
||||
patchFuncWallEntity( &values );
|
||||
patchEntity( &values, have_fields );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Ignored:
|
||||
case Xvk_Target:
|
||||
// Skip
|
||||
break;
|
||||
}
|
||||
|
||||
g_map_entities.entity_count++;
|
||||
if (g_map_entities.entity_count == MAX_MAP_ENTITIES) {
|
||||
gEngine.Con_Printf(S_ERROR "vk_mapents: too many entities, skipping the rest");\
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -615,7 +659,7 @@ static void parsePatches( const model_t *const map ) {
|
||||
return;
|
||||
}
|
||||
|
||||
parseEntities( (char*)data );
|
||||
parseEntities( (char*)data, true );
|
||||
Mem_Free(data);
|
||||
}
|
||||
|
||||
@ -630,7 +674,7 @@ void XVK_ParseMapEntities( void ) {
|
||||
g_map_entities.entity_count = 0;
|
||||
g_map_entities.func_walls_count = 0;
|
||||
|
||||
parseEntities( map->entities );
|
||||
parseEntities( map->entities, false );
|
||||
orientSpotlights();
|
||||
}
|
||||
|
||||
@ -638,6 +682,24 @@ void XVK_ParseMapPatches( void ) {
|
||||
const model_t* const map = gEngine.pfnGetModelByIndex( 1 );
|
||||
|
||||
parsePatches( map );
|
||||
|
||||
// Perform light deletion and compaction
|
||||
{
|
||||
int w = 0;
|
||||
for (int r = 0; r < g_map_entities.num_lights; ++r) {
|
||||
// Deleted
|
||||
if (g_map_entities.lights[r].entity_index < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r != w)
|
||||
memcpy(g_map_entities.lights + w, g_map_entities.lights + r, sizeof(vk_light_entity_t));
|
||||
++w;
|
||||
}
|
||||
|
||||
g_map_entities.num_lights = w;
|
||||
}
|
||||
|
||||
orientSpotlights();
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
#include "xash3d_types.h"
|
||||
#include "const.h" // typedef word, needed for bspfile.h
|
||||
#include "bspfile.h" // MAX_MAP_ENTITIES
|
||||
|
||||
#define ENT_PROP_LIST(X) \
|
||||
X(0, vec3_t, origin, Vec3) \
|
||||
@ -24,11 +26,14 @@
|
||||
X(19, vec2_t, _xvk_tex_offset, Vec2) \
|
||||
X(20, vec2_t, _xvk_tex_scale, Vec2) \
|
||||
X(21, string, model, String) \
|
||||
|
||||
/* NOTE: not used
|
||||
X(22, int, rendermode, Int) \
|
||||
X(23, int, renderamt, Int) \
|
||||
X(24, vec3_t, rendercolor, Vec3) \
|
||||
X(25, int, renderfx, Int) \
|
||||
X(26, vec3_t, _xvk_offset, Vec3) \
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
Unknown = 0,
|
||||
@ -38,6 +43,7 @@ typedef enum {
|
||||
Worldspawn,
|
||||
FuncWall,
|
||||
Ignored,
|
||||
Xvk_Target,
|
||||
} class_name_e;
|
||||
|
||||
#define MAX_INT_ARRAY_SIZE 64
|
||||
@ -88,13 +94,21 @@ typedef struct {
|
||||
typedef struct {
|
||||
int entity_index;
|
||||
string model;
|
||||
vec3_t origin;
|
||||
|
||||
/* NOTE: not used. Might be needed for #118 in the future.
|
||||
int rendermode, renderamt, renderfx;
|
||||
color24 rendercolor;
|
||||
|
||||
struct cl_entity_s *ent;
|
||||
vec3_t offset;
|
||||
*/
|
||||
} xvk_mapent_func_wall_t;
|
||||
|
||||
typedef struct {
|
||||
class_name_e class;
|
||||
int index;
|
||||
} xvk_mapent_ref_t;
|
||||
|
||||
typedef struct {
|
||||
int num_lights;
|
||||
vk_light_entity_t lights[256];
|
||||
@ -110,6 +124,10 @@ typedef struct {
|
||||
#define MAX_FUNC_WALL_ENTITIES 64
|
||||
int func_walls_count;
|
||||
xvk_mapent_func_wall_t func_walls[MAX_FUNC_WALL_ENTITIES];
|
||||
|
||||
// TODO find out how to read this from the engine, or make its size dynamic
|
||||
//#define MAX_MAP_ENTITIES 2048
|
||||
xvk_mapent_ref_t refs[MAX_MAP_ENTITIES];
|
||||
} xvk_map_entities_t;
|
||||
|
||||
extern xvk_map_entities_t g_map_entities;
|
||||
|
@ -577,15 +577,35 @@ static void drawEntity( cl_entity_t *ent, int render_mode )
|
||||
case mod_brush:
|
||||
R_RotateForEntity( model, ent );
|
||||
|
||||
// Patch func_wall offsets
|
||||
// TODO universal entity patching by index O(1); don't loop like that
|
||||
{
|
||||
// Patch func_wall entities offsets
|
||||
const int eindex = ent->index + 1; // TODO why is this off-by-1?
|
||||
const xvk_mapent_func_wall_t *func_wall = NULL;
|
||||
if (eindex >= 0 && eindex < g_map_entities.entity_count) {
|
||||
const xvk_mapent_ref_t *const ref = g_map_entities.refs + eindex;
|
||||
if (ref->class == FuncWall) {
|
||||
func_wall = g_map_entities.func_walls + ref->index;
|
||||
} else {
|
||||
// Not found directly by index, find otherwise
|
||||
// TODO this should be removed after we make sure the the index method above is enough
|
||||
// FIXME nope, indexes are not stable
|
||||
for (int i = 0; i < g_map_entities.func_walls_count; ++i) {
|
||||
xvk_mapent_func_wall_t *const fw = g_map_entities.func_walls + i;
|
||||
if (fw->entity_index == ent->index + 1) {
|
||||
Matrix4x4_ConcatTranslate(model, fw->offset[0], fw->offset[1], fw->offset[2]);
|
||||
if (Q_strcmp(ent->model->name, fw->model) == 0) {
|
||||
gEngine.Con_Printf(S_ERROR "Entity %s is func_wall=%d, but its ent->index=%d(+1=%d) is off (mapents: %d)\n", ent->model->name, i, ent->index, eindex, fw->entity_index);
|
||||
//func_wall = fw;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (func_wall) {
|
||||
Matrix3x4_LoadIdentity(model);
|
||||
Matrix4x4_SetOrigin(model, func_wall->origin[0], func_wall->origin[1], func_wall->origin[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VK_RenderStateSetMatrixModel( model );
|
||||
VK_BrushModelDraw( ent, render_mode, blend, model );
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user