Merge pull request #547 from w23/brush-smoothing
Smooth normals between selected brush surfaces if the angle between them is small enough. - [x] Per-vertex-per-surface smoothing functionality (differs from qrad, which is per-edge; this gives artifacts as (supposedly) we have higher than lightmap lighting resolution) - [x] Automatically select surfaces with less than X degrees between normals. - [x] Make this X threshold adjustable from <map>.bsp.patch - [ ] ~~Try not joining coplanar surfaces~~ -- doesn't seem to be affecting anything. - [ ] ~~Think about linking surfaces more. Should we link distant surfaces w/o direct edges to this one?~~ -- it seems that we should be fine for now. Per-surface+vertex vs per-edge smoothing has no clear winner, just different tradeoffs. - [ ] ~~Scale normals according to surfaces areas, so larger surfaces have more weight (experimental; may improve some artifacts)~~ -- also, non trivial to compute, and may not affect things too much. - [x] Patch: add explicit smoothing or no-smoothing for given surfaces. Fixes #139, supersedes #348
This commit is contained in:
commit
29508cd324
|
@ -36,11 +36,14 @@ layout(set = 0, binding = 15, rgba16f) uniform image2D prev_temporal_diffuse;
|
|||
layout(set = 0, binding = 16, rgba16f) uniform image2D out_temporal_specular;
|
||||
layout(set = 0, binding = 17, rgba16f) uniform image2D prev_temporal_specular;
|
||||
|
||||
|
||||
const int INDIRECT_SCALE = 2;
|
||||
|
||||
//#define DEBUG_TEXTURE normals_gs
|
||||
//#define DEBUG_TEXTURE emissive
|
||||
//#define DEBUG_TEXTURE light_point_diffuse
|
||||
//#define DEBUG_NORMAL
|
||||
//layout(set = 0, binding = 18, rgba8) uniform readonly image2D material_rmxx;
|
||||
|
||||
// Blatantly copypasted from https://www.shadertoy.com/view/XsGfWV
|
||||
vec3 aces_tonemap(vec3 color){
|
||||
|
@ -197,11 +200,15 @@ void main() {
|
|||
//imageStore(out_dest, pix, vec4(fract(imageLoad(position_t, pix).rgb/10.), 0.)); return;
|
||||
//imageStore(out_dest, pix, vec4(fract(imageLoad(geometry_prev_position, pix).rgb/50.), 0.)); return;
|
||||
|
||||
#if 0
|
||||
#if defined(DEBUG_NORMAL)
|
||||
vec3 geometry_normal, shading_normal;
|
||||
readNormals(pix, geometry_normal, shading_normal);
|
||||
//imageStore(out_dest, pix, vec4(.5 + geometry_normal * .5, 0.)); return;
|
||||
imageStore(out_dest, pix, vec4(.5 + shading_normal * .5, 0.)); return;
|
||||
//const vec4 mat_rmxx = imageLoad(material_rmxx, pix);
|
||||
//imageStore(out_dest, pix, vec4((.5 + shading_normal * .5)*.8 + .2 * mat_rmxx.a , 0.)); return;
|
||||
|
||||
vec3 normal = pix.x < res.x / 2 ? shading_normal : geometry_normal;
|
||||
imageStore(out_dest, pix, vec4(.5 + normal * .5, 0.)); return;
|
||||
#endif
|
||||
|
||||
/* const uint mi = uint(material_index); */
|
||||
|
|
|
@ -8,6 +8,7 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
|||
|
||||
#include "ray_primary_common.glsl"
|
||||
#include "ray_primary_hit.glsl"
|
||||
//#include "noise.glsl"
|
||||
|
||||
#define RAY_PRIMARY_OUTPUTS(X) \
|
||||
X(10, base_color_a, rgba8) \
|
||||
|
@ -97,8 +98,10 @@ void main() {
|
|||
}
|
||||
|
||||
float L = ray.dist;
|
||||
|
||||
//uint debug_geometry_index = 0;
|
||||
if (rayQueryGetIntersectionTypeEXT(rq, true) == gl_RayQueryCommittedIntersectionTriangleEXT) {
|
||||
//debug_geometry_index = rayQueryGetIntersectionGeometryIndexEXT(rq, true);
|
||||
//debug_geometry_index = rayQueryGetIntersectionPrimitiveIndexEXT(rq, true);
|
||||
primaryRayHit(rq, payload);
|
||||
L = rayQueryGetIntersectionTEXT(rq, true);
|
||||
}
|
||||
|
@ -108,6 +111,7 @@ void main() {
|
|||
imageStore(out_position_t, pix, payload.hit_t);
|
||||
imageStore(out_base_color_a, pix, payload.base_color_a);
|
||||
imageStore(out_normals_gs, pix, payload.normals_gs);
|
||||
//imageStore(out_material_rmxx, pix, vec4(payload.material_rmxx.rg, 0, uintToFloat01(xxhash32(debug_geometry_index))));
|
||||
imageStore(out_material_rmxx, pix, payload.material_rmxx);
|
||||
imageStore(out_emissive, pix, payload.emissive);
|
||||
imageStore(out_geometry_prev_position, pix, payload.prev_pos_t);
|
||||
|
|
|
@ -58,6 +58,21 @@ typedef struct {
|
|||
int water_indices;
|
||||
} model_sizes_t;
|
||||
|
||||
typedef struct conn_edge_s {
|
||||
int first_surface;
|
||||
int count;
|
||||
} conn_edge_t;
|
||||
|
||||
typedef struct linked_value_s {
|
||||
int value, link;
|
||||
} linked_value_t;
|
||||
|
||||
#define MAX_VERTEX_SURFACES 16
|
||||
typedef struct conn_vertex_s {
|
||||
int count;
|
||||
linked_value_t surfs[MAX_VERTEX_SURFACES];
|
||||
} conn_vertex_t;
|
||||
|
||||
static struct {
|
||||
struct {
|
||||
int total_vertices, total_indices;
|
||||
|
@ -76,6 +91,16 @@ static struct {
|
|||
|
||||
#define MAX_ANIMATED_TEXTURES 256
|
||||
int updated_textures[MAX_ANIMATED_TEXTURES];
|
||||
|
||||
// Smoothed normals comptutation
|
||||
// Connectome for edges and vertices
|
||||
struct {
|
||||
int edges_capacity;
|
||||
conn_edge_t *edges;
|
||||
|
||||
int vertices_capacity;
|
||||
conn_vertex_t *vertices;
|
||||
} conn;
|
||||
} g_brush;
|
||||
|
||||
void VK_InitRandomTable( void )
|
||||
|
@ -107,8 +132,9 @@ qboolean VK_BrushInit( void )
|
|||
return true;
|
||||
}
|
||||
|
||||
void VK_BrushShutdown( void )
|
||||
{
|
||||
void VK_BrushShutdown( void ) {
|
||||
if (g_brush.conn.edges)
|
||||
Mem_Free(g_brush.conn.edges);
|
||||
}
|
||||
|
||||
// speed up sin calculations
|
||||
|
@ -763,6 +789,218 @@ typedef struct {
|
|||
uint16_t *out_indices;
|
||||
} fill_geometries_args_t;
|
||||
|
||||
static void getSurfaceNormal( const msurface_t *surf, vec3_t out_normal) {
|
||||
if( FBitSet( surf->flags, SURF_PLANEBACK ))
|
||||
VectorNegate( surf->plane->normal, out_normal );
|
||||
else
|
||||
VectorCopy( surf->plane->normal, out_normal );
|
||||
|
||||
// TODO scale normal by area -- bigger surfaces should have bigger impact
|
||||
//VectorScale(normal, surf->plane.
|
||||
}
|
||||
|
||||
static int getSurfaceTexture(const msurface_t *surf, int surface_index) {
|
||||
const xvk_patch_surface_t *const psurf = R_VkPatchGetSurface(surface_index);
|
||||
if (psurf && psurf->tex_id >= 0)
|
||||
return psurf->tex_id;
|
||||
return surf->texinfo->texture->gl_texturenum;
|
||||
}
|
||||
|
||||
static qboolean shouldSmoothLinkSurfaces(const model_t* mod, int surf1, int surf2) {
|
||||
//return Q_min(surf1, surf2) == 741 && Q_max(surf1, surf2) == 743;
|
||||
|
||||
// Filter explicit exclusion
|
||||
for (int i = 0; i < g_map_entities.smoothing.excluded_count; i+=2) {
|
||||
const int cand1 = g_map_entities.smoothing.excluded[i];
|
||||
const int cand2 = g_map_entities.smoothing.excluded[i+1];
|
||||
|
||||
if ((cand1 == surf1 && cand2 == surf2)
|
||||
|| (cand1 == surf2 && cand2 == surf1))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < g_map_entities.smoothing.groups_count; ++i) {
|
||||
const xvk_smoothing_group_t *g = g_map_entities.smoothing.groups + i;
|
||||
uint32_t bits = 0;
|
||||
for (int j = 0; j < g->count; ++j) {
|
||||
if (g->surfaces[j] == surf1) {
|
||||
bits |= 1;
|
||||
if (bits == 3)
|
||||
return true;
|
||||
}
|
||||
else if (g->surfaces[j] == surf2) {
|
||||
bits |= 2;
|
||||
if (bits == 3)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do not join surfaces with different textures. Assume they belong to different objects.
|
||||
const int t1 = getSurfaceTexture(mod->surfaces + surf1, surf1);
|
||||
const int t2 = getSurfaceTexture(mod->surfaces + surf2, surf2);
|
||||
if (t1 != t2)
|
||||
return false;
|
||||
|
||||
vec3_t n1, n2;
|
||||
getSurfaceNormal(mod->surfaces + surf1, n1);
|
||||
getSurfaceNormal(mod->surfaces + surf2, n2);
|
||||
|
||||
const float dot = DotProduct(n1, n2);
|
||||
DEBUG("Smoothing: dot(%d, %d) = %f (t=%f)", surf1, surf2, dot, g_map_entities.smoothing.threshold);
|
||||
|
||||
return dot >= g_map_entities.smoothing.threshold;
|
||||
}
|
||||
|
||||
static int lvFindValue(const linked_value_t *li, int count, int needle) {
|
||||
for (int i = 0; i < count; ++i)
|
||||
if (li[i].value == needle)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
static int lvFindOrAddValue(linked_value_t *li, int *count, int capacity, int needle) {
|
||||
const int found = lvFindValue(li, *count, needle);
|
||||
if (found >= 0)
|
||||
return found;
|
||||
if (*count == capacity)
|
||||
return -1;
|
||||
li[*count].value = needle;
|
||||
li[*count].link = *count;
|
||||
return (*count)++;
|
||||
}
|
||||
|
||||
static int lvFindBaseIndex(const linked_value_t *li, int index) {
|
||||
while (li[index].link != index)
|
||||
index = li[index].link;
|
||||
return index;
|
||||
}
|
||||
|
||||
static void lvFlatten(linked_value_t *li, int count) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
for (int j = i; j < count; ++j) {
|
||||
if (lvFindBaseIndex(li, j) == i) {
|
||||
li[j].link = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void linkSmoothSurfaces(const model_t* mod, int surf1, int surf2, int vertex_index) {
|
||||
conn_vertex_t *v = g_brush.conn.vertices + vertex_index;
|
||||
|
||||
int i1 = lvFindOrAddValue(v->surfs, &v->count, COUNTOF(v->surfs), surf1);
|
||||
int i2 = lvFindOrAddValue(v->surfs, &v->count, COUNTOF(v->surfs), surf2);
|
||||
|
||||
DEBUG("Link %d(%d)<->%d(%d) v=%d", surf1, i1, surf2, i2, vertex_index);
|
||||
|
||||
if (i1 < 0 || i2 < 0) {
|
||||
ERR("Model %s cannot smooth link surf %d<->%d for vertex %d", mod->name, surf1, surf2, vertex_index);
|
||||
return;
|
||||
}
|
||||
|
||||
i1 = lvFindBaseIndex(v->surfs, i1);
|
||||
i2 = lvFindBaseIndex(v->surfs, i2);
|
||||
|
||||
// Link them
|
||||
v->surfs[Q_max(i1, i2)].link = Q_min(i1, i2);
|
||||
}
|
||||
|
||||
static void connectVertices( const model_t *mod ) {
|
||||
if (mod->numedges > g_brush.conn.edges_capacity) {
|
||||
if (g_brush.conn.edges)
|
||||
Mem_Free(g_brush.conn.edges);
|
||||
|
||||
g_brush.conn.edges_capacity = mod->numedges;
|
||||
g_brush.conn.edges = Mem_Calloc(vk_core.pool, sizeof(*g_brush.conn.edges) * g_brush.conn.edges_capacity);
|
||||
}
|
||||
|
||||
if (mod->numvertexes > g_brush.conn.vertices_capacity) {
|
||||
if (g_brush.conn.vertices)
|
||||
Mem_Free(g_brush.conn.vertices);
|
||||
|
||||
g_brush.conn.vertices_capacity = mod->numvertexes;
|
||||
g_brush.conn.vertices = Mem_Calloc(vk_core.pool, sizeof(*g_brush.conn.vertices) * g_brush.conn.vertices_capacity);
|
||||
}
|
||||
|
||||
// Find connection edges
|
||||
for (int i = 0; i < mod->nummodelsurfaces; ++i) {
|
||||
const int surface_index = mod->firstmodelsurface + i;
|
||||
const msurface_t *surf = mod->surfaces + surface_index;
|
||||
|
||||
for(int k = 0; k < surf->numedges; k++) {
|
||||
const int iedge_dir = mod->surfedges[surf->firstedge + k];
|
||||
const int iedge = iedge_dir >= 0 ? iedge_dir : -iedge_dir;
|
||||
|
||||
ASSERT(iedge >= 0);
|
||||
ASSERT(iedge < mod->numedges);
|
||||
|
||||
conn_edge_t *cedge = g_brush.conn.edges + iedge;
|
||||
if (cedge->count == 0) {
|
||||
cedge->first_surface = surface_index;
|
||||
} else {
|
||||
const medge_t *edge = mod->edges + iedge;
|
||||
if (shouldSmoothLinkSurfaces(mod, cedge->first_surface, surface_index)) {
|
||||
linkSmoothSurfaces(mod, cedge->first_surface, surface_index, edge->v[0]);
|
||||
linkSmoothSurfaces(mod, cedge->first_surface, surface_index, edge->v[1]);
|
||||
}
|
||||
|
||||
if (cedge->count > 1) {
|
||||
WARN("Model %s edge %d has %d surfaces", mod->name, i, cedge->count);
|
||||
}
|
||||
}
|
||||
cedge->count++;
|
||||
} // for surf->numedges
|
||||
} // for mod->nummodelsurfaces
|
||||
|
||||
int hist[17] = {0};
|
||||
for (int i = 0; i < mod->numvertexes; ++i) {
|
||||
conn_vertex_t *vtx = g_brush.conn.vertices + i;
|
||||
if (vtx->count < 16) {
|
||||
hist[vtx->count]++;
|
||||
} else {
|
||||
hist[16]++;
|
||||
}
|
||||
|
||||
lvFlatten(vtx->surfs, vtx->count);
|
||||
|
||||
// Too verbose
|
||||
#if 0
|
||||
if (vtx->count) {
|
||||
DEBUG("Vertex %d linked count %d", i, vtx->count);
|
||||
for (int j = 0; j < vtx->count; ++j) {
|
||||
DEBUG(" %d: l=%d v=%d", j, vtx->surfs[j].link, vtx->surfs[j].value);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for (int i = 0; i < COUNTOF(hist); ++i) {
|
||||
DEBUG("VTX hist[%d] = %d", i, hist[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static qboolean getSmoothedNormalFor(const model_t* mod, int vertex_index, int surface_index, vec3_t out_normal) {
|
||||
const conn_vertex_t *v = g_brush.conn.vertices + vertex_index;
|
||||
const int index = lvFindValue(v->surfs, v->count, surface_index);
|
||||
if (index < 0)
|
||||
return false;
|
||||
const int base = lvFindBaseIndex(v->surfs, index);
|
||||
|
||||
vec3_t normal = {0};
|
||||
for (int i = 0; i < v->count; ++i) {
|
||||
if (v->surfs[i].link == base) {
|
||||
const int surface = v->surfs[i].value;
|
||||
vec3_t surf_normal = {0};
|
||||
getSurfaceNormal(mod->surfaces + surface, surf_normal);
|
||||
VectorAdd(normal, surf_normal, normal);
|
||||
}
|
||||
}
|
||||
|
||||
VectorNormalize(normal);
|
||||
VectorCopy(normal, out_normal);
|
||||
return true;
|
||||
}
|
||||
|
||||
static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
|
||||
int vertex_offset = 0;
|
||||
int num_geometries = 0;
|
||||
|
@ -772,13 +1010,15 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
|
|||
uint16_t *p_ind = args.out_indices;
|
||||
int index_offset = args.base_index_offset;
|
||||
|
||||
connectVertices(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) {
|
||||
for( int i = 0; i < args.mod->nummodelsurfaces; ++i) {
|
||||
const int surface_index = args.mod->firstmodelsurface + i;
|
||||
msurface_t *surf = args.mod->surfaces + surface_index;
|
||||
mextrasurf_t *info = surf->info;
|
||||
const mextrasurf_t *info = surf->info;
|
||||
vk_render_geometry_t *model_geometry = args.out_geometries + num_geometries;
|
||||
const float sample_size = gEngine.Mod_SampleSizeForFace( surf );
|
||||
int index_count = 0;
|
||||
|
@ -841,11 +1081,18 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
|
|||
VectorCopy(surf->texinfo->vecs[0], tangent);
|
||||
VectorNormalize(tangent);
|
||||
|
||||
vec3_t surf_normal;
|
||||
getSurfaceNormal(surf, surf_normal);
|
||||
|
||||
vk_vertex_t *const pvert_begin = p_vert;
|
||||
for( int k = 0; k < surf->numedges; k++ )
|
||||
{
|
||||
const int iedge = args.mod->surfedges[surf->firstedge + k];
|
||||
const medge_t *edge = args.mod->edges + (iedge >= 0 ? iedge : -iedge);
|
||||
const mvertex_t *in_vertex = args.mod->vertexes + (iedge >= 0 ? edge->v[0] : edge->v[1]);
|
||||
const int iedge_dir = args.mod->surfedges[surf->firstedge + k];
|
||||
const int iedge = iedge_dir >= 0 ? iedge_dir : -iedge_dir;
|
||||
const medge_t *edge = args.mod->edges + iedge;
|
||||
const int vertex_index = iedge_dir >= 0 ? edge->v[0] : edge->v[1];
|
||||
const mvertex_t *in_vertex = args.mod->vertexes + vertex_index;
|
||||
|
||||
vk_vertex_t vertex = {
|
||||
{in_vertex->position[0], in_vertex->position[1], in_vertex->position[2]},
|
||||
};
|
||||
|
@ -902,9 +1149,10 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
|
|||
vertex.lm_tc[1] = t;
|
||||
}
|
||||
|
||||
if( FBitSet( surf->flags, SURF_PLANEBACK ))
|
||||
VectorNegate( surf->plane->normal, vertex.normal );
|
||||
else VectorCopy( surf->plane->normal, vertex.normal );
|
||||
// Compute smoothed normal if needed
|
||||
if (!getSmoothedNormalFor(args.mod, vertex_index, surface_index, vertex.normal)) {
|
||||
VectorCopy(surf_normal, vertex.normal);
|
||||
}
|
||||
|
||||
VectorCopy(tangent, vertex.tangent);
|
||||
|
||||
|
@ -920,11 +1168,11 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
|
|||
index_count += 3;
|
||||
index_offset += 3;
|
||||
}
|
||||
}
|
||||
} // for surf->numedges
|
||||
|
||||
model_geometry->element_count = index_count;
|
||||
vertex_offset += surf->numedges;
|
||||
}
|
||||
} // for mod->nummodelsurfaces
|
||||
}
|
||||
|
||||
ASSERT(args.sizes.num_surfaces == num_geometries);
|
||||
|
@ -1081,6 +1329,10 @@ void VK_BrushModelDestroyAll( void ) {
|
|||
g_brush.stat.total_vertices = 0;
|
||||
g_brush.stat.total_indices = 0;
|
||||
g_brush.models_count = 0;
|
||||
|
||||
memset(g_brush.conn.edges, 0, sizeof(*g_brush.conn.edges) * g_brush.conn.edges_capacity);
|
||||
|
||||
memset(g_brush.conn.vertices, 0, sizeof(*g_brush.conn.vertices) * g_brush.conn.vertices_capacity);
|
||||
}
|
||||
|
||||
static rt_light_add_polygon_t loadPolyLight(const model_t *mod, const int surface_index, const msurface_t *surf, const vec3_t emissive) {
|
||||
|
|
|
@ -518,7 +518,40 @@ static void patchEntity( const entity_props_t *props, uint32_t have_fields ) {
|
|||
WARN("vk_mapents: trying to patch unsupported entity %d class %d", ei, ref->class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void appendExludedPairs(const entity_props_t *props) {
|
||||
if (props->_xvk_smoothing_excluded_pairs.num % 2 != 0) {
|
||||
ERR("vk_mapents: smoothing group exclusion list should be list of pairs -- divisible by 2; cutting the tail");
|
||||
}
|
||||
|
||||
int count = props->_xvk_smoothing_excluded_pairs.num & ~1;
|
||||
if (g_map_entities.smoothing.excluded_count + count > COUNTOF(g_map_entities.smoothing.excluded)) {
|
||||
ERR("vk_mapents: smoothing exclusion group capacity exceeded, go complain in github issues");
|
||||
count = COUNTOF(g_map_entities.smoothing.excluded) - g_map_entities.smoothing.excluded_count;
|
||||
}
|
||||
|
||||
memcpy(g_map_entities.smoothing.excluded + g_map_entities.smoothing.excluded_count, props->_xvk_smoothing_excluded_pairs.values, count * sizeof(int));
|
||||
|
||||
g_map_entities.smoothing.excluded_count += count;
|
||||
}
|
||||
|
||||
static void addSmoothingGroup(const entity_props_t *props) {
|
||||
if (g_map_entities.smoothing.groups_count == MAX_INCLUDED_SMOOTHING_GROUPS) {
|
||||
ERR("vk_mapents: limit of %d smoothing groups reached", MAX_INCLUDED_SMOOTHING_GROUPS);
|
||||
return;
|
||||
}
|
||||
|
||||
xvk_smoothing_group_t *g = g_map_entities.smoothing.groups + (g_map_entities.smoothing.groups_count++);
|
||||
|
||||
int count = props->_xvk_smoothing_group.num;
|
||||
if (count > MAX_INCLUDED_SMOOTHING_SURFACES_IN_A_GROUP) {
|
||||
ERR("vk_mapents: too many surfaces in a smoothing group. Max %d, got %d. Culling", MAX_INCLUDED_SMOOTHING_SURFACES_IN_A_GROUP, props->_xvk_smoothing_group.num);
|
||||
count = MAX_INCLUDED_SMOOTHING_SURFACES_IN_A_GROUP;
|
||||
}
|
||||
|
||||
memcpy(g->surfaces, props->_xvk_smoothing_group.values, sizeof(int) * count);
|
||||
g->count = count;
|
||||
}
|
||||
|
||||
static void parseEntities( char *string, qboolean is_patch ) {
|
||||
|
@ -570,6 +603,18 @@ static void parseEntities( char *string, qboolean is_patch ) {
|
|||
addPatchSurface( &values, have_fields );
|
||||
} else if (have_fields & Field__xvk_ent_id) {
|
||||
patchEntity( &values, have_fields );
|
||||
} else {
|
||||
if (have_fields & Field__xvk_smoothing_threshold) {
|
||||
g_map_entities.smoothing.threshold = cosf(DEG2RAD(values._xvk_smoothing_threshold));
|
||||
}
|
||||
|
||||
if (have_fields & Field__xvk_smoothing_excluded_pairs) {
|
||||
appendExludedPairs(&values);
|
||||
}
|
||||
|
||||
if (have_fields & Field__xvk_smoothing_group) {
|
||||
addSmoothingGroup(&values);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -676,6 +721,11 @@ void XVK_ParseMapEntities( void ) {
|
|||
g_map_entities.single_environment_index = NoEnvironmentLights;
|
||||
g_map_entities.entity_count = 0;
|
||||
g_map_entities.func_walls_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)
|
||||
g_map_entities.smoothing.groups[i].count = 0;
|
||||
g_map_entities.smoothing.groups_count = 0;
|
||||
|
||||
parseEntities( map->entities, false );
|
||||
orientSpotlights();
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
X(19, vec2_t, _xvk_tex_offset, Vec2) \
|
||||
X(20, vec2_t, _xvk_tex_scale, Vec2) \
|
||||
X(21, string, model, String) \
|
||||
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) \
|
||||
|
||||
/* NOTE: not used
|
||||
X(22, int, rendermode, Int) \
|
||||
|
@ -109,6 +112,12 @@ typedef struct {
|
|||
int index;
|
||||
} xvk_mapent_ref_t;
|
||||
|
||||
#define MAX_INCLUDED_SMOOTHING_SURFACES_IN_A_GROUP 16
|
||||
typedef struct {
|
||||
int count;
|
||||
int surfaces[MAX_INCLUDED_SMOOTHING_SURFACES_IN_A_GROUP];
|
||||
} xvk_smoothing_group_t;
|
||||
|
||||
typedef struct {
|
||||
int num_lights;
|
||||
vk_light_entity_t lights[256];
|
||||
|
@ -128,6 +137,18 @@ typedef struct {
|
|||
// TODO find out how to read this from the engine, or make its size dynamic
|
||||
//#define MAX_MAP_ENTITIES 2048
|
||||
xvk_mapent_ref_t refs[MAX_MAP_ENTITIES];
|
||||
|
||||
struct {
|
||||
float threshold;
|
||||
|
||||
#define MAX_EXCLUDED_SMOOTHING_SURFACES_PAIRS 32
|
||||
int excluded[MAX_EXCLUDED_SMOOTHING_SURFACES_PAIRS * 2];
|
||||
int excluded_count;
|
||||
|
||||
#define MAX_INCLUDED_SMOOTHING_GROUPS 32
|
||||
int groups_count;
|
||||
xvk_smoothing_group_t groups[MAX_INCLUDED_SMOOTHING_GROUPS];
|
||||
} smoothing;
|
||||
} xvk_map_entities_t;
|
||||
|
||||
extern xvk_map_entities_t g_map_entities;
|
||||
|
|
Loading…
Reference in New Issue