Add the ItemSlot component.

This commit is contained in:
IntegratedQuantum 2023-03-23 13:08:29 +01:00
parent f158da89d4
commit 642624c94d
7 changed files with 188 additions and 14 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

View File

@ -0,0 +1,110 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const main = @import("root");
const ItemStack = main.items.ItemStack;
const graphics = main.graphics;
const draw = graphics.draw;
const Texture = graphics.Texture;
const TextBuffer = graphics.TextBuffer;
const vec = main.vec;
const Vec2f = vec.Vec2f;
const gui = @import("../gui.zig");
const GuiComponent = gui.GuiComponent;
const ItemSlot = @This();
var texture: Texture = undefined;
const border: f32 = 3;
pos: Vec2f,
size: Vec2f = .{32 + 2*border, 32 + 2*border},
itemStack: *ItemStack,
oldStack: ItemStack,
text: TextBuffer,
textSize: Vec2f = .{0, 0},
hovered: bool = false,
pressed: bool = false,
pub fn __init() !void {
texture = try Texture.initFromFile("assets/cubyz/ui/inventory/slot.png");
}
pub fn __deinit() void {
texture.deinit();
}
pub fn init(pos: Vec2f, itemStack: *ItemStack) Allocator.Error!*ItemSlot {
const self = try gui.allocator.create(ItemSlot);
var buf: [16]u8 = undefined;
self.* = ItemSlot {
.itemStack = itemStack,
.oldStack = itemStack.*,
.pos = pos,
.text = try TextBuffer.init(gui.allocator, std.fmt.bufPrint(&buf, "{}", .{self.itemStack.amount}) catch "", .{}, false, .right),
};
self.textSize = try self.text.calculateLineBreaks(8, self.size[0] - 2*border);
return self;
}
pub fn deinit(self: *const ItemSlot) void {
self.text.deinit();
gui.allocator.destroy(self);
}
fn refreshText(self: *ItemSlot) !void {
self.text.deinit();
var buf: [16]u8 = undefined;
self.text = try TextBuffer.init(gui.allocator, std.fmt.bufPrint(&buf, "{}", .{self.itemStack.amount}) catch "", .{}, false, .right);
self.textSize = try self.text.calculateLineBreaks(8, self.size[0] - 2*border);
}
pub fn toComponent(self: *ItemSlot) GuiComponent {
return GuiComponent{
.itemSlot = self
};
}
pub fn updateHovered(self: *ItemSlot, _: Vec2f) void {
self.hovered = true;
}
pub fn mainButtonPressed(self: *ItemSlot, _: Vec2f) void {
self.pressed = true;
}
pub fn mainButtonReleased(self: *ItemSlot, mousePosition: Vec2f) void {
if(self.pressed) {
self.pressed = false;
if(GuiComponent.contains(self.pos, self.size, mousePosition)) {
//TODO: self.onAction();
}
}
}
pub fn render(self: *ItemSlot, _: Vec2f) !void {
const newStack = self.itemStack.*;
if(newStack.amount != self.oldStack.amount) {
try self.refreshText();
}
draw.setColor(0xffffffff);
texture.bindTo(0);
draw.boundImage(self.pos, self.size);
if(self.itemStack.item) |item| {
const itemTexture = try item.getTexture();
itemTexture.bindTo(0);
draw.boundImage(self.pos + @splat(2, border), self.size - @splat(2, 2*border));
if(self.itemStack.amount > 1) {
try self.text.render(self.pos[0] + self.size[0] - self.textSize[0] - border, self.pos[1] + self.size[1] - self.textSize[1] - border, 8);
}
}
if(self.pressed) {
draw.setColor(0x80808080);
draw.rect(self.pos, self.size);
} else if(self.hovered) {
self.hovered = false;
draw.setColor(0x300000ff);
draw.rect(self.pos, self.size);
}
}

View File

