mirror of
https://github.com/w23/xash3d-fwgs
synced 2024-12-14 04:59:58 +01:00
vk: studio: extract all model/cache stuff into separate files
This commit is contained in:
parent
f99d43ec4c
commit
09d8534b01
@ -10,6 +10,7 @@
|
||||
#include "vk_cvar.h"
|
||||
#include "camera.h"
|
||||
#include "r_speeds.h"
|
||||
#include "vk_studio_model.h"
|
||||
|
||||
#include "xash3d_mathlib.h"
|
||||
#include "const.h"
|
||||
@ -145,133 +146,6 @@ static struct {
|
||||
model_t *currentmodel;
|
||||
} RI;
|
||||
|
||||
typedef struct {
|
||||
vk_render_model_t model;
|
||||
r_geometry_range_t geometry_range;
|
||||
vk_render_geometry_t *geometries;
|
||||
int geometries_count;
|
||||
int vertex_count, index_count;
|
||||
} r_studio_render_submodel_t;
|
||||
|
||||
typedef struct {
|
||||
const mstudiomodel_t *key_submodel;
|
||||
|
||||
// Non-NULL for animated instances
|
||||
const cl_entity_t *key_entity;
|
||||
|
||||
r_studio_render_submodel_t render;
|
||||
} r_studio_model_cache_entry_t;
|
||||
|
||||
typedef struct {
|
||||
vec3_t *prev_verts;
|
||||
} r_studio_entity_submodel_t;
|
||||
|
||||
typedef struct {
|
||||
const cl_entity_t *key_entity;
|
||||
int model_index;
|
||||
|
||||
//matrix3x4 transform;
|
||||
matrix3x4 prev_transform;
|
||||
|
||||
r_studio_entity_submodel_t *submodels;
|
||||
} r_studio_entity_model_t;
|
||||
|
||||
typedef struct {
|
||||
const studiohdr_t *key_model;
|
||||
|
||||
// Model contains no animations and can be used directly
|
||||
qboolean is_static;
|
||||
|
||||
// Pre-built submodels for static, NULL if not static
|
||||
r_studio_render_submodel_t *render_submodels;
|
||||
} r_studio_cached_model_t;
|
||||
|
||||
static struct {
|
||||
#define MAX_CACHED_STUDIO_SUBMODELS 1024
|
||||
// TODO proper map/hash table
|
||||
r_studio_model_cache_entry_t entries[MAX_CACHED_STUDIO_SUBMODELS];
|
||||
int entries_count;
|
||||
|
||||
#define MAX_STUDIO_MODELS 256
|
||||
r_studio_cached_model_t models[MAX_STUDIO_MODELS];
|
||||
int models_count;
|
||||
|
||||
// TODO hash table
|
||||
r_studio_entity_model_t *entities;
|
||||
int entities_count;
|
||||
} g_studio_cache;
|
||||
|
||||
static void studioRenderSubmodelDestroy( r_studio_render_submodel_t *submodel ) {
|
||||
R_RenderModelDestroy(&submodel->model);
|
||||
R_GeometryRangeFree(&submodel->geometry_range);
|
||||
Mem_Free(submodel->geometries);
|
||||
submodel->geometries = NULL;
|
||||
submodel->geometries_count = 0;
|
||||
submodel->vertex_count = 0;
|
||||
submodel->index_count = 0;
|
||||
}
|
||||
|
||||
void R_StudioCacheClear( void ) {
|
||||
for (int i = 0; i < g_studio_cache.entries_count; ++i) {
|
||||
r_studio_model_cache_entry_t *const entry = g_studio_cache.entries + i;
|
||||
ASSERT(entry->key_submodel);
|
||||
entry->key_submodel = 0;
|
||||
entry->key_entity = NULL;
|
||||
|
||||
studioRenderSubmodelDestroy(&entry->render);
|
||||
}
|
||||
|
||||
g_studio_cache.entries_count = 0;
|
||||
g_studio_cache.models_count = 0;
|
||||
}
|
||||
|
||||
static qboolean isStudioModelDynamic(const studiohdr_t *hdr) {
|
||||
gEngine.Con_Reportf("Studio model %s, sequences = %d:\n", hdr->name, hdr->numseq);
|
||||
if (hdr->numseq == 0)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < hdr->numseq; ++i) {
|
||||
const mstudioseqdesc_t *const pseqdesc = (mstudioseqdesc_t *)((byte *)hdr + hdr->seqindex) + i;
|
||||
gEngine.Con_Reportf(" %d: fps=%f numframes=%d\n", i, pseqdesc->fps, pseqdesc->numframes);
|
||||
|
||||
// TODO read the sequence and verify that the animation data does in fact animate
|
||||
// There are known cases where all the data is the same and no animation happens
|
||||
}
|
||||
|
||||
// This is rather conservative.
|
||||
// TODO We might be able to cache:
|
||||
// - individual sequences w/o animation frames
|
||||
// - individual submodels that are not affected by any sequences or animations
|
||||
const mstudioseqdesc_t *const pseqdesc = (mstudioseqdesc_t *)((byte *)hdr + hdr->seqindex) + 0;
|
||||
return hdr->numseq > 1 || (pseqdesc->fps > 0 && pseqdesc->numframes > 1);
|
||||
}
|
||||
|
||||
qboolean R_StudioModelPreload(model_t *mod) {
|
||||
const studiohdr_t *const hdr = (const studiohdr_t *)gEngine.Mod_Extradata( mod_studio, mod);
|
||||
|
||||
ASSERT(g_studio_cache.models_count < MAX_STUDIO_MODELS);
|
||||
|
||||
g_studio_cache.models[g_studio_cache.models_count++] = (r_studio_cached_model_t){
|
||||
.key_model = hdr,
|
||||
.is_static = !isStudioModelDynamic(hdr),
|
||||
};
|
||||
|
||||
// TODO if it is static, pregenerate the geometry
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const r_studio_model_cache_entry_t *findSubModelInCacheForEntity(const mstudiomodel_t *submodel, const cl_entity_t *ent) {
|
||||
// FIXME hash table, there are hundreds of entries
|
||||
for (int i = 0; i < g_studio_cache.entries_count; ++i) {
|
||||
const r_studio_model_cache_entry_t *const entry = g_studio_cache.entries + i;
|
||||
if (entry->key_submodel == submodel && (entry->key_entity == NULL || entry->key_entity == ent))
|
||||
return entry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_StudioSetupTimings
|
||||
@ -2304,10 +2178,9 @@ static qboolean buildStudioSubmodelGeometry(build_submodel_geometry_t args) {
|
||||
}
|
||||
|
||||
static const r_studio_model_cache_entry_t *buildCachedStudioSubModel( const mstudiomodel_t *submodel, const cl_entity_t *ent ) {
|
||||
if (g_studio_cache.entries_count == MAX_CACHED_STUDIO_SUBMODELS) {
|
||||
PRINT_NOT_IMPLEMENTED_ARGS("Studio submodel cache overflow at %d", MAX_CACHED_STUDIO_SUBMODELS);
|
||||
r_studio_model_cache_entry_t *const entry = studioSubModelCacheAlloc();
|
||||
if (!entry)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const mstudiomesh_t *const pmesh = (mstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex);
|
||||
|
||||
@ -2344,8 +2217,6 @@ static const r_studio_model_cache_entry_t *buildCachedStudioSubModel( const mstu
|
||||
|
||||
const qboolean is_dynamic = isStudioModelDynamic(m_pStudioHeader);
|
||||
|
||||
r_studio_model_cache_entry_t *const entry = g_studio_cache.entries + g_studio_cache.entries_count;
|
||||
|
||||
*entry = (r_studio_model_cache_entry_t){
|
||||
.key_submodel = submodel,
|
||||
.key_entity = is_dynamic ? ent : NULL,
|
||||
@ -2371,8 +2242,6 @@ static const r_studio_model_cache_entry_t *buildCachedStudioSubModel( const mstu
|
||||
return NULL;
|
||||
}
|
||||
|
||||
++g_studio_cache.entries_count;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -2420,9 +2289,9 @@ static void R_StudioDrawPoints( void ) {
|
||||
|
||||
const r_studio_model_cache_entry_t *cached_model = findSubModelInCacheForEntity( m_pSubModel, RI.currententity );
|
||||
|
||||
if (!cached_model)
|
||||
if (!cached_model) {
|
||||
cached_model = buildCachedStudioSubModel(m_pSubModel, RI.currententity);
|
||||
else if (cached_model->key_entity) {
|
||||
} else if (cached_model->key_entity) {
|
||||
updateCachedStudioSubModel(cached_model);
|
||||
}
|
||||
|
||||
@ -3636,7 +3505,7 @@ void VK_StudioInit( void )
|
||||
R_SPEEDS_COUNTER(g_studio_stats.submodels_static, "submodels_static", kSpeedsMetricCount);
|
||||
R_SPEEDS_COUNTER(g_studio_stats.submodels_dynamic, "submodels_dynamic", kSpeedsMetricCount);
|
||||
|
||||
R_SPEEDS_METRIC(g_studio_cache.entries_count, "cached_submodels", kSpeedsMetricCount);
|
||||
VK_StudioModelInit();
|
||||
}
|
||||
|
||||
void VK_StudioShutdown( void )
|
||||
|
112
ref/vk/vk_studio_model.c
Normal file
112
ref/vk/vk_studio_model.c
Normal file
@ -0,0 +1,112 @@
|
||||
#include "vk_studio_model.h"
|
||||
#include "r_speeds.h"
|
||||
|
||||
#define MODULE_NAME "studio"
|
||||
|
||||
static struct {
|
||||
#define MAX_CACHED_STUDIO_SUBMODELS 1024
|
||||
// TODO proper map/hash table
|
||||
r_studio_model_cache_entry_t entries[MAX_CACHED_STUDIO_SUBMODELS];
|
||||
int entries_count;
|
||||
|
||||
#define MAX_STUDIO_MODELS 256
|
||||
r_studio_cached_model_t models[MAX_STUDIO_MODELS];
|
||||
int models_count;
|
||||
|
||||
// TODO hash table
|
||||
r_studio_entity_model_t *entities;
|
||||
int entities_count;
|
||||
} g_studio_cache;
|
||||
|
||||
static void studioRenderSubmodelDestroy( r_studio_render_submodel_t *submodel ) {
|
||||
R_RenderModelDestroy(&submodel->model);
|
||||
R_GeometryRangeFree(&submodel->geometry_range);
|
||||
Mem_Free(submodel->geometries);
|
||||
submodel->geometries = NULL;
|
||||
submodel->geometries_count = 0;
|
||||
submodel->vertex_count = 0;
|
||||
submodel->index_count = 0;
|
||||
}
|
||||
|
||||
void R_StudioCacheClear( void ) {
|
||||
for (int i = 0; i < g_studio_cache.entries_count; ++i) {
|
||||
r_studio_model_cache_entry_t *const entry = g_studio_cache.entries + i;
|
||||
ASSERT(entry->key_submodel);
|
||||
entry->key_submodel = 0;
|
||||
entry->key_entity = NULL;
|
||||
|
||||
studioRenderSubmodelDestroy(&entry->render);
|
||||
}
|
||||
|
||||
g_studio_cache.entries_count = 0;
|
||||
g_studio_cache.models_count = 0;
|
||||
}
|
||||
|
||||
qboolean isStudioModelDynamic(const studiohdr_t *hdr) {
|
||||
gEngine.Con_Reportf("Studio model %s, sequences = %d:\n", hdr->name, hdr->numseq);
|
||||
if (hdr->numseq == 0)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < hdr->numseq; ++i) {
|
||||
const mstudioseqdesc_t *const pseqdesc = (mstudioseqdesc_t *)((byte *)hdr + hdr->seqindex) + i;
|
||||
gEngine.Con_Reportf(" %d: fps=%f numframes=%d\n", i, pseqdesc->fps, pseqdesc->numframes);
|
||||
|
||||
// TODO read the sequence and verify that the animation data does in fact animate
|
||||
// There are known cases where all the data is the same and no animation happens
|
||||
}
|
||||
|
||||
// This is rather conservative.
|
||||
// TODO We might be able to cache:
|
||||
// - individual sequences w/o animation frames
|
||||
// - individual submodels that are not affected by any sequences or animations
|
||||
// - animation sequences without real animations (all frames are the same)
|
||||
// - etc
|
||||
const mstudioseqdesc_t *const pseqdesc = (mstudioseqdesc_t *)((byte *)hdr + hdr->seqindex) + 0;
|
||||
const qboolean is_dynamic = hdr->numseq > 1 || (pseqdesc->fps > 0 && pseqdesc->numframes > 1);
|
||||
gEngine.Con_Reportf("Studio model %s is %s\n", hdr->name, is_dynamic ? "dynamic" : "static");
|
||||
return is_dynamic;
|
||||
}
|
||||
|
||||
qboolean R_StudioModelPreload(model_t *mod) {
|
||||
const studiohdr_t *const hdr = (const studiohdr_t *)gEngine.Mod_Extradata(mod_studio, mod);
|
||||
|
||||
ASSERT(g_studio_cache.models_count < MAX_STUDIO_MODELS);
|
||||
|
||||
g_studio_cache.models[g_studio_cache.models_count++] = (r_studio_cached_model_t){
|
||||
.key_model = hdr,
|
||||
.is_static = !isStudioModelDynamic(hdr),
|
||||
};
|
||||
|
||||
// TODO if it is static, pregenerate the geometry
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const r_studio_model_cache_entry_t *findSubModelInCacheForEntity(const mstudiomodel_t *submodel, const cl_entity_t *ent) {
|
||||
// FIXME hash table, there are hundreds of entries
|
||||
for (int i = 0; i < g_studio_cache.entries_count; ++i) {
|
||||
const r_studio_model_cache_entry_t *const entry = g_studio_cache.entries + i;
|
||||
if (entry->key_submodel == submodel && (entry->key_entity == NULL || entry->key_entity == ent))
|
||||
return entry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r_studio_model_cache_entry_t *studioSubModelCacheAlloc(void) {
|
||||
if (g_studio_cache.entries_count == MAX_CACHED_STUDIO_SUBMODELS) {
|
||||
PRINT_NOT_IMPLEMENTED_ARGS("Studio submodel cache overflow at %d", MAX_CACHED_STUDIO_SUBMODELS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r_studio_model_cache_entry_t *const entry = g_studio_cache.entries + g_studio_cache.entries_count;
|
||||
++g_studio_cache.entries_count;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
// TODO ? void studioSubModelCacheFree(r_studio_model_cache_entry_t*);
|
||||
|
||||
void VK_StudioModelInit(void) {
|
||||
R_SPEEDS_METRIC(g_studio_cache.entries_count, "cached_submodels", kSpeedsMetricCount);
|
||||
}
|
52
ref/vk/vk_studio_model.h
Normal file
52
ref/vk/vk_studio_model.h
Normal file
@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include "vk_render.h"
|
||||
#include "vk_geometry.h"
|
||||
|
||||
typedef struct {
|
||||
vk_render_model_t model;
|
||||
r_geometry_range_t geometry_range;
|
||||
vk_render_geometry_t *geometries;
|
||||
int geometries_count;
|
||||
int vertex_count, index_count;
|
||||
} r_studio_render_submodel_t;
|
||||
|
||||
typedef struct {
|
||||
const mstudiomodel_t *key_submodel;
|
||||
|
||||
// Non-NULL for animated instances
|
||||
const cl_entity_t *key_entity;
|
||||
|
||||
r_studio_render_submodel_t render;
|
||||
} r_studio_model_cache_entry_t;
|
||||
|
||||
typedef struct {
|
||||
vec3_t *prev_verts;
|
||||
} r_studio_entity_submodel_t;
|
||||
|
||||
typedef struct {
|
||||
const cl_entity_t *key_entity;
|
||||
int model_index;
|
||||
|
||||
//matrix3x4 transform;
|
||||
matrix3x4 prev_transform;
|
||||
|
||||
r_studio_entity_submodel_t *submodels;
|
||||
} r_studio_entity_model_t;
|
||||
|
||||
typedef struct {
|
||||
const studiohdr_t *key_model;
|
||||
|
||||
// Model contains no animations and can be used directly
|
||||
qboolean is_static;
|
||||
|
||||
// Pre-built submodels for static, NULL if not static
|
||||
r_studio_render_submodel_t *render_submodels;
|
||||
} r_studio_cached_model_t;
|
||||
|
||||
const r_studio_model_cache_entry_t *findSubModelInCacheForEntity(const mstudiomodel_t *submodel, const cl_entity_t *ent);
|
||||
r_studio_model_cache_entry_t *studioSubModelCacheAlloc(void);
|
||||
|
||||
qboolean isStudioModelDynamic(const studiohdr_t *hdr);
|
||||
|
||||
void VK_StudioModelInit(void);
|
Loading…
Reference in New Issue
Block a user