Created
July 3, 2023 23:12
-
-
Save ConnorRigby/baf48efbfc75d23e75a6946b38c19158 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const std = @import("std"); | |
const log = std.log.scoped(.Main); | |
const glfw = @import("glfw"); | |
const zgl = @import("zgl"); | |
const zlm = @import("zlm"); | |
const Mat4 = zlm.Mat4; | |
const Shader = @import("Shader.zig"); | |
const Texture = @import("Texture.zig"); | |
const c = @cImport({ | |
@cInclude("tmx.h"); | |
}); | |
export fn _tmx_load(path: [*c]const u8) callconv(.C) ?*anyopaque { | |
var texture = std.heap.c_allocator.create(Texture) catch @panic("out of memory"); | |
var path_len = std.mem.span(path); | |
texture.* = Texture.init(path_len) catch @panic("texture load failure"); | |
std.log.warn("_tmx_load({?s}) = {any}", .{ path, texture }); | |
return @ptrCast(texture); | |
} | |
export fn _tmx_free(data: ?*anyopaque) callconv(.C) void { | |
var texture: *Texture = @ptrCast(@alignCast(data)); | |
defer std.heap.c_allocator.destroy(texture); | |
} | |
fn draw_objects(shader: *Shader, objects: ?*c.tmx_object_group) void { | |
_ = objects; | |
_ = shader; | |
// std.log.warn("draw_objects({?*})", .{objects}); | |
} | |
fn draw_image_layer(shader: *Shader, image: ?*c.tmx_image) void { | |
_ = shader; | |
if (image) |i| { | |
var texture: *Texture = @ptrCast(@alignCast(i.resource_image)); | |
texture.bind(); | |
std.log.warn("draw_image_layer({*})", .{texture}); | |
} else unreachable; | |
} | |
fn draw_layer(shader: *Shader, map: *c.tmx_map, layer: *c.tmx_layer) void { | |
var i: usize = 0; | |
var j: usize = 0; | |
var op: f64 = undefined; | |
var gid: c_uint = undefined; | |
var x: c_uint = undefined; | |
var y: c_uint = undefined; | |
var w: c_uint = undefined; | |
var h: c_uint = undefined; | |
var flags: c_uint = 0; | |
var ts: *c.tmx_tileset = undefined; | |
var im: ?*c.tmx_image = undefined; | |
var image: ?*anyopaque = undefined; | |
op = layer.opacity; | |
while (i < map.height) : (i += 1) { | |
while (j < map.width) : (j += 1) { | |
gid = (layer.content.gids[(i * map.width) + j]) & c.TMX_FLIP_BITS_REMOVAL; | |
if (map.tiles[gid]) |g| { | |
ts = g[0].tileset; | |
im = g[0].image; | |
x = g[0].ul_x; | |
y = g[0].ul_y; | |
w = ts.tile_width; | |
h = ts.tile_height; | |
if (im) |im_| { | |
image = im_.resource_image; | |
} else { | |
image = ts.image[0].resource_image; | |
} | |
// flags = (layer.content.gids[(i * map.width) + j]) & ~c.TMX_FLIP_BITS_REMOVAL; | |
draw_tile( | |
shader, | |
image, | |
x, | |
y, | |
w, | |
h, | |
@intCast(j * ts.tile_width), | |
@intCast(i * ts.tile_height), | |
op, | |
flags, | |
); | |
} | |
} | |
} | |
} | |
fn draw_tile(shader: *Shader, image: ?*anyopaque, sx: c_uint, sy: c_uint, sw: c_uint, sh: c_uint, dx: c_uint, dy: c_uint, opacity: f64, flags: c_uint) void { | |
_ = flags; | |
_ = opacity; | |
var texture: *Texture = @ptrCast(@alignCast(image)); | |
shader.setUniform1i("image", 0); | |
// shader.setUniform1i("image", @intFromEnum(texture.id)); | |
zgl.activeTexture(.texture_0); | |
texture.bind(); | |
// std.log.info("draw_tile({any}, {d}, {d}, {d}, {d}, {d}, {d}, {d}, {d})", .{ texture, sx, sy, sw, sh, dx, dy, opacity, flags }); | |
var position = zlm.Vec2{ .x = @floatFromInt(dx), .y = @floatFromInt(dy) }; | |
var size = zlm.Vec2{ .x = @floatFromInt(sw), .y = @floatFromInt(sh) }; | |
var rotation: f32 = 0; | |
var model = Mat4.identity; | |
model = Mat4.mul(model, Mat4.createTranslationXYZ(position.x, position.y, 0)); | |
model = Mat4.mul(model, Mat4.createTranslationXYZ(0.5 * size.x, 0.5 * size.y, 0.0)); | |
model = Mat4.mul(model, Mat4.createAngleAxis(.{ .x = 0, .y = 0, .z = 1.0 }, zlm.toRadians(rotation))); | |
model = Mat4.mul(model, Mat4.createTranslationXYZ(-0.5 * size.x, -0.5 * size.y, 0.0)); | |
model = Mat4.mul(model, Mat4.createScale(size.x, size.y, 1.0)); | |
shader.setMat4("model", model); | |
const vertices = [_]f32{ | |
0.0, 1.0, | |
1.0, 0.0, | |
0.0, 0.0, | |
0.0, 1.0, | |
1.0, 1.0, | |
1.0, 0.0, | |
}; | |
var indices = [_]u32{ | |
0, 1, 2, // Triangle 1 (Bottom-left to bottom-right to top-left) | |
2, 1, 3, // Triangle 2 (Top-left to bottom-right to top-right) | |
}; | |
const texCoordLeft = @as(f32, @floatFromInt(sx)); | |
const texCoordRight = @as(f32, @floatFromInt(sx + sw)); | |
const texCoordTop = @as(f32, @floatFromInt(sy)); | |
const texCoordBottom = @as(f32, @floatFromInt(sy + sh)); | |
const texcoords = [_]f32{ texCoordLeft, texCoordTop, texCoordRight, texCoordTop, texCoordLeft, texCoordBottom, texCoordRight, texCoordBottom }; | |
var vao = zgl.genVertexArray(); | |
// defer zgl.deleteVertexArray(vao); | |
var vbo = zgl.genBuffer(); | |
// defer zgl.deleteBuffer(vbo); | |
var texvbo = zgl.genBuffer(); | |
// defer zgl.deleteBuffer(texvbo); | |
var ebo = zgl.genBuffer(); | |
// defer zgl.deleteBuffer(ebo); | |
zgl.bindVertexArray(vao); | |
zgl.bindBuffer(vbo, .array_buffer); | |
zgl.bufferData(.array_buffer, f32, &vertices, .static_draw); | |
zgl.bindBuffer(texvbo, .array_buffer); | |
zgl.bufferData(.array_buffer, f32, &texcoords, .static_draw); | |
zgl.vertexAttribPointer(0, 2, .float, false, 2 * @sizeOf(f32), 0); | |
zgl.enableVertexAttribArray(0); | |
zgl.vertexAttribPointer(1, 2, .float, false, 2 * @sizeOf(f32), 0); | |
zgl.enableVertexAttribArray(1); | |
zgl.bindBuffer(ebo, .element_array_buffer); | |
zgl.bufferData(.element_array_buffer, u32, &indices, .static_draw); | |
zgl.bindVertexArray(vao); | |
zgl.drawElements(.triangles, 6, .u32, 0); | |
// zgl.drawArrays(.triangles, 0, vertices.len); | |
} | |
fn draw_all_layers(shader: *Shader, map: *c.tmx_map, layers: ?*c.tmx_layer) void { | |
zgl.clearColor(0.2, 0.3, 0.3, 1.0); | |
zgl.clear(.{ .color = true, .depth = true }); | |
zgl.enable(.depth_test); | |
var layers_for_looping = layers; | |
while (layers_for_looping) |layer| { | |
if (layer.visible > 0) { | |
if (layer.type == c.L_GROUP) { | |
draw_all_layers(shader, map, layer.content.group_head); | |
} else if (layer.type == c.L_OBJGR) { | |
draw_objects(shader, layer.content.objgr); | |
} else if (layer.type == c.L_IMAGE) { | |
draw_image_layer(shader, layer.content.image); | |
} else if (layer.type == c.L_LAYER) { | |
draw_layer(shader, map, layer); | |
} | |
} | |
layers_for_looping = @ptrCast(layer.next); | |
} | |
zgl.disable(.depth_test); | |
} | |
pub fn main() !void { | |
var gpa = std.heap.GeneralPurposeAllocator(.{}){}; | |
var allocator = gpa.allocator(); | |
defer { | |
const deinit_status = gpa.deinit(); | |
//fail test; can't try in defer as defer is executed after we return | |
if (deinit_status == .leak) @panic("leak detected"); | |
} | |
glfw.setErrorCallback(errorCallback); | |
if (!glfw.init(.{})) { | |
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); | |
std.process.exit(1); | |
} | |
defer glfw.terminate(); | |
const window = glfw.Window.create(640, 480, "hello, world", null, null, .{ | |
.context_version_major = 4, | |
.context_version_minor = 0, | |
.opengl_profile = .opengl_core_profile, | |
}) orelse { | |
std.log.err("failed to create GLFW window: {?s}", .{glfw.getErrorString()}); | |
std.process.exit(1); | |
}; | |
defer window.destroy(); | |
glfw.makeContextCurrent(window); | |
const proc: glfw.GLProc = undefined; | |
try zgl.loadExtensions(proc, glGetProcAddress); | |
glfw.swapInterval(1); | |
var shader = try Shader.init( | |
@embedFile("shaders/test.vs"), | |
@embedFile("shaders/test.fs"), | |
allocator, | |
); | |
defer shader.deinit(); | |
shader.use(); | |
zgl.activeTexture(.texture_0); | |
var projection = Mat4.identity; | |
projection = Mat4.createOrthogonal(0, 640, 0, 480, -1, 1); | |
shader.setMat4("projection", projection); | |
c.tmx_img_load_func = _tmx_load; | |
c.tmx_img_free_func = _tmx_free; | |
var map = c.tmx_load("/home/connorrigby/Downloads/tiled-master/examples/rpg/island.tmx"); | |
defer c.tmx_map_free(map); | |
while (!window.shouldClose()) { | |
if (map) |map_root| { | |
var col = c.tmx_col_to_floats(map_root[0].backgroundcolor); | |
shader.setVec3("spriteColor", .{ .x = col.r, .y = col.g, .z = col.b }); | |
draw_all_layers(&shader, @ptrCast(map_root), @ptrCast(map_root[0].ly_head)); | |
} else unreachable; | |
window.swapBuffers(); | |
glfw.pollEvents(); | |
} | |
} | |
/// Default GLFW error handling callback | |
fn errorCallback(error_code: glfw.ErrorCode, description: [:0]const u8) void { | |
log.err("glfw: {}: {s}\n", .{ error_code, description }); | |
} | |
fn glGetProcAddress(p: glfw.GLProc, proc: [:0]const u8) ?*const anyopaque { | |
_ = p; | |
return glfw.getProcAddress(proc); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment