Merge pull request #572 from w23/lol-materials

- [x] Pass material reference via geom/render API
- [x] Show original textures for traditional renderer, #571
- [x] Remove old material type flags
  - [x] ~~Move sky surfaces to a separate BLAS~~ Remove `SURF_DRAWSKY` from geometries completely #474 
  - [x] **REVERT** `SURF_DRAWSKY` changes. Such surfaces still need to be "drawn" to hide geometry behind it (see comments).
  - [x] Chrome material: have an explicit material for it
    - [x] This needs vk_texture vs vk_material index decoupling
- [x] Assess #577
- [x] Improve paths #578 
  - [x] `pbr/maps/c0a0a.bsp/c0a0a.bsp.mat` -> `pbr/maps/c0a0a.bsp/c0a0a.mat`
  - [x] `pbr/halflife.wad/halflife.wad.mat` -> `pbr/halflife.wad/halflife.mat`
  - [x] Rename files in PBR repo for the above
  - [x] `luchiki/maps/c0a0.bsp.patch` -> `luchiki/maps/c0a0.patch`
  - [x] Rename patch files too
  - [x] Same for spr,mdl
  - [x] Rename
- [x] Pass material mode directly, instead of render type
- [x] Advanced material patching/selection
  - [x] Need a few advanced selection examples
    - [x] #317
    - [x] стёкла у костюма (??)
  - [x] #526
  - [x] #577
  - [x] #213
This commit is contained in:
Ivan Avdeev 2023-10-02 07:54:10 -07:00 committed by GitHub
commit 737cd944bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 649 additions and 168 deletions

View File

