fix graphics flickers
This commit is contained in:
parent
b827c759ba
commit
d91fd0f4dc
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<map version="1.10" tiledversion="1.12.2" orientation="orthogonal" renderorder="right-down" width="30" height="20" tilewidth="64" tileheight="64" infinite="0" nextlayerid="5" nextobjectid="1">
|
<map version="1.10" tiledversion="1.12.2" orientation="orthogonal" renderorder="right-down" width="30" height="20" tilewidth="64" tileheight="64" infinite="0" nextlayerid="6" nextobjectid="2">
|
||||||
<tileset firstgid="1" source="tileset.tsx"/>
|
<tileset firstgid="1" source="tileset.tsx"/>
|
||||||
<layer id="2" name="Ground" width="30" height="20">
|
<layer id="2" name="Ground" width="30" height="20">
|
||||||
<data encoding="csv">
|
<data encoding="csv">
|
||||||
@ -73,4 +73,9 @@
|
|||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
</data>
|
</data>
|
||||||
</layer>
|
</layer>
|
||||||
|
<objectgroup id="5" name="Markers">
|
||||||
|
<object id="1" name="spawn" x="479" y="550">
|
||||||
|
<point/>
|
||||||
|
</object>
|
||||||
|
</objectgroup>
|
||||||
</map>
|
</map>
|
||||||
|
|||||||
@ -1,17 +1,31 @@
|
|||||||
{
|
{
|
||||||
"activeFile": "",
|
"activeFile": "map.tmx",
|
||||||
"expandedProjectPaths": [
|
"expandedProjectPaths": [
|
||||||
],
|
],
|
||||||
|
"file.lastUsedOpenFilter": "All Files (*)",
|
||||||
"fileStates": {
|
"fileStates": {
|
||||||
|
"map.tmx": {
|
||||||
|
"scale": 1,
|
||||||
|
"selectedLayer": 3,
|
||||||
|
"viewCenter": {
|
||||||
|
"x": 624.5,
|
||||||
|
"y": 421
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tileset.tsx": {
|
||||||
|
"scaleInDock": 1
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"last.imagePath": "/home/rokas/code/games/sokol-template-v2/assets/sokoban",
|
"last.imagePath": "/home/rokas/code/games/sokol-template-v2/assets/sokoban",
|
||||||
"map.lastUsedFormat": "tmx",
|
"map.lastUsedFormat": "tmx",
|
||||||
"map.tileHeight": 64,
|
"map.tileHeight": 64,
|
||||||
"map.tileWidth": 64,
|
"map.tileWidth": 64,
|
||||||
"openFiles": [
|
"openFiles": [
|
||||||
|
"map.tmx"
|
||||||
],
|
],
|
||||||
"project": "sokoban.tiled-project",
|
"project": "sokoban.tiled-project",
|
||||||
"recentFiles": [
|
"recentFiles": [
|
||||||
|
"map.tmx"
|
||||||
],
|
],
|
||||||
"tileset.lastUsedFormat": "tsx",
|
"tileset.lastUsedFormat": "tsx",
|
||||||
"tileset.tileSize": {
|
"tileset.tileSize": {
|
||||||
|
|||||||
@ -98,7 +98,16 @@ pub const ObjectVariant = struct {
|
|||||||
|
|
||||||
color: ?Color,
|
color: ?Color,
|
||||||
draw_order: DrawOrder,
|
draw_order: DrawOrder,
|
||||||
items: []Object
|
items: []Object,
|
||||||
|
|
||||||
|
pub fn getByName(self: *const ObjectVariant, name: []const u8) ?*const Object {
|
||||||
|
for (self.items) |*item| {
|
||||||
|
if (std.mem.eql(u8, item.name, name)) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const GroupVariant = struct {
|
pub const GroupVariant = struct {
|
||||||
|
|||||||
@ -77,6 +77,14 @@ pub const Tile = struct {
|
|||||||
pub fn getProperties(self: Tile) Property.List {
|
pub fn getProperties(self: Tile) Property.List {
|
||||||
return self.tileset.getTileProperties(self.id) orelse .empty;
|
return self.tileset.getTileProperties(self.id) orelse .empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getPositionInImage(self: Tile) Position {
|
||||||
|
return self.tileset.getTilePositionInImage(self.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getPosition(self: Tile) Tileset.TilePosition {
|
||||||
|
return self.tileset.getTilePosition(self.id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
arena: std.heap.ArenaAllocator,
|
arena: std.heap.ArenaAllocator,
|
||||||
@ -230,6 +238,15 @@ pub fn getTile(self: *const Tilemap, layer: *const Layer, tilesets: Tileset.List
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getLayer(self: *const Tilemap, name: []const u8) ?*const Layer {
|
||||||
|
for (self.layers) |*layer| {
|
||||||
|
if (std.mem.eql(u8, layer.name, name)) {
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *const Tilemap) void {
|
pub fn deinit(self: *const Tilemap) void {
|
||||||
self.arena.deinit();
|
self.arena.deinit();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Io = std.Io;
|
const Io = std.Io;
|
||||||
|
const assert = std.debug.assert;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
const xml = @import("./xml.zig");
|
const xml = @import("./xml.zig");
|
||||||
@ -204,21 +205,32 @@ pub fn getTileProperties(self: *const Tileset, id: u32) ?Property.List {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getTilePositionInImage(self: *const Tileset, id: u32) ?Position {
|
pub const TilePosition = struct {
|
||||||
if (id >= self.tile_count) {
|
x: usize,
|
||||||
return null;
|
y: usize,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
pub fn getTilePosition(self: *const Tileset, id: u32) TilePosition {
|
||||||
|
assert(id < self.tile_count);
|
||||||
|
|
||||||
const tileset_width = @divExact(self.image.width, self.tile_width);
|
const tileset_width = @divExact(self.image.width, self.tile_width);
|
||||||
|
|
||||||
const tile_x = @mod(id, tileset_width);
|
const tile_x = @mod(id, tileset_width);
|
||||||
const tile_y = @divFloor(id, tileset_width);
|
const tile_y = @divFloor(id, tileset_width);
|
||||||
|
|
||||||
return Position{
|
return .{
|
||||||
.x = @floatFromInt(tile_x * self.tile_width),
|
.x = tile_x,
|
||||||
.y = @floatFromInt(tile_y * self.tile_height),
|
.y = tile_y,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getTilePositionInImage(self: *const Tileset, id: u32) Position {
|
||||||
|
const pos = self.getTilePosition(id);
|
||||||
|
|
||||||
|
return Position{
|
||||||
|
.x = @floatFromInt(pos.x * self.tile_width),
|
||||||
|
.y = @floatFromInt(pos.y * self.tile_height),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *const Tileset) void {
|
pub fn deinit(self: *const Tileset) void {
|
||||||
|
|||||||
195
src/app.zig
195
src/app.zig
@ -1,5 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const log = std.log.scoped(.app);
|
const log = std.log.scoped(.app);
|
||||||
|
const assert = std.debug.assert;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
const Math = @import("math");
|
const Math = @import("math");
|
||||||
@ -40,11 +41,46 @@ const PlayerSprites = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
show_first_window: bool,
|
const Tilemap = struct {
|
||||||
check: bool,
|
tiles: []Tile,
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
|
||||||
|
const Tile = struct {
|
||||||
|
ground_sprite: ?Gfx.Sprite.Id,
|
||||||
|
wall_sprite: ?Gfx.Sprite.Id,
|
||||||
|
|
||||||
|
const empty = Tile{
|
||||||
|
.ground_sprite = null,
|
||||||
|
.wall_sprite = null
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(gpa: Allocator, width: usize, height: usize) !Tilemap {
|
||||||
|
const tiles = try gpa.alloc(Tile, width * height);
|
||||||
|
@memset(tiles, .empty);
|
||||||
|
|
||||||
|
return Tilemap{
|
||||||
|
.width = width,
|
||||||
|
.height = height,
|
||||||
|
.tiles = tiles
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Tilemap, gpa: Allocator) void {
|
||||||
|
gpa.free(self.tiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: *Tilemap, x: usize, y: usize) *Tile {
|
||||||
|
assert(x < self.width);
|
||||||
|
assert(y < self.height);
|
||||||
|
return &self.tiles[y * self.width + x];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
player_pos: Vec2,
|
player_pos: Vec2,
|
||||||
wall_sprite: Gfx.Sprite.Id,
|
|
||||||
roboto_font: Gfx.Font.Id,
|
roboto_font: Gfx.Font.Id,
|
||||||
|
tilemap: Tilemap,
|
||||||
|
|
||||||
tilesheet: Tilesheet,
|
tilesheet: Tilesheet,
|
||||||
|
|
||||||
@ -65,7 +101,9 @@ const Tilesheet = struct {
|
|||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
|
|
||||||
pub fn init(gpa: Allocator, image: Gfx.ImageData, width: u32, height: u32, tile_size: Vec2) !Tilesheet {
|
pub fn init(gpa: Allocator, image: Gfx.ImageData, tile_width: u32, tile_height: u32) !Tilesheet {
|
||||||
|
const width = image.width / tile_width;
|
||||||
|
const height = image.height / tile_height;
|
||||||
const sprites = try gpa.alloc(Gfx.Sprite.Id, width * height);
|
const sprites = try gpa.alloc(Gfx.Sprite.Id, width * height);
|
||||||
errdefer gpa.free(sprites);
|
errdefer gpa.free(sprites);
|
||||||
@memset(sprites, .nil);
|
@memset(sprites, .nil);
|
||||||
@ -75,7 +113,7 @@ const Tilesheet = struct {
|
|||||||
.image = image,
|
.image = image,
|
||||||
.width = width,
|
.width = width,
|
||||||
.height = height,
|
.height = height,
|
||||||
.tile_size = tile_size
|
.tile_size = .initFromInt(u32, tile_width, tile_height)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +123,7 @@ const Tilesheet = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(self: Tilesheet, x: u32, y: u32) Gfx.Sprite.Id {
|
pub fn get(self: Tilesheet, x: usize, y: usize) Gfx.Sprite.Id {
|
||||||
if (x >= self.width or y >= self.height) {
|
if (x >= self.width or y >= self.height) {
|
||||||
log.warn("Attempt to get tile which is out of bounds", .{});
|
log.warn("Attempt to get tile which is out of bounds", .{});
|
||||||
return .nil;
|
return .nil;
|
||||||
@ -109,24 +147,6 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
|||||||
const robot_font = Gfx.initFont();
|
const robot_font = Gfx.initFont();
|
||||||
Gfx.setFont(robot_font, plt.assets.readFile("roboto-font/Roboto-Regular.ttf"));
|
Gfx.setFont(robot_font, plt.assets.readFile("roboto-font/Roboto-Regular.ttf"));
|
||||||
|
|
||||||
var scratch = std.heap.ArenaAllocator.init(plt.gpa);
|
|
||||||
defer scratch.deinit();
|
|
||||||
|
|
||||||
var buffers = Tiled.xml.Lexer.Buffers.init(plt.gpa);
|
|
||||||
defer buffers.deinit();
|
|
||||||
|
|
||||||
const tilemap = try Tiled.Tilemap.initFromBuffer(plt.gpa, &scratch, &buffers, plt.assets.readFile("tiled/map.tmx"));
|
|
||||||
defer tilemap.deinit();
|
|
||||||
|
|
||||||
var tilesets: Tiled.Tileset.List = .empty;
|
|
||||||
defer tilesets.deinit(plt.gpa);
|
|
||||||
|
|
||||||
try tilesets.add(plt.gpa, "tiled/tilemap.tsx", try Tiled.Tileset.initFromBuffer(plt.gpa, &scratch, &buffers, plt.assets.readFile("tiled/tileset.tsx")));
|
|
||||||
|
|
||||||
for (tilemap.layers) |layer| {
|
|
||||||
std.debug.print("{s}\n", .{layer.name});
|
|
||||||
}
|
|
||||||
|
|
||||||
const tilesheet_png = try STBImage.load(plt.assets.readFile("sokoban/sokoban_tilesheet.png"));
|
const tilesheet_png = try STBImage.load(plt.assets.readFile("sokoban/sokoban_tilesheet.png"));
|
||||||
const tilesheet = try Tilesheet.init(
|
const tilesheet = try Tilesheet.init(
|
||||||
plt.arena,
|
plt.arena,
|
||||||
@ -135,13 +155,9 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
|||||||
.height = tilesheet_png.height,
|
.height = tilesheet_png.height,
|
||||||
.pixels = .{ .rgba8 = tilesheet_png.rgba8_pixels }
|
.pixels = .{ .rgba8 = tilesheet_png.rgba8_pixels }
|
||||||
},
|
},
|
||||||
13,
|
64, 64,
|
||||||
8,
|
|
||||||
.init(64, 64)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const wall_sprite = tilesheet.get(1, 0);
|
|
||||||
|
|
||||||
var player_sprites: PlayerSprites = undefined;
|
var player_sprites: PlayerSprites = undefined;
|
||||||
inline for (.{
|
inline for (.{
|
||||||
.{
|
.{
|
||||||
@ -172,43 +188,114 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
|||||||
});
|
});
|
||||||
|
|
||||||
self.* = App{
|
self.* = App{
|
||||||
.player_pos = .init(100, 100),
|
.player_pos = .init(0, 0),
|
||||||
.show_first_window = true,
|
|
||||||
.check = false,
|
|
||||||
.player_sprites = player_sprites,
|
.player_sprites = player_sprites,
|
||||||
.wall_sprite = wall_sprite,
|
|
||||||
.roboto_font = robot_font,
|
.roboto_font = robot_font,
|
||||||
.player_direction = .left,
|
.player_direction = .left,
|
||||||
.player_frame_index = 0,
|
.player_frame_index = 0,
|
||||||
.animation_timer = 0,
|
.animation_timer = 0,
|
||||||
.tilesheet = tilesheet,
|
.tilesheet = tilesheet,
|
||||||
.footstep_buffer = footstep_sound,
|
.footstep_buffer = footstep_sound,
|
||||||
.sfx_bus = Audio.addBus(.{ .label = "sfx" })
|
.sfx_bus = Audio.addBus(.{ .label = "sfx" }),
|
||||||
|
.tilemap = try Tilemap.init(plt.gpa, 30, 20)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
var scratch = std.heap.ArenaAllocator.init(plt.gpa);
|
||||||
|
defer scratch.deinit();
|
||||||
|
|
||||||
|
var buffers = Tiled.xml.Lexer.Buffers.init(plt.gpa);
|
||||||
|
defer buffers.deinit();
|
||||||
|
|
||||||
|
const tilemap = try Tiled.Tilemap.initFromBuffer(plt.gpa, &scratch, &buffers, plt.assets.readFile("tiled/map.tmx"));
|
||||||
|
defer tilemap.deinit();
|
||||||
|
|
||||||
|
var tilesets: Tiled.Tileset.List = .empty;
|
||||||
|
defer tilesets.deinit(plt.gpa);
|
||||||
|
|
||||||
|
try tilesets.add(plt.gpa, "tileset.tsx", try Tiled.Tileset.initFromBuffer(plt.gpa, &scratch, &buffers, plt.assets.readFile("tiled/tileset.tsx")));
|
||||||
|
|
||||||
|
const ground = tilemap.getLayer("Ground").?;
|
||||||
|
const walls = tilemap.getLayer("Walls").?;
|
||||||
|
for (0..tilemap.height) |y| {
|
||||||
|
for (0..tilemap.width) |x| {
|
||||||
|
const tile = self.tilemap.get(x, y);
|
||||||
|
|
||||||
|
if (tilemap.getTile(ground, tilesets, x, y)) |tiled_tile| {
|
||||||
|
const pos = tiled_tile.getPosition();
|
||||||
|
tile.ground_sprite = tilesheet.get(pos.x, pos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tilemap.getTile(walls, tilesets, x, y)) |tiled_tile| {
|
||||||
|
const pos = tiled_tile.getPosition();
|
||||||
|
tile.wall_sprite = tilesheet.get(pos.x, pos.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const markers = &tilemap.getLayer("Markers").?.variant.object;
|
||||||
|
const spawn = markers.getByName("spawn").?;
|
||||||
|
self.player_pos.x = @divFloor(spawn.shape.point.x, @as(f32, @floatFromInt(tilemap.tile_width)));
|
||||||
|
self.player_pos.y = @divFloor(spawn.shape.point.y, @as(f32, @floatFromInt(tilemap.tile_height)));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var min_x: usize = self.tilemap.width;
|
||||||
|
var max_x: usize = 0;
|
||||||
|
var min_y: usize = self.tilemap.height;
|
||||||
|
var max_y: usize = 0;
|
||||||
|
for (0..self.tilemap.height) |y| {
|
||||||
|
for (0..self.tilemap.width) |x| {
|
||||||
|
const tile = self.tilemap.get(x, y);
|
||||||
|
if (tile.ground_sprite != null or tile.wall_sprite != null) {
|
||||||
|
min_x = @min(min_x, x);
|
||||||
|
min_y = @min(min_y, y);
|
||||||
|
max_x = @max(max_x, x);
|
||||||
|
max_y = @max(max_y, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const map_width = max_x - min_x + 1;
|
||||||
|
const map_height = max_y - min_y + 1;
|
||||||
|
|
||||||
|
var new_tilemap = try Tilemap.init(plt.gpa, map_width, map_height);
|
||||||
|
for (0..map_height) |y| {
|
||||||
|
for (0..map_width) |x| {
|
||||||
|
new_tilemap.get(x, y).* = self.tilemap.get(min_x + x, min_y + y).*;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tilemap.deinit(plt.gpa);
|
||||||
|
self.tilemap = new_tilemap;
|
||||||
|
|
||||||
|
self.player_pos.x -= @floatFromInt(min_x);
|
||||||
|
self.player_pos.y -= @floatFromInt(min_y);
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame(self: *App, plt: Platform.Frame) !void {
|
pub fn frame(self: *App, plt: Platform.Frame) !void {
|
||||||
const input = plt.input;
|
const input = plt.input;
|
||||||
|
|
||||||
const dt = plt.deltaTime();
|
|
||||||
|
|
||||||
var dir: Vec2 = .init(0, 0);
|
var dir: Vec2 = .init(0, 0);
|
||||||
if (input.isKeyDown(.S)) {
|
if (input.isKeyPressed(.S)) {
|
||||||
dir.y += 1;
|
dir.y += 1;
|
||||||
}
|
}
|
||||||
if (input.isKeyDown(.W)) {
|
if (input.isKeyPressed(.W)) {
|
||||||
dir.y -= 1;
|
dir.y -= 1;
|
||||||
}
|
}
|
||||||
if (input.isKeyDown(.D)) {
|
if (input.isKeyPressed(.D)) {
|
||||||
dir.x += 1;
|
dir.x += 1;
|
||||||
}
|
}
|
||||||
if (input.isKeyDown(.A)) {
|
if (input.isKeyPressed(.A)) {
|
||||||
dir.x -= 1;
|
dir.x -= 1;
|
||||||
}
|
}
|
||||||
dir = dir.normalized();
|
if (dir.x != 0) {
|
||||||
self.player_pos = self.player_pos.add(dir.multiplyScalar(50 * dt));
|
dir.y = 0;
|
||||||
|
}
|
||||||
|
self.player_pos = self.player_pos.add(dir);
|
||||||
|
|
||||||
if (input.isKeyPressed(.F)) {
|
if (input.isKeyPressed(.F)) {
|
||||||
Audio.stop(self.footstep_sound);
|
Audio.stop(self.footstep_sound);
|
||||||
@ -250,16 +337,30 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Gfx.setClearColor(.rgb(40, 40, 40));
|
Gfx.setClearColor(.rgb(40, 40, 40));
|
||||||
Gfx.drawSprite(frames[self.player_frame_index], self.player_pos, .init(64, 64), .white);
|
|
||||||
Gfx.drawSprite(self.tilesheet.get(11, 6), self.player_pos.add(.init(0, 200)), .init(64, 64), .white);
|
const tile_size = Vec2.init(48, 48);
|
||||||
|
for (0..self.tilemap.height) |y| {
|
||||||
|
for (0..self.tilemap.width) |x| {
|
||||||
|
const tile = self.tilemap.get(x, y);
|
||||||
|
|
||||||
|
if (tile.ground_sprite) |sprite| {
|
||||||
|
Gfx.drawSprite(sprite, Vec2.initFromInt(usize, x, y).multiply(tile_size), tile_size, .white);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tile.wall_sprite) |sprite| {
|
||||||
|
Gfx.drawSprite(sprite, Vec2.initFromInt(usize, x, y).multiply(tile_size), tile_size, .white);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx.drawSprite(frames[self.player_frame_index], self.player_pos.multiply(tile_size), tile_size, .white);
|
||||||
Gfx.drawText(self.roboto_font, .{
|
Gfx.drawText(self.roboto_font, .{
|
||||||
.pos = .init(300, 100),
|
.pos = .init(300, 100),
|
||||||
.text = "Hello, World!",
|
.text = try std.fmt.allocPrint(plt.frame, "Hello, World! {:.0}", .{ plt.time() }),
|
||||||
.height = 64,
|
.height = 64,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *App, plt: Platform.Deinit) void {
|
pub fn deinit(self: *App, plt: Platform.Deinit) void {
|
||||||
_ = plt; // autofix
|
self.tilemap.deinit(plt.gpa);
|
||||||
_ = self; // autofix
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -171,12 +171,6 @@ pub fn init(io: Io, gpa: std.mem.Allocator, opts: InitOptions) !void {
|
|||||||
@memset(self.thread_state.elapsed_time_ms.?, 0);
|
@memset(self.thread_state.elapsed_time_ms.?, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("Init:", .{});
|
|
||||||
log.debug("- sample_rate: {}", .{saudio.sampleRate()});
|
|
||||||
log.debug("- channels: {}", .{saudio.channels()});
|
|
||||||
log.debug("- buffer_frames: {}", .{saudio.bufferFrames()});
|
|
||||||
log.debug("- max callback duration: {f}", .{getMaxAudioThreadDuration()});
|
|
||||||
|
|
||||||
self.running.store(true, .seq_cst);
|
self.running.store(true, .seq_cst);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,7 +370,7 @@ fn busMultipliedVolume(id: BusId) f32 {
|
|||||||
|
|
||||||
const PlayOptions = struct {
|
const PlayOptions = struct {
|
||||||
buffer: BufferId,
|
buffer: BufferId,
|
||||||
// TODO: adsr: ?ADSR = null,
|
// TODO: adsr: ?Sound.ADSR = null,
|
||||||
volume: f32 = 1,
|
volume: f32 = 1,
|
||||||
loop: bool = false,
|
loop: bool = false,
|
||||||
bus: ?BusId = null
|
bus: ?BusId = null
|
||||||
@ -458,6 +452,11 @@ pub fn showDebug() void {
|
|||||||
if (ImGUI.beginTabItem("General")) {
|
if (ImGUI.beginTabItem("General")) {
|
||||||
defer ImGUI.endTabItem();
|
defer ImGUI.endTabItem();
|
||||||
|
|
||||||
|
ImGUI.text("Sample rate: {}Hz", .{saudio.sampleRate()});
|
||||||
|
ImGUI.text("Buffer frames: {}", .{saudio.bufferFrames()});
|
||||||
|
ImGUI.text("Max callback duration: {f}", .{getMaxAudioThreadDuration()});
|
||||||
|
|
||||||
|
ImGUI.separator();
|
||||||
ImGUI.text("Buffers: {}/{}", .{buffers.items.len, buffers.capacity});
|
ImGUI.text("Buffers: {}/{}", .{buffers.items.len, buffers.capacity});
|
||||||
ImGUI.text("Buses: {}/{}", .{buses.items.len, buses.capacity});
|
ImGUI.text("Buses: {}/{}", .{buses.items.len, buses.capacity});
|
||||||
ImGUI.text("Sounds: {}/{}", .{sounds.count(), sounds.slots.capacity});
|
ImGUI.text("Sounds: {}/{}", .{sounds.count(), sounds.slots.capacity});
|
||||||
|
|||||||
@ -233,9 +233,6 @@ pub fn init(gpa: std.mem.Allocator, logger: sg.Logger) !void {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
repackSpritesheetIfNeeded(self.default_spritesheet);
|
|
||||||
rebuildSpritesheetTextureIfNeeded(self.default_spritesheet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit() void {
|
pub fn deinit() void {
|
||||||
@ -347,45 +344,35 @@ pub fn beginFrame() void {
|
|||||||
.swapchain = sglue.swapchain()
|
.swapchain = sglue.swapchain()
|
||||||
});
|
});
|
||||||
|
|
||||||
const default_spritesheet = self.spritesheets.getAssumeExists(self.default_spritesheet);
|
self.bindings.views[shd.VIEW_tex].id = sg.invalid_id;
|
||||||
const spritesheet_texture = self.textures.getAssumeExists(default_spritesheet.texture);
|
|
||||||
self.bindings.views[shd.VIEW_tex] = spritesheet_texture.view;
|
|
||||||
self.bindings.samplers[shd.SMP_smp] = self.linear_sampler;
|
self.bindings.samplers[shd.SMP_smp] = self.linear_sampler;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn showDebug() void {
|
pub fn showDebug() void {
|
||||||
const self = &g_state;
|
const self = &g_state;
|
||||||
_ = self; // autofix
|
|
||||||
|
|
||||||
// TODO: Improve this by using tables or somekind of filtering
|
// TODO: Improve this by using tables or somekind of filtering
|
||||||
|
|
||||||
// if (ImGUI.beginWindow(.{
|
{
|
||||||
// .name = "graphics",
|
ImGUI.text("Spritesheets:", .{});
|
||||||
// .size = .init(200, 200)
|
var spritesheet_iter = self.spritesheets.iterator();
|
||||||
// })) {
|
while (spritesheet_iter.next()) |spritesheet_id| {
|
||||||
// defer ImGUI.endWindow();
|
const spritesheet = self.spritesheets.getAssumeExists(spritesheet_id);
|
||||||
//
|
ImGUI.text("{f}:", .{spritesheet_id});
|
||||||
// {
|
ImGUI.text(" - needs_texture_rebuild:{}", .{spritesheet.needs_texture_rebuild});
|
||||||
// ImGUI.text("Spritesheets:", .{});
|
ImGUI.text(" - texture:{f}", .{spritesheet.texture});
|
||||||
// var spritesheet_iter = self.spritesheets.iterator();
|
ImGUI.text(" - size:{}", .{spritesheet.size});
|
||||||
// while (spritesheet_iter.next()) |spritesheet_id| {
|
}
|
||||||
// const spritesheet = self.spritesheets.getAssumeExists(spritesheet_id);
|
}
|
||||||
// const texture = self.textures.get(spritesheet.texture);
|
|
||||||
// ImGUI.text("{f}:", .{spritesheet_id});
|
{
|
||||||
// ImGUI.text(" - needs_texture_rebuild:{}", .{spritesheet.needs_texture_rebuild});
|
ImGUI.text("Sprites:", .{});
|
||||||
// ImGUI.text(" - texture:{?}", .{texture});
|
var sprite_iter = self.sprites.iterator();
|
||||||
// }
|
while (sprite_iter.next()) |sprite_id| {
|
||||||
// }
|
const sprite = self.sprites.getAssumeExists(sprite_id);
|
||||||
//
|
ImGUI.text("{f} - {?}", .{sprite_id, sprite.position});
|
||||||
// {
|
}
|
||||||
// ImGUI.text("Sprites:", .{});
|
}
|
||||||
// var sprite_iter = self.sprites.iterator();
|
|
||||||
// while (sprite_iter.next()) |sprite_id| {
|
|
||||||
// const sprite = self.sprites.getAssumeExists(sprite_id);
|
|
||||||
// ImGUI.text("{f} - {?}", .{sprite_id, sprite.position});
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This will always have a 1-frame delay.
|
// TODO: This will always have a 1-frame delay.
|
||||||
@ -396,11 +383,7 @@ pub fn setClearColor(color: Color) void {
|
|||||||
self.clear_color = color;
|
self.clear_color = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FlushOptions = struct {
|
pub fn flush() void {
|
||||||
rebuild_spritesheets: bool = true
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn flush(opts: FlushOptions) void {
|
|
||||||
const self = &g_state;
|
const self = &g_state;
|
||||||
|
|
||||||
if (self.quads.items.len == 0) {
|
if (self.quads.items.len == 0) {
|
||||||
@ -408,7 +391,6 @@ pub fn flush(opts: FlushOptions) void {
|
|||||||
}
|
}
|
||||||
defer self.quads.clearRetainingCapacity();
|
defer self.quads.clearRetainingCapacity();
|
||||||
|
|
||||||
if (opts.rebuild_spritesheets) {
|
|
||||||
var spritesheet_iter = self.spritesheets.iterator();
|
var spritesheet_iter = self.spritesheets.iterator();
|
||||||
while (spritesheet_iter.next()) |spritesheet_id| {
|
while (spritesheet_iter.next()) |spritesheet_id| {
|
||||||
const spritesheet = self.spritesheets.getAssumeExists(spritesheet_id);
|
const spritesheet = self.spritesheets.getAssumeExists(spritesheet_id);
|
||||||
@ -417,6 +399,10 @@ pub fn flush(opts: FlushOptions) void {
|
|||||||
rebuildSpritesheetTextureIfNeeded(spritesheet_id);
|
rebuildSpritesheetTextureIfNeeded(spritesheet_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sg.queryViewState(getBoundView().*) != .VALID) {
|
||||||
|
log.warn("Attempt to use view which isn't valid", .{});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const vertex_buffer = self.bindings.vertex_buffers[0];
|
const vertex_buffer = self.bindings.vertex_buffers[0];
|
||||||
@ -442,7 +428,7 @@ pub fn flush(opts: FlushOptions) void {
|
|||||||
var fs_params: shd.FsParams = .{
|
var fs_params: shd.FsParams = .{
|
||||||
.texture_mode = 0,
|
.texture_mode = 0,
|
||||||
};
|
};
|
||||||
const image = sg.queryViewImage(self.bindings.views[shd.VIEW_tex]);
|
const image = sg.queryViewImage(getBoundView().*);
|
||||||
if (sg.queryImagePixelformat(image) == .R8) {
|
if (sg.queryImagePixelformat(image) == .R8) {
|
||||||
fs_params.texture_mode = 1;
|
fs_params.texture_mode = 1;
|
||||||
}
|
}
|
||||||
@ -451,17 +437,17 @@ pub fn flush(opts: FlushOptions) void {
|
|||||||
sg.applyBindings(self.bindings);
|
sg.applyBindings(self.bindings);
|
||||||
sg.applyUniforms(shd.UB_vs_params, sg.asRange(&vs_params));
|
sg.applyUniforms(shd.UB_vs_params, sg.asRange(&vs_params));
|
||||||
sg.applyUniforms(shd.UB_fs_params, sg.asRange(&fs_params));
|
sg.applyUniforms(shd.UB_fs_params, sg.asRange(&fs_params));
|
||||||
|
assert(self.quads.items.len > 0);
|
||||||
sg.draw(0, @intCast(self.quads.items.len * 6), 1);
|
sg.draw(0, @intCast(self.quads.items.len * 6), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn endFrame() void {
|
pub fn endFrame() void {
|
||||||
const self = &g_state;
|
const self = &g_state;
|
||||||
|
|
||||||
flush(.{});
|
flush();
|
||||||
|
|
||||||
sg.endPass();
|
sg.endPass();
|
||||||
sg.commit();
|
sg.commit();
|
||||||
self.frame_index += 1;
|
|
||||||
|
|
||||||
var spritesheet_iter = self.spritesheets.iterator();
|
var spritesheet_iter = self.spritesheets.iterator();
|
||||||
while (spritesheet_iter.next()) |spritesheet_id| {
|
while (spritesheet_iter.next()) |spritesheet_id| {
|
||||||
@ -473,6 +459,8 @@ pub fn endFrame() void {
|
|||||||
} else if (self.transforms.items.len == 0) {
|
} else if (self.transforms.items.len == 0) {
|
||||||
log.warn("Too many calls to transformPop()", .{});
|
log.warn("Too many calls to transformPop()", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.frame_index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drawRectangle(pos: Vec2, size: Vec2, color: Color) void {
|
pub fn drawRectangle(pos: Vec2, size: Vec2, color: Color) void {
|
||||||
@ -577,33 +565,28 @@ pub fn initTexture(opts: TextureOptions) Texture.Id {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn getBoundView() *sg.View {
|
||||||
|
const self = &g_state;
|
||||||
|
return &self.bindings.views[shd.VIEW_tex];
|
||||||
|
}
|
||||||
|
|
||||||
fn isViewBound(view: sg.View) bool {
|
fn isViewBound(view: sg.View) bool {
|
||||||
const self = &g_state;
|
return getBoundView().id == view.id;
|
||||||
const bound_view = &self.bindings.views[shd.VIEW_tex];
|
|
||||||
return bound_view.id == view.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deinitTextureResources(texture: *Texture) void {
|
|
||||||
const self = &g_state;
|
|
||||||
|
|
||||||
if (isViewBound(texture.view)) {
|
|
||||||
const default_sprite = self.sprites.getAssumeExists(self.default_sprite);
|
|
||||||
const default_spritesheet = self.spritesheets.getAssumeExists(default_sprite.spritesheet);
|
|
||||||
const default_texture = self.textures.getAssumeExists(default_spritesheet.texture);
|
|
||||||
bindView(default_texture.view, .{ .rebuild_spritesheets = false });
|
|
||||||
}
|
|
||||||
|
|
||||||
sg.destroyImage(texture.image);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinitTexture(id: Texture.Id) void {
|
pub fn deinitTexture(id: Texture.Id) void {
|
||||||
const self = &g_state;
|
const self = &g_state;
|
||||||
if (id == self.nil_texture) {
|
if (id == .nil) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.textures.get(id)) |texture| {
|
if (self.textures.get(id)) |texture| {
|
||||||
deinitTextureResources(texture);
|
const bound_view = getBoundView();
|
||||||
|
if (bound_view.id == texture.view.id) {
|
||||||
|
bound_view.id = sg.invalid_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
sg.destroyImage(texture.image);
|
||||||
sg.destroyView(texture.view);
|
sg.destroyView(texture.view);
|
||||||
self.textures.removeAssumeExists(id);
|
self.textures.removeAssumeExists(id);
|
||||||
}
|
}
|
||||||
@ -649,7 +632,6 @@ pub fn setTexture(id: Texture.Id, texture_data: ImageData) void {
|
|||||||
|
|
||||||
var texture_updated: bool = false;
|
var texture_updated: bool = false;
|
||||||
if (sg.queryImageState(texture.image) == .VALID) {
|
if (sg.queryImageState(texture.image) == .VALID) {
|
||||||
// sg.queryImageInfo
|
|
||||||
const image_desc = sg.queryImageDesc(texture.image);
|
const image_desc = sg.queryImageDesc(texture.image);
|
||||||
if (image_desc.width == new_image_desc.width and
|
if (image_desc.width == new_image_desc.width and
|
||||||
image_desc.height == new_image_desc.height and
|
image_desc.height == new_image_desc.height and
|
||||||
@ -659,19 +641,19 @@ pub fn setTexture(id: Texture.Id, texture_data: ImageData) void {
|
|||||||
image_desc.usage.immutable == new_image_desc.usage.immutable and
|
image_desc.usage.immutable == new_image_desc.usage.immutable and
|
||||||
image_desc.usage.dynamic_update
|
image_desc.usage.dynamic_update
|
||||||
) {
|
) {
|
||||||
log.debug("Update texture '{f}'", .{id});
|
log.debug("[{}] Update texture '{f}'", .{self.frame_index, id});
|
||||||
if (texture.updated_at == null or texture.updated_at.? != self.frame_index) {
|
if (texture.updated_at == null or texture.updated_at.? != self.frame_index) {
|
||||||
sg.updateImage(texture.image, image_data);
|
sg.updateImage(texture.image, image_data);
|
||||||
texture_updated = true;
|
texture_updated = true;
|
||||||
texture.updated_at = self.frame_index;
|
texture.updated_at = self.frame_index;
|
||||||
} else {
|
} else {
|
||||||
log.warn("Attempt to update the same texture multiple times per frame", .{});
|
log.warn("Attempt to update the same texture multiple times per frame, texture: {f}", .{id});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!texture_updated) {
|
if (!texture_updated) {
|
||||||
log.debug("Create image-view, texture={f}", .{id});
|
log.debug("[{}] Create image-view, texture={f}", .{self.frame_index, id});
|
||||||
const new_image = sg.makeImage(new_image_desc);
|
const new_image = sg.makeImage(new_image_desc);
|
||||||
if (sg.queryImageState(new_image) != .VALID) {
|
if (sg.queryImageState(new_image) != .VALID) {
|
||||||
log.warn("makeImage() failed", .{});
|
log.warn("makeImage() failed", .{});
|
||||||
@ -689,11 +671,13 @@ pub fn setTexture(id: Texture.Id, texture_data: ImageData) void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
deinitTextureResources(texture);
|
sg.destroyImage(texture.image);
|
||||||
texture.image = new_image;
|
texture.image = new_image;
|
||||||
texture.updated_at = null;
|
texture.updated_at = null;
|
||||||
|
|
||||||
|
log.debug("is dynamic {f}, {}", .{id, texture.dynamic});
|
||||||
if (texture.dynamic) {
|
if (texture.dynamic) {
|
||||||
|
log.debug("update texture {f}", .{id});
|
||||||
sg.updateImage(new_image, image_data);
|
sg.updateImage(new_image, image_data);
|
||||||
texture.updated_at = self.frame_index;
|
texture.updated_at = self.frame_index;
|
||||||
}
|
}
|
||||||
@ -712,20 +696,11 @@ pub fn drawTexture(id: Texture.Id, pos: Vec2, size: Vec2, color: Color) void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bindView(view: sg.View, opts: FlushOptions) void {
|
fn bindView(view: sg.View) void {
|
||||||
|
_ = view; // autofix
|
||||||
const self = &g_state;
|
const self = &g_state;
|
||||||
|
_ = self; // autofix
|
||||||
|
|
||||||
const view_state = sg.queryViewState(view);
|
|
||||||
if (view_state != .VALID and view_state != .ALLOC) {
|
|
||||||
log.warn("Attempt to bind non-valid view: state={}", .{view_state});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bound_view = &self.bindings.views[shd.VIEW_tex];
|
|
||||||
if (bound_view.id != view.id) {
|
|
||||||
flush(opts);
|
|
||||||
bound_view.* = view;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setDefaultSampler(sampler: Sampler) void {
|
pub fn setDefaultSampler(sampler: Sampler) void {
|
||||||
@ -773,7 +748,17 @@ pub fn draw(opts: DrawOptions) void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bindView(view, .{});
|
const view_state = sg.queryViewState(view);
|
||||||
|
if (view_state == .VALID or view_state == .ALLOC) {
|
||||||
|
const bound_view = getBoundView();
|
||||||
|
if (bound_view.id != view.id) {
|
||||||
|
flush();
|
||||||
|
bound_view.* = view;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("Attempt to bind non-valid view: state={}", .{view_state});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const sampler = switch (opts.sampler orelse self.default_sampler) {
|
const sampler = switch (opts.sampler orelse self.default_sampler) {
|
||||||
.linear => self.linear_sampler,
|
.linear => self.linear_sampler,
|
||||||
@ -781,12 +766,12 @@ pub fn draw(opts: DrawOptions) void {
|
|||||||
};
|
};
|
||||||
const bound_sampler = &self.bindings.samplers[shd.SMP_smp];
|
const bound_sampler = &self.bindings.samplers[shd.SMP_smp];
|
||||||
if (bound_sampler.id != sampler.id) {
|
if (bound_sampler.id != sampler.id) {
|
||||||
flush(.{});
|
flush();
|
||||||
bound_sampler.* = sampler;
|
bound_sampler.* = sampler;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.quads.items.len == self.quads.capacity) {
|
if (self.quads.items.len == self.quads.capacity) {
|
||||||
flush(.{});
|
flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getTransformPtr()) |transform| {
|
if (getTransformPtr()) |transform| {
|
||||||
@ -843,6 +828,7 @@ const SetSpriteOptions = struct {
|
|||||||
|
|
||||||
pub fn setSprite(id: Sprite.Id, opts: SetSpriteOptions) void {
|
pub fn setSprite(id: Sprite.Id, opts: SetSpriteOptions) void {
|
||||||
const self = &g_state;
|
const self = &g_state;
|
||||||
|
|
||||||
const sprite = self.sprites.get(id) orelse {
|
const sprite = self.sprites.get(id) orelse {
|
||||||
log.warn("Attempt to set sprite that doesn't exist: {}", .{id});
|
log.warn("Attempt to set sprite that doesn't exist: {}", .{id});
|
||||||
return;
|
return;
|
||||||
@ -897,12 +883,14 @@ pub fn setSprite(id: Sprite.Id, opts: SetSpriteOptions) void {
|
|||||||
|
|
||||||
const new_size = Vec2.initFromInt(u32, sprite_data.width, sprite_data.height);
|
const new_size = Vec2.initFromInt(u32, sprite_data.width, sprite_data.height);
|
||||||
|
|
||||||
if (old_size != null and old_size.?.eql(new_size) and sprite.position != null) {
|
log.debug("set sprite on {f}", .{sprite.spritesheet});
|
||||||
spritesheet.needs_texture_rebuild = true;
|
|
||||||
} else {
|
if (old_size == null or !old_size.?.eql(new_size) or sprite.position == null) {
|
||||||
sprite.position = null;
|
sprite.position = null;
|
||||||
spritesheet.needs_repack = true;
|
spritesheet.needs_repack = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spritesheet.needs_texture_rebuild = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// WARNING: This will change the UV coordinates of all sprites.
|
// WARNING: This will change the UV coordinates of all sprites.
|
||||||
@ -915,7 +903,7 @@ fn repackSpritesheet(id: Spritesheet.Id) void {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
log.debug("Repack spritesheet: {f}", .{id});
|
log.debug("[{}] Repack spritesheet: {f}", .{self.frame_index, id});
|
||||||
|
|
||||||
// TODO: Add a smarter startegy for picking the initial texture size.
|
// TODO: Add a smarter startegy for picking the initial texture size.
|
||||||
// One idea is to calculate the sum area of all sprites and pick a atlas size based on that.
|
// One idea is to calculate the sum area of all sprites and pick a atlas size based on that.
|
||||||
@ -994,7 +982,7 @@ fn rebuildSpritesheetTextureIfNeeded(id: Spritesheet.Id) void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("Rebuild spritesheet texture: {f}", .{id});
|
log.debug("[{}] Rebuild spritesheet texture: {f}", .{self.frame_index, id});
|
||||||
|
|
||||||
const image_data = ImageData.init(
|
const image_data = ImageData.init(
|
||||||
self.gpa,
|
self.gpa,
|
||||||
@ -1265,12 +1253,12 @@ pub fn getGlyph(id: Font.Id, index: GlyphIndex, scale_x: f32, scale_y: f32) ?*Fo
|
|||||||
};
|
};
|
||||||
glyph = font.cache.get(glyph_id);
|
glyph = font.cache.get(glyph_id);
|
||||||
glyph.box = stb_font.getGlyphBitmapBox(glyph_key.index, glyph_key.scale_x, glyph_key.scale_y);
|
glyph.box = stb_font.getGlyphBitmapBox(glyph_key.index, glyph_key.scale_x, glyph_key.scale_y);
|
||||||
|
glyph.sprite = null;
|
||||||
|
|
||||||
const box_width: u32 = @intCast(glyph.box.x1 - glyph.box.x0);
|
const box_width: u32 = @intCast(glyph.box.x1 - glyph.box.x0);
|
||||||
const box_height: u32 = @intCast(glyph.box.y1 - glyph.box.y0);
|
const box_height: u32 = @intCast(glyph.box.y1 - glyph.box.y0);
|
||||||
if (box_width > 0 and box_height > 0) {
|
if (box_width > 0 and box_height > 0) {
|
||||||
assert(glyph.sprite == Sprite.Id.nil);
|
const sprite = initSprite(.{ .spritesheet = font.spritesheet, .padding = 1 });
|
||||||
glyph.sprite = initSprite(.{ .spritesheet = font.spritesheet, .padding = 1 });
|
|
||||||
|
|
||||||
assert(box_width < Font.Glyph.max_width);
|
assert(box_width < Font.Glyph.max_width);
|
||||||
assert(box_height < Font.Glyph.max_height);
|
assert(box_height < Font.Glyph.max_height);
|
||||||
@ -1288,9 +1276,10 @@ pub fn getGlyph(id: Font.Id, index: GlyphIndex, scale_x: f32, scale_y: f32) ?*Fo
|
|||||||
glyph_key.scale_x, glyph_key.scale_y,
|
glyph_key.scale_x, glyph_key.scale_y,
|
||||||
glyph_key.index
|
glyph_key.index
|
||||||
);
|
);
|
||||||
setSprite(glyph.sprite, .{ .image = bitmap });
|
setSprite(sprite, .{ .image = bitmap });
|
||||||
} else {
|
|
||||||
glyph.sprite = .nil;
|
assert(glyph.sprite == null);
|
||||||
|
glyph.sprite = sprite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
glyph.used_this_frame = true;
|
glyph.used_this_frame = true;
|
||||||
@ -1308,7 +1297,7 @@ pub const TextRunLayout = struct {
|
|||||||
|
|
||||||
const GlyphRect = struct {
|
const GlyphRect = struct {
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
sprite: Sprite.Id,
|
sprite: ?Sprite.Id,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(font: Font.Id, height: f32) TextRunLayout {
|
pub fn init(font: Font.Id, height: f32) TextRunLayout {
|
||||||
@ -1406,9 +1395,10 @@ pub fn drawText(id: Font.Id, opts: DrawTextOptions) void {
|
|||||||
while (iter.nextCodepoint()) |codepoint| {
|
while (iter.nextCodepoint()) |codepoint| {
|
||||||
const glyph_index = getGlyphIndex(id, codepoint) orelse continue;
|
const glyph_index = getGlyphIndex(id, codepoint) orelse continue;
|
||||||
const glyph_layout = layout.next(glyph_index) orelse continue;
|
const glyph_layout = layout.next(glyph_index) orelse continue;
|
||||||
|
const glyph_sprite = glyph_layout.sprite orelse continue;
|
||||||
|
|
||||||
drawSprite(
|
drawSprite(
|
||||||
glyph_layout.sprite,
|
glyph_sprite,
|
||||||
glyph_layout.rect.pos.add(pos),
|
glyph_layout.rect.pos.add(pos),
|
||||||
glyph_layout.rect.size,
|
glyph_layout.rect.size,
|
||||||
opts.color
|
opts.color
|
||||||
@ -2133,7 +2123,7 @@ pub const Font = struct {
|
|||||||
key: Key,
|
key: Key,
|
||||||
|
|
||||||
box: STBTrueType.Box,
|
box: STBTrueType.Box,
|
||||||
sprite: Sprite.Id,
|
sprite: ?Sprite.Id,
|
||||||
used_this_frame: bool,
|
used_this_frame: bool,
|
||||||
|
|
||||||
const max_width: u32 = 512;
|
const max_width: u32 = 512;
|
||||||
@ -2169,7 +2159,9 @@ pub const Font = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deinit(self: Glyph) void {
|
fn deinit(self: Glyph) void {
|
||||||
deinitSprite(self.sprite);
|
if (self.sprite) |sprite| {
|
||||||
|
deinitSprite(sprite);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -139,7 +139,7 @@ fn PlatformType(App: type) type {
|
|||||||
try self.app.frame(plt);
|
try self.app.frame(plt);
|
||||||
}
|
}
|
||||||
|
|
||||||
Gfx.flush(.{});
|
Gfx.flush();
|
||||||
if (ImGUI.beginWindow(.{
|
if (ImGUI.beginWindow(.{
|
||||||
.name = "Platform",
|
.name = "Platform",
|
||||||
.size = .init(300, 400)
|
.size = .init(300, 400)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user