Compare commits
2 Commits
8e56ee1f0f
...
d0e6fc6ecd
Author | SHA1 | Date |
---|---|---|
SeanOMik | d0e6fc6ecd | |
SeanOMik | 6a47cd2671 |
|
@ -15,6 +15,19 @@ function udname(val)
|
||||||
return tbl.__name
|
return tbl.__name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function dump(o)
|
||||||
|
if type(o) == 'table' then
|
||||||
|
local s = '{ '
|
||||||
|
for k,v in pairs(o) do
|
||||||
|
if type(k) ~= 'number' then k = '"'..k..'"' end
|
||||||
|
s = s .. '['..k..'] = ' .. dump(v) .. ','
|
||||||
|
end
|
||||||
|
return s .. '} '
|
||||||
|
else
|
||||||
|
return tostring(o)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function on_init()
|
function on_init()
|
||||||
local cube = world:request_asset("../assets/cube-texture-embedded.gltf") --[[@as GltfHandle]]
|
local cube = world:request_asset("../assets/cube-texture-embedded.gltf") --[[@as GltfHandle]]
|
||||||
|
@ -46,6 +59,17 @@ function on_first()
|
||||||
end, Window
|
end, Window
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@type EventReader
|
||||||
|
local reader = world:read_event(DeviceEvent)
|
||||||
|
|
||||||
|
---@param ev DeviceEvent
|
||||||
|
for ev in reader:read() do
|
||||||
|
if ev.event.kind == DeviceEventKind.MOTION then
|
||||||
|
local motion_ev = ev.event --[[@as DeviceEventMotion]]
|
||||||
|
print("axis: " .. tostring(motion_ev.axis) .. " = " .. tostring(motion_ev.value))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[ function on_pre_update()
|
--[[ function on_pre_update()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
use std::sync::Arc;
|
||||||
|
|
||||||
use atomic_refcell::AtomicRefCell;
|
use atomic_refcell::AtomicRefCell;
|
||||||
use lyra_ecs::{query::{ResMut, WorldTick}, system::FnArgFetcher, Tick};
|
use lyra_ecs::{query::{ResMut, WorldTick}, system::FnArgFetcher, Tick};
|
||||||
|
@ -99,7 +99,7 @@ impl<T: Event> Events<T> {
|
||||||
pub fn reader(&self) -> EventReader<T> {
|
pub fn reader(&self) -> EventReader<T> {
|
||||||
EventReader {
|
EventReader {
|
||||||
events: self.events.clone(),
|
events: self.events.clone(),
|
||||||
cursor: Rc::new(RefCell::new(0)),
|
cursor: Arc::new(AtomicRefCell::new(0)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,11 +112,11 @@ impl<T: Event> Events<T> {
|
||||||
|
|
||||||
pub struct EventReader<T: Event> {
|
pub struct EventReader<T: Event> {
|
||||||
events: Arc<AtomicRefCell<WaterfallVec<T>>>,
|
events: Arc<AtomicRefCell<WaterfallVec<T>>>,
|
||||||
cursor: Rc<RefCell<usize>>,
|
cursor: Arc<AtomicRefCell<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Event> EventReader<T> {
|
impl<T: Event> EventReader<T> {
|
||||||
pub fn read(&mut self) -> Option<atomic_refcell::AtomicRef<T>> {
|
pub fn read(&self) -> Option<atomic_refcell::AtomicRef<T>> {
|
||||||
let events = self.events.borrow();
|
let events = self.events.borrow();
|
||||||
|
|
||||||
let mut cursor = self.cursor.borrow_mut();
|
let mut cursor = self.cursor.borrow_mut();
|
||||||
|
@ -136,7 +136,7 @@ pub struct EventWriter<T: Event> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Event> EventWriter<T> {
|
impl<T: Event> EventWriter<T> {
|
||||||
pub fn write(&mut self, event: T) {
|
pub fn write(&self, event: T) {
|
||||||
let mut events = self.events.borrow_mut();
|
let mut events = self.events.borrow_mut();
|
||||||
events.push(event);
|
events.push(event);
|
||||||
}
|
}
|
||||||
|
@ -167,12 +167,12 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Event> FnArgFetcher for EventReader<T> {
|
impl<T: Event> FnArgFetcher for EventReader<T> {
|
||||||
type State = Rc<RefCell<usize>>;
|
type State = Arc<AtomicRefCell<usize>>;
|
||||||
|
|
||||||
type Arg<'a, 'state> = EventReader<T>;
|
type Arg<'a, 'state> = EventReader<T>;
|
||||||
|
|
||||||
fn create_state(_: std::ptr::NonNull<lyra_ecs::World>) -> Self::State {
|
fn create_state(_: std::ptr::NonNull<lyra_ecs::World>) -> Self::State {
|
||||||
Rc::new(RefCell::new(0))
|
Arc::new(AtomicRefCell::new(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn get<'a, 'state>(state: &'state mut Self::State, world: std::ptr::NonNull<lyra_ecs::World>) -> Self::Arg<'a, 'state> {
|
unsafe fn get<'a, 'state>(state: &'state mut Self::State, world: std::ptr::NonNull<lyra_ecs::World>) -> Self::Arg<'a, 'state> {
|
||||||
|
|
|
@ -520,7 +520,8 @@ impl KeyCode {
|
||||||
pub fn as_physical_key(&self) -> winit::keyboard::PhysicalKey {
|
pub fn as_physical_key(&self) -> winit::keyboard::PhysicalKey {
|
||||||
match self {
|
match self {
|
||||||
KeyCode::Unknown(v) => winit::keyboard::PhysicalKey::Unidentified((*v).into()),
|
KeyCode::Unknown(v) => winit::keyboard::PhysicalKey::Unidentified((*v).into()),
|
||||||
_ => winit::keyboard::PhysicalKey::Code(self.into())
|
// unwrap is safe here since we know self is not an `Unknown` key.
|
||||||
|
_ => winit::keyboard::PhysicalKey::Code(self.as_winit_keycode().unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use winit::{event::{MouseScrollDelta, WindowEvent}, keyboard::PhysicalKey};
|
||||||
|
|
||||||
use crate::{game::GameStages, plugin::Plugin, winit::DeviceEventPair, EventReader, EventWriter};
|
use crate::{game::GameStages, plugin::Plugin, winit::DeviceEventPair, EventReader, EventWriter};
|
||||||
|
|
||||||
use super::{events::*, InputButtons};
|
use super::{events::*, InputButtons, KeyCode};
|
||||||
|
|
||||||
fn write_scroll_delta(mouse_scroll_ev: &mut EventWriter<MouseScroll>, delta: &MouseScrollDelta) {
|
fn write_scroll_delta(mouse_scroll_ev: &mut EventWriter<MouseScroll>, delta: &MouseScrollDelta) {
|
||||||
let event = match delta {
|
let event = match delta {
|
||||||
|
@ -21,24 +21,24 @@ fn write_scroll_delta(mouse_scroll_ev: &mut EventWriter<MouseScroll>, delta: &Mo
|
||||||
mouse_scroll_ev.write(event);
|
mouse_scroll_ev.write(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_key_event(key_buttons: &mut ResMut<InputButtons<winit::keyboard::KeyCode>>, physical_key: winit::keyboard::PhysicalKey, state: winit::event::ElementState) {
|
fn write_key_event(key_buttons: &mut ResMut<InputButtons<KeyCode>>, physical_key: PhysicalKey, state: winit::event::ElementState) {
|
||||||
if let PhysicalKey::Code(code) = physical_key {
|
if let PhysicalKey::Code(code) = physical_key {
|
||||||
key_buttons.add_input_from_winit(code, state);
|
key_buttons.add_input_from_winit(KeyCode::from(code), state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input_system(
|
pub fn input_system(
|
||||||
mut key_code_res: ResMut<InputButtons<winit::keyboard::KeyCode>>,
|
mut key_code_res: ResMut<InputButtons<KeyCode>>,
|
||||||
mut mouse_btn_res: ResMut<InputButtons<MouseButton>>,
|
mut mouse_btn_res: ResMut<InputButtons<MouseButton>>,
|
||||||
mut touches_res: ResMut<Touches>,
|
mut touches_res: ResMut<Touches>,
|
||||||
mut window_ev: EventReader<WindowEvent>,
|
window_ev: EventReader<WindowEvent>,
|
||||||
mut device_ev: EventReader<DeviceEventPair>,
|
device_ev: EventReader<DeviceEventPair>,
|
||||||
mut mouse_scroll_ev: EventWriter<MouseScroll>,
|
mut mouse_scroll_ev: EventWriter<MouseScroll>,
|
||||||
mut mouse_btn_ev: EventWriter<MouseButton>,
|
mouse_btn_ev: EventWriter<MouseButton>,
|
||||||
mut mouse_exact_ev: EventWriter<MouseExact>,
|
mouse_exact_ev: EventWriter<MouseExact>,
|
||||||
mut mouse_entered_ev: EventWriter<CursorEnteredWindow>,
|
mouse_entered_ev: EventWriter<CursorEnteredWindow>,
|
||||||
mut mouse_left_ev: EventWriter<CursorLeftWindow>,
|
mouse_left_ev: EventWriter<CursorLeftWindow>,
|
||||||
mut mouse_motion_ev: EventWriter<MouseMotion>,
|
mouse_motion_ev: EventWriter<MouseMotion>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
while let Some(event) = window_ev.read() {
|
while let Some(event) = window_ev.read() {
|
||||||
match event.deref() {
|
match event.deref() {
|
||||||
|
@ -122,7 +122,7 @@ pub struct InputPlugin;
|
||||||
|
|
||||||
impl Plugin for InputPlugin {
|
impl Plugin for InputPlugin {
|
||||||
fn setup(&mut self, app: &mut crate::game::App) {
|
fn setup(&mut self, app: &mut crate::game::App) {
|
||||||
app.add_resource(InputButtons::<winit::keyboard::KeyCode>::default());
|
app.add_resource(InputButtons::<KeyCode>::default());
|
||||||
app.add_resource(InputButtons::<MouseButton>::default());
|
app.add_resource(InputButtons::<MouseButton>::default());
|
||||||
app.add_resource(Touches::default());
|
app.add_resource(Touches::default());
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ use winit::{
|
||||||
window::{Window, WindowAttributes, WindowId},
|
window::{Window, WindowAttributes, WindowId},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use winit::event::{DeviceId, DeviceEvent, MouseScrollDelta, ElementState};
|
pub use winit::event::{DeviceId, DeviceEvent, MouseScrollDelta, ElementState, RawKeyEvent};
|
||||||
pub use winit::keyboard::PhysicalKey;
|
pub use winit::keyboard::PhysicalKey;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
|
@ -67,3 +67,28 @@ CameraProjectionMode = {
|
||||||
PERSPECTIVE = "perspective",
|
PERSPECTIVE = "perspective",
|
||||||
ORTHOGRAPHIC = "orthographic",
|
ORTHOGRAPHIC = "orthographic",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
---@enum DeviceEventKind
|
||||||
|
DeviceEventKind = {
|
||||||
|
ADDED = "added",
|
||||||
|
REMOVED = "removed",
|
||||||
|
MOUSE_MOTION = "mouse_motion",
|
||||||
|
MOUSE_WHEEL = "mouse_wheel",
|
||||||
|
MOTION = "motion",
|
||||||
|
BUTTON = "button",
|
||||||
|
KEY = "key",
|
||||||
|
}
|
||||||
|
|
||||||
|
---@enum NativeKeyCodeKind
|
||||||
|
NativeKeyCodeKind = {
|
||||||
|
ANDROID = "android",
|
||||||
|
MACOS = "macos",
|
||||||
|
WINDOWS = "windows",
|
||||||
|
XKB = "xkb",
|
||||||
|
}
|
||||||
|
|
||||||
|
---@enum ElementState
|
||||||
|
ElementState = {
|
||||||
|
PRESSED = "pressed",
|
||||||
|
RELEASED = "released",
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
---@meta
|
||||||
|
|
||||||
|
---@class DeviceEventAdded: table
|
||||||
|
DeviceEventAdded = {
|
||||||
|
---@type DeviceEventKind
|
||||||
|
kind = DeviceEventKind.ADDED,
|
||||||
|
}
|
||||||
|
|
||||||
|
---@class DeviceEventRemoved: table
|
||||||
|
DeviceEventRemoved = {
|
||||||
|
---@type DeviceEventKind
|
||||||
|
kind = DeviceEventKind.REMOVED,
|
||||||
|
}
|
||||||
|
|
||||||
|
---@class DeviceEventMouseMotion: table
|
||||||
|
DeviceEventMouseMotion = {
|
||||||
|
---@type DeviceEventKind
|
||||||
|
kind = DeviceEventKind.MOUSE_MOTION,
|
||||||
|
|
||||||
|
---The change in physical position of a pointing device.
|
||||||
|
---
|
||||||
|
---This represents raw, unfiltered physical motion.
|
||||||
|
---
|
||||||
|
---@type Vec2
|
||||||
|
delta = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
---A physical scroll event from a device.
|
||||||
|
---
|
||||||
|
---`line_delta` and `pixel_delta` are exclusive, only one is non-nil at a time.
|
||||||
|
---
|
||||||
|
---@class DeviceEventMouseWheel: table
|
||||||
|
DeviceEventMouseWheel = {
|
||||||
|
---@type DeviceEventKind
|
||||||
|
kind = DeviceEventKind.MOUSE_WHEEL,
|
||||||
|
|
||||||
|
---Amount in lines or rows to scroll.
|
||||||
|
---
|
||||||
|
---Positive values indicate that the content that is being scrolled should move right
|
||||||
|
---and down (revealing more content left and up).
|
||||||
|
---
|
||||||
|
---@type Vec2?
|
||||||
|
line_delta = nil,
|
||||||
|
|
||||||
|
---Amount in pixels to scroll in the horizontal and vertical direction.
|
||||||
|
---
|
||||||
|
---Positive values indicate that the content being scrolled should move right/down.
|
||||||
|
---
|
||||||
|
---@type Vec2?
|
||||||
|
pixel_delta = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
---Device event that was triggered by motion on an analog axis.
|
||||||
|
---@class DeviceEventMotion: table
|
||||||
|
DeviceEventMotion = {
|
||||||
|
---@type DeviceEventKind
|
||||||
|
kind = DeviceEventKind.MOTION,
|
||||||
|
|
||||||
|
---The analog axis that motion was triggered from.
|
||||||
|
---@type number
|
||||||
|
axis = nil,
|
||||||
|
|
||||||
|
---The amount of motion.
|
||||||
|
---@type number
|
||||||
|
value = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
---@class DeviceEventButton: table
|
||||||
|
DeviceEventButton = {
|
||||||
|
---@type DeviceEventKind
|
||||||
|
kind = DeviceEventKind.BUTTON,
|
||||||
|
|
||||||
|
---The button id that the event is from.
|
||||||
|
---@type number
|
||||||
|
button = nil,
|
||||||
|
|
||||||
|
---The state of the button.
|
||||||
|
---@type ElementState
|
||||||
|
state = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
---A device event triggered from a key press.
|
||||||
|
---
|
||||||
|
---The field `code` will be nil if the key code identifier is unknown.
|
||||||
|
---When the identifier is unknown, it can be retrieved with `native_code`. The field
|
||||||
|
---`native` specifies the kind of platform the code is from.
|
||||||
|
---
|
||||||
|
---@class DeviceEventKey: table
|
||||||
|
DeviceEventKey = {
|
||||||
|
---@type DeviceEventKind
|
||||||
|
kind = DeviceEventKind.KEY,
|
||||||
|
|
||||||
|
---@type ElementState
|
||||||
|
state = nil,
|
||||||
|
|
||||||
|
---The known key name.
|
||||||
|
---
|
||||||
|
---This is `nil` if `native` or `native_code` is specified.
|
||||||
|
---
|
||||||
|
---@type string
|
||||||
|
code = nil,
|
||||||
|
|
||||||
|
---The kind of native platform this code is for.
|
||||||
|
---
|
||||||
|
---This is `nil` if `code` is specified.
|
||||||
|
---
|
||||||
|
---@type NativeKeyCodeKind
|
||||||
|
native = nil,
|
||||||
|
|
||||||
|
---The platform-native physical key identifier.
|
||||||
|
---
|
||||||
|
---This is `nil` if `code` is specified.
|
||||||
|
---
|
||||||
|
---@type number
|
||||||
|
native_code = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
---@alias DeviceEventRaw
|
||||||
|
---| DeviceEventAdded
|
||||||
|
---| DeviceEventRemoved
|
||||||
|
---| DeviceEventMotion
|
||||||
|
---| DeviceEventMouseMotion
|
||||||
|
---| DeviceEventMouseWheel
|
||||||
|
---| DeviceEventButton
|
||||||
|
---| DeviceEventKey
|
||||||
|
DeviceEventRaw = { }
|
||||||
|
|
||||||
|
---@class DeviceId: userdata
|
||||||
|
DeviceId = {}
|
||||||
|
|
||||||
|
---@class DeviceEvent: table
|
||||||
|
DeviceEvent = {
|
||||||
|
---The device id that the event came from
|
||||||
|
---@type DeviceId
|
||||||
|
source = nil,
|
||||||
|
---The actual device event
|
||||||
|
---@type DeviceEventRaw
|
||||||
|
event = nil,
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
---@meta
|
||||||
|
|
||||||
|
---@class EventReader: userdata
|
||||||
|
EventReader = {}
|
||||||
|
|
||||||
|
---Returns an iterator over the events in the reader.
|
||||||
|
---@return fun(): any
|
||||||
|
function EventReader:read() end
|
||||||
|
|
||||||
|
---@class EventWriter: userdata
|
||||||
|
EventWriter = {}
|
||||||
|
|
||||||
|
---Writes an event.
|
||||||
|
---
|
||||||
|
---The event must be the same type that this writer wraps.
|
||||||
|
---
|
||||||
|
---@param event any
|
||||||
|
function EventWriter:write(event) end
|
|
@ -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,10 +1,7 @@
|
||||||
use std::any::TypeId;
|
|
||||||
|
|
||||||
use lyra_ecs::ResourceObject;
|
use lyra_ecs::ResourceObject;
|
||||||
use lyra_reflect::{Reflect, TypeRegistry};
|
use lyra_reflect::Reflect;
|
||||||
use lyra_resource::gltf::Gltf;
|
|
||||||
|
|
||||||
use crate::{lua::{wrappers::*, LuaContext, LuaWrapper, ReflectLuaProxy, RegisterLuaType, 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:
|
||||||
|
|
||||||
|
@ -19,24 +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");
|
||||||
|
|
||||||
let mut registry = world.get_resource_mut::<TypeRegistry>().unwrap();
|
world.register_lua_wrapper::<LuaDeviceId>();
|
||||||
|
world.register_lua_convert::<LuaDeviceEventRaw>();
|
||||||
|
world.register_lua_convert::<LuaDeviceEvent>();
|
||||||
|
world.add_lua_event::<LuaDeviceEvent>("DeviceEvent");
|
||||||
|
|
||||||
let reg_type = registry.get_type_or_default(TypeId::of::<Gltf>());
|
world.register_asset_handle::<LuaGltfHandle>("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> {
|
||||||
|
@ -53,8 +42,9 @@ impl ScriptApiProvider for LyraEcsApiProvider {
|
||||||
globals.set("ActionHandler", ctx.create_proxy::<LuaActionHandler>()?)?;
|
globals.set("ActionHandler", ctx.create_proxy::<LuaActionHandler>()?)?;
|
||||||
globals.set("Window", ctx.create_proxy::<LuaWindow>()?)?;
|
globals.set("Window", ctx.create_proxy::<LuaWindow>()?)?;
|
||||||
|
|
||||||
expose_table_wrapper::<LuaCamera>(&ctx, &globals, "Camera")?;
|
expose_comp_table_wrapper::<LuaCamera>(&ctx, &globals, "Camera")?;
|
||||||
expose_table_wrapper::<LuaFreeFlyCamera>(&ctx, &globals, "FreeFlyCamera")?;
|
expose_comp_table_wrapper::<LuaFreeFlyCamera>(&ctx, &globals, "FreeFlyCamera")?;
|
||||||
|
expose_table_wrapper::<LuaDeviceEvent>(&ctx, &globals, "DeviceEvent")?;
|
||||||
|
|
||||||
let dt_table = create_reflect_table::<lyra_game::DeltaTime>(&ctx)?;
|
let dt_table = create_reflect_table::<lyra_game::DeltaTime>(&ctx)?;
|
||||||
globals.set("DeltaTime", dt_table)?;
|
globals.set("DeltaTime", dt_table)?;
|
||||||
|
@ -104,7 +94,7 @@ where
|
||||||
///
|
///
|
||||||
/// This creates the reflection functions on a table specified in globals.
|
/// This creates the reflection functions on a table specified in globals.
|
||||||
/// The table name is set to `name`, which is also how the script will use the table.
|
/// The table name is set to `name`, which is also how the script will use the table.
|
||||||
fn expose_table_wrapper<T>(lua: &mlua::Lua, globals: &mlua::Table, name: &str) -> mlua::Result<()>
|
fn expose_comp_table_wrapper<T>(lua: &mlua::Lua, globals: &mlua::Table, name: &str) -> mlua::Result<()>
|
||||||
where
|
where
|
||||||
T: LuaWrapper + mlua::FromLua,
|
T: LuaWrapper + mlua::FromLua,
|
||||||
T::Wrap: lyra_ecs::Component + Reflect
|
T::Wrap: lyra_ecs::Component + Reflect
|
||||||
|
@ -113,3 +103,14 @@ where
|
||||||
globals.set(name, table)?;
|
globals.set(name, table)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expose_table_wrapper<T>(lua: &mlua::Lua, globals: &mlua::Table, name: &str) -> mlua::Result<()>
|
||||||
|
where
|
||||||
|
T: LuaWrapper,
|
||||||
|
{
|
||||||
|
let table = lua.create_table()?;
|
||||||
|
table.set(mlua::MetaMethod::Type.name(), name.to_string())?;
|
||||||
|
globals.set(name, table)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -8,8 +8,8 @@ use crate::{ScriptBorrow, ScriptDynamicBundle};
|
||||||
|
|
||||||
use super::{Error, FN_NAME_INTERNAL_REFLECT};
|
use super::{Error, FN_NAME_INTERNAL_REFLECT};
|
||||||
|
|
||||||
pub trait LuaWrapper {
|
pub trait LuaWrapper: Sized {
|
||||||
type Wrap: Reflect + 'static;
|
type Wrap: 'static;
|
||||||
|
|
||||||
/// The type id of the wrapped type.
|
/// The type id of the wrapped type.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -18,6 +18,12 @@ pub trait LuaWrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_wrapped(self) -> Self::Wrap;
|
fn into_wrapped(self) -> Self::Wrap;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn from_wrapped(wrap: Self::Wrap) -> Option<Self> {
|
||||||
|
let _ = wrap;
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait that used to convert something into lua, or to set something to a value from lua.
|
/// A trait that used to convert something into lua, or to set something to a value from lua.
|
||||||
|
@ -36,7 +42,7 @@ pub trait LuaProxy {
|
||||||
|
|
||||||
impl<'a, T> LuaProxy for T
|
impl<'a, T> LuaProxy for T
|
||||||
where
|
where
|
||||||
T: Reflect + Clone + mlua::FromLua + mlua::UserData
|
T: Reflect + Clone + mlua::FromLua + mlua::IntoLua
|
||||||
{
|
{
|
||||||
fn as_lua_value(
|
fn as_lua_value(
|
||||||
lua: &mlua::Lua,
|
lua: &mlua::Lua,
|
||||||
|
@ -47,16 +53,14 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply(
|
fn apply(
|
||||||
_: &mlua::Lua,
|
lua: &mlua::Lua,
|
||||||
this: &mut dyn Reflect,
|
this: &mut dyn Reflect,
|
||||||
apply: &mlua::Value,
|
apply: &mlua::Value,
|
||||||
) -> mlua::Result<()> {
|
) -> mlua::Result<()> {
|
||||||
let this = this.as_any_mut().downcast_mut::<T>().unwrap();
|
let this = this.as_any_mut().downcast_mut::<T>().unwrap();
|
||||||
let apply = apply.as_userdata()
|
let apply = T::from_lua(apply.clone(), lua)?;
|
||||||
.expect("Somehow a non-userdata Lua Value was provided to a LuaProxy")
|
|
||||||
.borrow::<T>()?;
|
|
||||||
|
|
||||||
*this = apply.clone();
|
*this = apply;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,20 @@ use lyra_resource::ResourceManager;
|
||||||
use mlua::{IntoLua, ObjectLike};
|
use mlua::{IntoLua, ObjectLike};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
reflect_user_data, wrappers::LuaResHandleToComponent, Error, TypeLookup, ReflectLuaProxy, ReflectedIterator, FN_NAME_INTERNAL_AS_COMPONENT, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE
|
reflect_user_data,
|
||||||
|
wrappers::{LuaResHandleToComponent, LuaWrappedEventProxy},
|
||||||
|
Error, ReflectLuaProxy, ReflectedIterator, TypeLookup, FN_NAME_INTERNAL_AS_COMPONENT,
|
||||||
|
FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl mlua::FromLua for ScriptEntity {
|
impl mlua::FromLua for ScriptEntity {
|
||||||
fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
match value {
|
match value {
|
||||||
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
||||||
mlua::Value::Nil => Err(mlua::Error::external(Error::type_mismatch("ScriptEntity", "Nil"))),
|
mlua::Value::Nil => Err(mlua::Error::external(Error::type_mismatch(
|
||||||
|
"ScriptEntity",
|
||||||
|
"Nil",
|
||||||
|
))),
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +47,10 @@ impl mlua::FromLua for ScriptWorldPtr {
|
||||||
fn from_lua(val: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
fn from_lua(val: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
match val {
|
match val {
|
||||||
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
||||||
mlua::Value::Nil => Err(mlua::Error::external(Error::type_mismatch("ScriptWorldPtr", "Nil"))),
|
mlua::Value::Nil => Err(mlua::Error::external(Error::type_mismatch(
|
||||||
|
"ScriptWorldPtr",
|
||||||
|
"Nil",
|
||||||
|
))),
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,8 +73,7 @@ impl mlua::UserData for ScriptWorldPtr {
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let comp_borrow = {
|
let comp_borrow = {
|
||||||
if let Ok(as_comp) = ud.get::<mlua::Function>(FN_NAME_INTERNAL_AS_COMPONENT)
|
if let Ok(as_comp) = ud.get::<mlua::Function>(FN_NAME_INTERNAL_AS_COMPONENT) {
|
||||||
{
|
|
||||||
let ud = match as_comp.call(ud.clone())? {
|
let ud = match as_comp.call(ud.clone())? {
|
||||||
mlua::Value::UserData(ud) => ud,
|
mlua::Value::UserData(ud) => ud,
|
||||||
mlua::Value::Nil => ud.clone(),
|
mlua::Value::Nil => ud.clone(),
|
||||||
|
@ -115,11 +123,12 @@ impl mlua::UserData for ScriptWorldPtr {
|
||||||
mlua::Value::Table(t) => {
|
mlua::Value::Table(t) => {
|
||||||
let name: String = t.get(mlua::MetaMethod::Type.name())?;
|
let name: String = t.get(mlua::MetaMethod::Type.name())?;
|
||||||
|
|
||||||
let lookup = world.get_resource::<TypeLookup>().ok_or(
|
let lookup =
|
||||||
mlua::Error::runtime(
|
world
|
||||||
|
.get_resource::<TypeLookup>()
|
||||||
|
.ok_or(mlua::Error::runtime(
|
||||||
"Unable to lookup table proxy, none were ever registered!",
|
"Unable to lookup table proxy, none were ever registered!",
|
||||||
),
|
))?;
|
||||||
)?;
|
|
||||||
let info = lookup.comp_info_from_name.get(&name).ok_or_else(|| {
|
let info = lookup.comp_info_from_name.get(&name).ok_or_else(|| {
|
||||||
mlua::Error::BadArgument {
|
mlua::Error::BadArgument {
|
||||||
to: Some("World:view".into()),
|
to: Some("World:view".into()),
|
||||||
|
@ -139,10 +148,7 @@ impl mlua::UserData for ScriptWorldPtr {
|
||||||
}
|
}
|
||||||
mlua::Value::UserData(ud) => {
|
mlua::Value::UserData(ud) => {
|
||||||
let reflect = ud
|
let reflect = ud
|
||||||
.call_function::<ScriptBorrow>(
|
.call_function::<ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
||||||
FN_NAME_INTERNAL_REFLECT_TYPE,
|
|
||||||
(),
|
|
||||||
)
|
|
||||||
.expect("Type does not implement 'reflect_type' properly");
|
.expect("Type does not implement 'reflect_type' properly");
|
||||||
let refl_comp = reflect.reflect_branch.as_component_unchecked();
|
let refl_comp = reflect.reflect_branch.as_component_unchecked();
|
||||||
|
|
||||||
|
@ -172,7 +178,9 @@ impl mlua::UserData for ScriptWorldPtr {
|
||||||
let mut world = this.write();
|
let mut world = this.write();
|
||||||
|
|
||||||
while let Some(row) = reflected_iter.next_lua(lua) {
|
while let Some(row) = reflected_iter.next_lua(lua) {
|
||||||
let r = row.row.into_iter()
|
let r = row
|
||||||
|
.row
|
||||||
|
.into_iter()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|r| (r.comp_val, r.comp_ptr.cast::<()>()))
|
.map(|r| (r.comp_val, r.comp_ptr.cast::<()>()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
@ -183,7 +191,6 @@ impl mlua::UserData for ScriptWorldPtr {
|
||||||
|
|
||||||
// if values were returned, find the type in the type registry, and apply the new values
|
// if values were returned, find the type in the type registry, and apply the new values
|
||||||
if res.len() <= ptrs.len() {
|
if res.len() <= ptrs.len() {
|
||||||
|
|
||||||
for (comp, ptr) in res.into_iter().zip(ptrs) {
|
for (comp, ptr) in res.into_iter().zip(ptrs) {
|
||||||
let lua_typeid = match &comp {
|
let lua_typeid = match &comp {
|
||||||
mlua::Value::UserData(ud) => {
|
mlua::Value::UserData(ud) => {
|
||||||
|
@ -310,5 +317,41 @@ impl mlua::UserData for ScriptWorldPtr {
|
||||||
|
|
||||||
Ok((data.fn_to_lua)(lua, handle).unwrap())
|
Ok((data.fn_to_lua)(lua, handle).unwrap())
|
||||||
});
|
});
|
||||||
|
methods.add_method_mut(
|
||||||
|
"read_event",
|
||||||
|
|lua, this, either: mlua::Either<String, mlua::Table>| {
|
||||||
|
let mut world = this.write();
|
||||||
|
|
||||||
|
// get the type name
|
||||||
|
let name = match either {
|
||||||
|
mlua::Either::Left(name) => name,
|
||||||
|
mlua::Either::Right(table) => table.get(mlua::MetaMethod::Type.name())?,
|
||||||
|
};
|
||||||
|
|
||||||
|
// lookup the type id using the name, return an error if not found
|
||||||
|
let lookup = world.get_resource::<TypeLookup>().unwrap();
|
||||||
|
let tyid = lookup.typeid_from_name.get(&name).cloned();
|
||||||
|
if tyid.is_none() {
|
||||||
|
return Err(mlua::Error::runtime(format!(
|
||||||
|
"failed to lookup type id from type name: {}",
|
||||||
|
name
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let tyid = tyid.unwrap();
|
||||||
|
drop(lookup);
|
||||||
|
|
||||||
|
let registry = world.get_resource::<TypeRegistry>().unwrap();
|
||||||
|
let ty = registry
|
||||||
|
.get_type(tyid)
|
||||||
|
.expect("Could not find asset type in registry");
|
||||||
|
let data = ty
|
||||||
|
.get_data::<LuaWrappedEventProxy>()
|
||||||
|
.expect("Asset type does not have 'LuaWrappedEventProxy' as TypeData")
|
||||||
|
.clone();
|
||||||
|
drop(registry);
|
||||||
|
|
||||||
|
data.reader(&mut world).into_lua(lua)
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -4,16 +4,18 @@ use lyra_game::{
|
||||||
math::Vec2,
|
math::Vec2,
|
||||||
winit::{
|
winit::{
|
||||||
dpi::PhysicalPosition, DeviceEvent, DeviceEventPair, DeviceId, MouseScrollDelta,
|
dpi::PhysicalPosition, DeviceEvent, DeviceEventPair, DeviceId, MouseScrollDelta,
|
||||||
PhysicalKey,
|
PhysicalKey, RawKeyEvent,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use lyra_reflect::Reflect;
|
||||||
use lyra_scripting_derive::wrap_lua_struct;
|
use lyra_scripting_derive::wrap_lua_struct;
|
||||||
|
|
||||||
|
use crate as lyra_scripting;
|
||||||
use crate::lyra_engine;
|
use crate::lyra_engine;
|
||||||
|
|
||||||
use super::LuaVec2;
|
use super::LuaVec2;
|
||||||
|
|
||||||
wrap_lua_struct!(DeviceId, skip(lua_reflect, lua_wrapper));
|
wrap_lua_struct!(DeviceId, skip(lua_reflect));
|
||||||
|
|
||||||
/// Wraps [`DeviceEvent`] and implements [`IntoLua`]
|
/// Wraps [`DeviceEvent`] and implements [`IntoLua`]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -42,7 +44,7 @@ impl mlua::FromLua for LuaDeviceEventRaw {
|
||||||
message: Some("expected Lua Table".into()),
|
message: Some("expected Lua Table".into()),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let type_str: String = table.get("type")?;
|
let type_str: String = table.get("kind")?;
|
||||||
let type_str = type_str.as_str();
|
let type_str = type_str.as_str();
|
||||||
|
|
||||||
let ret = match type_str {
|
let ret = match type_str {
|
||||||
|
@ -125,8 +127,9 @@ impl mlua::FromLua for LuaDeviceEventRaw {
|
||||||
message: Some(format!("unknown key code: '{}'", code_str)),
|
message: Some(format!("unknown key code: '{}'", code_str)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
let code = code.unwrap();
|
||||||
|
|
||||||
let phy = PhysicalKey::Code(code);
|
let phy = PhysicalKey::Code(code.as_winit_keycode().unwrap());
|
||||||
Self(DeviceEvent::Key(RawKeyEvent {
|
Self(DeviceEvent::Key(RawKeyEvent {
|
||||||
physical_key: phy,
|
physical_key: phy,
|
||||||
state,
|
state,
|
||||||
|
@ -140,12 +143,19 @@ impl mlua::FromLua for LuaDeviceEventRaw {
|
||||||
"unknown" => NativeKeyCode::Unidentified,
|
"unknown" => NativeKeyCode::Unidentified,
|
||||||
"android" => NativeKeyCode::Android(native_code),
|
"android" => NativeKeyCode::Android(native_code),
|
||||||
"macos" => NativeKeyCode::MacOS(native_code as u16),
|
"macos" => NativeKeyCode::MacOS(native_code as u16),
|
||||||
"windows" => NativeKeyCode::Windows(native_code),
|
"windows" => NativeKeyCode::Windows(native_code as u16),
|
||||||
"xkb" => NativeKeyCode::Xkb(native_code),
|
"xkb" => NativeKeyCode::Xkb(native_code),
|
||||||
|
_ => {
|
||||||
|
return Err(mlua::Error::FromLuaConversionError {
|
||||||
|
from: ty,
|
||||||
|
to: "LuaDeviceEventRaw".into(),
|
||||||
|
message: Some(format!("unknown native code type: {}", native_str)),
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Self(DeviceEvent::Key(RawKeyEvent {
|
Self(DeviceEvent::Key(RawKeyEvent {
|
||||||
physical_key: PhysicalKey::Unidentified(native_code),
|
physical_key: PhysicalKey::Unidentified(native_code.into()),
|
||||||
state,
|
state,
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
|
@ -179,17 +189,17 @@ impl mlua::IntoLua for LuaDeviceEventRaw {
|
||||||
|
|
||||||
match self.0 {
|
match self.0 {
|
||||||
DeviceEvent::Added => {
|
DeviceEvent::Added => {
|
||||||
table.set("type", "added")?;
|
table.set("kind", "added")?;
|
||||||
}
|
}
|
||||||
DeviceEvent::Removed => {
|
DeviceEvent::Removed => {
|
||||||
table.set("type", "removed")?;
|
table.set("kind", "removed")?;
|
||||||
}
|
}
|
||||||
DeviceEvent::MouseMotion { delta } => {
|
DeviceEvent::MouseMotion { delta } => {
|
||||||
table.set("type", "mouse_motion")?;
|
table.set("kind", "mouse_motion")?;
|
||||||
table.set("delta", LuaVec2(Vec2::new(delta.0 as _, delta.1 as _)))?;
|
table.set("delta", LuaVec2(Vec2::new(delta.0 as _, delta.1 as _)))?;
|
||||||
}
|
}
|
||||||
DeviceEvent::MouseWheel { delta } => {
|
DeviceEvent::MouseWheel { delta } => {
|
||||||
table.set("type", "mouse_wheel")?;
|
table.set("kind", "mouse_wheel")?;
|
||||||
|
|
||||||
match delta {
|
match delta {
|
||||||
MouseScrollDelta::LineDelta(x, y) => {
|
MouseScrollDelta::LineDelta(x, y) => {
|
||||||
|
@ -204,12 +214,12 @@ impl mlua::IntoLua for LuaDeviceEventRaw {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DeviceEvent::Motion { axis, value } => {
|
DeviceEvent::Motion { axis, value } => {
|
||||||
table.set("type", "motion")?;
|
table.set("kind", "motion")?;
|
||||||
table.set("axis", axis)?;
|
table.set("axis", axis)?;
|
||||||
table.set("value", value)?;
|
table.set("value", value)?;
|
||||||
}
|
}
|
||||||
DeviceEvent::Button { button, state } => {
|
DeviceEvent::Button { button, state } => {
|
||||||
table.set("type", "button")?;
|
table.set("kind", "button")?;
|
||||||
table.set("button", button)?;
|
table.set("button", button)?;
|
||||||
|
|
||||||
let state = match state {
|
let state = match state {
|
||||||
|
@ -219,7 +229,7 @@ impl mlua::IntoLua for LuaDeviceEventRaw {
|
||||||
table.set("state", state)?;
|
table.set("state", state)?;
|
||||||
}
|
}
|
||||||
DeviceEvent::Key(raw_key_event) => {
|
DeviceEvent::Key(raw_key_event) => {
|
||||||
table.set("type", "key")?;
|
table.set("kind", "key")?;
|
||||||
|
|
||||||
let state = match raw_key_event.state {
|
let state = match raw_key_event.state {
|
||||||
lyra_game::winit::ElementState::Pressed => "pressed",
|
lyra_game::winit::ElementState::Pressed => "pressed",
|
||||||
|
@ -262,7 +272,16 @@ impl mlua::IntoLua for LuaDeviceEventRaw {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
impl LuaWrapper for LuaDeviceEventRaw {
|
||||||
|
type Wrap = DeviceEvent;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn into_wrapped(self) -> Self::Wrap {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Reflect)]
|
||||||
pub struct LuaDeviceEvent(pub(crate) DeviceEventPair);
|
pub struct LuaDeviceEvent(pub(crate) DeviceEventPair);
|
||||||
|
|
||||||
impl std::ops::Deref for LuaDeviceEvent {
|
impl std::ops::Deref for LuaDeviceEvent {
|
||||||
|
@ -292,8 +311,8 @@ impl mlua::FromLua for LuaDeviceEvent {
|
||||||
let ev: LuaDeviceEventRaw = table.get("event")?;
|
let ev: LuaDeviceEventRaw = table.get("event")?;
|
||||||
|
|
||||||
Ok(Self(DeviceEventPair {
|
Ok(Self(DeviceEventPair {
|
||||||
device_src: id,
|
device_src: id.0,
|
||||||
event: ev,
|
event: ev.0,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,7 +322,6 @@ impl mlua::IntoLua for LuaDeviceEvent {
|
||||||
let table = lua.create_table()?;
|
let table = lua.create_table()?;
|
||||||
table.set("device", LuaDeviceId(self.device_src))?;
|
table.set("device", LuaDeviceId(self.device_src))?;
|
||||||
table.set("event", LuaDeviceEventRaw(self.event.clone()))?;
|
table.set("event", LuaDeviceEventRaw(self.event.clone()))?;
|
||||||
|
|
||||||
table.into_lua(lua)
|
table.into_lua(lua)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,4 +333,9 @@ impl LuaWrapper for LuaDeviceEvent {
|
||||||
fn into_wrapped(self) -> Self::Wrap {
|
fn into_wrapped(self) -> Self::Wrap {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn from_wrapped(wrap: Self::Wrap) -> Option<Self> {
|
||||||
|
Some(Self(wrap))
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,151 @@
|
||||||
|
use std::{marker::PhantomData, sync::Arc};
|
||||||
|
|
||||||
|
use crate::lua::LuaWrapper;
|
||||||
|
use atomic_refcell::AtomicRefCell;
|
||||||
|
use lyra_ecs::World;
|
||||||
|
use lyra_game::{
|
||||||
|
Event, EventReader, EventWriter, Events,
|
||||||
|
};
|
||||||
|
use lyra_reflect::{FromType, Reflect};
|
||||||
|
use mlua::{FromLua, IntoLua};
|
||||||
|
|
||||||
|
use super::LuaVec2;
|
||||||
|
|
||||||
|
mod device_event;
|
||||||
|
pub use device_event::*;
|
||||||
|
|
||||||
|
/// Helper trait to type erase EventReader<T>
|
||||||
|
trait UntypedEventReader: Send + Sync {
|
||||||
|
fn next(&self, lua: &mlua::Lua) -> mlua::Result<mlua::Value>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper trait to type erase EventWriter<T>
|
||||||
|
trait UntypedEventWriter: Send + Sync {
|
||||||
|
fn push(&self, lua: &mlua::Lua, event: mlua::Value) -> mlua::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Event reader exposed to Lua
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LuaEventReader(Arc<AtomicRefCell<dyn UntypedEventReader>>);
|
||||||
|
|
||||||
|
impl mlua::FromLua for LuaEventReader {
|
||||||
|
fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
|
let ty = value.type_name();
|
||||||
|
let ud = value.as_userdata()
|
||||||
|
.ok_or(mlua::Error::FromLuaConversionError { from: ty, to: "EventReader".into(), message: None })?;
|
||||||
|
let reader = ud.borrow::<Self>()?;
|
||||||
|
Ok(reader.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mlua::UserData for LuaEventReader {
|
||||||
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||||
|
methods.add_method("read", |lua, this, ()| {
|
||||||
|
let reg = lua.create_registry_value(this.clone())?;
|
||||||
|
|
||||||
|
lua.create_function(move |lua: &mlua::Lua, ()| {
|
||||||
|
let reader = lua.registry_value::<Self>(®)?;
|
||||||
|
let reader = reader.0.borrow();
|
||||||
|
reader.next(lua)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Event writer exposed to Lua
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LuaEventWriter(Arc<AtomicRefCell<dyn UntypedEventWriter>>);
|
||||||
|
|
||||||
|
impl mlua::UserData for LuaEventWriter {
|
||||||
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||||
|
methods.add_method("write", |lua, this, event: mlua::Value| {
|
||||||
|
let writer = this.0.borrow();
|
||||||
|
writer.push(lua, event)?;
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TypedReader<T>
|
||||||
|
where
|
||||||
|
T: Reflect + LuaWrapper + IntoLua + Send + Sync,
|
||||||
|
T::Wrap: Clone + Event,
|
||||||
|
{
|
||||||
|
reader: EventReader<T::Wrap>,
|
||||||
|
_marker: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> UntypedEventReader for TypedReader<T>
|
||||||
|
where
|
||||||
|
T: Reflect + LuaWrapper + IntoLua + Send + Sync,
|
||||||
|
T::Wrap: Clone + Event,
|
||||||
|
{
|
||||||
|
fn next(&self, lua: &mlua::Lua) -> mlua::Result<mlua::Value> {
|
||||||
|
self.reader
|
||||||
|
.read()
|
||||||
|
.map(|e| T::from_wrapped(e.clone()).into_lua(lua))
|
||||||
|
.unwrap_or(Ok(mlua::Value::Nil))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TypedWriter<T>
|
||||||
|
where
|
||||||
|
T: Reflect + LuaWrapper + FromLua,
|
||||||
|
T::Wrap: Clone + Event,
|
||||||
|
{
|
||||||
|
writer: EventWriter<T::Wrap>,
|
||||||
|
_marker: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> UntypedEventWriter for TypedWriter<T>
|
||||||
|
where
|
||||||
|
T: Reflect + LuaWrapper + FromLua,
|
||||||
|
T::Wrap: Clone + Event,
|
||||||
|
{
|
||||||
|
fn push(&self, lua: &mlua::Lua, event: mlua::Value) -> mlua::Result<()> {
|
||||||
|
let ev = T::from_lua(event, lua)?.into_wrapped();
|
||||||
|
self.writer.write(ev);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LuaWrappedEventProxy {
|
||||||
|
fn_reader: for<'a> fn(world: &'a mut World) -> Arc<AtomicRefCell<dyn UntypedEventReader>>,
|
||||||
|
fn_writer: for<'a> fn(world: &'a mut World) -> Arc<AtomicRefCell<dyn UntypedEventWriter>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> FromType<T> for LuaWrappedEventProxy
|
||||||
|
where
|
||||||
|
T: Reflect + LuaWrapper + FromLua + IntoLua + Send + Sync,
|
||||||
|
T::Wrap: Clone + Event,
|
||||||
|
{
|
||||||
|
fn from_type() -> Self {
|
||||||
|
Self {
|
||||||
|
fn_reader: |world| {
|
||||||
|
let events = world.get_resource_or_default::<Events<T::Wrap>>();
|
||||||
|
Arc::new(AtomicRefCell::new(TypedReader {
|
||||||
|
reader: events.reader(),
|
||||||
|
_marker: PhantomData::<T>,
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
fn_writer: |world| {
|
||||||
|
let events = world.get_resource_or_default::<Events<T::Wrap>>();
|
||||||
|
Arc::new(AtomicRefCell::new(TypedWriter {
|
||||||
|
writer: events.writer(),
|
||||||
|
_marker: PhantomData::<T>,
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LuaWrappedEventProxy {
|
||||||
|
pub fn reader(&self, world: &mut World) -> LuaEventReader {
|
||||||
|
LuaEventReader((self.fn_reader)(world))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn writer(&self, world: &mut World) -> LuaEventWriter {
|
||||||
|
LuaEventWriter((self.fn_writer)(world))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
use lyra_game::input::{keycode_from_str, Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource, ActionState, LayoutId, MouseAxis, MouseInput};
|
use lyra_game::input::{Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource, ActionState, KeyCode, LayoutId, MouseAxis, MouseInput};
|
||||||
use mlua::IntoLua;
|
use mlua::IntoLua;
|
||||||
use crate::{lua::Error, lyra_engine};
|
use crate::{lua::Error, lyra_engine};
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ impl LuaWrapper for LuaActionHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_keyboard_string(key_name: &str) -> Option<ActionSource> {
|
fn process_keyboard_string(key_name: &str) -> Option<ActionSource> {
|
||||||
let key = keycode_from_str(key_name)?;
|
let key = KeyCode::from_str(key_name)?;
|
||||||
|
|
||||||
Some(ActionSource::Keyboard(key))
|
Some(ActionSource::Keyboard(key))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue