Allow setting the highestLod parameter when in the menu.

I decided to avoid the trouble of making this dynamic, by just only allowing to change it in the menu.
fixes #747
This commit is contained in:
IntegratedQuantum 2024-12-17 14:37:45 +01:00
parent 3bdc1dd83d
commit 458dd20ade
7 changed files with 30 additions and 19 deletions

View File

@ -546,7 +546,7 @@ pub const ServerChunk = struct { // MARK: ServerChunk
self.wasChanged = false;
// Update the next lod chunk:
if(pos.voxelSize != 1 << settings.highestLOD) {
if(pos.voxelSize != 1 << settings.highestSupportedLod) {
var nextPos = pos;
nextPos.wx &= ~@as(i32, pos.voxelSize*chunkSize);
nextPos.wy &= ~@as(i32, pos.voxelSize*chunkSize);

View File

@ -19,6 +19,7 @@ pub var window = GuiWindow {
const padding: f32 = 8;
const renderDistances = [_]u16{5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};
const lodValues = [_][]const u8{"0.5", "1", "2", "3", "4", "5"};
const anisotropy = [_]u8{1, 2, 4, 8, 16};
@ -53,6 +54,11 @@ fn renderDistanceCallback(newValue: u16) void {
settings.save();
}
fn highestLodCallback(newValue: u16) void {
settings.highestLod = @intCast(@min(newValue, settings.highestSupportedLod));
settings.save();
}
fn leavesQualityCallback(newValue: u16) void {
settings.leavesQuality = newValue;
settings.save();
@ -106,6 +112,9 @@ pub fn onOpen() void {
const list = VerticalList.init(.{padding, 16 + padding}, 300, 16);
list.add(ContinuousSlider.init(.{0, 0}, 128, 10.0, 154.0, @floatFromInt(settings.fpsCap orelse 154), &fpsCapCallback, &fpsCapFormatter));
list.add(DiscreteSlider.init(.{0, 0}, 128, "#ffffffRender Distance: ", "{}", &renderDistances, @min(@max(settings.renderDistance, renderDistances[0]) - renderDistances[0], renderDistances.len - 1), &renderDistanceCallback));
if(main.game.world == null) {
list.add(DiscreteSlider.init(.{0, 0}, 128, "#ffffffHighest LOD: ", "{s}", &lodValues, @min(settings.highestLod, settings.highestSupportedLod), &highestLodCallback));
}
list.add(DiscreteSlider.init(.{0, 0}, 128, "#ffffffLeaves Quality (TODO: requires reload): ", "{}", &leavesQualities, settings.leavesQuality - leavesQualities[0], &leavesQualityCallback));
list.add(ContinuousSlider.init(.{0, 0}, 128, 50.0, 400.0, settings.@"lod0.5Distance", &lodDistanceCallback, &lodDistanceFormatter));
list.add(ContinuousSlider.init(.{0, 0}, 128, 40.0, 120.0, settings.fov, &fovCallback, &fovFormatter));

View File

@ -1430,7 +1430,7 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
}
}
// lod border:
if(self.pos.voxelSize == 1 << settings.highestLOD) continue;
if(self.pos.voxelSize == @as(u31, 1) << settings.highestLod) continue;
const neighborMesh = mesh_storage.getNeighborAndIncreaseRefCount(self.pos, 2*self.pos.voxelSize, neighbor) orelse {
self.mutex.lock();
defer self.mutex.unlock();

View File

@ -33,8 +33,8 @@ const ChunkMeshNode = struct {
};
const storageSize = 64;
const storageMask = storageSize - 1;
var storageLists: [settings.highestLOD + 1]*[storageSize*storageSize*storageSize]ChunkMeshNode = undefined;
var mapStorageLists: [settings.highestLOD + 1]*[storageSize*storageSize]?*LightMap.LightMapFragment = undefined;
var storageLists: [settings.highestSupportedLod + 1]*[storageSize*storageSize*storageSize]ChunkMeshNode = undefined;
var mapStorageLists: [settings.highestSupportedLod + 1]*[storageSize*storageSize]?*LightMap.LightMapFragment = undefined;
var meshList = main.List(*chunk_meshing.ChunkMesh).init(main.globalAllocator);
var priorityMeshUpdateList = main.List(*chunk_meshing.ChunkMesh).init(main.globalAllocator);
pub var updatableList = main.List(*chunk_meshing.ChunkMesh).init(main.globalAllocator);
@ -132,7 +132,7 @@ fn finishedMeshingMask(x: bool, y: bool, z: bool) u8 {
fn updateHigherLodNodeFinishedMeshing(pos_: chunk.ChunkPosition, finishedMeshing: bool) void {
const lod = std.math.log2_int(u31, pos_.voxelSize);
if(lod == settings.highestLOD) return;
if(lod == settings.highestLod) return;
var pos = pos_;
pos.wx &= ~@as(i32, pos.voxelSize*chunk.chunkSize);
pos.wy &= ~@as(i32, pos.voxelSize*chunk.chunkSize);
@ -178,7 +178,7 @@ pub fn getBlock(x: i32, y: i32, z: i32) ?blocks.Block {
pub fn getBlockFromAnyLod(x: i32, y: i32, z: i32) blocks.Block {
var lod: u5 = 0;
while(lod < settings.highestLOD) : (lod += 1) {
while(lod < settings.highestLod) : (lod += 1) {
const node = getNodePointer(.{.wx = x, .wy = y, .wz = z, .voxelSize=@as(u31, 1) << lod});
node.mutex.lock();
defer node.mutex.unlock();
@ -209,7 +209,7 @@ pub fn getMeshAndIncreaseRefCount(pos: chunk.ChunkPosition) ?*chunk_meshing.Chun
pub fn getMeshFromAnyLodAndIncreaseRefCount(wx: i32, wy: i32, wz: i32, voxelSize: u31) ?*chunk_meshing.ChunkMesh {
var lod: u5 = @ctz(voxelSize);
while(lod < settings.highestLOD) : (lod += 1) {
while(lod < settings.highestLod) : (lod += 1) {
const mesh = getMeshAndIncreaseRefCount(.{.wx = wx & ~chunk.chunkMask<<lod, .wy = wy & ~chunk.chunkMask<<lod, .wz = wz & ~chunk.chunkMask<<lod, .voxelSize=@as(u31, 1) << lod});
return mesh orelse continue;
}
@ -284,7 +284,7 @@ fn isMapInRenderDistance(pos: LightMap.MapFragmentPosition) bool {
}
fn freeOldMeshes(olderPx: i32, olderPy: i32, olderPz: i32, olderRD: u16) void { // MARK: freeOldMeshes()
for(0..storageLists.len) |_lod| {
for(0..settings.highestLod + 1) |_lod| {
const lod: u5 = @intCast(_lod);
const maxRenderDistanceNew = lastRD*chunk.chunkSize << lod;
const maxRenderDistanceOld = olderRD*chunk.chunkSize << lod;
@ -362,7 +362,7 @@ fn freeOldMeshes(olderPx: i32, olderPy: i32, olderPz: i32, olderRD: u16) void {
}
}
}
for(0..mapStorageLists.len) |_lod| {
for(0..settings.highestLod + 1) |_lod| {
const lod: u5 = @intCast(_lod);
const maxRenderDistanceNew = lastRD*chunk.chunkSize << lod;
const maxRenderDistanceOld = olderRD*chunk.chunkSize << lod;
@ -426,7 +426,7 @@ fn freeOldMeshes(olderPx: i32, olderPy: i32, olderPz: i32, olderRD: u16) void {
}
fn createNewMeshes(olderPx: i32, olderPy: i32, olderPz: i32, olderRD: u16, meshRequests: *main.List(chunk.ChunkPosition), mapRequests: *main.List(LightMap.MapFragmentPosition)) void { // MARK: createNewMeshes()
for(0..storageLists.len) |_lod| {
for(0..settings.highestLod + 1) |_lod| {
const lod: u5 = @intCast(_lod);
const maxRenderDistanceNew = lastRD*chunk.chunkSize << lod;
const maxRenderDistanceOld = olderRD*chunk.chunkSize << lod;
@ -502,7 +502,7 @@ fn createNewMeshes(olderPx: i32, olderPy: i32, olderPz: i32, olderRD: u16, meshR
}
}
}
for(0..mapStorageLists.len) |_lod| {
for(0..settings.highestLod + 1) |_lod| {
const lod: u5 = @intCast(_lod);
const maxRenderDistanceNew = lastRD*chunk.chunkSize << lod;
const maxRenderDistanceOld = olderRD*chunk.chunkSize << lod;
@ -605,7 +605,7 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, frustum: *co
.wz = @intFromFloat(@floor(playerPos[2])),
.voxelSize = 1,
};
const lod: u3 = settings.highestLOD;
const lod: u3 = settings.highestLod;
firstPos.wx &= ~@as(i32, chunk.chunkMask << lod | (@as(i32, 1) << lod)-1);
firstPos.wy &= ~@as(i32, chunk.chunkMask << lod | (@as(i32, 1) << lod)-1);
firstPos.wz &= ~@as(i32, chunk.chunkMask << lod | (@as(i32, 1) << lod)-1);
@ -631,7 +631,7 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, frustum: *co
const relPos: Vec3d = @as(Vec3d, @floatFromInt(Vec3i{pos.wx, pos.wy, pos.wz})) - playerPos;
const relPosFloat: Vec3f = @floatCast(relPos);
if(pos.voxelSize == @as(i32, 1) << settings.highestLOD) {
if(pos.voxelSize == @as(i32, 1) << settings.highestLod) {
for(chunk.Neighbor.iterable) |neighbor| {
const component = neighbor.extractDirectionComponent(relPosFloat);
if(neighbor.isPositive() and component + @as(f32, @floatFromInt(chunk.chunkSize*pos.voxelSize)) <= 0) continue;
@ -687,7 +687,7 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, frustum: *co
for(nodeList.items) |node| {
const pos = node.pos;
var isNeighborLod: [6]bool = .{false} ** 6;
if(pos.voxelSize != @as(i32, 1) << settings.highestLOD) {
if(pos.voxelSize != @as(i32, 1) << settings.highestLod) {
for(chunk.Neighbor.iterable) |neighbor| {
var neighborPos = chunk.ChunkPosition{
.wx = pos.wx +% neighbor.relX()*chunk.chunkSize*pos.voxelSize,

View File

@ -273,7 +273,7 @@ fn cacheInit(pos: MapFragmentPosition) *MapFragment {
pub fn regenerateLOD(worldName: []const u8) !void { // MARK: regenerateLOD()
std.log.info("Regenerating map LODs...", .{});
// Delete old LODs:
for(1..main.settings.highestLOD+1) |i| {
for(1..main.settings.highestSupportedLod+1) |i| {
const lod = @as(u32, 1) << @intCast(i);
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/maps", .{worldName}) catch unreachable;
defer main.stackAllocator.free(path);
@ -568,7 +568,7 @@ pub fn regenerateLOD(worldName: []const u8) !void { // MARK: regenerateLOD()
// Generate LODs
var cur = mapFragment;
defer if(cur.pos.voxelSize != 1) cur.decreaseRefCount();
while(cur.pos.voxelSizeShift < main.settings.highestLOD) {
while(cur.pos.voxelSizeShift < main.settings.highestSupportedLod) {
var nextPos = cur.pos;
nextPos.voxelSize *= 2;
nextPos.voxelSizeShift += 1;

View File

@ -257,7 +257,7 @@ const ChunkManager = struct { // MARK: ChunkManager
}
pub fn deinit(self: ChunkManager) void {
for(0..main.settings.highestLOD) |_| {
for(0..main.settings.highestSupportedLod) |_| {
chunkCache.clear();
}
entityChunkHashMap.deinit();
@ -656,7 +656,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
try terrain.SurfaceMap.regenerateLOD(self.name);
}
// Delete old LODs:
for(1..main.settings.highestLOD+1) |i| {
for(1..main.settings.highestSupportedLod+1) |i| {
const lod = @as(u32, 1) << @intCast(i);
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/chunks", .{self.name}) catch unreachable;
defer main.stackAllocator.free(path);

View File

@ -10,7 +10,7 @@ pub const entityLookback: i16 = 100;
pub const version = "Cubyz α 0.12.0";
pub const highestLOD: u5 = 5;
pub const highestSupportedLod: u3 = 5;
pub var simulationDistance: u16 = 4;
@ -29,6 +29,8 @@ pub var controllerSensitivity: f32 = 1;
pub var renderDistance: u16 = 7;
pub var highestLod: u3 = highestSupportedLod;
pub var resolutionScale: f32 = 1;
pub var bloom: bool = true;