mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 03:06:55 -04:00
Start the gui system: movable windows
This commit is contained in:
parent
fc52ad22ef
commit
0cf88c46a5
25
build.zig
25
build.zig
@ -10,9 +10,13 @@ pub fn build(b: *std.build.Builder) !void {
|
||||
|
||||
// Standard release options allow the person running `zig build` to select
|
||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
|
||||
const mode = b.standardReleaseOptions();
|
||||
|
||||
const exe = b.addExecutable("Cubyzig", "src/main.zig");
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "Cubyzig",
|
||||
.root_source_file = .{ .path = "src/main.zig" },
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
exe.addIncludePath("include");
|
||||
exe.linkLibC();
|
||||
{ // compile glfw from source:
|
||||
@ -40,11 +44,10 @@ pub fn build(b: *std.build.Builder) !void {
|
||||
}
|
||||
}
|
||||
exe.addCSourceFiles(&[_][]const u8{"lib/glad.c", "lib/stb_image.c"}, &[_][]const u8{"-g"});
|
||||
exe.addPackage(freetype.pkg);
|
||||
exe.addPackage(freetype.harfbuzz_pkg);
|
||||
exe.addAnonymousModule("gui", .{.source_file = .{.path = "src/gui/gui.zig"}});
|
||||
exe.addModule("freetype", freetype.module(b));
|
||||
exe.addModule("harfbuzz", freetype.harfbuzzModule(b));
|
||||
freetype.link(b, exe, .{ .harfbuzz = .{} });
|
||||
exe.setTarget(target);
|
||||
exe.setBuildMode(mode);
|
||||
//exe.sanitize_thread = true;
|
||||
exe.install();
|
||||
|
||||
@ -57,9 +60,11 @@ pub fn build(b: *std.build.Builder) !void {
|
||||
const run_step = b.step("run", "Run the app");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
|
||||
const exe_tests = b.addTest("src/main.zig");
|
||||
exe_tests.setTarget(target);
|
||||
exe_tests.setBuildMode(mode);
|
||||
const exe_tests = b.addTest(.{
|
||||
.root_source_file = .{ .path = "src/main.zig" },
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
const test_step = b.step("test", "Run unit tests");
|
||||
test_step.dependOn(&exe_tests.step);
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 9cfd1177292533c68f7d4d9a2a123722c8b494f4
|
||||
Subproject commit 0fed693866fb86d9e94169ca06338353b3e40511
|
@ -127,8 +127,8 @@ pub const ClientEntityManager = struct {
|
||||
const xCenter = (1 + projectedPos[0]/projectedPos[3])*@intToFloat(f32, main.Window.width/2);
|
||||
const yCenter = (1 - projectedPos[1]/projectedPos[3])*@intToFloat(f32, main.Window.height/2);
|
||||
|
||||
graphics.Draw.setColor(0xffff00ff);
|
||||
graphics.Draw.rect(.{xCenter, yCenter}, .{100, 20}); // TODO: Text rendering.
|
||||
graphics.draw.setColor(0xffff00ff);
|
||||
graphics.draw.rect(.{xCenter, yCenter}, .{100, 20}); // TODO: Text rendering.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ fn fileToString(allocator: Allocator, path: []const u8) ![]u8 {
|
||||
return file.readToEndAlloc(allocator, std.math.maxInt(usize));
|
||||
}
|
||||
|
||||
pub const Draw = struct {
|
||||
pub const draw = struct {
|
||||
var color: i32 = 0;
|
||||
var clip: ?Vec4i = null;
|
||||
|
||||
@ -541,7 +541,7 @@ pub const TextBuffer = struct {
|
||||
c.glUniform1f(TextRendering.uniforms.ratio, fontScaling);
|
||||
c.glActiveTexture(c.GL_TEXTURE0);
|
||||
c.glBindTexture(c.GL_TEXTURE_2D, TextRendering.glyphTexture[0]);
|
||||
c.glBindVertexArray(Draw.rectVAO);
|
||||
c.glBindVertexArray(draw.rectVAO);
|
||||
const lineWraps: []f32 = try main.threadAllocator.alloc(f32, self.lineBreakIndices.items.len - 1);
|
||||
defer main.threadAllocator.free(lineWraps);
|
||||
var i: usize = 0;
|
||||
@ -563,14 +563,14 @@ pub const TextBuffer = struct {
|
||||
y = _y/fontScaling;
|
||||
if(line.isUnderline) y += 15
|
||||
else y += 8;
|
||||
Draw.setColor(line.color | @as(u32, 0xff000000));
|
||||
draw.setColor(line.color | @as(u32, 0xff000000));
|
||||
for(lineWraps) |lineWrap| {
|
||||
const lineStart = @max(0, line.start);
|
||||
const lineEnd = @min(lineWrap, line.end);
|
||||
if(lineStart < lineEnd) {
|
||||
var start = Vec2f{lineStart*fontScaling + _x, y*fontScaling};
|
||||
const dim = Vec2f{(lineEnd - lineStart)*fontScaling, fontScaling};
|
||||
Draw.rect(start, dim);
|
||||
draw.rect(start, dim);
|
||||
}
|
||||
line.start -= lineWrap;
|
||||
line.end -= lineWrap;
|
||||
@ -725,20 +725,20 @@ const TextRendering = struct {
|
||||
};
|
||||
|
||||
pub fn init() !void {
|
||||
Draw.initCircle();
|
||||
Draw.initDrawRect();
|
||||
Draw.initImage();
|
||||
Draw.initLine();
|
||||
Draw.initRect();
|
||||
draw.initCircle();
|
||||
draw.initDrawRect();
|
||||
draw.initImage();
|
||||
draw.initLine();
|
||||
draw.initRect();
|
||||
try TextRendering.init();
|
||||
}
|
||||
|
||||
pub fn deinit() void {
|
||||
Draw.deinitCircle();
|
||||
Draw.deinitDrawRect();
|
||||
Draw.deinitImage();
|
||||
Draw.deinitLine();
|
||||
Draw.deinitRect();
|
||||
draw.deinitCircle();
|
||||
draw.deinitDrawRect();
|
||||
draw.deinitImage();
|
||||
draw.deinitLine();
|
||||
draw.deinitRect();
|
||||
TextRendering.deinit();
|
||||
}
|
||||
|
||||
|
343
src/gui/GuiWindow.zig
Normal file
343
src/gui/GuiWindow.zig
Normal file
@ -0,0 +1,343 @@
|
||||
const std = @import("std");
|
||||
|
||||
const main = @import("root");
|
||||
const graphics = main.graphics;
|
||||
const draw = graphics.draw;
|
||||
const settings = main.settings;
|
||||
const vec = main.vec;
|
||||
const Vec2f = vec.Vec2f;
|
||||
const Vec2i = vec.Vec2i;
|
||||
|
||||
const gui = @import("gui.zig");
|
||||
|
||||
const GuiWindow = @This();
|
||||
|
||||
const AttachmentPoint = enum {
|
||||
lower,
|
||||
middle,
|
||||
upper,
|
||||
};
|
||||
|
||||
const OrientationLine = struct {
|
||||
pos: f32,
|
||||
start: f32,
|
||||
end: f32,
|
||||
};
|
||||
|
||||
const RelativePosition = union(enum) {
|
||||
ratio: f32,
|
||||
attachedToFrame: struct {
|
||||
selfAttachmentPoint: AttachmentPoint,
|
||||
otherAttachmentPoint: AttachmentPoint,
|
||||
},
|
||||
relativeToWindow: struct {
|
||||
reference: *GuiWindow,
|
||||
ratio: f32,
|
||||
},
|
||||
attachedToWindow: struct {
|
||||
reference: *GuiWindow,
|
||||
selfAttachmentPoint: AttachmentPoint,
|
||||
otherAttachmentPoint: AttachmentPoint,
|
||||
},
|
||||
};
|
||||
|
||||
pos: Vec2f = undefined,
|
||||
size: Vec2f = undefined,
|
||||
contentSize: Vec2f,
|
||||
scale: f32 = 1,
|
||||
spacing: f32 = 0,
|
||||
relativePosition: [2]RelativePosition = .{.{.ratio = 0.5}, .{.ratio = 0.5}},
|
||||
showTitleBar: bool = true,
|
||||
title: []const u8,
|
||||
id: []const u8,
|
||||
|
||||
/// Called every frame.
|
||||
renderFn: *const fn()void,
|
||||
/// Called every frame for the currently selected window.
|
||||
updateFn: *const fn()void = &defaultFunction,
|
||||
|
||||
onOpenFn: *const fn()void = &defaultFunction,
|
||||
|
||||
onCloseFn: *const fn()void = &defaultFunction,
|
||||
|
||||
var grabPosition: ?Vec2f = null;
|
||||
var selfPositionWhenGrabbed: Vec2f = undefined;
|
||||
|
||||
pub fn defaultFunction() void {}
|
||||
|
||||
pub fn leftMouseButtonPressed(self: *const GuiWindow) void {
|
||||
const scale = @floor(settings.guiScale*self.scale); // TODO
|
||||
var mousePosition = main.Window.getMousePosition();
|
||||
mousePosition -= self.pos;
|
||||
mousePosition /= @splat(2, scale);
|
||||
if(mousePosition[1] < 16) {
|
||||
grabPosition = main.Window.getMousePosition();
|
||||
selfPositionWhenGrabbed = self.pos;
|
||||
} else {
|
||||
// TODO: Call window function.
|
||||
}
|
||||
}
|
||||
|
||||
pub fn leftMouseButtonReleased(self: *const GuiWindow) void {
|
||||
_ = self; // TODO
|
||||
grabPosition = null;
|
||||
}
|
||||
|
||||
fn snapToOtherWindow(self: *GuiWindow) void {
|
||||
const scale = @floor(settings.guiScale*self.scale); // TODO
|
||||
for(self.relativePosition) |*relPos, i| {
|
||||
var minDist: f32 = settings.guiScale*2;
|
||||
var minWindow: ?*GuiWindow = null;
|
||||
var selfAttachment: AttachmentPoint = undefined;
|
||||
var otherAttachment: AttachmentPoint = undefined;
|
||||
outer: for(gui.openWindows.items) |other| {
|
||||
// Check if they touch:
|
||||
const start = @max(self.pos[i^1], other.pos[i^1]);
|
||||
const end = @min(self.pos[i^1] + self.size[i^1]*scale, other.pos[i^1] + other.size[i^1]*@floor(settings.guiScale*other.scale));
|
||||
if(start >= end) continue;
|
||||
// Detect cycles:
|
||||
var win: ?*GuiWindow = other;
|
||||
while(win) |_win| {
|
||||
if(win == self) continue :outer;
|
||||
switch(_win.relativePosition[i]) {
|
||||
.ratio => {
|
||||
win = null;
|
||||
},
|
||||
.attachedToFrame => {
|
||||
win = null;
|
||||
},
|
||||
.relativeToWindow => |relativeToWindow| {
|
||||
win = relativeToWindow.reference;
|
||||
},
|
||||
.attachedToWindow => |attachedToWindow| {
|
||||
win = attachedToWindow.reference;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const dist1 = @fabs(self.pos[i] - other.pos[i] - other.size[i]*@floor(settings.guiScale*other.scale)); // TODO: scale
|
||||
if(dist1 < minDist) {
|
||||
minDist = dist1;
|
||||
minWindow = other;
|
||||
selfAttachment = .lower;
|
||||
otherAttachment = .upper;
|
||||
}
|
||||
const dist2 = @fabs(self.pos[i] + self.size[i]*scale - other.pos[i]);
|
||||
if(dist2 < minDist) {
|
||||
minDist = dist2;
|
||||
minWindow = other;
|
||||
selfAttachment = .upper;
|
||||
otherAttachment = .lower;
|
||||
}
|
||||
}
|
||||
if(minWindow) |other| {
|
||||
relPos.* = .{.attachedToWindow = .{.reference = other, .selfAttachmentPoint = selfAttachment, .otherAttachmentPoint = otherAttachment}};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn positionRelativeToFrame(self: *GuiWindow) void {
|
||||
const scale = @floor(settings.guiScale*self.scale); // TODO
|
||||
const windowSize = main.Window.getWindowSize();
|
||||
for(self.relativePosition) |*relPos, i| {
|
||||
// Snap to the center:
|
||||
if(@fabs(self.pos[i] + self.size[i]*scale - windowSize[i]/2) <= settings.guiScale*2) {
|
||||
relPos.* = .{.attachedToFrame = .{
|
||||
.selfAttachmentPoint = .upper,
|
||||
.otherAttachmentPoint = .middle,
|
||||
}};
|
||||
} else if(@fabs(self.pos[i] + self.size[i]*scale/2 - windowSize[i]/2) <= settings.guiScale*2) {
|
||||
relPos.* = .{.attachedToFrame = .{
|
||||
.selfAttachmentPoint = .middle,
|
||||
.otherAttachmentPoint = .middle,
|
||||
}};
|
||||
} else if(@fabs(self.pos[i] - windowSize[i]/2) <= settings.guiScale*2) {
|
||||
relPos.* = .{.attachedToFrame = .{
|
||||
.selfAttachmentPoint = .lower,
|
||||
.otherAttachmentPoint = .middle,
|
||||
}};
|
||||
} else {
|
||||
var ratio: f32 = (self.pos[i] + self.size[i]*scale/2)/windowSize[i];
|
||||
if(self.pos[i] <= 0) {
|
||||
ratio = 0;
|
||||
} else if(self.pos[i] + self.size[i]*scale >= windowSize[i]) {
|
||||
ratio = 1;
|
||||
}
|
||||
relPos.* = .{.ratio = ratio};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn positionRelativeToConnectedWindow(self: *GuiWindow, other: *GuiWindow, i: usize) void {
|
||||
const scale = @floor(settings.guiScale*self.scale); // TODO
|
||||
const otherSize = other.size*@splat(2, @floor(settings.guiScale*other.scale)); // TODO: scale
|
||||
const relPos = &self.relativePosition[i];
|
||||
// Snap to the center:
|
||||
if(@fabs(self.pos[i] + self.size[i]*scale - (other.pos[i] + otherSize[i]/2)) <= settings.guiScale*2) {
|
||||
relPos.* = .{.attachedToWindow = .{
|
||||
.reference = other,
|
||||
.selfAttachmentPoint = .upper,
|
||||
.otherAttachmentPoint = .middle,
|
||||
}};
|
||||
} else if(@fabs(self.pos[i] + self.size[i]*scale/2 - (other.pos[i] + otherSize[i]/2)) <= settings.guiScale*2) {
|
||||
relPos.* = .{.attachedToWindow = .{
|
||||
.reference = other,
|
||||
.selfAttachmentPoint = .middle,
|
||||
.otherAttachmentPoint = .middle,
|
||||
}};
|
||||
} else if(@fabs(self.pos[i] - (other.pos[i] + otherSize[i]/2)) <= settings.guiScale*2) {
|
||||
relPos.* = .{.attachedToWindow = .{
|
||||
.reference = other,
|
||||
.selfAttachmentPoint = .lower,
|
||||
.otherAttachmentPoint = .middle,
|
||||
}};
|
||||
// Snap to the edges:
|
||||
} else if(@fabs(self.pos[i] - other.pos[i]) <= settings.guiScale*2) {
|
||||
relPos.* = .{.attachedToWindow = .{
|
||||
.reference = other,
|
||||
.selfAttachmentPoint = .lower,
|
||||
.otherAttachmentPoint = .lower,
|
||||
}};
|
||||
} else if(@fabs(self.pos[i] + self.size[i]*scale - (other.pos[i] + otherSize[i])) <= settings.guiScale*2) {
|
||||
relPos.* = .{.attachedToWindow = .{
|
||||
.reference = other,
|
||||
.selfAttachmentPoint = .upper,
|
||||
.otherAttachmentPoint = .upper,
|
||||
}};
|
||||
} else {
|
||||
self.relativePosition[i] = .{.relativeToWindow = .{
|
||||
.reference = other,
|
||||
.ratio = (self.pos[i] + self.size[i]*scale/2 - other.pos[i])/otherSize[i]
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(self: *GuiWindow) !void {
|
||||
const scale = @floor(settings.guiScale*self.scale); // TODO
|
||||
const mousePosition = main.Window.getMousePosition();
|
||||
const windowSize = main.Window.getWindowSize();
|
||||
if(grabPosition) |_grabPosition| {
|
||||
self.relativePosition[0] = .{.ratio = undefined};
|
||||
self.relativePosition[1] = .{.ratio = undefined};
|
||||
self.pos = (mousePosition - _grabPosition) + selfPositionWhenGrabbed;
|
||||
self.snapToOtherWindow();
|
||||
if(self.relativePosition[0] == .ratio and self.relativePosition[1] == .ratio) {
|
||||
self.positionRelativeToFrame();
|
||||
} else if(self.relativePosition[0] == .ratio) {
|
||||
self.positionRelativeToConnectedWindow(self.relativePosition[1].attachedToWindow.reference, 0);
|
||||
} else if(self.relativePosition[1] == .ratio) {
|
||||
self.positionRelativeToConnectedWindow(self.relativePosition[0].attachedToWindow.reference, 1);
|
||||
}
|
||||
self.pos = @max(self.pos, Vec2f{0, 0});
|
||||
self.pos = @min(self.pos, windowSize - self.size*@splat(2, scale));
|
||||
gui.updateWindowPositions();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateWindowPosition(self: *GuiWindow) void {
|
||||
const scale = @floor(settings.guiScale*self.scale); // TODO
|
||||
const windowSize = main.Window.getWindowSize();
|
||||
for(self.relativePosition) |relPos, i| {
|
||||
switch(relPos) {
|
||||
.ratio => |ratio| {
|
||||
self.pos[i] = windowSize[i]*ratio - self.size[i]*scale/2;
|
||||
self.pos[i] = @max(self.pos[i], 0);
|
||||
self.pos[i] = @min(self.pos[i], windowSize[i] - self.size[i]*scale);
|
||||
},
|
||||
.attachedToFrame => |attachedToFrame| {
|
||||
const otherPos = switch(attachedToFrame.otherAttachmentPoint) {
|
||||
.lower => 0,
|
||||
.middle => 0.5*windowSize[i],
|
||||
.upper => windowSize[i],
|
||||
};
|
||||
self.pos[i] = switch(attachedToFrame.selfAttachmentPoint) {
|
||||
.lower => otherPos,
|
||||
.middle => otherPos - 0.5*self.size[i]*scale,
|
||||
.upper => otherPos - self.size[i]*scale,
|
||||
};
|
||||
},
|
||||
.attachedToWindow => |attachedToWindow| {
|
||||
const other = attachedToWindow.reference;
|
||||
const otherPos = switch(attachedToWindow.otherAttachmentPoint) {
|
||||
.lower => other.pos[i],
|
||||
.middle => other.pos[i] + 0.5*other.size[i]*@floor(settings.guiScale*other.scale), // TODO: scale
|
||||
.upper => other.pos[i] + other.size[i]*@floor(settings.guiScale*other.scale), // TODO: scale
|
||||
};
|
||||
self.pos[i] = switch(attachedToWindow.selfAttachmentPoint) {
|
||||
.lower => otherPos,
|
||||
.middle => otherPos - 0.5*self.size[i]*scale,
|
||||
.upper => otherPos - self.size[i]*scale,
|
||||
};
|
||||
},
|
||||
.relativeToWindow => |relativeToWindow| {
|
||||
const other = relativeToWindow.reference;
|
||||
const otherSize = other.size[i]*@floor(settings.guiScale*other.scale); // TODO: scale
|
||||
const otherPos = other.pos[i];
|
||||
self.pos[i] = otherPos + relativeToWindow.ratio*otherSize - self.size[i]*scale/2;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn drawOrientationLines(self: *const GuiWindow) void {
|
||||
const scale = @floor(settings.guiScale*self.scale); // TODO
|
||||
draw.setColor(0x80000000);
|
||||
const windowSize = main.Window.getWindowSize();
|
||||
for(self.relativePosition) |relPos, i| {
|
||||
switch(relPos) {
|
||||
.ratio, .relativeToWindow => {
|
||||
continue;
|
||||
},
|
||||
.attachedToFrame => |attachedToFrame| {
|
||||
const pos = switch(attachedToFrame.otherAttachmentPoint) {
|
||||
.lower => 0,
|
||||
.middle => 0.5*windowSize[i],
|
||||
.upper => windowSize[i],
|
||||
};
|
||||
if(i == 0) {
|
||||
draw.line(.{pos, 0}, .{pos, windowSize[i^1]});
|
||||
} else {
|
||||
draw.line(.{0, pos}, .{windowSize[i^1], pos});
|
||||
}
|
||||
},
|
||||
.attachedToWindow => |attachedToWindow| {
|
||||
const other = attachedToWindow.reference;
|
||||
const otherSize = other.size*@splat(2, @floor(settings.guiScale*other.scale)); // TODO: scale
|
||||
const pos = switch(attachedToWindow.otherAttachmentPoint) {
|
||||
.lower => other.pos[i],
|
||||
.middle => other.pos[i] + 0.5*otherSize[i],
|
||||
.upper => other.pos[i] + otherSize[i],
|
||||
};
|
||||
const start = @min(self.pos[i^1], other.pos[i^1]);
|
||||
const end = @max(self.pos[i^1] + self.size[i^1]*scale, other.pos[i^1] + otherSize[i^1]);
|
||||
if(i == 0) {
|
||||
draw.line(.{pos, start}, .{pos, end});
|
||||
} else {
|
||||
draw.line(.{start, pos}, .{end, pos});
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(self: *const GuiWindow) !void {
|
||||
const scale = @floor(settings.guiScale*self.scale); // TODO
|
||||
draw.setColor(0xff808080);
|
||||
draw.rect(self.pos, self.size*@splat(2, scale));
|
||||
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) {
|
||||
self.drawOrientationLines();
|
||||
}
|
||||
}
|
142
src/gui/gui.zig
Normal file
142
src/gui/gui.zig
Normal file
@ -0,0 +1,142 @@
|
||||
const std = @import("std");
|
||||
|
||||
const main = @import("root");
|
||||
const graphics = main.graphics;
|
||||
const draw = graphics.draw;
|
||||
const settings = main.settings;
|
||||
const vec = main.vec;
|
||||
const Vec2f = vec.Vec2f;
|
||||
|
||||
pub const GuiWindow = @import("GuiWindow.zig");
|
||||
|
||||
pub const hotbar = @import("windows/hotbar.zig");
|
||||
pub const healthbar = @import("windows/healthbar.zig");
|
||||
|
||||
var windowList: std.ArrayList(*GuiWindow) = undefined;
|
||||
var hudWindows: std.ArrayList(*GuiWindow) = undefined;
|
||||
pub var openWindows: std.ArrayList(*GuiWindow) = undefined;
|
||||
pub var selectedWindow: ?*GuiWindow = null; // TODO: Make private.
|
||||
|
||||
pub fn init() !void {
|
||||
windowList = std.ArrayList(*GuiWindow).init(main.globalAllocator);
|
||||
hudWindows = std.ArrayList(*GuiWindow).init(main.globalAllocator);
|
||||
openWindows = std.ArrayList(*GuiWindow).init(main.globalAllocator);
|
||||
try hotbar.init();
|
||||
try healthbar.init();
|
||||
}
|
||||
|
||||
pub fn deinit() void {
|
||||
windowList.deinit();
|
||||
hudWindows.deinit();
|
||||
openWindows.deinit();
|
||||
}
|
||||
|
||||
pub fn addWindow(window: *GuiWindow, isHudWindow: bool) !void {
|
||||
for(windowList.items) |other| {
|
||||
if(std.mem.eql(u8, window.id, other.id)) {
|
||||
std.log.err("Duplicate window id: {s}", .{window.id});
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(isHudWindow) {
|
||||
try hudWindows.append(window);
|
||||
window.showTitleBar = false;
|
||||
}
|
||||
try windowList.append(window);
|
||||
}
|
||||
|
||||
pub fn openWindow(id: []const u8) !void {
|
||||
defer updateWindowPositions();
|
||||
var wasFound: bool = false;
|
||||
outer: for(windowList.items) |window| {
|
||||
if(std.mem.eql(u8, window.id, id)) {
|
||||
wasFound = true;
|
||||
for(openWindows.items) |_openWindow| {
|
||||
if(_openWindow == window) {
|
||||
std.log.warn("Window with id {s} is already open.", .{id});
|
||||
continue :outer;
|
||||
}
|
||||
}
|
||||
window.showTitleBar = true;
|
||||
try openWindows.append(window);
|
||||
window.pos = .{0, 0};
|
||||
window.size = window.contentSize;
|
||||
window.onOpenFn();
|
||||
return;
|
||||
}
|
||||
}
|
||||
std.log.warn("Could not find window with id {s}.", .{id});
|
||||
}
|
||||
|
||||
pub fn closeWindow(window: *GuiWindow) void {
|
||||
defer updateWindowPositions();
|
||||
if(selectedWindow == window) {
|
||||
selectedWindow = null;
|
||||
}
|
||||
for(openWindows.items) |_openWindow, i| {
|
||||
if(_openWindow == window) {
|
||||
openWindows.swapRemove(i);
|
||||
}
|
||||
}
|
||||
window.onCloseFn();
|
||||
}
|
||||
|
||||
pub fn leftMouseButtonPressed() void {
|
||||
selectedWindow = null;
|
||||
var selectedI: usize = 0;
|
||||
for(openWindows.items) |window, i| {
|
||||
var mousePosition = main.Window.getMousePosition();
|
||||
mousePosition -= window.pos;
|
||||
mousePosition /= @splat(2, window.scale*settings.guiScale);
|
||||
if(@reduce(.And, mousePosition >= Vec2f{0, 0}) and @reduce(.And, mousePosition < window.size)) {
|
||||
selectedWindow = window;
|
||||
selectedI = i;
|
||||
}
|
||||
}
|
||||
if(selectedWindow) |_selectedWindow| {
|
||||
_selectedWindow.leftMouseButtonPressed();
|
||||
_ = openWindows.orderedRemove(selectedI);
|
||||
openWindows.appendAssumeCapacity(_selectedWindow);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn leftMouseButtonReleased() void {
|
||||
var oldWindow = selectedWindow;
|
||||
selectedWindow = null;
|
||||
for(openWindows.items) |window| {
|
||||
var mousePosition = main.Window.getMousePosition();
|
||||
mousePosition -= window.pos;
|
||||
mousePosition /= @splat(2, window.scale*settings.guiScale);
|
||||
if(@reduce(.And, mousePosition >= Vec2f{0, 0}) and @reduce(.And, mousePosition < window.size)) {
|
||||
selectedWindow = window;
|
||||
}
|
||||
}
|
||||
if(selectedWindow != oldWindow) { // Unselect the window if the mouse left it.
|
||||
selectedWindow = null;
|
||||
}
|
||||
if(oldWindow) |_oldWindow| {
|
||||
_oldWindow.leftMouseButtonReleased();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateWindowPositions() void {
|
||||
var wasChanged: bool = false;
|
||||
for(openWindows.items) |window| {
|
||||
const oldPos = window.pos;
|
||||
window.updateWindowPosition();
|
||||
const newPos = window.pos;
|
||||
if(vec.lengthSquare(oldPos - newPos) >= 1e-3) {
|
||||
wasChanged = true;
|
||||
}
|
||||
}
|
||||
if(wasChanged) @call(.always_tail, updateWindowPositions, .{}); // Very efficient O(n²) algorithm :P
|
||||
}
|
||||
|
||||
pub fn updateAndRenderGui() !void {
|
||||
if(selectedWindow) |selected| {
|
||||
try selected.update();
|
||||
}
|
||||
for(openWindows.items) |window| {
|
||||
try window.render();
|
||||
}
|
||||
}
|
25
src/gui/windows/healthbar.zig
Normal file
25
src/gui/windows/healthbar.zig
Normal file
@ -0,0 +1,25 @@
|
||||
const main = @import("root");
|
||||
const Vec2f = main.vec.Vec2f;
|
||||
|
||||
const gui = @import("../gui.zig");
|
||||
const GuiWindow = gui.GuiWindow;
|
||||
|
||||
var healthbarWindow: GuiWindow = undefined;
|
||||
pub fn init() !void {
|
||||
healthbarWindow = GuiWindow{
|
||||
.contentSize = Vec2f{128, 16},
|
||||
.title = "Health Bar",
|
||||
.id = "cubyz:healthbar",
|
||||
.renderFn = &render,
|
||||
.updateFn = &update,
|
||||
};
|
||||
try gui.addWindow(&healthbarWindow, true);
|
||||
}
|
||||
|
||||
pub fn render() void {
|
||||
|
||||
}
|
||||
|
||||
pub fn update() void {
|
||||
|
||||
}
|
44
src/gui/windows/hotbar.zig
Normal file
44
src/gui/windows/hotbar.zig
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
const main = @import("root");
|
||||
const Vec2f = main.vec.Vec2f;
|
||||
|
||||
const gui = @import("../gui.zig");
|
||||
const GuiWindow = gui.GuiWindow;
|
||||
|
||||
var hotbarWindow: GuiWindow = undefined;
|
||||
var hotbarWindow2: GuiWindow = undefined;
|
||||
var hotbarWindow3: GuiWindow = undefined;
|
||||
pub fn init() !void {
|
||||
hotbarWindow = GuiWindow{
|
||||
.contentSize = Vec2f{64*8, 64},
|
||||
.title = "Hotbar",
|
||||
.id = "cubyz:hotbar",
|
||||
.renderFn = &render,
|
||||
.updateFn = &update,
|
||||
};
|
||||
try gui.addWindow(&hotbarWindow, true);
|
||||
hotbarWindow2 = GuiWindow{
|
||||
.contentSize = Vec2f{64*8, 64},
|
||||
.title = "Hotbar2",
|
||||
.id = "cubyz:hotbar2",
|
||||
.renderFn = &render,
|
||||
.updateFn = &update,
|
||||
};
|
||||
try gui.addWindow(&hotbarWindow2, true);
|
||||
hotbarWindow3 = GuiWindow{
|
||||
.contentSize = Vec2f{64*8, 64},
|
||||
.title = "Hotbar3",
|
||||
.id = "cubyz:hotbar3",
|
||||
.renderFn = &render,
|
||||
.updateFn = &update,
|
||||
};
|
||||
try gui.addWindow(&hotbarWindow3, true);
|
||||
}
|
||||
|
||||
pub fn render() void {
|
||||
|
||||
}
|
||||
|
||||
pub fn update() void {
|
||||
|
||||
}
|
120
src/main.zig
120
src/main.zig
@ -1,22 +1,27 @@
|
||||
const std = @import("std");
|
||||
|
||||
const assets = @import("assets.zig");
|
||||
const blocks = @import("blocks.zig");
|
||||
const chunk = @import("chunk.zig");
|
||||
const entity = @import("entity.zig");
|
||||
const game = @import("game.zig");
|
||||
const graphics = @import("graphics.zig");
|
||||
const itemdrop = @import("itemdrop.zig");
|
||||
const items = @import("items.zig");
|
||||
const models = @import("models.zig");
|
||||
const network = @import("network.zig");
|
||||
const renderer = @import("renderer.zig");
|
||||
const rotation = @import("rotation.zig");
|
||||
const settings = @import("settings.zig");
|
||||
const utils = @import("utils.zig");
|
||||
const gui = @import("gui");
|
||||
|
||||
const Vec2f = @import("vec.zig").Vec2f;
|
||||
const Vec3d = @import("vec.zig").Vec3d;
|
||||
pub const assets = @import("assets.zig");
|
||||
pub const blocks = @import("blocks.zig");
|
||||
pub const chunk = @import("chunk.zig");
|
||||
pub const entity = @import("entity.zig");
|
||||
pub const game = @import("game.zig");
|
||||
pub const graphics = @import("graphics.zig");
|
||||
pub const itemdrop = @import("itemdrop.zig");
|
||||
pub const items = @import("items.zig");
|
||||
pub const JsonElement = @import("json.zig");
|
||||
pub const models = @import("models.zig");
|
||||
pub const network = @import("network.zig");
|
||||
pub const random = @import("random.zig");
|
||||
pub const renderer = @import("renderer.zig");
|
||||
pub const rotation = @import("rotation.zig");
|
||||
pub const settings = @import("settings.zig");
|
||||
pub const utils = @import("utils.zig");
|
||||
pub const vec = @import("vec.zig");
|
||||
|
||||
const Vec2f = vec.Vec2f;
|
||||
const Vec3d = vec.Vec3d;
|
||||
|
||||
pub const c = @cImport ({
|
||||
@cInclude("glad/glad.h");
|
||||
@ -59,8 +64,10 @@ pub const std_options = struct {
|
||||
const Key = struct {
|
||||
pressed: bool = false,
|
||||
key: c_int = c.GLFW_KEY_UNKNOWN,
|
||||
mouseButton: c_int = -1,
|
||||
scancode: c_int = 0,
|
||||
releaseAction: ?*const fn() void = null,
|
||||
pressAction: ?*const fn() void = null,
|
||||
};
|
||||
pub var keyboard: struct {
|
||||
forward: Key = Key{.key = c.GLFW_KEY_W},
|
||||
@ -71,6 +78,9 @@ pub var keyboard: struct {
|
||||
jump: Key = Key{.key = c.GLFW_KEY_SPACE},
|
||||
fall: Key = Key{.key = c.GLFW_KEY_LEFT_SHIFT},
|
||||
fullscreen: Key = Key{.key = c.GLFW_KEY_F11, .releaseAction = &Window.toggleFullscreen},
|
||||
leftMouseButton: Key = Key{.mouseButton = c.GLFW_MOUSE_BUTTON_LEFT, .pressAction = &gui.leftMouseButtonPressed, .releaseAction = &gui.leftMouseButtonReleased},
|
||||
rightMouseButton: Key = Key{.mouseButton = c.GLFW_MOUSE_BUTTON_RIGHT},
|
||||
middleMouseButton: Key = Key{.mouseButton = c.GLFW_MOUSE_BUTTON_MIDDLE},
|
||||
} = .{};
|
||||
|
||||
pub const Window = struct {
|
||||
@ -90,6 +100,9 @@ pub const Window = struct {
|
||||
if(key == @field(keyboard, field.name).key) {
|
||||
if(key != c.GLFW_KEY_UNKNOWN or scancode == @field(keyboard, field.name).scancode) {
|
||||
@field(keyboard, field.name).pressed = true;
|
||||
if(@field(keyboard, field.name).pressAction) |pressAction| {
|
||||
pressAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -111,6 +124,7 @@ pub const Window = struct {
|
||||
width = @intCast(u31, newWidth);
|
||||
height = @intCast(u31, newHeight);
|
||||
renderer.updateViewport(width, height, settings.fov);
|
||||
gui.updateWindowPositions();
|
||||
}
|
||||
// Mouse deltas are averaged over multiple frames using a circular buffer:
|
||||
const deltasLen: u2 = 3;
|
||||
@ -137,6 +151,28 @@ pub const Window = struct {
|
||||
ignoreDataAfterRecentGrab = false;
|
||||
currentPos = newPos;
|
||||
}
|
||||
fn mouseButton(_: ?*c.GLFWwindow, button: c_int, action: c_int, mods: c_int) callconv(.C) void {
|
||||
_ = mods;
|
||||
if(action == c.GLFW_PRESS) {
|
||||
inline for(@typeInfo(@TypeOf(keyboard)).Struct.fields) |field| {
|
||||
if(button == @field(keyboard, field.name).mouseButton) {
|
||||
@field(keyboard, field.name).pressed = true;
|
||||
if(@field(keyboard, field.name).pressAction) |pressAction| {
|
||||
pressAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(action == c.GLFW_RELEASE) {
|
||||
inline for(@typeInfo(@TypeOf(keyboard)).Struct.fields) |field| {
|
||||
if(button == @field(keyboard, field.name).mouseButton) {
|
||||
@field(keyboard, field.name).pressed = false;
|
||||
if(@field(keyboard, field.name).releaseAction) |releaseAction| {
|
||||
releaseAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
std.log.err("OpenGL {}:{s}", .{severity, message[0..@intCast(usize, length)]});
|
||||
@ -162,6 +198,14 @@ pub const Window = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getMousePosition() Vec2f {
|
||||
return GLFWCallbacks.currentPos;
|
||||
}
|
||||
|
||||
pub fn getWindowSize() Vec2f {
|
||||
return Vec2f{@intToFloat(f32, width), @intToFloat(f32, height)};
|
||||
}
|
||||
|
||||
fn init() !void {
|
||||
_ = c.glfwSetErrorCallback(GLFWCallbacks.errorCallback);
|
||||
|
||||
@ -180,6 +224,7 @@ pub const Window = struct {
|
||||
_ = c.glfwSetKeyCallback(window, GLFWCallbacks.keyCallback);
|
||||
_ = c.glfwSetFramebufferSizeCallback(window, GLFWCallbacks.framebufferSize);
|
||||
_ = c.glfwSetCursorPosCallback(window, GLFWCallbacks.cursorPosition);
|
||||
_ = c.glfwSetMouseButtonCallback(window, GLFWCallbacks.mouseButton);
|
||||
|
||||
c.glfwMakeContextCurrent(window);
|
||||
|
||||
@ -257,6 +302,37 @@ pub fn main() !void {
|
||||
try graphics.init();
|
||||
defer graphics.deinit();
|
||||
|
||||
try gui.init();
|
||||
defer gui.deinit();
|
||||
try gui.openWindow("cubyz:hotbar");
|
||||
try gui.openWindow("cubyz:hotbar2");
|
||||
try gui.openWindow("cubyz:hotbar3");
|
||||
try gui.openWindow("cubyz:healthbar");
|
||||
|
||||
c.glCullFace(c.GL_BACK);
|
||||
c.glEnable(c.GL_BLEND);
|
||||
c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
while(c.glfwWindowShouldClose(Window.window) == 0) {
|
||||
{ // Check opengl errors:
|
||||
const err = c.glGetError();
|
||||
if(err != 0) {
|
||||
std.log.err("Got opengl error: {}", .{err});
|
||||
}
|
||||
}
|
||||
c.glfwSwapBuffers(Window.window);
|
||||
c.glfwPollEvents();
|
||||
|
||||
{ // Render the GUI
|
||||
c.glClearColor(0.5, 1, 1, 1);
|
||||
c.glClear(c.GL_DEPTH_BUFFER_BIT | c.GL_STENCIL_BUFFER_BIT | c.GL_COLOR_BUFFER_BIT);
|
||||
c.glDisable(c.GL_CULL_FACE);
|
||||
c.glDisable(c.GL_DEPTH_TEST);
|
||||
try gui.updateAndRenderGui();
|
||||
}
|
||||
}
|
||||
if(true) return; // TODO
|
||||
|
||||
try rotation.init();
|
||||
defer rotation.deinit();
|
||||
|
||||
@ -333,20 +409,14 @@ pub fn main() !void {
|
||||
{ // Render the GUI
|
||||
c.glDisable(c.GL_CULL_FACE);
|
||||
c.glDisable(c.GL_DEPTH_TEST);
|
||||
|
||||
try gui.updateAndRenderGui();
|
||||
//const dim = try buffer2.calculateLineBreaks(32, 200);
|
||||
//try buffer.render(100, 200, 32);
|
||||
//graphics.Draw.setColor(0xff008000);
|
||||
//graphics.Draw.rect(.{100, 400}, .{200, dim[1]});
|
||||
//graphics.draw.setColor(0xff008000);
|
||||
//graphics.draw.rect(.{100, 400}, .{200, dim[1]});
|
||||
//try buffer2.render(100, 400, 32);
|
||||
//_ = try buffer3.calculateLineBreaks(32, 600);
|
||||
//try buffer3.render(400, 400, 32);
|
||||
|
||||
//graphics.Draw.setColor(0xff0000ff);
|
||||
//graphics.Draw.rect(Vec2f{.x = 100, .y = 100}, Vec2f{.x = 200, .y = 100});
|
||||
//graphics.Draw.circle(Vec2f{.x = 200, .y = 200}, 59);
|
||||
//graphics.Draw.setColor(0xffff00ff);
|
||||
//graphics.Draw.line(Vec2f{.x = 0, .y = 0}, Vec2f{.x = 1920, .y = 1080});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -327,7 +327,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
|
||||
// if(Window.getRenderTarget() != null)
|
||||
// Window.getRenderTarget().bind();
|
||||
|
||||
c.glBindVertexArray(graphics.Draw.rectVAO);
|
||||
c.glBindVertexArray(graphics.draw.rectVAO);
|
||||
c.glDisable(c.GL_DEPTH_TEST);
|
||||
c.glDisable(c.GL_CULL_FACE);
|
||||
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
||||
@ -419,7 +419,7 @@ const Bloom = struct {
|
||||
colorExtractShader.bind();
|
||||
buffers.bindTextures();
|
||||
extractedBuffer.bind();
|
||||
c.glBindVertexArray(graphics.Draw.rectVAO);
|
||||
c.glBindVertexArray(graphics.draw.rectVAO);
|
||||
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
@ -428,7 +428,7 @@ const Bloom = struct {
|
||||
c.glActiveTexture(c.GL_TEXTURE3);
|
||||
c.glBindTexture(c.GL_TEXTURE_2D, extractedBuffer.texture);
|
||||
buffer1.bind();
|
||||
c.glBindVertexArray(graphics.Draw.rectVAO);
|
||||
c.glBindVertexArray(graphics.draw.rectVAO);
|
||||
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
@ -437,7 +437,7 @@ const Bloom = struct {
|
||||
c.glActiveTexture(c.GL_TEXTURE3);
|
||||
c.glBindTexture(c.GL_TEXTURE_2D, buffer1.texture);
|
||||
buffer2.bind();
|
||||
c.glBindVertexArray(graphics.Draw.rectVAO);
|
||||
c.glBindVertexArray(graphics.draw.rectVAO);
|
||||
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
@ -446,7 +446,7 @@ const Bloom = struct {
|
||||
c.glActiveTexture(c.GL_TEXTURE3);
|
||||
c.glBindTexture(c.GL_TEXTURE_2D, buffer2.texture);
|
||||
buffer1.bind();
|
||||
c.glBindVertexArray(graphics.Draw.rectVAO);
|
||||
c.glBindVertexArray(graphics.draw.rectVAO);
|
||||
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
@ -455,7 +455,7 @@ const Bloom = struct {
|
||||
c.glActiveTexture(c.GL_TEXTURE3);
|
||||
c.glBindTexture(c.GL_TEXTURE_2D, buffer1.texture);
|
||||
buffers.bind();
|
||||
c.glBindVertexArray(graphics.Draw.rectVAO);
|
||||
c.glBindVertexArray(graphics.draw.rectVAO);
|
||||
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,8 @@ pub var playerName: []const u8 = "quanturmdoelvloper";
|
||||
|
||||
pub var lastUsedIPAddress: []const u8 = "127.0.0.1";
|
||||
|
||||
pub var guiScale: f32 = 2;
|
||||
|
||||
|
||||
pub fn init() !void {
|
||||
const json = blk: {
|
||||
@ -117,8 +119,6 @@ pub fn deinit() void {
|
||||
//
|
||||
// private static Language currentLanguage = null;
|
||||
//
|
||||
// public static int GUI_SCALE = 2;
|
||||
//
|
||||
// public static boolean musicOnOff = true; //Turn on or off the music
|
||||
//
|
||||
// /**Not actually a setting, but stored here anyways.*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user