Interrupt / Interrupt/delve-framework

Positioning of text for font rendering with `addStringToSpriteBatch` and `addStringToSpriteBatchWithKerning` does not behave as expected

Open
#61 4 comments 0 reactions 0 assignees View on GitHub
Dominant language
Zig
Stars
338
Forks
17
PR merge metrics
No merged PRs in 30d

Description

Hi @Interrupt ,

recently I tried to use the builtin `addStringToSpriteBatch` and `addStringToSpriteBatchWithKerning` functions to render text to a 2D surface.
However, positioning the text seems to not work as it does for regular shapes or textures (for instance with `Batcher.addRectangle`).

In the following example I positioned both – a red rectangle and the text – at X: 50 and Y: 50 (using a math grid, meaning Y grows up and X grows to the right).
The result looks as follows:
![Bildschirmfoto vom 2024-10-10 16-39-34](https://github.com/user-attachments/assets/fedce0cc-774f-4d4e-9491-88297aa27e4b)

One can clearly see that the text is in a completely different position than the rectangle. I would have expected to be below the left-bottom corner of the rectangle.

```zig
const std = @import("std");
const delve = @import("delve");
const app = delve.app;

const debug = delve.debug;
const graphics = delve.platform.graphics;
const colors = delve.colors;
const input = delve.platform.input;
const math = delve.math;
const modules = delve.modules;

var gpa = std.heap.GeneralPurposeAllocator(.{}){};
var font_batch: delve.graphics.batcher.SpriteBatcher = undefined;
var batch: delve.graphics.batcher.Batcher = undefined;
var shader_blend: graphics.Shader = undefined;
const font_name = "DroidSans";

pub fn main() !void {
try delve.init(std.heap.c_allocator);
try registerModule();
try app.start(app.AppConfig{ .title = "Delve Framework - 2D Fonts Example" });
}

pub fn registerModule() !void {
const fontsExample = modules.Module{
.name = "fonts_example",
.init_fn = on_init,
.tick_fn = on_tick,
.pre_draw_fn = on_pre_draw,
.draw_fn = on_draw,
.cleanup_fn = on_cleanup,
};

try modules.registerModule(fontsExample);
}

pub fn getCamera2d() graphics.CameraMatrices {
return graphics.CameraMatrices{
.view = math.Mat4.lookat(
.{ .x = 0, .y = 0, .z = 1 },
math.Vec3.zero,
math.Vec3.up,
),
.proj = graphics.getProjectionOrtho(-1, 1, false),
};
}

fn on_init() !void {
debug.log("2D Fonts example module initializing", .{});
graphics.setClearColor(colors.examples_bg_dark);

font_batch = delve.graphics.batcher.SpriteBatcher.init(.{}) catch {
debug.log("Error creating font sprite batch!", .{});
return;
};

batch = delve.graphics.batcher.Batcher.init(.{}) catch {
debug.log("Error creating shape batch!", .{});
return;
};

_ = try delve.fonts.loadFont(font_name, "assets/fonts/" ++ font_name ++ ".ttf", 1024, 200);

// make a shader with alpha blending
shader_blend = try graphics.Shader.initDefault(.{ .blend_mode = graphics.BlendMode.BLEND });
}

fn on_tick(_: f32) void {
if (input.isKeyJustPressed(.ESCAPE))
delve.platform.app.exit();
}

fn on_pre_draw() void {
const text_scale: f32 = 0.25;

// Drawing position of characters, updated as each gets added
var x_pos: f32 = 50.0;
var y_pos: f32 = 50.0;

const message = "This is some text!\nHello World!\n[]'.@%#$<>?;:-=_+'";

const font_name_string = std.fmt.allocPrintZ(delve.mem.getAllocator(), "Drawing from {s}", .{font_name}) catch {
return;
};
defer delve.mem.getAllocator().free(font_name_string);

// Add font characters as sprites to our sprite batch
// Ideally you would only do this when the text updates, and just draw the batch until then
font_batch.reset();

font_batch.useShader(shader_blend);

if (delve.fonts.getLoadedFont(font_name)) |font| {
// give the header a bit of padding
const extra_header_line_height = font.font_size / 8;

delve.fonts.addStringToSpriteBatchWithKerning(font, &font_batch, font_name_string, &x_pos, &y_pos, extra_header_line_height, 0, text_scale, colors.blue);
delve.fonts.addStringToSpriteBatch(font, &font_batch, message, &x_pos, &y_pos, text_scale, colors.white);
}

font_batch.apply();

batch.reset();
const rect = delve.spatial.Rect.fromSize(math.vec2(100, 100)).setPosition(math.vec2(50, 50));
batch.addRectangle(rect, delve.graphics.sprites.TextureRegion.default(), delve.colors.red);
batch.apply();
}

fn on_draw() void {
const cam = getCamera2d();
batch.draw(cam, math.Mat4.identity);
font_batch.draw(cam, math.Mat4.identity);
}

fn on_cleanup() !void {
font_batch.deinit();
shader_blend.destroy();
}
```

You can run the example by putting in the `examples` directory of the repo. Maybe you can also temporarily overwrite the `fonts.zig` example and the run `zig build run-fonts`.

Thanks :)

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.