diff --git a/main.lua b/main.lua index d59fa2d..2d5ee3a 100644 --- a/main.lua +++ b/main.lua @@ -2,6 +2,7 @@ print("Hello from a lua script!") function init() print("Hello from \"init\"") + print(couch.root:find_node("cube"):get_transform()) couch.debug("init") couch.say_hello("dane", "Hi!") end diff --git a/src/gameobject.rs b/src/gameobject.rs index 40e7396..052ce58 100644 --- a/src/gameobject.rs +++ b/src/gameobject.rs @@ -2,34 +2,35 @@ use nalgebra_glm as glm; use crate::model::Model; +use std::rc::Rc; +use std::cell::RefCell; + +pub type NodeRef = Rc>; + pub struct Node { pub name: String, pub gameobject: GameObject, - pub children: Vec, + pub children: Vec, } -pub trait Childbearing { +pub trait Childbearing { // TODO remove this fn add_child(&mut self, name: &str, child: T); - fn find_node(&mut self, name: &str) -> Option<&mut Box>; +} + +impl Node { + pub fn find_node(&mut self, name: &str) -> Option { + match self.children.iter().find(|node| node.borrow().name == name) { + Some(node) => Some(Rc::clone(node)), + None => None + } + } } macro_rules! impl_childbearing { ($t:ty, $e:path) => { impl Childbearing<$t> for Node { fn add_child(&mut self, name: &str, child: $t) { - self.children.push(Node::new(name.to_string(), $e(Box::new(child)))); - } - fn find_node(&mut self, name: &str) -> Option<&mut Box<$t>> { - match self.children.iter_mut().find(|node| node.name == name) { - Some(node) => { - if let $e(child) = &mut node.gameobject { - Some(child) - } else { - None - } - }, - None => None, - } + self.children.push(Rc::new(RefCell::new(Node::new(name.to_string(), $e(child))))); } } } @@ -49,8 +50,8 @@ impl Node { pub enum GameObject { Null, - Camera(Box), - Mesh(Box), + Camera(Camera), + Mesh(Mesh), } #[derive(Clone, Copy)] diff --git a/src/main.rs b/src/main.rs index 43eadec..e063864 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,20 @@ mod device; + mod model; +use model::Model; + mod scripting; +use scripting::{ ScriptLang, Lua }; + mod gameobject; +use gameobject::*; #[macro_use] extern crate glium; extern crate nalgebra_glm as glm; -use model::Model; - -use scripting::{ ScriptLang, Lua }; - -use gameobject::*; +use std::rc::Rc; +use std::cell::RefCell; fn main() { use glium::{glutin, Surface}; @@ -30,18 +33,22 @@ fn main() { let mut device_manager = crate::device::DeviceManager::new(); - let mut root = Node::new("_root_".to_string(), GameObject::Null); - root.add_child("camera", Camera::new()); + let root = Rc::new(RefCell::new(Node::new("_root_".to_string(), GameObject::Null))); + { + // Initial scene setup + let mut root = root.borrow_mut(); + root.add_child("camera", Camera::new()); - let mut cube = Mesh::new(Model::new(&display, "Box.glb")); - cube.set_transform(gameobject::Transform { - position: glm::vec3(0.0, 0.0, -10.0), - rotation: glm::vec3(0.0, 15.0_f32.to_radians(), 0.0), - scale: glm::vec3(1.0, 1.0, 1.0), - }); - root.add_child("cube", cube); + let mut cube = Mesh::new(Model::new(&display, "Box.glb")); + cube.set_transform(gameobject::Transform { + position: glm::vec3(0.0, 0.0, -10.0), + rotation: glm::vec3(0.0, 15.0_f32.to_radians(), 0.0), + scale: glm::vec3(1.0, 1.0, 1.0), + }); + root.add_child("cube", cube); + } - let mut script_lang = Lua::new(); + let mut script_lang = Lua::new(Rc::clone(&root)); script_lang.init(); let mut last_draw = std::time::Instant::now(); @@ -77,8 +84,15 @@ fn main() { .. Default::default() }; target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0); - - let cube: &mut Box = root.find_node("cube").unwrap(); + + let mut root = root.borrow_mut(); + + let cube = root.find_node("cube").unwrap(); + let mut cube = cube.borrow_mut(); + let cube: &mut Mesh = match &mut cube.gameobject { + GameObject::Mesh(mesh) => mesh, + _ => panic!("cube is not a mesh"), + }; let mut transform = cube.get_transform(); if device_manager.is_pressed(&device::Key::W) { transform.position.z += 1.0 * delta; @@ -101,8 +115,6 @@ fn main() { }; cube.model.draw(&mut target, &program, &uniforms, ¶ms); - let _camera: &mut Box = root.find_node("camera").unwrap(); - target.finish().unwrap(); } _ => (), diff --git a/src/scripting.rs b/src/scripting.rs index 3310c0d..6d0ef19 100644 --- a/src/scripting.rs +++ b/src/scripting.rs @@ -1,8 +1,12 @@ -extern crate mlua; +use crate::gameobject::{ Node, Transform, Spatial }; +extern crate mlua; use mlua::Lua as LuaContext; use mlua::chunk; +use std::rc::Rc; +use std::cell::RefCell; + pub trait ScriptLang { fn init(&mut self); fn update(&mut self, delta: f32); @@ -12,12 +16,35 @@ pub struct Lua { ctx: LuaContext, } +impl mlua::UserData for Node { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + use crate::gameobject::GameObject::*; + methods.add_method_mut("find_node", |_, this, name: String| { + let child = this.find_node(&name); + match child { + Some(child) => Ok(child), + None => Err(mlua::Error::RuntimeError("Could not find child".to_string())), + } + }); + methods.add_method("get_transform", |_, this, _: ()| { + match &this.gameobject { + Mesh(mesh) => Ok(mesh.get_transform()), + Camera(camera) => Ok(camera.get_transform()), + _ => Err(mlua::Error::RuntimeError("Node does not implement get_transform".to_string())) + } + }); + } +} + +impl mlua::UserData for Transform {} + impl Lua { - pub fn new() -> Self { + pub fn new(root: Rc>) -> Self { // Create a lua context, load std libraries let ctx = LuaContext::new(); // Create the ``couch'' api let couch = ctx.create_table().unwrap(); + couch.set("root", ctx.create_userdata(root).unwrap()).unwrap(); couch.set("debug", ctx.create_function(debug).unwrap()).unwrap(); couch.set("say_hello", ctx.create_function(say_hello).unwrap()).unwrap(); // Hook in to globals