start rewriting mesh code in zig

This commit is contained in:
catangent 2024-12-16 23:19:26 +00:00
parent 5a76cdcd13
commit 6f1eb16a30
14 changed files with 47357 additions and 40 deletions

3
.gitmodules vendored
View file

@ -1,3 +1,6 @@
[submodule "raylib"]
path = raylib
url = git@github.com:raysan5/raylib.git
[submodule "zig-gamedev"]
path = zig-gamedev
url = https://github.com/zig-gamedev/zig-gamedev.git

View file

@ -4,6 +4,18 @@ pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const rl = raylib: {
const rl = b.dependency("raylib", .{
.target = target,
.optimize = optimize,
});
break :raylib rl;
};
const znoise = b.dependency("znoise", .{
.target = target,
.optimize = optimize,
});
const exe = b.addExecutable(.{
.name = "voxel_test",
.root_source_file = b.path("src/main.zig"),
@ -11,19 +23,14 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
});
const rl = b.dependency("raylib", .{
.target = target,
.optimize = optimize,
});
exe.linkLibrary(rl.artifact("raylib"));
exe.root_module.addImport("znoise", znoise.module("root"));
exe.linkLibrary(znoise.artifact("FastNoiseLite"));
b.installArtifact(exe);
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
@ -38,6 +45,8 @@ pub fn build(b: *std.Build) void {
});
exe_unit_tests.linkLibrary(rl.artifact("raylib"));
exe_unit_tests.root_module.addImport("znoise", znoise.module("root"));
exe_unit_tests.linkLibrary(znoise.artifact("FastNoiseLite"));
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);

View file

