Various ui improvements proposed by @till++
@ -2,14 +2,16 @@
|
|||||||
|
|
||||||
layout (location=0) out vec4 frag_color;
|
layout (location=0) out vec4 frag_color;
|
||||||
|
|
||||||
in vec2 frag_face_pos;
|
flat in vec4 color;
|
||||||
in vec4 color;
|
|
||||||
|
|
||||||
uniform sampler2D texture_sampler;
|
uniform sampler2D texture_sampler;
|
||||||
|
|
||||||
//in pxls
|
//in pxls
|
||||||
uniform vec4 texture_rect;
|
uniform vec4 texture_rect;
|
||||||
|
uniform vec2 scene;
|
||||||
uniform vec2 fontSize;
|
uniform vec2 fontSize;
|
||||||
|
uniform vec2 offset;
|
||||||
|
uniform float ratio;
|
||||||
uniform int fontEffects;
|
uniform int fontEffects;
|
||||||
|
|
||||||
vec2 convert2Proportional(vec2 original, vec2 full){
|
vec2 convert2Proportional(vec2 original, vec2 full){
|
||||||
@ -18,6 +20,7 @@ vec2 convert2Proportional(vec2 original, vec2 full){
|
|||||||
|
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
|
vec2 frag_face_pos = (vec2(0, scene.y) + gl_FragCoord.xy*vec2(1, -1) - offset)/texture_rect.zw/ratio;
|
||||||
vec4 texture_rect_percentage = vec4(convert2Proportional(texture_rect.xy, fontSize), convert2Proportional(texture_rect.zw, fontSize));
|
vec4 texture_rect_percentage = vec4(convert2Proportional(texture_rect.xy, fontSize), convert2Proportional(texture_rect.zw, fontSize));
|
||||||
vec2 texture_position = vec2(
|
vec2 texture_position = vec2(
|
||||||
texture_rect_percentage.x+
|
texture_rect_percentage.x+
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
layout (location=0) in vec2 face_pos;
|
layout (location=0) in vec2 face_pos;
|
||||||
|
|
||||||
out vec2 frag_face_pos;
|
flat out vec4 color;
|
||||||
out vec4 color;
|
|
||||||
|
|
||||||
|
|
||||||
//in pixel
|
//in pixel
|
||||||
@ -35,6 +34,5 @@ void main() {
|
|||||||
vec2 position = vec2(rect.x+vertex_pos.x*rect.z, -rect.y+vertex_pos.y*rect.w)*2+vec2(-1, 1);
|
vec2 position = vec2(rect.x+vertex_pos.x*rect.z, -rect.y+vertex_pos.y*rect.w)*2+vec2(-1, 1);
|
||||||
|
|
||||||
gl_Position = vec4(position, 0, 1);
|
gl_Position = vec4(position, 0, 1);
|
||||||
frag_face_pos = face_pos;
|
|
||||||
color = vec4(vec3((fontEffects & 0xff0000)>>16, (fontEffects & 0xff00)>>8, fontEffects & 0xff)/255.0, alpha);
|
color = vec4(vec3((fontEffects & 0xff0000)>>16, (fontEffects & 0xff00)>>8, fontEffects & 0xff)/255.0, alpha);
|
||||||
}
|
}
|
19
assets/cubyz/shaders/ui/window_border.fs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#version 330
|
||||||
|
|
||||||
|
layout (location=0) out vec4 frag_color;
|
||||||
|
|
||||||
|
flat in vec4 fColor;
|
||||||
|
flat in vec2 startCoord;
|
||||||
|
flat in vec2 endCoord;
|
||||||
|
|
||||||
|
uniform vec2 start;
|
||||||
|
uniform vec2 size;
|
||||||
|
uniform float scale;
|
||||||
|
uniform vec2 effectLength;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 distanceToBorder = min(gl_FragCoord.xy - startCoord, endCoord - gl_FragCoord.xy)/effectLength/scale;
|
||||||
|
float reducedDistance = distanceToBorder.x*distanceToBorder.y/(distanceToBorder.x + distanceToBorder.y); // Inspired by the reduced mass from physics, to give a sort of curvy look to the outline.
|
||||||
|
float opacity = max(1 - reducedDistance, 0);
|
||||||
|
frag_color = fColor*vec4(1, 1, 1, opacity);
|
||||||
|
}
|
30
assets/cubyz/shaders/ui/window_border.vs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#version 330 core
|
||||||
|
|
||||||
|
layout (location=0) in vec2 vertex_pos;
|
||||||
|
|
||||||
|
flat out vec2 startCoord;
|
||||||
|
flat out vec2 endCoord;
|
||||||
|
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 - size.y;
|
||||||
|
endCoord.x = start.x + size.x;
|
||||||
|
endCoord.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;
|
||||||
|
}
|
Before Width: | Height: | Size: 588 B After Width: | Height: | Size: 675 B |
Before Width: | Height: | Size: 696 B After Width: | Height: | Size: 605 B |
Before Width: | Height: | Size: 696 B After Width: | Height: | Size: 602 B |
Before Width: | Height: | Size: 696 B After Width: | Height: | Size: 603 B |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.5 KiB |
@ -95,11 +95,22 @@ var windowUniforms: struct {
|
|||||||
image: c_int,
|
image: c_int,
|
||||||
randomOffset: c_int,
|
randomOffset: c_int,
|
||||||
} = undefined;
|
} = undefined;
|
||||||
|
pub var borderShader: Shader = undefined;
|
||||||
|
pub var borderUniforms: struct {
|
||||||
|
screen: c_int,
|
||||||
|
start: c_int,
|
||||||
|
size: c_int,
|
||||||
|
color: c_int,
|
||||||
|
scale: c_int,
|
||||||
|
effectLength: c_int,
|
||||||
|
} = undefined;
|
||||||
|
|
||||||
pub fn __init() !void {
|
pub fn __init() !void {
|
||||||
shader = try Shader.initAndGetUniforms("assets/cubyz/shaders/ui/button.vs", "assets/cubyz/shaders/ui/button.fs", &windowUniforms);
|
shader = try Shader.initAndGetUniforms("assets/cubyz/shaders/ui/button.vs", "assets/cubyz/shaders/ui/button.fs", &windowUniforms);
|
||||||
shader.bind();
|
shader.bind();
|
||||||
graphics.c.glUniform1i(windowUniforms.image, 0);
|
graphics.c.glUniform1i(windowUniforms.image, 0);
|
||||||
|
borderShader = try Shader.initAndGetUniforms("assets/cubyz/shaders/ui/window_border.vs", "assets/cubyz/shaders/ui/window_border.fs", &borderUniforms);
|
||||||
|
borderShader.bind();
|
||||||
|
|
||||||
backgroundTexture = try Texture.initFromFile("assets/cubyz/ui/window_background.png");
|
backgroundTexture = try Texture.initFromFile("assets/cubyz/ui/window_background.png");
|
||||||
titleTexture = try Texture.initFromFile("assets/cubyz/ui/window_title.png");
|
titleTexture = try Texture.initFromFile("assets/cubyz/ui/window_title.png");
|
||||||
@ -473,9 +484,15 @@ pub fn render(self: *const GuiWindow, mousePosition: Vec2f) !void {
|
|||||||
expandTitleBarTexture.render(.{0, 0}, .{16, 16});
|
expandTitleBarTexture.render(.{0, 0}, .{16, 16});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(self.hasBackground or (!main.Window.grabbed and self.titleBarExpanded)) {
|
||||||
|
draw.setColor(0x80000000);
|
||||||
|
borderShader.bind();
|
||||||
|
graphics.c.glUniform2f(borderUniforms.effectLength, 2.5, 2.5);
|
||||||
|
draw.customShadedRect(borderUniforms, .{0, 0}, self.size/@splat(2, self.scale));
|
||||||
|
}
|
||||||
draw.restoreTranslation(oldTranslation);
|
draw.restoreTranslation(oldTranslation);
|
||||||
draw.restoreScale(oldScale);
|
draw.restoreScale(oldScale);
|
||||||
if(self.showTitleBar) {
|
if(self.showTitleBar and false) { // TODO: Figure out whether I should even draw titlebar text.
|
||||||
var text = try graphics.TextBuffer.init(gui.allocator, self.title, .{.color=0}, false, .center);
|
var text = try graphics.TextBuffer.init(gui.allocator, self.title, .{.color=0}, false, .center);
|
||||||
defer text.deinit();
|
defer text.deinit();
|
||||||
const titleDimension = try text.calculateLineBreaks(16*self.scale, self.size[0]);
|
const titleDimension = try text.calculateLineBreaks(16*self.scale, self.size[0]);
|
||||||
|
@ -66,8 +66,8 @@ pub fn initText(pos: Vec2f, width: f32, text: []const u8, onAction: ?*const fn()
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initIcon(pos: Vec2f, iconSize: Vec2f, iconTexture: Texture, onAction: ?*const fn() void) Allocator.Error!*Button {
|
pub fn initIcon(pos: Vec2f, iconSize: Vec2f, iconTexture: Texture, hasShadow: bool, onAction: ?*const fn() void) Allocator.Error!*Button {
|
||||||
const icon = try Icon.init(undefined, iconSize, iconTexture);
|
const icon = try Icon.init(undefined, iconSize, iconTexture, hasShadow);
|
||||||
const self = try gui.allocator.create(Button);
|
const self = try gui.allocator.create(Button);
|
||||||
self.* = Button {
|
self.* = Button {
|
||||||
.pos = pos,
|
.pos = pos,
|
||||||
|
@ -19,7 +19,7 @@ var texture: Texture = undefined;
|
|||||||
const border: f32 = 3;
|
const border: f32 = 3;
|
||||||
|
|
||||||
pos: Vec2f,
|
pos: Vec2f,
|
||||||
size: Vec2f = .{32 + 2*border, 32 + 2*border},
|
size: Vec2f = .{24 + 2*border, 24 + 2*border},
|
||||||
itemStack: ItemStack,
|
itemStack: ItemStack,
|
||||||
text: TextBuffer,
|
text: TextBuffer,
|
||||||
textSize: Vec2f = .{0, 0},
|
textSize: Vec2f = .{0, 0},
|
||||||
@ -94,6 +94,9 @@ pub fn render(self: *CraftingResultSlot, _: Vec2f) !void {
|
|||||||
if(self.itemStack.item) |item| {
|
if(self.itemStack.item) |item| {
|
||||||
const itemTexture = try item.getTexture();
|
const itemTexture = try item.getTexture();
|
||||||
itemTexture.bindTo(0);
|
itemTexture.bindTo(0);
|
||||||
|
draw.setColor(0xff000000);
|
||||||
|
draw.boundImage(self.pos + @splat(2, border) + Vec2f{1.0, 1.0}, self.size - @splat(2, 2*border));
|
||||||
|
draw.setColor(0xffffffff);
|
||||||
draw.boundImage(self.pos + @splat(2, border), self.size - @splat(2, 2*border));
|
draw.boundImage(self.pos + @splat(2, border), self.size - @splat(2, 2*border));
|
||||||
if(self.itemStack.amount != 1) {
|
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);
|
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);
|
||||||
|
@ -18,13 +18,15 @@ const fontSize: f32 = 16;
|
|||||||
pos: Vec2f,
|
pos: Vec2f,
|
||||||
size: Vec2f,
|
size: Vec2f,
|
||||||
texture: Texture,
|
texture: Texture,
|
||||||
|
hasShadow: bool,
|
||||||
|
|
||||||
pub fn init(pos: Vec2f, size: Vec2f, texture: Texture) Allocator.Error!*Icon {
|
pub fn init(pos: Vec2f, size: Vec2f, texture: Texture, hasShadow: bool) Allocator.Error!*Icon {
|
||||||
const self = try gui.allocator.create(Icon);
|
const self = try gui.allocator.create(Icon);
|
||||||
self.* = Icon {
|
self.* = Icon {
|
||||||
.texture = texture,
|
.texture = texture,
|
||||||
.pos = pos,
|
.pos = pos,
|
||||||
.size = size,
|
.size = size,
|
||||||
|
.hasShadow = hasShadow,
|
||||||
};
|
};
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -44,6 +46,10 @@ pub fn updateTexture(self: *Icon, newTexture: Texture) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(self: *Icon, _: Vec2f) !void {
|
pub fn render(self: *Icon, _: Vec2f) !void {
|
||||||
|
if(self.hasShadow) {
|
||||||
|
draw.setColor(0xff000000);
|
||||||
|
self.texture.render(self.pos + Vec2f{1, 1}, self.size);
|
||||||
|
}
|
||||||
draw.setColor(0xffffffff);
|
draw.setColor(0xffffffff);
|
||||||
self.texture.render(self.pos, self.size);
|
self.texture.render(self.pos, self.size);
|
||||||
}
|
}
|
@ -19,7 +19,7 @@ var texture: Texture = undefined;
|
|||||||
const border: f32 = 3;
|
const border: f32 = 3;
|
||||||
|
|
||||||
pos: Vec2f,
|
pos: Vec2f,
|
||||||
size: Vec2f = .{32 + 2*border, 32 + 2*border},
|
size: Vec2f = .{24 + 2*border, 24 + 2*border},
|
||||||
item: *BaseItem,
|
item: *BaseItem,
|
||||||
amount: u32,
|
amount: u32,
|
||||||
text: TextBuffer,
|
text: TextBuffer,
|
||||||
@ -63,6 +63,9 @@ pub fn render(self: *ImmutableItemSlot, _: Vec2f) !void {
|
|||||||
draw.boundImage(self.pos, self.size);
|
draw.boundImage(self.pos, self.size);
|
||||||
const itemTexture = try self.item.getTexture();
|
const itemTexture = try self.item.getTexture();
|
||||||
itemTexture.bindTo(0);
|
itemTexture.bindTo(0);
|
||||||
|
draw.setColor(0xff000000);
|
||||||
|
draw.boundImage(self.pos + @splat(2, border) + Vec2f{1.0, 1.0}, self.size - @splat(2, 2*border));
|
||||||
|
draw.setColor(0xffffffff);
|
||||||
draw.boundImage(self.pos + @splat(2, border), self.size - @splat(2, 2*border));
|
draw.boundImage(self.pos + @splat(2, border), self.size - @splat(2, 2*border));
|
||||||
if(self.amount != 1) {
|
if(self.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);
|
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);
|
||||||
|
@ -16,10 +16,10 @@ const GuiComponent = gui.GuiComponent;
|
|||||||
const ItemSlot = @This();
|
const ItemSlot = @This();
|
||||||
|
|
||||||
var texture: Texture = undefined;
|
var texture: Texture = undefined;
|
||||||
const border: f32 = 3;
|
const border: f32 = 2;
|
||||||
|
|
||||||
pos: Vec2f,
|
pos: Vec2f,
|
||||||
size: Vec2f = .{32 + 2*border, 32 + 2*border},
|
size: Vec2f = .{24 + 2*border, 24 + 2*border},
|
||||||
itemStack: *ItemStack,
|
itemStack: *ItemStack,
|
||||||
oldStack: ItemStack,
|
oldStack: ItemStack,
|
||||||
text: TextBuffer,
|
text: TextBuffer,
|
||||||
@ -105,6 +105,9 @@ pub fn render(self: *ItemSlot, _: Vec2f) !void {
|
|||||||
if(self.itemStack.item) |item| {
|
if(self.itemStack.item) |item| {
|
||||||
const itemTexture = try item.getTexture();
|
const itemTexture = try item.getTexture();
|
||||||
itemTexture.bindTo(0);
|
itemTexture.bindTo(0);
|
||||||
|
draw.setColor(0xff000000);
|
||||||
|
draw.boundImage(self.pos + @splat(2, border) + Vec2f{1.0, 1.0}, self.size - @splat(2, 2*border));
|
||||||
|
draw.setColor(0xffffffff);
|
||||||
draw.boundImage(self.pos + @splat(2, border), self.size - @splat(2, 2*border));
|
draw.boundImage(self.pos + @splat(2, border), self.size - @splat(2, 2*border));
|
||||||
if(self.itemStack.amount != 1) {
|
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);
|
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);
|
||||||
|
@ -458,6 +458,12 @@ pub fn updateAndRenderGui() !void {
|
|||||||
for(openWindows.items) |window| {
|
for(openWindows.items) |window| {
|
||||||
try window.update();
|
try window.update();
|
||||||
}
|
}
|
||||||
|
if(!main.Window.grabbed) {
|
||||||
|
draw.setColor(0x80000000);
|
||||||
|
GuiWindow.borderShader.bind();
|
||||||
|
graphics.c.glUniform2f(GuiWindow.borderUniforms.effectLength, main.Window.getWindowSize()[0]/6, main.Window.getWindowSize()[1]/6);
|
||||||
|
draw.customShadedRect(GuiWindow.borderUniforms, .{0, 0}, main.Window.getWindowSize());
|
||||||
|
}
|
||||||
const oldScale = draw.setScale(scale);
|
const oldScale = draw.setScale(scale);
|
||||||
defer draw.restoreScale(oldScale);
|
defer draw.restoreScale(oldScale);
|
||||||
for(openWindows.items) |window| {
|
for(openWindows.items) |window| {
|
||||||
|
@ -33,7 +33,7 @@ pub fn onOpen() Allocator.Error!void {
|
|||||||
try items.append(Item{.baseItem = item.*});
|
try items.append(Item{.baseItem = item.*});
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = try VerticalList.init(.{padding, padding + 16}, 150, 0);
|
var list = try VerticalList.init(.{padding, padding + 16}, 140, 0);
|
||||||
var i: u32 = 0;
|
var i: u32 = 0;
|
||||||
while(i < items.items.len) {
|
while(i < items.items.len) {
|
||||||
var row = try HorizontalList.init();
|
var row = try HorizontalList.init();
|
||||||
|
@ -38,7 +38,7 @@ pub fn onOpen() Allocator.Error!void {
|
|||||||
// TODO: armor slots, backpack slot + stack-based backpack inventory, other items maybe?
|
// TODO: armor slots, backpack slot + stack-based backpack inventory, other items maybe?
|
||||||
{
|
{
|
||||||
var row = try HorizontalList.init();
|
var row = try HorizontalList.init();
|
||||||
try row.add(try Button.initIcon(.{0, 0}, .{32, 32}, craftingIcon, gui.openWindowFunction("cubyz:inventory_crafting"))); // TODO: Replace the text with an icon
|
try row.add(try Button.initIcon(.{0, 0}, .{24, 24}, craftingIcon, true, gui.openWindowFunction("cubyz:inventory_crafting"))); // TODO: Replace the text with an icon
|
||||||
try list.add(row);
|
try list.add(row);
|
||||||
}
|
}
|
||||||
// Inventory:
|
// Inventory:
|
||||||
|
@ -128,7 +128,7 @@ fn findAvailableRecipes(list: *VerticalList) Allocator.Error!bool {
|
|||||||
columnList.finish(.center);
|
columnList.finish(.center);
|
||||||
try rowList.add(columnList);
|
try rowList.add(columnList);
|
||||||
}
|
}
|
||||||
try rowList.add(try Icon.init(.{8, 0}, .{32, 32}, arrowTexture));
|
try rowList.add(try Icon.init(.{8, 0}, .{32, 32}, arrowTexture, false));
|
||||||
const itemSlot = try CraftingResultSlot.init(.{8, 0}, recipe.resultItem, &onTake, recipeIndex);
|
const itemSlot = try CraftingResultSlot.init(.{8, 0}, recipe.resultItem, &onTake, recipeIndex);
|
||||||
try rowList.add(itemSlot);
|
try rowList.add(itemSlot);
|
||||||
rowList.finish(.{0, 0}, .center);
|
rowList.finish(.{0, 0}, .center);
|
||||||
|
@ -100,7 +100,7 @@ pub fn onOpen() Allocator.Error!void {
|
|||||||
grid.finish(.center);
|
grid.finish(.center);
|
||||||
try list.add(grid);
|
try list.add(grid);
|
||||||
}
|
}
|
||||||
try list.add(try Icon.init(.{8, 0}, .{32, 32}, inventory_crafting.arrowTexture));
|
try list.add(try Icon.init(.{8, 0}, .{32, 32}, inventory_crafting.arrowTexture, false));
|
||||||
craftingResult = try CraftingResultSlot.init(.{8, 0}, .{}, &onTake, 0);
|
craftingResult = try CraftingResultSlot.init(.{8, 0}, .{}, &onTake, 0);
|
||||||
try list.add(craftingResult);
|
try list.add(craftingResult);
|
||||||
list.finish(.{padding, padding + 16}, .center);
|
list.finish(.{padding, padding + 16}, .center);
|
||||||
|