diff --git a/ref/vk/vk_brush.c b/ref/vk/vk_brush.c index 55718079..ad1dfd59 100644 --- a/ref/vk/vk_brush.c +++ b/ref/vk/vk_brush.c @@ -459,8 +459,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 ) { @@ -482,39 +480,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 = R_VkPatchGetSurface(i); - 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; @@ -556,30 +526,6 @@ 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); - } - } - } - ++num_geometries; //gEngine.Con_Reportf( "surface %d: numverts=%d numedges=%d\n", i, surf->polys ? surf->polys->numverts : -1, surf->numedges ); @@ -680,10 +626,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; @@ -691,10 +635,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; } @@ -711,7 +653,6 @@ qboolean VK_BrushModelLoad( model_t *mod, qboolean map ) 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); @@ -719,9 +660,6 @@ qboolean VK_BrushModelLoad( model_t *mod, qboolean map ) 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); - if (!loadBrushSurfaces(sizes, mod) || !VK_RenderModelInit(&bmodel->render_model)) { gEngine.Con_Printf(S_ERROR "Could not load model %s\n", mod->name); Mem_Free(bmodel); @@ -745,8 +683,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; } @@ -757,3 +693,83 @@ 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; + + 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? + const xvk_patch_surface_t *const psurf = R_VkPatchGetSurface(surface_index); + + vec3_t emissive; + if ((psurf && (psurf->flags & Patch_Surface_Emissive)) || (RT_GetEmissiveForTexture(emissive, tex_id))) { + 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); + + 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); + } + + 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); + if (!is_worldmodel) { + bmodel->render_model.dynamic_polylights[i] = polylight; + } else { + RT_LightAddPolygon(&polylight); + } + } + + gEngine.Con_Reportf("Loaded %d polylights for %smodel %s\n", emissive_surfaces_count, is_worldmodel ? "world" : "movable ", mod->name); +} diff --git a/ref/vk/vk_brush.h b/ref/vk/vk_brush.h index 0f2d72ba..e55565a5 100644 --- a/ref/vk/vk_brush.h +++ b/ref/vk/vk_brush.h @@ -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 ); diff --git a/ref/vk/vk_light.c b/ref/vk/vk_light.c index 41e7cac6..c840b3d9 100644 --- a/ref/vk/vk_light.c +++ b/ref/vk/vk_light.c @@ -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 ); diff --git a/ref/vk/vk_light.h b/ref/vk/vk_light.h index 6d83c0a5..53b104be 100644 --- a/ref/vk/vk_light.h +++ b/ref/vk/vk_light.h @@ -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 ); diff --git a/ref/vk/vk_ray_model.c b/ref/vk/vk_ray_model.c index a82748eb..9c1bd6b1 100644 --- a/ref/vk/vk_ray_model.c +++ b/ref/vk/vk_ray_model.c @@ -267,6 +267,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 +545,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 +559,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 diff --git a/ref/vk/vk_render.c b/ref/vk/vk_render.c index 2c41addd..ae6d7b1d 100644 --- a/ref/vk/vk_render.c +++ b/ref/vk/vk_render.c @@ -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); } } diff --git a/ref/vk/vk_render.h b/ref/vk/vk_render.h index ca3a2d98..f70f39be 100644 --- a/ref/vk/vk_render.h +++ b/ref/vk/vk_render.h @@ -59,10 +59,6 @@ typedef struct vk_render_geometry_s { 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; diff --git a/ref/vk/vk_rtx.c b/ref/vk/vk_rtx.c index 05ed3ecb..83bcf416 100644 --- a/ref/vk/vk_rtx.c +++ b/ref/vk/vk_rtx.c @@ -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; diff --git a/ref/vk/vk_scene.c b/ref/vk/vk_scene.c index 6a67d3b5..9dac72d2 100644 --- a/ref/vk/vk_scene.c +++ b/ref/vk/vk_scene.c @@ -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();