add function for drawing a blurred rectangle
This commit is contained in:
parent
b80a356739
commit
522840ca22
232
gui/app.zig
232
gui/app.zig
@ -7,6 +7,9 @@ const UIStack = @import("./ui_stack.zig");
|
||||
const RectUtils = @import("./rect_utils.zig");
|
||||
const rl = @import("raylib");
|
||||
const srcery = @import("./srcery.zig");
|
||||
const rlgl_h = @cImport({
|
||||
@cInclude("rlgl.h");
|
||||
});
|
||||
|
||||
const assert = std.debug.assert;
|
||||
|
||||
@ -229,13 +232,181 @@ fn createOrGetRenderTexture(maybe_render_texture: *?rl.RenderTexture) !rl.Render
|
||||
return maybe_render_texture.*.?;
|
||||
}
|
||||
|
||||
fn drawRectangleRoundedUV(rect: rl.Rectangle, roundness: f32, color: rl.Color) void {
|
||||
if (roundness == 0) {
|
||||
rl.drawRectangleRec(rect, color);
|
||||
// Modified version of `DrawRectangleRounded` where the UV texture coordiantes are consistent and align
|
||||
fn drawRectangleRoundedUV(rec: rl.Rectangle, roundness: f32, color: rl.Color) void {
|
||||
assert(roundness < 1);
|
||||
|
||||
if (roundness <= 0 or rec.width <= 1 or rec.height <= 1) {
|
||||
rl.drawRectangleRec(rec, color);
|
||||
return;
|
||||
}
|
||||
|
||||
const radius: f32 = @min(rec.width, rec.height) * roundness / 2;
|
||||
if (radius <= 0.0) return;
|
||||
|
||||
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
|
||||
const smooth_circle_error_rate = 0.5;
|
||||
const th: f32 = std.math.acos(2 * std.math.pow(f32, 1 - smooth_circle_error_rate / radius, 2) - 1);
|
||||
var segments: i32 = @intFromFloat(@ceil(2 * std.math.pi / th) / 4.0);
|
||||
if (segments <= 0) segments = 4;
|
||||
|
||||
const step_length = 90.0 / @as(f32, @floatFromInt(segments));
|
||||
|
||||
// Quick sketch to make sense of all of this,
|
||||
// there are 9 parts to draw, also mark the 12 points we'll use
|
||||
//
|
||||
// P0____________________P1
|
||||
// /| |\
|
||||
// /1| 2 |3\
|
||||
// P7 /__|____________________|__\ P2
|
||||
// | |P8 P9| |
|
||||
// | 8 | 9 | 4 |
|
||||
// | __|____________________|__ |
|
||||
// P6 \ |P11 P10| / P3
|
||||
// \7| 6 |5/
|
||||
// \|____________________|/
|
||||
// P5 P4
|
||||
|
||||
// Coordinates of the 12 points that define the rounded rect
|
||||
const radius_u = radius / rec.width;
|
||||
const radius_v = radius / rec.height;
|
||||
const points = [_]rl.Vector2{
|
||||
.{ .x = radius_u , .y = 0 }, // P0
|
||||
.{ .x = 1 - radius_u , .y = 0 }, // P1
|
||||
.{ .x = 1 , .y = radius_v }, // P2
|
||||
.{ .x = 1 , .y = 1 - radius_v }, // P3
|
||||
.{ .x = 1 - radius_u , .y = 1 }, // P4
|
||||
.{ .x = radius_u , .y = 1 }, // P5
|
||||
.{ .x = 0 , .y = 1 - radius_v }, // P6
|
||||
.{ .x = 0 , .y = radius_v }, // P7
|
||||
.{ .x = radius_u , .y = radius_v }, // P8
|
||||
.{ .x = 1 - radius_u , .y = radius_v }, // P9
|
||||
.{ .x = 1 - radius_u , .y = 1 - radius_v }, // P10
|
||||
.{ .x = radius_u , .y = 1 - radius_v }, // P11
|
||||
};
|
||||
|
||||
const texture = rl.getShapesTexture();
|
||||
const shape_rect = rl.getShapesTextureRectangle();
|
||||
|
||||
const texture_width: f32 = @floatFromInt(texture.width);
|
||||
const texture_height: f32 = @floatFromInt(texture.height);
|
||||
|
||||
rl.gl.rlBegin(rlgl_h.RL_TRIANGLES);
|
||||
defer rl.gl.rlEnd();
|
||||
|
||||
rl.gl.rlSetTexture(texture.id);
|
||||
defer rl.gl.rlSetTexture(0);
|
||||
|
||||
// Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner
|
||||
const centers = [_]rl.Vector2{ points[8], points[9], points[10], points[11] };
|
||||
const angles = [_]f32{ 180.0, 270.0, 0.0, 90.0 };
|
||||
for (0..4) |k| {
|
||||
var angle = angles[k];
|
||||
const center = centers[k];
|
||||
for (0..@intCast(segments)) |_| {
|
||||
rl.gl.rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
const rad_per_deg = std.math.rad_per_deg;
|
||||
|
||||
const triangle = .{
|
||||
center,
|
||||
.{
|
||||
.x = center.x + @cos(rad_per_deg*(angle + step_length))*radius_u,
|
||||
.y = center.y + @sin(rad_per_deg*(angle + step_length))*radius_v
|
||||
},
|
||||
.{
|
||||
.x = center.x + @cos(rad_per_deg * angle)*radius_u,
|
||||
.y = center.y + @sin(rad_per_deg * angle)*radius_v
|
||||
}
|
||||
};
|
||||
|
||||
inline for (triangle) |point| {
|
||||
rl.gl.rlTexCoord2f(
|
||||
(shape_rect.x + shape_rect.width * point.x) / texture_width,
|
||||
(shape_rect.y + shape_rect.height * point.y) / texture_height
|
||||
);
|
||||
rl.gl.rlVertex2f(
|
||||
rec.x + rec.width * point.x,
|
||||
rec.y + rec.height * point.y
|
||||
);
|
||||
}
|
||||
|
||||
angle += step_length;
|
||||
}
|
||||
}
|
||||
|
||||
// [2] Upper Rectangle
|
||||
rl.gl.rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
inline for (.{ 0, 8, 9, 1, 0, 9 }) |index| {
|
||||
const point = points[index];
|
||||
rl.gl.rlTexCoord2f(
|
||||
(shape_rect.x + shape_rect.width * point.x) / texture_width,
|
||||
(shape_rect.y + shape_rect.height * point.y) / texture_height
|
||||
);
|
||||
rl.gl.rlVertex2f(
|
||||
rec.x + rec.width * point.x,
|
||||
rec.y + rec.height * point.y
|
||||
);
|
||||
}
|
||||
|
||||
// [4] Right Rectangle
|
||||
rl.gl.rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
inline for (.{ 9, 10, 3, 2, 9, 3 }) |index| {
|
||||
const point = points[index];
|
||||
rl.gl.rlTexCoord2f(
|
||||
(shape_rect.x + shape_rect.width * point.x) / texture_width,
|
||||
(shape_rect.y + shape_rect.height * point.y) / texture_height
|
||||
);
|
||||
rl.gl.rlVertex2f(
|
||||
rec.x + rec.width * point.x,
|
||||
rec.y + rec.height * point.y
|
||||
);
|
||||
}
|
||||
|
||||
// [6] Bottom Rectangle
|
||||
rl.gl.rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
inline for (.{ 11, 5, 4, 10, 11, 4 }) |index| {
|
||||
const point = points[index];
|
||||
rl.gl.rlTexCoord2f(
|
||||
(shape_rect.x + shape_rect.width * point.x) / texture_width,
|
||||
(shape_rect.y + shape_rect.height * point.y) / texture_height
|
||||
);
|
||||
rl.gl.rlVertex2f(
|
||||
rec.x + rec.width * point.x,
|
||||
rec.y + rec.height * point.y
|
||||
);
|
||||
}
|
||||
|
||||
// [8] Left Rectangle
|
||||
rl.gl.rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
inline for (.{ 7, 6, 11, 8, 7, 11 }) |index| {
|
||||
const point = points[index];
|
||||
rl.gl.rlTexCoord2f(
|
||||
(shape_rect.x + shape_rect.width * point.x) / texture_width,
|
||||
(shape_rect.y + shape_rect.height * point.y) / texture_height
|
||||
);
|
||||
rl.gl.rlVertex2f(
|
||||
rec.x + rec.width * point.x,
|
||||
rec.y + rec.height * point.y
|
||||
);
|
||||
}
|
||||
|
||||
// [9] Middle Rectangle
|
||||
rl.gl.rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
inline for (.{ 8, 11, 10, 9, 8, 10 }) |index| {
|
||||
const point = points[index];
|
||||
rl.gl.rlTexCoord2f(
|
||||
(shape_rect.x + shape_rect.width * point.x) / texture_width,
|
||||
(shape_rect.y + shape_rect.height * point.y) / texture_height
|
||||
);
|
||||
rl.gl.rlVertex2f(
|
||||
rec.x + rec.width * point.x,
|
||||
rec.y + rec.height * point.y
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn drawBlurredWorld(self: *App, rect: rl.Rectangle, roundness: f32, color: rl.Color) !void {
|
||||
fn drawBlurredWorld(self: *App, rect: rl.Rectangle, color: rl.Color) !void {
|
||||
const blur_both = try createOrGetRenderTexture(&self.blur_texture_both);
|
||||
|
||||
const previous_texture = rl.getShapesTexture();
|
||||
@ -250,10 +421,35 @@ fn drawBlurredWorld(self: *App, rect: rl.Rectangle, roundness: f32, color: rl.Co
|
||||
.height = -rect.height,
|
||||
};
|
||||
rl.setShapesTexture(blur_both.texture, shape_rect);
|
||||
drawRectangleRoundedUV(rect, roundness, 0, color);
|
||||
|
||||
const border = 2;
|
||||
const roundness = 0.2;
|
||||
drawRectangleRoundedUV(rect, roundness, color);
|
||||
rl.drawRectangleRoundedLinesEx(RectUtils.shrink(rect, border - 1, border - 1), roundness, 0, border, srcery.bright_white.alpha(0.3));
|
||||
}
|
||||
|
||||
pub fn drawWorld(self: *App) !void {
|
||||
pub fn drawWorld(self: *App) void {
|
||||
rl.clearBackground(srcery.black);
|
||||
|
||||
rl.drawCircleV(rl.Vector2.zero(), 5, rl.Color.red);
|
||||
|
||||
const map_size = self.map_position_max.subtract(self.map_position_min);
|
||||
for (0..@intCast(map_size.y)) |oy| {
|
||||
for (0..@intCast(map_size.x)) |ox| {
|
||||
const map_index = @as(usize, @intCast(map_size.x)) * oy + ox;
|
||||
const x = self.map_position_min.x + @as(i64, @intCast(ox));
|
||||
const y = self.map_position_min.y + @as(i64, @intCast(oy));
|
||||
const texture_index = self.map_texture_indexes.items[map_index];
|
||||
const texture = self.map_textures.items[texture_index].texture;
|
||||
|
||||
const tile_size = rl.Vector2.init(224, 224);
|
||||
const position = rl.Vector2.init(@floatFromInt(x), @floatFromInt(y)).multiply(tile_size);
|
||||
rl.drawTextureV(texture, position, rl.Color.white);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drawWorldAndBlur(self: *App) !void {
|
||||
const screen_width = rl.getScreenWidth();
|
||||
const screen_height = rl.getScreenHeight();
|
||||
const screen_size = rl.Vector2.init(@floatFromInt(screen_width), @floatFromInt(screen_height));
|
||||
@ -267,27 +463,10 @@ pub fn drawWorld(self: *App) !void {
|
||||
blur_original.begin();
|
||||
defer blur_original.end();
|
||||
|
||||
rl.clearBackground(rl.Color.black.alpha(0));
|
||||
|
||||
self.camera.begin();
|
||||
defer self.camera.end();
|
||||
|
||||
rl.drawCircleV(rl.Vector2.zero(), 5, rl.Color.red);
|
||||
|
||||
const map_size = self.map_position_max.subtract(self.map_position_min);
|
||||
for (0..@intCast(map_size.y)) |oy| {
|
||||
for (0..@intCast(map_size.x)) |ox| {
|
||||
const map_index = @as(usize, @intCast(map_size.x)) * oy + ox;
|
||||
const x = self.map_position_min.x + @as(i64, @intCast(ox));
|
||||
const y = self.map_position_min.y + @as(i64, @intCast(oy));
|
||||
const texture_index = self.map_texture_indexes.items[map_index];
|
||||
const texture = self.map_textures.items[texture_index].texture;
|
||||
|
||||
const tile_size = rl.Vector2.init(224, 224);
|
||||
const position = rl.Vector2.init(@floatFromInt(x), @floatFromInt(y)).multiply(tile_size);
|
||||
rl.drawTextureV(texture, position, rl.Color.white);
|
||||
}
|
||||
}
|
||||
self.drawWorld();
|
||||
}
|
||||
|
||||
// 2 pass. Apply horizontal blur
|
||||
@ -421,12 +600,11 @@ pub fn tick(self: *App) !void {
|
||||
|
||||
rl.clearBackground(srcery.black);
|
||||
|
||||
try self.drawWorld();
|
||||
try self.drawWorldAndBlur();
|
||||
|
||||
try self.drawBlurredWorld(
|
||||
.{ .x = 20, .y = 20, .width = 200, .height = 200 },
|
||||
0.5,
|
||||
rl.Color.gray
|
||||
srcery.xgray10
|
||||
);
|
||||
|
||||
rl.drawFPS(
|
||||
|
@ -114,7 +114,7 @@ pub fn main() anyerror!void {
|
||||
rl.setWindowMinSize(200, 200);
|
||||
rl.setWindowState(.{
|
||||
.vsync_hint = true,
|
||||
// .window_resizable = true
|
||||
.window_resizable = true
|
||||
});
|
||||
|
||||
var app = try App.init(allocator, &artificer);
|
||||
|
Loading…
Reference in New Issue
Block a user