Dedupliacte quads from the model data, reducing it from 4151 to just 247 unique quads.

Fixes #278
This commit is contained in:
IntegratedQuantum 2024-04-24 19:55:27 +02:00
parent c64ece2163
commit ad1e79a4c1

View File

@ -21,8 +21,12 @@ pub const QuadInfo = extern struct {
textureSlot: u32, textureSlot: u32,
}; };
fn approxEqAbs(x: Vec3f, y: Vec3f, tolerance: Vec3f) @Vector(3, bool) { const gridSize = 4096;
return @abs(x - y) <= tolerance;
fn snapToGrid(x: anytype) @TypeOf(x) {
const T = @TypeOf(x);
const int = @as(@Vector(@typeInfo(T).Vector.len, i32), @intFromFloat(std.math.round(x*@as(T, @splat(gridSize)))));
return @as(T, @floatFromInt(int))/@as(T, @splat(gridSize));
} }
pub const Model = struct { pub const Model = struct {
@ -36,8 +40,8 @@ pub const Model = struct {
var allZero: @Vector(3, bool) = .{true, true, true}; var allZero: @Vector(3, bool) = .{true, true, true};
var allOne: @Vector(3, bool) = .{true, true, true}; var allOne: @Vector(3, bool) = .{true, true, true};
for(quad.corners) |corner| { for(quad.corners) |corner| {
allZero = @select(bool, allZero, approxEqAbs(corner, @splat(0), @splat(0.0001)), allZero); // vector and TODO: #14306 allZero = @select(bool, allZero, corner == @as(Vec3f, @splat(0)), allZero); // vector and TODO: #14306
allOne = @select(bool, allOne, approxEqAbs(corner, @splat(1), @splat(0.0001)), allOne); // vector and TODO: #14306 allOne = @select(bool, allOne, corner == @as(Vec3f, @splat(1)), allOne); // vector and TODO: #14306
} }
if(allZero[0]) return Neighbors.dirNegX; if(allZero[0]) return Neighbors.dirNegX;
if(allZero[1]) return Neighbors.dirNegY; if(allZero[1]) return Neighbors.dirNegY;
@ -52,8 +56,8 @@ pub const Model = struct {
var zeroes: @Vector(3, u32) = .{0, 0, 0}; var zeroes: @Vector(3, u32) = .{0, 0, 0};
var ones: @Vector(3, u32) = .{0, 0, 0}; var ones: @Vector(3, u32) = .{0, 0, 0};
for(quad.corners) |corner| { for(quad.corners) |corner| {
zeroes += @select(u32, approxEqAbs(corner, @splat(0), @splat(0.0001)), .{1, 1, 1}, .{0, 0, 0}); zeroes += @select(u32, corner == @as(Vec3f, @splat(0)), .{1, 1, 1}, .{0, 0, 0});
ones += @select(u32, approxEqAbs(corner, @splat(1), @splat(0.0001)), .{1, 1, 1}, .{0, 0, 0}); ones += @select(u32, corner == @as(Vec3f, @splat(1)), .{1, 1, 1}, .{0, 0, 0});
} }
// For full coverage there will 2 ones and 2 zeroes for two components, while the other one is constant. // For full coverage there will 2 ones and 2 zeroes for two components, while the other one is constant.
const hasTwoZeroes = zeroes == @Vector(3, u32){2, 2, 2}; const hasTwoZeroes = zeroes == @Vector(3, u32){2, 2, 2};
@ -61,7 +65,23 @@ pub const Model = struct {
return @popCount(@as(u3, @bitCast(hasTwoOnes))) == 2 and @popCount(@as(u3, @bitCast(hasTwoZeroes))) == 2; return @popCount(@as(u3, @bitCast(hasTwoOnes))) == 2 and @popCount(@as(u3, @bitCast(hasTwoZeroes))) == 2;
} }
pub fn init(quadInfos: []const QuadInfo) u16 { pub fn init(quadInfos: []const QuadInfo) u16 {
const adjustedQuads = main.stackAllocator.alloc(QuadInfo, quadInfos.len);
defer main.stackAllocator.free(adjustedQuads);
for(adjustedQuads, quadInfos) |*dest, *src| {
dest.* = src.*;
// Snap all values to a fixed point grid to make comparisons more accurate.
for(&dest.corners) |*corner| {
corner.* = snapToGrid(corner.*);
}
for(&dest.cornerUV) |*uv| {
uv.* = snapToGrid(uv.*);
}
// Snap the normals as well:
dest.normal = snapToGrid(dest.normal);
}
const modelIndex: u16 = @intCast(models.items.len); const modelIndex: u16 = @intCast(models.items.len);
const self = models.addOne(); const self = models.addOne();
var amounts: [6]usize = .{0, 0, 0, 0, 0, 0}; var amounts: [6]usize = .{0, 0, 0, 0, 0, 0};
@ -69,7 +89,7 @@ pub const Model = struct {
self.min = .{1, 1, 1}; self.min = .{1, 1, 1};
self.max = .{0, 0, 0}; self.max = .{0, 0, 0};
self.isNeighborOccluded = .{false} ** 6; self.isNeighborOccluded = .{false} ** 6;
for(quadInfos) |*quad| { for(adjustedQuads) |*quad| {
for(quad.corners) |corner| { for(quad.corners) |corner| {
self.min = @min(self.min, corner); self.min = @min(self.min, corner);
self.max = @max(self.max, corner); self.max = @max(self.max, corner);
@ -88,7 +108,7 @@ pub const Model = struct {
var indices: [6]usize = .{0, 0, 0, 0, 0, 0}; var indices: [6]usize = .{0, 0, 0, 0, 0, 0};
var internalIndex: usize = 0; var internalIndex: usize = 0;
for(quadInfos) |_quad| { for(adjustedQuads) |_quad| {
var quad = _quad; var quad = _quad;
if(getFaceNeighbor(&quad)) |neighbor| { if(getFaceNeighbor(&quad)) |neighbor| {
for(&quad.corners) |*corner| { for(&quad.corners) |*corner| {
@ -183,9 +203,15 @@ pub var quads: main.List(QuadInfo) = undefined;
pub var models: main.List(Model) = undefined; pub var models: main.List(Model) = undefined;
pub var fullCube: u16 = undefined; pub var fullCube: u16 = undefined;
var quadDeduplication: std.AutoHashMap([@sizeOf(QuadInfo)]u8, u16) = undefined;
fn addQuad(info: QuadInfo) u16 { // TODO: Merge duplicates fn addQuad(info: QuadInfo) u16 { // TODO: Merge duplicates
if(quadDeduplication.get(std.mem.toBytes(info))) |id| {
return id;
}
const index: u16 = @intCast(quads.items.len); const index: u16 = @intCast(quads.items.len);
quads.append(info); quads.append(info);
quadDeduplication.put(std.mem.toBytes(info), index) catch unreachable;
return index; return index;
} }
@ -252,6 +278,7 @@ fn openBox(min: Vec3f, max: Vec3f, uvOffset: Vec2f, openSide: enum{x, y, z}) [4]
pub fn init() void { pub fn init() void {
models = main.List(Model).init(main.globalAllocator); models = main.List(Model).init(main.globalAllocator);
quads = main.List(QuadInfo).init(main.globalAllocator); quads = main.List(QuadInfo).init(main.globalAllocator);
quadDeduplication = std.AutoHashMap([@sizeOf(QuadInfo)]u8, u16).init(main.globalAllocator.allocator);
nameToIndex = std.StringHashMap(u16).init(main.globalAllocator.allocator); nameToIndex = std.StringHashMap(u16).init(main.globalAllocator.allocator);
@ -334,4 +361,5 @@ pub fn deinit() void {
} }
models.deinit(); models.deinit();
quads.deinit(); quads.deinit();
quadDeduplication.deinit();
} }