@ -4,9 +4,8 @@
.version = "0.0.0",
.dependencies = .{
.raylib = .{
.path = "raylib",
},
.znoise = .{ .path = "zig-gamedev/libs/znoise" },
.raylib = .{ .path = "raylib" },
},
.paths = .{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Before After
Before After

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Before After
Before After

40465
rmodels.tmpzig Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,10 @@
const std = @import("std");
const rh = @import("util/raylib_helper.zig");
const raylib = rh.raylib;
const v3 = rh.v3;
const raylib_helper = @import("lib_helpers/raylib_helper.zig");
const raylib = raylib_helper.raylib;
const v3 = raylib_helper.v3;
const znoise = @import("znoise");
const chunks = @import("world/chunk.zig");
const TILE_TEXTURE_RESOLUTION = 16;
@ -14,7 +17,7 @@ pub fn drawCameraPosition(camera: raylib.Camera3D, x: i32, y: i32) !void {
const slice = try std.fmt.bufPrintZ(
&buf,
"position: {d} {d} {d}",
"position: {d:.2} {d:.2} {d:.2}",
.{ camera.position.x, camera.position.y, camera.position.z },
);
@ -43,7 +46,8 @@ pub fn main() !void {
defer raylib.CloseWindow();
raylib.DisableCursor();
raylib.SetTargetFPS(60);
raylib.SetWindowState(raylib.FLAG_VSYNC_HINT);
raylib.SetWindowState(raylib.FLAG_FULLSCREEN_MODE);
var camera = raylib.Camera3D{
.position = raylib.Vector3{ .x = 0, .y = 0, .z = 0 },
@ -67,14 +71,18 @@ pub fn main() !void {
var chunk = try chunks.Chunk.init(a7r);
defer chunk.deinit();
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 xt: i32 = @as(i32, @intCast(x)) - 16;
const yt: i32 = @as(i32, @intCast(y)) - 16;
const zt: i32 = @as(i32, @intCast(z)) - 16;
if (xt * xt + yt * yt + zt * zt < 15 * 15) chunk.setTile(x, y, z, if (2 * xt > yt - 30) 1 else 2);
const xf: f32 = @floatFromInt(raw_x);
const yf: f32 = @floatFromInt(raw_y);
const zf: f32 = @floatFromInt(raw_z);
const height: f32 = (height_generator.noise2(xf, zf) + 1) * 16;
const tile_type: u32 = if (tile_type_generator.noise3(xf, yf, zf) > 0) 1 else 2;
if (height >= yf) chunk.setTile(x, y, z, tile_type);
};
if (benchmark_chunk_meshing) {

View file

@ -0,0 +1,177 @@
const std = @import("std");
const raylib_helper = @import("../lib_helpers/raylib_helper.zig");
const raylib = raylib_helper.raylib;
const MAX_VBOS = 4;
const VERTICES_VBO_ID = 0;
const TEXCOORDS_VBO_ID = 1;
const TEXCOORDS2_VBO_ID = 2;
const NORMALS_VBO_ID = 3;
const ChunkMesh = packed struct {
vertexCount: i32,
triangleCount: i32,
vertices: [*]f32, // vertex position, XYZ, 3 vars per vertex
texcoords: [*]f32, // vertex texture coorinates, UV, 2 vars per vertex
texcoords2: [*]f32, // vertex second texture coorinates, UV, 2 vars per vertex
normals: [*]f32, // vertex normals, XYZ, 3 vars per vertex
vaoId: u32,
vboId: [*]u32,
};
pub fn UploadChunkMesh(mesh: ChunkMesh, dynamic: bool) void {
if (mesh.vaoId > 0) {
raylib.TraceLog(raylib.LOG_WARNING, "VAO: [ID %i] Trying to re-load an already loaded chunk mesh", mesh.vaoId);
return;
}
mesh.vboId = @ptrCast(@alignCast(raylib.MemAlloc(@sizeOf(u32) * MAX_VBOS)));
mesh.vaoId = 0;
mesh.vboId[VERTICES_VBO_ID] = 0;
mesh.vboId[TEXCOORDS_VBO_ID] = 0;
mesh.vboId[TEXCOORDS2_VBO_ID] = 0;
mesh.vboId[NORMALS_VBO_ID] = 0;
mesh.vaoId = raylib.rlLoadVertexArray();
raylib.rlEnableVertexArray(mesh.vaoId);
mesh.vboId[VERTICES_VBO_ID] = raylib.rlLoadVertexBuffer(mesh.vertices, mesh.vertexCount * 3 * @sizeOf(f32), dynamic);
raylib.rlSetVertexAttribute(VERTICES_VBO_ID, 3, raylib.RL_FLOAT, false, 0, 0);
raylib.rlEnableVertexAttribute(VERTICES_VBO_ID);
mesh.vboId[TEXCOORDS_VBO_ID] = raylib.rlLoadVertexBuffer(mesh.texcoords, mesh.vertexCount * 2 * @sizeOf(f32), dynamic);
raylib.rlSetVertexAttribute(TEXCOORDS_VBO_ID, 2, raylib.RL_FLOAT, false, 0, 0);
raylib.rlEnableVertexAttribute(TEXCOORDS_VBO_ID);
mesh.vboId[TEXCOORDS2_VBO_ID] = raylib.rlLoadVertexBuffer(mesh.texcoords, mesh.vertexCount * 2 * @sizeOf(f32), dynamic);
raylib.rlSetVertexAttribute(TEXCOORDS2_VBO_ID, 2, raylib.RL_FLOAT, false, 0, 0);
raylib.rlEnableVertexAttribute(TEXCOORDS2_VBO_ID);
mesh.vboId[NORMALS_VBO_ID] = raylib.rlLoadVertexBuffer(mesh.vertices, mesh.vertexCount * 3 * @sizeOf(f32), dynamic);
raylib.rlSetVertexAttribute(NORMALS_VBO_ID, 3, raylib.RL_FLOAT, false, 0, 0);
raylib.rlEnableVertexAttribute(NORMALS_VBO_ID);
if (mesh.vaoId > 0) {
raylib.TraceLog(raylib.LOG_INFO, "VAO: [ID %i] Chunk mesh uploaded successfully to VRAM (GPU)", mesh.vaoId);
} else {
raylib.TraceLog(raylib.LOG_INFO, "VBO: Chunk mesh uploaded successfully to VRAM (GPU)");
}
raylib.rlDisableVertexArray();
}
pub fn UpdateMeshBuffer(mesh: ChunkMesh, index: i32, data: ?*const anyopaque, dataSize: i32, offset: i32) void {
raylib.rlUpdateVertexBuffer(mesh.vboId[index], data, dataSize, offset);
}
pub export fn UnloadMesh(mesh: ChunkMesh) void {
raylib.rlUnloadVertexArray(mesh.vaoId);
if (mesh.vboId != null) {
for (0..MAX_VBOS) |i| {
raylib.rlUnloadVertexBuffer(mesh.vboId[i]);
}
}
raylib.MemFree(mesh.vboId);
raylib.MemFree(mesh.vertices);
raylib.MemFree(mesh.texcoords);
raylib.MemFree(mesh.texcoords2);
raylib.MemFree(mesh.normals);
}
pub fn DrawMesh(mesh: ChunkMesh, material: raylib.Material, transform: raylib.Matrix) void {
raylib.rlEnableShader(material.shader.id);
if (material.shader.locs[raylib.SHADER_LOC_COLOR_DIFFUSE] != -1) {
const values: [4]f32 = [4]f32{
@as(u32, @floatFromInt(material.maps[raylib.MATERIAL_MAP_DIFFUSE].color.r)) / 255.0,
@as(u32, @floatFromInt(material.maps[raylib.MATERIAL_MAP_DIFFUSE].color.g)) / 255.0,
@as(u32, @floatFromInt(material.maps[raylib.MATERIAL_MAP_DIFFUSE].color.b)) / 255.0,
@as(u32, @floatFromInt(material.maps[raylib.MATERIAL_MAP_DIFFUSE].color.a)) / 255.0,
};
raylib.rlSetUniform(material.shader.locs[raylib.SHADER_LOC_COLOR_DIFFUSE], values, raylib.SHADER_UNIFORM_VEC4, 1);
}
if (material.shader.locs[raylib.SHADER_LOC_COLOR_SPECULAR] != -1) {
const values: [4]f32 = [4]f32{
@as(u32, @floatFromInt(material.maps[raylib.MATERIAL_MAP_SPECULAR].color.r)) / 255.0,
@as(u32, @floatFromInt(material.maps[raylib.MATERIAL_MAP_SPECULAR].color.g)) / 255.0,
@as(u32, @floatFromInt(material.maps[raylib.MATERIAL_MAP_SPECULAR].color.b)) / 255.0,
@as(u32, @floatFromInt(material.maps[raylib.MATERIAL_MAP_SPECULAR].color.a)) / 255.0,
};
raylib.rlSetUniform(material.shader.locs[raylib.SHADER_LOC_COLOR_SPECULAR], values, raylib.SHADER_UNIFORM_VEC4, 1);
}
var matModel: raylib.Matrix = raylib.MatrixIdentity();
const matView: raylib.Matrix = raylib.rlGetMatrixModelview();
var matModelView: raylib.Matrix = raylib.MatrixIdentity();
const matProjection: raylib.Matrix = raylib.rlGetMatrixProjection();
if (material.shader.locs[raylib.SHADER_LOC_MATRIX_VIEW] != -1) raylib.rlSetUniformMatrix(material.shader.locs[raylib.SHADER_LOC_MATRIX_VIEW], matView);
if (material.shader.locs[raylib.SHADER_LOC_MATRIX_PROJECTION] != -1) raylib.rlSetUniformMatrix(material.shader.locs[raylib.SHADER_LOC_MATRIX_PROJECTION], matProjection);
matModel = raylib.MatrixMultiply(transform, raylib.rlGetMatrixTransform());
if (material.shader.locs[raylib.SHADER_LOC_MATRIX_MODEL] != -1) raylib.rlSetUniformMatrix(material.shader.locs[raylib.SHADER_LOC_MATRIX_MODEL], matModel);
matModelView = raylib.MatrixMultiply(matModel, matView);
if (material.shader.locs[raylib.SHADER_LOC_MATRIX_NORMAL] != -1) raylib.rlSetUniformMatrix(material.shader.locs[raylib.SHADER_LOC_MATRIX_NORMAL], raylib.MatrixTranspose(raylib.MatrixInvert(matModel)));
for (0..raylib.MAX_MATERIAL_MAPS) |i| {
if (material.maps[i].texture.id > 0) {
raylib.rlActiveTextureSlot(i);
if (i == raylib.MATERIAL_MAP_IRRADIANCE or i == raylib.MATERIAL_MAP_PREFILTER or i == raylib.MATERIAL_MAP_CUBEMAP) {
raylib.rlEnableTextureCubemap(material.maps[i].texture.id);
} else {
raylib.rlEnableTexture(material.maps[i].texture.id);
}
raylib.rlSetUniform(material.shader.locs[raylib.SHADER_LOC_MAP_DIFFUSE + i], &i, raylib.SHADER_UNIFORM_INT, 1);
}
}
if (!raylib.rlEnableVertexArray(mesh.vaoId)) {
raylib.rlEnableVertexBuffer(mesh.vboId[0]);
raylib.rlSetVertexAttribute(material.shader.locs[VERTICES_VBO_ID], 3, raylib.RL_FLOAT, 0, 0, 0);
raylib.rlEnableVertexAttribute(material.shader.locs[VERTICES_VBO_ID]);
raylib.rlEnableVertexBuffer(mesh.vboId[1]);
raylib.rlSetVertexAttribute(material.shader.locs[TEXCOORDS_VBO_ID], 2, raylib.RL_FLOAT, 0, 0, 0);
raylib.rlEnableVertexAttribute(material.shader.locs[TEXCOORDS_VBO_ID]);
raylib.rlEnableVertexBuffer(mesh.vboId[2]);
raylib.rlSetVertexAttribute(material.shader.locs[TEXCOORDS2_VBO_ID], 2, raylib.RL_FLOAT, 0, 0, 0);
raylib.rlEnableVertexAttribute(material.shader.locs[TEXCOORDS2_VBO_ID]);
raylib.rlEnableVertexBuffer(mesh.vboId[3]);
raylib.rlSetVertexAttribute(material.shader.locs[NORMALS_VBO_ID], 3, raylib.RL_FLOAT, 0, 0, 0);
raylib.rlEnableVertexAttribute(material.shader.locs[NORMALS_VBO_ID]);
}
var eyeCount = 1;
if (raylib.rlIsStereoRenderEnabled()) {
eyeCount = 2;
}
for (0..eyeCount) |eye| {
var matModelViewProjection: raylib.Matrix = raylib.MatrixIdentity();
if (eyeCount == 1) {
matModelViewProjection = raylib.MatrixMultiply(matModelView, matProjection);
} else {
raylib.rlViewport(@divTrunc(eye * raylib.rlGetFramebufferWidth(), 2), 0, @divTrunc(raylib.rlGetFramebufferWidth(), 2), raylib.rlGetFramebufferHeight());
matModelViewProjection = raylib.MatrixMultiply(raylib.MatrixMultiply(matModelView, raylib.rlGetMatrixViewOffsetStereo(eye)), raylib.rlGetMatrixProjectionStereo(eye));
}
raylib.rlSetUniformMatrix(material.shader.locs[raylib.SHADER_LOC_MATRIX_MVP], matModelViewProjection);
raylib.rlDrawVertexArray(0, mesh.vertexCount);
}
for (0..raylib.MAX_MATERIAL_MAPS) |i| {
if (material.maps[i].texture.id > 0) {
raylib.rlActiveTextureSlot(i);
if (((i == raylib.MATERIAL_MAP_IRRADIANCE) or (i == raylib.MATERIAL_MAP_PREFILTER)) or (i == raylib.MATERIAL_MAP_CUBEMAP)) {
raylib.rlDisableTextureCubemap();
} else {
raylib.rlDisableTexture();
}
}
}
raylib.rlDisableVertexArray();
raylib.rlDisableVertexBuffer();
raylib.rlDisableVertexBufferElement();
raylib.rlDisableShader();
raylib.rlSetMatrixModelview(matView);
raylib.rlSetMatrixProjection(matProjection);
}

6648
src/rendering/chunk_models.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,11 @@
const std = @import("std");
const rh = @import("../util/raylib_helper.zig");
const raylib = rh.raylib;
const v3 = rh.v3;
const raylib_helper = @import("../lib_helpers/raylib_helper.zig");
const raylib = raylib_helper.raylib;
const v3 = raylib_helper.v3;
const A7r = std.mem.Allocator;
const RawQuad = struct {
tile: i32,
tile: u32,
top_left: raylib.Vector3,
top_right: raylib.Vector3,
bottom_right: raylib.Vector3,
@ -16,13 +16,13 @@ const RawQuad = struct {
};
pub const Chunk = struct {
tiles: []i32,
tiles: []u32,
a7r: A7r,
pub fn init(a7r: A7r) !Chunk {
const self = Chunk{
.a7r = a7r,
.tiles = try a7r.alloc(i32, 32 * 32 * 32),
.tiles = try a7r.alloc(u32, 32 * 32 * 32),
};
@memset(self.tiles, 0);
return self;
@ -32,19 +32,19 @@ pub const Chunk = struct {
self.a7r.free(self.tiles);
}
pub fn getTile(self: Chunk, x: u5, y: u5, z: u5) i32 {
pub fn getTile(self: Chunk, x: u5, y: u5, z: u5) u32 {
return self.tiles[@as(u15, x) << 10 | @as(u15, y) << 5 | @as(u15, z)];
}
pub fn setTile(self: Chunk, x: u5, y: u5, z: u5, tile: i32) void {
pub fn setTile(self: Chunk, x: u5, y: u5, z: u5, tile: u32) void {
self.tiles[@as(u15, x) << 10 | @as(u15, y) << 5 | @as(u15, z)] = tile;
}
fn getTileRaw(self: Chunk, x: u5, y: u5, z: u5) i32 {
fn getTileRaw(self: Chunk, x: u5, y: u5, z: u5) u32 {
return self.tiles[@as(u15, x) << 10 | @as(u15, y) << 5 | @as(u15, z)];
}
inline fn getTileRawShifted(self: Chunk, x: u5, y: u5, z: u5, comptime d: comptime_int) i32 {
inline fn getTileRawShifted(self: Chunk, x: u5, y: u5, z: u5, comptime d: comptime_int) u32 {
if (d % 3 == 0) {
return self.getTileRaw(x, y, z);
} else if (d % 3 == 1) {
@ -61,12 +61,12 @@ pub const Chunk = struct {
inline for (0..3) |d| {
for (0..32) |raw_x| {
const x: u5 = @intCast(raw_x);
var positive_tile_surfaces: [32][32]i32 = .{.{0} ** 32} ** 32;
var negative_tile_surfaces: [32][32]i32 = .{.{0} ** 32} ** 32;
var positive_tile_surfaces: [32][32]u32 = .{.{0} ** 32} ** 32;
var negative_tile_surfaces: [32][32]u32 = .{.{0} ** 32} ** 32;
for (0..32) |raw_y| for (0..32) |raw_z| {
const y: u5 = @intCast(raw_y);
const z: u5 = @intCast(raw_z);
const tile: i32 = chunk.getTileRawShifted(x, y, z, d);
const tile: u32 = chunk.getTileRawShifted(x, y, z, d);
if (tile == 0) continue;
if (x == 31 or chunk.getTileRawShifted(x + 1, y, z, d) == 0) positive_tile_surfaces[y][z] = tile;
if (x == 0 or chunk.getTileRawShifted(x - 1, y, z, d) == 0) negative_tile_surfaces[y][z] = tile;
@ -154,7 +154,7 @@ pub const Chunk = struct {
for (raw_quads.items, 0..) |raw_quad, i| {
if (raw_quad.tile <= 0) continue;
const tile = @as(u32, @intCast(raw_quad.tile));
const tile = raw_quad.tile;
for (0..6) |j| {
normals[18 * i + 3 * j + 0] = raw_quad.normal.x;
@ -224,13 +224,7 @@ pub const Chunk = struct {
.texcoords = texcoords,
.texcoords2 = texcoords2,
.normals = normals,
.tangents = null,
.colors = null,
.indices = null,
.animVertices = null,
.animNormals = null,
.boneIds = null,
.boneWeights = null,
.vaoId = 0,
.vboId = null,
};

13
todo.md Normal file
View file

@ -0,0 +1,13 @@
# current tasks
yoink implementation of mesh into meshes.zig so i could modify it to add ambient occlusion vars
implement ambient occlusion either
- via passing extra info to shader (can use 132 bits to indicate what tiles around the quad are obsuring light. need to pass as an extra variable)
implement animated textures by either
- making literally everything animated
- somehow passing extra info to shader
limit vertical camera rotations
update libraries like raylib
# future tasks
implement chunk meshing cache to reduce delay on block placement
investigate binary/SIMD meshing for performance

1
zig-gamedev Submodule

@ -0,0 +1 @@
Subproject commit d96ecc993bcfc4461f44d9432589dc9273952a78