171 lines
5.3 KiB
Rust
171 lines
5.3 KiB
Rust
// Copyright 2020 Sergiusz 'q3k' Bazanski <q3k@q3k.org>
|
|
//
|
|
// This file is part of Abrasion.
|
|
//
|
|
// Abrasion is free software: you can redistribute it and/or modify it under
|
|
// the terms of the GNU General Public License as published by the Free
|
|
// Software Foundation, version 3.
|
|
//
|
|
// Abrasion is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
// details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License along with
|
|
// Abrasion. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
use std::collections::HashMap;
|
|
use std::hash;
|
|
use std::cell::Ref;
|
|
|
|
use cgmath as cgm;
|
|
|
|
use ecs::{Component, ComponentLuaBindings};
|
|
use crate::render::{Light, Mesh, Material};
|
|
use crate::render::resource::{ResourceID};
|
|
|
|
use mlua::ToLua;
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Transform(pub cgm::Matrix4<f32>);
|
|
|
|
impl Component for Transform {
|
|
fn id(&self) -> ecs::component::ID {
|
|
ecs::component::component_id::<Transform>()
|
|
}
|
|
fn clone_dyn(&self) -> Box<dyn Component> {
|
|
Box::new(self.clone())
|
|
}
|
|
fn lua_userdata<'access, 'lua>(
|
|
&'access self,
|
|
lua: &'lua mlua::Lua,
|
|
) -> Option<mlua::Value<'lua>> {
|
|
let ud: mlua::Value<'lua> = self.clone().to_lua(lua).unwrap();
|
|
Some(ud)
|
|
}
|
|
fn lua_fromuserdata<'a>(
|
|
&self,
|
|
ud: &'a mlua::AnyUserData,
|
|
) -> Option<Box<dyn Component>> {
|
|
match ud.borrow::<Transform>() {
|
|
Ok(v) => Some(Box::new(Transform::clone(&v))),
|
|
Err(_) => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
struct TransformBindings;
|
|
|
|
impl ComponentLuaBindings for TransformBindings {
|
|
fn globals<'a>(&self, lua: &'a mlua::Lua) -> mlua::Table<'a> {
|
|
let res = lua.create_table().unwrap();
|
|
res.set("new", lua.create_function(|_, args: mlua::Variadic<mlua::Number>| {
|
|
let args: Vec<f32> = args.iter().map(|el| *el as f32).collect();
|
|
let t = match args.len() {
|
|
0 => Transform::at(0., 0., 0.),
|
|
3 => Transform::at(args[0], args[1], args[2]),
|
|
16 => Transform(cgm::Matrix4::new(
|
|
// Matrix4::new takes column-wise arguments, this api takes them row-wise.
|
|
args[0], args[4], args[8], args[12],
|
|
args[1], args[5], args[9], args[13],
|
|
args[2], args[6], args[10], args[14],
|
|
args[3], args[7], args[11], args[15],
|
|
)),
|
|
_ => {
|
|
return Err(mlua::prelude::LuaError::RuntimeError("Transform.new must be called with 0, 3 ,or 16 arguments".to_string()));
|
|
},
|
|
};
|
|
Ok(t)
|
|
}).unwrap()).unwrap();
|
|
res
|
|
}
|
|
fn idstr(&self) -> &'static str {
|
|
"Transform"
|
|
}
|
|
fn id(&self) -> ecs::component::ID {
|
|
ecs::component::component_id::<Transform>()
|
|
}
|
|
fn any_into_dyn<'a>(&self, ud: &'a mlua::AnyUserData) -> Option<Box<dyn Component>> {
|
|
match ud.borrow::<Transform>() {
|
|
Ok(v) => Some(Box::new(Transform::clone(&v))),
|
|
Err(_) => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
impl mlua::UserData for Transform {
|
|
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
|
|
methods.add_method("xyzw", |_, this, _: ()| {
|
|
// TODO(q3k): lua wrappers for cgmath
|
|
let xyzw = this.xyzw();
|
|
Ok(vec![xyzw.x, xyzw.y, xyzw.z, xyzw.w])
|
|
});
|
|
}
|
|
}
|
|
|
|
impl Transform {
|
|
pub fn at(x: f32, y: f32, z: f32) -> Self {
|
|
Transform(cgm::Matrix4::from_translation(cgm::Vector3::new(x, y, z)))
|
|
}
|
|
pub fn xyzw(&self) -> cgm::Vector4<f32> {
|
|
self.0 * cgm::Vector4::new(0.0, 0.0, 0.0, 1.0)
|
|
}
|
|
pub fn xyz(&self) -> cgm::Vector3<f32> {
|
|
let res4 = self.xyzw();
|
|
cgm::Vector3::new(res4.x/res4.w, res4.y/res4.w, res4.z/res4.w)
|
|
}
|
|
pub fn m4(&self) -> &cgm::Matrix4<f32> {
|
|
&self.0
|
|
}
|
|
pub fn bindings() -> Box<dyn ComponentLuaBindings> {
|
|
Box::new(TransformBindings)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum Renderable {
|
|
Light(ResourceID<Light>),
|
|
Mesh(ResourceID<Mesh>, ResourceID<Material>),
|
|
}
|
|
impl mlua::UserData for Renderable {}
|
|
|
|
impl Renderable {
|
|
pub fn bindings() -> Box<dyn ComponentLuaBindings> {
|
|
Box::new(RenderableBindings)
|
|
}
|
|
}
|
|
|
|
impl Component for Renderable {
|
|
fn id(&self) -> ecs::component::ID {
|
|
ecs::component::component_id::<Renderable>()
|
|
}
|
|
fn clone_dyn(&self) -> Box<dyn Component> {
|
|
Box::new(self.clone())
|
|
}
|
|
}
|
|
|
|
struct RenderableBindings;
|
|
|
|
impl ComponentLuaBindings for RenderableBindings {
|
|
fn globals<'a>(&self, lua: &'a mlua::Lua) -> mlua::Table<'a> {
|
|
let res = lua.create_table().unwrap();
|
|
res.set("new_mesh", lua.create_function(|_, args: (ResourceID<Mesh>, ResourceID<Material>)| {
|
|
Ok(Renderable::Mesh(args.0, args.1))
|
|
}).unwrap()).unwrap();
|
|
res
|
|
}
|
|
fn idstr(&self) -> &'static str {
|
|
"Renderable"
|
|
}
|
|
fn id(&self) -> ecs::component::ID {
|
|
ecs::component::component_id::<Renderable>()
|
|
}
|
|
fn any_into_dyn<'a>(&self, ud: &'a mlua::AnyUserData) -> Option<Box<dyn Component>> {
|
|
match ud.borrow::<Renderable>() {
|
|
Ok(v) => Some(Box::new(Renderable::clone(&v))),
|
|
Err(_) => None,
|
|
}
|
|
}
|
|
}
|