Merge "Enable live reloading light data" #457

- [x] Fixes #417 
- [x] Fixes #330 
- [x] Fixes #104
This commit is contained in:
Ivan Avdeev 2023-03-03 16:50:41 -08:00 committed by GitHub
commit d1376a89e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 307 additions and 219 deletions

View File

@ -24,6 +24,7 @@
typedef struct vk_brush_model_s {
vk_render_model_t render_model;
int num_water_surfaces;
int *surface_to_geometry_index;
} vk_brush_model_t;
static struct {
@ -218,6 +219,9 @@ static void EmitWaterPolys( const cl_entity_t *ent, const msurface_t *warp, qboo
// Render
{
vec3_t emissive;
RT_GetEmissiveForTexture(emissive, warp->texinfo->texture->gl_texturenum);
const vk_render_geometry_t geometry = {
.texture = warp->texinfo->texture->gl_texturenum, // FIXME assert >= 0
.material = kXVkMaterialWater,
@ -228,6 +232,7 @@ static void EmitWaterPolys( const cl_entity_t *ent, const msurface_t *warp, qboo
.element_count = num_indices,
.index_offset = buffer.indices.unit_offset,
.emissive = {emissive[0], emissive[1], emissive[2]},
};
VK_RenderModelDynamicAddGeometry( &geometry );
@ -388,7 +393,7 @@ void VK_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, co
for (int i = 0; i < bmodel->render_model.num_geometries; ++i) {
vk_render_geometry_t *geom = bmodel->render_model.geometries + i;
const int surface_index = geom->surf - mod->surfaces;
const xvk_patch_surface_t *patch_surface = g_map_entities.patch.surfaces ? g_map_entities.patch.surfaces+surface_index : NULL;
const xvk_patch_surface_t *const patch_surface = R_VkPatchGetSurface(surface_index);
if (render_mode == kRenderTransColor) {
// TransColor mode means no texture color is used
@ -427,9 +432,12 @@ static qboolean renderableSurface( const msurface_t *surf, int i ) {
// PRINTFLAGS(PRINTFLAG)
// gEngine.Con_Reportf("\n");
// }
//
if (g_map_entities.patch.surfaces && g_map_entities.patch.surfaces[i].flags & Patch_Surface_Delete)
return false;
{
const xvk_patch_surface_t *patch_surface = R_VkPatchGetSurface(i);
if (patch_surface && patch_surface->flags & Patch_Surface_Delete)
return false;
}
//if( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS ) ) {
if( surf->flags & ( SURF_DRAWTURB | SURF_DRAWTURB_QUADS ) ) {
@ -456,8 +464,6 @@ typedef struct {
int num_surfaces, num_vertices, num_indices;
int max_texture_id;
int water_surfaces;
//int sky_surfaces;
int emissive_surfaces;
} model_sizes_t;
static model_sizes_t computeSizes( const model_t *mod ) {
@ -479,39 +485,11 @@ static model_sizes_t computeSizes( const model_t *mod ) {
sizes.num_indices += 3 * (surf->numedges - 1);
if (tex_id > sizes.max_texture_id)
sizes.max_texture_id = tex_id;
{
const xvk_patch_surface_t *const psurf = g_map_entities.patch.surfaces ? g_map_entities.patch.surfaces + surface_index : NULL;
vec3_t emissive;
if ((psurf && (psurf->flags & Patch_Surface_Emissive)) || (RT_GetEmissiveForTexture(emissive, tex_id)))
++sizes.emissive_surfaces;
}
}
return sizes;
}
static rt_light_add_polygon_t loadPolyLight(const model_t *mod, const int surface_index, const msurface_t *surf, const vec3_t emissive) {
rt_light_add_polygon_t lpoly = {0};
lpoly.num_vertices = Q_min(7, surf->numedges);
// TODO split, don't clip
if (surf->numedges > 7)
gEngine.Con_Printf(S_WARN "emissive surface %d has %d vertices; clipping to 7\n", surface_index, surf->numedges);
VectorCopy(emissive, lpoly.emissive);
for (int i = 0; i < lpoly.num_vertices; ++i) {
const int iedge = mod->surfedges[surf->firstedge + i];
const medge_t *edge = mod->edges + (iedge >= 0 ? iedge : -iedge);
const mvertex_t *vertex = mod->vertexes + (iedge >= 0 ? edge->v[0] : edge->v[1]);
VectorCopy(vertex->position, lpoly.vertices[i]);
}
lpoly.surface = surf;
return lpoly;
}
static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
vk_brush_model_t *bmodel = mod->cache.data;
uint32_t vertex_offset = 0;
@ -545,7 +523,7 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
int index_count = 0;
vec3_t tangent;
int tex_id = surf->texinfo->texture->gl_texturenum;
const xvk_patch_surface_t *const psurf = g_map_entities.patch.surfaces ? g_map_entities.patch.surfaces + surface_index : NULL;
const xvk_patch_surface_t *const psurf = R_VkPatchGetSurface(i);
if (!renderableSurface(surf, surface_index))
continue;
@ -553,29 +531,7 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
if (t != tex_id)
continue;
// FIXME move this to rt_light_bsp and static loading
{
qboolean is_emissive = false;
vec3_t emissive = {0};
rt_light_add_polygon_t polylight;
if (psurf && (psurf->flags & Patch_Surface_Emissive)) {
is_emissive = true;
VectorCopy(psurf->emissive, emissive);
} else if (RT_GetEmissiveForTexture(emissive, tex_id)) {
is_emissive = true;
}
if (is_emissive) {
if (bmodel->render_model.polylights) {
ASSERT(bmodel->render_model.polylights_count < sizes.emissive_surfaces);
bmodel->render_model.polylights[bmodel->render_model.polylights_count++] = loadPolyLight(mod, surface_index, surf, emissive);
} else {
polylight = loadPolyLight(mod, surface_index, surf, emissive);
RT_LightAddPolygon(&polylight);
}
}
}
bmodel->surface_to_geometry_index[i] = num_geometries;
++num_geometries;
@ -588,6 +544,8 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
return false;
}
VectorClear(model_geometry->emissive);
model_geometry->surf = surf;
model_geometry->texture = tex_id;
@ -677,10 +635,8 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
R_GeometryBufferUnlock( &buffer );
if (bmodel->render_model.polylights) {
gEngine.Con_Reportf("Dynamic polylights %d %d \n", sizes.emissive_surfaces, bmodel->render_model.polylights_count);
ASSERT(sizes.emissive_surfaces == bmodel->render_model.polylights_count);
}
bmodel->render_model.dynamic_polylights = NULL;
bmodel->render_model.dynamic_polylights_count = 0;
ASSERT(sizes.num_surfaces == num_geometries);
bmodel->render_model.num_geometries = num_geometries;
@ -688,10 +644,8 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
return true;
}
qboolean VK_BrushModelLoad( model_t *mod, qboolean map )
{
if (mod->cache.data)
{
qboolean VK_BrushModelLoad( model_t *mod ) {
if (mod->cache.data) {
gEngine.Con_Reportf( S_WARN "Model %s was already loaded\n", mod->name );
return true;
}
@ -702,22 +656,20 @@ qboolean VK_BrushModelLoad( model_t *mod, qboolean map )
const model_sizes_t sizes = computeSizes( mod );
const size_t model_size =
sizeof(vk_brush_model_t) +
sizeof(vk_render_geometry_t) * sizes.num_surfaces;
sizeof(vk_render_geometry_t) * sizes.num_surfaces +
sizeof(int) * mod->nummodelsurfaces;
vk_brush_model_t *bmodel = Mem_Calloc(vk_core.pool, model_size);
mod->cache.data = bmodel;
Q_strncpy(bmodel->render_model.debug_name, mod->name, sizeof(bmodel->render_model.debug_name));
bmodel->render_model.render_type = kVkRenderTypeSolid;
bmodel->render_model.static_map = map;
bmodel->num_water_surfaces = sizes.water_surfaces;
Vector4Set(bmodel->render_model.color, 1, 1, 1, 1);
if (sizes.num_surfaces != 0) {
bmodel->render_model.geometries = (vk_render_geometry_t*)((char*)(bmodel + 1));
if (!map && sizes.emissive_surfaces)
bmodel->render_model.polylights = Mem_Malloc(vk_core.pool, sizeof(bmodel->render_model.polylights[0]) * sizes.emissive_surfaces);
bmodel->surface_to_geometry_index = (int*)((char*)(bmodel->render_model.geometries + sizes.num_surfaces));
if (!loadBrushSurfaces(sizes, mod) || !VK_RenderModelInit(&bmodel->render_model)) {
gEngine.Con_Printf(S_ERROR "Could not load model %s\n", mod->name);
@ -742,8 +694,6 @@ void VK_BrushModelDestroy( model_t *mod ) {
return;
VK_RenderModelDestroy(&bmodel->render_model);
if (bmodel->render_model.polylights)
Mem_Free(bmodel->render_model.polylights);
Mem_Free(bmodel);
mod->cache.data = NULL;
}
@ -754,3 +704,106 @@ void VK_BrushStatsClear( void )
g_brush.stat.num_vertices = 0;
g_brush.stat.num_indices = 0;
}
static rt_light_add_polygon_t loadPolyLight(const model_t *mod, const int surface_index, const msurface_t *surf, const vec3_t emissive) {
rt_light_add_polygon_t lpoly = {0};
lpoly.num_vertices = Q_min(7, surf->numedges);
// TODO split, don't clip
if (surf->numedges > 7)
gEngine.Con_Printf(S_WARN "emissive surface %d has %d vertices; clipping to 7\n", surface_index, surf->numedges);
VectorCopy(emissive, lpoly.emissive);
for (int i = 0; i < lpoly.num_vertices; ++i) {
const int iedge = mod->surfedges[surf->firstedge + i];
const medge_t *edge = mod->edges + (iedge >= 0 ? iedge : -iedge);
const mvertex_t *vertex = mod->vertexes + (iedge >= 0 ? edge->v[0] : edge->v[1]);
VectorCopy(vertex->position, lpoly.vertices[i]);
}
lpoly.surface = surf;
return lpoly;
}
void R_VkBrushModelCollectEmissiveSurfaces( const struct model_s *mod, qboolean is_worldmodel ) {
typedef struct {
int model_surface_index;
int surface_index;
const msurface_t *surf;
vec3_t emissive;
} emissive_surface_t;
emissive_surface_t emissive_surfaces[MAX_SURFACE_LIGHTS];
int emissive_surfaces_count = 0;
// Load list of all emissive surfaces
for( int i = 0; i < mod->nummodelsurfaces; ++i) {
const int surface_index = mod->firstmodelsurface + i;
const msurface_t *surf = mod->surfaces + surface_index;
if (!renderableSurface(surf, surface_index))
continue;
const int tex_id = surf->texinfo->texture->gl_texturenum; // TODO animation?
vec3_t emissive;
const xvk_patch_surface_t *const psurf = R_VkPatchGetSurface(surface_index);
if (psurf && (psurf->flags & Patch_Surface_Emissive)) {
VectorCopy(psurf->emissive, emissive);
} else if (RT_GetEmissiveForTexture(emissive, tex_id)) {
// emissive
} else {
// not emissive, continue to the next
continue;
}
//gEngine.Con_Reportf("%d: i=%d surf_index=%d patch=%d(%#x) => emissive=(%f,%f,%f)\n", emissive_surfaces_count, i, surface_index, !!psurf, psurf?psurf->flags:0, emissive[0], emissive[1], emissive[2]);
if (emissive_surfaces_count == MAX_SURFACE_LIGHTS) {
gEngine.Con_Printf(S_ERROR "Too many emissive surfaces for model %s: max=%d\n", mod->name, MAX_SURFACE_LIGHTS);
break;
}
emissive_surface_t* const surface = &emissive_surfaces[emissive_surfaces_count++];
surface->model_surface_index = i;
surface->surface_index = surface_index;
surface->surf = surf;
VectorCopy(emissive, surface->emissive);
}
vk_brush_model_t *const bmodel = mod->cache.data;
ASSERT(bmodel);
// Clear old per-geometry emissive values. The new emissive values will be assigned by the loop below only to the relevant geoms
for (int i = 0; i < bmodel->render_model.num_geometries; ++i) {
vk_render_geometry_t *const geom = bmodel->render_model.geometries + i;
VectorClear(geom->emissive);
}
// Non-worldmodel brush models may move around and so must have their emissive surfaces treated as dynamic
if (!is_worldmodel) {
if (bmodel->render_model.dynamic_polylights)
Mem_Free(bmodel->render_model.dynamic_polylights);
bmodel->render_model.dynamic_polylights_count = emissive_surfaces_count;
bmodel->render_model.dynamic_polylights = Mem_Malloc(vk_core.pool, sizeof(bmodel->render_model.dynamic_polylights[0]) * emissive_surfaces_count);
}
// Apply all emissive surfaces found
for (int i = 0; i < emissive_surfaces_count; ++i) {
const emissive_surface_t* const s = emissive_surfaces + i;
const rt_light_add_polygon_t polylight = loadPolyLight(mod, s->surface_index, s->surf, s->emissive);
// Worldmodel emissive surfaces are added immediately, as the worldmodel is always drawn and is static.
// Non-worldmodel ones will be applied later when the model is actually rendered
if (is_worldmodel) {
RT_LightAddPolygon(&polylight);
} else {
bmodel->render_model.dynamic_polylights[i] = polylight;
}
// Assign the emissive value to the right geometry
VectorCopy(polylight.emissive, bmodel->render_model.geometries[bmodel->surface_to_geometry_index[s->model_surface_index]].emissive);
}
gEngine.Con_Reportf("Loaded %d polylights for %smodel %s\n", emissive_surfaces_count, is_worldmodel ? "world" : "movable ", mod->name);
}

View File

@ -11,10 +11,12 @@ struct cl_entity_s;
qboolean VK_BrushInit( void );
void VK_BrushShutdown( void );
qboolean VK_BrushModelLoad(struct model_s *mod, qboolean map);
qboolean VK_BrushModelLoad(struct model_s *mod);
void VK_BrushModelDestroy(struct model_s *mod);
void VK_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, const matrix4x4 model );
void VK_BrushStatsClear( void );
const texture_t *R_TextureAnimation( const cl_entity_t *ent, const msurface_t *s, const struct texture_s *base_override );
void R_VkBrushModelCollectEmissiveSurfaces( const struct model_s *mod, qboolean is_worldmodel );

View File

@ -467,7 +467,7 @@ static void prepareSurfacesLeafVisibilityCache( const struct model_s *map ) {
g_lights_bsp.surfaces[i].potentially_visible_leafs = NULL;
}
void RT_LightsNewMapBegin( const struct model_s *map ) {
void RT_LightsNewMap( const struct model_s *map ) {
// 1. Determine map bounding box (and optimal grid size?)
// map->mins, maxs
vec3_t map_size, min_cell, max_cell;
@ -504,48 +504,6 @@ void RT_LightsNewMapBegin( const struct model_s *map ) {
g_lights_.visited_cells = bitArrayCreate(g_lights.map.grid_cells);
prepareSurfacesLeafVisibilityCache( map );
// Load RAD data based on map name
memset(g_lights_.map.emissive_textures, 0, sizeof(g_lights_.map.emissive_textures));
loadRadData( map, "maps/lights.rad" );
{
int name_len = Q_strlen(map->name);
// Strip ".bsp" suffix
if (name_len > 4 && 0 == Q_stricmp(map->name + name_len - 4, ".bsp"))
name_len -= 4;
loadRadData( map, "%.*s.rad", name_len, map->name );
}
// Clear static lights counts
{
g_lights_.num_polygons = g_lights_.num_static.polygons = 0;
g_lights_.num_point_lights = g_lights_.num_static.point_lights = 0;
g_lights_.num_polygon_vertices = g_lights_.num_static.polygon_vertices = 0;
for (int i = 0; i < g_lights.map.grid_cells; ++i) {
vk_lights_cell_t *const cell = g_lights.cells + i;
cell->num_point_lights = cell->num_static.point_lights = 0;
cell->num_polygons = cell->num_static.polygons = 0;
cell->frame_sequence = g_lights_.frame_sequence;
}
}
}
void RT_LightsFrameBegin( void ) {
g_lights_.num_polygons = g_lights_.num_static.polygons;
g_lights_.num_point_lights = g_lights_.num_static.point_lights;
g_lights_.num_polygon_vertices = g_lights_.num_static.polygon_vertices;
g_lights.stats.dirty_cells = 0;
for (int i = 0; i < g_lights.map.grid_cells; ++i) {
vk_lights_cell_t *const cell = g_lights.cells + i;
cell->num_polygons = cell->num_static.polygons;
cell->num_point_lights = cell->num_static.point_lights;
}
}
static qboolean addSurfaceLightToCell( int cell_index, int polygon_light_index ) {
@ -931,10 +889,39 @@ static void processStaticPointLights( void ) {
APROF_SCOPE_END(static_lights);
}
void RT_LightsNewMapEnd( const struct model_s *map ) {
//debug_dump_lights.enabled = true;
void RT_LightsLoadBegin( const struct model_s *map ) {
// Load RAD data based on map name
{
int name_len = Q_strlen(map->name);
// Strip ".bsp" suffix
if (name_len > 4 && 0 == Q_stricmp(map->name + name_len - 4, ".bsp"))
name_len -= 4;
memset(g_lights_.map.emissive_textures, 0, sizeof(g_lights_.map.emissive_textures));
loadRadData( map, "maps/lights.rad" );
loadRadData( map, "%.*s.rad", name_len, map->name );
}
// Clear static lights counts
{
g_lights_.num_polygons = g_lights_.num_static.polygons = 0;
g_lights_.num_point_lights = g_lights_.num_static.point_lights = 0;
g_lights_.num_polygon_vertices = g_lights_.num_static.polygon_vertices = 0;
for (int i = 0; i < g_lights.map.grid_cells; ++i) {
vk_lights_cell_t *const cell = g_lights.cells + i;
cell->num_point_lights = cell->num_static.point_lights = 0;
cell->num_polygons = cell->num_static.polygons = 0;
cell->frame_sequence = g_lights_.frame_sequence;
}
}
processStaticPointLights();
}
void RT_LightsLoadEnd( void ) {
//debug_dump_lights.enabled = true;
// Fix static counts
{
@ -1131,6 +1118,20 @@ int RT_LightAddPolygon(const rt_light_add_polygon_t *addpoly) {
}
}
void RT_LightsFrameBegin( void ) {
g_lights_.num_polygons = g_lights_.num_static.polygons;
g_lights_.num_point_lights = g_lights_.num_static.point_lights;
g_lights_.num_polygon_vertices = g_lights_.num_static.polygon_vertices;
g_lights.stats.dirty_cells = 0;
for (int i = 0; i < g_lights.map.grid_cells; ++i) {
vk_lights_cell_t *const cell = g_lights.cells + i;
cell->num_polygons = cell->num_static.polygons;
cell->num_point_lights = cell->num_static.point_lights;
}
}
static void uploadGridRange( int begin, int end ) {
const int count = end - begin;
ASSERT( count > 0 );

View File

@ -71,9 +71,15 @@ extern vk_lights_t g_lights;
qboolean VK_LightsInit( void );
void VK_LightsShutdown( void );
// Allocate clusters and vis data for the new map
struct model_s;
void RT_LightsNewMapBegin( const struct model_s *map );
void RT_LightsNewMapEnd( const struct model_s *map );
void RT_LightsNewMap( const struct model_s *map );
// Clear light data and prepare for loading
// RT_LightsNewMap should have been already called for current map
void RT_LightsLoadBegin( const struct model_s *map );
// Finalize loading light data, i.e. mark everything loaded so far as static light data
void RT_LightsLoadEnd( void );
void RT_LightsFrameBegin( void );
void RT_LightsFrameEnd( void );

View File

@ -10,6 +10,11 @@
xvk_map_entities_t g_map_entities;
static struct {
xvk_patch_surface_t *surfaces;
int surfaces_count;
} g_patch;
static unsigned parseEntPropWadList(const char* value, string *out, unsigned bit) {
int dst_left = sizeof(string) - 2; // ; \0
char *dst = *out;
@ -321,16 +326,17 @@ static void addPatchSurface( const entity_props_t *props, uint32_t have_fields )
continue;
}
if (!g_map_entities.patch.surfaces) {
g_map_entities.patch.surfaces = Mem_Malloc(vk_core.pool, num_surfaces * sizeof(xvk_patch_surface_t));
if (!g_patch.surfaces) {
g_patch.surfaces = Mem_Malloc(vk_core.pool, num_surfaces * sizeof(xvk_patch_surface_t));
g_patch.surfaces_count = num_surfaces;
for (int i = 0; i < num_surfaces; ++i) {
g_map_entities.patch.surfaces[i].flags = Patch_Surface_NoPatch;
g_map_entities.patch.surfaces[i].tex_id = -1;
g_map_entities.patch.surfaces[i].tex = NULL;
g_patch.surfaces[i].flags = Patch_Surface_NoPatch;
g_patch.surfaces[i].tex_id = -1;
g_patch.surfaces[i].tex = NULL;
}
}
psurf = g_map_entities.patch.surfaces + index;
psurf = g_patch.surfaces + index;
if (should_remove) {
gEngine.Con_Reportf("Patch: surface %d removed\n", index);
@ -507,9 +513,10 @@ static void parsePatches( const model_t *const map ) {
char filename[256];
byte *data;
if (g_map_entities.patch.surfaces) {
Mem_Free(g_map_entities.patch.surfaces);
g_map_entities.patch.surfaces = NULL;
if (g_patch.surfaces) {
Mem_Free(g_patch.surfaces);
g_patch.surfaces = NULL;
g_patch.surfaces_count = 0;
}
Q_snprintf(filename, sizeof(filename), "luchiki/%s.patch", map->name);
@ -544,3 +551,14 @@ void XVK_ParseMapPatches( void ) {
parsePatches( map );
orientSpotlights();
}
const xvk_patch_surface_t* R_VkPatchGetSurface( int surface_index ) {
if (!g_patch.surfaces_count)
return NULL;
ASSERT(g_patch.surfaces);
ASSERT(surface_index >= 0);
ASSERT(surface_index < g_patch.surfaces_count);
return g_patch.surfaces + surface_index;
}

View File

@ -72,6 +72,28 @@ typedef struct {
vec3_t origin;
} xvk_mapent_target_t;
#define MAX_MAPENT_TARGETS 256
typedef struct {
int num_lights;
vk_light_entity_t lights[256];
int single_environment_index;
int entity_count;
string wadlist;
int num_targets;
xvk_mapent_target_t targets[MAX_MAPENT_TARGETS];
} xvk_map_entities_t;
extern xvk_map_entities_t g_map_entities;
enum { NoEnvironmentLights = -1, MoreThanOneEnvironmentLight = -2 };
void XVK_ParseMapEntities( void );
void XVK_ParseMapPatches( void );
enum {
Patch_Surface_NoPatch = 0,
Patch_Surface_Delete = 0x01,
@ -93,30 +115,5 @@ typedef struct {
vec3_t emissive;
} xvk_patch_surface_t;
typedef struct {
xvk_patch_surface_t *surfaces;
} xvk_patch_t;
const xvk_patch_surface_t* R_VkPatchGetSurface( int surface_index );
#define MAX_MAPENT_TARGETS 256
typedef struct {
int num_lights;
vk_light_entity_t lights[256];
int single_environment_index;
int entity_count;
string wadlist;
int num_targets;
xvk_mapent_target_t targets[MAX_MAPENT_TARGETS];
xvk_patch_t patch;
} xvk_map_entities_t;
extern xvk_map_entities_t g_map_entities;
enum { NoEnvironmentLights = -1, MoreThanOneEnvironmentLight = -2 };
void XVK_ParseMapEntities( void );
void XVK_ParseMapPatches( void );

View File

@ -164,9 +164,6 @@ static void applyMaterialToKusok(vk_kusok_data_t* kusok, const vk_render_geometr
kusok->index_offset = geom->index_offset;
kusok->triangles = geom->element_count / 3;
/* if (!render_model->static_map) */
/* VK_LightsAddEmissiveSurface( geom, transform_row, false ); */
kusok->tex_base_color = mat->tex_base_color;
kusok->tex_roughness = mat->tex_roughness;
kusok->tex_metalness = mat->tex_metalness;
@ -200,11 +197,7 @@ static void applyMaterialToKusok(vk_kusok_data_t* kusok, const vk_render_geometr
Vector4Copy(gcolor, kusok->color);
}
if (geom->material == kXVkMaterialEmissive || geom->material == kXVkMaterialEmissiveGlow) {
VectorCopy(geom->emissive, kusok->emissive);
} else {
RT_GetEmissiveForTexture( kusok->emissive, geom->texture );
}
VectorCopy(geom->emissive, kusok->emissive);
/* FIXME these should be done in a different way
if (geom->material == kXVkMaterialConveyor) {
@ -267,6 +260,12 @@ vk_ray_model_t* VK_RayModelCreate( vk_ray_model_init_t args ) {
case kVkRenderType_1_1_R: // blend: scr + dst, depth test
HACK_additive_emissive = true;
break;
case kVkRenderTypeSolid:
case kVkRenderType_AT:
break;
case kVkRenderType_COUNT:
ASSERT(!"Invalid model render_type");
break;
}
for (int i = 0; i < args.model->num_geometries; ++i) {
@ -539,8 +538,8 @@ void VK_RayFrameAddModel( vk_ray_model_t *model, const vk_render_model_t *render
model->kusochki_updated_this_frame = true;
}
for (int i = 0; i < render_model->polylights_count; ++i) {
rt_light_add_polygon_t *const polylight = render_model->polylights + i;
for (int i = 0; i < render_model->dynamic_polylights_count; ++i) {
rt_light_add_polygon_t *const polylight = render_model->dynamic_polylights + i;
polylight->transform_row = (const matrix3x4*)transform_row;
polylight->dynamic = true;
RT_LightAddPolygon(polylight);
@ -553,8 +552,7 @@ void RT_RayModel_Clear(void) {
R_DEBuffer_Init(&g_ray_model_state.kusochki_alloc, MAX_KUSOCHKI / 2, MAX_KUSOCHKI / 2);
}
void XVK_RayModel_ClearForNextFrame( void )
{
void XVK_RayModel_ClearForNextFrame( void ) {
// FIXME we depend on the fact that only a single frame can be in flight
// currently framectl waits for the queue to complete before returning
// so we can be sure here that previous frame is complete and we're free to

View File

@ -662,6 +662,8 @@ qboolean VK_RenderModelInit( vk_render_model_t *model ) {
.model = model,
};
model->ray_model = VK_RayModelCreate(args);
model->dynamic_polylights = NULL;
model->dynamic_polylights_count = 0;
return !!model->ray_model;
}
@ -670,8 +672,11 @@ qboolean VK_RenderModelInit( vk_render_model_t *model ) {
}
void VK_RenderModelDestroy( vk_render_model_t* model ) {
// FIXME why the condition? we should do the cleanup anyway
if (vk_core.rtx && (g_render_state.current_frame_is_ray_traced || !model->dynamic)) {
VK_RayModelDestroy(model->ray_model);
if (model->dynamic_polylights)
Mem_Free(model->dynamic_polylights);
}
}

View File

@ -35,7 +35,7 @@ typedef enum {
kXVkMaterialChrome,
} XVkMaterialType;
typedef struct vk_render_geometry_s {
typedef struct vk_render_geometry_s {
int index_offset, vertex_offset;
// Animated textures will be dynamic and change between frames
@ -55,14 +55,10 @@ typedef struct vk_render_geometry_s {
// - updating dynamic lights (TODO: can decouple from surface/brush models by providing texture_id and aabb directly here)
const struct msurface_s *surf;
// for kXVkMaterialEmissive
// for kXVkMaterialEmissive{,Glow} and others
vec3_t emissive;
} vk_render_geometry_t;
struct vk_ray_model_s;
#define MAX_MODEL_NAME_LENGTH 64
typedef enum {
kVkRenderTypeSolid, // no blending, depth RW
kVkRenderType_A_1mA_RW, // blend: src*a + dst*(1-a), depth: RW
@ -73,11 +69,14 @@ typedef enum {
kVkRenderType_1_1_R, // blend: src + dst, depth test
kVkRenderType_COUNT
} vk_render_type_e;
struct rt_light_add_polygon_s;
struct vk_ray_model_s;
typedef struct vk_render_model_s {
#define MAX_MODEL_NAME_LENGTH 64
char debug_name[MAX_MODEL_NAME_LENGTH];
// FIXME: brushes, sprites, studio models, etc all treat render_mode differently
vk_render_type_e render_type;
vec4_t color;
int lightmap; // <= 0 if no lightmap
@ -88,13 +87,13 @@ typedef struct vk_render_model_s {
// This model will be one-frame only, its buffers are not preserved between frames
qboolean dynamic;
// FIXME ...
qboolean static_map;
// Non-NULL only for ray tracing
struct vk_ray_model_s *ray_model;
struct rt_light_add_polygon_s *polylights;
int polylights_count;
// Polylights which need to be added per-frame dynamically
// Used for non-worldmodel brush models which are not static
struct rt_light_add_polygon_s *dynamic_polylights;
int dynamic_polylights_count;
// previous frame ObjectToWorld (model) matrix
matrix4x4 prev_transform;

View File

@ -82,7 +82,6 @@ static struct {
rt_resource_t res[MAX_RESOURCES];
qboolean reload_pipeline;
qboolean reload_lighting;
matrix4x4 prev_inv_proj, prev_inv_view;
} g_rtx = {0};
@ -140,12 +139,6 @@ void VK_RayFrameBegin( void ) {
R_PrevFrame_StartFrame();
// TODO: move all lighting update to scene?
if (g_rtx.reload_lighting) {
g_rtx.reload_lighting = false;
// FIXME temporarily not supported VK_LightsLoadMapStaticLights();
}
// TODO shouldn't we do this in freeze models mode anyway?
RT_LightsFrameBegin();
}
@ -601,10 +594,6 @@ static void reloadPipeline( void ) {
g_rtx.reload_pipeline = true;
}
static void reloadLighting( void ) {
g_rtx.reload_lighting = true;
}
static void freezeModels( void ) {
g_ray_model_state.freeze_models = !g_ray_model_state.freeze_models;
}
@ -653,7 +642,6 @@ qboolean VK_RayInit( void )
RT_RayModel_Clear();
gEngine.Cmd_AddCommand("vk_rtx_reload", reloadPipeline, "Reload RTX shader");
gEngine.Cmd_AddCommand("vk_rtx_reload_rad", reloadLighting, "Reload RAD files for static lights");
gEngine.Cmd_AddCommand("vk_rtx_freeze", freezeModels, "Freeze models, do not update/add/delete models from to-draw list");
return true;

View File

@ -61,6 +61,44 @@ static struct {
draw_list_t *draw_list;
} g_lists;
static void loadLights( const model_t *const map ) {
RT_LightsLoadBegin(map);
const int num_models = gEngine.EngineGetParm( PARM_NUMMODELS, 0 );
for( int i = 0; i < num_models; i++ ) {
const model_t *const mod = gEngine.pfnGetModelByIndex( i + 1 );
if (!mod)
continue;
if( mod->type != mod_brush )
continue;
const qboolean is_worldmodel = i == 0;
R_VkBrushModelCollectEmissiveSurfaces(mod, is_worldmodel);
}
// Load static map lights
// Reads surfaces from loaded brush models (must happen after all brushes are loaded)
RT_LightsLoadEnd();
}
static void reloadMaterials( void ) {
// Materials do affect patching, as new materials can be referenced in patch data
// So we must do the full sequence
XVK_ParseMapEntities();
XVK_ReloadMaterials();
XVK_ParseMapPatches();
// Assumes that the map has been loaded
// Might have loaded new patch data, need to reload lighting data just in case
const model_t *const map = gEngine.pfnGetModelByIndex( 1 );
loadLights(map);
}
// Same as the above, but avoids reloading heavy materials data
// Only reloads light entities, patches, rad files
static void reloadPatches( void ) {
// Must re-parse map entities to initialize initial values before patching
XVK_ParseMapEntities();
@ -70,23 +108,8 @@ static void reloadPatches( void ) {
// Assumes that the map brush model has been loaded
// Patching does disturb light sources, reinitialize
// FIXME loading patches will be broken now ;_;
// ?? VK_LightsLoadMapStaticLights();
}
static void reloadMaterials( void ) {
// Materials do affect patching, as new materials can be referenced in patch data
// So we must do the full sequencce
XVK_ParseMapEntities();
XVK_ReloadMaterials();
XVK_ParseMapPatches();
// Assumes that the map has been loaded
// Might have loaded new patch data, need to reload lighting data just in case
// FIXME loading patches will be broken now ;_;
// ??? VK_LightsLoadMapStaticLights();
const model_t *const map = gEngine.pfnGetModelByIndex( 1 );
loadLights(map);
}
void VK_SceneInit( void )
@ -95,9 +118,11 @@ void VK_SceneInit( void )
g_lists.draw_list = g_lists.draw_stack;
g_lists.draw_stack_pos = 0;
if (vk_core.rtx) {
gEngine.Cmd_AddCommand("vk_rtx_reload_materials", reloadMaterials, "Reload PBR materials");
gEngine.Cmd_AddCommand("vk_rtx_reload_patches", reloadPatches, "Reload patches (does not update surface deletion)");
gEngine.Cmd_AddCommand("vk_rtx_reload_rad", reloadPatches, "Reload RAD files for static lights");
}
}
@ -178,9 +203,6 @@ void R_NewMap( void ) {
// Depends on loaded materials. Must preceed loading brush models.
XVK_ParseMapPatches();
// Need parsed map entities, and also should happen before brush model loading
RT_LightsNewMapBegin(map);
// Load all models at once
gEngine.Con_Reportf( "Num models: %d:\n", num_models );
for( int i = 0; i < num_models; i++ )
@ -194,15 +216,12 @@ void R_NewMap( void ) {
if( m->type != mod_brush )
continue;
if (!VK_BrushModelLoad(m, i == 0))
{
gEngine.Con_Printf( S_ERROR "Couldn't load model %s\n", m->name );
}
if (!VK_BrushModelLoad(m))
gEngine.Host_Error( "Couldn't load model %s\n", m->name );
}
// Load static map lights
// Reads surfaces from loaded brush models (must happen after all brushes are loaded)
RT_LightsNewMapEnd(map);
RT_LightsNewMap(map);
loadLights(map);
// TODO should we do something like VK_BrushEndLoad?
VK_UploadLightmap();

View File

@ -2021,6 +2021,8 @@ static void R_StudioDrawNormalMesh( short *ptricmds, vec3_t *pstudionorms, float
.index_offset = buffer.indices.unit_offset,
.element_count = num_indices,
.emissive = {0, 0, 0},
};
VK_RenderModelDynamicAddGeometry( &geometry );