Skip to content

Commit

Permalink
Begin work on ctx 2d bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
thetarnav committed May 6, 2024
1 parent 200f0f0 commit de61cf2
Show file tree
Hide file tree
Showing 9 changed files with 368 additions and 101 deletions.
16 changes: 16 additions & 0 deletions example/bezier_curve.odin
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//+private file
package example

import gl "../wasm/webgl"

@private
State_Bezier_Curve :: struct {
}

@private
setup_bezier_curve :: proc(s: ^State_Bezier_Curve, program: gl.Program) {
}

@private
frame_bezier_curve :: proc(s: ^State_Bezier_Curve, delta: f32) {
}
4 changes: 2 additions & 2 deletions example/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ const src_instance = await wasm.fetchInstanciateWasm(WASM_FILENAME, {
env: {}, // TODO
odin_env: wasm.env.makeOdinEnv(wasm_state),
odin_dom: wasm.dom.makeOdinDOM(wasm_state),
webgl : wasm.webgl.makeOdinWebGL(webgl_state, wasm_state),
webgl2 : wasm.webgl.makeOdinWegGL2(webgl_state, wasm_state),
webgl : wasm.webgl.makeOdinWebGL(wasm_state, webgl_state),
webgl2 : wasm.webgl.makeOdinWegGL2(wasm_state, webgl_state),
})

wasm.initWasmState(wasm_state, src_instance)
Expand Down
59 changes: 32 additions & 27 deletions example/setup.odin
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Example_Kind :: enum {
Spotlight,
Candy,
Sol_System,
Bezier_Curve,
}
example: Example_Kind

Expand Down Expand Up @@ -71,19 +72,21 @@ demos: [Example_Kind]struct {
vs_sources = {#load("./sol_system.vert", string)},
fs_sources = {#load("./sol_system.frag", string)},
},
.Bezier_Curve = {},
}

// state is a union because it is being used by only one of the examples
demo_state: struct #raw_union {
rectangle: State_Rectangle,
pyramid: State_Pyramid,
boxes: State_Boxes,
camera: State_Camera,
lighting: State_Lighting,
specular: State_Specular,
spotlight: State_Spotlight,
candy: State_Candy,
sol_system: State_Sol_System,
rectangle: State_Rectangle,
pyramid: State_Pyramid,
boxes: State_Boxes,
camera: State_Camera,
lighting: State_Lighting,
specular: State_Specular,
spotlight: State_Spotlight,
candy: State_Candy,
sol_system: State_Sol_System,
bezier_curve: State_Bezier_Curve,
}


