Skip to content

Commit

Permalink
image: add at and atOrNull image access methods
Browse files Browse the repository at this point in the history
  • Loading branch information
arrufat committed Dec 9, 2024
1 parent fe4aa77 commit 1f1f2e5
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 14 deletions.
3 changes: 1 addition & 2 deletions examples/src/perlin_noise.zig
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,13 @@ pub export fn generate(rgba_ptr: [*]Rgba, rows: usize, cols: usize) void {
for (0..image.rows) |r| {
const y: f32 = @as(f32, @floatFromInt(r)) / @as(f32, @floatFromInt(image.rows));
for (0..image.cols) |c| {
const pos = r * image.cols + c;
const x: f32 = @as(f32, @floatFromInt(c)) / @as(f32, @floatFromInt(image.cols));
const val: u8 = @intFromFloat(
@max(0, @min(255, @round(
255 * (opts.amplitude / 2 * (perlin.generate(f32, x, y, 0, opts) + opts.amplitude)),
))),
);
image.data[pos] = Rgba.fromGray(val, 255);
image.at(r, c).* = Rgba.fromGray(val, 255);
}
}
}
15 changes: 6 additions & 9 deletions examples/src/seam_carving.zig
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,11 @@ pub fn computeEnergy(
var x: isize = @as(isize, @intCast(c)) + i;
if (x == energy.cols) x = @intCast(energy.cols - 1);
const y: isize = @as(isize, @intCast(r)) - 1;
if (energy.at(y, x)) |val| {
if (energy.atOrNull(y, x)) |val| {
min = @min(val.*, min);
}
}
const pos = r * edges.cols + c;
energy.data[pos] = edges.data[pos] + min;
energy.at(r, c).* = edges.at(r, c).* + min;
}
}
}
Expand All @@ -43,9 +42,7 @@ pub fn computeSeam(energy: Image(u32), seam: []usize) void {
const row: usize = energy.rows - 1;
seam[row] = 0;
for (0..energy.cols) |c| {
const pos1 = row * energy.cols + c;
const pos2 = row * energy.cols + seam[row];
if (energy.data[pos1] < energy.data[pos2]) {
if (energy.at(row, c).* < energy.at(row, seam[row]).*) {
seam[row] = c;
}
}
Expand All @@ -58,8 +55,8 @@ pub fn computeSeam(energy: Image(u32), seam: []usize) void {
while (i <= 1) : (i += 1) {
var x: isize = @as(isize, @intCast(seam[r + 1])) + i;
if (x == energy.cols) x = @intCast(energy.cols - 1);
if (energy.at(y, x)) |curr| {
if (energy.at(y, @intCast(seam[r]))) |prev| {
if (energy.atOrNull(y, x)) |curr| {
if (energy.atOrNull(y, @intCast(seam[r]))) |prev| {
if (curr.* < prev.*) {
seam[r] = @intCast(x);
}
Expand All @@ -76,7 +73,7 @@ pub fn removeSeam(comptime T: type, image: *Image(T), seam: []const usize) void
for (0..image.rows) |r| {
for (0..image.cols) |c| {
if (c == seam[r]) continue;
image.data[pos] = image.data[r * image.cols + c];
image.data[pos] = image.at(r, c).*;
pos += 1;
}
}
Expand Down
14 changes: 11 additions & 3 deletions src/image.zig
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,16 @@ pub fn Image(comptime T: type) type {
return self.rows == other.rows and self.cols == other.cols and self.data.len == other.data.len;
}

/// Returns the value at position row, col. It assumes the coordinates are in bounds and
/// triggers safety-checked undefined behavior when they aren't.
pub inline fn at(self: Self, row: usize, col: usize) *T {
assert(row < self.rows);
assert(col < self.cols);
return &self.data[row * self.cols + col];
}

/// Returns the optional value at row, col in the image.
pub fn at(self: Self, row: isize, col: isize) ?*T {
pub fn atOrNull(self: Self, row: isize, col: isize) ?*T {
const irows: isize = @intCast(self.rows);
const icols: isize = @intCast(self.cols);
if (row < 0 or col < 0 or row >= irows or col >= icols) {
Expand Down Expand Up @@ -197,7 +205,7 @@ pub fn Image(comptime T: type) type {
const ir: isize = @intCast(r);
for (0..chip_cols) |c| {
const ic: isize = @intCast(c);
chip.data[r * chip_cols + c] = if (self.at(@intCast(ir + chip_top), @intCast(ic + chip_left))) |val|
chip.data[r * chip_cols + c] = if (self.atOrNull(@intCast(ir + chip_top), @intCast(ic + chip_left))) |val|
val.*
else
std.mem.zeroes(T);
Expand Down Expand Up @@ -494,7 +502,7 @@ pub fn Image(comptime T: type) type {
const py: isize = ir - 1 + @as(isize, @intCast(m));
for (0..vert_filter[0].len) |n| {
const px: isize = ic - 1 + @as(isize, @intCast(n));
if (self.at(py, px)) |val| {
if (self.atOrNull(py, px)) |val| {
const p: i32 = @intCast(convert(u8, val.*));
horz_temp += p * horz_filter[m][n];
vert_temp += p * vert_filter[m][n];
Expand Down

0 comments on commit 1f1f2e5

Please sign in to comment.