separate GLTF loader to its own crate
This commit is contained in:
parent
3ce9ab6fb3
commit
5542467d7e
|
@ -1829,6 +1829,7 @@ dependencies = [
|
|||
"itertools 0.13.0",
|
||||
"lyra-ecs",
|
||||
"lyra-game-derive",
|
||||
"lyra-gltf",
|
||||
"lyra-math",
|
||||
"lyra-reflect",
|
||||
"lyra-resource",
|
||||
|
@ -1860,6 +1861,34 @@ dependencies = [
|
|||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lyra-gltf"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-std",
|
||||
"base64 0.21.7",
|
||||
"crossbeam",
|
||||
"glam",
|
||||
"gltf",
|
||||
"image",
|
||||
"infer",
|
||||
"instant",
|
||||
"lyra-ecs",
|
||||
"lyra-math",
|
||||
"lyra-reflect",
|
||||
"lyra-resource",
|
||||
"lyra-scene",
|
||||
"mime",
|
||||
"notify",
|
||||
"notify-debouncer-full",
|
||||
"percent-encoding",
|
||||
"rand",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lyra-math"
|
||||
version = "0.1.0"
|
||||
|
@ -1894,14 +1923,12 @@ dependencies = [
|
|||
"base64 0.21.7",
|
||||
"crossbeam",
|
||||
"glam",
|
||||
"gltf",
|
||||
"image",
|
||||
"infer",
|
||||
"instant",
|
||||
"lyra-ecs",
|
||||
"lyra-math",
|
||||
"lyra-reflect",
|
||||
"lyra-scene",
|
||||
"mime",
|
||||
"notify",
|
||||
"notify-debouncer-full",
|
||||
|
@ -1920,6 +1947,7 @@ dependencies = [
|
|||
"lyra-ecs",
|
||||
"lyra-math",
|
||||
"lyra-reflect",
|
||||
"lyra-resource",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -10,6 +10,7 @@ lyra-ecs = { path = "../lyra-ecs", features = [ "math" ] }
|
|||
lyra-reflect = { path = "../lyra-reflect", features = [ "math" ] }
|
||||
lyra-math = { path = "../lyra-math" }
|
||||
lyra-scene = { path = "../lyra-scene" }
|
||||
lyra-gltf = { path = "../lyra-gltf" }
|
||||
wgsl_preprocessor = { path = "../wgsl-preprocessor" }
|
||||
|
||||
winit = "0.30.5"
|
||||
|
|
|
@ -29,5 +29,6 @@ pub use lyra_resource as assets;
|
|||
pub use lyra_ecs as ecs;
|
||||
pub use lyra_math as math;
|
||||
pub use lyra_reflect as reflect;
|
||||
pub use lyra_gltf as gltf;
|
||||
|
||||
pub use plugin::DefaultPlugins;
|
|
@ -1,4 +1,6 @@
|
|||
use lyra_ecs::query::ResMut;
|
||||
use lyra_ecs::CommandQueue;
|
||||
use lyra_gltf::GltfLoader;
|
||||
use lyra_resource::ResourceManager;
|
||||
|
||||
use crate::game::App;
|
||||
|
@ -113,6 +115,7 @@ impl Plugin for DefaultPlugins {
|
|||
CommandQueuePlugin.setup(app);
|
||||
InputPlugin.setup(app);
|
||||
ResourceManagerPlugin.setup(app);
|
||||
GltfPlugin.setup(app);
|
||||
WindowPlugin::default().setup(app);
|
||||
DeltaTimePlugin.setup(app);
|
||||
}
|
||||
|
@ -128,3 +131,13 @@ impl Plugin for CommandQueuePlugin {
|
|||
app.world.add_resource(CommandQueue::default());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct GltfPlugin;
|
||||
|
||||
impl Plugin for GltfPlugin {
|
||||
fn setup(&mut self, app: &mut App) {
|
||||
let man: ResMut<ResourceManager> = app.world.get_resource_or_default();
|
||||
man.register_loader::<GltfLoader>();
|
||||
}
|
||||
}
|
|
@ -12,7 +12,8 @@ use lyra_ecs::{
|
|||
Entity, ResourceObject, World,
|
||||
};
|
||||
use lyra_game_derive::RenderGraphLabel;
|
||||
use lyra_resource::{gltf::Mesh, ResHandle};
|
||||
use lyra_resource::ResHandle;
|
||||
use lyra_gltf::Mesh;
|
||||
use lyra_scene::SceneGraph;
|
||||
use rustc_hash::FxHashMap;
|
||||
use tracing::{debug, instrument};
|
||||
|
@ -93,10 +94,10 @@ impl MeshPrepNode {
|
|||
if let Some(index_buffer) = buffers.buffer_indices.as_ref() {
|
||||
let aligned_indices = match mesh.indices.as_ref().unwrap() {
|
||||
// U16 indices need to be aligned to u32, for wpgu, which are 4-bytes in size.
|
||||
lyra_resource::gltf::MeshIndices::U16(v) => {
|
||||
lyra_gltf::MeshIndices::U16(v) => {
|
||||
bytemuck::pod_align_to::<u16, u32>(v).1
|
||||
}
|
||||
lyra_resource::gltf::MeshIndices::U32(v) => {
|
||||
lyra_gltf::MeshIndices::U32(v) => {
|
||||
bytemuck::pod_align_to::<u32, u32>(v).1
|
||||
}
|
||||
};
|
||||
|
@ -137,10 +138,10 @@ impl MeshPrepNode {
|
|||
let indices = match mesh.indices.as_ref() {
|
||||
Some(indices) => {
|
||||
let (idx_type, len, contents) = match indices {
|
||||
lyra_resource::gltf::MeshIndices::U16(v) => {
|
||||
lyra_gltf::MeshIndices::U16(v) => {
|
||||
(wgpu::IndexFormat::Uint16, v.len(), bytemuck::cast_slice(v))
|
||||
}
|
||||
lyra_resource::gltf::MeshIndices::U32(v) => {
|
||||
lyra_gltf::MeshIndices::U32(v) => {
|
||||
(wgpu::IndexFormat::Uint32, v.len(), bytemuck::cast_slice(v))
|
||||
}
|
||||
};
|
||||
|
@ -518,7 +519,7 @@ impl GpuMaterial {
|
|||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
layout: &Arc<wgpu::BindGroupLayout>,
|
||||
mat: &lyra_resource::gltf::Material,
|
||||
mat: &lyra_gltf::Material,
|
||||
) -> Self {
|
||||
//let specular = mat.specular.as_ref().unwrap_or_default();
|
||||
//let specular_
|
||||
|
|
|
@ -21,7 +21,7 @@ fn texture_to_render(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: &Arc
|
|||
}
|
||||
|
||||
impl MaterialSpecular {
|
||||
pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc<wgpu::BindGroupLayout>, value: &lyra_resource::gltf::Specular) -> Self {
|
||||
pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc<wgpu::BindGroupLayout>, value: &lyra_gltf::Specular) -> Self {
|
||||
let tex = texture_to_render(device, queue, &bg_layout, &value.texture);
|
||||
let color_tex = texture_to_render(device, queue, &bg_layout, &value.color_texture);
|
||||
|
||||
|
@ -46,7 +46,7 @@ pub struct Material {
|
|||
}
|
||||
|
||||
impl Material {
|
||||
pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc<wgpu::BindGroupLayout>, value: &lyra_resource::gltf::Material) -> Self {
|
||||
pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc<wgpu::BindGroupLayout>, value: &lyra_gltf::Material) -> Self {
|
||||
let diffuse_texture = texture_to_render(device, queue, &bg_layout, &value.base_color_texture);
|
||||
|
||||
let specular = value.specular.as_ref().map(|s| MaterialSpecular::from_resource(device, queue, bg_layout.clone(), s));
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
[package]
|
||||
name = "lyra-gltf"
|
||||
version = "0.0.1"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
lyra-ecs = { path = "../lyra-ecs", features = [ "math" ] }
|
||||
lyra-reflect = { path = "../lyra-reflect", features = [ "math" ] }
|
||||
lyra-math = { path = "../lyra-math" }
|
||||
lyra-scene = { path = "../lyra-scene" }
|
||||
lyra-resource = { path = "../lyra-resource" }
|
||||
anyhow = "1.0.75"
|
||||
base64 = "0.21.4"
|
||||
crossbeam = { version = "0.8.4", features = [ "crossbeam-channel" ] }
|
||||
glam = "0.29.0"
|
||||
gltf = { version = "1.3.0", features = ["KHR_materials_pbrSpecularGlossiness", "KHR_materials_specular"] }
|
||||
image = "0.25.2"
|
||||
# not using custom matcher, or file type from file path
|
||||
infer = { version = "0.15.0", default-features = false }
|
||||
mime = "0.3.17"
|
||||
notify = "6.1.1"
|
||||
notify-debouncer-full = "0.3.1"
|
||||
#notify = { version = "6.1.1", default-features = false, features = [ "fsevent-sys", "macos_fsevent" ]} # disables crossbeam-channel
|
||||
percent-encoding = "2.3.0"
|
||||
thiserror = "1.0.48"
|
||||
tracing = "0.1.37"
|
||||
uuid = { version = "1.4.1", features = ["v4"] }
|
||||
instant = "0.1"
|
||||
async-std = "1.12.0"
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.8.5"
|
|
@ -0,0 +1,104 @@
|
|||
pub mod loader;
|
||||
use base64::Engine;
|
||||
pub use loader::*;
|
||||
|
||||
pub mod material;
|
||||
use lyra_reflect::Reflect;
|
||||
use lyra_resource::{ResHandle, ResourceData, UntypedResHandle};
|
||||
use lyra_scene::SceneGraph;
|
||||
pub use material::*;
|
||||
|
||||
pub mod mesh;
|
||||
pub use mesh::*;
|
||||
|
||||
pub mod scene;
|
||||
pub use scene::*;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) mod lyra_engine {
|
||||
pub(crate) mod ecs {
|
||||
pub use lyra_ecs::*;
|
||||
}
|
||||
|
||||
pub(crate) mod reflect {
|
||||
pub use lyra_reflect::*;
|
||||
}
|
||||
}
|
||||
|
||||
use thiserror::Error;
|
||||
use std::io;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Error, Debug)]
|
||||
pub enum UriReadError {
|
||||
#[error("IOError: '{0}'")]
|
||||
IoError(io::Error),
|
||||
|
||||
// From is implemented for this field in each loader module
|
||||
#[error("Base64 decoding error: '{0}'")]
|
||||
Base64Decode(base64::DecodeError),
|
||||
|
||||
#[error("Some data was missing from the uri")]
|
||||
None
|
||||
}
|
||||
|
||||
/// Read a buffer's uri string into a byte buffer.
|
||||
///
|
||||
/// * `containing_path`: The path of the containing folder of the buffers "parent",
|
||||
/// the parent being where this buffer is defined in,
|
||||
/// i.e. parent="resources/models/player.gltf", containing="resource/models"
|
||||
pub(crate) fn gltf_read_buffer_uri(containing_path: &str, uri: &str) -> Result<Vec<u8>, UriReadError> {
|
||||
if let Some((mime, data)) = uri.strip_prefix("data")
|
||||
.and_then(|uri| uri.split_once(',')) {
|
||||
let (_mime, is_base64) = match mime.strip_suffix(";base64") {
|
||||
Some(mime) => (mime, true),
|
||||
None => (mime, false),
|
||||
};
|
||||
|
||||
if is_base64 {
|
||||
base64::engine::general_purpose::STANDARD.decode(data)
|
||||
.map_err(UriReadError::Base64Decode)
|
||||
} else {
|
||||
Ok(data.as_bytes().to_vec())
|
||||
}
|
||||
} else {
|
||||
let full_path = format!("{containing_path}/{uri}");
|
||||
std::fs::read(full_path).map_err(UriReadError::IoError)
|
||||
}
|
||||
}
|
||||
|
||||
/// A loaded Gltf file
|
||||
#[derive(Clone, Default, Reflect)]
|
||||
pub struct Gltf {
|
||||
pub scenes: Vec<ResHandle<SceneGraph>>,
|
||||
pub materials: Vec<ResHandle<Material>>,
|
||||
pub meshes: Vec<ResHandle<Mesh>>,
|
||||
}
|
||||
|
||||
impl ResourceData for Gltf {
|
||||
fn dependencies(&self) -> Vec<UntypedResHandle> {
|
||||
let mut deps = vec![];
|
||||
|
||||
for scene in self.scenes.iter() {
|
||||
deps.push(scene.untyped_clone())
|
||||
}
|
||||
|
||||
for mat in self.materials.iter() {
|
||||
deps.push(mat.untyped_clone())
|
||||
}
|
||||
|
||||
for mesh in self.meshes.iter() {
|
||||
deps.push(mesh.untyped_clone())
|
||||
}
|
||||
|
||||
deps
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
|
@ -7,23 +7,19 @@ use lyra_math::Transform;
|
|||
use lyra_scene::{SceneGraph, SceneNode, WorldTransform};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{loader::{LoaderError, PinedBoxLoaderFuture, ResourceLoader}, util, ResHandle, ResourceData, ResourceManager, ResourceStorage};
|
||||
use lyra_resource::{loader::{LoaderError, PinedBoxLoaderFuture, ResourceLoader}, ResHandle, ResourceData, ResourceManager, ResourceStorage};
|
||||
use crate::{gltf_read_buffer_uri, UriReadError};
|
||||
|
||||
use super::{Gltf, GltfNode, Material, Mesh, MeshIndices, MeshVertexAttribute, VertexAttributeData};
|
||||
|
||||
use tracing::debug;
|
||||
|
||||
impl From<gltf::Error> for LoaderError {
|
||||
fn from(value: gltf::Error) -> Self {
|
||||
LoaderError::DecodingError(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
enum ModelLoaderError {
|
||||
#[error("The model ({0}) is missing the BIN section in the gltf file")]
|
||||
MissingBin(String),
|
||||
#[error("There was an error with decoding a uri defined in the model: '{0}'")]
|
||||
UriDecodingError(util::UriReadError),
|
||||
UriDecodingError(UriReadError),
|
||||
}
|
||||
|
||||
impl From<ModelLoaderError> for LoaderError {
|
||||
|
@ -45,9 +41,9 @@ pub(crate) struct GltfLoadContext<'a> {
|
|||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ModelLoader;
|
||||
pub struct GltfLoader;
|
||||
|
||||
impl ModelLoader {
|
||||
impl GltfLoader {
|
||||
/* fn parse_uri(containing_path: &str, uri: &str) -> Option<Vec<u8>> {
|
||||
let uri = uri.strip_prefix("data")?;
|
||||
let (mime, data) = uri.split_once(",")?;
|
||||
|
@ -136,7 +132,7 @@ impl ModelLoader {
|
|||
}
|
||||
|
||||
for child in gnode.children() {
|
||||
let cmesh = ModelLoader::process_node(ctx, materials, scene, &scene_node, child);
|
||||
let cmesh = GltfLoader::process_node(ctx, materials, scene, &scene_node, child);
|
||||
node.children.push(cmesh);
|
||||
}
|
||||
|
||||
|
@ -159,7 +155,7 @@ impl ModelLoader {
|
|||
}
|
||||
}
|
||||
|
||||
impl ResourceLoader for ModelLoader {
|
||||
impl ResourceLoader for GltfLoader {
|
||||
fn extensions(&self) -> &[&str] {
|
||||
&[
|
||||
"gltf", "glb"
|
||||
|
@ -184,7 +180,8 @@ impl ResourceLoader for ModelLoader {
|
|||
parent_path.pop();
|
||||
let parent_path = parent_path.display().to_string();
|
||||
|
||||
let gltf = gltf::Gltf::open(&path)?;
|
||||
let gltf = gltf::Gltf::open(&path)
|
||||
.map_err(|ge| LoaderError::DecodingError(ge.into()))?;
|
||||
|
||||
let mut use_bin = false;
|
||||
let buffers: Vec<Vec<u8>> = gltf.buffers().flat_map(|b| match b.source() {
|
||||
|
@ -193,7 +190,7 @@ impl ResourceLoader for ModelLoader {
|
|||
gltf.blob.as_deref().map(|v| v.to_vec())
|
||||
.ok_or(ModelLoaderError::MissingBin(path.to_string()))
|
||||
},
|
||||
gltf::buffer::Source::Uri(uri) => util::gltf_read_buffer_uri(&parent_path, uri)
|
||||
gltf::buffer::Source::Uri(uri) => gltf_read_buffer_uri(&parent_path, uri)
|
||||
.map_err(ModelLoaderError::UriDecodingError),
|
||||
}).collect();
|
||||
|
||||
|
@ -219,7 +216,7 @@ impl ResourceLoader for ModelLoader {
|
|||
let root_node = graph.root_node();
|
||||
|
||||
for node in scene.nodes() {
|
||||
let n = ModelLoader::process_node(&mut context, &materials, &mut graph, &root_node, node);
|
||||
let n = GltfLoader::process_node(&mut context, &materials, &mut graph, &root_node, node);
|
||||
|
||||
if let Some(mesh) = n.mesh {
|
||||
gltf_out.meshes.push(mesh.clone());
|
||||
|
@ -272,10 +269,12 @@ impl ResourceLoader for ModelLoader {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::time::Duration;
|
||||
|
||||
use lyra_ecs::{query::Entities, relation::ChildOf};
|
||||
use lyra_scene::WorldTransform;
|
||||
|
||||
use crate::tests::busy_wait_resource;
|
||||
//use lyra_resource::tests::busy_wait_resource;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -291,7 +290,7 @@ mod tests {
|
|||
|
||||
let manager = ResourceManager::new();
|
||||
let gltf = manager.request::<Gltf>(&path).unwrap();
|
||||
busy_wait_resource(&gltf, 15.0);
|
||||
assert!(gltf.wait_for_load_timeout(Duration::from_secs(10)), "failed to load gltf, hit 10 second timeout");
|
||||
let gltf = gltf.data_ref().unwrap();
|
||||
|
||||
assert_eq!(gltf.scenes.len(), 1);
|
|
@ -2,9 +2,9 @@ use std::{collections::hash_map::DefaultHasher, hash::{Hash, Hasher}};
|
|||
|
||||
use gltf::texture::{MagFilter, MinFilter};
|
||||
use lyra_reflect::Reflect;
|
||||
use crate::{lyra_engine, optionally_add_to_dep, ResourceData};
|
||||
use lyra_resource::{optionally_add_to_dep, FilterMode, Image, ResHandle, ResourceData, Texture, TextureSampler, WrappingMode};
|
||||
use crate::{gltf_read_buffer_uri, lyra_engine, UriReadError};
|
||||
|
||||
use crate::{util, FilterMode, Image, ResHandle, Texture, TextureSampler, WrappingMode};
|
||||
use super::loader::GltfLoadContext;
|
||||
|
||||
/// PBR metallic roughness
|
||||
|
@ -184,8 +184,6 @@ pub struct Material {
|
|||
}
|
||||
|
||||
impl ResourceData for Material {
|
||||
|
||||
|
||||
fn dependencies(&self) -> Vec<crate::UntypedResHandle> {
|
||||
let mut deps = vec![];
|
||||
|
||||
|
@ -242,7 +240,7 @@ impl Material {
|
|||
}
|
||||
}
|
||||
|
||||
fn read_source(context: &mut GltfLoadContext, src: gltf::image::Source) -> Result<Vec<u8>, util::UriReadError> {
|
||||
fn read_source(context: &mut GltfLoadContext, src: gltf::image::Source) -> Result<Vec<u8>, UriReadError> {
|
||||
let gltf_rel_path = context.gltf_parent_path;
|
||||
// TODO: Don't copy sources
|
||||
match src {
|
||||
|
@ -261,7 +259,7 @@ impl Material {
|
|||
Ok(b)
|
||||
},
|
||||
gltf::buffer::Source::Uri(uri) => {
|
||||
util::gltf_read_buffer_uri(gltf_rel_path, uri)
|
||||
gltf_read_buffer_uri(gltf_rel_path, uri)
|
||||
.map(|mut buf| {
|
||||
buf.drain(0..offset);
|
||||
buf.truncate(len);
|
||||
|
@ -271,7 +269,7 @@ impl Material {
|
|||
}
|
||||
},
|
||||
gltf::image::Source::Uri { uri, mime_type: _ } => {
|
||||
util::gltf_read_buffer_uri(gltf_rel_path, uri)
|
||||
gltf_read_buffer_uri(gltf_rel_path, uri)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -292,11 +290,11 @@ impl Material {
|
|||
|
||||
let samp = tex.sampler();
|
||||
let samp = TextureSampler {
|
||||
mag_filter: samp.mag_filter().map(FilterMode::from_mag_filter),
|
||||
min_filter: samp.min_filter().map(FilterMode::from_min_filter),
|
||||
mipmap_filter: samp.min_filter().and_then(FilterMode::mipmap_filter),
|
||||
wrap_u: samp.wrap_s().into(),
|
||||
wrap_v: samp.wrap_t().into(),
|
||||
mag_filter: samp.mag_filter().map(filter_mode_from_mag_filter),
|
||||
min_filter: samp.min_filter().map(filter_mode_from_min_filter),
|
||||
mipmap_filter: samp.min_filter().and_then(filter_mode_mipmap_filter),
|
||||
wrap_u: wrapping_mode_from_gltf_wrapping_mode(samp.wrap_s()),
|
||||
wrap_v: wrapping_mode_from_gltf_wrapping_mode(samp.wrap_t()),
|
||||
wrap_w: WrappingMode::ClampToEdge,
|
||||
};
|
||||
|
||||
|
@ -347,58 +345,44 @@ impl Material {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<gltf::texture::MagFilter> for FilterMode {
|
||||
#[inline(always)]
|
||||
fn from(value: gltf::texture::MagFilter) -> Self {
|
||||
match value {
|
||||
gltf::texture::MagFilter::Nearest => Self::Nearest,
|
||||
gltf::texture::MagFilter::Linear => Self::Linear,
|
||||
}
|
||||
/// Get the MinFilter mode and the mipmap filter mode from gltf MinFilter
|
||||
#[inline(always)]
|
||||
fn filter_mode_from_min_filter(minf: MinFilter) -> FilterMode {
|
||||
match minf {
|
||||
MinFilter::Nearest => FilterMode::Nearest,
|
||||
MinFilter::Linear => FilterMode::Linear,
|
||||
MinFilter::NearestMipmapNearest => FilterMode::Nearest,
|
||||
MinFilter::LinearMipmapNearest => FilterMode::Linear,
|
||||
MinFilter::NearestMipmapLinear => FilterMode::Nearest,
|
||||
MinFilter::LinearMipmapLinear => FilterMode::Linear,
|
||||
}
|
||||
}
|
||||
|
||||
impl FilterMode {
|
||||
/// Get the MinFilter mode and the mipmap filter mode from gltf MinFilter
|
||||
#[inline(always)]
|
||||
pub fn from_min_filter(minf: MinFilter) -> FilterMode {
|
||||
match minf {
|
||||
MinFilter::Nearest => FilterMode::Nearest,
|
||||
MinFilter::Linear => FilterMode::Linear,
|
||||
MinFilter::NearestMipmapNearest => FilterMode::Nearest,
|
||||
MinFilter::LinearMipmapNearest => FilterMode::Linear,
|
||||
MinFilter::NearestMipmapLinear => FilterMode::Nearest,
|
||||
MinFilter::LinearMipmapLinear => FilterMode::Linear,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_mag_filter(magf: MagFilter) -> FilterMode {
|
||||
match magf {
|
||||
MagFilter::Nearest => FilterMode::Nearest,
|
||||
MagFilter::Linear => FilterMode::Linear,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn mipmap_filter(minf: MinFilter) -> Option<FilterMode> {
|
||||
match minf {
|
||||
MinFilter::Nearest => None,
|
||||
MinFilter::Linear => None,
|
||||
MinFilter::NearestMipmapNearest => Some(FilterMode::Nearest),
|
||||
MinFilter::LinearMipmapNearest => Some(FilterMode::Nearest),
|
||||
MinFilter::NearestMipmapLinear => Some(FilterMode::Linear),
|
||||
MinFilter::LinearMipmapLinear => Some(FilterMode::Linear),
|
||||
}
|
||||
#[inline(always)]
|
||||
fn filter_mode_from_mag_filter(magf: MagFilter) -> FilterMode {
|
||||
match magf {
|
||||
MagFilter::Nearest => FilterMode::Nearest,
|
||||
MagFilter::Linear => FilterMode::Linear,
|
||||
}
|
||||
}
|
||||
|
||||
impl From<gltf::texture::WrappingMode> for WrappingMode {
|
||||
#[inline(always)]
|
||||
fn from(value: gltf::texture::WrappingMode) -> Self {
|
||||
match value {
|
||||
gltf::texture::WrappingMode::ClampToEdge => Self::ClampToEdge,
|
||||
gltf::texture::WrappingMode::MirroredRepeat => Self::MirroredRepeat,
|
||||
gltf::texture::WrappingMode::Repeat => Self::Repeat,
|
||||
}
|
||||
#[inline(always)]
|
||||
fn filter_mode_mipmap_filter(minf: MinFilter) -> Option<FilterMode> {
|
||||
match minf {
|
||||
MinFilter::Nearest => None,
|
||||
MinFilter::Linear => None,
|
||||
MinFilter::NearestMipmapNearest => Some(FilterMode::Nearest),
|
||||
MinFilter::LinearMipmapNearest => Some(FilterMode::Nearest),
|
||||
MinFilter::NearestMipmapLinear => Some(FilterMode::Linear),
|
||||
MinFilter::LinearMipmapLinear => Some(FilterMode::Linear),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn wrapping_mode_from_gltf_wrapping_mode(value: gltf::texture::WrappingMode) -> WrappingMode {
|
||||
match value {
|
||||
gltf::texture::WrappingMode::ClampToEdge => WrappingMode::ClampToEdge,
|
||||
gltf::texture::WrappingMode::MirroredRepeat => WrappingMode::MirroredRepeat,
|
||||
gltf::texture::WrappingMode::Repeat => WrappingMode::Repeat,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
use lyra_math::Transform;
|
||||
use lyra_resource::{optionally_add_to_dep, ResourceData, UntypedResHandle};
|
||||
|
||||
use super::Mesh;
|
||||
use crate::ResHandle;
|
||||
|
||||
/// A Node in the Gltf file
|
||||
#[derive(Clone, Default)]
|
||||
pub struct GltfNode {
|
||||
pub name: Option<String>,
|
||||
pub mesh: Option<ResHandle<Mesh>>,
|
||||
pub transform: Transform,
|
||||
pub children: Vec<GltfNode>,
|
||||
}
|
||||
|
||||
impl ResourceData for GltfNode {
|
||||
fn dependencies(&self) -> Vec<crate::UntypedResHandle> {
|
||||
let mut deps: Vec<UntypedResHandle> = self.children.iter()
|
||||
.flat_map(|c| c.mesh.as_ref().map(|h| h.untyped_clone()))
|
||||
.collect();
|
||||
|
||||
optionally_add_to_dep(&mut deps, &self.mesh);
|
||||
|
||||
deps
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
|
@ -9,12 +9,10 @@ edition = "2021"
|
|||
lyra-ecs = { path = "../lyra-ecs", features = [ "math" ] }
|
||||
lyra-reflect = { path = "../lyra-reflect", features = [ "math" ] }
|
||||
lyra-math = { path = "../lyra-math" }
|
||||
lyra-scene = { path = "../lyra-scene" }
|
||||
anyhow = "1.0.75"
|
||||
base64 = "0.21.4"
|
||||
crossbeam = { version = "0.8.4", features = [ "crossbeam-channel" ] }
|
||||
glam = "0.29.0"
|
||||
gltf = { version = "1.3.0", features = ["KHR_materials_pbrSpecularGlossiness", "KHR_materials_specular"] }
|
||||
image = "0.25.2"
|
||||
# not using custom matcher, or file type from file path
|
||||
infer = { version = "0.15.0", default-features = false }
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
pub mod loader;
|
||||
pub use loader::*;
|
||||
|
||||
pub mod material;
|
||||
use lyra_reflect::Reflect;
|
||||
use lyra_scene::SceneGraph;
|
||||
use crate::ResourceData;
|
||||
pub use material::*;
|
||||
|
||||
pub mod mesh;
|
||||
pub use mesh::*;
|
||||
|
||||
pub mod scene;
|
||||
pub use scene::*;
|
||||
|
||||
use crate::ResHandle;
|
||||
|
||||
use crate::lyra_engine;
|
||||
|
||||
/// A loaded Gltf file
|
||||
#[derive(Clone, Default, Reflect)]
|
||||
pub struct Gltf {
|
||||
pub scenes: Vec<ResHandle<SceneGraph>>,
|
||||
pub materials: Vec<ResHandle<Material>>,
|
||||
pub meshes: Vec<ResHandle<Mesh>>,
|
||||
}
|
||||
|
||||
impl ResourceData for Gltf {
|
||||
fn dependencies(&self) -> Vec<crate::UntypedResHandle> {
|
||||
let mut deps = vec![];
|
||||
|
||||
for scene in self.scenes.iter() {
|
||||
deps.push(scene.untyped_clone())
|
||||
}
|
||||
|
||||
for mat in self.materials.iter() {
|
||||
deps.push(mat.untyped_clone())
|
||||
}
|
||||
|
||||
for mesh in self.meshes.iter() {
|
||||
deps.push(mesh.untyped_clone())
|
||||
}
|
||||
|
||||
deps
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
use lyra_math::Transform;
|
||||
use lyra_scene::SceneGraph;
|
||||
use crate::{optionally_add_to_dep, ResourceData, UntypedResHandle};
|
||||
|
||||
use super::Mesh;
|
||||
use crate::ResHandle;
|
||||
|
||||
/// A Node in the Gltf file
|
||||
#[derive(Clone, Default)]
|
||||
pub struct GltfNode {
|
||||
pub name: Option<String>,
|
||||
pub mesh: Option<ResHandle<Mesh>>,
|
||||
pub transform: Transform,
|
||||
pub children: Vec<GltfNode>,
|
||||
}
|
||||
|
||||
impl ResourceData for GltfNode {
|
||||
fn dependencies(&self) -> Vec<crate::UntypedResHandle> {
|
||||
let mut deps: Vec<UntypedResHandle> = self.children.iter()
|
||||
.flat_map(|c| c.mesh.as_ref().map(|h| h.untyped_clone()))
|
||||
.collect();
|
||||
|
||||
optionally_add_to_dep(&mut deps, &self.mesh);
|
||||
|
||||
deps
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// A Scene in a Gltf file
|
||||
/* #[derive(Clone)]
|
||||
pub struct GltfScene {
|
||||
pub nodes: Vec<GltfNode>,
|
||||
}
|
||||
|
||||
impl ResourceData for GltfScene {
|
||||
fn dependencies(&self) -> Vec<crate::UntypedResHandle> {
|
||||
let deps: Vec<UntypedResHandle> = self.nodes.iter()
|
||||
.map(|n| n.dependencies())
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
deps
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl GltfScene {
|
||||
fn collect_node(&self, parent_node: &GltfNode, node: &GltfNode) -> Vec<(ResHandle<Mesh>, Transform)> {
|
||||
let mut v = vec![];
|
||||
|
||||
if let Some(mesh) = &node.mesh {
|
||||
v.push((mesh.clone(), parent_node.transform + node.transform));
|
||||
}
|
||||
|
||||
for child in node.children.iter() {
|
||||
let mut tmp = self.collect_node(node, child);
|
||||
v.append(&mut tmp);
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
/// Collects all Gltf meshes and gets their world Transform.
|
||||
pub fn collect_world_meshes(&self) -> Vec<(ResHandle<Mesh>, Transform)> {
|
||||
let mut v = vec![];
|
||||
|
||||
// process the root nodes in the scene
|
||||
for parent_node in self.nodes.iter() {
|
||||
if let Some(mesh) = &parent_node.mesh {
|
||||
v.push((mesh.clone(), parent_node.transform));
|
||||
}
|
||||
|
||||
for child in parent_node.children.iter() {
|
||||
let mut tmp = self.collect_node(parent_node, child);
|
||||
v.append(&mut tmp);
|
||||
}
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
} */
|
||||
|
||||
impl ResourceData for SceneGraph {
|
||||
fn dependencies(&self) -> Vec<crate::UntypedResHandle> {
|
||||
self.world().view::<&crate::UntypedResHandle>()
|
||||
.iter()
|
||||
.map(|han| han.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
|
@ -12,8 +12,6 @@ pub use dep_state::*;
|
|||
|
||||
pub mod loader;
|
||||
|
||||
pub mod gltf;
|
||||
|
||||
mod world_ext;
|
||||
pub use world_ext::*;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{any::{Any, TypeId}, marker::PhantomData, ops::{Deref, DerefMut}, sync::{Arc, Condvar, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}};
|
||||
use std::{any::{Any, TypeId}, marker::PhantomData, ops::{Deref, DerefMut}, sync::{Arc, Condvar, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}, time::Duration};
|
||||
|
||||
use lyra_ecs::Component;
|
||||
use lyra_reflect::Reflect;
|
||||
|
@ -198,17 +198,14 @@ impl UntypedResHandle {
|
|||
/// This blocks the thread without consuming CPU time; its backed by a
|
||||
/// [`Condvar`](std::sync::Condvar).
|
||||
pub fn wait_for_load(&self) {
|
||||
let d = self.read();
|
||||
self.wait_for_load_timeout_option_impl(None);
|
||||
}
|
||||
|
||||
if matches!(d.state, ResourceState::Ready(_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cv = d.condvar.clone();
|
||||
drop(d);
|
||||
|
||||
let l = cv.0.lock().unwrap();
|
||||
let _unused = cv.1.wait(l).unwrap();
|
||||
/// Does the same as [`UntypedResHandle::wait_for_load`] but has a timeout.
|
||||
///
|
||||
/// Returns true if the resource was loaded before hitting the timeout.
|
||||
pub fn wait_for_load_timeout(&self, timeout: Duration) -> bool {
|
||||
self.wait_for_load_timeout_option_impl(Some(timeout))
|
||||
}
|
||||
|
||||
/// Wait for the entire resource, including its dependencies to be loaded.
|
||||
|
@ -216,7 +213,41 @@ impl UntypedResHandle {
|
|||
/// This blocks the thread without consuming CPU time; its backed by a
|
||||
/// [`Condvar`](std::sync::Condvar).
|
||||
pub fn wait_recurse_dependencies_load(&self) {
|
||||
self.wait_for_load();
|
||||
self.wait_recurse_dependencies_load_timeout_option_impl(None);
|
||||
}
|
||||
|
||||
/// Does the same as [`UntypedResHandle::wait_recurse_dependencies_load`] but has a timeout.
|
||||
///
|
||||
/// Returns true if the resource was loaded before hitting the timeout.
|
||||
pub fn wait_recurse_dependencies_load_timeout(&self, timeout: Duration) -> bool {
|
||||
self.wait_recurse_dependencies_load_timeout_option_impl(Some(timeout))
|
||||
}
|
||||
|
||||
fn wait_for_load_timeout_option_impl(&self, timeout: Option<Duration>) -> bool {
|
||||
let d = self.read();
|
||||
|
||||
if matches!(d.state, ResourceState::Ready(_)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let cv = d.condvar.clone();
|
||||
drop(d);
|
||||
|
||||
let l = cv.0.lock().unwrap();
|
||||
|
||||
if let Some(timeout) = timeout {
|
||||
let (_unused, timeout) = cv.1.wait_timeout(l, timeout).unwrap();
|
||||
!timeout.timed_out()
|
||||
} else {
|
||||
let _unused = cv.1.wait(l).unwrap();
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn wait_recurse_dependencies_load_timeout_option_impl(&self, timeout: Option<Duration>) -> bool {
|
||||
if !self.wait_for_load_timeout_option_impl(timeout) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let res = self.read();
|
||||
match &res.state {
|
||||
|
@ -226,11 +257,16 @@ impl UntypedResHandle {
|
|||
// waiting for some resources and finish early.
|
||||
while self.recurse_dependency_state().is_loading() {
|
||||
for dep in data.recur_dependencies() {
|
||||
dep.wait_for_load();
|
||||
if !dep.wait_for_load_timeout_option_impl(timeout) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
},
|
||||
_ => unreachable!() // the self.wait_for_load ensures that the state is ready
|
||||
// self.wait_for_load at the start ensures that the state is ready
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use notify_debouncer_full::{DebouncedEvent, FileIdMap};
|
|||
use thiserror::Error;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{gltf::ModelLoader, loader::{ImageLoader, LoaderError, ResourceLoader}, resource::ResHandle, ResourceData, ResourceState, UntypedResHandle};
|
||||
use crate::{loader::{ImageLoader, LoaderError, ResourceLoader}, resource::ResHandle, ResourceData, ResourceState, UntypedResHandle};
|
||||
|
||||
/// A trait for type erased storage of a resource.
|
||||
/// Implemented for [`ResHandle<T>`]
|
||||
|
@ -82,7 +82,7 @@ impl Default for ResourceManager {
|
|||
ResourceManagerState {
|
||||
resources: HashMap::new(),
|
||||
uuid_resources: HashMap::new(),
|
||||
loaders: vec![ Arc::new(ImageLoader), Arc::new(ModelLoader) ],
|
||||
loaders: vec![ Arc::new(ImageLoader), ],
|
||||
watchers: HashMap::new(),
|
||||
}
|
||||
))
|
||||
|
@ -369,7 +369,7 @@ impl ResourceManager {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
pub mod tests {
|
||||
use std::{io, ops::Deref};
|
||||
|
||||
use instant::Instant;
|
||||
|
@ -384,7 +384,7 @@ pub(crate) mod tests {
|
|||
format!("{manifest}/test_files/img/{path}")
|
||||
}
|
||||
|
||||
pub(crate) fn busy_wait_resource<R: ResourceData>(handle: &ResHandle<R>, timeout: f32) {
|
||||
pub fn busy_wait_resource<R: ResourceData>(handle: &ResHandle<R>, timeout: f32) {
|
||||
let start = Instant::now();
|
||||
while !handle.is_loaded() {
|
||||
// loop until the image is loaded
|
||||
|
@ -398,7 +398,7 @@ pub(crate) mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn busy_wait_resource_reload<R: ResourceData>(handle: &ResHandle<R>, timeout: f32) {
|
||||
pub fn busy_wait_resource_reload<R: ResourceData>(handle: &ResHandle<R>, timeout: f32) {
|
||||
let version = handle.version();
|
||||
let start = Instant::now();
|
||||
|
||||
|
|
|
@ -1,42 +1 @@
|
|||
use base64::Engine;
|
||||
use thiserror::Error;
|
||||
use std::io;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Error, Debug)]
|
||||
pub enum UriReadError {
|
||||
#[error("IOError: '{0}'")]
|
||||
IoError(io::Error),
|
||||
|
||||
// From is implemented for this field in each loader module
|
||||
#[error("Base64 decoding error: '{0}'")]
|
||||
Base64Decode(base64::DecodeError),
|
||||
|
||||
#[error("Some data was missing from the uri")]
|
||||
None
|
||||
}
|
||||
|
||||
/// Read a buffer's uri string into a byte buffer.
|
||||
///
|
||||
/// * `containing_path`: The path of the containing folder of the buffers "parent",
|
||||
/// the parent being where this buffer is defined in,
|
||||
/// i.e. parent="resources/models/player.gltf", containing="resource/models"
|
||||
pub(crate) fn gltf_read_buffer_uri(containing_path: &str, uri: &str) -> Result<Vec<u8>, UriReadError> {
|
||||
if let Some((mime, data)) = uri.strip_prefix("data")
|
||||
.and_then(|uri| uri.split_once(',')) {
|
||||
let (_mime, is_base64) = match mime.strip_suffix(";base64") {
|
||||
Some(mime) => (mime, true),
|
||||
None => (mime, false),
|
||||
};
|
||||
|
||||
if is_base64 {
|
||||
base64::engine::general_purpose::STANDARD.decode(data)
|
||||
.map_err(UriReadError::Base64Decode)
|
||||
} else {
|
||||
Ok(data.as_bytes().to_vec())
|
||||
}
|
||||
} else {
|
||||
let full_path = format!("{containing_path}/{uri}");
|
||||
std::fs::read(full_path).map_err(UriReadError::IoError)
|
||||
}
|
||||
}
|
|
@ -10,3 +10,4 @@ anyhow = "1.0.81"
|
|||
lyra-ecs = { path = "../lyra-ecs", features = [ "math" ] }
|
||||
lyra-math = { path = "../lyra-math" }
|
||||
lyra-reflect = { path = "../lyra-reflect" }
|
||||
lyra-resource = { path = "../lyra-resource" }
|
|
@ -1,5 +1,6 @@
|
|||
mod node;
|
||||
use lyra_reflect::Reflect;
|
||||
use lyra_resource::{ResourceData, UntypedResHandle};
|
||||
pub use node::*;
|
||||
|
||||
mod world_transform;
|
||||
|
@ -135,6 +136,23 @@ impl SceneGraph {
|
|||
}
|
||||
}
|
||||
|
||||
impl ResourceData for SceneGraph {
|
||||
fn dependencies(&self) -> Vec<UntypedResHandle> {
|
||||
self.world().view::<&UntypedResHandle>()
|
||||
.iter()
|
||||
.map(|han| han.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a node under a parent node.
|
||||
///
|
||||
/// The spawned entity will have a `ChildOf` relation targeting the provided parent node,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{any::TypeId, ops::Deref};
|
||||
use lyra_resource::{gltf::{Gltf, Material, Mesh}, FilterMode, ResHandle, Texture, WrappingMode};
|
||||
use lyra_game::scene::SceneGraph;
|
||||
use lyra_resource::{FilterMode, ResHandle, Texture, WrappingMode};
|
||||
use lyra_game::{scene::SceneGraph, gltf::{Gltf, Material, Mesh, PbrGlossiness, Specular, MeshIndices, AlphaMode}};
|
||||
use lyra_reflect::Reflect;
|
||||
use lyra_scripting_derive::{lua_wrap_handle, wrap_lua_struct};
|
||||
|
||||
|
@ -58,7 +58,7 @@ wrap_lua_struct!(lyra_resource::TextureSampler,
|
|||
}
|
||||
);
|
||||
|
||||
wrap_lua_struct!(lyra_resource::gltf::PbrGlossiness,
|
||||
wrap_lua_struct!(PbrGlossiness,
|
||||
// this can be safely skipped since it wont be a component or resource.
|
||||
skip(lua_reflect),
|
||||
fields={
|
||||
|
@ -68,7 +68,7 @@ wrap_lua_struct!(lyra_resource::gltf::PbrGlossiness,
|
|||
}
|
||||
);
|
||||
|
||||
wrap_lua_struct!(lyra_resource::gltf::Specular,
|
||||
wrap_lua_struct!(Specular,
|
||||
// this can be safely skipped since it wont be a component or resource.
|
||||
skip(lua_reflect),
|
||||
fields={
|
||||
|
@ -104,13 +104,13 @@ lua_wrap_handle!(Mesh,
|
|||
let table = lua.create_table()?;
|
||||
|
||||
match &data.indices {
|
||||
Some(lyra_resource::gltf::MeshIndices::U16(v)) => {
|
||||
Some(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)) => {
|
||||
Some(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)?;
|
||||
|
@ -178,9 +178,9 @@ lua_wrap_handle!(Material,
|
|||
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",
|
||||
AlphaMode::Opaque => "opaque",
|
||||
AlphaMode::Mask => "mask",
|
||||
AlphaMode::Blend => "blend",
|
||||
}.into_lua(lua)
|
||||
}),
|
||||
(specular, {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use lyra_engine::{
|
||||
assets::{gltf::Gltf, ResourceManager}, ecs::query::View, game::App, input::{
|
||||
assets::ResourceManager, gltf::Gltf, ecs::query::View, game::App, input::{
|
||||
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
|
||||
InputActionPlugin, KeyCode, LayoutId,
|
||||
}, math::{self, Transform, Vec3}, render::light::directional::DirectionalLight, scene::{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::ptr::NonNull;
|
||||
|
||||
use lyra_engine::{
|
||||
assets::{gltf::Gltf, ResourceManager},
|
||||
assets::ResourceManager, gltf::Gltf,
|
||||
ecs::{
|
||||
query::{Res, View},
|
||||
system::{BatchedSystem, Criteria, CriteriaSchedule, IntoSystem},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use lyra_engine::{
|
||||
assets::{gltf::Gltf, ResourceManager}, game::App, input::{
|
||||
assets::ResourceManager, gltf::Gltf, game::App, input::{
|
||||
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
|
||||
InputActionPlugin, KeyCode, LayoutId, MouseAxis, MouseInput,
|
||||
}, math::{self, Transform, Vec3}, render::light::directional::DirectionalLight, scene::{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use lyra_engine::{assets::{gltf::Gltf, ResourceManager}, ecs::query::{Res, View}, game::App, input::{Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource, InputActionPlugin, KeyCode, LayoutId, MouseAxis, MouseInput}, math::{self, Quat, Transform, Vec3}, render::light::{directional::DirectionalLight, PointLight}, scene::{CameraComponent, FreeFlyCamera, FreeFlyCameraPlugin, ACTLBL_LOOK_LEFT_RIGHT, ACTLBL_LOOK_ROLL, ACTLBL_LOOK_UP_DOWN, ACTLBL_MOVE_FORWARD_BACKWARD, ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN}, DeltaTime};
|
||||
use lyra_engine::{assets::ResourceManager, gltf::Gltf, ecs::query::{Res, View}, game::App, input::{Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource, InputActionPlugin, KeyCode, LayoutId, MouseAxis, MouseInput}, math::{self, Quat, Transform, Vec3}, render::light::{directional::DirectionalLight, PointLight}, scene::{CameraComponent, FreeFlyCamera, FreeFlyCameraPlugin, ACTLBL_LOOK_LEFT_RIGHT, ACTLBL_LOOK_ROLL, ACTLBL_LOOK_UP_DOWN, ACTLBL_MOVE_FORWARD_BACKWARD, ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN}, DeltaTime};
|
||||
use rand::Rng;
|
||||
use tracing::info;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use lyra_engine::{
|
||||
assets::{gltf::Gltf, ResourceManager},
|
||||
assets::ResourceManager, gltf::Gltf,
|
||||
game::App,
|
||||
input::{
|
||||
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use lyra_engine::{
|
||||
assets::{gltf::Gltf, ResourceManager}, ecs::query::View, game::App, input::{
|
||||
assets::ResourceManager, gltf::Gltf, ecs::query::View, game::App, input::{
|
||||
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
|
||||
InputActionPlugin, KeyCode, LayoutId,
|
||||
}, math::{self, Transform, Vec3}, render::light::directional::DirectionalLight, scene::{
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::ptr::NonNull;
|
|||
|
||||
use lyra_engine::assets::ResourceManager;
|
||||
use lyra_engine::{
|
||||
assets::gltf::Gltf,
|
||||
gltf::Gltf,
|
||||
ecs::{
|
||||
query::{Res, View},
|
||||
system::{Criteria, CriteriaSchedule, IntoSystem},
|
||||
|
|
Loading…
Reference in New Issue