Expand Down Expand Up @@ -163,15 +166,16 @@ start :: proc "c" (ctx: ^runtime.Context, example_kind: Example_Kind) -> (ok: bo
gl.UseProgram(program)

switch example {
case .Rectangle: setup_rectangle (&demo_state.rectangle, program)
case .Pyramid: setup_pyramid (&demo_state.pyramid, program)
case .Boxes: setup_boxes (&demo_state.boxes, program)
case .Camera: setup_camera (&demo_state.camera, program)
case .Lighting: setup_lighting (&demo_state.lighting, program)
case .Specular: setup_specular (&demo_state.specular, program)
case .Spotlight: setup_spotlight (&demo_state.spotlight, program)
case .Candy: setup_candy (&demo_state.candy, program)
case .Sol_System: setup_sol_system(&demo_state.sol_system, program)
case .Rectangle: setup_rectangle (&demo_state.rectangle, program)
case .Pyramid: setup_pyramid (&demo_state.pyramid, program)
case .Boxes: setup_boxes (&demo_state.boxes, program)
case .Camera: setup_camera (&demo_state.camera, program)
case .Lighting: setup_lighting (&demo_state.lighting, program)
case .Specular: setup_specular (&demo_state.specular, program)
case .Spotlight: setup_spotlight (&demo_state.spotlight, program)
case .Candy: setup_candy (&demo_state.candy, program)
case .Sol_System: setup_sol_system (&demo_state.sol_system, program)
case .Bezier_Curve: setup_bezier_curve(&demo_state.bezier_curve, program)
}

if err := gl.GetError(); err != gl.NO_ERROR {
Expand All @@ -195,14 +199,15 @@ frame :: proc "c" (ctx: ^runtime.Context, delta: f32) {
}

switch example {
case .Rectangle: frame_rectangle (&demo_state.rectangle, delta)
case .Pyramid: frame_pyramid (&demo_state.pyramid, delta)
case .Boxes: frame_boxes (&demo_state.boxes, delta)
case .Camera: frame_camera (&demo_state.camera, delta)
case .Lighting: frame_lighting (&demo_state.lighting, delta)
case .Specular: frame_specular (&demo_state.specular, delta)
case .Spotlight: frame_spotlight (&demo_state.spotlight, delta)
case .Candy: frame_candy (&demo_state.candy, delta)
case .Sol_System: frame_sol_system(&demo_state.sol_system, delta)
case .Rectangle: frame_rectangle (&demo_state.rectangle, delta)
case .Pyramid: frame_pyramid (&demo_state.pyramid, delta)
case .Boxes: frame_boxes (&demo_state.boxes, delta)
case .Camera: frame_camera (&demo_state.camera, delta)
case .Lighting: frame_lighting (&demo_state.lighting, delta)
case .Specular: frame_specular (&demo_state.specular, delta)
case .Spotlight: frame_spotlight (&demo_state.spotlight, delta)
case .Candy: frame_candy (&demo_state.candy, delta)
case .Sol_System: frame_sol_system (&demo_state.sol_system, delta)
case .Bezier_Curve: frame_bezier_curve(&demo_state.bezier_curve, delta)
}
}
2 changes: 1 addition & 1 deletion example/utils.odin
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ vec3_rotate :: proc "contextless" (v, axis: vec3, angle: f32) -> vec3 {
}

vec3_transform :: proc "contextless" (v: vec3, m: mat4) -> vec3 {
w := m[0][3] * v.x + m[1][3] * v.y + m[2][3] * v.z + m[3][3] // assume v[3] is 1
w := m[0][3] * v.x + m[1][3] * v.y + m[2][3] * v.z + m[3][3]

return {
(m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0]) / w,
Expand Down
178 changes: 178 additions & 0 deletions wasm/ctx2d/ctx2d.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import * as mem from "../memory.js"


/** @typedef {import("../types.js").WasmState} Wasm_State */


export function Ctx2d_State() {
this.ctx = /** @type {CanvasRenderingContext2D} */ (/** @type {*} */(null))
}

/** @enum {typeof CanvasFillRuleEnum[keyof typeof CanvasFillRuleEnum]} */
const CanvasFillRuleEnum = /** @type {const} */({
nonzero: 0,
evenodd: 1,
})

/** @type {Record<CanvasFillRuleEnum, CanvasFillRule>} */
const CANVAS_FILL_RULE = {
0: "nonzero",
1: "evenodd",
}


/**
* @param {Wasm_State} wasm
* @param {Ctx2d_State} s
* @returns Canvas 2d context bindings for Odin.
*/
export function make_odin_ctx2d(wasm, s) {
return {
/**
* Sets the current 2d context by canvas id.
* @param {number} id_ptr
* @param {number} id_len
* @returns {boolean} */
setCurrentContextById: (id_ptr, id_len) => {
const id = mem.load_string_raw(wasm.memory.buffer, id_ptr, id_len)
const element = document.getElementById(id)

if (!(element instanceof HTMLCanvasElement)) return false

const ctx = element.getContext("2d")
if (!ctx) return false

s.ctx = ctx
return true
},
// ------------------------------ /
// COMPOSITING /
// ------------------------------ /
/** @returns {number} */
getGlobalAlpha() {
return s.ctx.globalAlpha
},
/**
* @param {number} alpha
* @returns {void} */
setGlobalAlpha(alpha) {
s.ctx.globalAlpha = alpha
},
/** @returns {number} */
getGlobalCompositeOperation() {
switch (s.ctx.globalCompositeOperation) {
case "source-over": return 0
case "source-in": return 1
case "source-out": return 2
case "source-atop": return 3
case "destination-over": return 4
case "destination-in": return 5
case "destination-out": return 6
case "destination-atop": return 7
case "lighter": return 8
case "copy": return 9
case "xor": return 10
case "multiply": return 11
case "screen": return 12
case "overlay": return 13
case "darken": return 14
case "lighten": return 15
case "color-dodge": return 16
case "color-burn": return 17
case "hard-light": return 18
case "soft-light": return 19
case "difference": return 20
case "exclusion": return 21
case "hue": return 22
case "saturation": return 23
case "color": return 24
case "luminosity": return 25
}
},
/**
* @param {number} op
* @returns {void} */
setGlobalCompositeOperation(op) {
switch (op) {
case 0: s.ctx.globalCompositeOperation = "source-over" ;break
case 1: s.ctx.globalCompositeOperation = "source-in" ;break
case 2: s.ctx.globalCompositeOperation = "source-out" ;break
case 3: s.ctx.globalCompositeOperation = "source-atop" ;break
case 4: s.ctx.globalCompositeOperation = "destination-over" ;break
case 5: s.ctx.globalCompositeOperation = "destination-in" ;break
case 6: s.ctx.globalCompositeOperation = "destination-out" ;break
case 7: s.ctx.globalCompositeOperation = "destination-atop" ;break
case 8: s.ctx.globalCompositeOperation = "lighter" ;break
case 9: s.ctx.globalCompositeOperation = "copy" ;break
case 10: s.ctx.globalCompositeOperation = "xor" ;break
case 11: s.ctx.globalCompositeOperation = "multiply" ;break
case 12: s.ctx.globalCompositeOperation = "screen" ;break
case 13: s.ctx.globalCompositeOperation = "overlay" ;break
case 14: s.ctx.globalCompositeOperation = "darken" ;break
case 15: s.ctx.globalCompositeOperation = "lighten" ;break
case 16: s.ctx.globalCompositeOperation = "color-dodge" ;break
case 17: s.ctx.globalCompositeOperation = "color-burn" ;break
case 18: s.ctx.globalCompositeOperation = "hard-light" ;break
case 19: s.ctx.globalCompositeOperation = "soft-light" ;break
case 20: s.ctx.globalCompositeOperation = "difference" ;break
case 21: s.ctx.globalCompositeOperation = "exclusion" ;break
case 22: s.ctx.globalCompositeOperation = "hue" ;break
case 23: s.ctx.globalCompositeOperation = "saturation" ;break
case 24: s.ctx.globalCompositeOperation = "color" ;break
case 25: s.ctx.globalCompositeOperation = "luminosity" ;break
}
},
// ------------------------------ /
// DRAW PATH /
// ------------------------------ /
/**
* Begins a new path.
* @returns {void}
*/
beginPath() {
s.ctx.beginPath();
},
/**
* Clips the current path.
* @param {CanvasFillRuleEnum} fill_rule
* @returns {void}
*/
clip(fill_rule) {
s.ctx.clip(CANVAS_FILL_RULE[fill_rule]);
},
/**
* Fills the current path.
* @param {CanvasFillRuleEnum} fill_rule
* @returns {void}
*/
fill(fill_rule) {
s.ctx.fill(CANVAS_FILL_RULE[fill_rule])
},
/**
* Checks if the given point is inside the current path.
* @param {number} x
* @param {number} y
* @param {CanvasFillRuleEnum} fill_rule
* @returns {boolean}
*/
isPointInPath(x, y, fill_rule) {
return s.ctx.isPointInPath(x, y, CANVAS_FILL_RULE[fill_rule])
},
/**
* Checks if the given point is inside the current stroke.
* @param {number} x
* @param {number} y
* @returns {boolean}
*/
isPointInStroke(x, y) {
return s.ctx.isPointInStroke(x, y)
},
/**
* Strokes the current path.
* @returns {void}
*/
stroke() {
s.ctx.stroke()
},
}
}
69 changes: 69 additions & 0 deletions wasm/ctx2d/ctx2d.odin
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package ctx2d

foreign import "ctx2d"

GlobalCompositeOperation :: enum {
source_over = 0,
source_in = 1,
source_out = 2,
source_atop = 3,
destination_over = 4,
destination_in = 5,
destination_out = 6,
destination_atop = 7,
lighter = 8,
copy = 9,
xor = 10,
multiply = 11,
screen = 12,
overlay = 13,
darken = 14,
lighten = 15,
color_dodge = 16,
color_burn = 17,
hard_light = 18,
soft_light = 19,
difference = 20,
exclusion = 21,
hue = 22,
saturation = 23,
color = 24,
luminosity = 25,
}

CanvasFillRule :: enum {
nonzero = 0,
evenodd = 1,
}

@(default_calling_convention="contextless")
foreign ctx2d {
// Sets the current 2d context by canvas id.
setCurrentContextById :: proc (id: string) -> bool ---

// ------------------------------ /
// COMPOSITING /
// ------------------------------ /

getGlobalCompositeOperation :: proc () -> GlobalCompositeOperation ---
setGlobalCompositeOperation :: proc (operation: GlobalCompositeOperation) ---
getGlobalAlpha :: proc () -> f32 ---
setGlobalAlpha :: proc (alpha: f32) ---

// ------------------------------ /
// DRAW PATH /
// ------------------------------ /

// Begins a new path.
beginPath :: proc () ---
// Clips the current path.
clip :: proc (fill_rule: CanvasFillRule = .nonzero) ---
// Fills the current path.
fill :: proc (fill_rule: CanvasFillRule = .nonzero) ---
// Checks if the given point is inside the current path.
isPointInPath :: proc (x: f32, y: f32, fill_rule: CanvasFillRule = .nonzero) -> bool ---
// Checks if the given point is inside the current stroke.
isPointInStroke :: proc (x: f32, y: f32) -> bool ---
// Strokes the current path.
stroke :: proc () ---
}
Loading

0 comments on commit de61cf2

Please sign in to comment.