mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 03:06:55 -04:00
Add textures for the button and window.
This commit is contained in:
parent
ff7df1bdbc
commit
61e2e417a2
20
assets/cubyz/shaders/ui/button.fs
Normal file
20
assets/cubyz/shaders/ui/button.fs
Normal file
@ -0,0 +1,20 @@
|
||||
#version 330
|
||||
|
||||
layout (location=0) out vec4 frag_color;
|
||||
uniform sampler2D image;
|
||||
|
||||
flat in vec4 fColor;
|
||||
in vec2 startCoord;
|
||||
|
||||
uniform bool pressed;
|
||||
uniform float scale;
|
||||
uniform vec2 randomOffset;
|
||||
|
||||
void main() {
|
||||
frag_color = texture(image, (gl_FragCoord.xy - startCoord)/(2*scale)/textureSize(image, 0) + randomOffset);
|
||||
frag_color.a *= fColor.a;
|
||||
frag_color.rgb += fColor.rgb;
|
||||
if(pressed) {
|
||||
frag_color.rgb *= 0.8;
|
||||
}
|
||||
}
|
27
assets/cubyz/shaders/ui/button.vs
Normal file
27
assets/cubyz/shaders/ui/button.vs
Normal file
@ -0,0 +1,27 @@
|
||||
#version 330 core
|
||||
|
||||
layout (location=0) in vec2 vertex_pos;
|
||||
|
||||
out vec2 startCoord;
|
||||
flat out vec4 fColor;
|
||||
|
||||
//in pixel
|
||||
uniform vec2 start;
|
||||
uniform vec2 size;
|
||||
uniform vec2 screen;
|
||||
|
||||
uniform int color;
|
||||
|
||||
void main() {
|
||||
|
||||
// Convert to opengl coordinates:
|
||||
vec2 position_percentage = (start + vertex_pos*size)/screen;
|
||||
startCoord.x = start.x;
|
||||
startCoord.y = screen.y - start.y;
|
||||
|
||||
vec2 position = vec2(position_percentage.x, -position_percentage.y)*2+vec2(-1, 1);
|
||||
|
||||
gl_Position = vec4(position, 0, 1);
|
||||
|
||||
fColor = vec4((color & 0xff0000)>>16, (color & 0xff00)>>8, color & 0xff, (color>>24) & 255)/255.0;
|
||||
}
|
BIN
assets/cubyz/ui/button.png
Normal file
BIN
assets/cubyz/ui/button.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 263 B |
BIN
assets/cubyz/ui/oak_log_side.png
Normal file
BIN
assets/cubyz/ui/oak_log_side.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 843 B |
BIN
assets/cubyz/ui/window_background.png
Normal file
BIN
assets/cubyz/ui/window_background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 846 B |
BIN
assets/cubyz/ui/window_title.png
Normal file
BIN
assets/cubyz/ui/window_title.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 706 B |
@ -45,8 +45,10 @@ pub fn build(b: *std.build.Builder) !void {
|
||||
}
|
||||
exe.addCSourceFiles(&[_][]const u8{"lib/glad.c", "lib/stb_image.c"}, &[_][]const u8{"-g"});
|
||||
exe.addAnonymousModule("gui", .{.source_file = .{.path = "src/gui/gui.zig"}});
|
||||
exe.addModule("freetype", freetype.module(b));
|
||||
exe.addModule("harfbuzz", freetype.harfbuzzModule(b));
|
||||
const harfbuzzModule = freetype.harfbuzzModule(b);
|
||||
const freetypeModule = harfbuzzModule.dependencies.get("freetype").?;
|
||||
exe.addModule("harfbuzz", harfbuzzModule);
|
||||
exe.addModule("freetype", freetypeModule);
|
||||
freetype.link(b, exe, .{ .harfbuzz = .{} });
|
||||
//exe.sanitize_thread = true;
|
||||
exe.install();
|
||||
|
@ -346,6 +346,25 @@ pub const draw = struct {
|
||||
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
pub fn customShadedRect(uniforms: anytype, _pos: Vec2f, _dim: Vec2f) void {
|
||||
var pos = _pos;
|
||||
var dim = _dim;
|
||||
pos *= @splat(2, scale);
|
||||
pos += translation;
|
||||
dim *= @splat(2, scale);
|
||||
|
||||
c.glUniform2f(uniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
|
||||
c.glUniform2f(uniforms.start, pos[0], pos[1]);
|
||||
c.glUniform2f(uniforms.size, dim[0], dim[1]);
|
||||
c.glUniform1i(uniforms.color, color);
|
||||
c.glUniform1f(uniforms.scale, scale);
|
||||
|
||||
c.glBindVertexArray(rectVAO);
|
||||
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
pub fn text(_text: []const u8, x: f32, y: f32, fontSize: f32) !void {
|
||||
@ -1220,6 +1239,35 @@ pub const TextureArray = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Texture = struct {
|
||||
textureID: c_uint,
|
||||
|
||||
pub fn init() Texture {
|
||||
var self: Texture = undefined;
|
||||
c.glGenTextures(1, &self.textureID);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn deinit(self: Texture) void {
|
||||
c.glDeleteTextures(1, &self.textureID);
|
||||
}
|
||||
|
||||
pub fn bind(self: Texture) void {
|
||||
c.glBindTexture(c.GL_TEXTURE_2D, self.textureID);
|
||||
}
|
||||
|
||||
/// (Re-)Generates the GPU buffer.
|
||||
pub fn generate(self: Texture, image: Image) !void {
|
||||
self.bind();
|
||||
|
||||
c.glTexImage2D(c.GL_TEXTURE_2D, 0, c.GL_RGBA8, image.width, image.height, 0, c.GL_RGBA, c.GL_UNSIGNED_BYTE, image.imageData.ptr);
|
||||
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_NEAREST);
|
||||
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_NEAREST);
|
||||
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_S, c.GL_REPEAT);
|
||||
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_T, c.GL_REPEAT);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Color = extern struct {
|
||||
r: u8,
|
||||
g: u8,
|
||||
|
@ -4,6 +4,9 @@ const Allocator = std.mem.Allocator;
|
||||
const main = @import("root");
|
||||
const graphics = main.graphics;
|
||||
const draw = graphics.draw;
|
||||
const Image = graphics.Image;
|
||||
const Shader = graphics.Shader;
|
||||
const Texture = graphics.Texture;
|
||||
const settings = main.settings;
|
||||
const vec = main.vec;
|
||||
const Vec2f = vec.Vec2f;
|
||||
@ -66,6 +69,43 @@ onCloseFn: *const fn()void = &defaultFunction,
|
||||
var grabPosition: ?Vec2f = null;
|
||||
var selfPositionWhenGrabbed: Vec2f = undefined;
|
||||
|
||||
var backgroundTexture: Texture = undefined;
|
||||
var titleTexture: Texture = undefined;
|
||||
var shader: Shader = undefined;
|
||||
var windowUniforms: struct {
|
||||
screen: c_int,
|
||||
start: c_int,
|
||||
size: c_int,
|
||||
color: c_int,
|
||||
scale: c_int,
|
||||
|
||||
image: c_int,
|
||||
randomOffset: c_int,
|
||||
} = undefined;
|
||||
|
||||
pub fn __init() !void {
|
||||
shader = try Shader.create("assets/cubyz/shaders/ui/button.vs", "assets/cubyz/shaders/ui/button.fs");
|
||||
windowUniforms = shader.bulkGetUniformLocation(@TypeOf(windowUniforms));
|
||||
shader.bind();
|
||||
graphics.c.glUniform1i(windowUniforms.image, 0);
|
||||
|
||||
backgroundTexture = Texture.init();
|
||||
const backgroundImage = try Image.readFromFile(main.threadAllocator, "assets/cubyz/ui/window_background.png");
|
||||
defer backgroundImage.deinit(main.threadAllocator);
|
||||
try backgroundTexture.generate(backgroundImage);
|
||||
|
||||
titleTexture = Texture.init();
|
||||
const titleImage = try Image.readFromFile(main.threadAllocator, "assets/cubyz/ui/window_title.png");
|
||||
defer titleImage.deinit(main.threadAllocator);
|
||||
try titleTexture.generate(titleImage);
|
||||
}
|
||||
|
||||
pub fn __deinit() void {
|
||||
shader.delete();
|
||||
backgroundTexture.deinit();
|
||||
titleTexture.deinit();
|
||||
}
|
||||
|
||||
pub fn defaultFunction() void {}
|
||||
pub fn defaultErrorFunction() Allocator.Error!void {}
|
||||
|
||||
@ -351,21 +391,31 @@ pub fn render(self: *const GuiWindow) !void {
|
||||
mousePosition /= @splat(2, scale);
|
||||
const oldTranslation = draw.setTranslation(self.pos);
|
||||
const oldScale = draw.setScale(scale);
|
||||
draw.setColor(0xff000000);
|
||||
graphics.c.glActiveTexture(graphics.c.GL_TEXTURE0);
|
||||
shader.bind();
|
||||
backgroundTexture.bind();
|
||||
draw.customShadedRect(windowUniforms, .{0, 0}, self.size);
|
||||
for(self.components) |*component| {
|
||||
try component.render(mousePosition);
|
||||
}
|
||||
if(self.showTitleBar) {
|
||||
graphics.c.glActiveTexture(graphics.c.GL_TEXTURE0);
|
||||
shader.bind();
|
||||
titleTexture.bind();
|
||||
if(self == gui.selectedWindow) {
|
||||
draw.setColor(0xff000040);
|
||||
} else {
|
||||
draw.setColor(0xff000000);
|
||||
}
|
||||
draw.customShadedRect(windowUniforms, .{0, 0}, .{self.size[0], 16});
|
||||
}
|
||||
draw.restoreTranslation(oldTranslation);
|
||||
draw.restoreScale(oldScale);
|
||||
if(self.showTitleBar) {
|
||||
var text = try graphics.TextBuffer.init(main.threadAllocator, self.title, .{}, false);
|
||||
defer text.deinit();
|
||||
const titleDimension = try text.calculateLineBreaks(16*scale, self.size[0]*scale);
|
||||
if(self == gui.selectedWindow) {
|
||||
draw.setColor(0xff80b080);
|
||||
} else {
|
||||
draw.setColor(0xffb08080);
|
||||
}
|
||||
draw.rect(self.pos, Vec2f{self.size[0]*scale, titleDimension[1]});
|
||||
try text.render(self.pos[0] + self.size[0]*scale/2 - titleDimension[0]/2, self.pos[1], 16*scale);
|
||||
}
|
||||
if(self == gui.selectedWindow and grabPosition != null) {
|
||||
|
@ -8,6 +8,7 @@ const Image = graphics.Image;
|
||||
const Shader = graphics.Shader;
|
||||
const TextBuffer = graphics.TextBuffer;
|
||||
const Texture = graphics.Texture;
|
||||
const random = main.random;
|
||||
const vec = main.vec;
|
||||
const Vec2f = vec.Vec2f;
|
||||
|
||||
@ -19,15 +20,50 @@ const Button = @This();
|
||||
const border: f32 = 3;
|
||||
const fontSize: f32 = 16;
|
||||
|
||||
var texture: Texture = undefined;
|
||||
pub var shader: Shader = undefined;
|
||||
var buttonUniforms: struct {
|
||||
screen: c_int,
|
||||
start: c_int,
|
||||
size: c_int,
|
||||
color: c_int,
|
||||
scale: c_int,
|
||||
|
||||
image: c_int,
|
||||
pressed: c_int,
|
||||
randomOffset: c_int,
|
||||
} = undefined;
|
||||
|
||||
pressed: bool = false,
|
||||
onAction: *const fn() void,
|
||||
text: TextBuffer,
|
||||
textSize: Vec2f = undefined,
|
||||
randomOffset: Vec2f = undefined,
|
||||
|
||||
pub fn __init() !void {
|
||||
shader = try Shader.create("assets/cubyz/shaders/ui/button.vs", "assets/cubyz/shaders/ui/button.fs");
|
||||
buttonUniforms = shader.bulkGetUniformLocation(@TypeOf(buttonUniforms));
|
||||
shader.bind();
|
||||
graphics.c.glUniform1i(buttonUniforms.image, 0);
|
||||
texture = Texture.init();
|
||||
const image = try Image.readFromFile(main.threadAllocator, "assets/cubyz/ui/button.png");
|
||||
defer image.deinit(main.threadAllocator);
|
||||
try texture.generate(image);
|
||||
}
|
||||
|
||||
pub fn __deinit() void {
|
||||
shader.delete();
|
||||
texture.deinit();
|
||||
}
|
||||
|
||||
pub fn init(pos: Vec2f, width: f32, allocator: Allocator, text: []const u8, onAction: *const fn() void) Allocator.Error!GuiComponent {
|
||||
var self = Button {
|
||||
.onAction = onAction,
|
||||
.text = try TextBuffer.init(allocator, text, .{}, false),
|
||||
.randomOffset = Vec2f{
|
||||
random.nextFloat(&main.seed),
|
||||
random.nextFloat(&main.seed),
|
||||
},
|
||||
};
|
||||
self.textSize = try self.text.calculateLineBreaks(fontSize, width - 3*border);
|
||||
return GuiComponent {
|
||||
@ -54,49 +90,21 @@ pub fn mainButtonReleased(self: *Button, component: *const GuiComponent, mousePo
|
||||
}
|
||||
}
|
||||
|
||||
const buttonColor: [5]u32 = [_]u32{
|
||||
0xff9ca6bf, // center
|
||||
0xffa6b0cc, // top
|
||||
0xffa0aac4, // right
|
||||
0xff919ab3, // bottom
|
||||
0xff97a1ba, // left
|
||||
};
|
||||
|
||||
const buttonPressedColor: [5]u32 = [_]u32{
|
||||
0xff929ab3, // center
|
||||
0xff878fa6, // top
|
||||
0xff8e96ad, // right
|
||||
0xff9ca5bf, // bottom
|
||||
0xff969fb8, // left
|
||||
};
|
||||
|
||||
const buttonHoveredColor: [5]u32 = [_]u32{
|
||||
0xff9ca6dd, // center
|
||||
0xffa6b0ea, // top
|
||||
0xffa0aae2, // right
|
||||
0xff919ad1, // bottom
|
||||
0xff97a1d8, // left
|
||||
};
|
||||
|
||||
pub fn render(self: *Button, component: *const GuiComponent, mousePosition: Vec2f) !void {
|
||||
// TODO: I should really just add a proper button texture.
|
||||
var colors = &buttonColor;
|
||||
if(component.contains(mousePosition)) {
|
||||
colors = &buttonHoveredColor;
|
||||
}
|
||||
graphics.c.glActiveTexture(graphics.c.GL_TEXTURE0);
|
||||
texture.bind();
|
||||
shader.bind();
|
||||
graphics.c.glUniform2f(buttonUniforms.randomOffset, self.randomOffset[0], self.randomOffset[1]);
|
||||
graphics.c.glUniform1i(buttonUniforms.pressed, 0);
|
||||
if(self.pressed) {
|
||||
colors = &buttonPressedColor;
|
||||
draw.setColor(0xff000000);
|
||||
graphics.c.glUniform1i(buttonUniforms.pressed, 1);
|
||||
} else if(component.contains(mousePosition)) {
|
||||
draw.setColor(0xff000040);
|
||||
} else {
|
||||
draw.setColor(0xff000000);
|
||||
}
|
||||
draw.setColor(colors[0]);
|
||||
draw.rect(component.pos + @splat(2, border), component.size - @splat(2, 2*border));
|
||||
draw.setColor(colors[1]);
|
||||
draw.rect(component.pos, Vec2f{component.size[0] - border, border});
|
||||
draw.setColor(colors[2]);
|
||||
draw.rect(component.pos + Vec2f{component.size[0] - border, 0}, Vec2f{border, component.size[1] - border});
|
||||
draw.setColor(colors[3]);
|
||||
draw.rect(component.pos + Vec2f{border, component.size[1] - border}, Vec2f{component.size[0] - border, border});
|
||||
draw.setColor(colors[4]);
|
||||
draw.rect(component.pos + Vec2f{0, border}, Vec2f{border, component.size[1] - border});
|
||||
draw.customShadedRect(buttonUniforms, component.pos, component.size);
|
||||
const textPos = component.pos + component.size/@splat(2, @as(f32, 2.0)) - self.textSize/@splat(2, @as(f32, 2.0));
|
||||
try self.text.render(textPos[0], textPos[1], fontSize);
|
||||
}
|
@ -7,6 +7,7 @@ const settings = main.settings;
|
||||
const vec = main.vec;
|
||||
const Vec2f = vec.Vec2f;
|
||||
|
||||
const Button = @import("components/Button.zig");
|
||||
pub const GuiComponent = @import("GuiComponent.zig");
|
||||
pub const GuiWindow = @import("GuiWindow.zig");
|
||||
|
||||
@ -24,6 +25,8 @@ pub fn init() !void {
|
||||
inline for(@typeInfo(windowlist).Struct.decls) |decl| {
|
||||
try @field(windowlist, decl.name).init();
|
||||
}
|
||||
try GuiWindow.__init();
|
||||
try Button.__init();
|
||||
}
|
||||
|
||||
pub fn deinit() void {
|
||||
@ -33,6 +36,8 @@ pub fn deinit() void {
|
||||
window.onCloseFn();
|
||||
}
|
||||
openWindows.deinit();
|
||||
GuiWindow.__deinit();
|
||||
Button.__deinit();
|
||||
}
|
||||
|
||||
pub fn addWindow(window: *GuiWindow, isHudWindow: bool) !void {
|
||||
|
@ -174,7 +174,7 @@ pub const Window = struct {
|
||||
}
|
||||
}
|
||||
fn glDebugOutput(_: c_uint, _: c_uint, _: c_uint, severity: c_uint, length: c_int, message: [*c]const u8, _: ?*const anyopaque) callconv(.C) void {
|
||||
if(severity == c.GL_DEBUG_SEVERITY_HIGH) {
|
||||
if(severity == c.GL_DEBUG_SEVERITY_HIGH) { // TODO: Capture the stack traces.
|
||||
std.log.err("OpenGL {}:{s}", .{severity, message[0..@intCast(usize, length)]});
|
||||
} else if(severity == c.GL_DEBUG_SEVERITY_MEDIUM) {
|
||||
std.log.warn("OpenGL {}:{s}", .{severity, message[0..@intCast(usize, length)]});
|
||||
|
Loading…
x
Reference in New Issue
Block a user