font/sprite: replace pixman with z2d, extend Box coverage

More complete coverage of the Symbols For Legacy Computing block,
including characters from Unicode 16.0.

Pixman and the web canvas impl for Canvas have been removed in favor of
z2d for drawing, since it has a nicer API with more powerful methods,
and is in Zig with no specific platform optimizations so should compile
to wasm no problem.
This commit is contained in:
Qwerasd
2024-10-09 19:31:13 -04:00
parent c86b5f44ce
commit d38d0f30c4
115 changed files with 1029 additions and 68180 deletions

View File

@@ -1,122 +0,0 @@
const std = @import("std");
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const module = b.addModule("pixman", .{ .root_source_file = b.path("main.zig") });
const upstream = b.dependency("pixman", .{});
const lib = b.addStaticLibrary(.{
.name = "pixman",
.target = target,
.optimize = optimize,
});
lib.linkLibC();
if (target.result.os.tag != .windows) {
lib.linkSystemLibrary("pthread");
}
if (target.result.isDarwin()) {
const apple_sdk = @import("apple_sdk");
try apple_sdk.addPaths(b, &lib.root_module);
}
lib.addIncludePath(upstream.path(""));
lib.addIncludePath(b.path(""));
module.addIncludePath(upstream.path("pixman"));
module.addIncludePath(b.path(""));
var flags = std.ArrayList([]const u8).init(b.allocator);
defer flags.deinit();
try flags.appendSlice(&.{
"-DHAVE_SIGACTION=1",
"-DHAVE_ALARM=1",
"-DHAVE_MPROTECT=1",
"-DHAVE_GETPAGESIZE=1",
"-DHAVE_MMAP=1",
"-DHAVE_GETISAX=1",
"-DHAVE_GETTIMEOFDAY=1",
"-DHAVE_FENV_H=1",
"-DHAVE_SYS_MMAN_H=1",
"-DHAVE_UNISTD_H=1",
"-DSIZEOF_LONG=8",
"-DPACKAGE=foo",
// There is ubsan
"-fno-sanitize=undefined",
"-fno-sanitize-trap=undefined",
});
if (!(target.result.os.tag == .windows)) {
try flags.appendSlice(&.{
"-DHAVE_PTHREADS=1",
"-DHAVE_POSIX_MEMALIGN=1",
});
}
lib.addCSourceFiles(.{
.root = upstream.path(""),
.files = srcs,
.flags = flags.items,
});
lib.installHeader(b.path("pixman-version.h"), "pixman-version.h");
lib.installHeadersDirectory(
upstream.path("pixman"),
"",
.{ .include_extensions = &.{".h"} },
);
b.installArtifact(lib);
if (target.query.isNative()) {
const test_exe = b.addTest(.{
.name = "test",
.root_source_file = b.path("main.zig"),
.target = target,
.optimize = optimize,
});
test_exe.linkLibrary(lib);
var it = module.import_table.iterator();
while (it.next()) |entry| test_exe.root_module.addImport(entry.key_ptr.*, entry.value_ptr.*);
const tests_run = b.addRunArtifact(test_exe);
const test_step = b.step("test", "Run tests");
test_step.dependOn(&tests_run.step);
}
}
const srcs: []const []const u8 = &.{
"pixman/pixman.c",
"pixman/pixman-access.c",
"pixman/pixman-access-accessors.c",
"pixman/pixman-bits-image.c",
"pixman/pixman-combine32.c",
"pixman/pixman-combine-float.c",
"pixman/pixman-conical-gradient.c",
"pixman/pixman-filter.c",
"pixman/pixman-x86.c",
"pixman/pixman-mips.c",
"pixman/pixman-arm.c",
"pixman/pixman-ppc.c",
"pixman/pixman-edge.c",
"pixman/pixman-edge-accessors.c",
"pixman/pixman-fast-path.c",
"pixman/pixman-glyph.c",
"pixman/pixman-general.c",
"pixman/pixman-gradient-walker.c",
"pixman/pixman-image.c",
"pixman/pixman-implementation.c",
"pixman/pixman-linear-gradient.c",
"pixman/pixman-matrix.c",
"pixman/pixman-noop.c",
"pixman/pixman-radial-gradient.c",
"pixman/pixman-region16.c",
"pixman/pixman-region32.c",
"pixman/pixman-solid-fill.c",
//"pixman/pixman-timer.c",
"pixman/pixman-trap.c",
"pixman/pixman-utils.c",
};

View File