@ -398,3 +398,192 @@ TODO: can we not have a BLAS/model for each submodel? Can it be per-model instea
# 2023-07-30
- ~~R_DrawStudioModel is the main func for drawing studio model. Called from scene code for each studio entity, with everything current (RI and stuff) set up~~
- `R_StudioDrawModelInternal()` is the main one. It is where it splits into renderer-vs-game rendering functions.
# 2023-09-19 E298
## SURF_DRAWSKY
- (context: want to remove kXVkMaterialSky, #474)
- qrad:
- uses textue name "sky" or "SKY" to check `IsSky()`. `IsSky()` surfaces do not get patches and do not participate in radiosity.
- uses CONTENTS_SKY node flag to detect whether a ray has hit skybox and can contribute sky light.
- xash/gl:
- CONTENTS_SKY is not used in any meaningful way
- sets SURF_DRAWSKY for surfaces with "sky" texture.
- uses SURF_DRAWSKY:
- to build skychain, and then draw it in Quake mode (the other branch does a bunch of math, which seemingly isn't used for anything at all).
- for dynamic lighting: if sky ray has hit sky surface then sky is contributing light
# 2023-09-25 #301
## Materials format
Define new material, independently of any existing textures, etc
This can be .vmat compatible, primext compatbile, etc.
The important parts:
- It has a unique name that we can reference it with
- It has all the fields that we use for our PBR shading model
- (? Material mode can be specified)
```
{
"material" "MAT_NAME"
"map_base_color" "base.png"
"map_normal" "irregular.ktx2"
"base_color" "1 .5 0"
// ...
}
{
"material" "mirror"
"map_base_color" "white"
"base_color" "1 1 1"
"roughness" "0"
"metalness" "1"
// ...
}
```
Then, we can map existing textures to new materials:
```
{
"for_texture" "+EXIT"
"use" "MAT_NAME"
}
```
Or, with more context:
```
{
"for_model_type" "brush"
"for_rendermode" "kRenderTransAlpha"
"for_texture" "wood"
"use" "mat_glass"
"mode" "translucent"
"map_base_color" "glass2.ktx"
}
// ??? meh, see the better _xvk_ example below
{
"for_model_type" "brush"
"for_surface_id" "584"
"use" "mirror"
}
// This example: use previously specified material (e.g. via _xvk stuff below)
// (Depends on applying multiple matching rules, see questions below)
{
"for_model_type" "brush"
"for_rendermode" "kRenderTransAlpha"
"mode" "translucent"
"map_normal" "glass2.ktx"
}
// We also want this (for maps, not globally ofc), see https://github.com/w23/xash3d-fwgs/issues/526
{
"for_entity_id" "39"
"for_texture" "generic028"
"use" "generic_metal1"
}
{
"for_entity_id" "39"
"for_texture" "generic029"
"use" "generic_metal2"
}
```
What it does is:
1. If all `"for_"` fields match, apply values from `"use"` material (in this case `"wood"`)
2. Additionally, override any extra fields/values with ones specified in this block
As we already have surface-patching ability, can just use that for patching materials directly for brush surfaces:
```
// mirror in toilet
{
"_xvk_surface_id" "2057"
"_xvk_material" "mirror"
}
```
Questions:
- Should it apply the first found rule that matches a given geometry and stop?
Or should it apply updates to the material using all the rules that matched in their specified order? Doing the first rule and stopping is more readable and perofrmant, but also might be verbose in some cases.
- Should we do "automatic" materials? I.e. if there's no manually specified material for a texture named `"<TEX>"`, then we try to load `"<TEX>_basecolor.ktx"`, `"<TEX>_normalmap.ktx"`, etc automatically.
# 2023-09-26 E302
Map loading sequence
```
[2023:09:26|11:30:31] Couldn't open file overviews/c1a0d.txt. Using default values for overiew mode.
[2023:09:26|11:30:31] CL_SignonReply: 2
[2023:09:26|11:30:31] Signon network traffic: 10.380 Kb from server, 349 bytes to server
[2023:09:26|11:30:31] client connected at 0.07 sec
[2023:09:26|11:30:31] Error: SDL_GL_SetSwapInterval: No OpenGL context has been made current
[2023:09:26|11:30:31] vk: Mod_ProcessRenderData(sprites/640_pain.spr, create=1)
[2023:09:26|11:30:43] Loading game from save/autosave01.sav...
[2023:09:26|11:30:43] Spawn Server: c2a5
[2023:09:26|11:30:43] vk: Mod_ProcessRenderData(maps/c1a0d.bsp, create=0)
[2023:09:26|11:30:43] Warning: VK FIXME Trying to unload brush model maps/c1a0d.bsp
[2023:09:26|11:30:43] Error: VK NOT_IMPLEMENTED(x0): RT_KusochkiFree
[2023:09:26|11:30:43] loading maps/c2a5.bsp
[2023:09:26|11:30:43] Warning: FS_LoadImage: couldn't load "alpha_sky"
[2023:09:26|11:30:43] Warning: FS_LoadImage: couldn't load "solid_sky"
[2023:09:26|11:30:43] lighting: colored
[2023:09:26|11:30:43] Wad files required to run the map: "halflife.wad; liquids.wad; xeno.wad"
[2023:09:26|11:30:43] vk: Mod_ProcessRenderData(maps/c2a5.bsp, create=1)
[2023:09:26|11:30:43] Loading game from save/c2a5.HL1...
[2023:09:26|11:30:43]
GAME SKILL LEVEL:1
[2023:09:26|11:30:43] Loading CGraph in GRAPH_VERSION 16 compatibility mode
[2023:09:26|11:30:43] Loading CLink array in GRAPH_VERSION 16 compatibility mode
[2023:09:26|11:30:43]
*Graph Loaded!
[2023:09:26|11:30:43] **Graph Pointers Set!
[2023:09:26|11:30:43] loading sprites/flare1.spr
[2023:09:26|11:30:43] vk: Mod_ProcessRenderData(sprites/flare1.spr, create=1)
.. more Mod_ProcessRenderData
.. and only then R_NewMap
```
# 2023-09-28 E303
## #526
Replace textures for specific brush entities.
For a single texture it might be as easy as:
```
{
"_xvk_ent_id" "39"
"_xvk_texture" "generic028"
"_xvk_material" "generic_metal1"
}
```
For multiple replacements:
0. Multiple entries
```
{
"_xvk_ent_id" "39"
"_xvk_texture" "generic028"
"_xvk_material" "generic_metal1"
}
{
"_xvk_ent_id" "39"
"_xvk_texture" "generic029"
"_xvk_material" "generic_metal2"
}
```
1. Pairwise
```
{
"_xvk_ent_id" "39"
"_xvk_texture" "generic028 generic029 ..."
"_xvk_material" "generic_metal1 generic_metal2 ..."
}
```
2. Pair list <-- preferred
```
{
"_xvk_ent_id" "39"
"_xvk_texture_material" "generic028 generic_metal1 generic029 generic_metal2 ... ..."
}
```

View File

@ -76,6 +76,7 @@ void main() {
;
rayQueryInitializeEXT(rq, tlas, flags, GEOMETRY_BIT_OPAQUE | GEOMETRY_BIT_ALPHA_TEST | GEOMETRY_BIT_REFRACTIVE, ray.origin, 0., ray.direction, ray.dist);
while (rayQueryProceedEXT(rq)) {
// FIXME this is a no-op. It doesn't do what I though it did. Should check for SBT index for alpha-test material instead.
if (0 != (rayQueryGetRayFlagsEXT(rq) & gl_RayFlagsOpaqueEXT))
continue;
@ -104,6 +105,9 @@ void main() {
//debug_geometry_index = rayQueryGetIntersectionPrimitiveIndexEXT(rq, true);
primaryRayHit(rq, payload);
L = rayQueryGetIntersectionTEXT(rq, true);
} else {
// Draw skybox when nothing is hit
payload.emissive.rgb = SRGBtoLINEAR(texture(skybox, ray.direction).rgb);
}
traceSimpleBlending(ray.origin, ray.direction, L, payload.emissive.rgb, payload.base_color_a.rgb);

View File

@ -275,9 +275,12 @@ static void brushComputeWaterPolys( compute_water_polys_t args ) {
// Render
const int tex_id = args.warp->texinfo->texture->gl_texturenum;
const r_vk_material_t material = R_VkMaterialGetForTexture(tex_id);
*args.dst_geometry = (vk_render_geometry_t){
.texture = tex_id, // FIXME assert >= 0
.material = kXVkMaterialRegular,
.material = material,
.ye_olde_texture = tex_id,
.surf_deprecate = args.warp,
.max_vertex = vertices,
@ -531,6 +534,33 @@ static qboolean brushCreateWaterModel(const model_t *mod, vk_brush_model_t *bmod
return true;
}
material_mode_e brushMaterialModeForRenderType(vk_render_type_e render_type) {
switch (render_type) {
case kVkRenderTypeSolid:
return kMaterialMode_Opaque;
break;
case kVkRenderType_A_1mA_RW: // blend: scr*a + dst*(1-a), depth: RW
case kVkRenderType_A_1mA_R: // blend: scr*a + dst*(1-a), depth test
return kMaterialMode_Translucent;
break;
case kVkRenderType_A_1: // blend: scr*a + dst, no depth test or write; sprite:kRenderGlow only
return kMaterialMode_BlendGlow;
break;
case kVkRenderType_A_1_R: // blend: scr*a + dst, depth test
case kVkRenderType_1_1_R: // blend: scr + dst, depth test
return kMaterialMode_BlendAdd;
break;
case kVkRenderType_AT: // no blend, depth RW, alpha test
return kMaterialMode_AlphaTest;
break;
default:
gEngine.Host_Error("Unexpected render type %d\n", render_type);
}
return kMaterialMode_Opaque;
}
static void brushDrawWater(vk_brush_model_t *bmodel, const cl_entity_t *ent, int render_type, const vec4_t color, const matrix4x4 transform) {
APROF_SCOPE_DECLARE_BEGIN(brush_draw_water, __FUNCTION__);
ASSERT(bmodel->water.surfaces_count > 0);
@ -540,8 +570,10 @@ static void brushDrawWater(vk_brush_model_t *bmodel, const cl_entity_t *ent, int
ERR("Failed to update brush model \"%s\" water", bmodel->render_model.debug_name);
}
const material_mode_e material_mode = brushMaterialModeForRenderType(render_type);
R_RenderModelDraw(&bmodel->water.render_model, (r_model_draw_t){
.render_type = render_type,
.material_mode = material_mode,
.color = (const vec4_t*)color,
.transform = (const matrix4x4*)transform,
.prev_transform = &bmodel->prev_transform,
@ -704,7 +736,8 @@ void VK_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, co
// TODO also it will break switching render type from TransColor to anyting else -- textures will be stuck at white
for (int i = 0; i < bmodel->render_model.num_geometries; ++i) {
vk_render_geometry_t *geom = bmodel->render_model.geometries + i;
geom->texture = tglob.whiteTexture;
geom->material = R_VkMaterialGetForTexture(tglob.whiteTexture);
geom->ye_olde_texture = tglob.whiteTexture;
}
} else {
APROF_SCOPE_DECLARE_BEGIN(brush_update_textures, "brush: update animated textures");
@ -719,10 +752,11 @@ void VK_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, co
// Optionally patch by texture_s pointer and run animations
const struct texture_s *texture_override = patch_surface ? patch_surface->tex : NULL;
const texture_t *t = R_TextureAnimation(ent, geom->surf_deprecate, texture_override);
const int new_texture = t->gl_texturenum;
const int new_tex_id = t->gl_texturenum;
if (new_texture >= 0 && new_texture != geom->texture) {
geom->texture = t->gl_texturenum;
if (new_tex_id >= 0 && new_tex_id != geom->ye_olde_texture) {
geom->ye_olde_texture = new_tex_id;
geom->material = R_VkMaterialGetForTexture(new_tex_id);
if (updated_textures_count < MAX_ANIMATED_TEXTURES) {
g_brush.updated_textures[updated_textures_count++] = bmodel->animated_indexes[i];
}
@ -732,7 +766,7 @@ void VK_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, co
// Add them as dynamic lights for now. It would probably be better if they were static lights (for worldmodel),
// but there's no easy way to do it for now.
vec3_t *emissive = &bmodel->render_model.geometries[geom_index].emissive;
if (RT_GetEmissiveForTexture(*emissive, geom->texture)) {
if (RT_GetEmissiveForTexture(*emissive, new_tex_id)) {
rt_light_add_polygon_t polylight = loadPolyLight(mod, surface_index, geom->surf_deprecate, *emissive);
polylight.dynamic = true;
polylight.transform_row = (const matrix3x4*)&transform;
@ -746,8 +780,10 @@ void VK_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, co
APROF_SCOPE_END(brush_update_textures);
}
const material_mode_e material_mode = brushMaterialModeForRenderType(render_type);
R_RenderModelDraw(&bmodel->render_model, (r_model_draw_t){
.render_type = render_type,
.material_mode = material_mode,
.color = &color,
.transform = &transform,
.prev_transform = &bmodel->prev_transform,
@ -1017,6 +1053,17 @@ static qboolean getSmoothedNormalFor(const model_t* mod, int vertex_index, int s
return true;
}
static const xvk_mapent_func_any_t *getModelFuncAnyPatch( const model_t *const mod ) {
for (int i = 0; i < g_map_entities.func_any_count; ++i) {
const xvk_mapent_func_any_t *const fw = g_map_entities.func_any + i;
if (Q_strcmp(mod->name, fw->model) == 0) {
return fw;
}
}
return NULL;
}
static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
int vertex_offset = 0;
int num_geometries = 0;
@ -1028,6 +1075,8 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
connectVertices(args.mod);
const xvk_mapent_func_any_t *const entity_patch = getModelFuncAnyPatch(args.mod);
// Load sorted by gl_texturenum
// TODO this does not make that much sense in vulkan (can sort later)
for (int t = 0; t <= args.sizes.max_texture_id; ++t) {
@ -1039,12 +1088,12 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
const float sample_size = gEngine.Mod_SampleSizeForFace( surf );
int index_count = 0;
vec3_t tangent;
int tex_id = surf->texinfo->texture->gl_texturenum;
const xvk_patch_surface_t *const psurf = R_VkPatchGetSurface(surface_index);
if (t != tex_id)
const int orig_tex_id = surf->texinfo->texture->gl_texturenum;
if (t != orig_tex_id)
continue;
int tex_id = orig_tex_id;
const xvk_patch_surface_t *const psurf = R_VkPatchGetSurface(surface_index);
if (psurf && psurf->tex_id >= 0)
tex_id = psurf->tex_id;
@ -1072,20 +1121,41 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
return false;
}
qboolean material_assigned = false;
if (entity_patch) {
for (int i = 0; i < entity_patch->matmap_count; ++i) {
if (entity_patch->matmap[i].from_tex == tex_id) {
model_geometry->material = R_VkMaterialGetForTexture(entity_patch->matmap[i].to_mat.index);
material_assigned = true;
break;
}
}
if (!material_assigned && entity_patch->rendermode > 0) {
model_geometry->material = R_VkMaterialGetEx(tex_id, entity_patch->rendermode);
material_assigned = true;
}
}
if (!material_assigned) {
model_geometry->material = R_VkMaterialGetForTexture(tex_id);
material_assigned = true;
}
VectorClear(model_geometry->emissive);
model_geometry->surf_deprecate = surf;
model_geometry->texture = tex_id;
model_geometry->ye_olde_texture = orig_tex_id;
model_geometry->vertex_offset = args.base_vertex_offset;
model_geometry->max_vertex = vertex_offset + surf->numedges;
model_geometry->index_offset = index_offset;
if(type == BrushSurface_Sky) {
model_geometry->material = kXVkMaterialSky;
if ( type == BrushSurface_Sky ) {
#define TEX_BASE_SKYBOX 0xffffffffu // FIXME ray_interop.h
model_geometry->material.tex_base_color = TEX_BASE_SKYBOX;
} else {
model_geometry->material = kXVkMaterialRegular;
ASSERT(!FBitSet( surf->flags, SURF_DRAWTILED ));
VK_CreateSurfaceLightmap( surf, args.mod );
}
@ -1196,17 +1266,6 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
return true;
}
static const xvk_mapent_func_wall_t *getModelFuncWallPatch( const model_t *const mod ) {
for (int i = 0; i < g_map_entities.func_walls_count; ++i) {
const xvk_mapent_func_wall_t *const fw = g_map_entities.func_walls + i;
if (Q_strcmp(mod->name, fw->model) == 0) {
return fw;
}
}
return NULL;
}
static qboolean createRenderModel( const model_t *mod, vk_brush_model_t *bmodel, const model_sizes_t sizes ) {
bmodel->geometry = R_GeometryRangeAlloc(sizes.num_vertices, sizes.num_indices);
if (!bmodel->geometry.block_handle.size) {
@ -1376,8 +1435,8 @@ void R_VkBrushModelCollectEmissiveSurfaces( const struct model_s *mod, qboolean
vk_brush_model_t *const bmodel = mod->cache.data;
ASSERT(bmodel);
const xvk_mapent_func_wall_t *func_wall = getModelFuncWallPatch(mod);
const qboolean is_static = is_worldmodel || func_wall;
const xvk_mapent_func_any_t *func_any = getModelFuncAnyPatch(mod);
const qboolean is_static = is_worldmodel || (func_any && func_any->origin_patched);
typedef struct {
int model_surface_index;
@ -1449,14 +1508,14 @@ void R_VkBrushModelCollectEmissiveSurfaces( const struct model_s *mod, qboolean
rt_light_add_polygon_t polylight = loadPolyLight(mod, s->surface_index, s->surf, s->emissive);
// func_wall surfaces do not really belong to BSP+PVS system, so they can't be used
// func_any surfaces do not really belong to BSP+PVS system, so they can't be used
// for lights visibility calculation directly.
if (func_wall) {
if (func_any && func_any->origin_patched) {
// TODO this is not really dynamic, but this flag signals using MovingSurface visibility calc
polylight.dynamic = true;
matrix3x4 m;
Matrix3x4_LoadIdentity(m);
Matrix3x4_SetOrigin(m, func_wall->origin[0], func_wall->origin[1], func_wall->origin[2]);
Matrix3x4_SetOrigin(m, func_any->origin[0], func_any->origin[1], func_any->origin[2]);
polylight.transform_row = &m;
}

View File

@ -16,6 +16,8 @@ static const struct log_pair_t {
{"mat", LogModule_Material},
{"meat", LogModule_Meatpipe},
{"rt", LogModule_RT},
{"rmain", LogModule_RMain},
{"sprite", LogModule_Sprite},
};
void VK_LogsReadCvar(void) {

View File

@ -12,6 +12,8 @@ enum {
LogModule_Material = (1<<6),
LogModule_Meatpipe = (1<<7),
LogModule_RT = (1<<8),
LogModule_RMain = (1<<9),
LogModule_Sprite = (1<<10),
};
extern uint32_t g_log_debug_bits;

View File

@ -138,8 +138,8 @@ static unsigned parseEntPropClassname(const char* value, class_name_e *out, unsi
*out = LightEnvironment;
} else if (Q_strcmp(value, "worldspawn") == 0) {
*out = Worldspawn;
} else if (Q_strcmp(value, "func_wall") == 0) {
*out = FuncWall;
} else if (Q_strncmp(value, "func_", 5) == 0) {
*out = FuncAny;
} else {
*out = Ignored;
}
@ -339,20 +339,35 @@ static void readWorldspawn( const entity_props_t *props ) {
};
}
static void readFuncWall( const entity_props_t *const props, uint32_t have_fields, int props_count ) {
DEBUG("func_wall entity=%d model=\"%s\", props_count=%d", g_map_entities.entity_count, (have_fields & Field_model) ? props->model : "N/A", props_count);
int R_VkRenderModeFromString( const char *s ) {
#define CHECK_IF_MODE(mode) if (Q_strcmp(s, #mode) == 0) { return mode; }
CHECK_IF_MODE(kRenderNormal)
else CHECK_IF_MODE(kRenderTransColor)
else CHECK_IF_MODE(kRenderTransTexture)
else CHECK_IF_MODE(kRenderGlow)
else CHECK_IF_MODE(kRenderTransAlpha)
else CHECK_IF_MODE(kRenderTransAdd)
return -1;
}
if (g_map_entities.func_walls_count >= MAX_FUNC_WALL_ENTITIES) {
ERR("Too many func_wall entities, max supported = %d", MAX_FUNC_WALL_ENTITIES);
static void readFuncAny( const entity_props_t *const props, uint32_t have_fields, int props_count ) {
DEBUG("func_any entity=%d model=\"%s\", props_count=%d", g_map_entities.entity_count, (have_fields & Field_model) ? props->model : "N/A", props_count);
if (g_map_entities.func_any_count >= MAX_FUNC_ANY_ENTITIES) {
ERR("Too many func_any entities, max supported = %d", MAX_FUNC_ANY_ENTITIES);
return;
}
xvk_mapent_func_wall_t *const e = g_map_entities.func_walls + g_map_entities.func_walls_count;
xvk_mapent_func_any_t *const e = g_map_entities.func_any + g_map_entities.func_any_count;
*e = (xvk_mapent_func_wall_t){0};
*e = (xvk_mapent_func_any_t){0};
e->rendermode = -1;
Q_strncpy( e->model, props->model, sizeof( e->model ));
if (have_fields & Field_rendermode)
e->rendermode = props->rendermode;
/* NOTE: not used
e->rendercolor.r = 255;
e->rendercolor.g = 255;
@ -364,9 +379,6 @@ static void readFuncWall( const entity_props_t *const props, uint32_t have_field
if (have_fields & Field_renderfx)
e->renderfx = props->renderfx;
if (have_fields & Field_rendermode)
e->rendermode = props->rendermode;
if (have_fields & Field_rendercolor) {
e->rendercolor.r = props->rendercolor[0];
e->rendercolor.g = props->rendercolor[1];
@ -376,10 +388,10 @@ static void readFuncWall( const entity_props_t *const props, uint32_t have_field
e->entity_index = g_map_entities.entity_count;
g_map_entities.refs[g_map_entities.entity_count] = (xvk_mapent_ref_t){
.class = FuncWall,
.index = g_map_entities.func_walls_count,
.class = FuncAny,
.index = g_map_entities.func_any_count,
};
++g_map_entities.func_walls_count;
++g_map_entities.func_any_count;
}
static void addPatchSurface( const entity_props_t *props, uint32_t have_fields ) {
@ -483,15 +495,67 @@ static void patchLightEntity( const entity_props_t *props, int ent_id, uint32_t
fillLightFromProps(light, props, have_fields, true, ent_id);
}
static void patchFuncWallEntity( const entity_props_t *props, uint32_t have_fields, int index ) {
static void patchFuncAnyEntity( const entity_props_t *props, uint32_t have_fields, int index ) {
ASSERT(index >= 0);
ASSERT(index < g_map_entities.func_walls_count);
xvk_mapent_func_wall_t *const fw = g_map_entities.func_walls + index;
ASSERT(index < g_map_entities.func_any_count);
xvk_mapent_func_any_t *const e = g_map_entities.func_any + index;
if (have_fields & Field_origin)
VectorCopy(props->origin, fw->origin);
if (have_fields & Field_origin) {
VectorCopy(props->origin, e->origin);
e->origin_patched = true;
DEBUG("Patching ent=%d func_wall=%d %f %f %f", fw->entity_index, index, fw->origin[0], fw->origin[1], fw->origin[2]);
DEBUG("Patching ent=%d func_any=%d %f %f %f", e->entity_index, index, e->origin[0], e->origin[1], e->origin[2]);
}
if (have_fields & Field__xvk_map_material) {
const char *s = props->_xvk_map_material;
while (*s) {
while (*s && isspace(*s)) ++s; // skip space
const char *from_begin = s;
while (*s && !isspace(*s)) ++s; // find first space or end
const int from_len = s - from_begin;
if (!from_len)
break;
while (*s && isspace(*s)) ++s; // skip space
const char *to_begin = s;
while (*s && !isspace(*s)) ++s; // find first space or end
const int to_len = s - to_begin;
if (!to_len)
break;
string from_tex, to_mat;
Q_strncpy(from_tex, from_begin, Q_min(sizeof from_tex, from_len + 1));
Q_strncpy(to_mat, to_begin, Q_min(sizeof to_mat, to_len + 1));
const int from_tex_index = XVK_FindTextureNamedLike(from_tex);
const r_vk_material_ref_t to_mat_ref = R_VkMaterialGetForName(to_mat);
DEBUG("Adding mapping from tex \"%s\"(%d) to mat \"%s\"(%d) for entity=%d",
from_tex, from_tex_index, to_mat, to_mat_ref.index, e->entity_index);
if (from_tex_index <= 0) {
ERR("When patching entity=%d couldn't find map-from texture \"%s\"", e->entity_index, from_tex);
continue;
}
if (to_mat_ref.index <= 0) {
ERR("When patching entity=%d couldn't find map-to material \"%s\"", e->entity_index, to_mat);
continue;
}
if (e->matmap_count == MAX_MATERIAL_MAPPINGS) {
ERR("Cannot map tex \"%s\"(%d) to mat \"%s\"(%d) for entity=%d: too many mappings, "
"consider increasing MAX_MATERIAL_MAPPINGS",
from_tex, from_tex_index, to_mat, to_mat_ref.index, e->entity_index);
continue;
}
e->matmap[e->matmap_count].from_tex = from_tex_index;
e->matmap[e->matmap_count].to_mat = to_mat_ref;
++e->matmap_count;
}
}
}
static void patchEntity( const entity_props_t *props, uint32_t have_fields ) {
@ -511,8 +575,8 @@ static void patchEntity( const entity_props_t *props, uint32_t have_fields ) {
case LightEnvironment:
patchLightEntity(props, ei, have_fields, ref->index);
break;
case FuncWall:
patchFuncWallEntity(props, have_fields, ref->index);
case FuncAny:
patchFuncAnyEntity(props, have_fields, ref->index);
break;
default:
WARN("vk_mapents: trying to patch unsupported entity %d class %d", ei, ref->class);
@ -593,8 +657,8 @@ static void parseEntities( char *string, qboolean is_patch ) {
readWorldspawn( &values );
break;
case FuncWall:
readFuncWall( &values, have_fields, props_count );
case FuncAny:
readFuncAny( &values, have_fields, props_count );
break;
case Unknown:
@ -699,7 +763,22 @@ static void parsePatches( const model_t *const map ) {
g_patch.surfaces_count = 0;
}
Q_snprintf(filename, sizeof(filename), "luchiki/%s.patch", map->name);
{
const char *ext = NULL;
// Find extension (if any)
{
const char *p = map->name;
for(; *p; ++p)
if (*p == '.')
ext = p;
if (!ext)
ext = p;
}
Q_snprintf(filename, sizeof(filename), "luchiki/%.*s.patch", (int)(ext - map->name), map->name);
}
DEBUG("Loading patches from file \"%s\"", filename);
data = gEngine.fsapi->LoadFile( filename, 0, false );
if (!data) {
@ -720,7 +799,7 @@ void XVK_ParseMapEntities( void ) {
g_map_entities.num_lights = 0;
g_map_entities.single_environment_index = NoEnvironmentLights;
g_map_entities.entity_count = 0;
g_map_entities.func_walls_count = 0;
g_map_entities.func_any_count = 0;
g_map_entities.smoothing.threshold = cosf(DEG2RAD(45.f));
g_map_entities.smoothing.excluded_count = 0;
for (int i = 0; i < g_map_entities.smoothing.groups_count; ++i)

View File

@ -1,8 +1,13 @@
#pragma once
#include "vk_materials.h"
#include "xash3d_types.h"
#include "const.h" // typedef word, needed for bspfile.h
#include "bspfile.h" // MAX_MAP_ENTITIES
// TODO string_view instead of string. map entities string/buffer is supposed to be alive for the entire map duration
// NOTE that the above is not true for string in patches. but we can change that in parsePatches
#define ENT_PROP_LIST(X) \
X(0, vec3_t, origin, Vec3) \
X(1, vec3_t, angles, Vec3) \
@ -29,9 +34,10 @@
X(22, float, _xvk_smoothing_threshold, Float) \
X(23, int_array_t, _xvk_smoothing_excluded_pairs, IntArray) \
X(24, int_array_t, _xvk_smoothing_group, IntArray) \
X(25, string, _xvk_map_material, String) \
X(26, int, rendermode, Int) \
/* NOTE: not used
X(22, int, rendermode, Int) \
X(23, int, renderamt, Int) \
X(24, vec3_t, rendercolor, Vec3) \
X(25, int, renderfx, Int) \
@ -44,7 +50,7 @@ typedef enum {
LightSpot,
LightEnvironment,
Worldspawn,
FuncWall,
FuncAny,
Ignored,
Xvk_Target,
} class_name_e;
@ -99,13 +105,24 @@ typedef struct {
string model;
vec3_t origin;
qboolean origin_patched;
#define MAX_MATERIAL_MAPPINGS 8
int matmap_count;
struct {
int from_tex;
r_vk_material_ref_t to_mat;
} matmap[MAX_MATERIAL_MAPPINGS];
int rendermode;
/* NOTE: not used. Might be needed for #118 in the future.
int rendermode, renderamt, renderfx;
int renderamt, renderfx;
color24 rendercolor;
struct cl_entity_s *ent;
*/
} xvk_mapent_func_wall_t;
} xvk_mapent_func_any_t;
typedef struct {
class_name_e class;
@ -130,9 +147,9 @@ typedef struct {
int num_targets;
xvk_mapent_target_t targets[MAX_MAPENT_TARGETS];
#define MAX_FUNC_WALL_ENTITIES 64
int func_walls_count;
xvk_mapent_func_wall_t func_walls[MAX_FUNC_WALL_ENTITIES];
#define MAX_FUNC_ANY_ENTITIES 1024
int func_any_count;
xvk_mapent_func_any_t func_any[MAX_FUNC_ANY_ENTITIES];
// TODO find out how to read this from the engine, or make its size dynamic
//#define MAX_MAP_ENTITIES 2048
@ -188,3 +205,5 @@ typedef struct {
const xvk_patch_surface_t* R_VkPatchGetSurface( int surface_index );
// -1 if failed
int R_VkRenderModeFromString( const char *s );

View File

@ -11,7 +11,7 @@
#define MAX_INCLUDE_DEPTH 4
static xvk_material_t k_default_material = {
static r_vk_material_t k_default_material = {
.tex_base_color = -1,
.tex_metalness = 0,
.tex_roughness = 0,
@ -25,8 +25,19 @@ static xvk_material_t k_default_material = {
.set = false,
};
#define MAX_RENDERMODE_MATERIALS 32
typedef struct {
struct {
int tex_id;
r_vk_material_t mat;
} materials[MAX_RENDERMODE_MATERIALS];
int count;
} r_vk_material_per_mode_t;
static struct {
xvk_material_t materials[MAX_TEXTURES];
r_vk_material_t materials[MAX_TEXTURES];
r_vk_material_per_mode_t rendermode[kRenderTransAdd+1];
} g_materials;
static struct {
@ -70,7 +81,7 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
g_stats.material_file_read_duration_ns += aprof_time_now_ns() - load_file_begin_ns;
char *pos = (char*)data;
xvk_material_t current_material = k_default_material;
r_vk_material_t current_material = k_default_material;
int current_material_index = -1;
qboolean force_reload = false;
qboolean create = false;
@ -78,7 +89,9 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
string basecolor_map, normal_map, metal_map, roughness_map;
DEBUG("Loading materials from %s", filename);
int rendermode = 0;
DEBUG("Loading materials from %s (exists=%d)", filename, data != 0);
if ( !data )
return;
@ -105,6 +118,7 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
create = false;
metalness_set = false;
basecolor_map[0] = normal_map[0] = metal_map[0] = roughness_map[0] = '\0';
rendermode = 0;
continue;
}
@ -146,8 +160,28 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
DEBUG("Creating%s material for texture %s(%d)", create?" new":"",
findTexture(current_material_index)->name, current_material_index);
g_materials.materials[current_material_index] = current_material;
g_materials.materials[current_material_index].set = true;
// Assign rendermode-specific materials
if (rendermode > 0) {
r_vk_material_per_mode_t* const rm = g_materials.rendermode + rendermode;
if (rm->count == COUNTOF(rm->materials)) {
ERR("Too many rendermode/tex_id mappings");
continue;
}
DEBUG("Adding material %d for rendermode %d", current_material_index, rendermode);
// TODO proper texid-vs-material-index
rm->materials[rm->count].tex_id = current_material_index;
rm->materials[rm->count].mat = current_material;
rm->materials[rm->count].mat.set = true;
rm->count++;
} else {
DEBUG("Creating%s material for texture %s(%d)", create?" new":"",
findTexture(current_material_index)->name, current_material_index);
g_materials.materials[current_material_index] = current_material;
g_materials.materials[current_material_index].set = true;
}
continue;
}
@ -193,6 +227,11 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
sscanf(value, "%f", &current_material.normal_scale);
} else if (Q_stricmp(key, "base_color") == 0) {
sscanf(value, "%f %f %f %f", &current_material.base_color[0], &current_material.base_color[1], &current_material.base_color[2], &current_material.base_color[3]);
} else if (Q_stricmp(key, "for_rendermode") == 0) {
rendermode = R_VkRenderModeFromString(value);
if (rendermode < 0)
ERR("Invalid rendermode \"%s\"", value);
ASSERT(rendermode < COUNTOF(g_materials.rendermode[0].materials));
} else {
ERR("Unknown material key \"%s\" on line `%.*s`", key, (int)(pos - line_begin), line_begin);
continue;
@ -215,15 +254,30 @@ static void loadMaterialsFromFileF( const char *fmt, ... ) {
loadMaterialsFromFile( buffer, MAX_INCLUDE_DEPTH );
}
void XVK_ReloadMaterials( void ) {
static int findFilenameExtension(const char *s, int len) {
if (len < 0)
len = Q_strlen(s);
for (int i = len - 1; i >= 0; --i) {
if (s[i] == '.')
return i;
}
return len;
}
void R_VkMaterialsReload( void ) {
memset(&g_stats, 0, sizeof(g_stats));
const uint64_t begin_time_ns = aprof_time_now_ns();
for (int i = 0; i < COUNTOF(g_materials.rendermode); ++i)
g_materials.rendermode[i].count = 0;
k_default_material.tex_metalness = tglob.blackTexture;
k_default_material.tex_roughness = tglob.whiteTexture;
for (int i = 0; i < MAX_TEXTURES; ++i) {
xvk_material_t *const mat = g_materials.materials + i;
r_vk_material_t *const mat = g_materials.materials + i;
const vk_texture_t *const tex = findTexture( i );
*mat = k_default_material;
@ -232,21 +286,32 @@ void XVK_ReloadMaterials( void ) {
}
loadMaterialsFromFile( "pbr/materials.mat", MAX_INCLUDE_DEPTH );
loadMaterialsFromFile( "pbr/models/models.mat", MAX_INCLUDE_DEPTH );
loadMaterialsFromFile( "pbr/sprites/sprites.mat", MAX_INCLUDE_DEPTH );
{
const char *wad = g_map_entities.wadlist;
for (; *wad;) {
const char *const wad_end = Q_strchr(wad, ';');
loadMaterialsFromFileF("pbr/%.*s/%.*s.mat", wad_end - wad, wad, wad_end - wad, wad);
for(const char *wad = g_map_entities.wadlist; *wad;) {
const char *wad_end = wad;
const char *ext = NULL;
while (*wad_end && *wad_end != ';') {
if (*wad_end == '.')
ext = wad_end;
++wad_end;
}
const int full_length = wad_end - wad;
// Length without extension
const int short_length = ext ? ext - wad : full_length;
loadMaterialsFromFileF("pbr/%.*s/%.*s.mat", full_length, wad, short_length, wad);
wad = wad_end + 1;
}
}
{
const model_t *map = gEngine.pfnGetModelByIndex( 1 );
loadMaterialsFromFileF("pbr/%s/%s.mat", map->name, COM_FileWithoutPath(map->name));
const char *filename = COM_FileWithoutPath(map->name);
const int no_ext_len = findFilenameExtension(filename, -1);
loadMaterialsFromFileF("pbr/%s/%.*s.mat", map->name, no_ext_len, filename);
}
// Print out statistics
@ -264,14 +329,50 @@ void XVK_ReloadMaterials( void ) {
}
}
xvk_material_t* XVK_GetMaterialForTextureIndex( int tex_index ) {
xvk_material_t *mat = NULL;
void R_VkMaterialsLoadForModel( const struct model_s* mod ) {
// Brush models are loaded separately
if (mod->type == mod_brush)
return;
const char *filename = COM_FileWithoutPath(mod->name);
const int no_ext_len = findFilenameExtension(filename, -1);
loadMaterialsFromFileF("pbr/%s/%.*s.mat", mod->name, no_ext_len, filename);
}
r_vk_material_t R_VkMaterialGetForTexture( int tex_index ) {
ASSERT(tex_index >= 0);
ASSERT(tex_index < MAX_TEXTURES);
mat = g_materials.materials + tex_index;
if (mat->base_color >= 0)
return mat;
return NULL;
return g_materials.materials[tex_index];
}
r_vk_material_ref_t R_VkMaterialGetForName( const char *name ) {
// TODO separate material table
// For now it depends on 1-to-1 mapping between materials and textures
return (r_vk_material_ref_t){.index = VK_FindTexture(name)};
}
r_vk_material_t R_VkMaterialGetForRef( r_vk_material_ref_t ref ) {
// TODO separate material table
// For now it depends on 1-to-1 mapping between materials and textures
ASSERT(ref.index >= 0);
ASSERT(ref.index < MAX_TEXTURES);
return g_materials.materials[ref.index];
}
r_vk_material_t R_VkMaterialGetEx( int tex_id, int rendermode ) {
DEBUG("Getting material for tex_id=%d rendermode=%d", tex_id, rendermode);
if (rendermode > 0) {
ASSERT(rendermode < COUNTOF(g_materials.rendermode));
const r_vk_material_per_mode_t* const mode = &g_materials.rendermode[rendermode];
for (int i = 0; i < mode->count; ++i) {
if (mode->materials[i].tex_id == tex_id)
return mode->materials[i].mat;
}
}
DEBUG("Fallback to regular tex_id=%d", tex_id);
return R_VkMaterialGetForTexture(tex_id);
}

View File

@ -2,7 +2,7 @@
#include "xash3d_types.h"
typedef struct {
typedef struct r_vk_material_s {
int tex_base_color;
int tex_roughness;
int tex_metalness;
@ -13,9 +13,22 @@ typedef struct {
float metalness;
float normal_scale;
// TODO this should be internal
qboolean set;
} xvk_material_t;
} r_vk_material_t;
void XVK_ReloadMaterials( void );
typedef struct { int index; } r_vk_material_ref_t;
xvk_material_t* XVK_GetMaterialForTextureIndex( int tex_index );
// Note: invalidates all previously issued material refs
// TODO: track "version" in high bits?
void R_VkMaterialsReload( void );
struct model_s;
void R_VkMaterialsLoadForModel( const struct model_s* mod );
r_vk_material_t R_VkMaterialGetForTexture( int tex_id );
r_vk_material_t R_VkMaterialGetEx( int tex_id, int rendermode );
r_vk_material_ref_t R_VkMaterialGetForName( const char *name );
r_vk_material_t R_VkMaterialGetForRef( r_vk_material_ref_t ref );

View File

@ -101,8 +101,8 @@ rt_kusochki_t RT_KusochkiAllocLong(int count);
uint32_t RT_KusochkiAllocOnce(int count);
void RT_KusochkiFree(const rt_kusochki_t*);
struct vk_render_geometry_s;
qboolean RT_KusochkiUpload(uint32_t kusochki_offset, const struct vk_render_geometry_s *geoms, int geoms_count, int override_texture_id, const vec4_t *override_color);
//struct vk_render_geometry_s;
//qboolean RT_KusochkiUpload(uint32_t kusochki_offset, const struct vk_render_geometry_s *geoms, int geoms_count, int override_texture_id, const vec4_t *override_color);
qboolean RT_DynamicModelInit(void);
void RT_DynamicModelShutdown(void);

View File

@ -25,9 +25,8 @@ typedef struct rt_model_s {
rt_kusochki_t kusochki;
} rt_model_t;
static void applyMaterialToKusok(vk_kusok_data_t* kusok, const vk_render_geometry_t *geom, int override_texture_id, const vec4_t override_color) {
const int tex_id = override_texture_id > 0 ? override_texture_id : geom->texture;
const xvk_material_t *const mat = XVK_GetMaterialForTextureIndex( tex_id );
static void applyMaterialToKusok(vk_kusok_data_t* kusok, const vk_render_geometry_t *geom, const r_vk_material_t *override_material, const vec4_t override_color) {
const r_vk_material_t *const mat = override_material ? override_material : &geom->material;
ASSERT(mat);
// TODO split kusochki into static geometry data and potentially dynamic material data
@ -57,15 +56,6 @@ static void applyMaterialToKusok(vk_kusok_data_t* kusok, const vk_render_geometr
kusok->material.base_color[2] *= override_color[2];
kusok->material.base_color[3] *= override_color[3];
}
// TODO should be patched by the Chrome material source itself to generate a static chrome material
const qboolean HACK_chrome = geom->material == kXVkMaterialChrome;
if (!mat->set && HACK_chrome)
kusok->material.tex_roughness = tglob.grayTexture;
// Purely static. Once a sky forever a sky.
if (geom->material == kXVkMaterialSky)
kusok->material.tex_base_color = TEX_BASE_SKYBOX;
}
// TODO utilize uploadKusochki([1]) to avoid 2 copies of staging code
@ -109,7 +99,7 @@ static qboolean uploadKusochkiSubset(const vk_ray_model_t *const model, const vk
// TODO this material mapping is context dependent. I.e. different entity types might need different ray tracing behaviours for
// same render_mode/type and even texture.
static uint32_t materialModeFromRenderType(vk_render_type_e render_type) {
uint32_t R_VkMaterialModeFromRenderType(vk_render_type_e render_type) {
switch (render_type) {
case kVkRenderTypeSolid:
return MATERIAL_MODE_OPAQUE;
@ -180,7 +170,7 @@ void RT_KusochkiFree(const rt_kusochki_t *kusochki) {
}
// TODO this function can't really fail. It'd mean that staging is completely broken.
qboolean RT_KusochkiUpload(uint32_t kusochki_offset, const struct vk_render_geometry_s *geoms, int geoms_count, int override_texture_id, const vec4_t *override_colors) {
qboolean RT_KusochkiUpload(uint32_t kusochki_offset, const struct vk_render_geometry_s *geoms, int geoms_count, const r_vk_material_t *override_material, const vec4_t *override_colors) {
const vk_staging_buffer_args_t staging_args = {
.buffer = g_ray_model_state.kusochki_buffer.buffer,
.offset = kusochki_offset * sizeof(vk_kusok_data_t),
@ -197,7 +187,7 @@ qboolean RT_KusochkiUpload(uint32_t kusochki_offset, const struct vk_render_geom
vk_kusok_data_t *const p = kusok_staging.ptr;
for (int i = 0; i < geoms_count; ++i) {
const vk_render_geometry_t *geom = geoms + i;
applyMaterialToKusok(p + i, geom, override_texture_id, override_colors ? override_colors[i] : NULL);
applyMaterialToKusok(p + i, geom, override_material, override_colors ? override_colors[i] : NULL);
}
R_VkStagingUnlock(kusok_staging.handle);
@ -222,7 +212,7 @@ struct rt_model_s *RT_ModelCreate(rt_model_create_t args) {
goto fail;
}
RT_KusochkiUpload(kusochki.offset, args.geometries, args.geometries_count, -1, NULL);
RT_KusochkiUpload(kusochki.offset, args.geometries, args.geometries_count, NULL, NULL);
{
rt_model_t *const ret = Mem_Malloc(vk_core.pool, sizeof(*ret));
@ -275,7 +265,7 @@ qboolean RT_ModelUpdateMaterials(struct rt_model_s *model, const struct vk_rende
const int offset = geom_indices[begin];
const int count = i - begin;
ASSERT(offset + count <= geometries_count);
if (!RT_KusochkiUpload(model->kusochki.offset + offset, geometries + offset, count, -1, NULL)) {
if (!RT_KusochkiUpload(model->kusochki.offset + offset, geometries + offset, count, NULL, NULL)) {
APROF_SCOPE_END(update_materials);
return false;
}
@ -288,7 +278,7 @@ qboolean RT_ModelUpdateMaterials(struct rt_model_s *model, const struct vk_rende
const int offset = geom_indices[begin];
const int count = geom_indices_count - begin;
ASSERT(offset + count <= geometries_count);
if (!RT_KusochkiUpload(model->kusochki.offset + offset, geometries + offset, count, -1, NULL)) {
if (!RT_KusochkiUpload(model->kusochki.offset + offset, geometries + offset, count, NULL, NULL)) {
APROF_SCOPE_END(update_materials);
return false;
@ -314,12 +304,12 @@ void RT_FrameAddModel( struct rt_model_s *model, rt_frame_add_model_t args ) {
uint32_t kusochki_offset = model->kusochki.offset;
if (args.override.textures > 0) {
if (args.override.material != NULL) {
kusochki_offset = RT_KusochkiAllocOnce(args.override.geoms_count);
if (kusochki_offset == ALO_ALLOC_FAILED)
return;
if (!RT_KusochkiUpload(kusochki_offset, args.override.geoms, args.override.geoms_count, args.override.textures, NULL)) {
if (!RT_KusochkiUpload(kusochki_offset, args.override.geoms, args.override.geoms_count, args.override.material, NULL)) {
gEngine.Con_Printf(S_ERROR "Couldn't upload kusochki for instanced model\n");
return;
}
@ -338,7 +328,7 @@ void RT_FrameAddModel( struct rt_model_s *model, rt_frame_add_model_t args ) {
draw_instance->blas_addr = model->blas_addr;
draw_instance->kusochki_offset = kusochki_offset;
draw_instance->material_mode = materialModeFromRenderType(args.render_type);
draw_instance->material_mode = args.material_mode;
Vector4Copy(*args.color, draw_instance->color);
Matrix3x4_Copy(draw_instance->transform_row, args.transform);
Matrix4x4_Copy(draw_instance->prev_transform_row, args.prev_transform);
@ -413,7 +403,7 @@ void RT_DynamicModelProcessFrame(void) {
}
// FIXME override color
if (!RT_KusochkiUpload(kusochki_offset, dyn->geometries, dyn->geometries_count, -1, dyn->colors)) {
if (!RT_KusochkiUpload(kusochki_offset, dyn->geometries, dyn->geometries_count, NULL, dyn->colors)) {
gEngine.Con_Printf(S_ERROR "Couldn't build blas for %d geoms of %s, skipping\n", dyn->geometries_count, group_names[i]);
goto tail;
}
@ -440,7 +430,8 @@ tail:
}
void RT_FrameAddOnce( rt_frame_add_once_t args ) {
const int material_mode = materialModeFromRenderType(args.render_type);
// TODO pass material_mode explicitly
const int material_mode = R_VkMaterialModeFromRenderType(args.render_type);
rt_dynamic_t *const dyn = g_dyn.groups + material_mode;
for (int i = 0; i < args.geometries_count; ++i) {

View File

@ -723,7 +723,7 @@ static void submitToTraditionalRender( trad_submit_t args ) {
for (int i = 0; i < args.geometries_count; ++i) {
const vk_render_geometry_t *geom = args.geometries + i;
const int tex = args.textures_override > 0 ? args.textures_override : geom->texture;
const int tex = args.textures_override > 0 ? args.textures_override : geom->ye_olde_texture;
const qboolean split = current_texture != tex
|| vertex_offset != geom->vertex_offset
|| (index_offset + element_count) != geom->index_offset;
@ -781,14 +781,14 @@ void R_RenderModelDraw(const vk_render_model_t *model, r_model_draw_t args) {
if (g_render_state.current_frame_is_ray_traced) {
ASSERT(model->rt_model);
RT_FrameAddModel(model->rt_model, (rt_frame_add_model_t){
.render_type = args.render_type,
.material_mode = args.material_mode,
.transform = (const matrix3x4*)args.transform,
.prev_transform = (const matrix3x4*)args.prev_transform,
.color = args.color,
.dynamic_polylights = model->dynamic_polylights,
.dynamic_polylights_count = model->dynamic_polylights_count,
.override = {
.textures = args.textures_override,
.material = args.material_override,
.geoms = model->geometries,
.geoms_count = model->num_geometries,
},
@ -802,7 +802,7 @@ void R_RenderModelDraw(const vk_render_model_t *model, r_model_draw_t args) {
.transform = args.transform,
.color = args.color,
.render_type = args.render_type,
.textures_override = args.textures_override
.textures_override = args.material_override ? args.material_override->tex_base_color : -1,
});
}
}
@ -820,8 +820,8 @@ void R_RenderDrawOnce(r_draw_once_t args) {
R_GeometryBufferUnlock( &buffer );
const vk_render_geometry_t geometry = {
.texture = args.texture,
.material = kXVkMaterialRegular,
.material = args.material,
.ye_olde_texture = args.ye_olde_texture,
.max_vertex = args.vertices_count,
.vertex_offset = buffer.vertices.unit_offset,

View File

@ -1,4 +1,5 @@
#pragma once
#include "vk_materials.h"
#include "vk_common.h"
#include "vk_const.h"
#include "vk_core.h"
@ -9,26 +10,6 @@ void VK_RenderShutdown( void );
struct ref_viewpass_s;
void VK_RenderSetupCamera( const struct ref_viewpass_s *rvp );
// Quirk for passing surface type to the renderer
// xash3d does not really have a notion of materials. Instead there are custom code paths
// for different things. There's also render_mode for entities which determine blending mode
// and stuff.
// For ray tracing we do need to assing a material to each rendered surface, so we need to
// figure out what it is given heuristics like render_mode, texture name, surface flags, source entity type, etc.
typedef enum {
kXVkMaterialRegular = 0,
// Set for SURF_DRAWSKY surfaces in vk_brush.c.
// Used: for setting TEX_BASE_SKYBOX for skybox texture sampling and environment shadows.
// Remove: pass it as a special texture/material index (e.g. -2).
kXVkMaterialSky,
// Set for chrome studio submodels.
// Used: ray tracing sets gray roughness texture to get smooth surface look.
// Remove: Have an explicit material for chrome surfaces.
kXVkMaterialChrome,
} XVkMaterialType;
typedef struct vk_render_geometry_s {
int index_offset, vertex_offset;
@ -42,11 +23,11 @@ typedef struct vk_render_geometry_s {
// Remove: have an explicit list of surfaces with animated textures
const struct msurface_s *surf_deprecate;
// Animated textures will be dynamic and change between frames
int texture;
// If this geometry is special, it will have a material type override
XVkMaterialType material;
r_vk_material_t material;
// Olde unpatched texture used for traditional renderer
int ye_olde_texture;
// for kXVkMaterialEmissive{,Glow} and others
vec3_t emissive;
@ -96,6 +77,20 @@ typedef enum {
kVkRenderType_COUNT
} vk_render_type_e;
typedef enum {
// MUST be congruent to MATERIAL_MODE_* definitions in shaders/ray_interop.h
kMaterialMode_Opaque = 0,
kMaterialMode_AlphaTest = 1,
kMaterialMode_Translucent = 2,
kMaterialMode_BlendAdd = 3,
kMaterialMode_BlendMix = 4,
kMaterialMode_BlendGlow = 5,
kMaterialMode_COUNT = 6,
} material_mode_e;
uint32_t R_VkMaterialModeFromRenderType(vk_render_type_e render_type);
struct rt_light_add_polygon_s;
struct rt_model_s;
@ -139,15 +134,14 @@ qboolean R_RenderModelUpdate( const vk_render_model_t *model );
qboolean R_RenderModelUpdateMaterials( const vk_render_model_t *model, const int *geom_indices, int geom_indices_count);
typedef struct {
vk_render_type_e render_type;
vk_render_type_e render_type; // TODO rename legacy
material_mode_e material_mode;
// These are "consumed": copied into internal storage and can be pointers to stack vars
const vec4_t *color;
const matrix4x4 *transform, *prev_transform;
// Global texture override if > 0
// Used by sprite+quad instancing
int textures_override;
const r_vk_material_t* material_override;
} r_model_draw_t;
void R_RenderModelDraw(const vk_render_model_t *model, r_model_draw_t args);
@ -159,7 +153,8 @@ typedef struct {
int vertices_count, indices_count;
int render_type;
int texture;
r_vk_material_t material;
int ye_olde_texture;
const vec4_t *emissive;
const vec4_t *color;
} r_draw_once_t;

View File

@ -21,6 +21,8 @@
#include <memory.h>
#define LOG_MODULE LogModule_RMain
ref_api_t gEngine = {0};
ref_globals_t *gpGlobals = NULL;
@ -117,7 +119,7 @@ static qboolean Mod_ProcessRenderData( model_t *mod, qboolean create, const byte
{
qboolean loaded = true;
//gEngine.Con_Reportf("%s(%s, create=%d)\n", __FUNCTION__, mod->name, create);
DEBUG("%s(%s, create=%d)", __FUNCTION__, mod->name, create);
// TODO does this ever happen?
if (!create && mod->type == mod_brush)

View File

@ -34,6 +34,7 @@ void VK_RayShutdown( void );
struct vk_render_geometry_s;
struct rt_model_s;
struct r_vk_material_s;
typedef enum {
kBlasBuildStatic, // builds slow for fast trace
@ -55,7 +56,7 @@ qboolean RT_ModelUpdate(struct rt_model_s *model, const struct vk_render_geometr
qboolean RT_ModelUpdateMaterials(struct rt_model_s *model, const struct vk_render_geometry_s *geometries, int geometries_count, const int *geom_indices, int geom_indices_count);
typedef struct {
int render_type; // TODO material_mode
int material_mode;
const matrix3x4 *transform, *prev_transform;
const vec4_t *color;
@ -63,7 +64,7 @@ typedef struct {
int dynamic_polylights_count;
struct {
int textures; // Override kusochki/material textures if > 0
const struct r_vk_material_s *material;
// These are needed in order to recreate kusochki geometry data
// TODO remove when material data is split from kusochki

View File

@ -89,6 +89,9 @@ static void loadLights( const model_t *const map ) {
// Clears all old map data
static void mapLoadBegin( const model_t *const map ) {
VK_EntityDataClear();
// Depends on VK_EntityDataClear()
R_StudioCacheClear();
R_GeometryBuffer_MapClear();
@ -121,6 +124,8 @@ static void preloadModels( void ) {
DEBUG( " %d: name=%s, type=%d, submodels=%d, nodes=%d, surfaces=%d, nummodelsurfaces=%d", i, m->name, m->type, m->numsubmodels, m->numnodes, m->numsurfaces, m->nummodelsurfaces);
R_VkMaterialsLoadForModel(m);
switch (m->type) {
case mod_brush:
if (!VK_BrushModelLoad(m))
@ -148,7 +153,7 @@ static void loadMap(const model_t* const map) {
XVK_ParseMapEntities();
// Load PBR materials (depends on wadlist from parsed map entities)
XVK_ReloadMaterials();
R_VkMaterialsReload();
// Parse patch data
// Depends on loaded materials. Must preceed loading brush models.
@ -589,11 +594,11 @@ static void drawEntity( cl_entity_t *ent, int render_mode )
case mod_brush:
R_RotateForEntity( model, ent );
// If this is potentially a func_wall model
// If this is potentially a func_any model
if (ent->model->name[0] == '*') {
for (int i = 0; i < g_map_entities.func_walls_count; ++i) {
xvk_mapent_func_wall_t *const fw = g_map_entities.func_walls + i;
if (Q_strcmp(ent->model->name, fw->model) == 0) {
for (int i = 0; i < g_map_entities.func_any_count; ++i) {
xvk_mapent_func_any_t *const fw = g_map_entities.func_any + i;
if (Q_strcmp(ent->model->name, fw->model) == 0 && fw->origin_patched) {
/* DEBUG("ent->index=%d (%s) mapent:%d off=%f %f %f", */
/* ent->index, ent->model->name, fw->entity_index, */
/* fw->origin[0], fw->origin[1], fw->origin[2]); */

View File

@ -6,6 +6,7 @@
#include "vk_scene.h"
#include "r_speeds.h"
#include "vk_math.h"
#include "vk_logs.h"
#include "sprite.h"
#include "xash3d_mathlib.h"
@ -16,6 +17,7 @@
#include <memory.h>
#define MODULE_NAME "sprite"
#define LOG_MODULE LogModule_Sprite
// it's a Valve default value for LoadMapSprite (probably must be power of two)
#define MAPSPRITE_SIZE 128
@ -103,8 +105,8 @@ static qboolean createQuadModel(void) {
.element_count = 6,
.index_offset = g_sprite.quad.geom.indices.unit_offset,
.material = kXVkMaterialRegular,
.texture = tglob.defaultTexture,
.material = R_VkMaterialGetForTexture(tglob.defaultTexture),
.ye_olde_texture = tglob.defaultTexture,
.emissive = {1,1,1},
};
@ -404,6 +406,7 @@ Loading a bitmap image as sprite with multiple frames
as pieces of input image
====================
*/
// IS NOT CALLED BY ANYTHING?!
void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean *loaded )
{
byte *src, *dst;
@ -417,6 +420,8 @@ void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean
msprite_t *psprite;
SpriteLoadContext ctx = {0};
DEBUG("%s(%s, %p, %d, %d)", __FUNCTION__, mod->name, buffer, (int)size, (int)*loaded);
if( loaded ) *loaded = false;
Q_snprintf( texname, sizeof( texname ), "#%s", mod->name );
gEngine.Image_SetForceFlags( IL_OVERVIEW );
@ -798,13 +803,16 @@ static void R_DrawSpriteQuad( const char *debug_name, const mspriteframe_t *fram
Matrix4x4_CreateFromVectors(transform, right, up, v_normal, org);
const vk_render_type_e render_type = spriteRenderModeToRenderType(render_mode);
const r_vk_material_t material_override = R_VkMaterialGetForTexture(texture);
const material_mode_e material_mode = R_VkMaterialModeFromRenderType(render_type);
R_RenderModelDraw(&g_sprite.quad.model, (r_model_draw_t){
.render_type = render_type,
.material_mode = material_mode,
.color = (const vec4_t*)color,
.transform = &transform,
.prev_transform = &transform,
.textures_override = texture,
.material_override = &material_override,
});
}

View File

@ -1770,8 +1770,8 @@ static void buildSubmodelMeshGeometry( build_submodel_mesh_t args ) {
ASSERT(vertex_offset == num_vertices);
*args.out_geometry = (vk_render_geometry_t){
.texture = args.texture,
.material = FBitSet( args.face_flags, STUDIO_NF_CHROME ) ? kXVkMaterialChrome : kXVkMaterialRegular,
.material = R_VkMaterialGetForTexture(args.texture),
.ye_olde_texture = args.texture,
.vertex_offset = args.vertices_offset,
.max_vertex = num_vertices,
@ -1782,6 +1782,11 @@ static void buildSubmodelMeshGeometry( build_submodel_mesh_t args ) {
.emissive = {0, 0, 0},
};
if (!args.out_geometry->material.set && FBitSet( args.face_flags, STUDIO_NF_CHROME )) {
// TODO configurable
args.out_geometry->material.roughness = tglob.grayTexture;
}
*args.out_vertices_count += num_vertices;
*args.out_indices_count += num_indices;
}
@ -2299,12 +2304,15 @@ static void R_StudioDrawPoints( void ) {
Vector4Set(color, g_studio.blend, g_studio.blend, g_studio.blend, 1.f);
// TODO r_model_draw_t.transform should be matrix3x4
const vk_render_type_e render_type = studioRenderModeToRenderType(RI.currententity->curstate.rendermode);
const material_mode_e material_mode = R_VkMaterialModeFromRenderType(render_type);
R_RenderModelDraw(&render_submodel->model, (r_model_draw_t){
.render_type = studioRenderModeToRenderType(RI.currententity->curstate.rendermode),
.render_type = render_type,
.material_mode = material_mode,
.color = &color,
.transform = &g_studio_current.entmodel->transform,
.prev_transform = &g_studio_current.entmodel->prev_transform,
.textures_override = -1,
.material_override = NULL,
});
++g_studio_stats.submodels_total;

View File

@ -285,7 +285,8 @@ r_studio_submodel_render_t *studioSubmodelRenderModelAcquire(r_studio_submodel_i
}
subinfo->render_refcount++;
DEBUG("%s: submodel=%p(%s) \"%s\" rendermodel=%p refcount=%d", __FUNCTION__, subinfo->submodel_key, mode, subinfo->submodel_key->name, render, subinfo->render_refcount);
DEBUG("%s: submodel=%p(%s) %s rendermodel=%p refcount=%d",
__FUNCTION__, subinfo->submodel_key, subinfo->submodel_key->name, mode, render, subinfo->render_refcount);
return render;
}
@ -297,7 +298,8 @@ void studioSubmodelRenderModelRelease(r_studio_submodel_render_t *render_submode
render_submodel->_.info->render_refcount--;
const r_studio_submodel_info_t* const subinfo = render_submodel->_.info;
DEBUG("%s: submodel=%p(%s) rendermodel=%p refcount=%d", __FUNCTION__, subinfo->submodel_key, subinfo->submodel_key->name, render_submodel, subinfo->render_refcount);
DEBUG("%s: submodel=%p(%s) rendermodel=%p refcount=%d",
__FUNCTION__, subinfo->submodel_key, subinfo->submodel_key->name, render_submodel, subinfo->render_refcount);
if (!render_submodel->_.info->is_dynamic)
return;

View File

@ -170,7 +170,8 @@ void TriEndEx( const vec4_t color, const char* name ) {
.vertices_count = g_triapi.num_vertices,
.indices_count = num_indices,
.render_type = g_triapi.render_type,
.texture = g_triapi.texture_index,
.material = R_VkMaterialGetForTexture(g_triapi.texture_index),
.ye_olde_texture = g_triapi.texture_index,
.emissive = (const vec4_t*)color,
.color = (const vec4_t*)color,
});