add tilemap
This commit is contained in:
parent
5be299ad4c
commit
61e5edb8cf
23
src/assets/kenney-micro-roguelike/License.txt
Normal file
23
src/assets/kenney-micro-roguelike/License.txt
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
|
||||
Micro Roguelike (1.4)
|
||||
|
||||
Created/distributed by Kenney (www.kenney.nl)
|
||||
Creation date: 01-11-2021
|
||||
|
||||
------------------------------
|
||||
|
||||
License: (Creative Commons Zero, CC0)
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
This content is free to use in personal, educational and commercial projects.
|
||||
|
||||
Support us by crediting Kenney or www.kenney.nl (this is not mandatory)
|
||||
|
||||
------------------------------
|
||||
|
||||
Donate: http://support.kenney.nl
|
||||
Patreon: http://patreon.com/kenney/
|
||||
|
||||
Follow on Twitter for updates:
|
||||
http://twitter.com/KenneyNL
|
||||
BIN
src/assets/kenney-micro-roguelike/colored_tilemap_packed.png
Normal file
BIN
src/assets/kenney-micro-roguelike/colored_tilemap_packed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
@ -23,7 +23,7 @@ pub const Input = struct {
|
||||
move_right: Window.KeyState,
|
||||
};
|
||||
|
||||
const tile_size = Vec2.init(10, 10);
|
||||
const tile_size = Vec2.init(8, 8);
|
||||
|
||||
canvas_size: Vec2,
|
||||
entities: Entity.List,
|
||||
@ -37,7 +37,7 @@ last_right_repeat_at: ?f64 = null,
|
||||
|
||||
pub fn init(gpa: Allocator) !Game {
|
||||
var game = Game{
|
||||
.canvas_size = .init(320, 180),
|
||||
.canvas_size = (Vec2.init(20, 15)).multiply(tile_size),
|
||||
.entities = .empty,
|
||||
.timers = .empty,
|
||||
.last_move = .init(0, 0)
|
||||
@ -129,7 +129,7 @@ pub fn tick(self: *Game, input: Input) !void {
|
||||
// entity.position = entity.position.add(velocity.multiplyScalar(input.dt));
|
||||
entity.position = entity.position.add(move.multiply(tile_size));
|
||||
|
||||
Gfx.drawRectangle(entity.position, .init(10, 10), rgb(255, 0, 0));
|
||||
Gfx.drawTileById(.player, entity.position, tile_size, rgb(255, 255, 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
516
src/graphics.zig
516
src/graphics.zig
@ -451,8 +451,11 @@ pub const Font = struct {
|
||||
};
|
||||
|
||||
pub const ImageId = enum {
|
||||
// package,
|
||||
// trash
|
||||
tilemap
|
||||
};
|
||||
|
||||
pub const TileId = enum {
|
||||
player
|
||||
};
|
||||
|
||||
pub const Borders = struct {
|
||||
@ -659,7 +662,13 @@ var font_id_map: std.EnumArray(FontVariant, c_int) = .initFill(c.FONS_INVALID);
|
||||
|
||||
var image_map: std.EnumArray(ImageId, sg.Image) = .initFill(.{});
|
||||
var image_view_map: std.EnumArray(ImageId, sg.View) = .initFill(.{});
|
||||
|
||||
var linear_sampler: sg.Sampler = .{};
|
||||
var nearest_sampler: sg.Sampler = .{};
|
||||
|
||||
var tile_coords: std.EnumArray(TileId, Vec2) = .initUndefined();
|
||||
const tile_size: Vec2 = .init(8, 8);
|
||||
var tilemap_size: Vec2 = .init(0, 0);
|
||||
|
||||
const Options = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
@ -679,38 +688,47 @@ fn loadEmbededFont(fs: ?*c.FONScontext, name: [*c]const u8, comptime path: []co
|
||||
return font_id;
|
||||
}
|
||||
|
||||
fn makeImageFromMemory(image_datas: []const []const u8) !sg.Image {
|
||||
var stbi_images_buffer: [16][*c]u8 = undefined;
|
||||
var stbi_images: std.ArrayListUnmanaged([*c]u8) = .initBuffer(&stbi_images_buffer);
|
||||
defer {
|
||||
for (stbi_images.items) |stbi_image| {
|
||||
c.stbi_image_free(stbi_image);
|
||||
const ImageData = struct {
|
||||
rgba8_pixels: [*c]u8,
|
||||
width: u32,
|
||||
height: u32,
|
||||
|
||||
fn load(png_data: []const u8) !ImageData {
|
||||
var width: c_int = undefined;
|
||||
var height: c_int = undefined;
|
||||
const pixels = c.stbi_load_from_memory(png_data.ptr, @intCast(png_data.len), &width, &height, null, 4);
|
||||
if (pixels == null) {
|
||||
return error.InvalidPng;
|
||||
}
|
||||
|
||||
return ImageData{
|
||||
.rgba8_pixels = pixels,
|
||||
.width = @intCast(width),
|
||||
.height = @intCast(height)
|
||||
};
|
||||
}
|
||||
|
||||
fn deinit(self: *const ImageData) void {
|
||||
c.stbi_image_free(self.rgba8_pixels);
|
||||
}
|
||||
};
|
||||
|
||||
fn makeImageWithMipMaps(image_datas: []const ImageData) !sg.Image {
|
||||
var mip_levels_buffer = [_]sg.Range{.{}} ** 16;
|
||||
var mip_levels: std.ArrayListUnmanaged(sg.Range) = .initBuffer(&mip_levels_buffer);
|
||||
|
||||
var image_width: c_int = -1;
|
||||
var image_height: c_int = -1;
|
||||
|
||||
for (image_datas) |image_data| {
|
||||
var width: c_int = undefined;
|
||||
var height: c_int = undefined;
|
||||
const pixels = c.stbi_load_from_memory(image_data.ptr, @intCast(image_data.len), &width, &height, null, 4);
|
||||
if (pixels == null) {
|
||||
return error.InvalidPng;
|
||||
}
|
||||
|
||||
for (image_datas) |mipmap_image| {
|
||||
if (image_height == -1) {
|
||||
image_width = width;
|
||||
image_height = height;
|
||||
image_width = @intCast(mipmap_image.width);
|
||||
image_height = @intCast(mipmap_image.height);
|
||||
}
|
||||
|
||||
try stbi_images.appendBounded(pixels);
|
||||
try mip_levels.appendBounded(.{
|
||||
.ptr = pixels,
|
||||
.size = @intCast(width * height * 4)
|
||||
.ptr = mipmap_image.rgba8_pixels,
|
||||
.size = mipmap_image.width * mipmap_image.height * 4
|
||||
});
|
||||
}
|
||||
|
||||
@ -735,6 +753,31 @@ fn makeImageFromMemory(image_datas: []const []const u8) !sg.Image {
|
||||
return image;
|
||||
}
|
||||
|
||||
fn makeImageFromMemory(image_datas: []const []const u8) !sg.Image {
|
||||
var stbi_images_buffer: [16]ImageData = undefined;
|
||||
var stbi_images: std.ArrayListUnmanaged(ImageData) = .initBuffer(&stbi_images_buffer);
|
||||
defer {
|
||||
for (stbi_images.items) |image| {
|
||||
image.deinit();
|
||||
}
|
||||
}
|
||||
|
||||
if (image_datas.len > stbi_images.capacity) {
|
||||
return error.OutOfMemory;
|
||||
}
|
||||
|
||||
for (image_datas) |image_data| {
|
||||
const mipmap_image = try ImageData.load(image_data);
|
||||
stbi_images.appendAssumeCapacity(mipmap_image);
|
||||
}
|
||||
|
||||
return try makeImageWithMipMaps(stbi_images.items);
|
||||
}
|
||||
|
||||
fn tileCoordToQuad(coord: Vec2) Rect {
|
||||
_ = coord; // autofix
|
||||
}
|
||||
|
||||
pub fn init(options: Options) !void {
|
||||
dpi_scale = sapp.dpiScale();
|
||||
|
||||
@ -792,32 +835,30 @@ pub fn init(options: Options) !void {
|
||||
.bold = loadEmbededFont(g_fons_context, "bold", "./assets/roboto-font/Roboto-Bold.ttf"),
|
||||
});
|
||||
|
||||
// TODO: Generate mipmap from SVG.
|
||||
// image_map = .init(.{
|
||||
// .package = try makeImageFromMemory(&.{
|
||||
// // https://www.iconfinder.com/icons/9026684/package_thin_icon
|
||||
// @embedFile("../assets/icons/package-512x512.png"),
|
||||
// @embedFile("../assets/icons/package-256x256.png"),
|
||||
// @embedFile("../assets/icons/package-128x128.png"),
|
||||
// @embedFile("../assets/icons/package-64x64.png"),
|
||||
// @embedFile("../assets/icons/package-32x32.png"),
|
||||
// }),
|
||||
// .trash = try makeImageFromMemory(&.{
|
||||
// // TODO: Provide attribution for image
|
||||
// // https://www.iconfinder.com/icons/9027022/trash_thin_icon
|
||||
// @embedFile("../assets/icons/trash-32x32.png"),
|
||||
// })
|
||||
// });
|
||||
const tilemap = try ImageData.load(@embedFile("./assets/kenney-micro-roguelike/colored_tilemap_packed.png"));
|
||||
defer tilemap.deinit();
|
||||
|
||||
// var image_iter = image_map.iterator();
|
||||
// while (image_iter.next()) |entry| {
|
||||
// const image_view = sg.makeView(.{
|
||||
// .texture = .{ .image = entry.value.* }
|
||||
// });
|
||||
// assert(image_view.id != sg.invalid_id);
|
||||
//
|
||||
// image_view_map.set(entry.key, image_view);
|
||||
// }
|
||||
image_map = .init(.{
|
||||
.tilemap = try makeImageWithMipMaps(&.{
|
||||
tilemap
|
||||
})
|
||||
});
|
||||
|
||||
tilemap_size = Vec2.init(@floatFromInt(tilemap.width), @floatFromInt(tilemap.height));
|
||||
|
||||
tile_coords = .init(.{
|
||||
.player = .init(4, 0)
|
||||
});
|
||||
|
||||
var image_iter = image_map.iterator();
|
||||
while (image_iter.next()) |entry| {
|
||||
const image_view = sg.makeView(.{
|
||||
.texture = .{ .image = entry.value.* }
|
||||
});
|
||||
assert(image_view.id != sg.invalid_id);
|
||||
|
||||
image_view_map.set(entry.key, image_view);
|
||||
}
|
||||
|
||||
linear_sampler = sg.makeSampler(.{
|
||||
.min_filter = .LINEAR,
|
||||
@ -825,6 +866,13 @@ pub fn init(options: Options) !void {
|
||||
.mipmap_filter = .LINEAR,
|
||||
.label = "linear-sampler",
|
||||
});
|
||||
|
||||
nearest_sampler = sg.makeSampler(.{
|
||||
.min_filter = .NEAREST,
|
||||
.mag_filter = .NEAREST,
|
||||
.mipmap_filter = .NEAREST,
|
||||
.label = "nearest-sampler",
|
||||
});
|
||||
}
|
||||
|
||||
pub fn deinit() void {
|
||||
@ -883,16 +931,17 @@ pub fn drawRectangle(pos: Vec2, size: Vec2, color: Vec4) void {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn drawImage(image_id: ImageId, pos: Vec2, size: Vec2, tint: Vec4) void {
|
||||
pub fn drawTile(tile_coord: Vec2, pos: Vec2, size: Vec2, tint: Vec4) void {
|
||||
sgl.enableTexture();
|
||||
defer sgl.disableTexture();
|
||||
|
||||
|
||||
sgl.texture(
|
||||
image_view_map.get(image_id),
|
||||
linear_sampler
|
||||
image_view_map.get(.tilemap),
|
||||
nearest_sampler
|
||||
);
|
||||
|
||||
const tile_quad = Rect.init(tile_coord.x, tile_coord.y, 1, 1).multiply(tile_size).divide(tilemap_size);
|
||||
|
||||
const top_left = pos;
|
||||
const top_right = pos.add(.{ .x = size.x, .y = 0 });
|
||||
const bottom_right = pos.add(size);
|
||||
@ -901,352 +950,39 @@ pub fn drawImage(image_id: ImageId, pos: Vec2, size: Vec2, tint: Vec4) void {
|
||||
sgl.beginQuads();
|
||||
defer sgl.end();
|
||||
|
||||
v2fT2Color(top_left.x, top_left.y, 0, 0, tint);
|
||||
v2fT2Color(top_right.x, top_right.y, 1, 0, tint);
|
||||
v2fT2Color(bottom_right.x, bottom_right.y, 1, 1, tint);
|
||||
v2fT2Color(bottom_left.x, bottom_left.y, 0, 1, tint);
|
||||
}
|
||||
|
||||
fn getCircleSegmentCount(radius: f32, from_angle: f32, to_angle: f32) usize {
|
||||
const pi2 = 2 * std.math.pi;
|
||||
|
||||
const C = pi2 * radius;
|
||||
const C_segment = C * (@abs(to_angle - from_angle) / pi2);
|
||||
|
||||
return @intFromFloat(C_segment / circle_quality);
|
||||
}
|
||||
|
||||
fn drawCorner(pos: Vec2, radius: f32, color: Vec4, from_angle: f32, to_angle: f32) void {
|
||||
sgl.beginTriangles();
|
||||
defer sgl.end();
|
||||
|
||||
const detail = getCircleSegmentCount(radius, from_angle, to_angle);
|
||||
|
||||
// TODO: Use precomputed angles
|
||||
for (0..detail) |i| {
|
||||
const angle = std.math.lerp(from_angle, to_angle, @as(f32, @floatFromInt(i)) / @as(f32, @floatFromInt(detail)));
|
||||
const angle1 = std.math.lerp(from_angle, to_angle, @as(f32, @floatFromInt(i + 1)) / @as(f32, @floatFromInt(detail)));
|
||||
const x = @cos(angle);
|
||||
const y = @sin(angle);
|
||||
const x1 = @cos(angle1);
|
||||
const y1 = @sin(angle1);
|
||||
|
||||
v2fColor(pos.x , pos.y , color);
|
||||
v2fColor(pos.x + x * radius, pos.y + y * radius, color);
|
||||
v2fColor(pos.x + x1 * radius, pos.y + y1 * radius, color);
|
||||
}
|
||||
}
|
||||
|
||||
fn drawOutlineCornerSegment(
|
||||
pos: Vec2,
|
||||
color: Vec4,
|
||||
outer_radius: f32, inner_radius: f32,
|
||||
from_angle: f32, to_angle: f32
|
||||
) void {
|
||||
const zone = tracy.initZone(@src(), .{ });
|
||||
defer zone.deinit();
|
||||
|
||||
var detail = getCircleSegmentCount(outer_radius, from_angle, to_angle);
|
||||
detail = @max(detail, 1);
|
||||
|
||||
// TODO: Use precomputed angles
|
||||
for (0..detail) |i| {
|
||||
const angle = std.math.lerp(from_angle, to_angle, @as(f32, @floatFromInt(i)) / @as(f32, @floatFromInt(detail)));
|
||||
const angle1 = std.math.lerp(from_angle, to_angle, @as(f32, @floatFromInt(i + 1)) / @as(f32, @floatFromInt(detail)));
|
||||
|
||||
const circle_point0 = Vec2.init(@cos(angle), @sin(angle));
|
||||
const circle_point1 = Vec2.init(@cos(angle1), @sin(angle1));
|
||||
|
||||
drawQuad(
|
||||
.{
|
||||
pos.add(circle_point1.multiplyScalar(outer_radius)),
|
||||
pos.add(circle_point0.multiplyScalar(outer_radius)),
|
||||
pos.add(circle_point0.multiplyScalar(@max(0, inner_radius))),
|
||||
pos.add(circle_point1.multiplyScalar(@max(0, inner_radius))),
|
||||
},
|
||||
color
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drawRoundedRectangle(pos: Vec2, size: Vec2, color: Vec4, corners: Corners) void {
|
||||
const zone = tracy.initZone(@src(), .{ });
|
||||
defer zone.deinit();
|
||||
|
||||
const left = pos.x;
|
||||
const right = pos.x + size.x;
|
||||
const top = pos.y;
|
||||
const bottom = pos.y + size.y;
|
||||
|
||||
const tr = corners.top_right;
|
||||
const tl = corners.top_left;
|
||||
const bl = corners.bottom_left;
|
||||
const br = corners.bottom_right;
|
||||
|
||||
{
|
||||
sgl.beginQuads();
|
||||
defer sgl.end();
|
||||
|
||||
vertexesQuad(
|
||||
Vec2.init(left + tl, top),
|
||||
Vec2.init(right - tr, top),
|
||||
Vec2.init(right - tr, top + tr),
|
||||
Vec2.init(left + tl, top + tl),
|
||||
color
|
||||
);
|
||||
|
||||
vertexesQuad(
|
||||
Vec2.init(right - tr, top + tr),
|
||||
Vec2.init(right, top + tr),
|
||||
Vec2.init(right, bottom - br),
|
||||
Vec2.init(right - br, bottom - br),
|
||||
color
|
||||
);
|
||||
|
||||
vertexesQuad(
|
||||
Vec2.init(left + bl, bottom - bl),
|
||||
Vec2.init(right - br, bottom - br),
|
||||
Vec2.init(right - br, bottom),
|
||||
Vec2.init(left + bl, bottom),
|
||||
color
|
||||
);
|
||||
|
||||
vertexesQuad(
|
||||
Vec2.init(left, top + tl),
|
||||
Vec2.init(left + tl, top + tl),
|
||||
Vec2.init(left + bl, bottom - bl),
|
||||
Vec2.init(left, bottom - bl),
|
||||
color
|
||||
);
|
||||
|
||||
vertexesQuad(
|
||||
Vec2.init(left + tl, top + tl),
|
||||
Vec2.init(right - tr, top + tr),
|
||||
Vec2.init(right - br, bottom - br),
|
||||
Vec2.init(left + bl, bottom - bl),
|
||||
color
|
||||
);
|
||||
}
|
||||
|
||||
drawCorner(
|
||||
Vec2.init(right - tr, top + tr),
|
||||
tr,
|
||||
color,
|
||||
std.math.pi * (3.0 / 2.0),
|
||||
std.math.pi * 2.0,
|
||||
v2fT2Color(
|
||||
top_left.x,
|
||||
top_left.y,
|
||||
tile_quad.left(),
|
||||
tile_quad.top(),
|
||||
tint
|
||||
);
|
||||
|
||||
drawCorner(
|
||||
Vec2.init(left + tl, top + tl),
|
||||
tl,
|
||||
color,
|
||||
std.math.pi,
|
||||
std.math.pi * (3.0 / 2.0)
|
||||
v2fT2Color(
|
||||
top_right.x,
|
||||
top_right.y,
|
||||
tile_quad.right(),
|
||||
tile_quad.top(),
|
||||
tint
|
||||
);
|
||||
|
||||
drawCorner(
|
||||
Vec2.init(left + bl, bottom - bl),
|
||||
bl,
|
||||
color,
|
||||
std.math.pi,
|
||||
std.math.pi * (1.0 / 2.0),
|
||||
v2fT2Color(
|
||||
bottom_right.x,
|
||||
bottom_right.y,
|
||||
tile_quad.right(),
|
||||
tile_quad.bottom(),
|
||||
tint
|
||||
);
|
||||
|
||||
drawCorner(
|
||||
Vec2.init(right - br, bottom - br),
|
||||
br,
|
||||
color,
|
||||
0,
|
||||
std.math.pi * (1.0 / 2.0)
|
||||
v2fT2Color(
|
||||
bottom_left.x,
|
||||
bottom_left.y,
|
||||
tile_quad.left(),
|
||||
tile_quad.bottom(),
|
||||
tint
|
||||
);
|
||||
}
|
||||
|
||||
const OutlineCorner = struct {
|
||||
point: Vec2,
|
||||
corner_radius: f32,
|
||||
dir_to_center: Vec2,
|
||||
|
||||
pub fn getCircleCenter(self: OutlineCorner) Vec2 {
|
||||
return self.point.add(self.dir_to_center.multiplyScalar(self.corner_radius));
|
||||
}
|
||||
|
||||
pub fn getEdge(self: OutlineCorner, segment: OutlineSegment, border: f32) [2]Vec2 {
|
||||
const inward_sign = switch (segment.axis) {
|
||||
.X => self.dir_to_center.x,
|
||||
.Y => self.dir_to_center.y,
|
||||
};
|
||||
|
||||
var bottom_left = self.point;
|
||||
if (segment.axis == .X) {
|
||||
bottom_left.x += self.corner_radius * inward_sign;
|
||||
} else {
|
||||
bottom_left.y += self.corner_radius * inward_sign;
|
||||
}
|
||||
|
||||
var top_left = bottom_left.add(segment.inward_direction.multiplyScalar(border));
|
||||
if (segment.axis == .X) {
|
||||
top_left.x += @max(border - self.corner_radius, 0) * inward_sign;
|
||||
} else {
|
||||
top_left.y += @max(border - self.corner_radius, 0) * inward_sign;
|
||||
}
|
||||
|
||||
return .{ bottom_left, top_left };
|
||||
}
|
||||
|
||||
fn draw(self: OutlineCorner, segment: OutlineSegment, border_size: f32, corner_angle_sign: f32, edge: [2]Vec2,) void {
|
||||
if (self.corner_radius > 0) {
|
||||
const center = self.getCircleCenter();
|
||||
|
||||
const inner_radius = self.corner_radius - border_size;
|
||||
if (inner_radius < 0) {
|
||||
drawTriangle(
|
||||
.{
|
||||
edge[0],
|
||||
edge[1],
|
||||
center
|
||||
},
|
||||
segment.color
|
||||
);
|
||||
}
|
||||
|
||||
drawOutlineCornerSegment(
|
||||
center,
|
||||
segment.color,
|
||||
self.corner_radius,
|
||||
inner_radius,
|
||||
segment.outward_angle,
|
||||
segment.outward_angle + corner_angle_sign * std.math.pi / 4.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const OutlineSegment = struct {
|
||||
// TODO: Figure out a way to remove `lower_side_angle_dir` and `upper_side_angle_dir`?
|
||||
|
||||
lower_side: OutlineCorner,
|
||||
lower_side_angle_dir: f32,
|
||||
upper_side: OutlineCorner,
|
||||
upper_side_angle_dir: f32,
|
||||
|
||||
outward_angle: f32,
|
||||
color: Vec4,
|
||||
axis: enum { X, Y },
|
||||
inward_direction: Vec2,
|
||||
|
||||
pub fn getLowerEdge(self: OutlineSegment, border: f32) [2]Vec2 {
|
||||
return self.lower_side.getEdge(self, border);
|
||||
}
|
||||
|
||||
pub fn getUpperEdge(self: OutlineSegment, border: f32) [2]Vec2 {
|
||||
return self.upper_side.getEdge(self, border);
|
||||
}
|
||||
|
||||
fn draw(self: OutlineSegment, border: f32) void {
|
||||
if (self.color.w != 0) {
|
||||
const lower_edge = self.getLowerEdge(border);
|
||||
const upper_edge = self.getUpperEdge(border);
|
||||
|
||||
drawQuad(
|
||||
.{
|
||||
lower_edge[0],
|
||||
lower_edge[1],
|
||||
|
||||
upper_edge[1],
|
||||
upper_edge[0],
|
||||
},
|
||||
self.color
|
||||
);
|
||||
|
||||
self.lower_side.draw(self, border, self.lower_side_angle_dir, lower_edge);
|
||||
self.upper_side.draw(self, border, self.upper_side_angle_dir, upper_edge);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub fn drawRectangleOutlineRounded(pos: Vec2, size: Vec2, corners: Corners, borders: Borders) void {
|
||||
const zone = tracy.initZone(@src(), .{ });
|
||||
defer zone.deinit();
|
||||
|
||||
if (borders.size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const left = pos.x;
|
||||
const right = pos.x+size.x;
|
||||
const top = pos.y;
|
||||
const bottom = pos.y+size.y;
|
||||
|
||||
const bottom_left_corner = OutlineCorner{
|
||||
.point = Vec2.init(left, bottom),
|
||||
.corner_radius = corners.bottom_left,
|
||||
.dir_to_center = Vec2.init(1, -1),
|
||||
};
|
||||
|
||||
const bottom_right_corner = OutlineCorner{
|
||||
.point = Vec2.init(right, bottom),
|
||||
.corner_radius = corners.bottom_right,
|
||||
.dir_to_center = Vec2.init(-1, -1),
|
||||
};
|
||||
|
||||
const top_right_corner = OutlineCorner{
|
||||
.point = Vec2.init(right, top),
|
||||
.corner_radius = corners.top_right,
|
||||
.dir_to_center = Vec2.init(-1, 1),
|
||||
};
|
||||
|
||||
const top_left_corner = OutlineCorner{
|
||||
.point = Vec2.init(left, top),
|
||||
.corner_radius = corners.top_left,
|
||||
.dir_to_center = Vec2.init(1, 1),
|
||||
};
|
||||
|
||||
const segments = .{
|
||||
OutlineSegment{
|
||||
.lower_side = bottom_left_corner,
|
||||
.lower_side_angle_dir = 1,
|
||||
.upper_side = bottom_right_corner,
|
||||
.upper_side_angle_dir = -1,
|
||||
.outward_angle = std.math.pi * 1.0 / 2.0,
|
||||
.color = borders.bottom,
|
||||
.axis = .X,
|
||||
.inward_direction = Vec2.init(0, -1)
|
||||
},
|
||||
OutlineSegment{
|
||||
.lower_side = top_left_corner,
|
||||
.lower_side_angle_dir = -1,
|
||||
.upper_side = top_right_corner,
|
||||
.upper_side_angle_dir = 1,
|
||||
.outward_angle = std.math.pi * 3.0 / 2.0,
|
||||
.color = borders.top,
|
||||
.axis = .X,
|
||||
.inward_direction = Vec2.init(0, 1)
|
||||
},
|
||||
OutlineSegment{
|
||||
.lower_side = top_left_corner,
|
||||
.lower_side_angle_dir = 1,
|
||||
.upper_side = bottom_left_corner,
|
||||
.upper_side_angle_dir = -1,
|
||||
.outward_angle = std.math.pi,
|
||||
.color = borders.left,
|
||||
.axis = .Y,
|
||||
.inward_direction = Vec2.init(1, 0)
|
||||
},
|
||||
OutlineSegment{
|
||||
.lower_side = top_right_corner,
|
||||
.lower_side_angle_dir = -1,
|
||||
.upper_side = bottom_right_corner,
|
||||
.upper_side_angle_dir = 1,
|
||||
.outward_angle = 0,
|
||||
.color = borders.right,
|
||||
.axis = .Y,
|
||||
.inward_direction = Vec2.init(-1, 0)
|
||||
}
|
||||
};
|
||||
|
||||
inline for (segments) |segment| {
|
||||
segment.draw(borders.size);
|
||||
}
|
||||
pub fn drawTileById(tile_id: TileId, pos: Vec2, size: Vec2, tint: Vec4) void {
|
||||
const tile_coord = tile_coords.get(tile_id);
|
||||
drawTile(tile_coord, pos, size, tint);
|
||||
}
|
||||
|
||||
pub fn drawRectanglOutline(pos: Vec2, size: Vec2, color: Vec4, width: f32) void {
|
||||
|
||||
14
src/math.zig
14
src/math.zig
@ -351,6 +351,20 @@ pub const Rect = struct {
|
||||
return self.pos.y + self.size.y;
|
||||
}
|
||||
|
||||
pub fn multiply(self: Rect, xy: Vec2) Rect {
|
||||
return Rect{
|
||||
.pos = self.pos.multiply(xy),
|
||||
.size = self.size.multiply(xy),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn divide(self: Rect, xy: Vec2) Rect {
|
||||
return Rect{
|
||||
.pos = self.pos.divide(xy),
|
||||
.size = self.size.divide(xy),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isInside(self: Rect, pos: Vec2) bool {
|
||||
const x_overlap = self.pos.x <= pos.x and pos.x < self.pos.x + self.size.x;
|
||||
const y_overlap = self.pos.y <= pos.y and pos.y < self.pos.y + self.size.y;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user