Start the gui system: movable windows

This commit is contained in:
IntegratedQuantum 2023-02-14 12:46:29 +01:00
parent fc52ad22ef
commit 0cf88c46a5
11 changed files with 691 additions and 62 deletions

View File

@ -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

View File

@ -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.
}
}

View File

@ -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
View 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
View 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();
}
}

View 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 {
}

View 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 {
}

View File

@ -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");
@ -31,8 +36,8 @@ pub var threadPool: utils.ThreadPool = undefined;
var logFile: std.fs.File = undefined;
// overwrite the log function:
pub const std_options = struct {
pub const log_level = .debug;
pub fn logFn(
pub const log_level = .debug;
pub fn logFn(
comptime level: std.log.Level,
comptime _: @Type(.EnumLiteral),
comptime format: []const u8,
@ -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});
}
}
}

View File

@ -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);
}

View File

@ -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.*/