diff --git a/src/graphics.zig b/src/graphics.zig index ab274f44..feec1131 100644 --- a/src/graphics.zig +++ b/src/graphics.zig @@ -399,7 +399,8 @@ pub const TextBuffer = struct { y_advance: f32, x_offset: f32, y_offset: f32, - codepoint: u32, + character: u21, + index: u32, cluster: u32, fontEffect: FontEffect, characterIndex: u32, @@ -573,7 +574,8 @@ pub const TextBuffer = struct { glyph.y_advance = @intToFloat(f32, glyphPositions[i].y_advance)/4.0; glyph.x_offset = @intToFloat(f32, glyphPositions[i].x_offset)/4.0; glyph.y_offset = @intToFloat(f32, glyphPositions[i].y_offset)/4.0; - glyph.codepoint = glyphInfos[i].codepoint; + glyph.character = @intCast(u21, parser.parsedText.items[textIndexGuess[i]]); + glyph.index = glyphInfos[i].codepoint; glyph.cluster = glyphInfos[i].cluster; glyph.fontEffect = parser.fontEffects.items[textIndexGuess[i]]; glyph.characterIndex = parser.characterIndex.items[textIndexGuess[i]]; @@ -632,7 +634,7 @@ pub const TextBuffer = struct { } /// Returns the calculated dimensions of the text block. - pub fn calculateLineBreaks(self: *TextBuffer, fontSize: f32, maxLineWidth: f32) !Vec2f { // TODO: Support newlines. + pub fn calculateLineBreaks(self: *TextBuffer, fontSize: f32, maxLineWidth: f32) !Vec2f { self.lineBreakIndices.clearRetainingCapacity(); try self.lineBreakIndices.append(0); var scaledMaxWidth = maxLineWidth/fontSize*16.0; @@ -649,10 +651,17 @@ pub const TextBuffer = struct { lastSpaceIndex = 0; lastSpaceWidth = 0; } - if(glyph.codepoint == TextRendering.spaceIndex) { + if(glyph.character == ' ') { lastSpaceWidth = lineWidth; lastSpaceIndex = @intCast(u32, i+1); } + if(glyph.character == '\n') { + totalWidth = @max(totalWidth, lineWidth); + try self.lineBreakIndices.append(@intCast(u32, i+1)); + lineWidth = 0; + lastSpaceIndex = 0; + lastSpaceWidth = 0; + } } totalWidth = @max(totalWidth, lineWidth); try self.lineBreakIndices.append(@intCast(u32, self.glyphs.len)); @@ -714,7 +723,8 @@ pub const TextBuffer = struct { var i: usize = 0; while(i < self.lineBreakIndices.items.len - 1) : (i += 1) { for(self.glyphs[self.lineBreakIndices.items[i]..self.lineBreakIndices.items[i+1]]) |glyph| { - const ftGlyph = try TextRendering.getGlyph(glyph.codepoint); + if(glyph.character == '\n') continue; + const ftGlyph = try TextRendering.getGlyph(glyph.index); TextRendering.drawGlyph(ftGlyph, x + glyph.x_offset, y - glyph.y_offset, @bitCast(u28, glyph.fontEffect)); x += glyph.x_advance; @@ -776,7 +786,6 @@ const TextRendering = struct { var textureWidth: i32 = 1024; const textureHeight: i32 = 16; var textureOffset: i32 = 0; - var spaceIndex: u32 = undefined; fn init() !void { shader = try Shader.create("assets/cubyz/shaders/graphics/Text.vs", "assets/cubyz/shaders/graphics/Text.fs"); uniforms = shader.bulkGetUniformLocation(@TypeOf(uniforms)); @@ -805,7 +814,6 @@ const TextRendering = struct { c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_NEAREST); c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_S, c.GL_REPEAT); c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_T, c.GL_REPEAT); - spaceIndex = freetypeFace.getCharIndex(' ').?; } fn deinit() void { @@ -845,17 +853,17 @@ const TextRendering = struct { textureOffset += width; } - fn getGlyph(codepoint: u32) !Glyph { - if(codepoint >= glyphMapping.items.len) { - try glyphMapping.appendNTimes(0, codepoint - glyphMapping.items.len + 1); + fn getGlyph(index: u32) !Glyph { + if(index >= glyphMapping.items.len) { + try glyphMapping.appendNTimes(0, index - glyphMapping.items.len + 1); } - if(glyphMapping.items[codepoint] == 0) {// glyph was not initialized yet. - try freetypeFace.loadGlyph(codepoint, freetype.LoadFlags{.render = true}); + if(glyphMapping.items[index] == 0) {// glyph was not initialized yet. + try freetypeFace.loadGlyph(index, freetype.LoadFlags{.render = true}); const glyph = freetypeFace.glyph(); const bitmap = glyph.bitmap(); const width = bitmap.width(); const height = bitmap.rows(); - glyphMapping.items[codepoint] = @intCast(u31, glyphData.items.len); + glyphMapping.items[index] = @intCast(u31, glyphData.items.len); (try glyphData.addOne()).* = Glyph { .textureX = textureOffset, .size = Vec2i{@intCast(i32, width), @intCast(i32, height)}, @@ -864,7 +872,7 @@ const TextRendering = struct { }; try uploadData(bitmap); } - return glyphData.items[glyphMapping.items[codepoint]]; + return glyphData.items[glyphMapping.items[index]]; } fn drawGlyph(glyph: Glyph, x: f32, y: f32, fontEffects: u28) void { diff --git a/src/gui/components/TextInput.zig b/src/gui/components/TextInput.zig index d833f417..b053a57d 100644 --- a/src/gui/components/TextInput.zig +++ b/src/gui/components/TextInput.zig @@ -238,7 +238,7 @@ fn moveCursorToEnd(self: *TextInput, mods: main.Key.Modifiers) void { if(mods.control) { self.cursor.? = @intCast(u32, self.currentString.items.len); } else { - self.cursor.? = @intCast(u32, std.mem.indexOf(u8, self.currentString.items[self.cursor.?..], "\n") orelse self.currentString.items.len); + self.cursor.? += @intCast(u32, std.mem.indexOf(u8, self.currentString.items[self.cursor.?..], "\n") orelse self.currentString.items.len); } } @@ -345,6 +345,12 @@ pub fn cut(self: *TextInput, mods: main.Key.Modifiers) void { } } +pub fn newline(self: *TextInput, _: main.Key.Modifiers) void { + self.inputCharacter('\n') catch |err| { + std.log.err("Error while entering text: {s}", .{@errorName(err)}); + }; +} + pub fn render(self: *TextInput, pos: Vec2f, _: Vec2f, mousePosition: Vec2f) !void { try self.textBuffer.render(pos[0], pos[1], fontSize); if(self.pressed) { diff --git a/src/gui/gui.zig b/src/gui/gui.zig index cdc80b68..cfbd0e58 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -178,6 +178,11 @@ pub const textCallbacks = struct { current.cut(mods); } } + pub fn newline(mods: main.Key.Modifiers) void { + if(selectedTextInput) |current| { + current.newline(mods); + } + } }; pub fn mainButtonPressed() void { diff --git a/src/gui/windows/change_name.zig b/src/gui/windows/change_name.zig index 84dd841c..b0af10ee 100644 --- a/src/gui/windows/change_name.zig +++ b/src/gui/windows/change_name.zig @@ -30,7 +30,7 @@ const padding: f32 = 8; pub fn onOpen() Allocator.Error!void { var list = try VerticalList.init(main.globalAllocator); // TODO Please change your name bla bla - try list.add(try TextInput.init(main.globalAllocator, .{0, 16}, 128, "gr da jkwa hfeka fuei ofuiewo atg78o4ea74e8t z57 t4738qa0 47a80 t47803a t478aqv t487 5t478a0 tg478a09 t748ao t7489a rt4e5 okv5895 678v54vgvo6r z8or z578v rox74et8ys9otv 4z3789so z4oa9t z489saoyt z")); + try list.add(try TextInput.init(main.globalAllocator, .{0, 16}, 128, "gr da jkwa hfeka fuei \n ofuiewo\natg78o4ea74e8t\nz57 t4738qa0 47a80 t47803a t478aqv t487 5t478a0 tg478a09 t748ao t7489a rt4e5 okv5895 678v54vgvo6r z8or z578v rox74et8ys9otv 4z3789so z4oa9t z489saoyt z")); // TODO //try list.add(try Button.init(.{0, 16}, 128, main.globalAllocator, "Singleplayer TODO", &buttonCallbackTest)); //try list.add(try Button.init(.{0, 16}, 128, main.globalAllocator, "Multiplayer TODO", &buttonCallbackTest)); diff --git a/src/main.zig b/src/main.zig index 501f6204..df645a21 100644 --- a/src/main.zig +++ b/src/main.zig @@ -185,6 +185,7 @@ pub var keyboard: struct { textCopy: Key = Key{.key = c.GLFW_KEY_C, .repeatAction = &gui.textCallbacks.copy}, textPaste: Key = Key{.key = c.GLFW_KEY_V, .repeatAction = &gui.textCallbacks.paste}, textCut: Key = Key{.key = c.GLFW_KEY_X, .repeatAction = &gui.textCallbacks.cut}, + textNewline: Key = Key{.key = c.GLFW_KEY_ENTER, .repeatAction = &gui.textCallbacks.newline}, } = .{}; pub const Window = struct {