From e8fd3617c587e80ab3ca9e8449fa85361eb641f9 Mon Sep 17 00:00:00 2001 From: Jeeves Date: Tue, 3 Jun 2025 00:20:44 -0600 Subject: [PATCH] add icon shader --- .gitignore | 3 +++ src/main.zig | 44 ++++++++++++++++++++++++++++++++++++++------ src/shaders/icon.fs | 29 +++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 src/shaders/icon.fs diff --git a/.gitignore b/.gitignore index 0aad988..8454e44 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ menu/ font/ reference/ screenshot.png +icon-mask.png +icon-normal.png +icon-normal-2.png diff --git a/src/main.zig b/src/main.zig index 6a815fd..35cea0f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -19,7 +19,8 @@ pub fn main() !void { var background = Background.init(); var column = Column.init( allocator, - raylib.LoadTextureFromImage(raylib.GenImageChecked(64, 64, 8, 8, raylib.BLACK, raylib.WHITE)), + raylib.LoadTexture("icon-mask.png"), + raylib.LoadTexture("icon-normal-2.png"), "Game", ); defer column.deinit(); @@ -50,6 +51,25 @@ pub fn main() !void { try column.appendItem(&item4); column.refresh(false); + icon_shader = raylib.LoadShaderFromMemory(0, @embedFile("shaders/icon.fs")); + defer raylib.UnloadShader(icon_shader); + + // const mask_loc = raylib.GetShaderLocation(shader, "textureMask"); + // const normal_loc = raylib.GetShaderLocation(icon_shader, "textureNormal"); + const light_dir_loc = raylib.GetShaderLocation(icon_shader, "lightDir"); + const light_color_loc = raylib.GetShaderLocation(icon_shader, "lightColor"); + const ambient_color_loc = raylib.GetShaderLocation(icon_shader, "ambientColor"); + + const icon_mask = raylib.LoadTexture("icon-mask.png"); + defer raylib.UnloadTexture(icon_mask); + + const icon_normal = raylib.LoadTexture("icon-normal-2.png"); + defer raylib.UnloadTexture(icon_normal); + + raylib.SetShaderValue(icon_shader, light_dir_loc, &raylib.Vector3{ .x = 0.5, .y = 0, .z = 0 }, raylib.SHADER_UNIFORM_VEC3); + raylib.SetShaderValue(icon_shader, light_color_loc, &raylib.Vector4{ .x = 1, .y = 1, .z = 1, .w = 1.5 }, raylib.SHADER_UNIFORM_VEC4); + raylib.SetShaderValue(icon_shader, ambient_color_loc, &raylib.Vector4{ .x = 0.90, .y = 0.82, .z = 0.98, .w = 0.8 }, raylib.SHADER_UNIFORM_VEC4); + raylib.SetTargetFPS(120); while (!raylib.WindowShouldClose()) { if (raylib.IsWindowResized()) { @@ -91,6 +111,7 @@ pub fn main() !void { var debug_draw = false; var global_font: raylib.Font = undefined; +var icon_shader: raylib.Shader = undefined; var screen_width: f32 = 480; var screen_height: f32 = 272; @@ -229,15 +250,17 @@ fn drawDebugGrid() void { // TODO item group sort pub const Column = struct { icon: raylib.Texture2D, + normal: ?raylib.Texture2D = null, title: []const u8, items: std.ArrayList(*Item), selected: usize = 0, - pub fn init(allocator: Allocator, icon: raylib.Texture2D, title: []const u8) Column { + pub fn init(allocator: Allocator, icon: raylib.Texture2D, normal: ?raylib.Texture2D, title: []const u8) Column { raylib.SetTextureFilter(icon, raylib.TEXTURE_FILTER_BILINEAR); return .{ .icon = icon, + .normal = normal, .title = title, .items = .init(allocator), }; @@ -250,6 +273,7 @@ pub const Column = struct { pub fn draw(self: *Column) void { var icon = Image{ .texture = self.icon, + .normal = self.normal, .box = .{ .x = scales.column_position_center.x, .y = scales.column_position_center.y, @@ -329,6 +353,7 @@ pub const Item = struct { pub fn init(texture: raylib.Texture2D, title: []const u8, subtitle: []const u8) Item { raylib.SetTextureFilter(texture, raylib.TEXTURE_FILTER_BILINEAR); + raylib.SetTextureWrap(texture, raylib.TEXTURE_WRAP_CLAMP); return .{ .icon = texture, .title = title, @@ -582,6 +607,7 @@ pub const BoundingBox = struct { pub const Image = struct { box: BoundingBox, texture: raylib.Texture2D, + normal: ?raylib.Texture2D = null, mode: Mode = .fit, align_w: Align = .center, @@ -609,16 +635,22 @@ pub const Image = struct { .right => self.box.y + self.box.h - height * scale, }, }; - if (debug_draw) + if (debug_draw) { raylib.DrawRectangleLines( @intFromFloat(self.box.x), @intFromFloat(self.box.y), @intFromFloat(self.box.w), @intFromFloat(self.box.h), raylib.MAROON, - ) - else - raylib.DrawTextureEx(self.texture, position, 0, scale, raylib.WHITE); + ); + } else { + if (self.normal) |n| { + raylib.SetShaderValueTexture(icon_shader, raylib.GetShaderLocation(icon_shader, "textureNormal"), n); + raylib.BeginShaderMode(icon_shader); + defer raylib.EndShaderMode(); + raylib.DrawTextureEx(self.texture, position, 0, scale, raylib.WHITE); + } else raylib.DrawTextureEx(self.texture, position, 0, scale, raylib.WHITE); + } } pub const Mode = enum { original, fit, fill }; diff --git a/src/shaders/icon.fs b/src/shaders/icon.fs new file mode 100644 index 0000000..a83e8fd --- /dev/null +++ b/src/shaders/icon.fs @@ -0,0 +1,29 @@ +#version 330 + +in vec2 fragTexCoord; +in vec4 fragColor; + +uniform sampler2D texture0; +uniform sampler2D textureNormal; + +uniform vec3 lightDir; +uniform vec4 lightColor; +uniform vec4 ambientColor; +uniform vec3 falloff = vec3(0.01, 2.4, 20); + +out vec4 finalColor; + +void main() { + float d = length(lightDir); + vec3 n = normalize(texture(textureNormal, fragTexCoord).xyz); + vec3 l = normalize(lightDir); + + vec3 diffuse = lightColor.rgb * lightColor.a * max(dot(n, l), 0.0); + vec3 ambient = ambientColor.rgb * ambientColor.a; + float attenuation = 1.0 / (falloff.x + falloff.y * d + falloff.z * d * d); + vec3 intensity = ambient + diffuse * attenuation; + + vec3 final = diffuse.rgb * intensity; + + finalColor = vec4(final, texture(texture0, fragTexCoord).a * 0.93); +}