diff --git a/wasm/ctx2d/ctx2d.js b/wasm/ctx2d/ctx2d.js index 375ad25..c48d8d2 100644 --- a/wasm/ctx2d/ctx2d.js +++ b/wasm/ctx2d/ctx2d.js @@ -9,25 +9,89 @@ export function Ctx2d_State() { } /** @type {Record} */ -const CANVAS_FILL_RULE = { +const FILL_RULE = { 0: "nonzero", 1: "evenodd", } /** @type {Record} */ -const CANVAS_LINE_CAP = { +const LINE_CAP = { 0: "butt", 1: "round", 2: "square", } /** @type {Record} */ -const CANVAS_LINE_JOIN = { +const LINE_JOIN = { 0: "miter", 1: "round", 2: "bevel", } +/** @type {Record} */ +const DIRECTION = { + 0: "inherit", + 1: "ltr", + 2: "rtl", +} + +/** @type {Record} */ +const FONT_KERNING = { + 0: "auto", + 1: "none", + 2: "normal", +} + +/** @type {Record} */ +const FONT_STRETCH = { + 0: "normal", + 1: "ultra-condensed", + 2: "extra-condensed", + 3: "condensed", + 4: "semi-condensed", + 5: "semi-expanded", + 6: "expanded", + 7: "extra-expanded", + 8: "ultra-expanded", +} + +/** @type {Record} */ +const FONT_VARIANT_CAPS = { + 0: "normal", + 1: "petite-caps", + 2: "all-petite-caps", + 3: "small-caps", + 4: "all-small-caps", + 5: "titling-caps", + 6: "unicase", +} + +/** @type {Record} */ +const TEXT_ALIGN = { + 0: "start", + 1: "end", + 2: "left", + 3: "right", + 4: "center", +} + +/** @type {Record} */ +const TEXT_BASELINE = { + 0: "alphabetic", + 1: "top", + 2: "hanging", + 3: "middle", + 4: "ideographic", + 5: "bottom", +} + +/** @type {Record} */ +const TEXT_RENDERING = { + 0: "auto", + 1: "optimizeSpeed", + 2: "optimizeLegibility", + 3: "geometricPrecision", +} /** * @param {Wasm_State} wasm @@ -110,7 +174,7 @@ export function make_odin_ctx2d(wasm, s) { clip( /** @type {number} */ fill_rule, ) { - s.ctx.clip(CANVAS_FILL_RULE[fill_rule]); + s.ctx.clip(FILL_RULE[fill_rule]); }, /** * Fills the current path. @@ -118,7 +182,7 @@ export function make_odin_ctx2d(wasm, s) { fill( /** @type {number} */ fill_rule, ) { - s.ctx.fill(CANVAS_FILL_RULE[fill_rule]) + s.ctx.fill(FILL_RULE[fill_rule]) }, /** * Checks if the given point is inside the current path. @@ -128,7 +192,7 @@ export function make_odin_ctx2d(wasm, s) { /** @type {number} */ y, /** @type {number} */ fill_rule, ) { - return s.ctx.isPointInPath(x, y, CANVAS_FILL_RULE[fill_rule]) + return s.ctx.isPointInPath(x, y, FILL_RULE[fill_rule]) }, /** * Checks if the given point is inside the current stroke. @@ -278,7 +342,7 @@ export function make_odin_ctx2d(wasm, s) { lineCap( /** @type {number} */ cap, ) { - s.ctx.lineCap = CANVAS_LINE_CAP[cap] + s.ctx.lineCap = LINE_CAP[cap] }, /** @returns {void} */ lineDashOffset( @@ -290,7 +354,7 @@ export function make_odin_ctx2d(wasm, s) { lineJoin( /** @type {number} */ join, ) { - s.ctx.lineJoin = CANVAS_LINE_JOIN[join] + s.ctx.lineJoin = LINE_JOIN[join] }, /** @returns {void} */ lineWidth( @@ -451,5 +515,73 @@ export function make_odin_ctx2d(wasm, s) { mem.store_offset_f32(data, offset, metrics.ideographicBaseline) mem.store_offset_f32(data, offset, metrics.width) }, + + // ------------------------------ / + // TEXT DRAWING STYLES / + // ------------------------------ / + + /** @returns {void} */ + direction( + /** @type {number} */ value, + ) { + s.ctx.direction = DIRECTION[value] + }, + /** @returns {void} */ + font( + /** @type {number} */ ptr, + /** @type {number} */ len, + ) { + s.ctx.font = mem.load_string_raw(wasm.memory.buffer, ptr, len) + }, + /** @returns {void} */ + fontKerning( + /** @type {number} */ value, + ) { + s.ctx.fontKerning = FONT_KERNING[value] + }, + /** @returns {void} */ + fontStretch( + /** @type {number} */ value, + ) { + s.ctx.fontStretch = FONT_STRETCH[value] + }, + /** @returns {void} */ + fontVariantCaps( + /** @type {number} */ value, + ) { + s.ctx.fontVariantCaps = FONT_VARIANT_CAPS[value] + }, + /** @returns {void} */ + letterSpacing( + /** @type {number} */ ptr, + /** @type {number} */ len, + ) { + s.ctx.letterSpacing = mem.load_string_raw(wasm.memory.buffer, ptr, len) + }, + /** @returns {void} */ + textAlign( + /** @type {number} */ value, + ) { + s.ctx.textAlign = TEXT_ALIGN[value] + }, + /** @returns {void} */ + textBaseline( + /** @type {number} */ value, + ) { + s.ctx.textBaseline = TEXT_BASELINE[value] + }, + /** @returns {void} */ + textRendering( + /** @type {number} */ value, + ) { + s.ctx.textRendering = TEXT_RENDERING[value] + }, + /** @returns {void} */ + wordSpacing( + /** @type {number} */ ptr, + /** @type {number} */ len, + ) { + s.ctx.wordSpacing = mem.load_string_raw(wasm.memory.buffer, ptr, len) + }, } } diff --git a/wasm/ctx2d/ctx2d.odin b/wasm/ctx2d/ctx2d.odin index 5f40522..59178ab 100644 --- a/wasm/ctx2d/ctx2d.odin +++ b/wasm/ctx2d/ctx2d.odin @@ -1,5 +1,7 @@ package ctx2d +import "core:strconv" + foreign import "ctx2d" @(default_calling_convention="contextless") @@ -51,7 +53,7 @@ foreign ctx2d { // DRAW PATH / // ------------------------------ / -CanvasFillRule :: enum { +FillRule :: enum { nonzero = 0, evenodd = 1, } @@ -61,11 +63,11 @@ foreign ctx2d { // Begins a new path. beginPath :: proc () --- // Clips the current path. - clip :: proc (fill_rule: CanvasFillRule = .nonzero) --- + clip :: proc (fill_rule: FillRule = .nonzero) --- // Fills the current path. - fill :: proc (fill_rule: CanvasFillRule = .nonzero) --- + fill :: proc (fill_rule: FillRule = .nonzero) --- // Checks if the given point is inside the current path. - isPointInPath :: proc (x, y: f32, fill_rule: CanvasFillRule = .nonzero) -> bool --- + isPointInPath :: proc (x, y: f32, fill_rule: FillRule = .nonzero) -> bool --- // Checks if the given point is inside the current stroke. isPointInStroke :: proc (x, y: f32) -> bool --- // Strokes the current path. @@ -106,13 +108,13 @@ foreign ctx2d { // PATH DRAWING STYLES / // ------------------------------ / -CanvasLineCap :: enum { +LineCap :: enum { butt = 0, round = 1, square = 2, } -CanvasLineJoin :: enum { +LineJoin :: enum { miter = 0, round = 1, bevel = 2, @@ -120,9 +122,9 @@ CanvasLineJoin :: enum { @(default_calling_convention="contextless") foreign ctx2d { - lineCap :: proc (cap: CanvasLineCap) --- + lineCap :: proc (cap: LineCap) --- lineDashOffset :: proc (offset: f32) --- - lineJoin :: proc (join: CanvasLineJoin) --- + lineJoin :: proc (join: LineJoin) --- lineWidth :: proc (width: f32) --- miterLimit :: proc (limit: f32) --- setLineDash :: proc (segments: []f32) --- @@ -199,3 +201,101 @@ getTextMetrics :: proc (text: string) -> (metrics: TextMetrics) { return } +// ------------------------------ / +// TEXT DRAWING STYLES / +// ------------------------------ / + +Direction :: enum { + inherit = 0, + ltr = 1, + rtl = 2, +} + +FontKerning :: enum { + auto = 0, + none = 1, + normal = 2, +} + +FontStretch :: enum { + normal = 0, + ultra_condensed = 1, + extra_condensed = 2, + condensed = 3, + semi_condensed = 4, + semi_expanded = 5, + expanded = 6, + extra_expanded = 7, + ultra_expanded = 8, +} + +FontVariantCaps :: enum { + normal = 0, + petite_caps = 1, + all_petite_caps = 2, + small_caps = 3, + all_small_caps = 4, + titling_caps = 5, + unicase = 6, +} + +TextAlign :: enum { + start = 0, + end = 1, + left = 2, + right = 3, + center = 4, +} + +TextBaseline :: enum { + alphabetic = 0, + top = 1, + hanging = 2, + middle = 3, + ideographic = 4, + bottom = 5, +} + +TextRendering :: enum { + auto = 0, + optimizeSpeed = 1, + optimizeLegibility = 2, + geometricPrecision = 3, +} + +@(default_calling_convention="contextless") +foreign ctx2d { + direction :: proc (Direction) --- + font :: proc (string) --- + fontKerning :: proc (FontKerning) --- + fontStretch :: proc (FontStretch) --- + fontVariantCaps :: proc (FontVariantCaps) --- + @(link_name="letterSpacing") + letterSpacingString :: proc (string) --- + textAlign :: proc (TextAlign) --- + textBaseline :: proc (TextBaseline) --- + textRendering :: proc (TextRendering) --- + @(link_name="wordSpacing") + wordSpacingString :: proc (string) --- +} + +px_to_string :: proc (buf: []byte, val: int) -> string { + val_str := strconv.append_int(buf, i64(val), 10) + val_len := len(val_str) + buf[val_len+0] = 'p' + buf[val_len+1] = 'x' + return string(buf[:val_len+2]) +} + +letterSpacingPx :: proc (val: int) { + buf: [32]byte + letterSpacingString(px_to_string(buf[:], val)) +} + +wordSpacingPx :: proc (val: int) { + buf: [32]byte + wordSpacingString(px_to_string(buf[:], val)) +} + +letterSpacing :: proc {letterSpacingString, letterSpacingPx} +wordSpacing :: proc {wordSpacingString, wordSpacingPx}