@ -11,6 +11,7 @@ const Vec2f = vec.Vec2f;
const Button = @import("components/Button.zig");
const CheckBox = @import("components/CheckBox.zig");
const ItemSlot = @import("components/ItemSlot.zig");
const ScrollBar = @import("components/ScrollBar.zig");
const Slider = @import("components/Slider.zig");
const TextInput = @import("components/TextInput.zig");
@ -46,6 +47,7 @@ pub fn init(_allocator: Allocator) !void {
try GuiWindow.__init();
try Button.__init();
try CheckBox.__init();
try ItemSlot.__init();
try ScrollBar.__init();
try Slider.__init();
try TextInput.__init();
@ -65,6 +67,7 @@ pub fn deinit() void {
GuiWindow.__deinit();
Button.__deinit();
CheckBox.__deinit();
ItemSlot.__deinit();
ScrollBar.__deinit();
Slider.__deinit();
TextInput.__deinit();

View File

@ -9,6 +9,7 @@ pub const GuiComponent = union(enum) {
pub const Button = @import("components/Button.zig");
pub const CheckBox = @import("components/CheckBox.zig");
pub const HorizontalList = @import("components/HorizontalList.zig");
pub const ItemSlot = @import("components/ItemSlot.zig");
pub const Label = @import("components/Label.zig");
pub const MutexComponent = @import("components/MutexComponent.zig");
pub const Slider = @import("components/Slider.zig");
@ -20,6 +21,7 @@ pub const GuiComponent = union(enum) {
button: *Button,
checkBox: *CheckBox,
horizontalList: *HorizontalList,
itemSlot: *ItemSlot,
label: *Label,
mutexComponent: *MutexComponent,
scrollBar: *ScrollBar,

View File

@ -2,20 +2,45 @@ const std = @import("std");
const Allocator = std.mem.Allocator;
const main = @import("root");
const Player = main.game.Player;
const Vec2f = main.vec.Vec2f;
const gui = @import("../gui.zig");
const GuiComponent = gui.GuiComponent;
const GuiWindow = gui.GuiWindow;
const HorizontalList = GuiComponent.HorizontalList;
const ItemSlot = GuiComponent.ItemSlot;
var components: [1]GuiComponent = undefined;
pub var window = GuiWindow {
.contentSize = Vec2f{64*8, 64},
.title = "Hotbar",
.id = "cubyz:hotbar",
.onOpenFn = &onOpen,
.onCloseFn = &onClose,
.renderFn = &render,
.components = &components,
.isHud = true,
.showTitleBar = false,
.hasBackground = false,
};
pub fn render() Allocator.Error!void {
pub fn onOpen() Allocator.Error!void {
var list = try HorizontalList.init();
for(0..8) |i| {
try list.add(try ItemSlot.init(.{0, 0}, &Player.inventory__SEND_CHANGES_TO_SERVER.items[i]));
}
list.finish(.{0, 0}, .center);
components[0] = list.toComponent();
window.contentSize = components[0].size();
gui.updateWindowPositions();
}
pub fn onClose() void {
for(&components) |*comp| {
comp.deinit();
}
}
pub fn render() Allocator.Error!void {
}

View File

@ -570,7 +570,7 @@ pub const ItemDropRenderer = struct {
.item = template.item,
};
// Find sizes and free index:
const img = self.item.getTexture();
const img = self.item.getImage();
self.size = Vec3i{img.width, 1, img.height};
var freeSlot: ?*ItemVoxelModel = null;
for(freeSlots.items, 0..) |potentialSlot, i| {

View File

@ -67,7 +67,8 @@ const Material = struct {
pub const BaseItem = struct {
texture: graphics.Image,
image: graphics.Image,
texture: ?graphics.Texture, // TODO: Properly deinit
id: []const u8,
name: []const u8,
@ -78,7 +79,7 @@ pub const BaseItem = struct {
fn init(self: *BaseItem, allocator: Allocator, texturePath: []const u8, replacementTexturePath: []const u8, id: []const u8, json: JsonElement) !void {
self.id = try allocator.dupe(u8, id);
self.texture = graphics.Image.readFromFile(allocator, texturePath) catch graphics.Image.readFromFile(allocator, replacementTexturePath) catch blk: {
self.image = graphics.Image.readFromFile(allocator, texturePath) catch graphics.Image.readFromFile(allocator, replacementTexturePath) catch blk: {
std.log.err("Item texture not found in {s} and {s}.", .{texturePath, replacementTexturePath});
break :blk graphics.Image.defaultImage;
};
@ -94,6 +95,7 @@ pub const BaseItem = struct {
self.block = blk: {
break :blk blocks.getByID(json.get(?[]const u8, "block", null) orelse break :blk null);
};
self.texture = null;
self.foodValue = json.get(f32, "food", 0);
}
@ -104,6 +106,14 @@ pub const BaseItem = struct {
}
return hash;
}
fn getTexture(self: *BaseItem) !graphics.Texture {
if(self.texture == null) {
self.texture = graphics.Texture.init();
try self.texture.?.generate(self.image);
}
return self.texture.?;
}
// TODO: Check if/how this is needed:
// protected Item(int stackSize) {
// id = Resource.EMPTY;
@ -412,7 +422,7 @@ const TextureGenerator = struct {
}
pub fn generate(tool: *Tool) !void {
const img = tool.texture;
const img = tool.image;
var pixelMaterials: [16][16]PixelData = undefined;
for(0..16) |x| {
for(0..16) |y| {
@ -869,7 +879,8 @@ const ToolPhysics = struct {
const Tool = struct {
craftingGrid: [25]?*const BaseItem,
materialGrid: [16][16]?*const BaseItem,
texture: graphics.Image,
image: graphics.Image,
texture: ?graphics.Texture,
seed: u32,
/// Reduction factor to block breaking time.
@ -901,12 +912,16 @@ const Tool = struct {
pub fn init() !*Tool {
var self = try main.globalAllocator.create(Tool);
self.texture = try graphics.Image.init(main.globalAllocator, 16, 16);
self.image = try graphics.Image.init(main.globalAllocator, 16, 16);
self.texture = null;
return self;
}
pub fn deinit(self: *const Tool) void {
self.texture.deinit(main.globalAllocator);
if(self.texture) |texture| {
texture.deinit();
}
self.image.deinit(main.globalAllocator);
main.globalAllocator.destroy(self);
}
@ -961,6 +976,14 @@ const Tool = struct {
return hash;
}
fn getTexture(self: *Tool) !graphics.Texture {
if(self.texture == null) {
self.texture = graphics.Texture.init();
try self.texture.?.generate(self.image);
}
return self.texture.?;
}
pub fn getPowerByBlockClass(self: *Tool, blockClass: blocks.BlockClass) f32 {
return switch(blockClass) {
.fluid => 0,
@ -979,8 +1002,8 @@ const Tool = struct {
};
pub const Item = union(enum) {
baseItem: *const BaseItem,
tool: *const Tool,
baseItem: *BaseItem,
tool: *Tool,
pub fn init(json: JsonElement) !Item {
if(reverseIndices.get(json.get([]const u8, "item", "null"))) |baseItem| {
@ -1026,13 +1049,24 @@ pub const Item = union(enum) {
}
}
pub fn getTexture(self: Item) graphics.Image {
pub fn getTexture(self: Item) !graphics.Texture {
switch(self) {
.baseItem => |_baseItem| {
return _baseItem.texture;
return try _baseItem.getTexture();
},
.tool => |_tool| {
return _tool.texture;
return try _tool.getTexture();
},
}
}
pub fn getImage(self: Item) graphics.Image {
switch(self) {
.baseItem => |_baseItem| {
return _baseItem.image;
},
.tool => |_tool| {
return _tool.image;
},
}
}
@ -1256,7 +1290,7 @@ pub fn deinit() void {
arena.deinit();
}
pub fn getByID(id: []const u8) ?*const BaseItem {
pub fn getByID(id: []const u8) ?*BaseItem {
if(reverseIndices.get(id)) |result| {
return result;
} else {