diff --git a/samples/zig-sample/src/main.zig b/samples/zig-sample/src/main.zig index 7ae8b6e..27ba3db 100644 --- a/samples/zig-sample/src/main.zig +++ b/samples/zig-sample/src/main.zig @@ -1,6 +1,8 @@ const std = @import("std"); const oc = @import("orca"); +const lerp = std.math.lerp; + const Vec2 = oc.Vec2; const Mat2x3 = oc.Mat2x3; const Str8 = oc.Str8; @@ -9,6 +11,7 @@ var surface: oc.Surface = undefined; var canvas: oc.Canvas = undefined; var font: oc.Font = undefined; var orca_image: oc.Image = undefined; +var gradient_image: oc.Image = undefined; var counter: u32 = 0; var last_seconds: f64 = 0; @@ -42,6 +45,41 @@ export fn oc_on_init() void { orca_image = oc.Image.createFromPath(surface, Str8.fromSlice("/orca_jumping.jpg"), false); oc.assert(oc.Image.nil().isNil() == true, "nil image should be nil", .{}, @src()); oc.assert(orca_image.isNil() == false, "created image should not be nil", .{}, @src()); + + // generate a gradient and upload it to an image + { + const width = 256; + const height = 128; + + const tl = oc.Color{ .r = 70.0 / 255.0, .g = 13.0 / 255.0, .b = 108.0 / 255.0 }; + const bl = oc.Color{ .r = 251.0 / 255.0, .g = 167.0 / 255.0, .b = 87.0 / 255.0 }; + const tr = oc.Color{ .r = 48.0 / 255.0, .g = 164.0 / 255.0, .b = 219.0 / 255.0 }; + const br = oc.Color{ .r = 151.0 / 255.0, .g = 222.0 / 255.0, .b = 150.0 / 255.0 }; + + var pixels: [width * height]u32 = undefined; + for (0..height) |y| { + for (0..width) |x| { + const h: f32 = @floatFromInt(height - 1); + const w: f32 = @floatFromInt(width - 1); + const y_norm: f32 = @as(f32, @floatFromInt(y)) / h; + const x_norm: f32 = @as(f32, @floatFromInt(x)) / w; + + const tl_weight = (1 - x_norm) * (1 - y_norm); + const bl_weight = (1 - x_norm) * y_norm; + const tr_weight = x_norm * (1 - y_norm); + const br_weight = x_norm * y_norm; + + const r: f32 = tl_weight * tl.r + bl_weight * bl.r + tr_weight * tr.r + br_weight * br.r; + const g: f32 = tl_weight * tl.g + bl_weight * bl.g + tr_weight * tr.g + br_weight * br.g; + const b: f32 = tl_weight * tl.b + bl_weight * bl.b + tr_weight * tr.b + br_weight * br.b; + const color = oc.Color{ .r = r, .g = g, .b = b, .a = 1.0 }; + pixels[y * width + x] = color.toRgba8(); + } + } + + gradient_image = oc.Image.create(surface, width, height); + gradient_image.uploadRegionRgba8(oc.Rect.xywh(0, 0, width, height), @ptrCast((&pixels).ptr)); + } } export fn oc_on_resize(width: u32, height: u32) void { @@ -106,9 +144,9 @@ export fn oc_on_frame_refresh() void { oc.Canvas.roundedRectangleFill(90, 0, 10, 10, 3); oc.Canvas.roundedRectangleStroke(110, 0, 10, 10, 3); - const green = oc.Color{ .Flat = .{ .r = 0.05, .g = 1, .b = 0.05, .a = 1 } }; + const green = oc.Color{ .r = 0.05, .g = 1, .b = 0.05, .a = 1 }; oc.Canvas.setColor(green); - oc.assert(std.meta.eql(oc.Canvas.getColor().Flat, green.Flat), "color should be green", .{}, @src()); + oc.assert(std.meta.eql(oc.Canvas.getColor(), green), "color should be green", .{}, @src()); oc.Canvas.setTolerance(1); oc.Canvas.setJoint(.Bevel); @@ -204,18 +242,32 @@ export fn oc_on_frame_refresh() void { } { - const trans = Mat2x3.translate(0, 200); - const scale = Mat2x3.scaleUniform(0.25); - Mat2x3.push(Mat2x3.mul_m(trans, scale)); - defer Mat2x3.pop(); + const orca_size = orca_image.size(); - const size = orca_image.size(); + { + const trans = Mat2x3.translate(0, 200); + const scale = Mat2x3.scaleUniform(0.25); + Mat2x3.push(Mat2x3.mul_m(trans, scale)); + defer Mat2x3.pop(); - orca_image.draw(oc.Rect.xywh(0, 0, size.x, size.y)); + orca_image.draw(oc.Rect.xywh(0, 0, orca_size.x, orca_size.y)); - var half_size = orca_image.size(); - half_size.x /= 2; - orca_image.drawRegion(oc.Rect.xywh(0, 0, half_size.x, half_size.y), oc.Rect.xywh(size.x + 10, 0, half_size.x, half_size.y)); + var half_size = orca_size; + half_size.x /= 2; + orca_image.drawRegion(oc.Rect.xywh(0, 0, half_size.x, half_size.y), oc.Rect.xywh(orca_size.x + 10, 0, half_size.x, half_size.y)); + } + + { + const x_offset = orca_size.x * 0.25 + orca_size.x * 0.25 * 0.5 + 5; + const gradient_size = gradient_image.size(); + + const trans = Mat2x3.translate(x_offset, 200); + const scale = Mat2x3.scaleUniform((orca_size.y * 0.25) / gradient_size.y); + Mat2x3.push(Mat2x3.mul_m(trans, scale)); + defer Mat2x3.pop(); + + gradient_image.draw(oc.Rect.xywh(0, 0, gradient_size.x, gradient_size.y)); + } } surface.select(); @@ -231,3 +283,7 @@ fn fatal(err: anyerror, source: std.builtin.SourceLocation) noreturn { oc.abort("Caught fatal {}", .{err}, source); unreachable; } + +fn oneMinusLerp(a: anytype, b: anytype, t: anytype) @TypeOf(a, b, t) { + return 1.0 - lerp(a, b, t); +} diff --git a/src/orca.zig b/src/orca.zig index 081f820..f2ec80a 100644 --- a/src/orca.zig +++ b/src/orca.zig @@ -1596,12 +1596,12 @@ pub const Image = extern struct { extern fn oc_image_nil() Image; extern fn oc_image_is_nil(image: Image) bool; extern fn oc_image_create(surface: Surface, width: u32, height: u32) Image; - extern fn oc_image_create_from_rgba8(surface: Surface, width: u32, height: u32, pixels: [*]u8) Image; + extern fn oc_image_create_from_rgba8(surface: Surface, width: u32, height: u32, pixels: [*]const u8) Image; extern fn oc_image_create_from_memory(surface: Surface, mem: Str8, flip: bool) Image; extern fn oc_image_create_from_file(surface: Surface, file: File, flip: bool) Image; extern fn oc_image_create_from_path(surface: Surface, path: Str8, flip: bool) Image; extern fn oc_image_destroy(image: Image) void; - extern fn oc_image_upload_region_rgba8(image: Image, region: Rect, pixels: [*]u8) void; + extern fn oc_image_upload_region_rgba8(image: Image, region: Rect, pixels: [*]const u8) void; extern fn oc_image_size(image: Image) Vec2; extern fn oc_image_draw(image: Image, rect: Rect) void; extern fn oc_image_draw_region(image: Image, srcRegion: Rect, dstRegion: Rect) void; @@ -1638,14 +1638,24 @@ pub const Rect = extern union { } }; -pub const Color = extern union { - Flat: extern struct { - r: f32, - g: f32, - b: f32, - a: f32, - }, - Array: [4]f32, +pub const Color = extern struct { + r: f32 = 1.0, + g: f32 = 1.0, + b: f32 = 1.0, + a: f32 = 1.0, + + pub fn toArray(color: *Color) *[4]f32 { + return @ptrCast(color); + } + + pub fn toRgba8(color: *const Color) u32 { + var c: u32 = 0; + c |= @as(u32, @intFromFloat(color.r * 255.0)); + c |= @as(u32, @intFromFloat(color.g * 255.0)) << 8; + c |= @as(u32, @intFromFloat(color.b * 255.0)) << 16; + c |= @as(u32, @intFromFloat(color.a * 255.0)) << 24; + return c; + } }; //------------------------------------------------------------------------------------------