[oden] Move scaling entirely into JavaScript
Now the game controls its own resolution. We might want to further copy Love2D and generate resize events, I don't know.
This commit is contained in:
parent
994be3e493
commit
1cb30034f8
9 changed files with 176 additions and 58 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import { cls } from "./graphics";
|
import { cls, get_dimensions, scale } from "./graphics";
|
||||||
import { since_start } from "./time";
|
import { since_start } from "./time";
|
||||||
import { new_v2 } from "./vector";
|
import { new_v2 } from "./vector";
|
||||||
import { load_world, World, Level, draw_level } from "./level";
|
import { load_world, World, Level, draw_level } from "./level";
|
||||||
|
|
@ -102,6 +102,13 @@ export function update() {
|
||||||
export function draw() {
|
export function draw() {
|
||||||
cls(0.1, 0.2, 0.3);
|
cls(0.1, 0.2, 0.3);
|
||||||
|
|
||||||
|
const dimensions = get_dimensions();
|
||||||
|
const s = Math.max(
|
||||||
|
1,
|
||||||
|
Math.floor(Math.min(dimensions[0] / 320, dimensions[1] / 240))
|
||||||
|
);
|
||||||
|
scale(s);
|
||||||
|
|
||||||
if (level != undefined) {
|
if (level != undefined) {
|
||||||
draw_level(level, 0, 0);
|
draw_level(level, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -149,3 +149,10 @@ impl TryIntoValue for () {
|
||||||
Ok(ctx.undefined())
|
Ok(ctx.undefined())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: TryIntoValue> TryIntoValue for &[T] {
|
||||||
|
#[inline]
|
||||||
|
fn try_into_value(self, ctx: &ContextRef) -> ValueResult {
|
||||||
|
Ok(ctx.undefined())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -232,8 +232,11 @@ impl ValueRef {
|
||||||
Ok(Value::from_raw(result, ctx))
|
Ok(Value::from_raw(result, ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_property(&self, ctx: &ContextRef, prop: &str) -> Result<Value> {
|
pub fn get_property<'a, T>(&self, ctx: &ContextRef, prop: T) -> Result<Value>
|
||||||
let atom = ctx.new_atom(prop)?;
|
where
|
||||||
|
T: Into<&'a str>,
|
||||||
|
{
|
||||||
|
let atom = ctx.new_atom(prop.into())?;
|
||||||
self.get_property_atom(ctx, &atom)
|
self.get_property_atom(ctx, &atom)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -241,6 +244,10 @@ impl ValueRef {
|
||||||
ctx.check_exception(unsafe { sys::JS_GetProperty(ctx.ctx, self.val, prop.atom) })
|
ctx.check_exception(unsafe { sys::JS_GetProperty(ctx.ctx, self.val, prop.atom) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_index(&self, ctx: &ContextRef, index: u32) -> Result<Value> {
|
||||||
|
ctx.check_exception(unsafe { sys::JS_GetPropertyUint32(ctx.ctx, self.val, index) })
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_property(&mut self, ctx: &ContextRef, prop: &str, val: &ValueRef) -> Result<()> {
|
pub fn set_property(&mut self, ctx: &ContextRef, prop: &str, val: &ValueRef) -> Result<()> {
|
||||||
// TODO: Consume API
|
// TODO: Consume API
|
||||||
let atom = ctx.new_atom(prop)?;
|
let atom = ctx.new_atom(prop)?;
|
||||||
|
|
@ -264,6 +271,18 @@ impl ValueRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_index(&mut self, ctx: &ContextRef, index: u32, val: &ValueRef) -> Result<()> {
|
||||||
|
unsafe {
|
||||||
|
sys::JS_DupValue(ctx.ctx, val.val);
|
||||||
|
let result = sys::JS_SetPropertyUint32(ctx.ctx, self.val, index, val.val);
|
||||||
|
if result == -1 {
|
||||||
|
Err(ctx.exception_error())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_fn<F>(
|
pub fn set_fn<F>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &ContextRef,
|
ctx: &ContextRef,
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,16 @@ export function stroke(r: number, g: number, b: number, a: number = 1) {
|
||||||
core.stroke(r, g, b, a);
|
core.stroke(r, g, b, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current scale factor.
|
||||||
|
*
|
||||||
|
* @param x - The scale factor in the x dimension.
|
||||||
|
* @param y - The scale factor in the y dimension. If omitted, defaults to x.
|
||||||
|
*/
|
||||||
|
export function scale(x: number, y?: number) {
|
||||||
|
core.scale(x, y ?? x);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print a message to the console.
|
* Print a message to the console.
|
||||||
*
|
*
|
||||||
|
|
@ -148,3 +158,10 @@ export function write_to_screen() {
|
||||||
export function write_to_texture(texture: Texture) {
|
export function write_to_texture(texture: Texture) {
|
||||||
core.write_to_texture(texture.id());
|
core.write_to_texture(texture.id());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the dimensions of the screen.
|
||||||
|
*/
|
||||||
|
export function get_dimensions(): [number, number] {
|
||||||
|
return core.get_dimensions();
|
||||||
|
}
|
||||||
|
|
|
||||||
73
src/lib.rs
73
src/lib.rs
|
|
@ -202,14 +202,12 @@ impl GlyphInstance {
|
||||||
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
|
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
struct ScreenUniforms {
|
struct ScreenUniforms {
|
||||||
resolution: [f32; 2],
|
resolution: [f32; 2],
|
||||||
scale: [f32; 2],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScreenUniforms {
|
impl ScreenUniforms {
|
||||||
fn new(width: u32, height: u32, scale_x: f32, scale_y: f32) -> ScreenUniforms {
|
fn new(width: u32, height: u32) -> ScreenUniforms {
|
||||||
ScreenUniforms {
|
ScreenUniforms {
|
||||||
resolution: [width as f32, height as f32],
|
resolution: [width as f32, height as f32],
|
||||||
scale: [scale_x, scale_y],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -485,7 +483,7 @@ impl State {
|
||||||
label: Some("sprite_bind_group_layout"),
|
label: Some("sprite_bind_group_layout"),
|
||||||
});
|
});
|
||||||
|
|
||||||
let screen_uniform = ScreenUniforms::new(size.width, size.height, 10.0, 10.0);
|
let screen_uniform = ScreenUniforms::new(size.width, size.height);
|
||||||
let screen_uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let screen_uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
label: Some("Screen Uniform Buffer"),
|
label: Some("Screen Uniform Buffer"),
|
||||||
contents: bytemuck::cast_slice(&[screen_uniform]),
|
contents: bytemuck::cast_slice(&[screen_uniform]),
|
||||||
|
|
@ -792,12 +790,6 @@ impl State {
|
||||||
let h = self.size.height as f32;
|
let h = self.size.height as f32;
|
||||||
self.screen_uniform.resolution = [w, h];
|
self.screen_uniform.resolution = [w, h];
|
||||||
|
|
||||||
// How do I compute the zoom for an effective resolution?
|
|
||||||
let z_x = w / 320.0;
|
|
||||||
let z_y = h / 240.0;
|
|
||||||
let z = z_y.min(z_x);
|
|
||||||
self.screen_uniform.scale = [z, z];
|
|
||||||
|
|
||||||
self.queue.write_buffer(
|
self.queue.write_buffer(
|
||||||
&self.screen_uniform_buffer,
|
&self.screen_uniform_buffer,
|
||||||
0,
|
0,
|
||||||
|
|
@ -1076,6 +1068,11 @@ struct FrameBuilder<'a> {
|
||||||
encoder: wgpu::CommandEncoder,
|
encoder: wgpu::CommandEncoder,
|
||||||
output: wgpu::SurfaceTexture,
|
output: wgpu::SurfaceTexture,
|
||||||
|
|
||||||
|
// TODO: Should we be persisting these settings across frames?
|
||||||
|
// Right now the whole GPU resets every frame, which I guess is
|
||||||
|
// good and bad?
|
||||||
|
//
|
||||||
|
// TODO: Should we actually be trying to maintain a RenderPassDescriptor?
|
||||||
mode: DrawMode,
|
mode: DrawMode,
|
||||||
last_texture: Option<u32>,
|
last_texture: Option<u32>,
|
||||||
fill_color: [f32; 4],
|
fill_color: [f32; 4],
|
||||||
|
|
@ -1083,6 +1080,7 @@ struct FrameBuilder<'a> {
|
||||||
target: Rc<wgpu::TextureView>,
|
target: Rc<wgpu::TextureView>,
|
||||||
color: Option<[f64; 4]>,
|
color: Option<[f64; 4]>,
|
||||||
draw_calls: Vec<DrawCall>,
|
draw_calls: Vec<DrawCall>,
|
||||||
|
scale: [f32; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FrameBuilder<'a> {
|
impl<'a> FrameBuilder<'a> {
|
||||||
|
|
@ -1116,6 +1114,7 @@ impl<'a> FrameBuilder<'a> {
|
||||||
target: last_view,
|
target: last_view,
|
||||||
color: None,
|
color: None,
|
||||||
draw_calls: Vec::new(),
|
draw_calls: Vec::new(),
|
||||||
|
scale: [1.0, 1.0],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1144,6 +1143,7 @@ impl<'a> FrameBuilder<'a> {
|
||||||
// followed nearly immediately by a clear command and we
|
// followed nearly immediately by a clear command and we
|
||||||
// wind up starting an extra pass in that case which sucks.
|
// wind up starting an extra pass in that case which sucks.
|
||||||
GraphicsCommand::Clear(cc) => self.start_pass(Some(cc.color), self.last_view.clone()),
|
GraphicsCommand::Clear(cc) => self.start_pass(Some(cc.color), self.last_view.clone()),
|
||||||
|
GraphicsCommand::Scale(s) => self.scale = s,
|
||||||
GraphicsCommand::WriteToTexture(id) => {
|
GraphicsCommand::WriteToTexture(id) => {
|
||||||
let texture = self.state.write_textures.get(&id).unwrap();
|
let texture = self.state.write_textures.get(&id).unwrap();
|
||||||
self.last_view = Rc::new(
|
self.last_view = Rc::new(
|
||||||
|
|
@ -1166,7 +1166,7 @@ impl<'a> FrameBuilder<'a> {
|
||||||
self.stroke_color = c;
|
self.stroke_color = c;
|
||||||
}
|
}
|
||||||
GraphicsCommand::Print(pc) => self.push_text(pc),
|
GraphicsCommand::Print(pc) => self.push_text(pc),
|
||||||
GraphicsCommand::Sprite(si) => self.push_sprite(si),
|
GraphicsCommand::Sprite(sc) => self.push_sprite(sc),
|
||||||
GraphicsCommand::Circle(cc) => self.push_circle(cc),
|
GraphicsCommand::Circle(cc) => self.push_circle(cc),
|
||||||
GraphicsCommand::UseTexture(id) => self.use_texture(id),
|
GraphicsCommand::UseTexture(id) => self.use_texture(id),
|
||||||
GraphicsCommand::EndFrame => self.flush(),
|
GraphicsCommand::EndFrame => self.flush(),
|
||||||
|
|
@ -1234,31 +1234,43 @@ impl<'a> FrameBuilder<'a> {
|
||||||
T::get_vertex_buffer(self.state, &vb)
|
T::get_vertex_buffer(self.state, &vb)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_sprite(&mut self, si: SpriteInstance) {
|
fn push_sprite(&mut self, sc: script::graphics::SpriteCommand) {
|
||||||
if let Some(id) = self.last_texture {
|
if let Some(id) = self.last_texture {
|
||||||
let vertex_buffer = self.get_instance_buffer(DrawMode::Sprites(id));
|
let sprite = SpriteInstance {
|
||||||
vertex_buffer.vec.push(si);
|
src_top_left: sc.src_top_left,
|
||||||
|
src_dims: sc.src_dims,
|
||||||
|
|
||||||
|
dest_top_left: [
|
||||||
|
sc.dest_top_left[0] * self.scale[0],
|
||||||
|
sc.dest_top_left[1] * self.scale[1],
|
||||||
|
],
|
||||||
|
dest_dims: [
|
||||||
|
sc.dest_dims[0] * self.scale[0],
|
||||||
|
sc.dest_dims[1] * self.scale[1],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
self.get_instance_buffer(DrawMode::Sprites(id))
|
||||||
|
.vec
|
||||||
|
.push(sprite);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("WARNING: sprite drawn with no active texture");
|
eprintln!("WARNING: sprite drawn with no active texture");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_circle(&mut self, cc: script::graphics::CircleCommand) {
|
fn push_circle(&mut self, cc: script::graphics::CircleCommand) {
|
||||||
let stroke_color = self.stroke_color.clone();
|
let circle = CircleInstance {
|
||||||
let fill_color = self.fill_color.clone();
|
center: [cc.center[0] * self.scale[0], cc.center[1] * self.scale[1]],
|
||||||
|
radius: cc.radius * self.scale[0], // WRONG!
|
||||||
|
stroke_width: cc.stroke_width * self.scale[0], // ALSO WRONG!
|
||||||
|
stroke_color: self.stroke_color,
|
||||||
|
fill_color: self.fill_color,
|
||||||
|
};
|
||||||
|
|
||||||
let vertex_buffer = self.get_instance_buffer(DrawMode::Circles);
|
self.get_instance_buffer(DrawMode::Circles).vec.push(circle);
|
||||||
vertex_buffer.vec.push(CircleInstance {
|
|
||||||
center: cc.center,
|
|
||||||
radius: cc.radius,
|
|
||||||
stroke_width: cc.stroke_width,
|
|
||||||
stroke_color,
|
|
||||||
fill_color,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_text(&mut self, pc: script::graphics::PrintCommand) {
|
fn push_text(&mut self, pc: script::graphics::PrintCommand) {
|
||||||
// println!("{}", pc.text);
|
|
||||||
let mut cursor_x = pc.pos[0];
|
let mut cursor_x = pc.pos[0];
|
||||||
let cursor_y = pc.pos[1];
|
let cursor_y = pc.pos[1];
|
||||||
|
|
||||||
|
|
@ -1273,10 +1285,13 @@ impl<'a> FrameBuilder<'a> {
|
||||||
src_top_left: [glyph.x, glyph.y],
|
src_top_left: [glyph.x, glyph.y],
|
||||||
src_dims: [glyph.w, glyph.h],
|
src_dims: [glyph.w, glyph.h],
|
||||||
dest_top_left: [
|
dest_top_left: [
|
||||||
cursor_x + (glyph.adjust_x / TEXT_SCALE),
|
self.scale[0] * (cursor_x + (glyph.adjust_x / TEXT_SCALE)),
|
||||||
cursor_y + (glyph.adjust_y / TEXT_SCALE),
|
self.scale[1] * (cursor_y + (glyph.adjust_y / TEXT_SCALE)),
|
||||||
|
],
|
||||||
|
dest_dims: [
|
||||||
|
self.scale[0] * (glyph.w / TEXT_SCALE),
|
||||||
|
self.scale[1] * (glyph.h / TEXT_SCALE),
|
||||||
],
|
],
|
||||||
dest_dims: [glyph.w / TEXT_SCALE, glyph.h / TEXT_SCALE],
|
|
||||||
color,
|
color,
|
||||||
});
|
});
|
||||||
cursor_x += glyph.advance_width / TEXT_SCALE;
|
cursor_x += glyph.advance_width / TEXT_SCALE;
|
||||||
|
|
@ -1422,7 +1437,7 @@ fn main_thread(event_loop: EventLoopProxy<OdenEvent>, state: State, reciever: Re
|
||||||
|
|
||||||
{
|
{
|
||||||
let _span = span!("update");
|
let _span = span!("update");
|
||||||
script.update();
|
script.update((state.size.width as f32, state.size.height as f32));
|
||||||
state.update();
|
state.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -154,9 +154,11 @@ impl ScriptContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self) {
|
pub fn update(&mut self, dimensions: (f32, f32)) {
|
||||||
let _span = span!("script update");
|
let _span = span!("script update");
|
||||||
|
|
||||||
|
self.gfx.set_dimensions(dimensions);
|
||||||
|
|
||||||
if self.error_lines.len() > 0 {
|
if self.error_lines.len() > 0 {
|
||||||
return; // Don't bother, nothing.
|
return; // Don't bother, nothing.
|
||||||
}
|
}
|
||||||
|
|
@ -190,6 +192,7 @@ impl ScriptContext {
|
||||||
let _span = span!("script render");
|
let _span = span!("script render");
|
||||||
if self.error_lines.len() > 0 {
|
if self.error_lines.len() > 0 {
|
||||||
// TODO: Use font 0 for a fallback.
|
// TODO: Use font 0 for a fallback.
|
||||||
|
// TODO: Scale!! Remember you're using a font at size 8 or something.
|
||||||
let mut commands = vec![
|
let mut commands = vec![
|
||||||
GraphicsCommand::Clear(ClearCommand {
|
GraphicsCommand::Clear(ClearCommand {
|
||||||
color: [0.0, 0.0, 1.0, 1.0],
|
color: [0.0, 0.0, 1.0, 1.0],
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use oden_js::{module, ContextRef, Error, Result, Value};
|
use oden_js::{module, ContextRef, Error, Result, Value};
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::sync::atomic::{AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
@ -23,6 +24,15 @@ pub struct CreateTextureCommand {
|
||||||
pub label: Option<String>,
|
pub label: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SpriteCommand {
|
||||||
|
pub src_top_left: [f32; 2],
|
||||||
|
pub src_dims: [f32; 2],
|
||||||
|
|
||||||
|
pub dest_top_left: [f32; 2],
|
||||||
|
pub dest_dims: [f32; 2],
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CircleCommand {
|
pub struct CircleCommand {
|
||||||
pub center: [f32; 2],
|
pub center: [f32; 2],
|
||||||
|
|
@ -35,9 +45,10 @@ pub enum GraphicsCommand {
|
||||||
Clear(ClearCommand),
|
Clear(ClearCommand),
|
||||||
FillColor([f32; 4]),
|
FillColor([f32; 4]),
|
||||||
StrokeColor([f32; 4]),
|
StrokeColor([f32; 4]),
|
||||||
|
Scale([f32; 2]),
|
||||||
Print(PrintCommand),
|
Print(PrintCommand),
|
||||||
Circle(CircleCommand),
|
Circle(CircleCommand),
|
||||||
Sprite(crate::SpriteInstance),
|
Sprite(SpriteCommand),
|
||||||
CreateTexture(CreateTextureCommand),
|
CreateTexture(CreateTextureCommand),
|
||||||
CreateWritableTexture {
|
CreateWritableTexture {
|
||||||
id: u32,
|
id: u32,
|
||||||
|
|
@ -53,6 +64,7 @@ pub enum GraphicsCommand {
|
||||||
|
|
||||||
struct GraphicsImpl {
|
struct GraphicsImpl {
|
||||||
next_texture_id: AtomicU32,
|
next_texture_id: AtomicU32,
|
||||||
|
dimensions: (f32, f32),
|
||||||
sender: Sender<GraphicsCommand>,
|
sender: Sender<GraphicsCommand>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,6 +72,7 @@ impl GraphicsImpl {
|
||||||
pub fn new(sender: Sender<GraphicsCommand>) -> Self {
|
pub fn new(sender: Sender<GraphicsCommand>) -> Self {
|
||||||
GraphicsImpl {
|
GraphicsImpl {
|
||||||
sender,
|
sender,
|
||||||
|
dimensions: (0.0, 0.0),
|
||||||
next_texture_id: AtomicU32::new(0),
|
next_texture_id: AtomicU32::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -84,10 +97,12 @@ impl GraphicsImpl {
|
||||||
let _ = self.sender.send(GraphicsCommand::StrokeColor([r, g, b, a]));
|
let _ = self.sender.send(GraphicsCommand::StrokeColor([r, g, b, a]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn scale(&self, x: f32, y: f32) -> () {
|
||||||
|
let _ = self.sender.send(GraphicsCommand::Scale([x, y]));
|
||||||
|
}
|
||||||
|
|
||||||
fn spr(&self, x: f32, y: f32, w: f32, h: f32, u: f32, v: f32, sw: f32, sh: f32) {
|
fn spr(&self, x: f32, y: f32, w: f32, h: f32, u: f32, v: f32, sw: f32, sh: f32) {
|
||||||
let _ = self
|
let _ = self.sender.send(GraphicsCommand::Sprite(SpriteCommand {
|
||||||
.sender
|
|
||||||
.send(GraphicsCommand::Sprite(crate::SpriteInstance {
|
|
||||||
src_top_left: [u, v],
|
src_top_left: [u, v],
|
||||||
src_dims: [sw, sh],
|
src_dims: [sw, sh],
|
||||||
dest_top_left: [x, y],
|
dest_top_left: [x, y],
|
||||||
|
|
@ -155,28 +170,42 @@ impl GraphicsImpl {
|
||||||
fn write_to_texture(&self, id: u32) {
|
fn write_to_texture(&self, id: u32) {
|
||||||
let _ = self.sender.send(GraphicsCommand::WriteToTexture(id));
|
let _ = self.sender.send(GraphicsCommand::WriteToTexture(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_dimensions(&self, ctx: &ContextRef) -> Result<Value> {
|
||||||
|
let width = ctx.new_f64(self.dimensions.0)?;
|
||||||
|
let height = ctx.new_f64(self.dimensions.1)?;
|
||||||
|
|
||||||
|
let mut result = ctx.new_array()?;
|
||||||
|
result.set_index(ctx, 0, &width)?;
|
||||||
|
result.set_index(ctx, 1, &height)?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GraphicsAPI {
|
pub struct GraphicsAPI {
|
||||||
gfx: Arc<GraphicsImpl>,
|
gfx: Arc<RefCell<GraphicsImpl>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GraphicsAPI {
|
impl GraphicsAPI {
|
||||||
pub fn define(ctx: &ContextRef, sender: Sender<GraphicsCommand>) -> oden_js::Result<Self> {
|
pub fn define(ctx: &ContextRef, sender: Sender<GraphicsCommand>) -> oden_js::Result<Self> {
|
||||||
let gfx = Arc::new(GraphicsImpl::new(sender));
|
let gfx = Arc::new(RefCell::new(GraphicsImpl::new(sender)));
|
||||||
let mut builder = module::native::NativeModuleBuilder::new(ctx);
|
let mut builder = module::native::NativeModuleBuilder::new(ctx);
|
||||||
{
|
{
|
||||||
let gfx = gfx.clone();
|
let gfx = gfx.clone();
|
||||||
builder.export(
|
builder.export(
|
||||||
"print",
|
"print",
|
||||||
ctx.new_fn(move |_: &ContextRef, t: String, x: f32, y: f32| gfx.print(t, x, y))?,
|
ctx.new_fn(move |_: &ContextRef, t: String, x: f32, y: f32| {
|
||||||
|
gfx.borrow().print(t, x, y)
|
||||||
|
})?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let gfx = gfx.clone();
|
let gfx = gfx.clone();
|
||||||
builder.export(
|
builder.export(
|
||||||
"cls",
|
"cls",
|
||||||
ctx.new_fn(move |_: &ContextRef, r: f64, g: f64, b: f64| gfx.cls(r, g, b))?,
|
ctx.new_fn(move |_: &ContextRef, r: f64, g: f64, b: f64| {
|
||||||
|
gfx.borrow().cls(r, g, b)
|
||||||
|
})?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
@ -184,7 +213,7 @@ impl GraphicsAPI {
|
||||||
builder.export(
|
builder.export(
|
||||||
"color",
|
"color",
|
||||||
ctx.new_fn(move |_: &ContextRef, r: f32, g: f32, b: f32, a: f32| {
|
ctx.new_fn(move |_: &ContextRef, r: f32, g: f32, b: f32, a: f32| {
|
||||||
gfx.color(r, g, b, a)
|
gfx.borrow().color(r, g, b, a)
|
||||||
})?,
|
})?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
@ -193,10 +222,17 @@ impl GraphicsAPI {
|
||||||
builder.export(
|
builder.export(
|
||||||
"stroke",
|
"stroke",
|
||||||
ctx.new_fn(move |_: &ContextRef, r: f32, g: f32, b: f32, a: f32| {
|
ctx.new_fn(move |_: &ContextRef, r: f32, g: f32, b: f32, a: f32| {
|
||||||
gfx.stroke(r, g, b, a)
|
gfx.borrow().stroke(r, g, b, a)
|
||||||
})?,
|
})?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
let gfx = gfx.clone();
|
||||||
|
builder.export(
|
||||||
|
"scale",
|
||||||
|
ctx.new_fn(move |_: &ContextRef, x: f32, y: f32| gfx.borrow().scale(x, y))?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
{
|
{
|
||||||
let gfx = gfx.clone();
|
let gfx = gfx.clone();
|
||||||
builder.export(
|
builder.export(
|
||||||
|
|
@ -210,7 +246,7 @@ impl GraphicsAPI {
|
||||||
u: f32,
|
u: f32,
|
||||||
v: f32,
|
v: f32,
|
||||||
sw: f32,
|
sw: f32,
|
||||||
sh: f32| gfx.spr(x, y, w, h, u, v, sw, sh),
|
sh: f32| gfx.borrow().spr(x, y, w, h, u, v, sw, sh),
|
||||||
)?,
|
)?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
@ -219,7 +255,7 @@ impl GraphicsAPI {
|
||||||
builder.export(
|
builder.export(
|
||||||
"circle",
|
"circle",
|
||||||
ctx.new_fn(move |_: &ContextRef, x: f32, y: f32, r: f32, s: f32| {
|
ctx.new_fn(move |_: &ContextRef, x: f32, y: f32, r: f32, s: f32| {
|
||||||
gfx.circle(x, y, r, s)
|
gfx.borrow().circle(x, y, r, s)
|
||||||
})?,
|
})?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
@ -227,7 +263,7 @@ impl GraphicsAPI {
|
||||||
let gfx = gfx.clone();
|
let gfx = gfx.clone();
|
||||||
builder.export(
|
builder.export(
|
||||||
"use_texture",
|
"use_texture",
|
||||||
ctx.new_fn(move |_: &ContextRef, id: u32| gfx.use_texture(id))?,
|
ctx.new_fn(move |_: &ContextRef, id: u32| gfx.borrow().use_texture(id))?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
@ -236,7 +272,7 @@ impl GraphicsAPI {
|
||||||
"create_texture",
|
"create_texture",
|
||||||
ctx.new_fn(
|
ctx.new_fn(
|
||||||
move |c: &ContextRef, buffer: Value, label: Option<String>| {
|
move |c: &ContextRef, buffer: Value, label: Option<String>| {
|
||||||
gfx.create_texture(c, buffer, label)
|
gfx.borrow().create_texture(c, buffer, label)
|
||||||
},
|
},
|
||||||
)?,
|
)?,
|
||||||
)?;
|
)?;
|
||||||
|
|
@ -247,7 +283,7 @@ impl GraphicsAPI {
|
||||||
"create_writable_texture",
|
"create_writable_texture",
|
||||||
ctx.new_fn(
|
ctx.new_fn(
|
||||||
move |_: &ContextRef, width: u32, height: u32, label: Option<String>| {
|
move |_: &ContextRef, width: u32, height: u32, label: Option<String>| {
|
||||||
gfx.create_writable_texture(width, height, label)
|
gfx.borrow().create_writable_texture(width, height, label)
|
||||||
},
|
},
|
||||||
)?,
|
)?,
|
||||||
)?;
|
)?;
|
||||||
|
|
@ -256,14 +292,21 @@ impl GraphicsAPI {
|
||||||
let gfx = gfx.clone();
|
let gfx = gfx.clone();
|
||||||
builder.export(
|
builder.export(
|
||||||
"write_to_screen",
|
"write_to_screen",
|
||||||
ctx.new_fn(move |_: &ContextRef| gfx.write_to_screen())?,
|
ctx.new_fn(move |_: &ContextRef| gfx.borrow().write_to_screen())?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let gfx = gfx.clone();
|
let gfx = gfx.clone();
|
||||||
builder.export(
|
builder.export(
|
||||||
"write_to_texture",
|
"write_to_texture",
|
||||||
ctx.new_fn(move |_: &ContextRef, id: u32| gfx.write_to_texture(id))?,
|
ctx.new_fn(move |_: &ContextRef, id: u32| gfx.borrow().write_to_texture(id))?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let gfx = gfx.clone();
|
||||||
|
builder.export(
|
||||||
|
"get_dimensions",
|
||||||
|
ctx.new_fn(move |ctx: &ContextRef| gfx.borrow().get_dimensions(ctx))?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,7 +314,11 @@ impl GraphicsAPI {
|
||||||
Ok(GraphicsAPI { gfx })
|
Ok(GraphicsAPI { gfx })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_dimensions(&mut self, dimensions: (f32, f32)) {
|
||||||
|
self.gfx.borrow_mut().dimensions = dimensions;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn end_frame(&self) {
|
pub fn end_frame(&self) {
|
||||||
let _ = self.gfx.sender.send(GraphicsCommand::EndFrame);
|
let _ = self.gfx.borrow().sender.send(GraphicsCommand::EndFrame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
struct ScreenUniform {
|
struct ScreenUniform {
|
||||||
resolution : vec2f,
|
resolution : vec2f,
|
||||||
zoom : vec2f,
|
|
||||||
};
|
};
|
||||||
@group(0) @binding(0) // 1.
|
@group(0) @binding(0) // 1.
|
||||||
var<uniform> screen : ScreenUniform;
|
var<uniform> screen : ScreenUniform;
|
||||||
|
|
@ -20,7 +19,7 @@ fn adjust_for_resolution(in_pos: vec2<f32>) -> vec2<f32> {
|
||||||
//
|
//
|
||||||
// Put result in the range [0-2], where (2,2) is the bottom-right corner
|
// Put result in the range [0-2], where (2,2) is the bottom-right corner
|
||||||
// of the screen.
|
// of the screen.
|
||||||
var result = (in_pos * screen.zoom * 2.0) / screen.resolution;
|
var result = (in_pos * 2.0) / screen.resolution;
|
||||||
|
|
||||||
// Put result in the range [-1,1] where [1,1] is the bottom-right corner
|
// Put result in the range [-1,1] where [1,1] is the bottom-right corner
|
||||||
// of the screen.
|
// of the screen.
|
||||||
|
|
|
||||||
4
types/graphics-core.d.ts
vendored
4
types/graphics-core.d.ts
vendored
|
|
@ -8,6 +8,8 @@ export function color(r: number, g: number, b: number, a: number);
|
||||||
|
|
||||||
export function stroke(r: number, g: number, b: number, a: number);
|
export function stroke(r: number, g: number, b: number, a: number);
|
||||||
|
|
||||||
|
export function scale(x: number, y: number);
|
||||||
|
|
||||||
export function spr(
|
export function spr(
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
|
|
@ -37,3 +39,5 @@ export function create_writable_texture(
|
||||||
export function write_to_screen();
|
export function write_to_screen();
|
||||||
|
|
||||||
export function write_to_texture(id: number);
|
export function write_to_texture(id: number);
|
||||||
|
|
||||||
|
export function get_dimensions(): [number, number];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue