lua: make it easier to expose events and asset handle wrappers
This commit is contained in:
parent
6a47cd2671
commit
d0e6fc6ecd
|
@ -257,5 +257,13 @@ pub(crate) fn lua_wrap_handle_impl(input: proc_macro::TokenStream) -> proc_macro
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LuaHandleWrapper for #wrapper_name {
|
||||||
|
type ResourceType = #handle_path;
|
||||||
|
|
||||||
|
fn from_handle(handle: ResHandle<Self::ResourceType>) -> Self {
|
||||||
|
Self(handle)
|
||||||
|
}
|
||||||
|
}
|
||||||
}.into()
|
}.into()
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@ pub mod dynamic_iter;
|
||||||
pub use dynamic_iter::*;
|
pub use dynamic_iter::*;
|
||||||
|
|
||||||
pub mod world;
|
pub mod world;
|
||||||
|
use lyra_resource::ResourceData;
|
||||||
use mlua::ObjectLike;
|
use mlua::ObjectLike;
|
||||||
pub use world::*;
|
pub use world::*;
|
||||||
|
|
||||||
|
@ -19,11 +20,12 @@ pub use proxy::*;
|
||||||
|
|
||||||
pub mod system;
|
pub mod system;
|
||||||
pub use system::*;
|
pub use system::*;
|
||||||
|
use wrappers::{LuaHandleWrapper, LuaResHandleToComponent, LuaWrappedEventProxy};
|
||||||
|
|
||||||
use std::{any::TypeId, sync::Mutex};
|
use std::{any::TypeId, sync::Mutex};
|
||||||
|
|
||||||
use lyra_ecs::World;
|
use lyra_ecs::World;
|
||||||
use lyra_reflect::{Reflect, TypeRegistry};
|
use lyra_reflect::{FromType, Reflect, TypeRegistry};
|
||||||
use crate::ScriptBorrow;
|
use crate::ScriptBorrow;
|
||||||
|
|
||||||
pub type LuaContext = Mutex<mlua::Lua>;
|
pub type LuaContext = Mutex<mlua::Lua>;
|
||||||
|
@ -140,10 +142,27 @@ pub trait RegisterLuaType {
|
||||||
T: Clone + mlua::FromLua + mlua::IntoLua + LuaWrapper + 'static,
|
T: Clone + mlua::FromLua + mlua::IntoLua + LuaWrapper + 'static,
|
||||||
T::Wrap: lyra_ecs::Component + Reflect;
|
T::Wrap: lyra_ecs::Component + Reflect;
|
||||||
|
|
||||||
|
/// Register an asset handle wrapper.
|
||||||
|
fn register_asset_handle<T>(&mut self, name: &str)
|
||||||
|
where
|
||||||
|
T: LuaHandleWrapper + Reflect + LuaProxy,
|
||||||
|
T::ResourceType: ResourceData;
|
||||||
|
|
||||||
|
/// Add an entry for a non-component in the [`TypeLookup`] table.
|
||||||
|
fn add_lua_event<T>(&mut self, name: &str)
|
||||||
|
where
|
||||||
|
T: Reflect + LuaWrapper + mlua::FromLua + mlua::IntoLua + Send + Sync,
|
||||||
|
T::Wrap: Clone + lyra_game::Event;
|
||||||
|
|
||||||
/// Add an entry for a component in the [`TypeLookup`] table.
|
/// Add an entry for a component in the [`TypeLookup`] table.
|
||||||
fn add_component_lookup_entry<T>(&mut self, name: &str)
|
fn add_component_lookup_entry<T>(&mut self, name: &str)
|
||||||
where
|
where
|
||||||
T: lyra_ecs::Component;
|
T: lyra_ecs::Component;
|
||||||
|
|
||||||
|
/// Add an entry for a non-component in the [`TypeLookup`] table.
|
||||||
|
fn add_lookup_entry<T>(&mut self, name: &str)
|
||||||
|
where
|
||||||
|
T: 'static;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegisterLuaType for World {
|
impl RegisterLuaType for World {
|
||||||
|
@ -188,6 +207,37 @@ impl RegisterLuaType for World {
|
||||||
self.add_component_lookup_entry::<T::Wrap>(name);
|
self.add_component_lookup_entry::<T::Wrap>(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn register_asset_handle<T>(&mut self, name: &str)
|
||||||
|
where
|
||||||
|
T: LuaHandleWrapper + Reflect + LuaProxy,
|
||||||
|
T::ResourceType: ResourceData
|
||||||
|
{
|
||||||
|
{
|
||||||
|
let mut registry = self.get_resource_mut::<TypeRegistry>().unwrap();
|
||||||
|
let reg_type = registry.get_type_or_default(TypeId::of::<T::ResourceType>());
|
||||||
|
reg_type.add_data(ReflectLuaProxy::from_lua_proxy::<T>());
|
||||||
|
let l: LuaResHandleToComponent = FromType::<T>::from_type();
|
||||||
|
reg_type.add_data(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.add_lookup_entry::<T>(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_lua_event<T>(&mut self, name: &str)
|
||||||
|
where
|
||||||
|
T: Reflect + LuaWrapper + mlua::FromLua + mlua::IntoLua + Send + Sync,
|
||||||
|
T::Wrap: Clone + lyra_game::Event
|
||||||
|
{
|
||||||
|
{
|
||||||
|
let mut registry = self.get_resource_mut::<TypeRegistry>().unwrap();
|
||||||
|
let reg_type = registry.get_type_or_default(TypeId::of::<T::Wrap>());
|
||||||
|
let proxy: LuaWrappedEventProxy = FromType::<T>::from_type();
|
||||||
|
reg_type.add_data(proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.add_lookup_entry::<T::Wrap>(name);
|
||||||
|
}
|
||||||
|
|
||||||
fn add_component_lookup_entry<T>(&mut self, name: &str)
|
fn add_component_lookup_entry<T>(&mut self, name: &str)
|
||||||
where
|
where
|
||||||
T: lyra_ecs::Component
|
T: lyra_ecs::Component
|
||||||
|
@ -196,6 +246,14 @@ impl RegisterLuaType for World {
|
||||||
lookup.comp_info_from_name.insert(name.into(), lyra_ecs::ComponentInfo::new::<T>());
|
lookup.comp_info_from_name.insert(name.into(), lyra_ecs::ComponentInfo::new::<T>());
|
||||||
lookup.typeid_from_name.insert(name.into(), std::any::TypeId::of::<T>());
|
lookup.typeid_from_name.insert(name.into(), std::any::TypeId::of::<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_lookup_entry<T>(&mut self, name: &str)
|
||||||
|
where
|
||||||
|
T: 'static
|
||||||
|
{
|
||||||
|
let mut lookup = self.get_resource_or_default::<TypeLookup>();
|
||||||
|
lookup.typeid_from_name.insert(name.into(), std::any::TypeId::of::<T>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl mlua::FromLua for ScriptBorrow {
|
impl mlua::FromLua for ScriptBorrow {
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
use std::any::TypeId;
|
|
||||||
|
|
||||||
use lyra_ecs::ResourceObject;
|
use lyra_ecs::ResourceObject;
|
||||||
use lyra_game::winit::DeviceEventPair;
|
use lyra_reflect::Reflect;
|
||||||
use lyra_reflect::{FromType, Reflect, TypeRegistry};
|
|
||||||
use lyra_resource::gltf::Gltf;
|
|
||||||
|
|
||||||
use crate::{lua::{wrappers::*, LuaContext, LuaWrapper, ReflectLuaProxy, RegisterLuaType, TypeLookup, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE}, ScriptApiProvider, ScriptBorrow, ScriptData, ScriptDynamicBundle, ScriptWorldPtr};
|
use crate::{lua::{wrappers::*, LuaContext, LuaWrapper, RegisterLuaType, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE}, ScriptApiProvider, ScriptBorrow, ScriptData, ScriptDynamicBundle, ScriptWorldPtr};
|
||||||
|
|
||||||
//fn register_lua_proxy::<T:
|
//fn register_lua_proxy::<T:
|
||||||
|
|
||||||
|
@ -20,37 +16,16 @@ impl ScriptApiProvider for LyraEcsApiProvider {
|
||||||
world.register_lua_wrapper::<LuaSceneHandle>();
|
world.register_lua_wrapper::<LuaSceneHandle>();
|
||||||
world.register_lua_wrapper::<LuaActionHandler>();
|
world.register_lua_wrapper::<LuaActionHandler>();
|
||||||
world.register_lua_wrapper::<LuaWindow>();
|
world.register_lua_wrapper::<LuaWindow>();
|
||||||
|
|
||||||
world.register_lua_convert_component::<LuaCamera>("Camera");
|
world.register_lua_convert_component::<LuaCamera>("Camera");
|
||||||
world.register_lua_convert_component::<LuaFreeFlyCamera>("FreeFlyCamera");
|
world.register_lua_convert_component::<LuaFreeFlyCamera>("FreeFlyCamera");
|
||||||
|
|
||||||
world.register_lua_wrapper::<LuaDeviceId>();
|
world.register_lua_wrapper::<LuaDeviceId>();
|
||||||
world.register_lua_convert::<LuaDeviceEventRaw>();
|
world.register_lua_convert::<LuaDeviceEventRaw>();
|
||||||
world.register_lua_convert::<LuaDeviceEvent>();
|
world.register_lua_convert::<LuaDeviceEvent>();
|
||||||
|
world.add_lua_event::<LuaDeviceEvent>("DeviceEvent");
|
||||||
|
|
||||||
// Add typeid of 'DeviceEvent'
|
world.register_asset_handle::<LuaGltfHandle>("Gltf");
|
||||||
let mut lookup = world.get_resource_or_default::<TypeLookup>();
|
|
||||||
lookup.typeid_from_name.insert("DeviceEvent".into(), std::any::TypeId::of::<DeviceEventPair>());
|
|
||||||
drop(lookup);
|
|
||||||
|
|
||||||
let mut registry = world.get_resource_mut::<TypeRegistry>().unwrap();
|
|
||||||
|
|
||||||
// add LuaWrappedEventProxy
|
|
||||||
let reg_type = registry.get_type_or_default(TypeId::of::<DeviceEventPair>());
|
|
||||||
let l: LuaWrappedEventProxy = FromType::<LuaDeviceEvent>::from_type();
|
|
||||||
reg_type.add_data(l);
|
|
||||||
|
|
||||||
// add Gltf handle
|
|
||||||
let reg_type = registry.get_type_or_default(TypeId::of::<Gltf>());
|
|
||||||
reg_type.add_data(ReflectLuaProxy::from_lua_proxy::<LuaGltfHandle>());
|
|
||||||
let l = LuaResHandleToComponent::new(
|
|
||||||
|lua, res| {
|
|
||||||
if let Some(gltf) = res.as_typed::<Gltf>() {
|
|
||||||
Some(lua.create_userdata(LuaGltfHandle(gltf)).unwrap())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
reg_type.add_data(l);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_api(&mut self, _: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
fn expose_api(&mut self, _: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||||
|
|
|
@ -0,0 +1,237 @@
|
||||||
|
use std::{any::TypeId, ops::Deref};
|
||||||
|
use lyra_resource::{gltf::{Gltf, Material, Mesh}, FilterMode, ResHandle, Texture, WrappingMode};
|
||||||
|
use lyra_game::scene::SceneGraph;
|
||||||
|
use lyra_reflect::Reflect;
|
||||||
|
use lyra_scripting_derive::{lua_wrap_handle, wrap_lua_struct};
|
||||||
|
|
||||||
|
use crate::{lua::{LuaWrapper, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE}, lyra_engine, ScriptBorrow};
|
||||||
|
use crate as lyra_scripting;
|
||||||
|
|
||||||
|
use super::LuaHandleWrapper;
|
||||||
|
|
||||||
|
use mlua::IntoLua;
|
||||||
|
|
||||||
|
fn filter_mode_to_str(fm: FilterMode) -> &'static str {
|
||||||
|
match fm {
|
||||||
|
FilterMode::Nearest => "nearest",
|
||||||
|
FilterMode::Linear => "linear",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrapping_mode_to_str(wm: WrappingMode) -> &'static str {
|
||||||
|
match wm {
|
||||||
|
WrappingMode::ClampToEdge => "clamp_to_edge",
|
||||||
|
WrappingMode::MirroredRepeat => "mirrored_repeat",
|
||||||
|
WrappingMode::Repeat => "repeat",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wrap_lua_struct!(lyra_resource::TextureSampler,
|
||||||
|
// this can be safely skipped since it wont be a component or resource.
|
||||||
|
skip(lua_reflect),
|
||||||
|
fields={
|
||||||
|
// don't need to specify field types since setters are skipped
|
||||||
|
(mag_filter, skip_set, get={
|
||||||
|
this.mag_filter.map(|f| filter_mode_to_str(f))
|
||||||
|
.into_lua(lua)
|
||||||
|
}),
|
||||||
|
(min_filter, skip_set, get={
|
||||||
|
this.min_filter.map(|f| filter_mode_to_str(f))
|
||||||
|
.into_lua(lua)
|
||||||
|
}),
|
||||||
|
(mipmap_filter, skip_set, get={
|
||||||
|
this.mipmap_filter.map(|f| filter_mode_to_str(f))
|
||||||
|
.into_lua(lua)
|
||||||
|
}),
|
||||||
|
(wrap_u, skip_set, get={
|
||||||
|
wrapping_mode_to_str(this.wrap_u)
|
||||||
|
.into_lua(lua)
|
||||||
|
}),
|
||||||
|
(wrap_v, skip_set, get={
|
||||||
|
wrapping_mode_to_str(this.wrap_v)
|
||||||
|
.into_lua(lua)
|
||||||
|
}),
|
||||||
|
(wrap_w, skip_set, get={
|
||||||
|
wrapping_mode_to_str(this.wrap_w)
|
||||||
|
.into_lua(lua)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
wrap_lua_struct!(lyra_resource::gltf::PbrGlossiness,
|
||||||
|
// this can be safely skipped since it wont be a component or resource.
|
||||||
|
skip(lua_reflect),
|
||||||
|
fields={
|
||||||
|
(diffuse_color: wrap(crate::lua::wrappers::LuaVec4), skip_set),
|
||||||
|
(specular: wrap(crate::lua::wrappers::LuaVec3), skip_set),
|
||||||
|
(glossiness, skip_set),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
wrap_lua_struct!(lyra_resource::gltf::Specular,
|
||||||
|
// this can be safely skipped since it wont be a component or resource.
|
||||||
|
skip(lua_reflect),
|
||||||
|
fields={
|
||||||
|
(factor, skip_set),
|
||||||
|
(color_factor: wrap(crate::lua::wrappers::LuaVec3), skip_set),
|
||||||
|
(texture, skip_set, get={
|
||||||
|
this.texture.clone()
|
||||||
|
.map(|t| LuaTextureHandle(t))
|
||||||
|
.into_lua(lua)
|
||||||
|
}),
|
||||||
|
(color_texture, skip_set, get={
|
||||||
|
this.color_texture.clone()
|
||||||
|
.map(|t| LuaTextureHandle(t))
|
||||||
|
.into_lua(lua)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: fields
|
||||||
|
lua_wrap_handle!(SceneGraph, name=Scene, {});
|
||||||
|
|
||||||
|
lua_wrap_handle!(Mesh,
|
||||||
|
field_getters={
|
||||||
|
(material, {
|
||||||
|
data.material.clone()
|
||||||
|
.map(|v| LuaMaterialHandle(v.clone()))
|
||||||
|
.into_lua(lua)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
methods.add_method("indices", |lua, this, ()| {
|
||||||
|
if let Some(data) = this.0.data_ref() {
|
||||||
|
let table = lua.create_table()?;
|
||||||
|
|
||||||
|
match &data.indices {
|
||||||
|
Some(lyra_resource::gltf::MeshIndices::U16(v)) => {
|
||||||
|
for (i, ind) in v.iter().enumerate() {
|
||||||
|
let i = i as i64 + 1; // lua indexes start at 1
|
||||||
|
table.raw_set(i, *ind)?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some(lyra_resource::gltf::MeshIndices::U32(v)) => {
|
||||||
|
for (i, ind) in v.iter().enumerate() {
|
||||||
|
let i = i as i64 + 1; // lua indexes start at 1
|
||||||
|
table.raw_set(i, *ind)?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(mlua::Value::Table(table))
|
||||||
|
} else {
|
||||||
|
Ok(mlua::Value::Nil)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: mesh attributes
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
lua_wrap_handle!(lyra_resource::Image,
|
||||||
|
field_getters={
|
||||||
|
(width, {
|
||||||
|
data.width().into_lua(lua)
|
||||||
|
}),
|
||||||
|
(height, {
|
||||||
|
data.height().into_lua(lua)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
lua_wrap_handle!(Texture,
|
||||||
|
field_getters={
|
||||||
|
(image, wrapper=LuaImageHandle),
|
||||||
|
(sampler, {
|
||||||
|
data.sampler.clone()
|
||||||
|
.map(|s| LuaTextureSampler(s))
|
||||||
|
.into_lua(lua)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
lua_wrap_handle!(Material,
|
||||||
|
field_getters={
|
||||||
|
shader_uuid,
|
||||||
|
name,
|
||||||
|
double_sided,
|
||||||
|
(base_color, wrapper=crate::lua::wrappers::LuaVec4),
|
||||||
|
metallic,
|
||||||
|
roughness,
|
||||||
|
(base_color_texture, {
|
||||||
|
data.base_color_texture.clone()
|
||||||
|
.map(|v| LuaTextureHandle(v.clone()))
|
||||||
|
.into_lua(lua)
|
||||||
|
}),
|
||||||
|
(metallic_roughness_texture, {
|
||||||
|
data.metallic_roughness_texture.clone()
|
||||||
|
.map(|v| LuaTextureHandle(v.clone()))
|
||||||
|
.into_lua(lua)
|
||||||
|
}),
|
||||||
|
(pbr_glossiness, {
|
||||||
|
data.pbr_glossiness.clone()
|
||||||
|
.map(|v| LuaPbrGlossiness(v.clone()))
|
||||||
|
.into_lua(lua)
|
||||||
|
}),
|
||||||
|
alpha_cutoff,
|
||||||
|
(alpha_mode, {
|
||||||
|
match data.alpha_mode {
|
||||||
|
lyra_resource::gltf::AlphaMode::Opaque => "opaque",
|
||||||
|
lyra_resource::gltf::AlphaMode::Mask => "mask",
|
||||||
|
lyra_resource::gltf::AlphaMode::Blend => "blend",
|
||||||
|
}.into_lua(lua)
|
||||||
|
}),
|
||||||
|
(specular, {
|
||||||
|
data.specular.clone()
|
||||||
|
.map(|v| LuaSpecular(v.clone()))
|
||||||
|
.into_lua(lua)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
lua_wrap_handle!(Gltf, {
|
||||||
|
methods.add_method("scenes", |lua, this, ()| {
|
||||||
|
if let Some(data) = this.0.data_ref() {
|
||||||
|
let table = lua.create_table()?;
|
||||||
|
|
||||||
|
for (i, scene) in data.scenes.iter().enumerate() {
|
||||||
|
let i = i as i64 + 1; // lua indexes start at 1
|
||||||
|
table.raw_set(i, LuaSceneHandle(scene.clone()))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(mlua::Value::Table(table))
|
||||||
|
} else {
|
||||||
|
Ok(mlua::Value::Nil)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
methods.add_method("materials", |lua, this, ()| {
|
||||||
|
if let Some(data) = this.0.data_ref() {
|
||||||
|
let table = lua.create_table()?;
|
||||||
|
|
||||||
|
for (i, mat) in data.materials.iter().enumerate() {
|
||||||
|
let i = i as i64 + 1; // lua indexes start at 1
|
||||||
|
table.raw_set(i, LuaMaterialHandle(mat.clone()))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(mlua::Value::Table(table))
|
||||||
|
} else {
|
||||||
|
Ok(mlua::Value::Nil)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
methods.add_method("meshes", |lua, this, ()| {
|
||||||
|
if let Some(data) = this.0.data_ref() {
|
||||||
|
let table = lua.create_table()?;
|
||||||
|
|
||||||
|
for (i, mesh) in data.meshes.iter().enumerate() {
|
||||||
|
let i = i as i64 + 1; // lua indexes start at 1
|
||||||
|
table.raw_set(i, LuaMeshHandle(mesh.clone()))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(mlua::Value::Table(table))
|
||||||
|
} else {
|
||||||
|
Ok(mlua::Value::Nil)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,21 +1,37 @@
|
||||||
use std::{any::TypeId, ops::Deref};
|
use lyra_resource::{ResHandle, ResourceData, UntypedResHandle};
|
||||||
//use mlua::{AnyUserData, IntoLua, FromLua, Lua, Value};
|
use lyra_reflect::FromType;
|
||||||
use lyra_resource::{gltf::{Gltf, Material, Mesh}, FilterMode, ResHandle, Texture, UntypedResHandle, WrappingMode};
|
use crate::lua::LuaWrapper;
|
||||||
use lyra_game::scene::SceneGraph;
|
|
||||||
use lyra_reflect::{Reflect, TypeData};
|
|
||||||
use lyra_scripting_derive::{lua_wrap_handle, wrap_lua_struct};
|
|
||||||
|
|
||||||
use crate::{lua::{Error, LuaWrapper, FN_NAME_INTERNAL_AS_COMPONENT, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE}, lyra_engine, ScriptBorrow};
|
mod gltf;
|
||||||
|
pub use gltf::*;
|
||||||
|
|
||||||
use crate as lyra_scripting;
|
pub trait LuaHandleWrapper: LuaWrapper + mlua::UserData + Send + 'static {
|
||||||
|
type ResourceType: lyra_resource::ResourceData;
|
||||||
|
|
||||||
use mlua::IntoLua;
|
fn from_handle(handle: ResHandle<Self::ResourceType>) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct LuaResHandleToComponent {
|
pub struct LuaResHandleToComponent {
|
||||||
/// Create the userdata component that
|
/// Create the userdata component that
|
||||||
pub fn_to_lua: fn(&mlua::Lua, UntypedResHandle) -> Option<mlua::AnyUserData>,
|
pub fn_to_lua: fn(&mlua::Lua, UntypedResHandle) -> Option<mlua::AnyUserData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> FromType<T> for LuaResHandleToComponent
|
||||||
|
where
|
||||||
|
T: LuaHandleWrapper,
|
||||||
|
T::ResourceType: ResourceData,
|
||||||
|
{
|
||||||
|
fn from_type() -> Self {
|
||||||
|
Self {
|
||||||
|
fn_to_lua: |lua: &mlua::Lua, handle: UntypedResHandle| {
|
||||||
|
handle.as_typed::<T::ResourceType>()
|
||||||
|
.map(|res| lua.create_userdata(T::from_handle(res)).unwrap())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl LuaResHandleToComponent {
|
impl LuaResHandleToComponent {
|
||||||
pub fn new(f: fn(&mlua::Lua, UntypedResHandle) -> Option<mlua::AnyUserData>) -> Self {
|
pub fn new(f: fn(&mlua::Lua, UntypedResHandle) -> Option<mlua::AnyUserData>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -23,315 +39,3 @@ impl LuaResHandleToComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeData for LuaResHandleToComponent {
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn boxed_clone(&self) -> Box<dyn TypeData> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct LuaResHandle(pub UntypedResHandle);
|
|
||||||
|
|
||||||
impl Deref for LuaResHandle {
|
|
||||||
type Target = UntypedResHandle;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<UntypedResHandle> for LuaResHandle {
|
|
||||||
fn from(value: UntypedResHandle) -> Self {
|
|
||||||
LuaResHandle(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl mlua::UserData for LuaResHandle {
|
|
||||||
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
|
|
||||||
fields.add_field_method_get("path", |_, this| Ok(this.path()));
|
|
||||||
fields.add_field_method_get("version", |_, this| Ok(this.version()));
|
|
||||||
fields.add_field_method_get("uuid", |_, this| Ok(this.uuid().to_string()));
|
|
||||||
fields.add_field_method_get("state", |_, this| {
|
|
||||||
let name = if this.is_loaded() {
|
|
||||||
"ready"
|
|
||||||
} else if this.get_error().is_some() {
|
|
||||||
"error"
|
|
||||||
} else { "loading" };
|
|
||||||
|
|
||||||
Ok(name)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
|
||||||
methods.add_method("is_watched", |_, this, ()| {
|
|
||||||
Ok(this.is_watched())
|
|
||||||
});
|
|
||||||
|
|
||||||
methods.add_method("is_loaded", |_, this, ()| {
|
|
||||||
Ok(this.is_loaded())
|
|
||||||
});
|
|
||||||
|
|
||||||
methods.add_method("wait_until_loaded", |_, this, ()| {
|
|
||||||
this.wait_recurse_dependencies_load();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
|
|
||||||
methods.add_method(FN_NAME_INTERNAL_AS_COMPONENT, |lua, this, ()| {
|
|
||||||
let handle = &this.0;
|
|
||||||
|
|
||||||
if let Some(handle) = handle.as_typed::<SceneGraph>() {
|
|
||||||
LuaSceneHandle(handle).into_lua(lua)
|
|
||||||
} else if let Some(handle) = handle.as_typed::<Gltf>() {
|
|
||||||
LuaGltfHandle(handle).into_lua(lua)
|
|
||||||
} else {
|
|
||||||
Ok(mlua::Value::Nil)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl mlua::FromLua for LuaResHandle {
|
|
||||||
fn from_lua(val: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
|
||||||
let tyname = val.type_name();
|
|
||||||
let ud = val.as_userdata()
|
|
||||||
.ok_or(mlua::Error::external(Error::type_mismatch("Handle", &tyname)))?;
|
|
||||||
let handle = ud.borrow::<LuaResHandle>()?;
|
|
||||||
|
|
||||||
Ok(handle.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn filter_mode_to_str(fm: FilterMode) -> &'static str {
|
|
||||||
match fm {
|
|
||||||
FilterMode::Nearest => "nearest",
|
|
||||||
FilterMode::Linear => "linear",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wrapping_mode_to_str(wm: WrappingMode) -> &'static str {
|
|
||||||
match wm {
|
|
||||||
WrappingMode::ClampToEdge => "clamp_to_edge",
|
|
||||||
WrappingMode::MirroredRepeat => "mirrored_repeat",
|
|
||||||
WrappingMode::Repeat => "repeat",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wrap_lua_struct!(lyra_resource::TextureSampler,
|
|
||||||
// this can be safely skipped since it wont be a component or resource.
|
|
||||||
skip(lua_reflect),
|
|
||||||
fields={
|
|
||||||
// don't need to specify field types since setters are skipped
|
|
||||||
(mag_filter, skip_set, get={
|
|
||||||
this.mag_filter.map(|f| filter_mode_to_str(f))
|
|
||||||
.into_lua(lua)
|
|
||||||
}),
|
|
||||||
(min_filter, skip_set, get={
|
|
||||||
this.min_filter.map(|f| filter_mode_to_str(f))
|
|
||||||
.into_lua(lua)
|
|
||||||
}),
|
|
||||||
(mipmap_filter, skip_set, get={
|
|
||||||
this.mipmap_filter.map(|f| filter_mode_to_str(f))
|
|
||||||
.into_lua(lua)
|
|
||||||
}),
|
|
||||||
(wrap_u, skip_set, get={
|
|
||||||
wrapping_mode_to_str(this.wrap_u)
|
|
||||||
.into_lua(lua)
|
|
||||||
}),
|
|
||||||
(wrap_v, skip_set, get={
|
|
||||||
wrapping_mode_to_str(this.wrap_v)
|
|
||||||
.into_lua(lua)
|
|
||||||
}),
|
|
||||||
(wrap_w, skip_set, get={
|
|
||||||
wrapping_mode_to_str(this.wrap_w)
|
|
||||||
.into_lua(lua)
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
wrap_lua_struct!(lyra_resource::gltf::PbrGlossiness,
|
|
||||||
// this can be safely skipped since it wont be a component or resource.
|
|
||||||
skip(lua_reflect),
|
|
||||||
fields={
|
|
||||||
(diffuse_color: wrap(crate::lua::wrappers::LuaVec4), skip_set),
|
|
||||||
(specular: wrap(crate::lua::wrappers::LuaVec3), skip_set),
|
|
||||||
(glossiness, skip_set),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
wrap_lua_struct!(lyra_resource::gltf::Specular,
|
|
||||||
// this can be safely skipped since it wont be a component or resource.
|
|
||||||
skip(lua_reflect),
|
|
||||||
fields={
|
|
||||||
(factor, skip_set),
|
|
||||||
(color_factor: wrap(crate::lua::wrappers::LuaVec3), skip_set),
|
|
||||||
(texture, skip_set, get={
|
|
||||||
this.texture.clone()
|
|
||||||
.map(|t| LuaTextureHandle(t))
|
|
||||||
.into_lua(lua)
|
|
||||||
}),
|
|
||||||
(color_texture, skip_set, get={
|
|
||||||
this.color_texture.clone()
|
|
||||||
.map(|t| LuaTextureHandle(t))
|
|
||||||
.into_lua(lua)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: fields
|
|
||||||
lua_wrap_handle!(SceneGraph, name=Scene, {});
|
|
||||||
|
|
||||||
lua_wrap_handle!(Mesh,
|
|
||||||
field_getters={
|
|
||||||
(material, {
|
|
||||||
data.material.clone()
|
|
||||||
.map(|v| LuaMaterialHandle(v.clone()))
|
|
||||||
.into_lua(lua)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
methods.add_method("indices", |lua, this, ()| {
|
|
||||||
if let Some(data) = this.0.data_ref() {
|
|
||||||
let table = lua.create_table()?;
|
|
||||||
|
|
||||||
match &data.indices {
|
|
||||||
Some(lyra_resource::gltf::MeshIndices::U16(v)) => {
|
|
||||||
for (i, ind) in v.iter().enumerate() {
|
|
||||||
let i = i as i64 + 1; // lua indexes start at 1
|
|
||||||
table.raw_set(i, *ind)?;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Some(lyra_resource::gltf::MeshIndices::U32(v)) => {
|
|
||||||
for (i, ind) in v.iter().enumerate() {
|
|
||||||
let i = i as i64 + 1; // lua indexes start at 1
|
|
||||||
table.raw_set(i, *ind)?;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => {},
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(mlua::Value::Table(table))
|
|
||||||
} else {
|
|
||||||
Ok(mlua::Value::Nil)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: mesh attributes
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
lua_wrap_handle!(lyra_resource::Image,
|
|
||||||
field_getters={
|
|
||||||
(width, {
|
|
||||||
data.width().into_lua(lua)
|
|
||||||
}),
|
|
||||||
(height, {
|
|
||||||
data.height().into_lua(lua)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
lua_wrap_handle!(Texture,
|
|
||||||
field_getters={
|
|
||||||
(image, wrapper=LuaImageHandle),
|
|
||||||
(sampler, {
|
|
||||||
data.sampler.clone()
|
|
||||||
.map(|s| LuaTextureSampler(s))
|
|
||||||
.into_lua(lua)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
lua_wrap_handle!(Material,
|
|
||||||
field_getters={
|
|
||||||
shader_uuid,
|
|
||||||
name,
|
|
||||||
double_sided,
|
|
||||||
(base_color, wrapper=crate::lua::wrappers::LuaVec4),
|
|
||||||
metallic,
|
|
||||||
roughness,
|
|
||||||
(base_color_texture, {
|
|
||||||
data.base_color_texture.clone()
|
|
||||||
.map(|v| LuaTextureHandle(v.clone()))
|
|
||||||
.into_lua(lua)
|
|
||||||
}),
|
|
||||||
(metallic_roughness_texture, {
|
|
||||||
data.metallic_roughness_texture.clone()
|
|
||||||
.map(|v| LuaTextureHandle(v.clone()))
|
|
||||||
.into_lua(lua)
|
|
||||||
}),
|
|
||||||
(pbr_glossiness, {
|
|
||||||
data.pbr_glossiness.clone()
|
|
||||||
.map(|v| LuaPbrGlossiness(v.clone()))
|
|
||||||
.into_lua(lua)
|
|
||||||
}),
|
|
||||||
alpha_cutoff,
|
|
||||||
(alpha_mode, {
|
|
||||||
match data.alpha_mode {
|
|
||||||
lyra_resource::gltf::AlphaMode::Opaque => "opaque",
|
|
||||||
lyra_resource::gltf::AlphaMode::Mask => "mask",
|
|
||||||
lyra_resource::gltf::AlphaMode::Blend => "blend",
|
|
||||||
}.into_lua(lua)
|
|
||||||
}),
|
|
||||||
(specular, {
|
|
||||||
data.specular.clone()
|
|
||||||
.map(|v| LuaSpecular(v.clone()))
|
|
||||||
.into_lua(lua)
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
lua_wrap_handle!(Gltf, {
|
|
||||||
methods.add_method("scenes", |lua, this, ()| {
|
|
||||||
if let Some(data) = this.0.data_ref() {
|
|
||||||
let table = lua.create_table()?;
|
|
||||||
|
|
||||||
for (i, scene) in data.scenes.iter().enumerate() {
|
|
||||||
let i = i as i64 + 1; // lua indexes start at 1
|
|
||||||
table.raw_set(i, LuaSceneHandle(scene.clone()))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(mlua::Value::Table(table))
|
|
||||||
} else {
|
|
||||||
Ok(mlua::Value::Nil)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
methods.add_method("materials", |lua, this, ()| {
|
|
||||||
if let Some(data) = this.0.data_ref() {
|
|
||||||
let table = lua.create_table()?;
|
|
||||||
|
|
||||||
for (i, mat) in data.materials.iter().enumerate() {
|
|
||||||
let i = i as i64 + 1; // lua indexes start at 1
|
|
||||||
table.raw_set(i, LuaMaterialHandle(mat.clone()))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(mlua::Value::Table(table))
|
|
||||||
} else {
|
|
||||||
Ok(mlua::Value::Nil)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
methods.add_method("meshes", |lua, this, ()| {
|
|
||||||
if let Some(data) = this.0.data_ref() {
|
|
||||||
let table = lua.create_table()?;
|
|
||||||
|
|
||||||
for (i, mesh) in data.meshes.iter().enumerate() {
|
|
||||||
let i = i as i64 + 1; // lua indexes start at 1
|
|
||||||
table.raw_set(i, LuaMeshHandle(mesh.clone()))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(mlua::Value::Table(table))
|
|
||||||
} else {
|
|
||||||
Ok(mlua::Value::Nil)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in New Issue