@@ -1,13 +0,0 @@
.{
.name = "pixman",
.version = "0.42.2",
.paths = .{""},
.dependencies = .{
.pixman = .{
.url = "https://deps.files.ghostty.dev/pixman-pixman-0.42.2.tar.gz",
.hash = "12209b9206f9a5d31ccd9a2312cc72cb9dfc3e034aee1883c549dc1d753fae457230",
},
.apple_sdk = .{ .path = "../apple-sdk" },
},
}

View File

@@ -1,3 +0,0 @@
pub const c = @cImport({
@cInclude("pixman.h");
});

View File

@@ -1,4 +0,0 @@
pub const Error = error{
// Pixman doesn't really have errors so we just have a single error.
PixmanFailure,
};

View File

@@ -1,118 +0,0 @@
const std = @import("std");
const c = @import("c.zig").c;
const pixman = @import("main.zig");
pub const FormatCode = enum(c_uint) {
// 128bpp formats
rgba_float = c.PIXMAN_FORMAT_BYTE(128, c.PIXMAN_TYPE_RGBA_FLOAT, 32, 32, 32, 32),
// 96bpp formats
rgb_float = c.PIXMAN_FORMAT_BYTE(96, c.PIXMAN_TYPE_RGBA_FLOAT, 0, 32, 32, 32),
// 32bpp formats
a8r8g8b8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ARGB, 8, 8, 8, 8),
x8r8g8b8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ARGB, 0, 8, 8, 8),
a8b8g8r8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ABGR, 8, 8, 8, 8),
x8b8g8r8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ABGR, 0, 8, 8, 8),
b8g8r8a8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_BGRA, 8, 8, 8, 8),
b8g8r8x8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_BGRA, 0, 8, 8, 8),
r8g8b8a8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_RGBA, 8, 8, 8, 8),
r8g8b8x8 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_RGBA, 0, 8, 8, 8),
x14r6g6b6 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ARGB, 0, 6, 6, 6),
x2r10g10b10 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ARGB, 0, 10, 10, 10),
a2r10g10b10 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ARGB, 2, 10, 10, 10),
x2b10g10r10 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ABGR, 0, 10, 10, 10),
a2b10g10r10 = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ABGR, 2, 10, 10, 10),
// sRGB formats
a8r8g8b8_sRGB = c.PIXMAN_FORMAT(32, c.PIXMAN_TYPE_ARGB_SRGB, 8, 8, 8, 8),
r8g8b8_sRGB = c.PIXMAN_FORMAT(24, c.PIXMAN_TYPE_ARGB_SRGB, 0, 8, 8, 8),
// 24bpp formats
r8g8b8 = c.PIXMAN_FORMAT(24, c.PIXMAN_TYPE_ARGB, 0, 8, 8, 8),
b8g8r8 = c.PIXMAN_FORMAT(24, c.PIXMAN_TYPE_ABGR, 0, 8, 8, 8),
// 16bpp formats
r5g6b5 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ARGB, 0, 5, 6, 5),
b5g6r5 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ABGR, 0, 5, 6, 5),
a1r5g5b5 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ARGB, 1, 5, 5, 5),
x1r5g5b5 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ARGB, 0, 5, 5, 5),
a1b5g5r5 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ABGR, 1, 5, 5, 5),
x1b5g5r5 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ABGR, 0, 5, 5, 5),
a4r4g4b4 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ARGB, 4, 4, 4, 4),
x4r4g4b4 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ARGB, 0, 4, 4, 4),
a4b4g4r4 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ABGR, 4, 4, 4, 4),
x4b4g4r4 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_ABGR, 0, 4, 4, 4),
// 8bpp formats
a8 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_A, 8, 0, 0, 0),
r3g3b2 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_ARGB, 0, 3, 3, 2),
b2g3r3 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_ABGR, 0, 3, 3, 2),
a2r2g2b2 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_ARGB, 2, 2, 2, 2),
a2b2g2r2 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_ABGR, 2, 2, 2, 2),
c8 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_COLOR, 0, 0, 0, 0),
g8 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_GRAY, 0, 0, 0, 0),
x4a4 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_A, 4, 0, 0, 0),
// c8/g8 equivalent
// x4c4 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_COLOR, 0, 0, 0, 0),
// x4g4 = c.PIXMAN_FORMAT(8, c.PIXMAN_TYPE_GRAY, 0, 0, 0, 0),
// 4bpp formats
a4 = c.PIXMAN_FORMAT(4, c.PIXMAN_TYPE_A, 4, 0, 0, 0),
r1g2b1 = c.PIXMAN_FORMAT(4, c.PIXMAN_TYPE_ARGB, 0, 1, 2, 1),
b1g2r1 = c.PIXMAN_FORMAT(4, c.PIXMAN_TYPE_ABGR, 0, 1, 2, 1),
a1r1g1b1 = c.PIXMAN_FORMAT(4, c.PIXMAN_TYPE_ARGB, 1, 1, 1, 1),
a1b1g1r1 = c.PIXMAN_FORMAT(4, c.PIXMAN_TYPE_ABGR, 1, 1, 1, 1),
c4 = c.PIXMAN_FORMAT(4, c.PIXMAN_TYPE_COLOR, 0, 0, 0, 0),
g4 = c.PIXMAN_FORMAT(4, c.PIXMAN_TYPE_GRAY, 0, 0, 0, 0),
// 1bpp formats
a1 = c.PIXMAN_FORMAT(1, c.PIXMAN_TYPE_A, 1, 0, 0, 0),
g1 = c.PIXMAN_FORMAT(1, c.PIXMAN_TYPE_GRAY, 0, 0, 0, 0),
// YUV formats
yuy2 = c.PIXMAN_FORMAT(16, c.PIXMAN_TYPE_YUY2, 0, 0, 0, 0),
yv12 = c.PIXMAN_FORMAT(12, c.PIXMAN_TYPE_YV12, 0, 0, 0, 0),
pub inline fn bpp(self: FormatCode) u32 {
return self.reshift(24, 8);
}
/// Calculates a valid stride for the bpp and width. Based on Cairo.
pub fn strideForWidth(self: FormatCode, width: u32) c_int {
const alignment = @sizeOf(u32);
const val = @as(c_int, @intCast((self.bpp() * width + 7) / 8));
return val + (alignment - 1) & -alignment;
}
// Converted from pixman.h
fn reshift(self: FormatCode, ofs: u5, num: u5) u32 {
const val = @intFromEnum(self);
const v1 = val >> ofs;
const v2 = @as(c_uint, 1) << num;
const v3 = @as(u5, @intCast((val >> 22) & 3));
return ((v1 & (v2 - 1)) << v3);
}
};
test "bpp" {
const testing = std.testing;
try testing.expectEqual(@as(u32, 1), FormatCode.g1.bpp());
try testing.expectEqual(@as(u32, 4), FormatCode.g4.bpp());
try testing.expectEqual(@as(u32, 8), FormatCode.g8.bpp());
}
test "stride" {
const testing = std.testing;
try testing.expectEqual(@as(c_int, 4), FormatCode.g1.strideForWidth(10));
try testing.expectEqual(@as(c_int, 8), FormatCode.g4.strideForWidth(10));
try testing.expectEqual(@as(c_int, 12), FormatCode.g8.strideForWidth(10));
}

