From 1f07fdcd9251128ad5df5c313ea64dd79e51fc54 Mon Sep 17 00:00:00 2001 From: LLLL Colonq Date: Thu, 7 May 2026 20:00:36 -0400 Subject: Scripting API --- crates/teleia/src/assets/shaders/bitmap/vert.glsl | 9 ++- crates/teleia/src/font.rs | 21 ++++++ crates/teleia/src/renderer.rs | 2 +- crates/teleia/src/script.rs | 87 +++++++++++++++++++++-- crates/teleia/src/shader.rs | 11 ++- crates/teleia/src/state.rs | 19 +++-- 6 files changed, 131 insertions(+), 18 deletions(-) (limited to 'crates') diff --git a/crates/teleia/src/assets/shaders/bitmap/vert.glsl b/crates/teleia/src/assets/shaders/bitmap/vert.glsl index 192d4b0..6a9870a 100644 --- a/crates/teleia/src/assets/shaders/bitmap/vert.glsl +++ b/crates/teleia/src/assets/shaders/bitmap/vert.glsl @@ -1,11 +1,13 @@ #version 300 es precision highp float; -in vec2 vertex; +in vec3 vertex; in vec2 texcoord; in vec3 color; -uniform mat4 transform; +uniform mat4 view; +uniform mat4 position; +uniform mat4 projection; out vec2 vertex_texcoord; out vec3 vertex_color; @@ -13,5 +15,6 @@ out vec3 vertex_color; void main() { vertex_texcoord = texcoord; vertex_color = color; - gl_Position = transform * vec4(vertex, 0.0, 1.0); + vec3 pos = (position * vec4(vertex, 1.0)).xyz; + gl_Position = projection * view * vec4(pos, 1.0); } diff --git a/crates/teleia/src/font.rs b/crates/teleia/src/font.rs index 2fe7423..2e90571 100644 --- a/crates/teleia/src/font.rs +++ b/crates/teleia/src/font.rs @@ -6,6 +6,15 @@ pub struct BitmapParams<'color> { pub scale: glam::Vec2, pub offset: glam::Vec2, } +impl<'color> Default for BitmapParams<'color> { + fn default() -> Self { + Self { + color: &[], + scale: glam::Vec2::ONE, + offset: glam::Vec2::ZERO, + } + } +} pub struct Bitmap { pub char_width: i32, pub char_height: i32, @@ -170,4 +179,16 @@ impl Bitmap { ) { self.render_text_helper(ctx, st, text, &[]); } + + pub fn render_text_at(&self, + ctx: &context::Context, st: &mut state::State, + pos: glam::Vec2, text: &str, + params: BitmapParams, + ) { + st.bind_2d(ctx, &st.shader_text_bitmap); + let dims = glam::Vec2::new(self.char_width as f32, self.char_height as f32); + let fpos = pos + glam::Vec2::new(-dims.x / 2.0, dims.y / 2.0); + st.shader_text_bitmap.set_position_text_bitmap(ctx, st, &self, &fpos); + self.render_text_parameterized(ctx, st, text, params); + } } diff --git a/crates/teleia/src/renderer.rs b/crates/teleia/src/renderer.rs index 19dd8a0..5242eac 100644 --- a/crates/teleia/src/renderer.rs +++ b/crates/teleia/src/renderer.rs @@ -280,7 +280,7 @@ impl Renderer { self.texture = BoundTexture::None; self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::VERTEX_COLOR | UberFlags::FLIP_TEXTURE); let dims = glam::Vec2::new(st.font_default.char_width as f32, st.font_default.char_height as f32); - let fpos = (pos + glam::Vec2::new(-dims.x / 2.0, st.font_default.char_height as f32 / 2.0)); + let fpos = pos + glam::Vec2::new(-dims.x / 2.0, dims.y / 2.0); self.set_position_2d(ctx, st, fpos, dims); st.font_default.render_text(ctx, st, s); } diff --git a/crates/teleia/src/script.rs b/crates/teleia/src/script.rs index 8e27f31..8eaf85a 100644 --- a/crates/teleia/src/script.rs +++ b/crates/teleia/src/script.rs @@ -15,6 +15,19 @@ impl std::fmt::Display for Error { } impl std::error::Error for Error {} +type PitNativeFunc = extern "C" fn(rt: *mut PitRuntime, args: PitValue, data: *mut PitNativeFuncData) -> PitValue; +#[repr(C)] +struct PitNativeFuncDataShim { _data: () } +struct PitNativeFuncData { + f: Box Value>, +} +extern "C" fn unwrap_nativefunc(rt: *mut PitRuntime, args: PitValue, data: *mut PitNativeFuncData) -> PitValue { + unsafe { + let ret = ((*data).f)(&mut Runtime::from_shared(rt), Value { val: args }); + ret.val + } +} + #[repr(C)] #[derive(Debug, Clone, Copy)] struct PitValue { data: u64 } @@ -57,7 +70,36 @@ unsafe extern "C" { fn pit_parse(rt: *mut PitRuntime, parser: *mut PitParser, eof: *mut bool) -> PitValue; fn pit_eval(rt: *mut PitRuntime, v: PitValue) -> PitValue; fn pit_dump(rt: *mut PitRuntime, buf: *mut u8, len: i64, v: PitValue, readable: bool) -> i64; - fn pit_eq(rt: *mut PitRuntime, x: PitValue, y: PitValue) -> bool; + + fn pit_eq(x: PitValue, y: PitValue) -> bool; + + fn pit_intern(rt: *mut PitRuntime, buf: *const u8, len: i64) -> PitValue; + fn pit_set(rt: *mut PitRuntime, sym: PitValue, v: PitValue); + fn pit_fset(rt: *mut PitRuntime, sym: PitValue, v: PitValue); + fn pit_get(rt: *mut PitRuntime, sym: PitValue) -> PitValue; + fn pit_fget(rt: *mut PitRuntime, sym: PitValue) -> PitValue; + + fn pit_array_new(rt: *mut PitRuntime, len: i64) -> PitValue; + fn pit_array_from_buf(rt: *mut PitRuntime, xs: *const PitValue, len: i64) -> PitValue; + fn pit_array_len(rt: *mut PitRuntime, arr: PitValue) -> i64; + fn pit_array_get(rt: *mut PitRuntime, arr: PitValue, idx: i64) -> PitValue; + fn pit_array_set(rt: *mut PitRuntime, arr: PitValue, idx: i64, v: PitValue) -> PitValue; + + fn pit_cons(rt: *mut PitRuntime, car: PitValue, cdr: PitValue) -> PitValue; + fn pit_list_len(rt: *mut PitRuntime, xs: PitValue) -> i64; + fn pit_car(rt: *mut PitRuntime, v: PitValue) -> PitValue; + fn pit_cdr(rt: *mut PitRuntime, v: PitValue) -> PitValue; + fn pit_setcar(rt: *mut PitRuntime, v: PitValue, x: PitValue); + fn pit_setcdr(rt: *mut PitRuntime, v: PitValue, x: PitValue); + fn pit_append(rt: *mut PitRuntime, xs: PitValue, ys: PitValue) -> PitValue; + fn pit_reverse(rt: *mut PitRuntime, xs: PitValue) -> PitValue; + fn pit_contains_eq(rt: *mut PitRuntime, needle: PitValue, haystack: PitValue) -> PitValue; + fn pit_contains_equal(rt: *mut PitRuntime, needle: PitValue, haystack: PitValue) -> PitValue; + fn pit_plist_get(rt: *mut PitRuntime, k: PitValue, vs: PitValue) -> PitValue; + + fn pit_lambda(rt: *mut PitRuntime, args: PitValue, body: PitValue) -> PitValue; + fn pit_nativefunc_new_with_data(rt: *mut PitRuntime, f: PitNativeFunc, data: *mut PitNativeFuncDataShim) -> PitValue; + fn pit_apply(rt: *mut PitRuntime, f: PitValue, args: PitValue) -> PitValue; } pub struct Runtime { @@ -65,6 +107,12 @@ pub struct Runtime { rt: *mut PitRuntime, } impl Runtime { + fn from_shared(rt: *mut PitRuntime) -> Self { + Self { + _buf: Box::new([]), + rt, + } + } pub fn new(sz: usize) -> Self { let mut buf = Box::new_uninit_slice(sz); let rt = unsafe { @@ -84,15 +132,14 @@ impl Runtime { let e = unsafe { pit_get_error(self.rt) }; let ve = Value { val: e }; if self.eq(ve, NIL) { return Ok(()) }; + eprintln!("ve: {}", ve.val.data); Err(Error { msg: self.dump(ve).unwrap_or("".to_owned()) }.into()) } pub fn parse(&mut self, s: &str) -> utils::Erm { - let mut rt = Runtime::new(1024 * 1024 * 1024); let lexer = Lexer::from_bytes(s.as_bytes()); let mut parser = Parser::from_lexer(lexer); - let expr = parser.parse(&mut rt)?.ok_or(Error { msg: "end of file".to_string() })?; - let res = rt.eval(expr)?; - Ok(res) + let expr = parser.parse(self)?.ok_or(Error { msg: "end of file".to_string() })?; + Ok(expr) } pub fn eval(&mut self, v: Value) -> utils::Erm { unsafe { @@ -108,8 +155,34 @@ impl Runtime { Ok(str::from_utf8(&buf[0..len]).map(|s| s.to_owned())?) } } - pub fn eq(&mut self, x: Value, y: Value) -> bool { - unsafe { pit_eq(self.rt, x.val, y.val) } + pub fn eq(&self, x: Value, y: Value) -> bool { + unsafe { pit_eq(x.val, y.val) } + } + pub fn intern(&mut self, nm: &str) -> utils::Erm { + unsafe { + let bs = nm.as_bytes(); + let sym = pit_intern(self.rt, bs.as_ptr(), bs.len() as i64); + self.error()?; + Ok(Value { val: sym }) + } + } + pub fn fset(&mut self, sym: Value, f: Value) -> utils::Erm<()> { + unsafe { + pit_fset(self.rt, sym.val, f.val); + self.error()?; + Ok(()) + } + } + pub fn nativefunc_new(&mut self, f: F) -> utils::Erm + where F: FnMut(&mut Runtime, Value) -> Value + 'static { + unsafe { + let data = Box::leak(Box::new(PitNativeFuncData { + f: Box::new(f), + })); + let ret = pit_nativefunc_new_with_data(self.rt, unwrap_nativefunc, data as *mut PitNativeFuncData as *mut _); + self.error()?; + Ok(Value { val: ret }) + } } } diff --git a/crates/teleia/src/shader.rs b/crates/teleia/src/shader.rs index b45e31e..d707416 100644 --- a/crates/teleia/src/shader.rs +++ b/crates/teleia/src/shader.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use glow::HasContext; -use crate::{context, state, mesh}; +use crate::{context, font, mesh, state}; const COMMON_VERT: &'static str = include_str!("assets/shaders/common/vert.glsl"); const COMMON_FRAG: &'static str = include_str!("assets/shaders/common/frag.glsl"); @@ -239,6 +239,15 @@ impl Shader { self.set_position_2d_helper(ctx, st, pos, dims, &glam::Quat::IDENTITY) } + pub fn set_position_text_bitmap(&self, + ctx: &context::Context, st: &state::State, + font: &font::Bitmap, + pos: &glam::Vec2 + ) { + let dims = glam::Vec2::new(font.char_width as f32, font.char_height as f32); + self.set_position_2d_helper(ctx, st, pos, &dims, &glam::Quat::IDENTITY) + } + pub fn bind(&self, ctx: &context::Context) { unsafe { ctx.gl.use_program(Some(self.program)); diff --git a/crates/teleia/src/state.rs b/crates/teleia/src/state.rs index f5b6313..9ac617e 100644 --- a/crates/teleia/src/state.rs +++ b/crates/teleia/src/state.rs @@ -175,6 +175,7 @@ pub struct State { pub render_framebuffer: framebuffer::Framebuffer, pub render_dims: glam::Vec2, pub shader_upscale: shader::Shader, + pub shader_text_bitmap: shader::Shader, pub mesh_square: mesh::Mesh, pub font_default: font::Bitmap, pub font_small: font::Bitmap, @@ -250,6 +251,11 @@ impl State { include_str!("assets/shaders/scale/vert.glsl"), include_str!("assets/shaders/scale/frag.glsl"), ); + let shader_text_bitmap = shader::Shader::new_nolib( + ctx, + include_str!("assets/shaders/bitmap/vert.glsl"), + include_str!("assets/shaders/bitmap/frag.glsl"), + ); let mesh_square = mesh::Mesh::from_obj(ctx, include_bytes!("assets/meshes/square.obj")); let nextframe = now(ctx); @@ -272,6 +278,7 @@ impl State { render_framebuffer, render_dims: glam::Vec2::new(ctx.render_width, ctx.render_height), shader_upscale, + shader_text_bitmap, mesh_square, font_default: font::Bitmap::default(ctx), font_small: font::Bitmap::small(ctx), @@ -369,7 +376,7 @@ impl State { ) } - pub fn bind_3d_helper(&mut self, ctx: &context::Context, shader: &shader::Shader, plc: usize, orth: bool) { + pub fn bind_3d_helper(&self, ctx: &context::Context, shader: &shader::Shader, plc: usize, orth: bool) { shader.bind(ctx); shader.set_mat4(ctx, "projection", if orth { &self.projection_orth } else { &self.projection }); shader.set_mat4(ctx, "view", &self.view()); @@ -391,11 +398,11 @@ impl State { ); } - pub fn bind_3d_no_point_lights(&mut self, ctx: &context::Context, shader: &shader::Shader) { + pub fn bind_3d_no_point_lights(&self, ctx: &context::Context, shader: &shader::Shader) { self.bind_3d_helper(ctx, shader, 0, false); } - pub fn bind_3d_with_point_lights(&mut self, ctx: &context::Context, shader: &shader::Shader, orth: bool) { + pub fn bind_3d_with_point_lights(&self, ctx: &context::Context, shader: &shader::Shader, orth: bool) { let plc = self.point_lights.len().min(5); self.bind_3d_helper(ctx, shader, plc, orth); if plc > 0 { @@ -417,15 +424,15 @@ impl State { } } - pub fn bind_3d(&mut self, ctx: &context::Context, shader: &shader::Shader) { + pub fn bind_3d(&self, ctx: &context::Context, shader: &shader::Shader) { self.bind_3d_with_point_lights(ctx, shader, false) } - pub fn bind_3d_orth(&mut self, ctx: &context::Context, shader: &shader::Shader) { + pub fn bind_3d_orth(&self, ctx: &context::Context, shader: &shader::Shader) { self.bind_3d_with_point_lights(ctx, shader, true) } - pub fn bind_2d(&mut self, ctx: &context::Context, shader: &shader::Shader) { + pub fn bind_2d(&self, ctx: &context::Context, shader: &shader::Shader) { shader.bind(ctx); shader.set_mat4(&ctx, "projection", &glam::Mat4::IDENTITY); shader.set_mat4( -- cgit v1.2.3