Merge "Enable live reloading light data" #457
- [x] Fixes #417 - [x] Fixes #330 - [x] Fixes #104
This commit is contained in:
commit
d1376a89e4
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in New Issue