cleanup graphics.zig

This commit is contained in:
Rokas Puzonas 2026-09-17 02:00:37 +03:00
parent ddb012d3df
commit 0ac0cd0c37

View File

@ -660,10 +660,19 @@ pub fn setTexture(id: Texture.Id, opts: SetTextureOptions) void {
return; return;
}; };
// TODO: Apply premultiply, will need scratch buffer var scratch = std.heap.ArenaAllocator.init(self.gpa);
assert(opts.premultiplied);
var mipchain = opts.mipchain; var mipchain = opts.mipchain;
if (!opts.premultiplied) {
var new_mipchain = mipchain.clone(scratch.allocator()) catch |e| {
log.warn("Failed to clone mipmap: {}", .{e});
return;
};
new_mipchain.premultiplyAlpha();
mipchain = new_mipchain;
}
var image_data: sg.ImageData = .{}; var image_data: sg.ImageData = .{};
assert(mipchain.length() <= image_data.mip_levels.len); assert(mipchain.length() <= image_data.mip_levels.len);
@ -917,12 +926,7 @@ pub fn setSprite(id: Sprite.Id, opts: SetSpriteOptions) void {
return; return;
}; };
next_mipchain.copyFromRect( next_mipchain.copyFromRect(opts.mipchain, 0, 0, .initTrunc(rect));
opts.mipchain,
0, 0,
@trunc(rect.pos.x), @trunc(rect.pos.y),
@trunc(rect.size.x), @trunc(rect.size.y)
);
} else { } else {
next_mipchain = opts.mipchain.clone(next_arena.allocator()) catch |e| { next_mipchain = opts.mipchain.clone(next_arena.allocator()) catch |e| {
log.warn("Failed to clone mipchain: {}", .{e}); log.warn("Failed to clone mipchain: {}", .{e});
@ -931,9 +935,7 @@ pub fn setSprite(id: Sprite.Id, opts: SetSpriteOptions) void {
} }
if (!opts.premultiplied) { if (!opts.premultiplied) {
for (0..next_mipchain.length()) |index| { next_mipchain.premultiplyAlpha();
next_mipchain.getLevel(index).premultiplyAlpha();
}
} }
var prev_size: ?Vec2 = null; var prev_size: ?Vec2 = null;
@ -1043,6 +1045,9 @@ fn repackSpritesheetIfNeeded(id: Spritesheet.Id) void {
// TODO: This function is a bit large, there are some easy things that could be moved to separate function. // TODO: This function is a bit large, there are some easy things that could be moved to separate function.
// e.g. extruding padding. // e.g. extruding padding.
fn rebuildSpritesheetTextureIfNeeded(id: Spritesheet.Id) void { fn rebuildSpritesheetTextureIfNeeded(id: Spritesheet.Id) void {
// TODO: Allow generating mipmaps
// https://github.com/floooh/sokol/issues/102#issuecomment-2926566603
const self = &g_state; const self = &g_state;
const spritesheet = self.spritesheets.get(id) orelse return; const spritesheet = self.spritesheets.get(id) orelse return;
if (!spritesheet.needs_texture_rebuild) { if (!spritesheet.needs_texture_rebuild) {
@ -1095,36 +1100,22 @@ fn rebuildSpritesheetTextureIfNeeded(id: Spritesheet.Id) void {
); );
level.copyFrom(sprite_level, x, y); level.copyFrom(sprite_level, x, y);
// TODO: Make `edge_extrusion` amount configurable
var edge_extrusion: u32 = 0;
if (padding > 0) { if (padding > 0) {
for (0..sprite_level.width) |ox| { edge_extrusion = 1;
const pixel = level.getPixel(x+ox, y);
for (0..padding) |i| {
@memcpy(level.getPixel(x+ox, y-(i+1)), pixel);
}
} }
for (0..sprite_level.width) |ox| { if (edge_extrusion > 0) {
const pixel = level.getPixel(x+ox, y+sprite_level.height-1); level.extrudeEdge(
for (0..padding) |i| { .{
@memcpy(level.getPixel(x+ox, y+sprite_level.height+i), pixel); .x = x,
} .y = y,
} .width = sprite_level.width,
.height = sprite_level.height,
for (0..sprite_level.height) |oy| { },
const pixel = level.getPixel(x, y+oy); edge_extrusion
for (0..padding) |i| { );
@memcpy(level.getPixel(x-(i+1), y+oy), pixel);
}
}
for (0..sprite_level.height) |oy| {
const pixel = level.getPixel(x+sprite_level.width-1, y+oy);
for (0..padding) |i| {
@memcpy(level.getPixel(x+sprite_level.width+i, y+oy), pixel);
}
}
// TODO: Add padding to corners.
} }
} }
} }
@ -1301,6 +1292,22 @@ pub const Image = struct {
height: u32, height: u32,
}; };
const Rect = struct {
x: u32,
y: u32,
width: u32,
height: u32,
fn initTrunc(r: Math.Rect) Image.Rect {
return .{
.x = @trunc(r.pos.x),
.y = @trunc(r.pos.y),
.width = @trunc(r.size.x),
.height = @trunc(r.size.y),
};
}
};
pub fn initAlloc(gpa: Allocator, opts: InitOptions) !Image { pub fn initAlloc(gpa: Allocator, opts: InitOptions) !Image {
const pixel_count = opts.width * opts.height; const pixel_count = opts.width * opts.height;
const pixel_size = opts.format.pixelSize(); const pixel_size = opts.format.pixelSize();
@ -1385,15 +1392,12 @@ pub const Image = struct {
source: Image, source: Image,
cx: u32, cx: u32,
cy: u32, cy: u32,
source_cx: u32, source_rect: Image.Rect,
source_cy: u32,
source_width: u32,
source_height: u32,
) void { ) void {
assert(source.format == self.format); assert(source.format == self.format);
for (0..source_height) |oy| { for (0..source_rect.height) |oy| {
const source_y = source_cy+oy; const source_y = source_rect.y+oy;
const dest_y = cy+oy; const dest_y = cy+oy;
if (dest_y >= self.height) { if (dest_y >= self.height) {
continue; continue;
@ -1402,8 +1406,8 @@ pub const Image = struct {
continue; continue;
} }
for (0..source_width) |ox| { for (0..source_rect.width) |ox| {
const source_x = source_cx+ox; const source_x = source_rect.x+ox;
const dest_x = cx+ox; const dest_x = cx+ox;
if (dest_x >= self.width) { if (dest_x >= self.width) {
continue; continue;
@ -1426,7 +1430,39 @@ pub const Image = struct {
cx: u32, cx: u32,
cy: u32, cy: u32,
) void { ) void {
self.copyFromRect(source, cx, cy, 0, 0, source.width, source.height); self.copyFromRect(source, cx, cy, .{ .x = 0, .y = 0, .width = source.width, .height = source.height});
}
pub fn extrudeEdge(self: Image, rect: Image.Rect, size: u32) void {
for (0..rect.width) |ox| {
const pixel = self.getPixel(rect.x+ox, rect.y);
for (0..size) |i| {
@memcpy(self.getPixel(rect.x+ox, rect.y-(i+1)), pixel);
}
}
for (0..rect.width) |ox| {
const pixel = self.getPixel(rect.x+ox, rect.y+rect.height-1);
for (0..size) |i| {
@memcpy(self.getPixel(rect.x+ox, rect.y+rect.height+i), pixel);
}
}
for (0..rect.height) |oy| {
const pixel = self.getPixel(rect.x, rect.y+oy);
for (0..size) |i| {
@memcpy(self.getPixel(rect.x-(i+1), rect.y+oy), pixel);
}
}
for (0..rect.height) |oy| {
const pixel = self.getPixel(rect.x+rect.width-1, rect.y+oy);
for (0..size) |i| {
@memcpy(self.getPixel(rect.x+rect.width+i, rect.y+oy), pixel);
}
}
// TODO: Add padding to corners.
} }
}; };
@ -1562,10 +1598,7 @@ pub const Mipchain = struct {
source: Mipchain, source: Mipchain,
cx: u32, cx: u32,
cy: u32, cy: u32,
source_cx: u32, source_rect: Image.Rect,
source_cy: u32,
source_width: u32,
source_height: u32,
) void { ) void {
assert(self.length() == source.length()); assert(self.length() == source.length());
@ -1576,13 +1609,21 @@ pub const Mipchain = struct {
source_level, source_level,
cx >> @intCast(index), cx >> @intCast(index),
cy >> @intCast(index), cy >> @intCast(index),
source_cx >> @intCast(index), .{
source_cy >> @intCast(index), .x = source_rect.x >> @intCast(index),
source_width >> @intCast(index), .y = source_rect.y >> @intCast(index),
source_height >> @intCast(index), .width = source_rect.width >> @intCast(index),
.height = source_rect.height >> @intCast(index),
}
); );
} }
} }
pub fn premultiplyAlpha(self: Mipchain) void {
for (0..self.length()) |index| {
self.getLevel(index).premultiplyAlpha();
}
}
}; };
pub const Texture = struct { pub const Texture = struct {