View File

@@ -1,211 +0,0 @@
const std = @import("std");
const c = @import("c.zig").c;
const pixman = @import("main.zig");
pub const Image = opaque {
pub fn createBitsNoClear(
format: pixman.FormatCode,
width: c_int,
height: c_int,
bits: [*]u32,
stride: c_int,
) pixman.Error!*Image {
return @as(?*Image, @ptrCast(c.pixman_image_create_bits_no_clear(
@intFromEnum(format),
width,
height,
bits,
stride,
))) orelse return pixman.Error.PixmanFailure;
}
pub fn createSolidFill(
color: pixman.Color,
) pixman.Error!*Image {
return @as(?*Image, @ptrCast(c.pixman_image_create_solid_fill(
@ptrCast(&color),
))) orelse return pixman.Error.PixmanFailure;
}
pub fn unref(self: *Image) bool {
return c.pixman_image_unref(@ptrCast(self)) == 1;
}
/// A variant of getDataUnsafe that sets the length of the slice to
/// height * stride. Its possible the buffer is larger but this is the
/// known safe values. If you KNOW the buffer is larger you can use the
/// unsafe variant.
pub fn getData(self: *Image) []u32 {
const height = self.getHeight();
const stride = self.getStride();
const ptr = self.getDataUnsafe();
const len = @as(usize, @intCast(height * stride));
return ptr[0..len];
}
pub fn getDataUnsafe(self: *Image) [*]u32 {
return c.pixman_image_get_data(@ptrCast(self));
}
pub fn getHeight(self: *Image) c_int {
return c.pixman_image_get_height(@ptrCast(self));
}
pub fn getWidth(self: *Image) c_int {
return c.pixman_image_get_width(@ptrCast(self));
}
pub fn getStride(self: *Image) c_int {
return c.pixman_image_get_stride(@ptrCast(self));
}
pub fn fillBoxes(
self: *Image,
op: pixman.Op,
color: pixman.Color,
boxes: []const pixman.Box32,
) pixman.Error!void {
if (c.pixman_image_fill_boxes(
@intFromEnum(op),
@ptrCast(self),
@ptrCast(&color),
@intCast(boxes.len),
@ptrCast(boxes.ptr),
) == 0) return pixman.Error.PixmanFailure;
}
pub fn fillRectangles(
self: *Image,
op: pixman.Op,
color: pixman.Color,
rects: []const pixman.Rectangle16,
) pixman.Error!void {
if (c.pixman_image_fill_rectangles(
@intFromEnum(op),
@ptrCast(self),
@ptrCast(&color),
@intCast(rects.len),
@ptrCast(rects.ptr),
) == 0) return pixman.Error.PixmanFailure;
}
pub fn rasterizeTrapezoid(
self: *Image,
trap: pixman.Trapezoid,
x_off: c_int,
y_off: c_int,
) void {
c.pixman_rasterize_trapezoid(
@ptrCast(self),
@ptrCast(&trap),
x_off,
y_off,
);
}
pub fn composite(
self: *Image,
op: pixman.Op,
src: *Image,
mask: ?*Image,
src_x: i16,
src_y: i16,
mask_x: i16,
mask_y: i16,
dest_x: i16,
dest_y: i16,
width: u16,
height: u16,
) void {
c.pixman_image_composite(
@intFromEnum(op),
@ptrCast(src),
@ptrCast(mask),
@ptrCast(self),
src_x,
src_y,
mask_x,
mask_y,
dest_x,
dest_y,
width,
height,
);
}
pub fn compositeTriangles(
self: *Image,
op: pixman.Op,
src: *Image,
mask_format: pixman.FormatCode,
x_src: c_int,
y_src: c_int,
x_dst: c_int,
y_dst: c_int,
tris: []const pixman.Triangle,
) void {
c.pixman_composite_triangles(
@intFromEnum(op),
@ptrCast(src),
@ptrCast(self),
@intFromEnum(mask_format),
x_src,
y_src,
x_dst,
y_dst,
@intCast(tris.len),
@ptrCast(tris.ptr),
);
}
};
test "create and destroy" {
const testing = std.testing;
const alloc = testing.allocator;
const width = 10;
const height = 10;
const format: pixman.FormatCode = .g1;
const stride = format.strideForWidth(width);
const len = height * @as(usize, @intCast(stride));
const data = try alloc.alloc(u32, len);
defer alloc.free(data);
@memset(data, 0);
const img = try Image.createBitsNoClear(.g1, width, height, data.ptr, stride);
try testing.expectEqual(@as(c_int, height), img.getHeight());
try testing.expectEqual(@as(c_int, stride), img.getStride());
try testing.expect(img.getData().len == height * stride);
try testing.expect(img.unref());
}
test "fill boxes a1" {
const testing = std.testing;
const alloc = testing.allocator;
// Dimensions
const width = 100;
const height = 100;
const format: pixman.FormatCode = .a1;
const stride = format.strideForWidth(width);
// Image
const len = height * @as(usize, @intCast(stride));
const data = try alloc.alloc(u32, len);
defer alloc.free(data);
@memset(data, 0);
const img = try Image.createBitsNoClear(format, width, height, data.ptr, stride);
defer _ = img.unref();
// Fill
const color: pixman.Color = .{ .red = 0xFFFF, .green = 0xFFFF, .blue = 0xFFFF, .alpha = 0xFFFF };
const boxes = &[_]pixman.Box32{
.{
.x1 = 0,
.y1 = 0,
.x2 = width,
.y2 = height,
},
};
try img.fillBoxes(.src, color, boxes);
}

