Start implementing lua scripting

This commit is contained in:
Dane Johnson 2022-04-15 14:54:15 -05:00
parent 0e6cc64c89
commit d6b5f82d72
4 changed files with 80 additions and 39 deletions

View File

@ -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

View File

@ -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<RefCell<Node>>;
pub struct Node {
pub name: String,
pub gameobject: GameObject,
pub children: Vec<Node>,
pub children: Vec<NodeRef>,
}
pub trait Childbearing<T> {
pub trait Childbearing<T> { // TODO remove this
fn add_child(&mut self, name: &str, child: T);
fn find_node(&mut self, name: &str) -> Option<&mut Box<T>>;
}
impl Node {
pub fn find_node(&mut self, name: &str) -> Option<NodeRef> {
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<Camera>),
Mesh(Box<Mesh>),
Camera(Camera),
Mesh(Mesh),
}
#[derive(Clone, Copy)]

View File

@ -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();
@ -78,7 +85,14 @@ fn main() {
};
target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
let cube: &mut Box<Mesh> = 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, &params);
let _camera: &mut Box<Camera> = root.find_node("camera").unwrap();
target.finish().unwrap();
}
_ => (),

View File

@ -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<RefCell<Node>>) -> 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