feat: basic world state, manual chunkgen for now
This commit is contained in:
parent
06ca8a5c0d
commit
dd41aabf0f
4 changed files with 132 additions and 46 deletions
58
src/main.zig
58
src/main.zig
|
|
@ -7,6 +7,8 @@ const v3 = raylib_helper.v3;
|
||||||
const znoise = @import("znoise");
|
const znoise = @import("znoise");
|
||||||
|
|
||||||
const chunks = @import("world/chunk.zig");
|
const chunks = @import("world/chunk.zig");
|
||||||
|
const WorldState = @import("world/world_state.zig").WorldState;
|
||||||
|
const chunk_generators = @import("world/chunk_generators.zig");
|
||||||
|
|
||||||
const TILE_TEXTURE_RESOLUTION = 16;
|
const TILE_TEXTURE_RESOLUTION = 16;
|
||||||
|
|
||||||
|
|
@ -29,36 +31,20 @@ pub fn moveCamera(camera: *raylib.Camera3D, vec: raylib.Vector3) void {
|
||||||
camera.target = v3.add(camera.target, vec);
|
camera.target = v3.add(camera.target, vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createDefaultChunk(a7r: Allocator) !chunks.Chunk {
|
|
||||||
var chunk = try chunks.Chunk.init(a7r);
|
|
||||||
|
|
||||||
const height_generator = znoise.FnlGenerator{ .seed = 413445 };
|
|
||||||
const tile_type_generator = znoise.FnlGenerator{ .seed = 4435, .frequency = 0.1 };
|
|
||||||
for (0..32) |raw_x| for (0..32) |raw_y| for (0..32) |raw_z| {
|
|
||||||
const x: u5 = @intCast(raw_x);
|
|
||||||
const y: u5 = @intCast(raw_y);
|
|
||||||
const z: u5 = @intCast(raw_z);
|
|
||||||
const xf: f32 = @floatFromInt(raw_x);
|
|
||||||
const yf: f32 = @floatFromInt(raw_y);
|
|
||||||
const zf: f32 = @floatFromInt(raw_z);
|
|
||||||
const tile_type: u32 = if (tile_type_generator.noise3(xf, yf, zf) > 0) 1 else 2;
|
|
||||||
const height: f32 = (height_generator.noise2(xf, zf) + 1) * 16;
|
|
||||||
if (height >= yf) chunk.setTile(x, y, z, tile_type);
|
|
||||||
// if((xf-16)*(xf-16)+(yf-16)*(yf-16)+(zf-16)*(zf-16) < 16*16) chunk.setTile(x, y, z, tile_type);
|
|
||||||
};
|
|
||||||
return chunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
if (!debug) raylib.SetTraceLogLevel(raylib.LOG_ERROR);
|
if (!debug) raylib.SetTraceLogLevel(raylib.LOG_ERROR);
|
||||||
|
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
const a7r = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
defer {
|
defer {
|
||||||
const status = gpa.deinit();
|
const status = gpa.deinit();
|
||||||
if (status == .leak) std.debug.print("MEMORY LEAK DETECTED!!!!!!!!!!!!!!!!!!!!!!\n", .{}) else std.debug.print("no leaks detected.\n", .{});
|
if (status == .leak) std.debug.print("MEMORY LEAK DETECTED!!!!!!!!!!!!!!!!!!!!!!\n", .{}) else std.debug.print("no leaks detected.\n", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var thread_pool: std.Thread.Pool = undefined;
|
||||||
|
try thread_pool.init(.{.allocator = allocator});
|
||||||
|
defer thread_pool.deinit();
|
||||||
|
|
||||||
raylib.SetConfigFlags(raylib.FLAG_WINDOW_RESIZABLE | raylib.FLAG_FULLSCREEN_MODE);
|
raylib.SetConfigFlags(raylib.FLAG_WINDOW_RESIZABLE | raylib.FLAG_FULLSCREEN_MODE);
|
||||||
|
|
||||||
const display = raylib.GetCurrentMonitor();
|
const display = raylib.GetCurrentMonitor();
|
||||||
|
|
@ -93,16 +79,13 @@ pub fn main() !void {
|
||||||
defer raylib.UnloadShader(shader);
|
defer raylib.UnloadShader(shader);
|
||||||
raylib.SetShaderValue(shader, raylib.GetShaderLocation(shader, "textureTiling"), &.{ @as(f32, @floatFromInt(tile_columns)), @as(f32, @floatFromInt(tile_rows)) }, raylib.SHADER_UNIFORM_VEC2);
|
raylib.SetShaderValue(shader, raylib.GetShaderLocation(shader, "textureTiling"), &.{ @as(f32, @floatFromInt(tile_columns)), @as(f32, @floatFromInt(tile_rows)) }, raylib.SHADER_UNIFORM_VEC2);
|
||||||
|
|
||||||
var chunk = try createDefaultChunk(a7r);
|
var world_state: WorldState = WorldState.init(thread_pool, allocator);
|
||||||
defer chunk.deinit();
|
defer world_state.deinit();
|
||||||
|
|
||||||
const model = raylib.LoadChunkModelFromMesh(try chunk.createMesh(tile_rows, tile_columns));
|
for (0..10) |x| for (0..10) |z| {
|
||||||
defer raylib.UnloadChunkModel(model);
|
_ = try world_state.generateChunk(.{@intCast(x), 0, @intCast(z)});
|
||||||
model.materials[0].maps[raylib.MATERIAL_MAP_DIFFUSE].texture = texture;
|
_ = try world_state.generateChunkModel(.{@intCast(x), 0, @intCast(z)}, tile_rows, tile_columns, texture, ambient_occlusion_texture, shader);
|
||||||
model.materials[0].shader = shader;
|
};
|
||||||
|
|
||||||
model.materials[0].shader.locs[raylib.SHADER_LOC_MAP_DIFFUSE+1] = raylib.GetShaderLocation(shader, "occlusionMap");
|
|
||||||
raylib.SetShaderValueTexture(shader, model.materials[0].shader.locs[raylib.SHADER_LOC_MAP_DIFFUSE+1], ambient_occlusion_texture); model.materials[0].maps[raylib.MATERIAL_MAP_DIFFUSE+1].texture = ambient_occlusion_texture;
|
|
||||||
|
|
||||||
while (!raylib.WindowShouldClose()) {
|
while (!raylib.WindowShouldClose()) {
|
||||||
raylib.ClearBackground(raylib.BLACK);
|
raylib.ClearBackground(raylib.BLACK);
|
||||||
|
|
@ -140,16 +123,19 @@ pub fn main() !void {
|
||||||
raylib.BeginDrawing();
|
raylib.BeginDrawing();
|
||||||
defer raylib.EndDrawing();
|
defer raylib.EndDrawing();
|
||||||
|
|
||||||
const model_position = v3.new(0, 0, 0);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
raylib.BeginMode3D(camera);
|
raylib.BeginMode3D(camera);
|
||||||
defer raylib.EndMode3D();
|
defer raylib.EndMode3D();
|
||||||
raylib.BeginShaderMode(shader);
|
|
||||||
defer raylib.EndShaderMode();
|
|
||||||
|
|
||||||
raylib.SetShaderValueTexture(shader, raylib.GetShaderLocation(shader, "ambientOcclusionTexture"), ambient_occlusion_texture);
|
world_state.chunks_access_mutex.lock();
|
||||||
raylib.DrawChunkModel(model, model_position, 0.5, raylib.WHITE);
|
var chunks_iterator = world_state.chunks.valueIterator();
|
||||||
|
while (chunks_iterator.next()) |entry| {
|
||||||
|
if (entry.*.model) |model| {
|
||||||
|
const model_position = v3.new(@floatFromInt(entry.position[0]*16), @floatFromInt(entry.position[1]*16), @floatFromInt(entry.position[2]*16));
|
||||||
|
raylib.DrawChunkModel(model, model_position, 0.5, raylib.WHITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
world_state.chunks_access_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
raylib.DrawFPS(10, 10);
|
raylib.DrawFPS(10, 10);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ const std = @import("std");
|
||||||
const raylib_helper = @import("../lib_helpers/raylib_helper.zig");
|
const raylib_helper = @import("../lib_helpers/raylib_helper.zig");
|
||||||
const raylib = raylib_helper.raylib;
|
const raylib = raylib_helper.raylib;
|
||||||
const v3 = raylib_helper.v3;
|
const v3 = raylib_helper.v3;
|
||||||
const A7r = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const comptimePrint = std.fmt.comptimePrint;
|
const comptimePrint = std.fmt.comptimePrint;
|
||||||
|
|
||||||
const VERTICES_BLOCK_SIZE = 2 * 3 * 3;
|
const VERTICES_BLOCK_SIZE = 2 * 3 * 3;
|
||||||
|
|
@ -56,19 +56,19 @@ comptime {
|
||||||
|
|
||||||
pub const Chunk = struct {
|
pub const Chunk = struct {
|
||||||
tiles: []u32,
|
tiles: []u32,
|
||||||
a7r: A7r,
|
allocator: Allocator,
|
||||||
|
|
||||||
pub fn init(a7r: A7r) !Chunk {
|
pub fn init(allocator: Allocator) !Chunk {
|
||||||
const self = Chunk{
|
const self = Chunk{
|
||||||
.a7r = a7r,
|
.allocator = allocator,
|
||||||
.tiles = try a7r.alloc(u32, 32 * 32 * 32),
|
.tiles = try allocator.alloc(u32, 32 * 32 * 32),
|
||||||
};
|
};
|
||||||
@memset(self.tiles, 0);
|
@memset(self.tiles, 0);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: Chunk) void {
|
pub fn deinit(self: Chunk) void {
|
||||||
self.a7r.free(self.tiles);
|
self.allocator.free(self.tiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the tile at (x, y, z), but with potential side effects. If you imagine tiles to be a 3-dimensional array, this would be tiles[x][y][z].
|
// Fetch the tile at (x, y, z), but with potential side effects. If you imagine tiles to be a 3-dimensional array, this would be tiles[x][y][z].
|
||||||
|
|
@ -291,7 +291,7 @@ pub const Chunk = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scanForRawQuads(chunk: Chunk) !std.ArrayList(RawQuad) {
|
fn scanForRawQuads(chunk: Chunk) !std.ArrayList(RawQuad) {
|
||||||
var raw_quads = try std.ArrayList(RawQuad).initCapacity(chunk.a7r, 4096);
|
var raw_quads = try std.ArrayList(RawQuad).initCapacity(chunk.allocator, 4096);
|
||||||
|
|
||||||
// Begin scanning the chunk for tile surfaces to make raw quads.
|
// Begin scanning the chunk for tile surfaces to make raw quads.
|
||||||
inline for (0..3) |dimension| { // Iterate over the 3 dimensions, X, Y and Z.
|
inline for (0..3) |dimension| { // Iterate over the 3 dimensions, X, Y and Z.
|
||||||
|
|
|
||||||
23
src/world/chunk_generators.zig
Normal file
23
src/world/chunk_generators.zig
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const znoise = @import("znoise");
|
||||||
|
|
||||||
|
const chunks = @import("chunk.zig");
|
||||||
|
|
||||||
|
pub fn createChunk(allocator: Allocator, chunk_pos: @Vector(3, i64)) !chunks.Chunk {
|
||||||
|
var chunk = try chunks.Chunk.init(allocator);
|
||||||
|
|
||||||
|
const height_generator = znoise.FnlGenerator{ .seed = 413445 };
|
||||||
|
for (0..32) |raw_x| for (0..32) |raw_y| for (0..32) |raw_z| {
|
||||||
|
const local_x: u5 = @intCast(raw_x);
|
||||||
|
const local_y: u5 = @intCast(raw_y);
|
||||||
|
const local_z: u5 = @intCast(raw_z);
|
||||||
|
const x: f32 = @floatFromInt(@as(i64, @intCast(raw_x)) + chunk_pos[0]*32);
|
||||||
|
const y: f32 = @floatFromInt(@as(i64, @intCast(raw_y)) + chunk_pos[1]*32);
|
||||||
|
const z: f32 = @floatFromInt(@as(i64, @intCast(raw_z)) + chunk_pos[2]*32);
|
||||||
|
const height: f32 = (height_generator.noise2(x, z) + 1) * 16;
|
||||||
|
const tile_type: u32 = if(height >= y + 1) 2 else 1;
|
||||||
|
if (height >= y) chunk.setTile(local_x, local_y, local_z, tile_type);
|
||||||
|
};
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
77
src/world/world_state.zig
Normal file
77
src/world/world_state.zig
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const Thread = std.Thread;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const AutoHashMap = std.AutoHashMap;
|
||||||
|
|
||||||
|
const Chunk = @import("chunk.zig").Chunk;
|
||||||
|
const chunk_generators = @import("chunk_generators.zig");
|
||||||
|
|
||||||
|
const raylib_helper = @import("../lib_helpers/raylib_helper.zig");
|
||||||
|
const raylib = raylib_helper.raylib;
|
||||||
|
|
||||||
|
pub const WorldStateError = error{
|
||||||
|
ChunkNotGeneratedError,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ChunkEntry = struct {
|
||||||
|
chunk: ?Chunk = null,
|
||||||
|
model: ?raylib.ChunkModel = null,
|
||||||
|
position: @Vector(3, i64),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const WorldState = struct {
|
||||||
|
pool: Thread.Pool = undefined,
|
||||||
|
allocator: Allocator = undefined,
|
||||||
|
|
||||||
|
// TODO: we can do better than a hashmap and a mutex
|
||||||
|
chunks: AutoHashMap(@Vector(3, i64), ChunkEntry) = undefined,
|
||||||
|
chunks_access_mutex: Thread.Mutex = .{},
|
||||||
|
|
||||||
|
pub fn init(global_pool: Thread.Pool, allocator: Allocator) WorldState {
|
||||||
|
var world_state: WorldState = undefined;
|
||||||
|
world_state.pool = global_pool;
|
||||||
|
world_state.allocator = allocator;
|
||||||
|
world_state.chunks = AutoHashMap(@Vector(3, i64), ChunkEntry).init(allocator);
|
||||||
|
return world_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *WorldState) void {
|
||||||
|
var chunk_iterator = self.chunks.valueIterator();
|
||||||
|
while(chunk_iterator.next()) |entry| {
|
||||||
|
if(entry.*.chunk) |chunk| {
|
||||||
|
chunk.deinit();
|
||||||
|
}
|
||||||
|
if(entry.*.model) |model| {
|
||||||
|
raylib.UnloadChunkModel(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.chunks.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generateChunk(self: *WorldState, pos: @Vector(3, i64)) !Chunk {
|
||||||
|
const chunk = try chunk_generators.createChunk(self.allocator, pos);
|
||||||
|
self.chunks_access_mutex.lock();
|
||||||
|
try self.chunks.put(pos, .{.chunk = chunk, .position = pos});
|
||||||
|
self.chunks_access_mutex.unlock();
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generateChunkModel(self: *WorldState, pos: @Vector(3, i64), tile_rows: u32, tile_columns: u32, texture: raylib.Texture, ambient_occlusion_texture: raylib.Texture, shader: raylib.Shader) !raylib.ChunkModel {
|
||||||
|
self.chunks_access_mutex.lock();
|
||||||
|
const chunk_entry = (try self.chunks.getOrPutValue(pos, .{.position = pos})).value_ptr;
|
||||||
|
self.chunks_access_mutex.unlock();
|
||||||
|
|
||||||
|
const chunk = chunk_entry.chunk;
|
||||||
|
if(chunk == null) return WorldStateError.ChunkNotGeneratedError;
|
||||||
|
|
||||||
|
const model = raylib.LoadChunkModelFromMesh(try chunk.?.createMesh(tile_rows, tile_columns));
|
||||||
|
model.materials[0].maps[raylib.MATERIAL_MAP_DIFFUSE].texture = texture;
|
||||||
|
model.materials[0].shader = shader;
|
||||||
|
|
||||||
|
model.materials[0].shader.locs[raylib.SHADER_LOC_MAP_DIFFUSE+1] = raylib.GetShaderLocation(shader, "occlusionMap");
|
||||||
|
raylib.SetShaderValueTexture(shader, model.materials[0].shader.locs[raylib.SHADER_LOC_MAP_DIFFUSE+1], ambient_occlusion_texture); model.materials[0].maps[raylib.MATERIAL_MAP_DIFFUSE+1].texture = ambient_occlusion_texture;
|
||||||
|
|
||||||
|
chunk_entry.model = model;
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Add table
Add a link
Reference in a new issue