View File

@@ -1,23 +0,0 @@
const std = @import("std");
const format = @import("format.zig");
const image = @import("image.zig");
const types = @import("types.zig");
pub const c = @import("c.zig").c;
pub const Color = types.Color;
pub const Error = @import("error.zig").Error;
pub const Fixed = types.Fixed;
pub const FormatCode = format.FormatCode;
pub const Image = image.Image;
pub const Op = types.Op;
pub const PointFixed = types.PointFixed;
pub const LineFixed = types.LineFixed;
pub const Triangle = types.Triangle;
pub const Trapezoid = types.Trapezoid;
pub const Rectangle16 = types.Rectangle16;
pub const Box32 = types.Box32;
pub const Indexed = types.Indexed;
test {
std.testing.refAllDecls(@This());
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright © 2008 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Author: Carl D. Worth <cworth@cworth.org>
*/
#ifndef PIXMAN_VERSION_H__
#define PIXMAN_VERSION_H__
#ifndef PIXMAN_H__
# error pixman-version.h should only be included by pixman.h
#endif
#define PIXMAN_VERSION_MAJOR 999
#define PIXMAN_VERSION_MINOR 999
#define PIXMAN_VERSION_MICRO 999
#define PIXMAN_VERSION_STRING "999.999.999"
#define PIXMAN_VERSION_ENCODE(major, minor, micro) ( \
((major) * 10000) \
+ ((minor) * 100) \
+ ((micro) * 1))
#define PIXMAN_VERSION PIXMAN_VERSION_ENCODE( \
PIXMAN_VERSION_MAJOR, \
PIXMAN_VERSION_MINOR, \
PIXMAN_VERSION_MICRO)
#ifndef PIXMAN_API
# define PIXMAN_API
#endif
#endif /* PIXMAN_VERSION_H__ */

