Import jonlib.bend as J for core operations and jonmath.bend as M for math
operations and shared vector/matrix types. See MODULES.md for the
ray* → jon* naming convention and import migration.
This is a source library for the Bend 2.0.27 base plus the compiler overlay in
toolchain.json. Helpers with further dotted suffixes
are implementation details; only operations listed here form this initial API.
Colors are U32 words in 0xRRGGBBAA order, matching raylib's GetColor and
the unsigned bit pattern returned by ColorToInt.
Color.rgba(r, g, b, a) -> U32: keeps the low eight bits of each U32 channel, equivalent to conversion to C unsigned bytes.Color.red/green/blue/alpha(color) -> U32: extract an 8-bit channel.Color.alpha_blend(destination, source, tint) -> U32: raylib's integerColorAlphaBlend, including 256-based tint and alpha rounding.Color.is_equal(left, right) -> Bool: exact RGBA equality.Color.with_alpha(color, factor) -> U32:ColorAlpha/Fade; finite factor clamped to 0..1, replacing alpha with the truncated255*factorvalue.Color.multiply(color, tint) -> U32:ColorTint's channel multiplication divided by 255, including alpha. The internal alpha-blend tint is different.Color.brightness(color, factor)andColor.contrast(color, factor): finite factors clamped to -1..1 with reference byte truncation; alpha is retained.Color.lerp(first, second, factor): straight RGBA interpolation with a finite factor clamped to 0..1; this does not perform alpha blending.Color.normalize(color) -> Vector4: exact reference RGBA normalization by 255.Color.from_normalized(vector) -> U32: finite RGBA components in 0..1, multiplied by 255 in F32 and truncated to bytes.Color.to_hsv(color) -> Vector3: hue in degrees, saturation and value in 0..1; ignores alpha and returns zero hue/saturation for achromatic colors.Color.from_hsv(hue, saturation, value) -> U32: hue 0..360 and saturation/value 0..1; preserves reference sector arithmetic and byte truncation, with alpha 255. Wider hue inputs remain outside this profile. RGB→HSV→RGB is not promised to recover every byte, because the reference itself rounds intermediate values.
The public scalar and Vector2 operations are listed in MATH.md, including their explicit uncontracted-F32 profile and remaining numeric gaps. Pure geometry queries are listed in COLLISION.md, including strict rectangle edges and inclusive circle tangency. Spline point queries and their explicit arithmetic profiles are listed in SPLINES.md. Owned random-stream APIs and their native rprand profile are described in RANDOM.md. Pixel sizing, raw byte/integer reads and writes, and packed dithering are documented in PIXELS.md. Owned byte/integer image conversion and Surface bridges are documented in FORMATS.md. Bounded raw DEFLATE and its reference-specific empty-block behavior are documented in DEFLATE.md. Native Base64 text, NUL-inclusive encoded sizes and bounded decoding are documented in BASE64.md. Bounded native CRC32 and four-word MD5 results are documented in CHECKSUMS.md. Native SHA-1/SHA-256 word lists, including the reference SHA-256 padding quirk, are documented in SHA.md. Bounded quality-8 raw compression, including empty-input and native sequence-limit behavior, is documented in COMPRESSION.md.
Vector2 is immutable Jonmath Data, constructed as M.Vector2{x, y} with F32 fields.
Reusable local constructor bindings need a type annotation, for example
+point = {M.Vector2{1.0, 2.0} : M.Vector2}.
Rectangle is Data with F32 x, y, width, height fields. The current
crop/extraction/region-drawing profile requires integral rectangle values;
draw_image_rect and the documented rectangle wrappers also support fractional fields.
M.Vector3{x, y, z} is immutable Data with three F32 fields.
M.Vector4{x, y, z, w} provides four immutable F32 fields.
J.BoundingBox{min, max} contains two M.Vector3 values; supplied bounds are retained
without reordering. Their numeric and collision operations are documented in
MATH.md and COLLISION.md.
Jonmath's M.Matrix contains 16 F32 fields in the reference declaration order; its layout,
identity/transpose operations and vector transforms are listed in MATH.md.
M.Matrix.Decomposition contains M.Decomposed{translation, rotation, scale} with
Vector3/Vector4/Vector3 fields, adapting the three distinct outputs of decomposition.
M.Float64{high, low} retains binary64 input bits for projection matrices;
M.Float64.from_f32 promotes existing F32 values. Precision and supported domains
are detailed in MATH.md.
Surface owns its row-major pixel array. Always start with Surface.create:
the underlying constructor is visible because Bend does not provide the needed
opaque user-type facility, but manually constructing an inconsistent surface
is outside this API's contract.
| Operation | Contract |
|---|---|
Surface.create(width, height, color) -> Maybe<Surface> |
Dimensions 1..4096 on each axis; otherwise None. Storage is rounded up to a power of two, with padding excluded from exports. |
Surface.create_checked(width, height, tile_width, tile_height, first, second) -> Maybe<Surface> |
Reference checkerboard generation. Dimensions 1..4096, checker sizes 1..2147483647; invalid values return None before allocation/division. |
Surface.create_white_noise(state, width, height, factor) -> Random.State & Maybe<Surface> |
Owned-stream RGBA8 white noise, dimensions 1..4096 and factor 0..1. Returns the advanced stream on success or the original stream with None on invalid input. |
Surface.create_cellular(state, width, height, tile_size) -> Random.State & Maybe<Surface> |
Owned-stream cellular RGBA8 generation; dimensions/tile size 1..4096. Rejected requests retain the original stream. Exact seed/distance rules are in CELLULAR.md. |
Surface.create_perlin(width, height, offset_x, offset_y, scale) / create_perlin_for(reference, ...) |
Six-octave RGBA8 Perlin noise returning Maybe; explicit fused/uncontracted profiles and bounded inputs. See PERLIN.md. |
Surface.create_text_bytes(width, height, bytes) -> Maybe<Surface> |
Grayscale data-image from bytes, stopping at NUL and padding/truncating to dimensions; opaque RGBA8 output. See PALETTES.md. |
Surface.create_gradient_square(width, height, density, inner, outer) -> Maybe<Surface> |
Square gradient with dimensions 1..4096 and finite density 0..1. Invalid requests return None; density one produces the inner color, matching the reference clamp behavior. |
Surface.create_gradient_radial(width, height, density, inner, outer) |
Same Maybe result, dimensions 1..4096 and density 0..1; reference radial RGBA interpolation with balanced generation. |
Surface.create_gradient_linear(width, height, direction, start, end) |
Same Maybe result; integral directions -360..360. Rejects invalid sizes/directions and a zero reference normalization extent. Wider-angle libm parity remains open; see GRADIENTS.md. |
Surface.create_gradient_linear_for(reference, width, height, direction, start, end) |
Jonmath's explicit M.Gradient.Reference: M.AccurateGradient{} or M.GnuGradient{}. Selects reference numerical behavior; see GRADIENTS.md. |
Surface.dimensions(surface) -> U32 & U32 |
Consumes a surface and returns its dimensions. |
Surface.clear(surface, color) -> Surface |
Replaces all pixels; preserves dimensions. |
Surface.get(surface, x, y) -> Surface & Maybe<&2, U32> |
Returns ownership and the pixel; out-of-bounds U32 coordinates return None, never wrap. |
Surface.draw_pixel(surface, x, y, color) -> Surface |
Replaces RGBA bytes at an in-bounds pixel; clips outside coordinates. |
Surface.draw_pixel_v(surface, position, color) |
Truncates bounded finite Vector2 coordinates before pixel clipping. |
Surface.draw_rectangle(surface, x, y, width, height, color) -> Surface |
Matches raylib 6.0 CPU ImageDrawRectangle for the declared integer-coordinate profile. |
Surface.draw_rectangle_v(surface, position, size, color) |
Truncates both vectors before drawing. |
Surface.draw_rectangle_rec(surface, rectangle, color) |
Clips bounded finite rectangle fields before converting pixel coordinates/extents to integers. |
Surface.draw_rectangle_lines(surface, rectangle, thickness, color) |
Four reference edge strips, including derived-coordinate truncation and degenerate behavior; thickness 0..32767. |
Surface.draw_circle(surface, cx, cy, radius, color) -> Surface |
Matches raylib 6.0 CPU ImageDrawCircle midpoint coverage; radius is U32. |
Surface.draw_circle_v(surface, center, radius, color) |
Truncates the bounded finite center before filled circle drawing. |
Surface.draw_circle_lines(surface, cx, cy, radius, color) / draw_circle_lines_v(surface, center, radius, color) |
Reference midpoint outlines, including radius zero and clipping. Vector centers are truncated. |
Surface.draw_line(surface, x0, y0, x1, y1, color) -> Surface |
Integral F32 endpoints; matches ImageDrawLine fixed-point stepping and excludes the final endpoint. A zero-length line draws nothing. |
Surface.draw_line_v(surface, start, end, color) -> Surface |
Vector2 endpoints; applies raylib's F32 coordinate + 0.5 followed by truncation toward zero before drawing. |
Surface.draw_line_ex(surface, start, end, thickness, color) |
Reference add-half/truncate endpoints, dominant-axis strips and even-thickness bias; thickness 0..32767. |
Surface.draw_triangle(surface, v1, v2, v3, color) -> Surface |
Integral Vector2 vertices; matches ImageDrawTriangle winding, inclusive edge tests, clipping and degenerate behavior. |
Surface.draw_triangle_lines(surface, v1, v2, v3, color) -> Surface |
Vector2 vertices truncated toward zero, then three reference-compatible line segments. |
Surface.draw_triangle_ex(surface, v1, v2, v3, c1, c2, c3) |
Reference coverage and byte-quantized barycentric color weights. Requires integral vertices, defined signed arithmetic and nonzero reference weight sum. |
Surface.draw_triangle_fan(surface, points, color) / draw_triangle_strip(surface, points, color) |
Immutable +List<Vector2> of integral vertices; reference vertex order/winding. Fewer than three points draws nothing. |
Surface.draw_image(destination, source, x, y, tint) -> Surface & Surface |
Full-source, unscaled RGBA8 drawing; clips destination placement, applies integer tint/alpha blending, returns destination then unchanged source. |
Surface.extract(surface, rectangle) -> Surface & Maybe<Surface> |
Retains the original; returns an independent region for positive integral in-bounds rectangles, otherwise None. |
Surface.crop(surface, rectangle) -> Result<&1, &1, Surface & Surface.Error, Surface> |
Clips an integral rectangle as raylib does; returns the cropped surface or the original with an error. An origin strictly beyond the right/bottom edge is the reference no-op. |
Surface.resize_nn(surface, width, height) -> Result<&1, &1, Surface & Surface.Error, Surface> |
Exact fixed-point nearest mapping; positive dimensions up to 4096; refuses out-of-allocation reference mappings. |
Surface.resize(surface, width, height) -> Result<&1, &1, Surface & Surface.Error, Surface> |
Default filtered RGBA8 resize; dimensions 1..4096; Catmull-Rom upsampling, Mitchell downsampling, clamp edges and alpha-aware filtering. Invalid sizes return the original owner with InvalidSize. |
Surface.resize_canvas(surface, width, height, offset_x, offset_y, fill) |
Same single-owner Result. Raw RGBA copy into a filled canvas; dimensions 1..4096, bounded integral offsets. Unchanged dimensions are a no-op. Changed sizes require positive overlap; invalid sizes/rectangles return the original owner. |
Surface.draw_image_region(destination, source, rectangle, x, y, tint) |
Returns Result<&1, &1, (Surface & Surface) & Surface.Error, Surface & Surface>; valid unscaled source subrectangles with integer placement, preserving both owners. |
Surface.draw_image_rect(destination, source, source_rectangle, destination_rectangle, tint) |
Same two-owner Result. Bounded finite rectangles, including fractional fields; source clipping, default filtered scaling and destination clipping follow reference order. Empty/invalid rectangles return both originals with InvalidRectangle. |
Surface.color_tint, color_invert, color_contrast, color_brightness, color_replace |
Owned RGBA8 transforms described below. |
Surface.color_grayscale(surface) -> Surface |
Reference luminance conversion with opaque grayscale RGBA8 output; alpha is discarded. See PALETTES.md. |
Surface.load_palette(surface, maximum) -> Surface & Maybe<Image.Palette> |
Preserves source; first-occurrence RGBA colors excluding alpha zero, with exact count and full padded capacity. Capacity 1..4096; access/disposal in PALETTES.md. |
Surface.dither(surface, r_bits, g_bits, b_bits, a_bits) |
Returns an owned Image.Packed16 or original source with InvalidDitherBits; channel widths 0..8 totaling at most 16. Exact raw format/export rules in PIXELS.md. |
Surface.alpha_clear(surface, color, threshold) |
Finite threshold 0..1, converted to an inclusive alpha-byte cutoff; replaces all RGBA bytes at matching pixels. |
Surface.alpha_premultiply(surface) |
Reference F32 alpha multiplication of RGB, including transparent-black conversion; retains alpha. |
Surface.blur_gaussian(surface, size) |
Native four-iteration RGBA8 box approximation with premultiplied alpha and per-pass byte truncation. U32 size 0..min(width,height); invalid sizes retain the original with InvalidSize. See BLUR.md. |
Surface.kernel_convolution(surface, kernel) |
Native bounded RGBA8 square-kernel filtering, flat-index edge behavior and unclamped alpha. Unsupported kernels/results retain the original with InvalidKernel. See CONVOLUTION.md. |
Surface.alpha_mask(destination, mask) |
Same-size RGBA8 mask converted to reference grayscale values, replacing destination alpha while preserving the original mask. Returns the two-owner Result; mismatched dimensions return both originals with InvalidSize. |
Surface.alpha_border(surface, threshold) -> Surface & Rectangle |
Retains the original and finds pixels with alpha strictly above the truncated threshold byte. Finite threshold 0..1; empty selections return (0,0,0,0). |
Surface.alpha_crop(surface, threshold) -> Surface |
Crops to nonempty alpha bounds; empty selections retain the original image and dimensions unchanged. |
Surface.colors(surface) -> List<U32> |
Consumes the image and exports exactly width × height packed pixels, row-major. |
Surface.copy(surface) -> Surface & Surface |
Returns the original and an independently owned pixel copy. |
Surface.mipmaps(surface) / Image.Mipmaps.entries/unload |
Consume RGBA8 into an owned base-to-1x1 chain using sequential default filtering; exact level counts, dimensions and pixels are documented in MIPMAPS.md. |
Surface.flip_horizontal/flip_vertical(surface) -> Surface |
Reorders whole RGBA pixels; dimensions and alpha bytes are preserved. |
Surface.rotate_cw(surface) / rotate_ccw(surface) |
Quarter-turn rotations preserving exact RGBA bytes and swapping width/height. |
Surface.rotate_degrees(surface, degrees) / rotate_degrees_for(reference, surface, degrees) |
Single-owner Result; integral degrees -360..360, reference bilinear sampling and truncated output dimensions. Invalid angles/output sizes preserve the original owner. See ROTATION.md. |
Surface.to_pot(surface, fill) |
Single-owner Result; raw canvas expansion to the next power-of-two dimensions, preserving the reference no-op for already-POT images. |
Surface.from_channel(surface, selected) -> Surface & Surface |
Returns the unchanged original, then an independent opaque grayscale RGBA8 image. Integral selectors in -32767..32767 clamp to 0..3 (RGBA). Equivalent to ImageFromChannel followed by RGBA8 normalization; native grayscale storage and other input formats remain gaps. |
Surface.to_image(surface) -> Image |
Consumes the surface and builds a Base.Image quadtree. RGB is retained, alpha discarded; padded regions are black. |
Surface.to_ppm(surface) -> String |
Consumes the surface and encodes P3 PPM text (RGB, alpha discarded). |
Surface.write_ppm(surface, path) -> IO(Result<&1, &1, U32 & String, Unit>) |
Writes P3 PPM through Base.File; returns open/write errors and closes the file after writing. |
Surface.decode_qoi, to_qoi, load_qoi, write_qoi |
QOI memory/file APIs, typed errors and RGBA8 normalization are specified in CODECS.md. |
Surface.load_image(path) |
Bounded PNG/BMP/TGA/PGM/PPM/QOI file loading with native supported suffix/content selection, closed handles and typed errors; see IMAGE-FILES.md. |
Surface.decode_image(file_type, bytes) |
Shared native-style memory dispatch for the implemented codec profiles, exact lower/upper-case extension tokens and typed decode errors; aliases and limits in IMAGE-FILES.md. |
Surface.decode_bmp, to_bmp, write_bmp |
CORE indexed/RGB24 plus 40/56/108/124-byte-header indexed, byte-color and 16/32-bit bitfield decoding; exact RGBA8 V4 export. Native rules in BMP.md. |
Surface.decode_tga, to_tga, write_tga |
Bounded raw/RLE direct/indexed decoding with native type/depth, RGB555 and palette behavior; byte-exact default RLE export. Formats and limits in TGA.md. |
Surface.decode_pnm |
Binary 8/16-bit P5/P6 decoding with native unscaled samples, little-endian 16-bit normalization and header parsing; see PNM.md. |
Surface.decode_psd |
Raw/PackBits RGB/alpha PSD planes with native depth interpretation, missing-channel defaults, uncontracted matte arithmetic and typed bounds; see PSD.md. |
Surface.decode_psd_for(reference, bytes) |
Raw/PackBits RGB/alpha PSD profiles with explicit fused/uncontracted white-matte arithmetic. decode_psd selects uncontracted; see PSD.md. |
Surface.decode_pic(bytes) |
Raw/pure-RLE/mixed-RLE Softimage PIC packets, native clipping/defaults/overwrite order and checked bounds; see PIC.md. |
Surface.decode_gif(bytes) |
First-frame GIF with in-canvas rectangles, interlacing, native background fills, palettes/transparency and bounded LZW; see GIF.md. |
Image.Animation.decode_gif(bytes, maximum_frames, maximum_pixels) |
Owned GIF frame sequence with caller budgets and native retain/restore disposal profiles; see GIF-ANIMATION.md. |
Image.Animation.decode_image(file_type, bytes, maximum_frames, maximum_pixels) / decode_image_for(reference, ...) |
Exact GIF-token sequence selection or one-frame profiled image fallback, retaining owned budgets and errors; see GIF-ANIMATION.md. |
Image.Animation.load_image(path, maximum_frames, maximum_pixels) / load_image_for(reference, ...) |
Bounded ordinary-file animation loading with case-insensitive GIF suffixes, static fallback, closed handles and typed file/decode errors; see GIF-ANIMATION.md. |
Image.Animation.entries(animation) / unload(animation) |
Consume the animation to return (width, height, count, List<Surface>) or dispose of the owned frames. |
Image.FloatRGB.decode_hdr(bytes) |
Owned raw/scanline-RLE Radiance RGBE data with exact native F32 bits, including subnormals; see HDR.md. |
Image.FloatRGB.load_hdr(path) |
Explicit HDR file selection, 1 MiB byte cap, complete reads, closed handles and typed errors; returns owned RGB float pixels. See HDR.md. |
Image.FloatRGB.entries(image) / unload(image) |
Consume a float image to return (width, height, List<M.Vector3>) or dispose of its owned pixels. |
Surface.to_float_rgb(surface) / Image.FloatRGB.to_surface(image) |
Native format-7/9 RGB normalization and checked opaque RGBA8 conversion. Rejection returns the original float owner; see FLOAT-RGB.md. |
Image.FloatRGB.from_bytes(width, height, bytes) / to_bytes(image) |
Exact non-NaN little-endian format-9 words, checked dimensions/lengths and rejected-owner preservation; see FLOAT-RGB-BYTES.md. |
Image.FloatRGB.copy(image) |
Returns the original float owner and an independent clone. See FLOAT-RGB.md. |
Image.FloatRGB.flip_horizontal/flip_vertical/rotate_cw/rotate_ccw |
Consume the float owner and preserve exact sample words; quarter-turns swap dimensions. See FLOAT-RGB.md. |
Image.FloatRGB.extract(image, rect) / crop(image, rect) |
Independent integral regions or clipped crops with exact sample words and retained rejected owners; see FLOAT-RGB.md. |
Image.FloatRGB.resize_nn(image, width, height) |
Native format-9 RGBA8-quantized nearest resizing with retained original owners on unsupported samples/sizes/mappings; see FLOAT-RGB.md. |
Image.FloatRGB.resize(image, width, height) |
Native format-9 RGBA8-quantized default filtering with retained owners; see FLOAT-RGB.md. |
Image.FloatRGB.resize_canvas(image, width, height, x, y, fill) / to_pot(image, fill) |
Native lossless movement, ignored float-format fill color, bounded offsets and retained rejected owners; see FLOAT-RGB.md. |
Image.FloatRGB.color_tint/color_invert/color_contrast/color_brightness/color_replace |
Native format-9 byte-quantized color paths with preserved rejected owners; see FLOAT-RGB.md. |
Image.FloatRGB.to_formatted(image, target) / color_grayscale(image) |
Direct native normalized conversion to formats 1..7, or grayscale format 1, retaining rejected float owners; see FLOAT-RGB.md. |
Image.Formatted.to_float_rgb(image) |
Consume formats 1..7 into native normalized RGB float storage, preserving packed-channel precision and dropping alpha; see FLOAT-RGB.md. |
Image.Formatted.from_channel(image, selected) / Image.FloatRGB.from_channel(image, selected) |
Retain the source and return an independent native grayscale channel with format-specific selector rules; see IMAGE-CHANNELS.md. |
Image.Formatted.colors/get / Image.FloatRGB.colors/get |
Native bulk and point RGBA observations with packed integer expansion, float truncation and retained point/error owners; see IMAGE-COLORS.md. |
Image.FloatRGB.load_raw(path, width, height, header_size) / write_raw(image, path) |
Native RAW header selection and exact non-NaN RGB words; typed load/write errors, closed handles and retained owners on NaN write rejection. See RAW-FILES.md. |
Surface.decode_image_for(reference, file_type, bytes) / Surface.load_image_for(reference, path) |
Shared dispatch with J.Image.Decode.Reference; affects PSD matte arithmetic and retains existing bounds/error/closure behavior. Convenience calls select J.UncontractedDecode{}. |
Surface.decode_png |
Bounded non-interlaced/Adam7 PNG and native-default CgBI decoding at supported 1/2/4/8/16-bit combinations; filtering, transparency and normalization in PNG.md. |
Surface.to_png, write_png |
Consuming RGBA8 memory/file exports with byte-exact native default filtering, quality-8 compression and checksums; see PNG-EXPORT.md. |
Image.Formatted.to_png |
Consuming PNG memory export preserving byte-format 1/2/3/4-channel data; unsupported packed formats return the original owner. See PNG-EXPORT.md. |
Image.Formatted.write_png |
Consuming PNG file export for checked formats 1..7, with native byte-channel or packed-color expansion; see PNG-EXPORT.md. |
Image.FloatRGB.to_png / write_png |
Preserve native raw-prefix memory PNG versus normalized-color file PNG, with retained rejected owners and typed file errors; see PNG-EXPORT.md. |
Image.FloatRGB.to_bmp/to_tga / write_bmp/write_tga |
Native normalized BMP/TGA file bytes and explicit typed writers, preserving rejected owners; see FLOAT-RASTER-EXPORT.md. |
Image.Formatted.to_code(image, path) / write_code(image, path) |
Exact native image-as-code text, basename/hex/newline rules and typed owner-preserving failures; see IMAGE-CODE.md. |
Image.FloatRGB.to_code(image, path) / write_code(image, path) |
Native format-9 image-as-code text from exact non-NaN sample bytes, bounded paths/payloads and typed owner-preserving failures; see IMAGE-CODE.md. |
Drawing coordinates and rectangle extents are represented as F32 but must be
finite integers in -32767..32767. Radius is 0..32767. This permits negative
positions while Bend has no native signed integer type. The vector wrappers,
draw_rectangle_rec, draw_rectangle_lines and draw_image_rect accept bounded
finite fractional fields with the conversion rules above. Filled triangle
vertices remain integral. NaN/infinity and larger values are outside the drawing profile.
Surface operations do not promise successful allocation when the process runs
out of memory; Bend's runtime treats allocation failure as fatal.
Line stepping uses a signed 16.16 short-axis increment. The short-axis endpoint delta must fit -32767..32767 after vector conversion. Triangle stepping uses signed 32-bit edge words, seeded with the reference F32 expressions. The supported contract requires the reference's integer calculations/conversions to be defined; the finite fixture suite does not establish every floating-point/compiler edge case.
ImageDraw* operations replace bytes, including alpha. They do not implicitly
perform source-over blending. Applying an alpha-zero pixel can therefore leave
nonzero RGB with zero alpha, exactly as in the reference image operation.
Raylib 6.0's accepted zero-width rectangles can still write their initial pixel; zero-height rectangles can write their first row. Position/clipping conditions also affect this behavior. Jonlib deliberately matches these observable CPU image semantics, including their effect on radius-zero and circle scanlines. These rules are covered by reference fixtures and are not generic mathematical rectangle/circle definitions.
draw_line omits its final endpoint, as raylib 6.0 does. Reversing a segment can
therefore change which end pixel is written. Negative short-axis increments use
arithmetic right-shift behavior, rather than truncating the interpolated position.
The vector-line API's add-half/truncate rule also differs from ordinary rounding
for negative values.
Filled triangle edges are stepped as integer words after their initial F32 calculation. Both windings are supported. A degenerate triangle is processed by the same edge rules as raylib; it is not automatically discarded.
Unlike the byte-replacing primitive draws, draw_image performs source-over
composition through raylib's integer ColorAlphaBlend rules. Destination and
source must be separately owned surfaces. Both are returned; the source's pixels
are unchanged and can be used for another draw. Use Surface.copy when a distinct
copy is needed.
This is a partial ImageDraw profile: RGBA8 and one mip level. The
draw_image_rect path clips source fields first, compares truncated extents to
decide whether to resize, then clips the destination before truncating pixel
indices/counts. It accepts fractional rectangles when the clipped source has at
least one pixel and truncated destination dimensions are 1..4096. The original
source remains unchanged, including when a temporary resized region is used.
Other formats, mipmaps, empty/undefined reference rectangles and full target/
performance coverage remain gaps.
Nearest-neighbor scaling is a separate API and is not substituted for raylib's
default ImageResize filtering behavior. See RESAMPLING.md.
Surface.resize provides that default filtered path separately. It retains
unweighted RGB alongside alpha-weighted RGB during filtering, preserving the
reference treatment of fully transparent colors. The numeric helpers in src/
are internal; they do not add a general-purpose F64 API. The implementation is
a correctness-oriented RGBA8 profile with an intermediate seven-channel image;
it does not claim the reference resizer's memory use or performance.
color_tint(surface, color) uses integer channel products divided by 255.
color_invert(surface) inverts RGB and retains alpha.
color_contrast(surface, amount) uses finite F32 contrast clamped to -100..100.
color_brightness(surface, amount) takes a finite integral F32 adjustment,
clamped to -255..255. Its negative channel underflow becomes 1, matching
the pinned reference; an exact zero remains zero. Both retain alpha.
color_replace(surface, original, replacement) matches all four bytes.
Alpha bounds use alpha > trunc(threshold*255), whereas alpha clearing uses
alpha <= trunc(threshold*255). A threshold of one therefore selects no pixels
for bounds/cropping. Canvas resizing copies RGBA bytes without blending, including
hidden RGB under zero alpha. It differs from ordinary resize: equal dimensions
ignore the offset and fill, as in the reference. Changed-size requests without
positive overlap return InvalidRectangle; some corresponding C calls have
negative copy sizes or invalid pointer arithmetic and remain outside the profile.
Vertex-colored triangles quantize each barycentric weight to a byte before
interpolating RGBA. This can darken interior pixels even when vertex colors are
equal; use draw_triangle for the reference flat-color operation. Degenerate
gradient triangles are excluded because the reference divides by zero and then
converts non-finite weights to bytes. Flat triangles retain their existing
degenerate behavior.
Surface.Error has InvalidSize, InvalidRectangle, UnsafeNearestMapping,
InvalidDitherBits and InvalidKernel constructors. Failed crop/resize/dither,
blur or convolution returns (original, error) in Fail; failed
region drawing returns ((destination, source), error). Callers can recover and
reuse these owners. Done carries the resulting surface or pair.
The current Surface invariant excludes zero-sized images. Empty crop results
therefore return an error. ImageFromImage has no clipping in raylib; extraction
requires an in-bounds rectangle here. Region drawing rejects out-of-bounds source
rectangles; callers wanting clipping/scaling use draw_image_rect.
Every drawing call consumes its input surface and returns the updated surface.
Do not reuse the previous handle. Surface.get returns a pair; destructure its
computed result through a typed helper parameter, following Bend's rules.
LAWS.bend/PROOF.bend establish that clearing preserves dimensions, transposing
a Matrix twice returns the original value, and Vector3/Matrix float-list exports
contain exactly 3/16 elements. Full-pixel and numeric tests establish the
exercised reference behaviors. These proofs and tests do not establish that all
rendering, allocation, hardware or compiler behavior is formally proven.
to_image currently builds a complete power-of-two quadtree. to_ppm builds
the complete output string in memory. These are correct small-image adapters;
large real-time frames and streaming encoders need later performance work.