View File

@@ -1,131 +0,0 @@
const std = @import("std");
const c = @import("c.zig").c;
const pixman = @import("main.zig");
pub const Op = enum(c_uint) {
clear = 0x00,
src = 0x01,
dst = 0x02,
over = 0x03,
over_reverse = 0x04,
in = 0x05,
in_reverse = 0x06,
out = 0x07,
out_reverse = 0x08,
atop = 0x09,
atop_reverse = 0x0a,
xor = 0x0b,
add = 0x0c,
saturate = 0x0d,
disjoint_clear = 0x10,
disjoint_src = 0x11,
disjoint_dst = 0x12,
disjoint_over = 0x13,
disjoint_over_reverse = 0x14,
disjoint_in = 0x15,
disjoint_in_reverse = 0x16,
disjoint_out = 0x17,
disjoint_out_reverse = 0x18,
disjoint_atop = 0x19,
disjoint_atop_reverse = 0x1a,
disjoint_xor = 0x1b,
conjoint_clear = 0x20,
conjoint_src = 0x21,
conjoint_dst = 0x22,
conjoint_over = 0x23,
conjoint_over_reverse = 0x24,
conjoint_in = 0x25,
conjoint_in_reverse = 0x26,
conjoint_out = 0x27,
conjoint_out_reverse = 0x28,
conjoint_atop = 0x29,
conjoint_atop_reverse = 0x2a,
conjoint_xor = 0x2b,
multiply = 0x30,
screen = 0x31,
overlay = 0x32,
darken = 0x33,
lighten = 0x34,
color_dodge = 0x35,
color_burn = 0x36,
hard_light = 0x37,
soft_light = 0x38,
difference = 0x39,
exclusion = 0x3a,
hsl_hue = 0x3b,
hsl_saturation = 0x3c,
hsl_color = 0x3d,
hsl_luminosity = 0x3e,
};
pub const Color = extern struct {
red: u16,
green: u16,
blue: u16,
alpha: u16,
};
pub const Fixed = enum(i32) {
_,
pub fn init(v: anytype) Fixed {
return switch (@TypeOf(v)) {
comptime_int, i32, u32 => @enumFromInt(v << 16),
f64 => @enumFromInt(@as(i32, @intFromFloat(v * 65536))),
else => {
@compileLog(@TypeOf(v));
@compileError("unsupported type");
},
};
}
};
pub const PointFixed = extern struct {
x: Fixed,
y: Fixed,
};
pub const LineFixed = extern struct {
p1: PointFixed,
p2: PointFixed,
};
pub const Triangle = extern struct {
p1: PointFixed,
p2: PointFixed,
p3: PointFixed,
};
pub const Trapezoid = extern struct {
top: Fixed,
bottom: Fixed,
left: LineFixed,
right: LineFixed,
};
pub const Rectangle16 = extern struct {
x: i16,
y: i16,
width: u16,
height: u16,
};
pub const Box32 = extern struct {
x1: i32,
y1: i32,
x2: i32,
y2: i32,
};
pub const Indexed = extern struct {
color: bool,
rgba: [256]u32,
ent: [32768]u8,
};
test {
std.testing.refAllDecls(@This());
}