engine build fix + resource system improvements

This commit is contained in:
Dmitry
2023-04-23 14:00:21 +03:00
parent d42c7aa0cb
commit 435b7e0f09
77 changed files with 1314 additions and 1205 deletions
+12 -12
View File
@@ -38,15 +38,15 @@ use fyrox::{
inspectable::InspectablePropertyEditorDefinition, PropertyEditorDefinitionContainer,
},
material::{
shader::{Shader, ShaderError, ShaderState},
shader::{Shader, ShaderError, ShaderResource},
SharedMaterial,
},
resource::{
curve::{CurveResource, CurveResourceError, CurveResourceState},
model::{MaterialSearchOptions, Model, ModelData, ModelLoadError},
model::{MaterialSearchOptions, Model, ModelLoadError, ModelResource},
texture::{
CompressionOptions, Texture, TextureMagnificationFilter, TextureMinificationFilter,
TextureWrapMode,
CompressionOptions, TextureMagnificationFilter, TextureMinificationFilter,
TextureResource, TextureWrapMode,
},
},
scene::{
@@ -89,8 +89,8 @@ use fyrox::{
HighShelfFilterEffect, LowPassFilterEffect, LowShelfFilterEffect,
},
reverb::Reverb,
Attenuate, AudioBus, Biquad, DistanceModel, Effect, EffectWrapper, SoundBufferResource,
SoundBufferResourceLoadError, SoundBufferState, Status,
Attenuate, AudioBus, Biquad, DistanceModel, Effect, EffectWrapper, SoundBuffer,
SoundBufferResource, SoundBufferResourceLoadError, Status,
},
terrain::Layer,
transform::Transform,
@@ -132,7 +132,7 @@ pub fn make_property_editors_container(
let container = PropertyEditorDefinitionContainer::new();
container.insert(TexturePropertyEditorDefinition);
container.insert(InheritablePropertyEditorDefinition::<Option<Texture>>::new());
container.insert(InheritablePropertyEditorDefinition::<Option<TextureResource>>::new());
container.insert(InheritablePropertyEditorDefinition::<Handle<Node>>::new());
container.insert(MaterialPropertyEditorDefinition {
@@ -174,17 +174,17 @@ pub fn make_property_editors_container(
.register_inheritable_vec_collection::<fyrox::animation::spritesheet::signal::Signal>();
container.insert(ResourceFieldPropertyEditorDefinition::<
ModelResource,
Model,
ModelData,
ModelLoadError,
>::new(Rc::new(|resource_manager, path| {
block_on(resource_manager.request_model(path))
})));
container.insert(InheritablePropertyEditorDefinition::<Option<Model>>::new());
container.insert(InheritablePropertyEditorDefinition::<Option<ModelResource>>::new());
container.insert(ResourceFieldPropertyEditorDefinition::<
SoundBufferResource,
SoundBufferState,
SoundBuffer,
SoundBufferResourceLoadError,
>::new(Rc::new(|resource_manager, path| {
block_on(resource_manager.request_sound_buffer(path))
@@ -203,13 +203,13 @@ pub fn make_property_editors_container(
container.insert(InheritablePropertyEditorDefinition::<Option<CurveResource>>::new());
container.insert(ResourceFieldPropertyEditorDefinition::<
ShaderResource,
Shader,
ShaderState,
ShaderError,
>::new(Rc::new(|resource_manager, path| {
block_on(resource_manager.request_shader(path))
})));
container.insert(InheritablePropertyEditorDefinition::<Option<Shader>>::new());
container.insert(InheritablePropertyEditorDefinition::<Option<ShaderResource>>::new());
container.register_inheritable_inspectable::<ColorGradingLut>();
container.register_inheritable_inspectable::<InteractionGroups>();
+9 -9
View File
@@ -16,7 +16,7 @@ use fyrox::{
widget::{Widget, WidgetBuilder, WidgetMessage},
BuildContext, Control, Thickness, UiNode, UserInterface,
},
resource::texture::Texture,
resource::texture::TextureResource,
utils::into_gui_texture,
};
use std::{
@@ -30,7 +30,7 @@ pub struct TextureEditor {
widget: Widget,
image: Handle<UiNode>,
resource_manager: ResourceManager,
texture: Option<Texture>,
texture: Option<TextureResource>,
}
impl Debug for TextureEditor {
@@ -55,11 +55,11 @@ impl DerefMut for TextureEditor {
#[derive(Debug, PartialEq, Clone, Eq)]
pub enum TextureEditorMessage {
Texture(Option<Texture>),
Texture(Option<TextureResource>),
}
impl TextureEditorMessage {
define_constructor!(TextureEditorMessage:Texture => fn texture(Option<Texture>), layout: false);
define_constructor!(TextureEditorMessage:Texture => fn texture(Option<TextureResource>), layout: false);
}
impl Control for TextureEditor {
@@ -106,7 +106,7 @@ impl Control for TextureEditor {
pub struct TextureEditorBuilder {
widget_builder: WidgetBuilder,
texture: Option<Texture>,
texture: Option<TextureResource>,
}
impl TextureEditorBuilder {
@@ -117,7 +117,7 @@ impl TextureEditorBuilder {
}
}
pub fn with_texture(mut self, texture: Option<Texture>) -> Self {
pub fn with_texture(mut self, texture: Option<TextureResource>) -> Self {
self.texture = texture;
self
}
@@ -158,14 +158,14 @@ pub struct TexturePropertyEditorDefinition;
impl PropertyEditorDefinition for TexturePropertyEditorDefinition {
fn value_type_id(&self) -> TypeId {
TypeId::of::<Option<Texture>>()
TypeId::of::<Option<TextureResource>>()
}
fn create_instance(
&self,
ctx: PropertyEditorBuildContext,
) -> Result<PropertyEditorInstance, InspectorError> {
let value = ctx.property_info.cast_value::<Option<Texture>>()?;
let value = ctx.property_info.cast_value::<Option<TextureResource>>()?;
Ok(PropertyEditorInstance::Simple {
editor: TextureEditorBuilder::new(
@@ -189,7 +189,7 @@ impl PropertyEditorDefinition for TexturePropertyEditorDefinition {
&self,
ctx: PropertyEditorMessageContext,
) -> Result<Option<UiMessage>, InspectorError> {
let value = ctx.property_info.cast_value::<Option<Texture>>()?;
let value = ctx.property_info.cast_value::<Option<TextureResource>>()?;
Ok(Some(TextureEditorMessage::texture(
ctx.instance,
+8 -8
View File
@@ -109,9 +109,9 @@ use fyrox::{
window::{WindowBuilder, WindowMessage, WindowTitle},
BuildContext, UiNode, UserInterface, VerticalAlignment,
},
material::{shader::Shader, Material, PropertyValue, SharedMaterial},
material::{shader::ShaderResource, Material, PropertyValue, SharedMaterial},
plugin::PluginConstructor,
resource::texture::{CompressionOptions, Texture, TextureKind},
resource::texture::{CompressionOptions, TextureKind, TextureResource},
scene::{
camera::{Camera, Projection},
mesh::Mesh,
@@ -152,13 +152,13 @@ type GameEngine = fyrox::engine::Engine;
pub fn load_image(data: &[u8]) -> Option<draw::SharedTexture> {
Some(into_gui_texture(
Texture::load_from_memory(data, CompressionOptions::NoCompression, false).ok()?,
TextureResource::load_from_memory(data, CompressionOptions::NoCompression, false).ok()?,
))
}
lazy_static! {
static ref GIZMO_SHADER: Shader = {
Shader::from_str(
static ref GIZMO_SHADER: ShaderResource = {
ShaderResource::from_str(
include_str!("../resources/embed/shaders/gizmo.shader",),
PathBuf::default(),
)
@@ -536,7 +536,7 @@ impl Editor {
let graphics_context = engine.graphics_context.as_initialized_mut();
if let Ok(icon_img) = Texture::load_from_memory(
if let Ok(icon_img) = TextureResource::load_from_memory(
include_bytes!("../resources/embed/icon.png"),
CompressionOptions::NoCompression,
false,
@@ -891,7 +891,7 @@ impl Editor {
}
// Setup new one.
scene.render_target = Some(Texture::new_render_target(0, 0));
scene.render_target = Some(TextureResource::new_render_target(0, 0));
self.scene_viewer
.set_render_target(&self.engine.user_interface, scene.render_target.clone());
@@ -1408,7 +1408,7 @@ impl Editor {
{
let frame_size = self.scene_viewer.frame_bounds(&engine.user_interface).size;
if width != frame_size.x as u32 || height != frame_size.y as u32 {
scene.render_target = Some(Texture::new_render_target(
scene.render_target = Some(TextureResource::new_render_target(
frame_size.x as u32,
frame_size.y as u32,
));
+3 -3
View File
@@ -39,7 +39,7 @@ use fyrox::{
window::{WindowBuilder, WindowTitle},
BuildContext, RcUiNodeHandle, Thickness, UiNode, UserInterface, VerticalAlignment,
},
material::{shader::Shader, Material, PropertyValue, SharedMaterial},
material::{shader::ShaderResource, Material, PropertyValue, SharedMaterial},
resource::texture::TextureState,
scene::{
base::BaseBuilder,
@@ -89,7 +89,7 @@ pub struct MaterialEditor {
preview: PreviewPanel,
material: Option<SharedMaterial>,
available_shaders: Handle<UiNode>,
shaders_list: Vec<Shader>,
shaders_list: Vec<ShaderResource>,
texture_context_menu: TextureContextMenu,
}
@@ -328,7 +328,7 @@ impl MaterialEditor {
self.shaders_list.clear();
self.shaders_list
.extend_from_slice(&Shader::standard_shaders());
.extend_from_slice(&ShaderResource::standard_shaders());
for dir in fyrox::walkdir::WalkDir::new(".").into_iter().flatten() {
let path = dir.path();
+5 -5
View File
@@ -11,7 +11,7 @@ use fyrox::{
},
RenderPassStatistics, SceneRenderPass, SceneRenderPassContext,
},
resource::texture::{CompressionOptions, Texture},
resource::texture::{CompressionOptions, TextureResource},
scene::mesh::surface::SurfaceData,
};
use std::{cell::RefCell, rc::Rc};
@@ -51,8 +51,8 @@ impl OverlayShader {
pub struct OverlayRenderPass {
quad: GeometryBuffer,
shader: OverlayShader,
sound_icon: Texture,
light_icon: Texture,
sound_icon: TextureResource,
light_icon: TextureResource,
pub pictogram_size: f32,
}
@@ -65,13 +65,13 @@ impl OverlayRenderPass {
state,
),
shader: OverlayShader::new(state).unwrap(),
sound_icon: Texture::load_from_memory(
sound_icon: TextureResource::load_from_memory(
include_bytes!("../resources/embed/sound_source.png"),
CompressionOptions::NoCompression,
false,
)
.unwrap(),
light_icon: Texture::load_from_memory(
light_icon: TextureResource::load_from_memory(
include_bytes!("../resources/embed/light_source.png"),
CompressionOptions::NoCompression,
false,
+4 -3
View File
@@ -16,7 +16,7 @@ use fyrox::{
widget::{WidgetBuilder, WidgetMessage},
HorizontalAlignment, Orientation, Thickness, UiNode, VerticalAlignment,
},
resource::texture::{Texture, TextureKind},
resource::texture::{TextureKind, TextureResource},
scene::{
base::BaseBuilder,
camera::{CameraBuilder, Projection},
@@ -157,7 +157,7 @@ impl PreviewPanel {
scene.ambient_lighting_color = Color::opaque(80, 80, 80);
let render_target = Texture::new_render_target(width, height);
let render_target = TextureResource::new_render_target(width, height);
scene.render_target = Some(render_target.clone());
let scene = engine.scenes.add(scene);
@@ -371,7 +371,8 @@ impl PreviewPanel {
if let Some(frame) = engine.user_interface.node(self.frame).cast::<Image>() {
let frame_size = frame.actual_local_size();
if rt_width != frame_size.x as u32 || rt_height != frame_size.y as u32 {
let rt = Texture::new_render_target(frame_size.x as u32, frame_size.y as u32);
let rt =
TextureResource::new_render_target(frame_size.x as u32, frame_size.y as u32);
scene.render_target = Some(rt.clone());
engine.user_interface.send_message(ImageMessage::texture(
self.frame,
+3 -3
View File
@@ -1,7 +1,7 @@
use crate::{command::Command, scene::commands::SceneContext};
use fyrox::{
core::sstorage::ImmutableString,
material::{shader::Shader, Material, PropertyValue, SharedMaterial},
material::{shader::ShaderResource, Material, PropertyValue, SharedMaterial},
};
#[derive(Debug)]
@@ -48,7 +48,7 @@ impl Command for SetMaterialPropertyValueCommand {
#[derive(Debug)]
enum SetMaterialShaderCommandState {
Undefined,
NonExecuted { new_shader: Shader },
NonExecuted { new_shader: ShaderResource },
Executed { old_material: Material },
Reverted { new_material: Material },
}
@@ -60,7 +60,7 @@ pub struct SetMaterialShaderCommand {
}
impl SetMaterialShaderCommand {
pub fn new(material: SharedMaterial, shader: Shader) -> Self {
pub fn new(material: SharedMaterial, shader: ShaderResource) -> Self {
Self {
material,
state: SetMaterialShaderCommandState::NonExecuted { new_shader: shader },
+4 -4
View File
@@ -2,14 +2,14 @@ use crate::{command::Command, scene::commands::SceneContext};
use fyrox::{
core::{pool::Handle, sstorage::ImmutableString},
material::{shader::SamplerFallback, PropertyValue},
resource::texture::Texture,
resource::texture::TextureResource,
scene::{mesh::Mesh, node::Node},
};
#[derive(Debug)]
enum TextureSet {
Single(Texture),
Multiple(Vec<Option<Texture>>),
Single(TextureResource),
Multiple(Vec<Option<TextureResource>>),
}
#[derive(Debug)]
@@ -19,7 +19,7 @@ pub struct SetMeshTextureCommand {
}
impl SetMeshTextureCommand {
pub fn new(node: Handle<Node>, texture: Texture) -> Self {
pub fn new(node: Handle<Node>, texture: TextureResource) -> Self {
Self {
node,
set: TextureSet::Single(texture),
+4 -4
View File
@@ -2,7 +2,7 @@ use crate::{command::Command, create_terrain_layer_material, scene::commands::Sc
use fyrox::resource::texture::{TextureKind, TexturePixelKind};
use fyrox::{
core::pool::Handle,
resource::texture::Texture,
resource::texture::TextureResource,
scene::{node::Node, terrain::Layer},
utils,
};
@@ -11,7 +11,7 @@ use fyrox::{
pub struct AddTerrainLayerCommand {
terrain: Handle<Node>,
layer: Option<Layer>,
masks: Vec<Texture>,
masks: Vec<TextureResource>,
}
impl AddTerrainLayerCommand {
@@ -50,7 +50,7 @@ pub struct DeleteTerrainLayerCommand {
terrain: Handle<Node>,
layer: Option<Layer>,
index: usize,
masks: Vec<Texture>,
masks: Vec<TextureResource>,
}
impl DeleteTerrainLayerCommand {
@@ -121,7 +121,7 @@ impl ModifyTerrainHeightCommand {
) {
chunk
.set_heightmap(
Texture::from_bytes(
TextureResource::from_bytes(
TextureKind::Rectangle {
width: heigth_map_size.x,
height: heigth_map_size.y,
+2 -2
View File
@@ -37,7 +37,7 @@ use fyrox::{
VerticalAlignment, BRUSH_BRIGHT_BLUE, BRUSH_DARKER, BRUSH_DARKEST, BRUSH_LIGHT,
BRUSH_LIGHTER, BRUSH_LIGHTEST,
},
resource::texture::{Texture, TextureState},
resource::texture::{TextureResource, TextureState},
scene::{
camera::{Camera, Projection},
node::Node,
@@ -764,7 +764,7 @@ impl SceneViewer {
));
}
pub fn set_render_target(&self, ui: &UserInterface, render_target: Option<Texture>) {
pub fn set_render_target(&self, ui: &UserInterface, render_target: Option<TextureResource>) {
ui.send_message(ImageMessage::texture(
self.frame,
MessageDirection::ToWidget,
+3 -3
View File
@@ -7,7 +7,7 @@ use fyrox::{
window::{Window, WindowBuilder},
BuildContext, UiNode, UserInterface,
},
resource::texture::{CompressionOptions, Texture},
resource::texture::{CompressionOptions, TextureResource},
scene::camera::{SkyBox, SkyBoxBuilder},
};
@@ -86,8 +86,8 @@ pub fn fetch_node_screen_center_ui(handle: Handle<UiNode>, ui: &UserInterface) -
.unwrap_or_default()
}
fn load_texture(data: &[u8]) -> Texture {
Texture::load_from_memory(data, CompressionOptions::NoCompression, false)
fn load_texture(data: &[u8]) -> TextureResource {
TextureResource::load_from_memory(data, CompressionOptions::NoCompression, false)
.ok()
.unwrap()
}
+3 -3
View File
@@ -26,7 +26,7 @@ use fyrox::{
VerticalAlignment,
},
material::PropertyValue,
resource::{model::Model, texture::Texture},
resource::{model::ModelResource, texture::TextureResource},
scene::{
camera::Camera, decal::Decal, dim2::rectangle::Rectangle, light::spot::SpotLight,
mesh::Mesh, particle_system::ParticleSystem, sprite::Sprite, terrain::Terrain, Scene,
@@ -60,8 +60,8 @@ pub struct PathFixer {
#[derive(Clone)]
enum SceneResource {
Model(Model),
Texture(Texture),
Model(ModelResource),
Texture(TextureResource),
// TODO: Add sound buffers.
}
+8 -8
View File
@@ -32,8 +32,8 @@ use fyrox::{
event_loop::{ControlFlow, EventLoop},
material::{shader::SamplerFallback, Material, PropertyValue, SharedMaterial},
resource::{
model::{Model, ModelImportOptions},
texture::{Texture, TextureImportOptions},
model::{ModelImportOptions, ModelResource},
texture::{TextureImportOptions, TextureResource},
},
scene::{
base::BaseBuilder,
@@ -55,12 +55,12 @@ use std::sync::Arc;
struct CustomModelLoader(Arc<ModelLoader>);
impl ResourceLoader<Model, ModelImportOptions> for CustomModelLoader {
impl ResourceLoader<ModelResource, ModelImportOptions> for CustomModelLoader {
fn load(
&self,
resource: Model,
resource: ModelResource,
default_import_options: ModelImportOptions,
event_broadcaster: ResourceEventBroadcaster<Model>,
event_broadcaster: ResourceEventBroadcaster<ModelResource>,
reload: bool,
) -> BoxedLoaderFuture {
// Arc is required as BoxedLoaderFuture has a static lifetime and hence self cannot be
@@ -79,12 +79,12 @@ impl ResourceLoader<Model, ModelImportOptions> for CustomModelLoader {
/// For simplicity we just simply wrap the default loader and log the invocation to the console.
struct CustomTextureLoader(Arc<TextureLoader>);
impl ResourceLoader<Texture, TextureImportOptions> for CustomTextureLoader {
impl ResourceLoader<TextureResource, TextureImportOptions> for CustomTextureLoader {
fn load(
&self,
resource: Texture,
resource: TextureResource,
default_import_options: TextureImportOptions,
event_broadcaster: ResourceEventBroadcaster<Texture>,
event_broadcaster: ResourceEventBroadcaster<TextureResource>,
reload: bool,
) -> BoxedLoaderFuture {
// Arc is required as BoxedLoaderFuture has a static lifetime and hence self cannot be
+4 -4
View File
@@ -11,14 +11,14 @@ use fyrox::{
UiNode, VerticalAlignment,
},
plugin::{Plugin, PluginConstructor, PluginContext},
resource::texture::{Texture, TextureKind},
resource::texture::{TextureKind, TextureResource},
scene::{Scene, SceneLoader},
utils,
window::WindowAttributes,
};
struct Game {
render_target: Texture,
render_target: TextureResource,
scene_handle: Handle<Scene>,
scene_image: Handle<UiNode>,
exit: Handle<UiNode>,
@@ -38,7 +38,7 @@ impl Plugin for Game {
// Re-create render target with new size.
drop(render_target);
self.render_target =
Texture::new_render_target(image_size.x as u32, image_size.y as u32);
TextureResource::new_render_target(image_size.x as u32, image_size.y as u32);
context.scenes[self.scene_handle].render_target = Some(self.render_target.clone());
context.user_interface.send_message(ImageMessage::texture(
self.scene_image,
@@ -100,7 +100,7 @@ impl PluginConstructor for GameConstructor {
// Create render target and force the scene to render into it.
let rt_size = Vector2::new(100.0, 100.0);
let render_target = Texture::new_render_target(rt_size.x as u32, rt_size.y as u32);
let render_target = TextureResource::new_render_target(rt_size.x as u32, rt_size.y as u32);
scene.render_target = Some(render_target.clone());
// Add the loaded scene to the engine.
+7
View File
@@ -53,6 +53,7 @@ pub use notify;
#[cfg(target_arch = "wasm32")]
pub use js_sys;
use std::iter::FromIterator;
use uuid::Uuid;
#[cfg(target_arch = "wasm32")]
pub use wasm_bindgen;
#[cfg(target_arch = "wasm32")]
@@ -348,3 +349,9 @@ pub fn make_relative_path<P: AsRef<Path>>(path: P) -> Result<PathBuf, std::io::E
)),
}
}
/// A trait for an entity that has unique type identifier.
pub trait TypeUuidProvider: Sized {
/// Return type UUID.
fn type_uuid() -> Uuid;
}
+9 -39
View File
@@ -6,15 +6,15 @@ use crate::{
entry::{TimedEntry, DEFAULT_RESOURCE_LIFETIME},
event::{ResourceEvent, ResourceEventBroadcaster},
},
core::{variable::InheritableVariable, VecExtensions},
core::VecExtensions,
loader::ResourceLoader,
state::ResourceState,
task::TaskPool,
UntypedResource,
};
use fxhash::FxHashMap;
use std::ffi::OsString;
use std::{path::Path, sync::Arc};
use fyrox_core::uuid::Uuid;
use std::{ffi::OsString, path::Path, sync::Arc};
pub mod entry;
pub mod event;
@@ -168,11 +168,14 @@ impl ResourceContainer {
}
/// Tries to load a resources at a given path.
pub fn request<P: AsRef<Path>>(&mut self, path: P) -> UntypedResource {
pub fn request<P>(&mut self, path: P, type_uuid: Uuid) -> UntypedResource
where
P: AsRef<Path>,
{
match self.find(path.as_ref()) {
Some(existing) => existing.clone(),
None => {
let resource = UntypedResource::new_pending(path.as_ref().to_owned());
let resource = UntypedResource::new_pending(path.as_ref().to_owned(), type_uuid);
self.push(resource.clone());
@@ -192,7 +195,7 @@ impl ResourceContainer {
/// Reloads a single resource.
pub fn reload_resource(&mut self, resource: UntypedResource) {
let state = resource.0.lock();
let mut state = resource.0.lock();
if !state.is_loading() {
let path = state.path().to_path_buf();
@@ -218,39 +221,6 @@ impl ResourceContainer {
resources
}
/// Tries to restore resource by making an attempt to request resource with path from existing
/// resource instance. This method is used to restore "shallow" resources after scene
/// deserialization.
pub fn try_restore_resource(&mut self, resource: &mut UntypedResource) {
let path = resource.0.lock().path().to_path_buf();
let new_resource = self.request(path);
*resource = new_resource;
}
/// Tries to restore resource by making an attempt to request resource with path from existing
/// resource instance. This method is used to restore "shallow" resources after scene
/// deserialization.
pub fn try_restore_optional_resource(&mut self, resource: &mut Option<UntypedResource>) {
if let Some(shallow_resource) = resource.as_mut() {
let path = shallow_resource.0.lock().path().to_path_buf();
let new_resource = self.request(path);
*shallow_resource = new_resource;
}
}
/// Tries to restore resource by making an attempt to request resource with path from existing
/// resource instance. This method is used to restore "shallow" resources after scene
/// deserialization.
pub fn try_restore_inheritable_resource(
&mut self,
inheritable_resource: &mut InheritableVariable<Option<UntypedResource>>,
) {
if let Some(shallow_resource) = inheritable_resource.get_value_mut_silent().as_mut() {
let new_resource = self.request(shallow_resource.0.lock().path());
*shallow_resource = new_resource;
}
}
}
impl Container for ResourceContainer {
+127 -79
View File
@@ -1,23 +1,23 @@
//! Resource management
#![warn(missing_docs)]
// #![warn(missing_docs)] TODO
use crate::{
core::{
parking_lot::MutexGuard,
reflect::prelude::*,
reflect::FieldValue,
uuid::{uuid, Uuid},
visitor::prelude::*,
},
state::ResourceState,
};
use std::fmt::Display;
use std::{
any::Any,
borrow::Cow,
fmt::{Debug, Formatter},
future::Future,
hash::Hash,
hash::{Hash, Hasher},
marker::PhantomData,
ops::{Deref, DerefMut},
path::{Path, PathBuf},
@@ -26,8 +26,10 @@ use std::{
task::{Context, Poll},
};
use crate::manager::ResourceManager;
use crate::untyped::UntypedResource;
pub use fyrox_core as core;
use fyrox_core::TypeUuidProvider;
pub mod constructor;
pub mod container;
@@ -39,6 +41,7 @@ pub mod task;
pub mod untyped;
pub const TEXTURE_RESOURCE_UUID: Uuid = uuid!("02c23a44-55fa-411a-bc39-eb7a5eadf15c");
pub const MODEL_RESOURCE_UUID: Uuid = uuid!("44cd768f-b4ca-4804-a98c-0adf85577ada");
pub const SOUND_BUFFER_RESOURCE_UUID: Uuid = uuid!("f6a077b7-c8ff-4473-a95b-0289441ea9d8");
pub const SHADER_RESOURCE_UUID: Uuid = uuid!("f1346417-b726-492a-b80f-c02096c6c019");
pub const CURVE_RESOURCE_UUID: Uuid = uuid!("f28b949f-28a2-4b68-9089-59c234f58b6b");
@@ -59,13 +62,13 @@ pub trait ResourceData: 'static + Debug + Visit + Send {
}
/// A trait for resource load error.
pub trait ResourceLoadError: 'static + Debug + Display + Send + Sync {}
pub trait ResourceLoadError: 'static + Debug + Send + Sync {}
impl<T> ResourceLoadError for T where T: 'static + Display + Debug + Send + Sync {}
impl<T> ResourceLoadError for T where T: 'static + Debug + Send + Sync {}
pub struct ResourceStateGuard<'a, T>
where
T: ResourceData,
T: ResourceData + TypeUuidProvider,
{
guard: MutexGuard<'a, ResourceState>,
phantom: PhantomData<T>,
@@ -73,12 +76,25 @@ where
impl<'a, T> ResourceStateGuard<'a, T>
where
T: ResourceData,
T: ResourceData + TypeUuidProvider,
{
pub fn get(&mut self) -> ResourceStateRef<'_, T> {
match &*self.guard {
ResourceState::Pending { path, .. } => ResourceStateRef::Pending { path },
ResourceState::LoadError { path, error } => ResourceStateRef::LoadError { path, error },
ResourceState::Pending {
path, type_uuid, ..
} => ResourceStateRef::Pending {
path,
type_uuid: *type_uuid,
},
ResourceState::LoadError {
path,
error,
type_uuid,
} => ResourceStateRef::LoadError {
path,
error,
type_uuid: *type_uuid,
},
ResourceState::Ok(data) => {
ResourceStateRef::Ok(data.as_any().downcast_ref().expect("Type mismatch!"))
}
@@ -87,10 +103,21 @@ where
pub fn get_mut(&mut self) -> ResourceStateRefMut<'_, T> {
match &mut *self.guard {
ResourceState::Pending { path, .. } => ResourceStateRefMut::Pending { path },
ResourceState::LoadError { path, error } => {
ResourceStateRefMut::LoadError { path, error }
}
ResourceState::Pending {
path, type_uuid, ..
} => ResourceStateRefMut::Pending {
path,
type_uuid: *type_uuid,
},
ResourceState::LoadError {
path,
error,
type_uuid,
} => ResourceStateRefMut::LoadError {
path,
error,
type_uuid: *type_uuid,
},
ResourceState::Ok(data) => {
ResourceStateRefMut::Ok(data.as_any_mut().downcast_mut().expect("Type mismatch!"))
}
@@ -107,6 +134,7 @@ where
Pending {
/// A path to load resource from.
path: &'a PathBuf,
type_uuid: Uuid,
},
/// An error has occurred during the load.
LoadError {
@@ -114,6 +142,7 @@ where
path: &'a PathBuf,
/// An error.
error: &'a Option<Arc<dyn ResourceLoadError>>,
type_uuid: Uuid,
},
/// Actual resource data when it is fully loaded.
Ok(&'a T),
@@ -125,6 +154,7 @@ pub enum ResourceStateRefMut<'a, T> {
Pending {
/// A path to load resource from.
path: &'a mut PathBuf,
type_uuid: Uuid,
},
/// An error has occurred during the load.
LoadError {
@@ -132,6 +162,7 @@ pub enum ResourceStateRefMut<'a, T> {
path: &'a mut PathBuf,
/// An error.
error: &'a mut Option<Arc<dyn ResourceLoadError>>,
type_uuid: Uuid,
},
/// Actual resource data when it is fully loaded.
Ok(&'a mut T),
@@ -142,27 +173,86 @@ impl Default for ResourceState {
Self::LoadError {
error: None,
path: Default::default(),
type_uuid: Default::default(),
}
}
}
#[derive(Visit, PartialEq, Eq, Hash, Debug)]
#[derive(Debug, Reflect)]
#[reflect(hide_all)]
pub struct Resource<T>
where
T: ResourceData,
T: ResourceData + TypeUuidProvider,
{
state: Option<UntypedResource>,
#[visit(skip)]
phantom: PhantomData<T>,
}
impl<T> Visit for Resource<T>
where
T: ResourceData + TypeUuidProvider,
{
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region(name)?;
self.state.visit("State", &mut region)?;
if region.is_reading() {
// Try to restore the shallow handle.
let resource_manager = region
.blackboard
.get::<ResourceManager>()
.expect("Resource manager must be available when deserializing resources!");
let path = self.state.as_ref().unwrap().path();
// Procedural resources usually have path empty or use it as an id, in this case we need to
// check if the file actually exists to not mess up procedural resources.
if path.exists() {
self.state = Some(
resource_manager.request_untyped(path, <T as TypeUuidProvider>::type_uuid()),
);
}
}
Ok(())
}
}
impl<T> PartialEq for Resource<T>
where
T: ResourceData + TypeUuidProvider,
{
fn eq(&self, other: &Self) -> bool {
match (&self.state, &other.state) {
(Some(a), Some(b)) => a == b,
(None, None) => true,
_ => false,
}
}
}
impl<T> Eq for Resource<T> where T: ResourceData + TypeUuidProvider {}
impl<T> Hash for Resource<T>
where
T: ResourceData + TypeUuidProvider,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.state.hash(state)
}
}
impl<T> Resource<T>
where
T: ResourceData,
T: ResourceData + TypeUuidProvider,
{
pub fn new_pending(path: PathBuf) -> Self {
Self {
state: Some(UntypedResource::new_pending(path)),
state: Some(UntypedResource::new_pending(
path,
<T as TypeUuidProvider>::type_uuid(),
)),
phantom: PhantomData,
}
}
@@ -176,7 +266,11 @@ where
pub fn new_load_error(path: PathBuf, error: Option<Arc<dyn ResourceLoadError>>) -> Self {
Self {
state: Some(UntypedResource::new_load_error(path, error)),
state: Some(UntypedResource::new_load_error(
path,
error,
<T as TypeUuidProvider>::type_uuid(),
)),
phantom: PhantomData,
}
}
@@ -230,6 +324,10 @@ where
self.state.as_ref().unwrap().key()
}
pub fn path(&self) -> PathBuf {
self.state.as_ref().unwrap().0.lock().path().to_path_buf()
}
/// Allows you to obtain reference to the resource data.
///
/// # Panic
@@ -250,7 +348,7 @@ where
impl<T> Default for Resource<T>
where
T: ResourceData,
T: ResourceData + TypeUuidProvider,
{
#[inline]
fn default() -> Self {
@@ -263,7 +361,7 @@ where
impl<T> Clone for Resource<T>
where
T: ResourceData,
T: ResourceData + TypeUuidProvider,
{
#[inline]
fn clone(&self) -> Self {
@@ -276,7 +374,7 @@ where
impl<T> From<UntypedResource> for Resource<T>
where
T: ResourceData,
T: ResourceData + TypeUuidProvider,
{
#[inline]
fn from(state: UntypedResource) -> Self {
@@ -290,7 +388,7 @@ where
#[allow(clippy::from_over_into)]
impl<T> Into<UntypedResource> for Resource<T>
where
T: ResourceData,
T: ResourceData + TypeUuidProvider,
{
#[inline]
fn into(self) -> UntypedResource {
@@ -300,12 +398,12 @@ where
impl<T> Future for Resource<T>
where
T: ResourceData,
T: ResourceData + TypeUuidProvider,
{
type Output = Result<Self, Option<Arc<dyn ResourceLoadError>>>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let inner = self.state.as_ref().unwrap().clone();
let mut inner = self.state.as_ref().unwrap().clone();
std::pin::Pin::new(&mut inner)
.poll(cx)
.map(|r| r.map(|_| self.clone()))
@@ -315,7 +413,7 @@ where
#[doc(hidden)]
pub struct ResourceDataRef<'a, T>
where
T: ResourceData,
T: ResourceData + TypeUuidProvider,
{
guard: MutexGuard<'a, ResourceState>,
phantom: PhantomData<T>,
@@ -323,7 +421,7 @@ where
impl<'a, T> Debug for ResourceDataRef<'a, T>
where
T: ResourceData,
T: ResourceData + TypeUuidProvider,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match *self.guard {
@@ -348,7 +446,7 @@ where
impl<'a, T> Deref for ResourceDataRef<'a, T>
where
T: ResourceData,
T: ResourceData + TypeUuidProvider,
{
type Target = T;
@@ -373,7 +471,7 @@ where
impl<'a, T> DerefMut for ResourceDataRef<'a, T>
where
T: ResourceData,
T: ResourceData + TypeUuidProvider,
{
fn deref_mut(&mut self) -> &mut Self::Target {
match *self.guard {
@@ -395,53 +493,3 @@ where
}
}
}
/// Defines a new resource type via new-type wrapper.
#[macro_export]
macro_rules! define_new_resource {
($(#[$meta:meta])* $name:ident<$state:ty>) => {
$(#[$meta])*
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct $name(pub Resource<$state>);
impl Visit for $name {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
self.0.visit(name, visitor)
}
}
impl From<Resource<$state>> for $name {
fn from(resource: Resource<$state>) -> Self {
$name(resource)
}
}
impl std::ops::Deref for $name {
type Target = Resource<$state>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for $name {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl std::future::Future for $name {
type Output = Result<Self, Option<std::sync::Arc<dyn $crate::ResourceLoadError>>>;
fn poll(
mut self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
std::pin::Pin::new(&mut self.0)
.poll(cx)
.map(|r| r.map(|_| self.clone()))
}
}
};
}
+49 -25
View File
@@ -4,17 +4,19 @@ use crate::{
container::{Container, ResourceContainer},
state::ResourceState,
task::TaskPool,
Resource, ResourceData, ResourceLoadError, UntypedResource,
Resource, ResourceData, UntypedResource,
};
use fyrox_core::uuid::Uuid;
use fyrox_core::{
futures::future::join_all,
make_relative_path, notify,
parking_lot::{Mutex, MutexGuard},
watcher::FileSystemWatcher,
TypeUuidProvider,
};
use std::{
fmt::{Debug, Display, Formatter},
ops::Deref,
marker::PhantomData,
path::Path,
sync::Arc,
};
@@ -69,34 +71,30 @@ pub struct ResourceManager {
/// An error that may occur during texture registration.
#[derive(Debug)]
pub enum ResourceRegistrationError {
/// Texture saving has failed.
Texture(Arc<dyn ResourceLoadError>),
/// Texture was in invalid state (Pending, LoadErr)
/// Resource saving has failed.
UnableToRegister,
/// Resource was in invalid state (Pending, LoadErr)
InvalidState,
/// Texture is already registered.
/// Resource is already registered.
AlreadyRegistered,
}
impl Display for ResourceRegistrationError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ResourceRegistrationError::Texture(v) => Display::fmt(v, f),
ResourceRegistrationError::UnableToRegister => {
write!(f, "Unable to register the resource!")
}
ResourceRegistrationError::InvalidState => {
write!(f, "A texture was in invalid state!")
write!(f, "A resource was in invalid state!")
}
ResourceRegistrationError::AlreadyRegistered => {
write!(f, "A texture is already registered!")
write!(f, "A resource is already registered!")
}
}
}
}
impl From<Arc<dyn ResourceLoadError>> for ResourceRegistrationError {
fn from(e: Arc<dyn ResourceLoadError>) -> Self {
Self::Texture(e)
}
}
impl ResourceManager {
/// Creates a resource manager with default settings and loaders.
pub fn new() -> Self {
@@ -118,20 +116,46 @@ impl ResourceManager {
self.state.lock()
}
pub fn request<P: AsRef<Path>, T: Deref<Target = Resource<D>>, D: ResourceData>(
&self,
path: P,
) -> T {
self.state().containers_mut().resources.request(path)
pub fn request<T, P>(&self, path: P) -> Resource<T>
where
P: AsRef<Path>,
T: ResourceData + TypeUuidProvider,
{
let untyped = self
.state()
.containers_mut()
.resources
.request(path, <T as TypeUuidProvider>::type_uuid());
let actual_type_uuid = untyped.type_uuid();
assert_eq!(actual_type_uuid, <T as TypeUuidProvider>::type_uuid());
Resource {
state: Some(untyped),
phantom: PhantomData::<T>,
}
}
/// Saves given texture in the specified path and registers it in resource manager, so
pub fn request_untyped<P>(&self, path: P, type_uuid: Uuid) -> UntypedResource
where
P: AsRef<Path>,
{
self.state()
.containers_mut()
.resources
.request(path, type_uuid)
}
/// Saves given resources in the specified path and registers it in resource manager, so
/// it will be accessible through it later.
pub fn register<P: AsRef<Path>>(
pub fn register<P, F>(
&self,
resource: UntypedResource,
path: P,
) -> Result<(), ResourceRegistrationError> {
mut on_register: F,
) -> Result<(), ResourceRegistrationError>
where
P: AsRef<Path>,
F: FnMut(&dyn ResourceData, &Path) -> bool,
{
let mut state = self.state();
if state.containers().resources.find(path.as_ref()).is_some() {
Err(ResourceRegistrationError::AlreadyRegistered)
@@ -140,8 +164,8 @@ impl ResourceManager {
match &mut *texture_state {
ResourceState::Ok(data) => {
data.set_path(path.as_ref().to_path_buf());
if let Err(e) = data.save() {
Err(ResourceRegistrationError::Texture(e))
if !on_register(&**data, path.as_ref()) {
Err(ResourceRegistrationError::UnableToRegister)
} else {
std::mem::drop(texture_state);
state.containers_mut().resources.push(resource);
+51 -7
View File
@@ -57,6 +57,7 @@ pub enum ResourceState {
path: PathBuf,
/// List of wakers to wake future when resource is fully loaded.
wakers: Vec<Waker>,
type_uuid: Uuid,
},
/// An error has occurred during the load.
LoadError {
@@ -64,6 +65,7 @@ pub enum ResourceState {
path: PathBuf,
/// An error. This wrapped in Option only to be Default_ed.
error: Option<Arc<dyn ResourceLoadError>>,
type_uuid: Uuid,
},
/// Actual resource data when it is fully loaded.
Ok(Box<dyn ResourceData>),
@@ -82,13 +84,21 @@ impl Visit for ResourceState {
let mut path = PathBuf::new();
path.visit("Path", &mut region)?;
let mut type_uuid = Uuid::default();
let _ = type_uuid.visit("TypeUuid", &mut region);
*self = Self::Pending {
path,
wakers: Default::default(),
type_uuid,
};
Ok(())
} else if let Self::Pending { path, .. } = self {
} else if let Self::Pending {
path, type_uuid, ..
} = self
{
let _ = type_uuid.visit("TypeUuid", &mut region);
path.visit("Path", &mut region)
} else {
Err(VisitError::User("Enum variant mismatch!".to_string()))
@@ -99,10 +109,21 @@ impl Visit for ResourceState {
let mut path = PathBuf::new();
path.visit("Path", &mut region)?;
*self = Self::LoadError { path, error: None };
let mut type_uuid = Uuid::default();
let _ = type_uuid.visit("TypeUuid", &mut region);
*self = Self::LoadError {
path,
error: None,
type_uuid,
};
Ok(())
} else if let Self::LoadError { path, .. } = self {
} else if let Self::LoadError {
path, type_uuid, ..
} = self
{
let _ = type_uuid.visit("TypeUuid", &mut region);
path.visit("Path", &mut region)
} else {
Err(VisitError::User("Enum variant mismatch!".to_string()))
@@ -151,16 +172,25 @@ impl Visit for ResourceState {
impl ResourceState {
/// Creates new resource in pending state.
#[inline]
pub fn new_pending(path: PathBuf) -> Self {
pub fn new_pending(path: PathBuf, type_uuid: Uuid) -> Self {
Self::Pending {
path,
wakers: Default::default(),
type_uuid,
}
}
#[inline]
pub fn new_load_error(path: PathBuf, error: Option<Arc<dyn ResourceLoadError>>) -> Self {
Self::LoadError { path, error }
pub fn new_load_error(
path: PathBuf,
error: Option<Arc<dyn ResourceLoadError>>,
type_uuid: Uuid,
) -> Self {
Self::LoadError {
path,
error,
type_uuid,
}
}
#[inline]
@@ -175,22 +205,34 @@ impl ResourceState {
/// Switches the internal state of the resource to [`ResourceState::Pending`].
pub fn switch_to_pending_state(&mut self) {
match self {
ResourceState::LoadError { path, .. } => {
ResourceState::LoadError {
path, type_uuid, ..
} => {
*self = ResourceState::Pending {
path: std::mem::take(path),
wakers: Default::default(),
type_uuid: *type_uuid,
}
}
ResourceState::Ok(data) => {
*self = ResourceState::Pending {
path: data.path().to_path_buf(),
wakers: Default::default(),
type_uuid: data.type_uuid(),
}
}
_ => (),
}
}
pub fn type_uuid(&self) -> Uuid {
match self {
ResourceState::Pending { type_uuid, .. } => *type_uuid,
ResourceState::LoadError { type_uuid, .. } => *type_uuid,
ResourceState::Ok(data) => data.type_uuid(),
}
}
#[inline]
fn id(&self) -> u32 {
match self {
@@ -234,9 +276,11 @@ impl ResourceState {
/// Changes internal state to [`ResourceState::LoadError`].
pub fn commit_error<E: ResourceLoadError>(&mut self, path: PathBuf, error: E) {
let type_uuid = self.type_uuid();
self.commit(ResourceState::LoadError {
path,
error: Some(Arc::new(error)),
type_uuid,
})
}
}
+42 -7
View File
@@ -1,9 +1,10 @@
use crate::{state::ResourceState, ResourceData, ResourceLoadError};
use fyrox_core::{parking_lot::Mutex, visitor::prelude::*};
use crate::{state::ResourceState, Resource, ResourceData, ResourceLoadError};
use fyrox_core::{parking_lot::Mutex, uuid::Uuid, visitor::prelude::*, TypeUuidProvider};
use std::{
fmt::{Debug, Formatter},
future::Future,
hash::{Hash, Hasher},
marker::PhantomData,
path::PathBuf,
pin::Pin,
sync::Arc,
@@ -24,6 +25,7 @@ impl Default for UntypedResource {
fn default() -> Self {
Self(Arc::new(Mutex::new(ResourceState::new_pending(
Default::default(),
Default::default(),
))))
}
}
@@ -49,20 +51,30 @@ impl Hash for UntypedResource {
}
impl UntypedResource {
pub fn new_pending(path: PathBuf) -> Self {
Self(Arc::new(Mutex::new(ResourceState::new_pending(path))))
pub fn new_pending(path: PathBuf, type_uuid: Uuid) -> Self {
Self(Arc::new(Mutex::new(ResourceState::new_pending(
path, type_uuid,
))))
}
pub fn new_ok<T: ResourceData>(data: T) -> Self {
Self(Arc::new(Mutex::new(ResourceState::new_ok(data))))
}
pub fn new_load_error(path: PathBuf, error: Option<Arc<dyn ResourceLoadError>>) -> Self {
pub fn new_load_error(
path: PathBuf,
error: Option<Arc<dyn ResourceLoadError>>,
type_uuid: Uuid,
) -> Self {
Self(Arc::new(Mutex::new(ResourceState::new_load_error(
path, error,
path, error, type_uuid,
))))
}
pub fn type_uuid(&self) -> Uuid {
self.0.lock().type_uuid()
}
/// Returns true if the resource is still loading.
pub fn is_loading(&self) -> bool {
matches!(*self.0.lock(), ResourceState::Pending { .. })
@@ -79,6 +91,28 @@ impl UntypedResource {
pub fn key(&self) -> usize {
(&*self.0 as *const _) as usize
}
pub fn path(&self) -> PathBuf {
match &*self.0.lock() {
ResourceState::Pending { path, .. } => path.clone(),
ResourceState::LoadError { path, .. } => path.clone(),
ResourceState::Ok(data) => data.path().to_path_buf(),
}
}
pub fn try_cast<T>(&self) -> Option<Resource<T>>
where
T: ResourceData + TypeUuidProvider,
{
if self.type_uuid() == <T as TypeUuidProvider>::type_uuid() {
Some(Resource {
state: Some(self.clone()),
phantom: PhantomData::<T>,
})
} else {
None
}
}
}
impl Future for UntypedResource {
@@ -86,7 +120,8 @@ impl Future for UntypedResource {
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let state = self.0.clone();
match *state.lock() {
let mut guard = state.lock();
match *guard {
ResourceState::Pending { ref mut wakers, .. } => {
// Collect wakers, so we'll be able to wake task when worker thread finish loading.
let cx_waker = cx.waker();
+43 -40
View File
@@ -12,8 +12,8 @@ use crate::{
buffer::{generic::GenericBuffer, streaming::StreamingBuffer},
error::SoundError,
};
use fyrox_core::{io::FileLoadError, reflect::prelude::*, uuid::Uuid, visitor::prelude::*};
use fyrox_resource::{define_new_resource, Resource, ResourceData, SOUND_BUFFER_RESOURCE_UUID};
use fyrox_core::{io::FileLoadError, uuid::Uuid, visitor::prelude::*, TypeUuidProvider};
use fyrox_resource::{Resource, ResourceData, SOUND_BUFFER_RESOURCE_UUID};
use std::{
any::Any,
borrow::Cow,
@@ -162,34 +162,9 @@ pub enum SoundBufferResourceLoadError {
Io(FileLoadError),
}
define_new_resource!(
/// A shared sound buffer resource.
#[derive(Reflect)]
#[reflect(hide_all)]
SoundBufferResource<SoundBufferState>
);
impl SoundBufferResource {
/// Tries to create new streaming sound buffer from a given data source. Returns sound source
/// wrapped into Arc<Mutex<>> that can be directly used with sound sources.
pub fn new_streaming(data_source: DataSource) -> Result<Self, DataSource> {
Ok(Self(Resource::new_ok(SoundBufferState::Streaming(
StreamingBuffer::new(data_source)?,
))))
}
/// Tries to create new generic sound buffer from a given data source. Returns sound source
/// wrapped into Arc<Mutex<>> that can be directly used with sound sources.
pub fn new_generic(data_source: DataSource) -> Result<Self, DataSource> {
Ok(Self(Resource::new_ok(SoundBufferState::Generic(
GenericBuffer::new(data_source)?,
))))
}
}
/// Sound buffer is a data source for sound sources. See module documentation for more info.
#[derive(Debug, Visit)]
pub enum SoundBufferState {
pub enum SoundBuffer {
/// General-purpose buffer, usually contains all the data and allows random
/// access to samples. It is also used to make streaming buffer via composition.
Generic(GenericBuffer),
@@ -201,7 +176,15 @@ pub enum SoundBufferState {
Streaming(StreamingBuffer),
}
impl SoundBufferState {
pub type SoundBufferResource = Resource<SoundBuffer>;
impl TypeUuidProvider for SoundBuffer {
fn type_uuid() -> Uuid {
SOUND_BUFFER_RESOURCE_UUID
}
}
impl SoundBuffer {
/// Tries to create new streaming sound buffer from a given data source. It returns raw sound
/// buffer that has to be wrapped into Arc<Mutex<>> for use with sound sources.
pub fn raw_streaming(data_source: DataSource) -> Result<Self, DataSource> {
@@ -213,39 +196,59 @@ impl SoundBufferState {
pub fn raw_generic(data_source: DataSource) -> Result<Self, DataSource> {
Ok(Self::Generic(GenericBuffer::new(data_source)?))
}
}
impl Default for SoundBufferState {
fn default() -> Self {
SoundBufferState::Generic(Default::default())
/// Tries to create new streaming sound buffer from a given data source. Returns sound source
/// wrapped into Arc<Mutex<>> that can be directly used with sound sources.
pub fn new_streaming_resource(
data_source: DataSource,
) -> Result<Resource<SoundBuffer>, DataSource> {
Ok(Resource::new_ok(SoundBuffer::Streaming(
StreamingBuffer::new(data_source)?,
)))
}
/// Tries to create new generic sound buffer from a given data source. Returns sound source
/// wrapped into Arc<Mutex<>> that can be directly used with sound sources.
pub fn new_generic_resource(
data_source: DataSource,
) -> Result<Resource<SoundBuffer>, DataSource> {
Ok(Resource::new_ok(SoundBuffer::Generic(GenericBuffer::new(
data_source,
)?)))
}
}
impl Deref for SoundBufferState {
impl Default for SoundBuffer {
fn default() -> Self {
SoundBuffer::Generic(Default::default())
}
}
impl Deref for SoundBuffer {
type Target = GenericBuffer;
/// Returns shared reference to generic buffer for any enum variant. It is possible because
/// streaming sound buffers are built on top of generic buffers.
fn deref(&self) -> &Self::Target {
match self {
SoundBufferState::Generic(v) => v,
SoundBufferState::Streaming(v) => v,
SoundBuffer::Generic(v) => v,
SoundBuffer::Streaming(v) => v,
}
}
}
impl DerefMut for SoundBufferState {
impl DerefMut for SoundBuffer {
/// Returns mutable reference to generic buffer for any enum variant. It is possible because
/// streaming sound buffers are built on top of generic buffers.
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
SoundBufferState::Generic(v) => v,
SoundBufferState::Streaming(v) => v,
SoundBuffer::Generic(v) => v,
SoundBuffer::Streaming(v) => v,
}
}
}
impl ResourceData for SoundBufferState {
impl ResourceData for SoundBuffer {
fn path(&self) -> Cow<Path> {
Cow::from(&self.external_source_path)
}
+12 -16
View File
@@ -29,7 +29,7 @@
#![allow(clippy::float_cmp)]
use crate::{
buffer::{streaming::StreamingBuffer, SoundBufferResource, SoundBufferState},
buffer::{streaming::StreamingBuffer, SoundBuffer, SoundBufferResource},
bus::AudioBusGraph,
context::DistanceModel,
error::SoundError,
@@ -210,7 +210,7 @@ impl SoundSource {
// If we already have streaming buffer assigned make sure to decrease use count
// so it can be reused later on if needed.
if let Some(buffer) = self.buffer.clone() {
if let SoundBufferState::Streaming(ref mut streaming) = *buffer.data_ref() {
if let SoundBuffer::Streaming(ref mut streaming) = *buffer.data_ref() {
streaming.use_count = streaming.use_count.saturating_sub(1);
}
}
@@ -222,7 +222,7 @@ impl SoundSource {
}
ResourceStateRefMut::Ok(locked_buffer) => {
// Check new buffer if streaming - it must not be used by anyone else.
if let SoundBufferState::Streaming(ref mut streaming) = *locked_buffer {
if let SoundBuffer::Streaming(ref mut streaming) = *locked_buffer {
if streaming.use_count != 0 {
return Err(SoundError::StreamingBufferAlreadyInUse);
}
@@ -340,7 +340,7 @@ impl SoundSource {
if let Some(buffer) = self.buffer.as_ref() {
let mut buffer = buffer.data_ref();
if let SoundBufferState::Streaming(ref mut streaming) = *buffer {
if let SoundBuffer::Streaming(ref mut streaming) = *buffer {
streaming.rewind()?;
}
}
@@ -464,7 +464,7 @@ impl SoundSource {
pub fn set_playback_time(&mut self, time: Duration) {
if let Some(buffer) = self.buffer.as_ref() {
let mut buffer = buffer.data_ref();
if let SoundBufferState::Streaming(ref mut streaming) = *buffer {
if let SoundBuffer::Streaming(ref mut streaming) = *buffer {
// Make sure decoder is at right position.
streaming.time_seek(time);
}
@@ -472,14 +472,14 @@ impl SoundSource {
self.playback_pos = time.as_secs_f64() * buffer.sample_rate as f64;
// Then adjust buffer read position.
self.buf_read_pos = match *buffer {
SoundBufferState::Streaming(ref mut streaming) => {
SoundBuffer::Streaming(ref mut streaming) => {
// Make sure to load correct data into buffer from decoder.
streaming.read_next_block();
// Streaming sources has different buffer read position because
// buffer contains only small portion of data.
self.playback_pos % (StreamingBuffer::STREAM_SAMPLE_COUNT as f64)
}
SoundBufferState::Generic(_) => self.playback_pos,
SoundBuffer::Generic(_) => self.playback_pos,
};
assert!(
self.buf_read_pos * (buffer.channel_count() as f64) < buffer.samples().len() as f64
@@ -506,7 +506,7 @@ impl SoundSource {
self.frame_samples.resize(amount, (0.0, 0.0));
}
fn render_playing(&mut self, buffer: &mut SoundBufferState, amount: usize) {
fn render_playing(&mut self, buffer: &mut SoundBuffer, amount: usize) {
let mut count = 0;
loop {
count += self.render_until_block_end(buffer, amount - count);
@@ -517,7 +517,7 @@ impl SoundSource {
let channel_count = buffer.channel_count();
let len = buffer.samples().len();
let mut end_reached = true;
if let SoundBufferState::Streaming(streaming) = buffer {
if let SoundBuffer::Streaming(streaming) = buffer {
// Means that this is the last available block.
if len != channel_count * StreamingBuffer::STREAM_SAMPLE_COUNT {
let _ = streaming.rewind();
@@ -542,11 +542,7 @@ impl SoundSource {
// Renders until the end of the block or until amount samples is written and returns
// the number of written samples.
fn render_until_block_end(
&mut self,
buffer: &mut SoundBufferState,
mut amount: usize,
) -> usize {
fn render_until_block_end(&mut self, buffer: &mut SoundBuffer, mut amount: usize) -> usize {
let step = self.pitch * self.resampling_multiplier;
if step == 1.0 {
if self.buf_read_pos < 0.0 {
@@ -581,7 +577,7 @@ impl SoundSource {
// Does linear resampling while rendering until the end of the block.
fn render_until_block_end_resample(
&mut self,
buffer: &mut SoundBufferState,
buffer: &mut SoundBuffer,
amount: usize,
step: f64,
) -> usize {
@@ -675,7 +671,7 @@ impl Drop for SoundSource {
fn drop(&mut self) {
if let Some(buffer) = self.buffer.as_ref() {
let mut buffer = buffer.data_ref();
if let SoundBufferState::Streaming(ref mut streaming) = *buffer {
if let SoundBuffer::Streaming(ref mut streaming) = *buffer {
streaming.use_count = streaming.use_count.saturating_sub(1);
}
}
+6 -6
View File
@@ -6,7 +6,7 @@
use crate::{
animation::spritesheet::signal::Signal,
core::{algebra::Vector2, math::Rect, reflect::prelude::*, visitor::prelude::*},
resource::texture::Texture,
resource::texture::TextureResource,
};
use std::collections::vec_deque::VecDeque;
use strum_macros::{AsRefStr, EnumString, EnumVariantNames};
@@ -55,7 +55,7 @@ pub struct SpriteSheetFramesContainer {
size: Vector2<u32>,
frames: Vec<Vector2<u32>>,
#[visit(optional)]
texture: Option<Texture>,
texture: Option<TextureResource>,
}
impl SpriteSheetFramesContainer {
@@ -112,7 +112,7 @@ impl SpriteSheetFramesContainer {
}
/// Returns current texture of the container. To set a texture use sprite sheet animation methods.
pub fn texture(&self) -> Option<Texture> {
pub fn texture(&self) -> Option<TextureResource> {
self.texture.clone()
}
}
@@ -140,7 +140,7 @@ pub struct SpriteSheetAnimation {
signals: Vec<Signal>,
#[visit(optional)]
#[reflect(setter = "set_texture")]
texture: Option<Texture>,
texture: Option<TextureResource>,
#[reflect(hidden)]
#[visit(skip)]
events: VecDeque<Event>,
@@ -305,13 +305,13 @@ impl SpriteSheetAnimation {
}
/// Sets new texture for the animation.
pub fn set_texture(&mut self, texture: Option<Texture>) -> Option<Texture> {
pub fn set_texture(&mut self, texture: Option<TextureResource>) -> Option<TextureResource> {
self.frames_container.texture = texture.clone();
std::mem::replace(&mut self.texture, texture)
}
/// Returns current texture of the animation.
pub fn texture(&self) -> Option<Texture> {
pub fn texture(&self) -> Option<TextureResource> {
self.texture.clone()
}
+3 -3
View File
@@ -1,10 +1,10 @@
//! Executor is a small wrapper that manages plugins and scripts for your game.
use crate::{
asset::manager::ResourceManager,
core::instant::Instant,
engine::{
resource_manager::ResourceManager, Engine, EngineInitParams, GraphicsContext,
GraphicsContextParams, SerializationContext,
Engine, EngineInitParams, GraphicsContext, GraphicsContextParams, SerializationContext,
},
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
@@ -71,7 +71,7 @@ impl Executor {
let serialization_context = Arc::new(SerializationContext::new());
let engine = Engine::new(EngineInitParams {
graphics_context_params,
resource_manager: ResourceManager::new(serialization_context.clone()),
resource_manager: ResourceManager::new(),
serialization_context,
})
.unwrap();
+39 -34
View File
@@ -7,18 +7,19 @@ pub mod error;
pub mod executor;
pub mod resource_loaders;
use crate::resource::model::Model;
use crate::{
core::{algebra::Vector2, futures::executor::block_on, instant, pool::Handle},
engine::{
error::EngineError,
resource_manager::{container::event::ResourceEvent, ResourceManager, ResourceWaitContext},
asset::{
container::event::ResourceEvent, manager::ResourceManager, manager::ResourceWaitContext,
},
core::{algebra::Vector2, futures::executor::block_on, instant, pool::Handle},
engine::error::EngineError,
event::Event,
event_loop::ControlFlow,
gui::UserInterface,
plugin::{Plugin, PluginConstructor, PluginContext, PluginRegistrationContext},
renderer::{framework::error::FrameworkError, Renderer},
resource::{model::Model, texture::TextureKind},
resource::{model::ModelResource, texture::TextureKind},
scene::{
base::NodeScriptMessage,
graph::GraphUpdateSwitches,
@@ -198,7 +199,7 @@ pub struct Engine {
performance_statistics: PerformanceStatistics,
model_events_receiver: Receiver<ResourceEvent<Model>>,
model_events_receiver: Receiver<ResourceEvent>,
#[allow(dead_code)] // Keep engine instance alive.
sound_engine: SoundEngine,
@@ -605,26 +606,28 @@ impl ScriptProcessor {
}
struct ResourceGraphVertex {
resource: Model,
resource: ModelResource,
children: Vec<ResourceGraphVertex>,
}
impl ResourceGraphVertex {
pub fn new(model: Model, resource_manager: ResourceManager) -> Self {
pub fn new(model: ModelResource, resource_manager: ResourceManager) -> Self {
let mut children = Vec::new();
// Look for dependent resources.
let mut dependent_resources = HashSet::new();
for other_model in resource_manager.state().containers().models.iter() {
let state = other_model.state();
if let ResourceStateRef::Ok(model_data) = state.get() {
if model_data
.get_scene()
.graph
.linear_iter()
.any(|n| n.resource.as_ref().map_or(false, |r| r == &model))
{
dependent_resources.insert(other_model.clone());
for resource in resource_manager.state().containers().resources.iter() {
if let Some(other_model) = resource.try_cast::<Model>() {
let mut state = other_model.state();
if let ResourceStateRef::Ok(model_data) = state.get() {
if model_data
.get_scene()
.graph
.linear_iter()
.any(|n| n.resource.as_ref().map_or(false, |r| r == &model))
{
dependent_resources.insert(other_model.clone());
}
}
}
}
@@ -644,7 +647,7 @@ impl ResourceGraphVertex {
pub fn resolve(&self) {
Log::info(format!(
"Resolving {} resource from dependency graph...",
self.resource.state().path().display()
self.resource.path().display()
));
// Wait until resource is fully loaded, then resolve.
@@ -663,7 +666,7 @@ struct ResourceDependencyGraph {
}
impl ResourceDependencyGraph {
pub fn new(model: Model, resource_manager: ResourceManager) -> Self {
pub fn new(model: ModelResource, resource_manager: ResourceManager) -> Self {
Self {
root: ResourceGraphVertex::new(model, resource_manager),
}
@@ -828,7 +831,7 @@ impl Engine {
resource_manager
.state()
.containers_mut()
.models
.resources
.event_broadcaster
.add(rx);
@@ -1362,22 +1365,24 @@ impl Engine {
/// You should only call this manually if you don't use that method.
pub fn handle_model_events(&mut self) {
while let Ok(event) = self.model_events_receiver.try_recv() {
if let ResourceEvent::Reloaded(model) = event {
Log::info(format!(
"A model resource {} was reloaded, propagating changes...",
model.state().path().display()
));
if let ResourceEvent::Reloaded(resource) = event {
if let Some(model) = resource.try_cast::<Model>() {
Log::info(format!(
"A model resource {} was reloaded, propagating changes...",
model.path().display()
));
// Build resource dependency graph and resolve it first.
ResourceDependencyGraph::new(model, self.resource_manager.clone()).resolve();
// Build resource dependency graph and resolve it first.
ResourceDependencyGraph::new(model, self.resource_manager.clone()).resolve();
Log::info("Propagating changes to active scenes...");
Log::info("Propagating changes to active scenes...");
// Resolve all scenes.
// TODO: This might be inefficient if there is bunch of scenes loaded,
// however this seems to be very rare case so it should be ok.
for scene in self.scenes.iter_mut() {
scene.resolve();
// Resolve all scenes.
// TODO: This might be inefficient if there is bunch of scenes loaded,
// however this seems to be very rare case so it should be ok.
for scene in self.scenes.iter_mut() {
scene.resolve();
}
}
}
}
+8 -8
View File
@@ -5,29 +5,29 @@ use crate::{
container::event::ResourceEventBroadcaster,
loader::{BoxedLoaderFuture, ResourceLoader},
},
resource::curve::{CurveImportOptions, CurveResource, CurveResourceState},
resource::curve::CurveResourceState,
utils::log::Log,
};
use fyrox_resource::untyped::UntypedResource;
/// Default implementation for curve loading.
pub struct CurveLoader;
impl ResourceLoader<CurveResource, CurveImportOptions> for CurveLoader {
impl ResourceLoader for CurveLoader {
fn load(
&self,
curve: CurveResource,
_default_import_options: CurveImportOptions,
event_broadcaster: ResourceEventBroadcaster<CurveResource>,
curve: UntypedResource,
event_broadcaster: ResourceEventBroadcaster,
reload: bool,
) -> BoxedLoaderFuture {
Box::pin(async move {
let path = curve.state().path().to_path_buf();
let path = curve.0.lock().path().to_path_buf();
match CurveResourceState::from_file(&path).await {
Ok(curve_state) => {
Log::info(format!("Curve {:?} is loaded!", path));
curve.state().commit_ok(curve_state);
curve.0.lock().commit_ok(curve_state);
event_broadcaster.broadcast_loaded_or_reloaded(curve, reload);
}
@@ -37,7 +37,7 @@ impl ResourceLoader<CurveResource, CurveImportOptions> for CurveLoader {
path, error
));
curve.state().commit_error(path, error);
curve.0.lock().commit_error(path, error);
}
}
})
+11 -10
View File
@@ -8,9 +8,10 @@ use crate::{
options::try_get_import_settings,
},
engine::SerializationContext,
resource::model::{Model, ModelData, ModelImportOptions},
resource::model::{Model, ModelImportOptions},
utils::log::Log,
};
use fyrox_resource::untyped::UntypedResource;
use std::sync::Arc;
/// Default implementation for model loading.
@@ -20,32 +21,32 @@ pub struct ModelLoader {
/// Node constructors contains a set of constructors that allows to build a node using its
/// type UUID.
pub serialization_context: Arc<SerializationContext>,
pub default_import_options: ModelImportOptions,
}
impl ResourceLoader<Model, ModelImportOptions> for ModelLoader {
impl ResourceLoader for ModelLoader {
fn load(
&self,
model: Model,
default_import_options: ModelImportOptions,
event_broadcaster: ResourceEventBroadcaster<Model>,
model: UntypedResource,
event_broadcaster: ResourceEventBroadcaster,
reload: bool,
) -> BoxedLoaderFuture {
let resource_manager = self.resource_manager.clone();
let node_constructors = self.serialization_context.clone();
let default_import_options = self.default_import_options.clone();
Box::pin(async move {
let path = model.state().path().to_path_buf();
let path = model.path().to_path_buf();
let import_options = try_get_import_settings(&path)
.await
.unwrap_or(default_import_options);
match ModelData::load(&path, node_constructors, resource_manager, import_options).await
{
match Model::load(&path, node_constructors, resource_manager, import_options).await {
Ok(raw_model) => {
Log::info(format!("Model {:?} is loaded!", path));
model.state().commit_ok(raw_model);
model.0.lock().commit_ok(raw_model);
event_broadcaster.broadcast_loaded_or_reloaded(model, reload);
}
@@ -55,7 +56,7 @@ impl ResourceLoader<Model, ModelImportOptions> for ModelLoader {
path, error
));
model.state().commit_error(path, error);
model.0.lock().commit_error(path, error);
}
}
})
+9 -9
View File
@@ -5,29 +5,29 @@ use crate::{
container::event::ResourceEventBroadcaster,
loader::{BoxedLoaderFuture, ResourceLoader},
},
material::shader::{Shader, ShaderImportOptions, ShaderState},
material::shader::Shader,
utils::log::Log,
};
use fyrox_resource::untyped::UntypedResource;
/// Default implementation for shader loading.
pub struct ShaderLoader;
impl ResourceLoader<Shader, ShaderImportOptions> for ShaderLoader {
impl ResourceLoader for ShaderLoader {
fn load(
&self,
shader: Shader,
_default_import_options: ShaderImportOptions,
event_broadcaster: ResourceEventBroadcaster<Shader>,
shader: UntypedResource,
event_broadcaster: ResourceEventBroadcaster,
reload: bool,
) -> BoxedLoaderFuture {
Box::pin(async move {
let path = shader.state().path().to_path_buf();
let path = shader.path().to_path_buf();
match ShaderState::from_file(&path).await {
match Shader::from_file(&path).await {
Ok(shader_state) => {
Log::info(format!("Shader {:?} is loaded!", path));
shader.state().commit_ok(shader_state);
shader.0.lock().commit_ok(shader_state);
event_broadcaster.broadcast_loaded_or_reloaded(shader, reload);
}
@@ -37,7 +37,7 @@ impl ResourceLoader<Shader, ShaderImportOptions> for ShaderLoader {
path, error
));
shader.state().commit_error(path, error);
shader.0.lock().commit_error(path, error);
}
}
})
+17 -14
View File
@@ -9,9 +9,8 @@ use crate::{
core::reflect::prelude::*,
utils::log::Log,
};
use fyrox_sound::buffer::{
DataSource, SoundBufferResource, SoundBufferResourceLoadError, SoundBufferState,
};
use fyrox_resource::untyped::UntypedResource;
use fyrox_sound::buffer::{DataSource, SoundBuffer, SoundBufferResourceLoadError};
use serde::{Deserialize, Serialize};
/// Defines sound buffer resource import options.
@@ -24,18 +23,21 @@ pub struct SoundBufferImportOptions {
impl ImportOptions for SoundBufferImportOptions {}
/// Default implementation for sound buffer loading.
pub struct SoundBufferLoader;
pub struct SoundBufferLoader {
pub default_import_options: SoundBufferImportOptions,
}
impl ResourceLoader<SoundBufferResource, SoundBufferImportOptions> for SoundBufferLoader {
impl ResourceLoader for SoundBufferLoader {
fn load(
&self,
resource: SoundBufferResource,
default_import_options: SoundBufferImportOptions,
event_broadcaster: ResourceEventBroadcaster<SoundBufferResource>,
resource: UntypedResource,
event_broadcaster: ResourceEventBroadcaster,
reload: bool,
) -> BoxedLoaderFuture {
let default_import_options = self.default_import_options.clone();
Box::pin(async move {
let path = resource.state().path().to_path_buf();
let path = resource.path().to_path_buf();
let import_options = try_get_import_settings(&path)
.await
@@ -44,20 +46,20 @@ impl ResourceLoader<SoundBufferResource, SoundBufferImportOptions> for SoundBuff
match DataSource::from_file(&path).await {
Ok(source) => {
let buffer = if import_options.stream {
SoundBufferState::raw_streaming(source)
SoundBuffer::raw_streaming(source)
} else {
SoundBufferState::raw_generic(source)
SoundBuffer::raw_generic(source)
};
match buffer {
Ok(sound_buffer) => {
resource.state().commit_ok(sound_buffer);
resource.0.lock().commit_ok(sound_buffer);
event_broadcaster.broadcast_loaded_or_reloaded(resource, reload);
Log::info(format!("Sound buffer {:?} is loaded!", path));
}
Err(_) => {
resource.state().commit_error(
resource.0.lock().commit_error(
path.clone(),
SoundBufferResourceLoadError::UnsupportedFormat,
);
@@ -70,7 +72,8 @@ impl ResourceLoader<SoundBufferResource, SoundBufferImportOptions> for SoundBuff
Log::err(format!("Invalid data source for sound buffer: {:?}", e));
resource
.state()
.0
.lock()
.commit_error(path.clone(), SoundBufferResourceLoadError::Io(e));
}
}
+14 -11
View File
@@ -7,23 +7,27 @@ use crate::{
options::try_get_import_settings,
},
core::instant,
resource::texture::{Texture, TextureData, TextureImportOptions},
resource::texture::{Texture, TextureImportOptions},
utils::log::Log,
};
use fyrox_resource::untyped::UntypedResource;
/// Default implementation for texture loading.
pub struct TextureLoader;
pub struct TextureLoader {
pub default_import_options: TextureImportOptions,
}
impl ResourceLoader<Texture, TextureImportOptions> for TextureLoader {
impl ResourceLoader for TextureLoader {
fn load(
&self,
texture: Texture,
default_import_options: TextureImportOptions,
event_broadcaster: ResourceEventBroadcaster<Texture>,
texture: UntypedResource,
event_broadcaster: ResourceEventBroadcaster,
reload: bool,
) -> BoxedLoaderFuture {
let default_import_options = self.default_import_options.clone();
Box::pin(async move {
let path = texture.state().path().to_path_buf();
let path = texture.path().to_path_buf();
let import_options = try_get_import_settings(&path)
.await
@@ -32,8 +36,7 @@ impl ResourceLoader<Texture, TextureImportOptions> for TextureLoader {
let gen_mip_maps = import_options.minification_filter.is_using_mip_mapping();
let time = instant::Instant::now();
match TextureData::load_from_file(&path, import_options.compression, gen_mip_maps).await
{
match Texture::load_from_file(&path, import_options.compression, gen_mip_maps).await {
Ok(mut raw_texture) => {
Log::info(format!(
"Texture {:?} is loaded in {:?}!",
@@ -47,7 +50,7 @@ impl ResourceLoader<Texture, TextureImportOptions> for TextureLoader {
raw_texture.set_s_wrap_mode(import_options.s_wrap_mode);
raw_texture.set_t_wrap_mode(import_options.t_wrap_mode);
texture.state().commit_ok(raw_texture);
texture.0.lock().commit_ok(raw_texture);
event_broadcaster.broadcast_loaded_or_reloaded(texture, reload);
}
@@ -57,7 +60,7 @@ impl ResourceLoader<Texture, TextureImportOptions> for TextureLoader {
&path, &error
));
texture.state().commit_error(path, error);
texture.0.lock().commit_error(path, error);
}
}
})
+17 -13
View File
@@ -4,7 +4,10 @@
#![warn(missing_docs)]
use crate::material::shader::ShaderResourceExtension;
use crate::resource::texture::Texture;
use crate::{
asset::manager::ResourceManager,
core::{
algebra::{Matrix2, Matrix3, Matrix4, Vector2, Vector3, Vector4},
color::Color,
@@ -13,9 +16,8 @@ use crate::{
sstorage::ImmutableString,
visitor::prelude::*,
},
engine::resource_manager::ResourceManager,
material::shader::{PropertyKind, SamplerFallback, Shader},
resource::texture::Texture,
material::shader::{PropertyKind, SamplerFallback, ShaderResource},
resource::texture::TextureResource,
};
use fxhash::FxHashMap;
use std::{
@@ -118,7 +120,7 @@ pub enum PropertyValue {
/// missing by very specific value in the fallback texture.
Sampler {
/// Actual value of the sampler. Could be [`None`], in this case `fallback` will be used.
value: Option<Texture>,
value: Option<TextureResource>,
/// Sampler fallback value.
fallback: SamplerFallback,
@@ -234,7 +236,7 @@ impl PropertyValue {
);
/// Tries to unwrap property value as texture.
pub fn as_sampler(&self) -> Option<Texture> {
pub fn as_sampler(&self) -> Option<TextureResource> {
if let PropertyValue::Sampler { value, .. } = self {
value.clone()
} else {
@@ -286,7 +288,7 @@ impl Default for PropertyValue {
///
/// ```no_run
/// use fyrox::{
/// material::shader::{Shader, SamplerFallback},
/// material::shader::{ShaderResource, SamplerFallback},
/// engine::resource_manager::ResourceManager,
/// material::{Material, PropertyValue},
/// core::sstorage::ImmutableString,
@@ -345,7 +347,7 @@ impl Default for PropertyValue {
/// material instance. Then we populate properties as usual.
#[derive(Default, Debug, Visit, Clone, Reflect)]
pub struct Material {
shader: Shader,
shader: ShaderResource,
properties: FxHashMap<ImmutableString, PropertyValue>,
}
@@ -398,7 +400,7 @@ impl Material {
///
/// ```no_run
/// use fyrox::{
/// material::shader::{Shader, SamplerFallback},
/// material::shader::{ShaderResource, SamplerFallback},
/// engine::resource_manager::ResourceManager,
/// material::{Material, PropertyValue},
/// core::sstorage::ImmutableString
@@ -419,12 +421,12 @@ impl Material {
/// }
/// ```
pub fn standard() -> Self {
Self::from_shader(Shader::standard(), None)
Self::from_shader(ShaderResource::standard(), None)
}
/// Creates new instance of standard terrain material.
pub fn standard_terrain() -> Self {
Self::from_shader(Shader::standard_terrain(), None)
Self::from_shader(ShaderResource::standard_terrain(), None)
}
/// Creates a new material instance with given shader. Each property will have default values
@@ -459,7 +461,7 @@ impl Material {
/// material
/// }
/// ```
pub fn from_shader(shader: Shader, resource_manager: Option<ResourceManager>) -> Self {
pub fn from_shader(shader: ShaderResource, resource_manager: Option<ResourceManager>) -> Self {
let data = shader.data_ref();
let mut property_values = FxHashMap::default();
@@ -483,7 +485,9 @@ impl Material {
fallback: usage,
} => PropertyValue::Sampler {
value: default.as_ref().and_then(|path| {
resource_manager.clone().map(|rm| rm.request_texture(path))
resource_manager
.clone()
.map(|rm| rm.request::<Texture, _>(path))
}),
fallback: *usage,
},
@@ -644,7 +648,7 @@ impl Material {
}
/// Returns a reference to current shader.
pub fn shader(&self) -> &Shader {
pub fn shader(&self) -> &ShaderResource {
&self.shader
}
+291 -259
View File
@@ -1,9 +1,232 @@
//! Shader is a script for graphics card. This module contains everything related to shaders.
//!
//! For more info see [`Shader`] struct docs.
//! Shader is a script for graphics adapter, it defines how to draw an object.
//!
//! # Structure
//!
//! Shader has rigid structure that could be described in this code snipped:
//!
//! ```ron
//! (
//! // A set of properties, there could be any amount of properties.
//! properties: [
//! (
//! // Each property must have a name. This name must match with respective
//! // uniforms! That's is the whole point of having properties.
//! name: "diffuseTexture",
//!
//! // Value has limited set of possible variants.
//! value: Sampler(default: None, fallback: White)
//! )
//! ],
//!
//! // A set of render passes (see a section `Render pass` for more info)
//! passes: [
//! (
//! // Name must match with the name of either standard render pass (see below) or
//! // one of your passes.
//! name: "Forward",
//!
//! // A set of parameters that regulate renderer pipeline state.
//! // This is mandatory field of each render pass.
//! draw_parameters: DrawParameters(
//! // A face to cull. Either Front or Back.
//! cull_face: Some(Back),
//!
//! // Color mask. Defines which colors should be written to render target.
//! color_write: ColorMask(
//! red: true,
//! green: true,
//! blue: true,
//! alpha: true,
//! ),
//!
//! // Whether to modify depth buffer or not.
//! depth_write: true,
//!
//! // Whether to use stencil test or not.
//! stencil_test: None,
//!
//! // Whether to perform depth test when drawing.
//! depth_test: true,
//!
//! // Blending options.
//! blend: Some(BlendParameters(
//! func: BlendFunc(
//! sfactor: SrcAlpha,
//! dfactor: OneMinusSrcAlpha,
//! alpha_sfactor: SrcAlpha,
//! alpha_dfactor: OneMinusSrcAlpha,
//! ),
//! equation: BlendEquation(
//! rgb: Add,
//! alpha: Add
//! )
//! )),
//!
//! // Stencil options.
//! stencil_op: StencilOp(
//! fail: Keep,
//! zfail: Keep,
//! zpass: Keep,
//! write_mask: 0xFFFF_FFFF,
//! ),
//! ),
//!
//! // Vertex shader code.
//! vertex_shader:
//! r#"
//! #version 330 core
//!
//! layout(location = 0) in vec3 vertexPosition;
//! layout(location = 1) in vec2 vertexTexCoord;
//!
//! uniform mat4 fyrox_worldViewProjection;
//!
//! out vec2 texCoord;
//!
//! void main()
//! {
//! texCoord = vertexTexCoord;
//! gl_Position = fyrox_worldViewProjection * vertexPosition;
//! }
//! "#;
//!
//! // Pixel shader code.
//! pixel_shader:
//! r#"
//! #version 330 core
//!
//! // Note that the name of this uniform match the name of the property up above.
//! uniform sampler2D diffuseTexture;
//!
//! out vec4 FragColor;
//!
//! in vec2 texCoord;
//!
//! void main()
//! {
//! FragColor = diffuseColor * texture(diffuseTexture, texCoord);
//! }
//! "#;
//! )
//! ],
//! )
//! ```
//!
//! Shader should contain at least one render pass to actually do some job. A shader could not
//! have properties at all. Currently only vertex and fragment programs are supported. Each
//! program mush be written in GLSL. Comprehensive GLSL documentation can be found
//! [here](https://www.khronos.org/opengl/wiki/Core_Language_(GLSL))
//!
//! # Render pass
//!
//! Modern rendering is a very complex thing that requires drawing an object multiple times
//! with different "scripts". For example to draw an object with shadows you need to draw an
//! object twice: one directly in a render target, and one in a shadow map. Such stages called
//! render passes.
//!
//! Binding of shaders to render passes is done via names, each render pass has unique name.
//!
//! ## Predefined passes
//!
//! There are number of predefined render passes:
//!
//! - GBuffer - A pass that fills a set of render target sized textures with various data
//! about each rendered object. These textures then are used for physically-based lighting.
//! Use this pass when you want the standard lighting to work with your objects.
//!
//! - Forward - A pass that draws an object directly in render target. This pass is very
//! limiting, it does not support lighting, shadows, etc. It should be only used to render
//! translucent objects.
//!
//! - SpotShadow - A pass that emits depth values for an object, later this depth map will be
//! used to render shadows.
//!
//! - PointShadow - A pass that emits distance from a fragment to a point light, later this depth
//! map will be used to render shadows.
//!
//! # Built-in variables
//!
//! There are number of build-in variables that Fyrox pass to each shader automatically:
//!
//! | Name | Type | Description
//! |---------------------------|-----------------|--------------------------------------------
//! | fyrox_worldMatrix | `Matrix4` | Local-to-world transformation.
//! | fyrox_worldViewProjection | `Matrix4` | Local-to-clip-space transform.
//! | fyrox_boneMatrices | `[Matrix4; 60]` | Array of bone matrices.
//! | fyrox_useSkeletalAnimation | `Vector3` | Whether skinned meshes is rendering or not.
//! | fyrox_cameraPosition | `Vector3` | Position of the camera.
//! | fyrox_usePOM | `bool` | Whether to use parallax mapping or not.
//! | fyrox_lightPosition | `Vector3` | Light position.
//!
//! To use any of the variables, just define a uniform with appropriate name:
//!
//! ```glsl
//! uniform mat4 fyrox_worldMatrix;
//! uniform vec3 fyrox_cameraPosition;
//! ```
//!
//! This list will be extended in future releases.
//!
//! # Drawing parameters
//!
//! Drawing parameters defines which GPU functions to use and at which state. For example, to render
//! transparent objects you need to enable blending with specific blending rules. Or you need to disable
//! culling to draw objects from both sides. This is when draw parameters comes in handy.
//!
//! There are relatively large list of drawing parameters and it could confuse a person who didn't get
//! used to work with graphics. The following list should help you to use drawing parameters correctly.
//!
//! - cull_face
//! - Defines which side of polygon should be culled.
//! - **Possible values:** `None`, [Some(CullFace::XXX)](crate::renderer::framework::state::CullFace)
//!
//! - color_write:
//! - Defines which components of color should be written to a render target
//! - **Possible values:** [ColorMask](crate::renderer::framework::state::ColorMask)(...)
//!
//! - depth_write:
//! - Whether to modify depth buffer or not.
//! - **Possible values:** `true/false`
//!
//! - stencil_test:
//! - Whether to use stencil test or not.
//! - **Possible values:**
//! - `None`
//! - Some([StencilFunc](crate::renderer::framework::state::StencilFunc))
//!
//! - depth_test:
//! - Whether to perform depth test when drawing.
//! - **Possible values:** `true/false`
//!
//! - blend:
//! - Blending options.
//! - **Possible values:**
//! - `None`
//! - Some([BlendFunc](crate::renderer::framework::state::BlendFunc))
//!
//! - stencil_op:
//! - Stencil options.
//! - **Possible values:** [StencilOp](crate::renderer::framework::state::StencilOp)
//!
//! # Standard shader
//!
//! By default Fyrox uses standard material for rendering, it covers 95% of uses cases and it is very
//! flexible. To get standard shader instance, use [`ShaderResource::standard`]
//!
//! ```no_run
//! # use fyrox::material::shader::ShaderResource;
//!
//! let standard_shader = ShaderResource::standard();
//! ```
//!
//! Usually you don't need to get this shader manually, using of [Material::standard](super::Material::standard)
//! is enough.
use crate::{
asset::{define_new_resource, Resource, ResourceData},
asset::options::ImportOptions,
asset::{Resource, ResourceData},
core::{
algebra::{Matrix2, Matrix3, Matrix4, Vector2, Vector3, Vector4},
io::{self, FileLoadError},
@@ -11,11 +234,14 @@ use crate::{
sparse::AtomicIndex,
visitor::prelude::*,
},
engine::resource_manager::options::ImportOptions,
lazy_static::lazy_static,
renderer::framework::framebuffer::DrawParameters,
};
use fyrox_core::uuid::Uuid;
use fyrox_core::TypeUuidProvider;
use fyrox_resource::SHADER_RESOURCE_UUID;
use serde::{Deserialize, Serialize};
use std::any::Any;
use std::fmt::{Display, Formatter};
use std::{
borrow::Cow,
@@ -55,7 +281,7 @@ pub const STANDARD_SHADER_NAMES: [&str; 3] = [
/// Usually you don't need to access internals of the shader, but there sometimes could be a need to
/// read shader definition, to get supported passes and properties.
#[derive(Default, Debug)]
pub struct ShaderState {
pub struct Shader {
path: PathBuf,
/// Shader definition contains description of properties and render passes.
@@ -64,7 +290,13 @@ pub struct ShaderState {
pub(crate) cache_index: AtomicIndex,
}
impl Visit for ShaderState {
impl TypeUuidProvider for Shader {
fn type_uuid() -> Uuid {
SHADER_RESOURCE_UUID
}
}
impl Visit for Shader {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region(name)?;
@@ -224,7 +456,7 @@ pub struct PropertyDefinition {
pub kind: PropertyKind,
}
/// A render pass definition. See [`Shader`] docs for more info about render passes.
/// A render pass definition. See [`ShaderResource`] docs for more info about render passes.
#[derive(Default, Deserialize, Debug, PartialEq, Eq)]
pub struct RenderPassDefinition {
/// A name of render pass.
@@ -258,7 +490,7 @@ impl ShaderDefinition {
}
}
impl ShaderState {
impl Shader {
pub(crate) async fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, ShaderError> {
let content = io::load_file(path.as_ref()).await?;
Ok(Self {
@@ -277,7 +509,7 @@ impl ShaderState {
}
}
impl ResourceData for ShaderState {
impl ResourceData for Shader {
fn path(&self) -> Cow<Path> {
Cow::from(&self.path)
}
@@ -285,6 +517,18 @@ impl ResourceData for ShaderState {
fn set_path(&mut self, path: PathBuf) {
self.path = path;
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn type_uuid(&self) -> Uuid {
<Self as TypeUuidProvider>::type_uuid()
}
}
/// A set of possible error variants that can occur during shader loading.
@@ -322,262 +566,50 @@ impl From<FileLoadError> for ShaderError {
}
}
define_new_resource!(
/// Shader is a script for graphics adapter, it defines how to draw an object.
///
/// # Structure
///
/// Shader has rigid structure that could be described in this code snipped:
///
/// ```ron
/// (
/// // A set of properties, there could be any amount of properties.
/// properties: [
/// (
/// // Each property must have a name. This name must match with respective
/// // uniforms! That's is the whole point of having properties.
/// name: "diffuseTexture",
///
/// // Value has limited set of possible variants.
/// value: Sampler(default: None, fallback: White)
/// )
/// ],
///
/// // A set of render passes (see a section `Render pass` for more info)
/// passes: [
/// (
/// // Name must match with the name of either standard render pass (see below) or
/// // one of your passes.
/// name: "Forward",
///
/// // A set of parameters that regulate renderer pipeline state.
/// // This is mandatory field of each render pass.
/// draw_parameters: DrawParameters(
/// // A face to cull. Either Front or Back.
/// cull_face: Some(Back),
///
/// // Color mask. Defines which colors should be written to render target.
/// color_write: ColorMask(
/// red: true,
/// green: true,
/// blue: true,
/// alpha: true,
/// ),
///
/// // Whether to modify depth buffer or not.
/// depth_write: true,
///
/// // Whether to use stencil test or not.
/// stencil_test: None,
///
/// // Whether to perform depth test when drawing.
/// depth_test: true,
///
/// // Blending options.
/// blend: Some(BlendParameters(
/// func: BlendFunc(
/// sfactor: SrcAlpha,
/// dfactor: OneMinusSrcAlpha,
/// alpha_sfactor: SrcAlpha,
/// alpha_dfactor: OneMinusSrcAlpha,
/// ),
/// equation: BlendEquation(
/// rgb: Add,
/// alpha: Add
/// )
/// )),
///
/// // Stencil options.
/// stencil_op: StencilOp(
/// fail: Keep,
/// zfail: Keep,
/// zpass: Keep,
/// write_mask: 0xFFFF_FFFF,
/// ),
/// ),
///
/// // Vertex shader code.
/// vertex_shader:
/// r#"
/// #version 330 core
///
/// layout(location = 0) in vec3 vertexPosition;
/// layout(location = 1) in vec2 vertexTexCoord;
///
/// uniform mat4 fyrox_worldViewProjection;
///
/// out vec2 texCoord;
///
/// void main()
/// {
/// texCoord = vertexTexCoord;
/// gl_Position = fyrox_worldViewProjection * vertexPosition;
/// }
/// "#;
///
/// // Pixel shader code.
/// pixel_shader:
/// r#"
/// #version 330 core
///
/// // Note that the name of this uniform match the name of the property up above.
/// uniform sampler2D diffuseTexture;
///
/// out vec4 FragColor;
///
/// in vec2 texCoord;
///
/// void main()
/// {
/// FragColor = diffuseColor * texture(diffuseTexture, texCoord);
/// }
/// "#;
/// )
/// ],
/// )
/// ```
///
/// Shader should contain at least one render pass to actually do some job. A shader could not
/// have properties at all. Currently only vertex and fragment programs are supported. Each
/// program mush be written in GLSL. Comprehensive GLSL documentation can be found
/// [here](https://www.khronos.org/opengl/wiki/Core_Language_(GLSL))
///
/// # Render pass
///
/// Modern rendering is a very complex thing that requires drawing an object multiple times
/// with different "scripts". For example to draw an object with shadows you need to draw an
/// object twice: one directly in a render target, and one in a shadow map. Such stages called
/// render passes.
///
/// Binding of shaders to render passes is done via names, each render pass has unique name.
///
/// ## Predefined passes
///
/// There are number of predefined render passes:
///
/// - GBuffer - A pass that fills a set of render target sized textures with various data
/// about each rendered object. These textures then are used for physically-based lighting.
/// Use this pass when you want the standard lighting to work with your objects.
///
/// - Forward - A pass that draws an object directly in render target. This pass is very
/// limiting, it does not support lighting, shadows, etc. It should be only used to render
/// translucent objects.
///
/// - SpotShadow - A pass that emits depth values for an object, later this depth map will be
/// used to render shadows.
///
/// - PointShadow - A pass that emits distance from a fragment to a point light, later this depth
/// map will be used to render shadows.
///
/// # Built-in variables
///
/// There are number of build-in variables that Fyrox pass to each shader automatically:
///
/// | Name | Type | Description
/// |---------------------------|-----------------|--------------------------------------------
/// | fyrox_worldMatrix | `Matrix4` | Local-to-world transformation.
/// | fyrox_worldViewProjection | `Matrix4` | Local-to-clip-space transform.
/// | fyrox_boneMatrices | `[Matrix4; 60]` | Array of bone matrices.
/// | fyrox_useSkeletalAnimation | `Vector3` | Whether skinned meshes is rendering or not.
/// | fyrox_cameraPosition | `Vector3` | Position of the camera.
/// | fyrox_usePOM | `bool` | Whether to use parallax mapping or not.
/// | fyrox_lightPosition | `Vector3` | Light position.
///
/// To use any of the variables, just define a uniform with appropriate name:
///
/// ```glsl
/// uniform mat4 fyrox_worldMatrix;
/// uniform vec3 fyrox_cameraPosition;
/// ```
///
/// This list will be extended in future releases.
///
/// # Drawing parameters
///
/// Drawing parameters defines which GPU functions to use and at which state. For example, to render
/// transparent objects you need to enable blending with specific blending rules. Or you need to disable
/// culling to draw objects from both sides. This is when draw parameters comes in handy.
///
/// There are relatively large list of drawing parameters and it could confuse a person who didn't get
/// used to work with graphics. The following list should help you to use drawing parameters correctly.
///
/// - cull_face
/// - Defines which side of polygon should be culled.
/// - **Possible values:** `None`, [Some(CullFace::XXX)](crate::renderer::framework::state::CullFace)
///
/// - color_write:
/// - Defines which components of color should be written to a render target
/// - **Possible values:** [ColorMask](crate::renderer::framework::state::ColorMask)(...)
///
/// - depth_write:
/// - Whether to modify depth buffer or not.
/// - **Possible values:** `true/false`
///
/// - stencil_test:
/// - Whether to use stencil test or not.
/// - **Possible values:**
/// - `None`
/// - Some([StencilFunc](crate::renderer::framework::state::StencilFunc))
///
/// - depth_test:
/// - Whether to perform depth test when drawing.
/// - **Possible values:** `true/false`
///
/// - blend:
/// - Blending options.
/// - **Possible values:**
/// - `None`
/// - Some([BlendFunc](crate::renderer::framework::state::BlendFunc))
///
/// - stencil_op:
/// - Stencil options.
/// - **Possible values:** [StencilOp](crate::renderer::framework::state::StencilOp)
///
/// # Standard shader
///
/// By default Fyrox uses standard material for rendering, it covers 95% of uses cases and it is very
/// flexible. To get standard shader instance, use [`Shader::standard`]
///
/// ```no_run
/// # use fyrox::material::shader::Shader;
///
/// let standard_shader = Shader::standard();
/// ```
///
/// Usually you don't need to get this shader manually, using of [Material::standard](super::Material::standard)
/// is enough.
#[derive(Reflect)]
#[reflect(hide_all)]
Shader<ShaderState>
);
pub type ShaderResource = Resource<Shader>;
impl Shader {
pub trait ShaderResourceExtension: Sized {
/// Creates new shader from given string. Input string must have the format defined in
/// examples for [`Shader`].
pub fn from_str<P: AsRef<Path>>(str: &str, path: P) -> Result<Self, ShaderError> {
Ok(Self(Resource::new_ok(ShaderState::from_str(
str,
path.as_ref(),
)?)))
/// examples for [`ShaderResource`].
fn from_str<P: AsRef<Path>>(str: &str, path: P) -> Result<Self, ShaderError>;
/// Returns an instance of standard shader.
fn standard() -> Self;
/// Returns an instance of standard terrain shader.
fn standard_terrain() -> Self;
/// Returns an instance of standard two-sides terrain shader.
fn standard_twosides() -> Self;
/// Returns a list of standard shader.
fn standard_shaders() -> Vec<ShaderResource>;
}
impl ShaderResourceExtension for ShaderResource {
/// Creates new shader from given string. Input string must have the format defined in
/// examples for [`ShaderResource`].
fn from_str<P: AsRef<Path>>(str: &str, path: P) -> Result<Self, ShaderError> {
Ok(Resource::new_ok(Shader::from_str(str, path.as_ref())?))
}
/// Returns an instance of standard shader.
pub fn standard() -> Self {
fn standard() -> Self {
STANDARD.clone()
}
/// Returns an instance of standard terrain shader.
pub fn standard_terrain() -> Self {
fn standard_terrain() -> Self {
STANDARD_TERRAIN.clone()
}
/// Returns an instance of standard two-sides terrain shader.
pub fn standard_twosides() -> Self {
fn standard_twosides() -> Self {
STANDARD_TWOSIDES.clone()
}
/// Returns a list of standard shader.
pub fn standard_shaders() -> Vec<Shader> {
fn standard_shaders() -> Vec<ShaderResource> {
vec![
Self::standard(),
Self::standard_terrain(),
@@ -593,28 +625,28 @@ pub struct ShaderImportOptions {}
impl ImportOptions for ShaderImportOptions {}
lazy_static! {
static ref STANDARD: Shader = Shader(Resource::new_ok(
ShaderState::from_str(STANDARD_SHADER_SRC, STANDARD_SHADER_NAME).unwrap(),
));
static ref STANDARD: ShaderResource = ShaderResource::new_ok(
Shader::from_str(STANDARD_SHADER_SRC, STANDARD_SHADER_NAME).unwrap(),
);
}
lazy_static! {
static ref STANDARD_TERRAIN: Shader = Shader(Resource::new_ok(
ShaderState::from_str(STANDARD_TERRAIN_SHADER_SRC, STANDARD_TERRAIN_SHADER_NAME).unwrap(),
));
static ref STANDARD_TERRAIN: ShaderResource = ShaderResource::new_ok(
Shader::from_str(STANDARD_TERRAIN_SHADER_SRC, STANDARD_TERRAIN_SHADER_NAME).unwrap(),
);
}
lazy_static! {
static ref STANDARD_TWOSIDES: Shader = Shader(Resource::new_ok(
ShaderState::from_str(STANDARD_TWOSIDES_SHADER_SRC, STANDARD_TWOSIDES_SHADER_NAME).unwrap(),
));
static ref STANDARD_TWOSIDES: ShaderResource = ShaderResource::new_ok(
Shader::from_str(STANDARD_TWOSIDES_SHADER_SRC, STANDARD_TWOSIDES_SHADER_NAME).unwrap(),
);
}
#[cfg(test)]
mod test {
use crate::material::shader::{
PropertyDefinition, PropertyKind, RenderPassDefinition, SamplerFallback, Shader,
ShaderDefinition,
PropertyDefinition, PropertyKind, RenderPassDefinition, SamplerFallback, ShaderDefinition,
ShaderResource,
};
#[test]
@@ -659,7 +691,7 @@ mod test {
)
"##;
let shader = Shader::from_str(code, "test").unwrap();
let shader = ShaderResource::from_str(code, "test").unwrap();
let data = shader.data_ref();
let reference_definition = ShaderDefinition {
+2 -4
View File
@@ -3,11 +3,9 @@
#![warn(missing_docs)]
use crate::{
asset::manager::ResourceManager,
core::pool::Handle,
engine::{
resource_manager::ResourceManager, GraphicsContext, PerformanceStatistics,
SerializationContext,
},
engine::{GraphicsContext, PerformanceStatistics, SerializationContext},
event::Event,
event_loop::ControlFlow,
gui::{message::UiMessage, UserInterface},
+2 -3
View File
@@ -1,12 +1,11 @@
use crate::scene::mesh::surface::SurfaceData;
use crate::{
asset::container::entry::DEFAULT_RESOURCE_LIFETIME,
core::{scope_profile, sparse::SparseBuffer},
engine::resource_manager::container::entry::DEFAULT_RESOURCE_LIFETIME,
renderer::framework::{
geometry_buffer::{GeometryBuffer, GeometryBufferKind},
state::PipelineState,
},
scene::mesh::surface::SurfaceSharedData,
scene::mesh::surface::{SurfaceData, SurfaceSharedData},
};
use fyrox_core::sparse::AtomicIndex;
+7 -7
View File
@@ -1,7 +1,7 @@
use crate::{
asset::container::entry::DEFAULT_RESOURCE_LIFETIME,
core::{scope_profile, sparse::SparseBuffer, sstorage::ImmutableString},
engine::resource_manager::container::entry::DEFAULT_RESOURCE_LIFETIME,
material::shader::{Shader, ShaderState},
material::shader::{Shader, ShaderResource},
renderer::{
cache::CacheEntry,
framework::{framebuffer::DrawParameters, gpu_program::GpuProgram, state::PipelineState},
@@ -21,7 +21,7 @@ pub struct ShaderSet {
}
impl ShaderSet {
pub fn new(state: &mut PipelineState, shader: &ShaderState) -> Option<Self> {
pub fn new(state: &mut PipelineState, shader: &Shader) -> Option<Self> {
let mut map = FxHashMap::default();
for render_pass in shader.definition.passes.iter() {
let program_name = format!("{}_{}", shader.definition.name, render_pass.name);
@@ -63,8 +63,8 @@ pub struct ShaderCache {
}
impl ShaderCache {
pub fn remove(&mut self, shader: &Shader) {
let state = shader.state();
pub fn remove(&mut self, shader: &ShaderResource) {
let mut state = shader.state();
if let ResourceStateRef::Ok(shader_state) = state.get() {
self.buffer.free(&shader_state.cache_index);
}
@@ -73,12 +73,12 @@ impl ShaderCache {
pub fn get(
&mut self,
pipeline_state: &mut PipelineState,
shader: &Shader,
shader: &ShaderResource,
) -> Option<&ShaderSet> {
scope_profile!();
let key = shader.key();
let shader_state = shader.state();
let mut shader_state = shader.state();
if let ResourceStateRef::Ok(shader_state) = shader_state.get() {
if self.buffer.is_index_valid(&shader_state.cache_index) {
+8 -8
View File
@@ -1,7 +1,7 @@
use crate::renderer::framework::error::FrameworkError;
use crate::{
asset::container::entry::DEFAULT_RESOURCE_LIFETIME,
core::scope_profile,
engine::resource_manager::container::entry::DEFAULT_RESOURCE_LIFETIME,
renderer::{
cache::CacheEntry,
framework::{
@@ -9,7 +9,7 @@ use crate::{
state::PipelineState,
},
},
resource::texture::Texture,
resource::texture::TextureResource,
utils::log::{Log, MessageKind},
};
use fxhash::FxHashMap;
@@ -27,10 +27,10 @@ impl TextureCache {
pub fn upload(
&mut self,
state: &mut PipelineState,
texture: &Texture,
texture: &TextureResource,
) -> Result<(), FrameworkError> {
let key = texture.key();
let texture = texture.state();
let mut texture = texture.state();
if let ResourceStateRef::Ok(texture) = texture.get() {
let gpu_texture = GpuTexture::new(
@@ -67,13 +67,13 @@ impl TextureCache {
pub fn get(
&mut self,
state: &mut PipelineState,
texture_resource: &Texture,
texture_resource: &TextureResource,
) -> Option<Rc<RefCell<GpuTexture>>> {
scope_profile!();
let key = texture_resource.key();
let texture_data_guard = texture_resource.state();
let mut texture_data_guard = texture_resource.state();
if let ResourceStateRef::Ok(texture) = texture_data_guard.get() {
let entry = match self.map.entry(key) {
@@ -160,7 +160,7 @@ impl TextureCache {
Log::writeln(
MessageKind::Error,
format!("Failed to create GPU texture from {:?} engine texture. Reason: {:?}", texture_resource.state().path(), e),
format!("Failed to create GPU texture from {:?} engine texture. Reason: {:?}", texture_resource.path(), e),
);
return None;
}
@@ -194,7 +194,7 @@ impl TextureCache {
self.map.clear();
}
pub fn unload(&mut self, texture: Texture) {
pub fn unload(&mut self, texture: TextureResource) {
self.map.remove(&texture.key());
}
}
+37 -35
View File
@@ -34,10 +34,10 @@ mod skybox_shader;
mod sprite_renderer;
mod ssao;
use crate::renderer::batch::ObserverInfo;
use crate::renderer::framework::geometry_buffer::ElementRange;
use crate::renderer::framework::state::{PolygonFace, PolygonFillMode};
use crate::material::shader::Shader;
use crate::resource::texture::Texture;
use crate::{
asset::{container::event::ResourceEvent, manager::ResourceManager},
core::{
algebra::{Matrix4, Vector2, Vector3},
color::Color,
@@ -47,14 +47,10 @@ use crate::{
reflect::prelude::*,
scope_profile,
},
engine::resource_manager::{container::event::ResourceEvent, ResourceManager},
gui::{draw::DrawingContext, UserInterface},
material::{
shader::{SamplerFallback, Shader},
Material, PropertyValue,
},
material::{shader::SamplerFallback, Material, PropertyValue},
renderer::{
batch::RenderDataBatchStorage,
batch::{ObserverInfo, RenderDataBatchStorage},
bloom::BloomRenderer,
cache::{geometry::GeometryCache, shader::ShaderCache, texture::TextureCache, CacheEntry},
debug_renderer::DebugRenderer,
@@ -63,13 +59,15 @@ use crate::{
framework::{
error::FrameworkError,
framebuffer::{Attachment, AttachmentKind, DrawParameters, FrameBuffer},
geometry_buffer::{DrawCallStatistics, GeometryBuffer, GeometryBufferKind},
geometry_buffer::{
DrawCallStatistics, ElementRange, GeometryBuffer, GeometryBufferKind,
},
gpu_program::{BuiltInUniform, GpuProgramBinding},
gpu_texture::{
Coordinate, GpuTexture, GpuTextureKind, MagnificationFilter, MinificationFilter,
PixelKind, WrapMode,
},
state::{PipelineState, PipelineStatistics},
state::{PipelineState, PipelineStatistics, PolygonFace, PolygonFillMode},
},
fxaa::FxaaRenderer,
gbuffer::{GBuffer, GBufferRenderContext},
@@ -81,7 +79,7 @@ use crate::{
storage::MatrixStorage,
ui_renderer::{UiRenderContext, UiRenderer},
},
resource::texture::{Texture, TextureKind},
resource::texture::{TextureKind, TextureResource},
scene::{camera::Camera, mesh::surface::SurfaceData, Scene, SceneContainer},
utils::log::{Log, MessageKind},
};
@@ -728,8 +726,8 @@ pub struct Renderer {
forward_renderer: ForwardRenderer,
fxaa_renderer: FxaaRenderer,
renderer2d: Renderer2d,
texture_event_receiver: Receiver<ResourceEvent<Texture>>,
shader_event_receiver: Receiver<ResourceEvent<Shader>>,
texture_event_receiver: Receiver<ResourceEvent>,
shader_event_receiver: Receiver<ResourceEvent>,
matrix_storage: MatrixStorage,
// TextureId -> FrameBuffer mapping. This mapping is used for temporal frame buffers
// like ones used to render UI instances.
@@ -944,7 +942,7 @@ pub(crate) struct MaterialContext<'a, 'b, 'c> {
pub camera_position: &'a Vector3<f32>,
pub use_pom: bool,
pub light_position: &'a Vector3<f32>,
pub blend_shapes_storage: Option<&'a Texture>,
pub blend_shapes_storage: Option<&'a TextureResource>,
pub blend_shapes_weights: &'a [f32],
// Fallback samplers.
@@ -1107,7 +1105,7 @@ impl Renderer {
resource_manager
.state()
.containers_mut()
.textures
.resources
.event_broadcaster
.add(texture_event_sender);
@@ -1116,7 +1114,7 @@ impl Renderer {
resource_manager
.state()
.containers_mut()
.shaders
.resources
.event_broadcaster
.add(shader_event_sender);
@@ -1275,7 +1273,7 @@ impl Renderer {
}
/// Unloads texture from GPU memory.
pub fn unload_texture(&mut self, texture: Texture) {
pub fn unload_texture(&mut self, texture: TextureResource) {
self.texture_cache.unload(texture)
}
@@ -1347,7 +1345,7 @@ impl Renderer {
/// to have off-screen UIs (like interactive touch-screen in Doom 3, Dead Space, etc).
pub fn render_ui_to_texture(
&mut self,
render_target: Texture,
render_target: TextureResource,
ui: &mut UserInterface,
) -> Result<(), FrameworkError> {
let new_width = ui.screen_size().x as usize;
@@ -1421,19 +1419,21 @@ impl Renderer {
let mut uploaded = 0;
while let Ok(event) = self.texture_event_receiver.try_recv() {
if let ResourceEvent::Loaded(texture) | ResourceEvent::Reloaded(texture) = event {
match self.texture_cache.upload(&mut self.state, &texture) {
Ok(_) => {
uploaded += 1;
if uploaded >= THROUGHPUT {
break;
if let ResourceEvent::Loaded(resource) | ResourceEvent::Reloaded(resource) = event {
if let Some(texture) = resource.try_cast::<Texture>() {
match self.texture_cache.upload(&mut self.state, &texture) {
Ok(_) => {
uploaded += 1;
if uploaded >= THROUGHPUT {
break;
}
}
Err(e) => {
Log::writeln(
MessageKind::Error,
format!("Failed to upload texture to GPU. Reason: {:?}", e),
);
}
}
Err(e) => {
Log::writeln(
MessageKind::Error,
format!("Failed to upload texture to GPU. Reason: {:?}", e),
);
}
}
}
@@ -1444,10 +1444,12 @@ impl Renderer {
fn update_shader_cache(&mut self, dt: f32) {
while let Ok(event) = self.shader_event_receiver.try_recv() {
if let ResourceEvent::Loaded(shader) | ResourceEvent::Reloaded(shader) = event {
// Remove and immediately "touch" the shader cache to force upload shader.
self.shader_cache.remove(&shader);
let _ = self.shader_cache.get(&mut self.state, &shader);
if let ResourceEvent::Loaded(resource) | ResourceEvent::Reloaded(resource) = event {
if let Some(shader) = resource.try_cast::<Shader>() {
// Remove and immediately "touch" the shader cache to force upload shader.
self.shader_cache.remove(&shader);
let _ = self.shader_cache.get(&mut self.state, &shader);
}
}
}
+1 -1
View File
@@ -1,11 +1,11 @@
use crate::{
asset::container::entry::TimedEntry,
core::{
algebra::{Matrix4, Vector2},
color::Color,
math::TriangleDefinition,
scope_profile,
},
engine::resource_manager::container::entry::TimedEntry,
renderer::framework::{
geometry_buffer::{
AttributeDefinition, AttributeKind, BufferBuilder, ElementKind, GeometryBuffer,
+21 -20
View File
@@ -1,9 +1,7 @@
//! See [`UiRenderer`] docs.
use crate::renderer::framework::framebuffer::BlendParameters;
use crate::renderer::framework::geometry_buffer::ElementRange;
use crate::{
asset::Resource,
asset::{state::ResourceState, untyped::UntypedResource},
core::{
algebra::{Matrix4, Vector2, Vector4},
color::Color,
@@ -19,10 +17,10 @@ use crate::{
renderer::{
framework::{
error::FrameworkError,
framebuffer::{DrawParameters, FrameBuffer},
framebuffer::{BlendParameters, DrawParameters, FrameBuffer},
geometry_buffer::{
AttributeDefinition, AttributeKind, BufferBuilder, ElementKind, GeometryBuffer,
GeometryBufferBuilder, GeometryBufferKind,
AttributeDefinition, AttributeKind, BufferBuilder, ElementKind, ElementRange,
GeometryBuffer, GeometryBufferBuilder, GeometryBufferKind,
},
gpu_program::{GpuProgram, UniformLocation},
gpu_texture::GpuTexture,
@@ -33,7 +31,7 @@ use crate::{
},
RenderPassStatistics, TextureCache,
},
resource::texture::{Texture, TextureData, TextureKind, TexturePixelKind},
resource::texture::{Texture, TextureKind, TexturePixelKind},
};
use std::{cell::RefCell, rc::Rc, sync::Arc};
@@ -267,7 +265,7 @@ impl UiRenderer {
let mut font = font_arc.0.lock();
if font.texture.is_none() {
let size = font.atlas_size() as u32;
if let Some(details) = TextureData::from_bytes(
if let Some(details) = Texture::from_bytes(
TextureKind::Rectangle {
width: size,
height: size,
@@ -277,26 +275,29 @@ impl UiRenderer {
false,
) {
font.texture = Some(SharedTexture(Arc::new(Mutex::new(
TextureState::Ok(details),
ResourceState::new_ok(details),
))));
}
}
let tex = font
.texture
.clone()
.unwrap()
.0
.downcast::<Mutex<TextureState>>()
.unwrap();
if let Some(texture) = texture_cache.get(state, &Texture(Resource::from(tex))) {
let tex = UntypedResource(
font.texture
.clone()
.unwrap()
.0
.downcast::<Mutex<ResourceState>>()
.unwrap(),
);
if let Some(texture) =
texture_cache.get(state, &tex.try_cast::<Texture>().unwrap())
{
diffuse_texture = texture;
}
is_font_texture = true;
}
CommandTexture::Texture(texture) => {
if let Ok(texture) = texture.clone().0.downcast::<Mutex<TextureState>>() {
let resource = Resource::from(texture);
if let Some(texture) = texture_cache.get(state, &Texture(resource)) {
if let Ok(texture) = texture.clone().0.downcast::<Mutex<ResourceState>>() {
let resource = UntypedResource(texture).try_cast::<Texture>().unwrap();
if let Some(texture) = texture_cache.get(state, &resource) {
diffuse_texture = texture;
}
}
+25 -9
View File
@@ -1,12 +1,15 @@
//! Curve resource holds a [`Curve`]
use crate::{
asset::{define_new_resource, Resource, ResourceData},
core::reflect::prelude::*,
asset::options::ImportOptions,
asset::{Resource, ResourceData},
core::{curve::Curve, io::FileLoadError, visitor::prelude::*},
engine::resource_manager::options::ImportOptions,
};
use fyrox_core::uuid::Uuid;
use fyrox_core::TypeUuidProvider;
use fyrox_resource::CURVE_RESOURCE_UUID;
use serde::{Deserialize, Serialize};
use std::any::Any;
use std::fmt::{Display, Formatter};
use std::{
borrow::Cow,
@@ -67,6 +70,24 @@ impl ResourceData for CurveResourceState {
fn set_path(&mut self, path: PathBuf) {
self.path = path;
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn type_uuid(&self) -> Uuid {
<Self as TypeUuidProvider>::type_uuid()
}
}
impl TypeUuidProvider for CurveResourceState {
fn type_uuid() -> Uuid {
CURVE_RESOURCE_UUID
}
}
impl CurveResourceState {
@@ -82,12 +103,7 @@ impl CurveResourceState {
}
}
define_new_resource!(
/// See module docs.
#[derive(Reflect)]
#[reflect(hide_all)]
CurveResource<CurveResourceState>
);
pub type CurveResource = Resource<Curve>;
/// Import options for curve resource.
#[derive(Serialize, Deserialize, Default, Clone)]
+4 -2
View File
@@ -10,9 +10,11 @@ mod document;
pub mod error;
mod scene;
use crate::resource::texture::Texture;
use crate::scene::mesh::surface::{BlendShape, InputBlendShapeData};
use crate::{
animation::{track::Track, Animation, AnimationContainer},
asset::manager::ResourceManager,
core::{
algebra::{Matrix4, Point3, UnitQuaternion, Vector2, Vector3, Vector4},
curve::{CurveKey, CurveKeyKind},
@@ -23,7 +25,6 @@ use crate::{
sstorage::ImmutableString,
uuid::Uuid,
},
engine::resource_manager::ResourceManager,
material::{shader::SamplerFallback, PropertyValue},
resource::{
fbx::{
@@ -351,7 +352,8 @@ async fn create_surfaces(
};
if let Some(texture_path) = texture_path {
let texture = resource_manager.request_texture(texture_path.as_path());
let texture =
resource_manager.request::<Texture, _>(texture_path.as_path());
// Make up your mind, Autodesk and Blender.
// Handle all possible combinations of links to auto-import materials.
+67 -32
View File
@@ -20,7 +20,7 @@
use crate::{
animation::Animation,
asset::{define_new_resource, Resource, ResourceData},
asset::{manager::ResourceManager, options::ImportOptions, Resource, ResourceData},
core::{
algebra::{UnitQuaternion, Vector3},
pool::Handle,
@@ -28,10 +28,7 @@ use crate::{
variable::reset_inheritable_properties,
visitor::{Visit, VisitError, VisitResult, Visitor},
},
engine::{
resource_manager::{options::ImportOptions, ResourceManager},
SerializationContext,
},
engine::SerializationContext,
resource::fbx::{self, error::FbxError},
scene::{
animation::AnimationPlayer,
@@ -41,7 +38,11 @@ use crate::{
},
utils::log::{Log, MessageKind},
};
use fyrox_core::uuid::Uuid;
use fyrox_core::TypeUuidProvider;
use fyrox_resource::MODEL_RESOURCE_UUID;
use serde::{Deserialize, Serialize};
use std::any::Any;
use std::{
borrow::Cow,
fmt::{Display, Formatter},
@@ -59,7 +60,7 @@ pub(crate) enum NodeMapping {
/// See module docs.
#[derive(Debug, Visit)]
pub struct ModelData {
pub struct Model {
pub(crate) path: PathBuf,
#[visit(skip)]
pub(crate) mapping: NodeMapping,
@@ -67,17 +68,47 @@ pub struct ModelData {
scene: Scene,
}
define_new_resource!(
/// See module docs.
#[derive(Reflect)]
#[reflect(hide_all)]
Model<ModelData>
);
impl TypeUuidProvider for Model {
fn type_uuid() -> Uuid {
MODEL_RESOURCE_UUID
}
}
impl Model {
pub(crate) fn instantiate_from(
model: Self,
model_data: &ModelData,
pub type ModelResource = Resource<Model>;
pub trait ModelResourceExtension: Sized {
fn instantiate_from(
model: ModelResource,
model_data: &Model,
handle: Handle<Node>,
dest_graph: &mut Graph,
) -> (Handle<Node>, NodeHandleMap);
fn instantiate(&self, dest_scene: &mut Scene) -> Handle<Node>;
fn instantiate_at(
&self,
scene: &mut Scene,
position: Vector3<f32>,
orientation: UnitQuaternion<f32>,
) -> Handle<Node>;
fn retarget_animations_directly(&self, root: Handle<Node>, graph: &Graph) -> Vec<Animation>;
fn retarget_animations_to_player(
&self,
root: Handle<Node>,
dest_animation_player: Handle<Node>,
graph: &mut Graph,
) -> Vec<Handle<Animation>>;
fn retarget_animations(&self, root: Handle<Node>, graph: &mut Graph) -> Vec<Handle<Animation>>;
}
impl ModelResourceExtension for ModelResource {
fn instantiate_from(
model: ModelResource,
model_data: &Model,
handle: Handle<Node>,
dest_graph: &mut Graph,
) -> (Handle<Node>, NodeHandleMap) {
@@ -115,7 +146,7 @@ impl Model {
}
/// Tries to instantiate model from given resource.
pub fn instantiate(&self, dest_scene: &mut Scene) -> Handle<Node> {
fn instantiate(&self, dest_scene: &mut Scene) -> Handle<Node> {
let data = self.data_ref();
let instance_root = Self::instantiate_from(
@@ -133,7 +164,7 @@ impl Model {
}
/// Instantiates a prefab and places it at specified position and orientation in global coordinates.
pub fn instantiate_at(
fn instantiate_at(
&self,
scene: &mut Scene,
position: Vector3<f32>,
@@ -172,11 +203,7 @@ impl Model {
///
/// Most of the 3d model formats can contain only one animation, so in most cases
/// this function will return vector with only one animation.
pub fn retarget_animations_directly(
&self,
root: Handle<Node>,
graph: &Graph,
) -> Vec<Animation> {
fn retarget_animations_directly(&self, root: Handle<Node>, graph: &Graph) -> Vec<Animation> {
let mut retargetted_animations = Vec::new();
let data = self.data_ref();
@@ -228,7 +255,7 @@ impl Model {
///
/// Panics if `dest_animation_player` is invalid handle, or the node does not have [`AnimationPlayer`]
/// component.
pub fn retarget_animations_to_player(
fn retarget_animations_to_player(
&self,
root: Handle<Node>,
dest_animation_player: Handle<Node>,
@@ -256,11 +283,7 @@ impl Model {
/// # Panic
///
/// Panics if there's no animation player in the given hierarchy (descendant nodes of `root`).
pub fn retarget_animations(
&self,
root: Handle<Node>,
graph: &mut Graph,
) -> Vec<Handle<Animation>> {
fn retarget_animations(&self, root: Handle<Node>, graph: &mut Graph) -> Vec<Handle<Animation>> {
if let Some((animation_player, _)) = graph.find(root, &mut |n| {
n.query_component_ref::<AnimationPlayer>().is_some()
}) {
@@ -271,7 +294,7 @@ impl Model {
}
}
impl ResourceData for ModelData {
impl ResourceData for Model {
fn path(&self) -> Cow<Path> {
Cow::Borrowed(&self.path)
}
@@ -279,9 +302,21 @@ impl ResourceData for ModelData {
fn set_path(&mut self, path: PathBuf) {
self.path = path;
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn type_uuid(&self) -> Uuid {
<Self as TypeUuidProvider>::type_uuid()
}
}
impl Default for ModelData {
impl Default for Model {
fn default() -> Self {
Self {
path: PathBuf::new(),
@@ -426,7 +461,7 @@ impl From<VisitError> for ModelLoadError {
}
}
impl ModelData {
impl Model {
pub(crate) async fn load<P: AsRef<Path>>(
path: P,
serialization_context: Arc<SerializationContext>,
+67 -33
View File
@@ -21,23 +21,25 @@
//! access to pixels of render target.
use crate::{
asset::{define_new_resource, Resource, ResourceData},
asset::{options::ImportOptions, Resource, ResourceData},
core::{
futures::io::Error,
io::{self, FileLoadError},
reflect::prelude::*,
visitor::{PodVecView, Visit, VisitError, VisitResult, Visitor},
},
engine::resource_manager::options::ImportOptions,
};
use ddsfile::{Caps2, D3DFormat};
use fxhash::FxHasher;
use fyrox_core::uuid::Uuid;
use fyrox_core::TypeUuidProvider;
use fyrox_resource::TEXTURE_RESOURCE_UUID;
use image::{imageops::FilterType, ColorType, DynamicImage, ImageError, ImageFormat};
use serde::{Deserialize, Serialize};
use std::fmt::Display;
use std::any::Any;
use std::{
borrow::Cow,
fmt::{Debug, Formatter},
fmt::{Debug, Display, Formatter},
hash::{Hash, Hasher},
io::Cursor,
ops::{Deref, DerefMut},
@@ -186,7 +188,7 @@ impl DerefMut for TextureBytes {
/// Actual texture data.
#[derive(Debug, Clone)]
pub struct TextureData {
pub struct Texture {
path: PathBuf,
kind: TextureKind,
bytes: TextureBytes,
@@ -202,7 +204,13 @@ pub struct TextureData {
is_render_target: bool,
}
impl ResourceData for TextureData {
impl TypeUuidProvider for Texture {
fn type_uuid() -> Uuid {
TEXTURE_RESOURCE_UUID
}
}
impl ResourceData for Texture {
fn path(&self) -> Cow<Path> {
Cow::Borrowed(&self.path)
}
@@ -210,9 +218,21 @@ impl ResourceData for TextureData {
fn set_path(&mut self, path: PathBuf) {
self.path = path;
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn type_uuid(&self) -> Uuid {
<Self as TypeUuidProvider>::type_uuid()
}
}
impl Visit for TextureData {
impl Visit for Texture {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region(name)?;
@@ -246,7 +266,7 @@ impl Visit for TextureData {
}
}
impl Default for TextureData {
impl Default for Texture {
/// It is very important to mention that defaults may be different for texture when you
/// importing them through resource manager, see
/// [TextureImportOptions](../engine/resource_manager/struct.TextureImportOptions.html) for more info.
@@ -404,19 +424,33 @@ impl TextureImportOptions {
}
}
define_new_resource!(
/// See module docs.
#[derive(Reflect)]
#[reflect(hide_all)]
Texture<TextureData>
);
pub type TextureResource = Resource<Texture>;
impl Texture {
pub trait TextureResourceExtension: Sized {
fn new_render_target(width: u32, height: u32) -> Self;
fn load_from_memory(
data: &[u8],
compression: CompressionOptions,
gen_mip_maps: bool,
) -> Result<Self, TextureError>;
fn from_bytes(
kind: TextureKind,
pixel_kind: TexturePixelKind,
bytes: Vec<u8>,
serialize_content: bool,
) -> Option<Self>;
fn deep_clone(&self) -> Self;
}
impl TextureResourceExtension for TextureResource {
/// Creates new render target for a scene. This method automatically configures GPU texture
/// to correct settings, after render target was created, it must not be modified, otherwise
/// result is undefined.
pub fn new_render_target(width: u32, height: u32) -> Self {
Self(Resource::new_ok(TextureData {
fn new_render_target(width: u32, height: u32) -> Self {
Resource::new_ok(Texture {
path: Default::default(),
// Render target will automatically set width and height before rendering.
kind: TextureKind::Rectangle { width, height },
@@ -431,7 +465,7 @@ impl Texture {
serialize_content: false,
data_hash: 0,
is_render_target: true,
}))
})
}
/// Tries to load a texture from given data. Use this method if you want to
@@ -451,38 +485,38 @@ impl Texture {
/// loading. You should use `ResourceManager::request_texture` in majority of cases!
///
/// Main use cases for this method are: procedural textures, icons for GUI.
pub fn load_from_memory(
fn load_from_memory(
data: &[u8],
compression: CompressionOptions,
gen_mip_maps: bool,
) -> Result<Self, TextureError> {
Ok(Self(Resource::new_ok(TextureData::load_from_memory(
Ok(Resource::new_ok(Texture::load_from_memory(
data,
compression,
gen_mip_maps,
)?)))
)?))
}
/// Tries to create new texture from given parameters, it may fail only if size of data passed
/// in does not match with required.
pub fn from_bytes(
fn from_bytes(
kind: TextureKind,
pixel_kind: TexturePixelKind,
bytes: Vec<u8>,
serialize_content: bool,
) -> Option<Self> {
Some(Self(Resource::new_ok(TextureData::from_bytes(
Some(Resource::new_ok(Texture::from_bytes(
kind,
pixel_kind,
bytes,
serialize_content,
)?)))
)?))
}
/// Creates a deep clone of the texture. Unlike [`Texture::clone`], this method clones the actual texture data,
/// Creates a deep clone of the texture. Unlike [`TextureResource::clone`], this method clones the actual texture data,
/// which could be slow.
pub fn deep_clone(&self) -> Self {
Self(Resource::new_ok(self.data_ref().clone()))
fn deep_clone(&self) -> Self {
Resource::new_ok(self.data_ref().clone())
}
}
@@ -1051,7 +1085,7 @@ fn bytes_in_first_mip(kind: TextureKind, pixel_kind: TexturePixelKind) -> u32 {
}
}
impl TextureData {
impl Texture {
/// Tries to load a texture from given data in one of the following formats: PNG, BMP, TGA, JPG, DDS, GIF. Use
/// this method if you want to load a texture from embedded data.
///
@@ -1468,7 +1502,7 @@ impl TextureData {
/// A special reference holder that provides mutable access to content of the
/// texture and automatically calculates hash of the data in its destructor.
pub struct TextureDataRefMut<'a> {
texture: &'a mut TextureData,
texture: &'a mut Texture,
}
impl<'a> Drop for TextureDataRefMut<'a> {
@@ -1478,7 +1512,7 @@ impl<'a> Drop for TextureDataRefMut<'a> {
}
impl<'a> Deref for TextureDataRefMut<'a> {
type Target = TextureData;
type Target = Texture;
fn deref(&self) -> &Self::Target {
self.texture
@@ -1515,10 +1549,10 @@ impl<'a> TextureDataRefMut<'a> {
#[cfg(test)]
pub mod test {
use crate::resource::texture::{Texture, TextureKind, TexturePixelKind};
use crate::resource::texture::{TextureKind, TexturePixelKind, TextureResource};
pub fn create_test_texture() -> Texture {
Texture::from_bytes(
pub fn create_test_texture() -> TextureResource {
TextureResource::from_bytes(
TextureKind::Rectangle {
width: 1,
height: 1,
+2 -1
View File
@@ -10,12 +10,13 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
TypeUuidProvider,
},
scene::{
animation::AnimationPlayer,
base::{Base, BaseBuilder},
graph::Graph,
node::{Node, NodeTrait, TypeUuidProvider, UpdateContext},
node::{Node, NodeTrait, UpdateContext},
Scene,
},
};
+2 -1
View File
@@ -10,11 +10,12 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
TypeUuidProvider,
},
scene::{
base::{Base, BaseBuilder},
graph::Graph,
node::{Node, NodeTrait, TypeUuidProvider, UpdateContext},
node::{Node, NodeTrait, UpdateContext},
},
};
use std::ops::{Deref, DerefMut};
+6 -7
View File
@@ -13,7 +13,7 @@ use crate::{
visitor::{Visit, VisitError, VisitResult, Visitor},
},
engine::SerializationContext,
resource::model::Model,
resource::model::ModelResource,
scene::{node::Node, transform::Transform},
script::{Script, ScriptTrait},
utils::log::Log,
@@ -382,7 +382,7 @@ pub struct Base {
// A resource from which this node was instantiated from, can work in pair
// with `original` handle to get corresponding node from resource.
#[reflect(read_only)]
pub(crate) resource: Option<Model>,
pub(crate) resource: Option<ModelResource>,
// Handle to node in scene of model resource from which this node
// was instantiated from.
@@ -540,7 +540,7 @@ impl Base {
/// Returns resource from which this node was instantiated from.
#[inline]
pub fn resource(&self) -> Option<Model> {
pub fn resource(&self) -> Option<ModelResource> {
self.resource.clone()
}
@@ -866,10 +866,9 @@ fn visit_opt_script(name: &str, script: &mut Option<Script>, visitor: &mut Visit
None
} else {
let serialization_context = region
.environment
.as_ref()
.and_then(|e| e.downcast_ref::<SerializationContext>())
.expect("Visitor environment must contain serialization context!");
.blackboard
.get::<SerializationContext>()
.expect("Visitor blackboard must contain serialization context!");
Some(
serialization_context
+64 -54
View File
@@ -14,6 +14,7 @@
//! Each camera forces engine to re-render same scene one more time, which may cause
//! almost double load of your GPU.
use crate::resource::texture::TextureResourceExtension;
use crate::{
core::{
algebra::{Matrix4, Point3, Vector2, Vector3, Vector4},
@@ -24,18 +25,19 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::{Visit, VisitResult, Visitor},
TypeUuidProvider,
},
resource::texture::{Texture, TextureError, TextureKind, TexturePixelKind, TextureWrapMode},
resource::texture::{TextureKind, TexturePixelKind, TextureResource, TextureWrapMode},
scene::{
base::{Base, BaseBuilder},
debug::SceneDrawingContext,
graph::Graph,
node::{Node, NodeTrait, TypeUuidProvider, UpdateContext},
node::{Node, NodeTrait, UpdateContext},
visibility::VisibilityCache,
},
utils::log::Log,
};
use fyrox_resource::ResourceStateRef;
use fyrox_resource::{ResourceLoadError, ResourceStateRef};
use std::{
fmt::{Display, Formatter},
ops::{Deref, DerefMut},
@@ -306,7 +308,7 @@ pub struct Camera {
sky_box: InheritableVariable<Option<SkyBox>>,
#[reflect(setter = "set_environment")]
environment: InheritableVariable<Option<Texture>>,
environment: InheritableVariable<Option<TextureResource>>,
#[reflect(setter = "set_exposure")]
exposure: InheritableVariable<Exposure>,
@@ -492,22 +494,25 @@ impl Camera {
}
/// Sets new environment.
pub fn set_environment(&mut self, environment: Option<Texture>) -> Option<Texture> {
pub fn set_environment(
&mut self,
environment: Option<TextureResource>,
) -> Option<TextureResource> {
self.environment.set_value_and_mark_modified(environment)
}
/// Return optional mutable reference to current environment.
pub fn environment_mut(&mut self) -> Option<&mut Texture> {
pub fn environment_mut(&mut self) -> Option<&mut TextureResource> {
self.environment.get_value_mut_and_mark_modified().as_mut()
}
/// Return optional shared reference to current environment.
pub fn environment_ref(&self) -> Option<&Texture> {
pub fn environment_ref(&self) -> Option<&TextureResource> {
self.environment.as_ref()
}
/// Return current environment map.
pub fn environment_map(&self) -> Option<Texture> {
pub fn environment_map(&self) -> Option<TextureResource> {
(*self.environment).clone()
}
@@ -649,7 +654,7 @@ pub enum ColorGradingLutCreationError {
InvalidPixelFormat(TexturePixelKind),
/// Texture error.
Texture(Option<Arc<TextureError>>),
Texture(Option<Arc<dyn ResourceLoadError>>),
}
impl Display for ColorGradingLutCreationError {
@@ -684,11 +689,11 @@ impl Display for ColorGradingLutCreationError {
/// See [more info in Unreal engine docs](https://docs.unrealengine.com/4.26/en-US/RenderingAndGraphics/PostProcessEffects/UsingLUTs/)
#[derive(Visit, Clone, Default, PartialEq, Debug, Reflect, Eq)]
pub struct ColorGradingLut {
unwrapped_lut: Option<Texture>,
unwrapped_lut: Option<TextureResource>,
#[visit(skip)]
#[reflect(hidden)]
lut: Option<Texture>,
lut: Option<TextureResource>,
}
impl ColorGradingLut {
@@ -719,7 +724,7 @@ impl ColorGradingLut {
///
/// Then pass LUT to either CameraBuilder or to camera instance, and don't forget to enable
/// color grading.
pub async fn new(unwrapped_lut: Texture) -> Result<Self, ColorGradingLutCreationError> {
pub async fn new(unwrapped_lut: TextureResource) -> Result<Self, ColorGradingLutCreationError> {
match unwrapped_lut.await {
Ok(unwrapped_lut) => {
let data = unwrapped_lut.data_ref();
@@ -772,7 +777,7 @@ impl ColorGradingLut {
}
}
let lut = Texture::from_bytes(
let lut = TextureResource::from_bytes(
TextureKind::Volume {
width: 16,
height: 16,
@@ -803,17 +808,17 @@ impl ColorGradingLut {
/// Returns color grading unwrapped look-up table. This is initial texture that was
/// used to create the look-up table.
pub fn unwrapped_lut(&self) -> Texture {
pub fn unwrapped_lut(&self) -> TextureResource {
self.unwrapped_lut.clone().unwrap()
}
/// Returns 3D color grading look-up table ready for use on GPU.
pub fn lut(&self) -> Texture {
pub fn lut(&self) -> TextureResource {
self.lut.clone().unwrap()
}
/// Returns 3D color grading look-up table by ref ready for use on GPU.
pub fn lut_ref(&self) -> &Texture {
pub fn lut_ref(&self) -> &TextureResource {
self.lut.as_ref().unwrap()
}
}
@@ -828,7 +833,7 @@ pub struct CameraBuilder {
viewport: Rect<f32>,
enabled: bool,
skybox: Option<SkyBox>,
environment: Option<Texture>,
environment: Option<TextureResource>,
exposure: Exposure,
color_grading_lut: Option<ColorGradingLut>,
color_grading_enabled: bool,
@@ -891,7 +896,7 @@ impl CameraBuilder {
}
/// Sets desired environment map.
pub fn with_environment(mut self, environment: Texture) -> Self {
pub fn with_environment(mut self, environment: TextureResource) -> Self {
self.environment = Some(environment);
self
}
@@ -954,52 +959,52 @@ impl CameraBuilder {
/// SkyBox builder is used to create new skybox in declarative manner.
pub struct SkyBoxBuilder {
/// Texture for front face.
pub front: Option<Texture>,
pub front: Option<TextureResource>,
/// Texture for back face.
pub back: Option<Texture>,
pub back: Option<TextureResource>,
/// Texture for left face.
pub left: Option<Texture>,
pub left: Option<TextureResource>,
/// Texture for right face.
pub right: Option<Texture>,
pub right: Option<TextureResource>,
/// Texture for top face.
pub top: Option<Texture>,
pub top: Option<TextureResource>,
/// Texture for bottom face.
pub bottom: Option<Texture>,
pub bottom: Option<TextureResource>,
}
impl SkyBoxBuilder {
/// Sets desired front face of cubemap.
pub fn with_front(mut self, texture: Texture) -> Self {
pub fn with_front(mut self, texture: TextureResource) -> Self {
self.front = Some(texture);
self
}
/// Sets desired back face of cubemap.
pub fn with_back(mut self, texture: Texture) -> Self {
pub fn with_back(mut self, texture: TextureResource) -> Self {
self.back = Some(texture);
self
}
/// Sets desired left face of cubemap.
pub fn with_left(mut self, texture: Texture) -> Self {
pub fn with_left(mut self, texture: TextureResource) -> Self {
self.left = Some(texture);
self
}
/// Sets desired right face of cubemap.
pub fn with_right(mut self, texture: Texture) -> Self {
pub fn with_right(mut self, texture: TextureResource) -> Self {
self.right = Some(texture);
self
}
/// Sets desired top face of cubemap.
pub fn with_top(mut self, texture: Texture) -> Self {
pub fn with_top(mut self, texture: TextureResource) -> Self {
self.top = Some(texture);
self
}
/// Sets desired front face of cubemap.
pub fn with_bottom(mut self, texture: Texture) -> Self {
pub fn with_bottom(mut self, texture: TextureResource) -> Self {
self.bottom = Some(texture);
self
}
@@ -1031,32 +1036,32 @@ impl SkyBoxBuilder {
pub struct SkyBox {
/// Texture for front face.
#[reflect(setter = "set_front")]
pub(crate) front: Option<Texture>,
pub(crate) front: Option<TextureResource>,
/// Texture for back face.
#[reflect(setter = "set_back")]
pub(crate) back: Option<Texture>,
pub(crate) back: Option<TextureResource>,
/// Texture for left face.
#[reflect(setter = "set_left")]
pub(crate) left: Option<Texture>,
pub(crate) left: Option<TextureResource>,
/// Texture for right face.
#[reflect(setter = "set_right")]
pub(crate) right: Option<Texture>,
pub(crate) right: Option<TextureResource>,
/// Texture for top face.
#[reflect(setter = "set_top")]
pub(crate) top: Option<Texture>,
pub(crate) top: Option<TextureResource>,
/// Texture for bottom face.
#[reflect(setter = "set_bottom")]
pub(crate) bottom: Option<Texture>,
pub(crate) bottom: Option<TextureResource>,
/// Cubemap texture
#[reflect(hidden)]
#[visit(skip)]
pub(crate) cubemap: Option<Texture>,
pub(crate) cubemap: Option<TextureResource>,
}
/// An error that may occur during skybox creation.
@@ -1101,12 +1106,12 @@ pub enum SkyBoxError {
impl SkyBox {
/// Returns cubemap texture
pub fn cubemap(&self) -> Option<Texture> {
pub fn cubemap(&self) -> Option<TextureResource> {
self.cubemap.clone()
}
/// Returns cubemap texture
pub fn cubemap_ref(&self) -> Option<&Texture> {
pub fn cubemap_ref(&self) -> Option<&TextureResource> {
self.cubemap.as_ref()
}
@@ -1213,8 +1218,13 @@ impl SkyBox {
}
self.cubemap = Some(
Texture::from_bytes(TextureKind::Cube { width, height }, pixel_kind, data, false)
.ok_or(SkyBoxError::UnableToBuildCubeMap)?,
TextureResource::from_bytes(
TextureKind::Cube { width, height },
pixel_kind,
data,
false,
)
.ok_or(SkyBoxError::UnableToBuildCubeMap)?,
);
Ok(())
@@ -1228,7 +1238,7 @@ impl SkyBox {
/// These textures are **not** used for rendering! The renderer uses cube map made of these
/// textures. Public access for these textures is needed in case you need to read internals
/// of the textures.
pub fn textures(&self) -> [Option<Texture>; 6] {
pub fn textures(&self) -> [Option<TextureResource>; 6] {
[
self.left.clone(),
self.right.clone(),
@@ -1240,7 +1250,7 @@ impl SkyBox {
}
/// Set new texture for the left side of the skybox.
pub fn set_left(&mut self, texture: Option<Texture>) -> Option<Texture> {
pub fn set_left(&mut self, texture: Option<TextureResource>) -> Option<TextureResource> {
let prev = std::mem::replace(&mut self.left, texture);
Log::verify(self.create_cubemap());
prev
@@ -1251,12 +1261,12 @@ impl SkyBox {
/// # Important notes.
///
/// This textures is not used for rendering! The renderer uses cube map made of face textures.
pub fn left(&self) -> Option<Texture> {
pub fn left(&self) -> Option<TextureResource> {
self.left.clone()
}
/// Set new texture for the right side of the skybox.
pub fn set_right(&mut self, texture: Option<Texture>) -> Option<Texture> {
pub fn set_right(&mut self, texture: Option<TextureResource>) -> Option<TextureResource> {
let prev = std::mem::replace(&mut self.right, texture);
Log::verify(self.create_cubemap());
prev
@@ -1267,12 +1277,12 @@ impl SkyBox {
/// # Important notes.
///
/// This textures is not used for rendering! The renderer uses cube map made of face textures.
pub fn right(&self) -> Option<Texture> {
pub fn right(&self) -> Option<TextureResource> {
self.right.clone()
}
/// Set new texture for the top side of the skybox.
pub fn set_top(&mut self, texture: Option<Texture>) -> Option<Texture> {
pub fn set_top(&mut self, texture: Option<TextureResource>) -> Option<TextureResource> {
let prev = std::mem::replace(&mut self.top, texture);
Log::verify(self.create_cubemap());
prev
@@ -1283,12 +1293,12 @@ impl SkyBox {
/// # Important notes.
///
/// This textures is not used for rendering! The renderer uses cube map made of face textures.
pub fn top(&self) -> Option<Texture> {
pub fn top(&self) -> Option<TextureResource> {
self.top.clone()
}
/// Set new texture for the bottom side of the skybox.
pub fn set_bottom(&mut self, texture: Option<Texture>) -> Option<Texture> {
pub fn set_bottom(&mut self, texture: Option<TextureResource>) -> Option<TextureResource> {
let prev = std::mem::replace(&mut self.bottom, texture);
Log::verify(self.create_cubemap());
prev
@@ -1299,12 +1309,12 @@ impl SkyBox {
/// # Important notes.
///
/// This textures is not used for rendering! The renderer uses cube map made of face textures.
pub fn bottom(&self) -> Option<Texture> {
pub fn bottom(&self) -> Option<TextureResource> {
self.bottom.clone()
}
/// Set new texture for the front side of the skybox.
pub fn set_front(&mut self, texture: Option<Texture>) -> Option<Texture> {
pub fn set_front(&mut self, texture: Option<TextureResource>) -> Option<TextureResource> {
let prev = std::mem::replace(&mut self.front, texture);
Log::verify(self.create_cubemap());
prev
@@ -1315,12 +1325,12 @@ impl SkyBox {
/// # Important notes.
///
/// This textures is not used for rendering! The renderer uses cube map made of face textures.
pub fn front(&self) -> Option<Texture> {
pub fn front(&self) -> Option<TextureResource> {
self.front.clone()
}
/// Set new texture for the back side of the skybox.
pub fn set_back(&mut self, texture: Option<Texture>) -> Option<Texture> {
pub fn set_back(&mut self, texture: Option<TextureResource>) -> Option<TextureResource> {
let prev = std::mem::replace(&mut self.back, texture);
Log::verify(self.create_cubemap());
prev
@@ -1331,7 +1341,7 @@ impl SkyBox {
/// # Important notes.
///
/// This textures is not used for rendering! The renderer uses cube map made of face textures.
pub fn back(&self) -> Option<Texture> {
pub fn back(&self) -> Option<TextureResource> {
self.back.clone()
}
}
+2 -1
View File
@@ -11,6 +11,7 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
TypeUuidProvider,
},
scene::{
base::{Base, BaseBuilder},
@@ -18,7 +19,7 @@ use crate::{
physics::{CoefficientCombineRule, ContactPair, IntersectionPair, PhysicsWorld},
Graph,
},
node::{Node, NodeTrait, SyncContext, TypeUuidProvider},
node::{Node, NodeTrait, SyncContext},
rigidbody::RigidBody,
Scene,
},
+21 -14
View File
@@ -11,12 +11,13 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
TypeUuidProvider,
},
resource::texture::Texture,
resource::texture::TextureResource,
scene::{
base::{Base, BaseBuilder},
graph::Graph,
node::{Node, NodeTrait, TypeUuidProvider},
node::{Node, NodeTrait},
},
};
use std::ops::{Deref, DerefMut};
@@ -86,10 +87,10 @@ pub struct Decal {
base: Base,
#[reflect(setter = "set_diffuse_texture")]
diffuse_texture: InheritableVariable<Option<Texture>>,
diffuse_texture: InheritableVariable<Option<TextureResource>>,
#[reflect(setter = "set_normal_texture")]
normal_texture: InheritableVariable<Option<Texture>>,
normal_texture: InheritableVariable<Option<TextureResource>>,
#[reflect(setter = "set_color")]
color: InheritableVariable<Color>,
@@ -121,7 +122,10 @@ impl TypeUuidProvider for Decal {
impl Decal {
/// Sets new diffuse texture.
pub fn set_diffuse_texture(&mut self, diffuse_texture: Option<Texture>) -> Option<Texture> {
pub fn set_diffuse_texture(
&mut self,
diffuse_texture: Option<TextureResource>,
) -> Option<TextureResource> {
std::mem::replace(
self.diffuse_texture.get_value_mut_and_mark_modified(),
diffuse_texture,
@@ -129,17 +133,20 @@ impl Decal {
}
/// Returns current diffuse texture.
pub fn diffuse_texture(&self) -> Option<&Texture> {
pub fn diffuse_texture(&self) -> Option<&TextureResource> {
self.diffuse_texture.as_ref()
}
/// Returns current diffuse texture.
pub fn diffuse_texture_value(&self) -> Option<Texture> {
pub fn diffuse_texture_value(&self) -> Option<TextureResource> {
(*self.diffuse_texture).clone()
}
/// Sets new normal texture.
pub fn set_normal_texture(&mut self, normal_texture: Option<Texture>) -> Option<Texture> {
pub fn set_normal_texture(
&mut self,
normal_texture: Option<TextureResource>,
) -> Option<TextureResource> {
std::mem::replace(
self.normal_texture.get_value_mut_and_mark_modified(),
normal_texture,
@@ -147,12 +154,12 @@ impl Decal {
}
/// Returns current normal texture.
pub fn normal_texture(&self) -> Option<&Texture> {
pub fn normal_texture(&self) -> Option<&TextureResource> {
self.normal_texture.as_ref()
}
/// Returns current normal texture.
pub fn normal_texture_value(&self) -> Option<Texture> {
pub fn normal_texture_value(&self) -> Option<TextureResource> {
(*self.normal_texture).clone()
}
@@ -204,8 +211,8 @@ impl NodeTrait for Decal {
/// Allows you to create a Decal in a declarative manner.
pub struct DecalBuilder {
base_builder: BaseBuilder,
diffuse_texture: Option<Texture>,
normal_texture: Option<Texture>,
diffuse_texture: Option<TextureResource>,
normal_texture: Option<TextureResource>,
color: Color,
layer: u8,
}
@@ -223,13 +230,13 @@ impl DecalBuilder {
}
/// Sets desired diffuse texture.
pub fn with_diffuse_texture(mut self, diffuse_texture: Texture) -> Self {
pub fn with_diffuse_texture(mut self, diffuse_texture: TextureResource) -> Self {
self.diffuse_texture = Some(diffuse_texture);
self
}
/// Sets desired normal texture.
pub fn with_normal_texture(mut self, normal_texture: Texture) -> Self {
pub fn with_normal_texture(mut self, normal_texture: TextureResource) -> Self {
self.normal_texture = Some(normal_texture);
self
}
+2 -1
View File
@@ -10,6 +10,7 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
TypeUuidProvider,
},
scene::{
base::{Base, BaseBuilder},
@@ -19,7 +20,7 @@ use crate::{
rigidbody::RigidBody,
},
graph::{physics::CoefficientCombineRule, Graph},
node::{Node, NodeTrait, SyncContext, TypeUuidProvider},
node::{Node, NodeTrait, SyncContext},
Scene,
},
utils::log::Log,
+2 -1
View File
@@ -9,12 +9,13 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
TypeUuidProvider,
},
scene::{
base::{Base, BaseBuilder},
dim2::rigidbody::RigidBody,
graph::Graph,
node::{Node, NodeTrait, SyncContext, TypeUuidProvider},
node::{Node, NodeTrait, SyncContext},
Scene,
},
utils::log::Log,
+9 -8
View File
@@ -12,12 +12,13 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
TypeUuidProvider,
},
resource::texture::Texture,
resource::texture::TextureResource,
scene::{
base::{Base, BaseBuilder},
graph::Graph,
node::{Node, NodeTrait, TypeUuidProvider},
node::{Node, NodeTrait},
},
};
use std::ops::{Deref, DerefMut};
@@ -104,7 +105,7 @@ pub struct Rectangle {
#[reflect(setter = "set_texture")]
#[visit(optional)] // Backward compatibility
texture: InheritableVariable<Option<Texture>>,
texture: InheritableVariable<Option<TextureResource>>,
#[reflect(setter = "set_color")]
color: InheritableVariable<Color>,
@@ -147,17 +148,17 @@ impl TypeUuidProvider for Rectangle {
impl Rectangle {
/// Returns a texture used by the rectangle.
pub fn texture(&self) -> Option<&Texture> {
pub fn texture(&self) -> Option<&TextureResource> {
self.texture.as_ref()
}
/// Returns a texture used by the rectangle.
pub fn texture_value(&self) -> Option<Texture> {
pub fn texture_value(&self) -> Option<TextureResource> {
(*self.texture).clone()
}
/// Sets new texture for the rectangle.
pub fn set_texture(&mut self, texture: Option<Texture>) -> Option<Texture> {
pub fn set_texture(&mut self, texture: Option<TextureResource>) -> Option<TextureResource> {
self.texture.set_value_and_mark_modified(texture)
}
@@ -211,7 +212,7 @@ impl NodeTrait for Rectangle {
/// Allows you to create rectangle in declarative manner.
pub struct RectangleBuilder {
base_builder: BaseBuilder,
texture: Option<Texture>,
texture: Option<TextureResource>,
color: Color,
uv_rect: Rect<f32>,
}
@@ -228,7 +229,7 @@ impl RectangleBuilder {
}
/// Sets desired texture of the rectangle.
pub fn with_texture(mut self, texture: Texture) -> Self {
pub fn with_texture(mut self, texture: TextureResource) -> Self {
self.texture = Some(texture);
self
}
+2 -1
View File
@@ -18,12 +18,13 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
TypeUuidProvider,
},
scene::{
base::{Base, BaseBuilder},
dim2::collider::Collider,
graph::Graph,
node::{Node, NodeTrait, SyncContext, TypeUuidProvider, UpdateContext},
node::{Node, NodeTrait, SyncContext, UpdateContext},
rigidbody::RigidBodyType,
Scene,
},
+7 -6
View File
@@ -22,6 +22,7 @@
//! just by linking nodes to each other. Good example of this is skeleton which
//! is used in skinning (animating 3d model by set of bones).
use crate::resource::model::ModelResourceExtension;
use crate::{
core::{
algebra::{Matrix4, Rotation3, UnitQuaternion, Vector2, Vector3},
@@ -33,7 +34,7 @@ use crate::{
visitor::{Visit, VisitResult, Visitor},
},
material::SharedMaterial,
resource::model::{Model, NodeMapping},
resource::model::{ModelResource, NodeMapping},
scene::{
self,
base::NodeScriptMessage,
@@ -771,7 +772,7 @@ impl Graph {
// if needed and copy surfaces from originals.
for node in self.pool.iter_mut() {
if let Some(model) = node.resource() {
let model = model.state();
let mut model = model.state();
match model.get() {
ResourceStateRef::Ok(data) => {
let resource_graph = &data.get_scene().graph;
@@ -841,7 +842,7 @@ impl Graph {
//
// To do so, we at first, build node handle mapping (original handle -> instance handle) starting from
// instance root. Then we must find all inheritable properties and try to remap them to instance handles.
fn remap_handles(&mut self, instances: &[(Handle<Node>, Model)]) {
fn remap_handles(&mut self, instances: &[(Handle<Node>, ModelResource)]) {
for (instance_root, resource) in instances {
// Prepare old -> new handle mapping first by walking over the graph
// starting from instance root.
@@ -877,7 +878,7 @@ impl Graph {
}
}
fn restore_integrity(&mut self) -> Vec<(Handle<Node>, Model)> {
fn restore_integrity(&mut self) -> Vec<(Handle<Node>, ModelResource)> {
Log::writeln(MessageKind::Information, "Checking integrity...");
// Check integrity - if a node was added in resource, it must be also added in the graph.
@@ -900,7 +901,7 @@ impl Graph {
let mut restored_count = 0;
for (instance_root, resource) in instances.iter().cloned() {
let model = resource.state();
let mut model = resource.state();
if let ResourceStateRef::Ok(data) = model.get() {
let resource_graph = &data.get_scene().graph;
@@ -942,7 +943,7 @@ impl Graph {
);
// Instantiate missing node.
let (copy, old_to_new_mapping) = Model::instantiate_from(
let (copy, old_to_new_mapping) = ModelResource::instantiate_from(
resource.clone(),
data,
resource_node_handle,
+2 -1
View File
@@ -9,11 +9,12 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
TypeUuidProvider,
},
scene::{
base::{Base, BaseBuilder},
graph::Graph,
node::{Node, NodeTrait, SyncContext, TypeUuidProvider},
node::{Node, NodeTrait, SyncContext},
rigidbody::RigidBody,
Scene,
},
+2 -1
View File
@@ -15,12 +15,13 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::{Visit, VisitResult, Visitor},
TypeUuidProvider,
},
scene::{
base::Base,
graph::Graph,
light::{BaseLight, BaseLightBuilder},
node::{Node, NodeTrait, TypeUuidProvider},
node::{Node, NodeTrait},
},
};
use std::ops::{Deref, DerefMut};
+2 -1
View File
@@ -26,13 +26,14 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::{Visit, VisitResult, Visitor},
TypeUuidProvider,
},
scene::{
base::Base,
debug::SceneDrawingContext,
graph::Graph,
light::{BaseLight, BaseLightBuilder},
node::{Node, NodeTrait, TypeUuidProvider},
node::{Node, NodeTrait},
},
};
use std::ops::{Deref, DerefMut};
+12 -8
View File
@@ -32,14 +32,15 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::{Visit, VisitResult, Visitor},
TypeUuidProvider,
},
resource::texture::Texture,
resource::texture::TextureResource,
scene::{
base::Base,
debug::SceneDrawingContext,
graph::Graph,
light::{BaseLight, BaseLightBuilder},
node::{Node, NodeTrait, TypeUuidProvider},
node::{Node, NodeTrait},
},
};
use std::ops::{Deref, DerefMut};
@@ -66,7 +67,7 @@ pub struct SpotLight {
distance: InheritableVariable<f32>,
#[reflect(setter = "set_cookie_texture")]
cookie_texture: InheritableVariable<Option<Texture>>,
cookie_texture: InheritableVariable<Option<TextureResource>>,
}
impl Deref for SpotLight {
@@ -171,21 +172,24 @@ impl SpotLight {
/// Set cookie texture. Also called gobo this texture gets projected
/// by the spot light.
#[inline]
pub fn set_cookie_texture(&mut self, texture: Option<Texture>) -> Option<Texture> {
pub fn set_cookie_texture(
&mut self,
texture: Option<TextureResource>,
) -> Option<TextureResource> {
self.cookie_texture.set_value_and_mark_modified(texture)
}
/// Get cookie texture. Also called gobo this texture gets projected
/// by the spot light.
#[inline]
pub fn cookie_texture(&self) -> Option<Texture> {
pub fn cookie_texture(&self) -> Option<TextureResource> {
(*self.cookie_texture).clone()
}
/// Get cookie texture by ref. Also called gobo this texture gets projected
/// by the spot light.
#[inline]
pub fn cookie_texture_ref(&self) -> Option<&Texture> {
pub fn cookie_texture_ref(&self) -> Option<&TextureResource> {
self.cookie_texture.as_ref()
}
}
@@ -233,7 +237,7 @@ pub struct SpotLightBuilder {
falloff_angle_delta: f32,
shadow_bias: f32,
distance: f32,
cookie_texture: Option<Texture>,
cookie_texture: Option<TextureResource>,
}
impl SpotLightBuilder {
@@ -274,7 +278,7 @@ impl SpotLightBuilder {
}
/// Sets the desired cookie/gobo texture.
pub fn with_cookie_texture(mut self, texture: Texture) -> Self {
pub fn with_cookie_texture(mut self, texture: TextureResource) -> Self {
self.cookie_texture = Some(texture);
self
}
+2 -1
View File
@@ -1,8 +1,9 @@
//! Async scene loader helper. See [`AsyncSceneLoader`] docs for more info.
use crate::{
asset::manager::ResourceManager,
core::parking_lot::Mutex,
engine::{resource_manager::ResourceManager, SerializationContext},
engine::SerializationContext,
scene::{Scene, SceneLoader},
};
use std::{path::PathBuf, sync::Arc};
+2 -1
View File
@@ -18,6 +18,7 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::{Visit, VisitResult, Visitor},
TypeUuidProvider,
},
renderer::{
self,
@@ -32,7 +33,7 @@ use crate::{
buffer::{VertexAttributeUsage, VertexReadTrait},
surface::{BlendShape, Surface},
},
node::{Node, NodeTrait, TypeUuidProvider, UpdateContext},
node::{Node, NodeTrait, UpdateContext},
},
};
use std::{
+4 -3
View File
@@ -4,6 +4,7 @@
//! Surfaces can use the same data source across many instances, this is a memory optimization for
//! being able to re-use data when you need to draw the same mesh in many places.
use crate::resource::texture::TextureResourceExtension;
use crate::{
core::{
algebra::{Matrix4, Point3, Vector2, Vector3, Vector4},
@@ -17,7 +18,7 @@ use crate::{
visitor::{Visit, VisitResult, Visitor},
},
material::{Material, SharedMaterial},
resource::texture::{Texture, TextureKind, TexturePixelKind},
resource::texture::{TextureKind, TexturePixelKind, TextureResource},
scene::{
mesh::{
buffer::{
@@ -63,7 +64,7 @@ pub struct BlendShapesContainer {
/// A list of blend shapes.
pub blend_shapes: Vec<BlendShape>,
/// A volume texture that stores all blend shapes at once.
pub blend_shape_storage: Option<Texture>,
pub blend_shape_storage: Option<TextureResource>,
}
/// A set of offsets for particular vertices.
@@ -173,7 +174,7 @@ impl BlendShapesContainer {
})
.collect(),
blend_shape_storage: Some(
Texture::from_bytes(
TextureResource::from_bytes(
TextureKind::Volume {
width: width * 3,
height,
+16 -210
View File
@@ -30,6 +30,7 @@ pub mod visibility;
use crate::renderer::framework::state::PolygonFillMode;
use crate::{
asset::manager::ResourceManager,
core::{
algebra::Vector2,
color::Color,
@@ -39,12 +40,9 @@ use crate::{
sstorage::ImmutableString,
visitor::{Visit, VisitError, VisitResult, Visitor},
},
engine::{resource_manager::ResourceManager, SerializationContext},
material::{
shader::{SamplerFallback, Shader, STANDARD_SHADER_NAMES},
PropertyValue,
},
resource::{curve::CurveResource, model::Model, texture::Texture},
engine::SerializationContext,
material::{shader::SamplerFallback, PropertyValue},
resource::texture::TextureResource,
scene::{
base::BaseBuilder,
camera::Camera,
@@ -64,8 +62,7 @@ use crate::{
utils::{lightmap::Lightmap, log::Log, log::MessageKind, navmesh::Navmesh},
};
use fxhash::{FxHashMap, FxHashSet};
use fyrox_resource::ResourceStateRef;
use fyrox_sound::buffer::SoundBufferResource;
use fyrox_resource::untyped::UntypedResource;
use std::{
fmt::{Display, Formatter},
ops::{Index, IndexMut},
@@ -166,7 +163,7 @@ pub struct Scene {
/// monitor. Other usage could be previewer of models, like pictogram of character
/// in real-time strategies, in other words there are plenty of possible uses.
#[reflect(hidden)]
pub render_target: Option<Texture>,
pub render_target: Option<TextureResource>,
/// Drawing context for simple graphics.
#[reflect(hidden)]
@@ -254,190 +251,16 @@ pub struct SceneLoader {
#[derive(Default)]
struct UsedResourcesSet {
models: FxHashSet<Model>,
curves: FxHashSet<CurveResource>,
shaders: FxHashSet<Shader>,
textures: FxHashSet<Texture>,
sound_buffers: FxHashSet<SoundBufferResource>,
models: FxHashSet<UntypedResource>,
}
impl UsedResourcesSet {
/// Waits asynchronously.
async fn wait_async(self) {
join_all(self.curves).await;
join_all(self.shaders).await;
join_all(self.textures).await;
join_all(self.sound_buffers).await;
join_all(self.models).await;
}
}
fn restore_resources(
entity: &mut dyn Reflect,
resource_manager: &ResourceManager,
used_resources: &mut UsedResourcesSet,
) {
let mut mapped = false;
entity.as_inheritable_variable_mut(&mut |result| {
if let Some(inheritable) = result {
restore_resources(
inheritable.inner_value_mut(),
resource_manager,
used_resources,
);
mapped = true;
}
});
if !mapped {
entity.as_hash_map_mut(&mut |result| {
if let Some(hash_map) = result {
let len = hash_map.reflect_len();
for i in 0..len {
let (_, value) = hash_map
.reflect_get_at_mut(i)
.expect("Hash maps cannot have sparse structure!");
restore_resources(value, resource_manager, used_resources)
}
mapped = true;
}
});
}
if !mapped {
entity.as_array_mut(&mut |result| {
if let Some(array) = result {
let len = array.reflect_len();
for i in 0..len {
// Support sparse arrays (Pool) too.
if let Some(value) = array.reflect_index_mut(i) {
restore_resources(value, resource_manager, used_resources)
}
}
mapped = true;
}
});
}
if !mapped {
// Textures are special - there could be procedural textures which must not be resolved.
entity.downcast_mut::<Texture>(&mut |result| {
if let Some(texture) = result {
let data_guard = texture.state();
match data_guard.get() {
// Try to restore the texture even if it failed to load or loading.
ResourceStateRef::LoadError { .. } | ResourceStateRef::Pending { .. } => {
drop(data_guard);
resource_manager
.state()
.containers_mut()
.textures
.try_restore_resource(texture);
}
ResourceStateRef::Ok(texture_state) => {
// Do not resolve procedural textures.
if !texture_state.is_procedural() {
drop(data_guard);
resource_manager
.state()
.containers_mut()
.textures
.try_restore_resource(texture);
}
}
}
used_resources.textures.insert(texture.clone());
mapped = true;
}
});
}
if !mapped {
entity.downcast_mut::<Model>(&mut |result| {
if let Some(model) = result {
resource_manager
.state()
.containers_mut()
.models
.try_restore_resource(model);
used_resources.models.insert(model.clone());
mapped = true;
}
});
}
if !mapped {
entity.downcast_mut::<SoundBufferResource>(&mut |result| {
if let Some(sound_buffer) = result {
resource_manager
.state()
.containers_mut()
.sound_buffers
.try_restore_resource(sound_buffer);
used_resources.sound_buffers.insert(sound_buffer.clone());
mapped = true;
}
});
}
if !mapped {
entity.downcast_mut::<Shader>(&mut |result| {
if let Some(shader) = result {
let shader_path = shader.state().path().to_path_buf();
// Do not try to restore any of the built-in standard shaders.
if STANDARD_SHADER_NAMES
.iter()
.all(|name| Path::new(*name) != shader_path)
{
resource_manager
.state()
.containers_mut()
.shaders
.try_restore_resource(shader);
used_resources.shaders.insert(shader.clone());
}
mapped = true;
}
});
}
if !mapped {
entity.downcast_mut::<CurveResource>(&mut |result| {
if let Some(curve) = result {
resource_manager
.state()
.containers_mut()
.curves
.try_restore_resource(curve);
used_resources.curves.insert(curve.clone());
mapped = true;
}
});
}
entity.fields_mut(&mut |fields| {
for field in fields {
// Continue resolving.
restore_resources(field, resource_manager, used_resources);
}
})
}
impl SceneLoader {
/// Tries to load scene from given file. File can contain any scene in native engine format.
/// Such scenes can be made in rusty editor.
@@ -461,7 +284,7 @@ impl SceneLoader {
));
}
visitor.environment = Some(serialization_context);
visitor.blackboard.register(serialization_context);
let mut scene = Scene::default();
scene.visit(region_name, visitor)?;
@@ -473,32 +296,15 @@ impl SceneLoader {
pub async fn finish(self, resource_manager: ResourceManager) -> Scene {
let mut scene = self.scene;
// Collect all model resources and wait for them. This step is crucial, because
// later on resolve stage we'll extensively access parent resources to inherit
// data from them and we can't read data of a resource being loading.
let mut used_resources = UsedResourcesSet::default();
for node in scene.graph.linear_iter_mut() {
restore_resources(
node as &mut dyn Reflect,
&resource_manager,
&mut used_resources,
);
}
// Wait everything.
used_resources.wait_async().await;
if let Some(lightmap) = scene.lightmap.as_mut() {
for entries in lightmap.map.values_mut() {
for entry in entries.iter_mut() {
resource_manager
.state()
.containers_mut()
.textures
.try_restore_optional_resource(&mut entry.texture);
}
}
}
let resource_handles = resource_manager
.state()
.containers()
.resources
.iter()
.cloned()
.collect::<Vec<_>>();
join_all(resource_handles.into_iter()).await;
// TODO: Move into Camera::restore_resources?
// We have to wait until skybox textures are all loaded, because we need to read their data
+3 -8
View File
@@ -1,22 +1,17 @@
#![allow(missing_docs)] // TODO
use crate::scene::base::BaseBuilder;
use crate::scene::graph::Graph;
use crate::scene::node::Node;
use crate::{
core::{
math::aabb::AxisAlignedBoundingBox,
pool::Handle,
reflect::prelude::*,
uuid::{uuid, Uuid},
visitor::prelude::*,
TypeUuidProvider,
},
scene::{
base::Base,
node::{NodeTrait, TypeUuidProvider},
},
scene::{base::Base, base::BaseBuilder, graph::Graph, node::Node, node::NodeTrait},
utils::navmesh::Navmesh,
};
use fyrox_core::pool::Handle;
use std::ops::{Deref, DerefMut};
#[derive(Debug, Clone, Visit, Reflect, Default)]
+2 -2
View File
@@ -1,7 +1,7 @@
//! A special container that is able to create nodes by their type UUID.
use crate::{
core::{parking_lot::Mutex, uuid::Uuid},
core::{parking_lot::Mutex, uuid::Uuid, TypeUuidProvider},
scene::{
self,
animation::{absm::AnimationBlendingStateMachine, AnimationPlayer},
@@ -11,7 +11,7 @@ use crate::{
light::{directional::DirectionalLight, point::PointLight, spot::SpotLight},
mesh::Mesh,
navmesh::NavigationalMesh,
node::{Node, NodeTrait, TypeUuidProvider},
node::{Node, NodeTrait},
particle_system::ParticleSystem,
pivot::Pivot,
sound::{listener::Listener, Sound},
+2 -3
View File
@@ -92,9 +92,8 @@ fn read_node(name: &str, visitor: &mut Visitor) -> Result<Node, VisitError> {
id.visit("TypeUuid", &mut region)?;
let serialization_context = region
.environment
.as_ref()
.and_then(|e| e.downcast_ref::<SerializationContext>())
.blackboard
.get::<SerializationContext>()
.expect("Visitor environment must contain serialization context!");
let mut node = serialization_context
-6
View File
@@ -41,12 +41,6 @@ use std::{
pub mod constructor;
pub mod container;
/// A trait for an entity that has unique type identifier.
pub trait TypeUuidProvider: Sized {
/// Return type UUID.
fn type_uuid() -> Uuid;
}
/// A set of useful methods that is possible to auto-implement.
pub trait BaseNodeTrait: Any + Debug + Deref<Target = Base> + DerefMut + Send {
/// This method creates raw copy of a node, it should never be called in normal circumstances
+10 -9
View File
@@ -81,13 +81,14 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
TypeUuidProvider,
},
rand::{prelude::StdRng, SeedableRng},
resource::texture::Texture,
resource::texture::TextureResource,
scene::{
base::{Base, BaseBuilder},
graph::Graph,
node::{Node, NodeTrait, TypeUuidProvider, UpdateContext},
node::{Node, NodeTrait, UpdateContext},
particle_system::{
draw::{DrawData, Vertex},
emitter::{Emit, Emitter},
@@ -207,7 +208,7 @@ pub struct ParticleSystem {
pub emitters: InheritableVariable<Vec<EmitterWrapper>>,
#[reflect(setter = "set_texture")]
texture: InheritableVariable<Option<Texture>>,
texture: InheritableVariable<Option<TextureResource>>,
#[reflect(setter = "set_acceleration")]
acceleration: InheritableVariable<Vector3<f32>>,
@@ -408,17 +409,17 @@ impl ParticleSystem {
}
/// Sets new texture for particle system.
pub fn set_texture(&mut self, texture: Option<Texture>) -> Option<Texture> {
pub fn set_texture(&mut self, texture: Option<TextureResource>) -> Option<TextureResource> {
self.texture.set_value_and_mark_modified(texture)
}
/// Returns current texture used by particle system.
pub fn texture(&self) -> Option<Texture> {
pub fn texture(&self) -> Option<TextureResource> {
(*self.texture).clone()
}
/// Returns current texture used by particle system by ref.
pub fn texture_ref(&self) -> Option<&Texture> {
pub fn texture_ref(&self) -> Option<&TextureResource> {
self.texture.as_ref()
}
@@ -526,7 +527,7 @@ impl NodeTrait for ParticleSystem {
pub struct ParticleSystemBuilder {
base_builder: BaseBuilder,
emitters: Vec<EmitterWrapper>,
texture: Option<Texture>,
texture: Option<TextureResource>,
acceleration: Vector3<f32>,
particles: Vec<Particle>,
color_over_lifetime: ColorGradient,
@@ -558,13 +559,13 @@ impl ParticleSystemBuilder {
}
/// Sets desired texture for particle system.
pub fn with_texture(mut self, texture: Texture) -> Self {
pub fn with_texture(mut self, texture: TextureResource) -> Self {
self.texture = Some(texture);
self
}
/// Sets desired texture for particle system.
pub fn with_opt_texture(mut self, texture: Option<Texture>) -> Self {
pub fn with_opt_texture(mut self, texture: Option<TextureResource>) -> Self {
self.texture = texture;
self
}
+2 -1
View File
@@ -6,11 +6,12 @@ use crate::{
reflect::prelude::*,
uuid::{uuid, Uuid},
visitor::prelude::*,
TypeUuidProvider,
},
scene::{
base::{Base, BaseBuilder},
graph::Graph,
node::{Node, NodeTrait, TypeUuidProvider},
node::{Node, NodeTrait},
},
};
use std::ops::{Deref, DerefMut};
+2 -1
View File
@@ -18,12 +18,13 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
TypeUuidProvider,
},
scene::{
base::{Base, BaseBuilder},
collider::Collider,
graph::Graph,
node::{Node, NodeTrait, SyncContext, TypeUuidProvider, UpdateContext},
node::{Node, NodeTrait, SyncContext, UpdateContext},
Scene,
},
utils::log::Log,
+2 -1
View File
@@ -10,11 +10,12 @@ use crate::{
reflect::prelude::*,
uuid::{uuid, Uuid},
visitor::prelude::*,
TypeUuidProvider,
},
scene::{
base::{Base, BaseBuilder},
graph::Graph,
node::{Node, NodeTrait, SyncContext, TypeUuidProvider},
node::{Node, NodeTrait, SyncContext},
},
};
use std::ops::{Deref, DerefMut};
+5 -4
View File
@@ -9,18 +9,19 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::prelude::*,
TypeUuidProvider,
},
define_with,
scene::{
base::{Base, BaseBuilder},
graph::Graph,
node::{Node, NodeTrait, SyncContext, TypeUuidProvider, UpdateContext},
node::{Node, NodeTrait, SyncContext, UpdateContext},
},
};
// Re-export some the fyrox_sound entities.
pub use fyrox_sound::{
buffer::{DataSource, SoundBufferResource, SoundBufferResourceLoadError, SoundBufferState},
buffer::{DataSource, SoundBuffer, SoundBufferResource, SoundBufferResourceLoadError},
bus::*,
context::{DistanceModel, SAMPLE_RATE},
dsp::{filters::*, DelayLine},
@@ -400,7 +401,7 @@ impl NodeTrait for Sound {
fn validate(&self, _scene: &Scene) -> Result<(), String> {
match self.buffer.as_ref() {
Some(buffer) => {
let state = buffer.state();
let mut state = buffer.state();
match state.get() {
ResourceStateRef::Pending { .. } | ResourceStateRef::Ok(_) => Ok(()),
ResourceStateRef::LoadError { error, .. } => {
@@ -409,7 +410,7 @@ impl NodeTrait for Sound {
.to_string()),
Some(err) => Err(format!(
"Sound buffer is failed to load. Reason: {:?}",
**err
*err
)),
}
}
+10 -9
View File
@@ -11,12 +11,13 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::{Visit, VisitResult, Visitor},
TypeUuidProvider,
},
resource::texture::Texture,
resource::texture::TextureResource,
scene::{
base::{Base, BaseBuilder},
graph::Graph,
node::{Node, NodeTrait, TypeUuidProvider},
node::{Node, NodeTrait},
},
};
use std::ops::{Deref, DerefMut};
@@ -65,7 +66,7 @@ pub struct Sprite {
base: Base,
#[reflect(setter = "set_texture")]
texture: InheritableVariable<Option<Texture>>,
texture: InheritableVariable<Option<TextureResource>>,
#[reflect(setter = "set_color")]
color: InheritableVariable<Color>,
@@ -139,17 +140,17 @@ impl Sprite {
}
/// Sets new texture for sprite. Default is None.
pub fn set_texture(&mut self, texture: Option<Texture>) -> Option<Texture> {
pub fn set_texture(&mut self, texture: Option<TextureResource>) -> Option<TextureResource> {
self.texture.set_value_and_mark_modified(texture)
}
/// Returns current texture of sprite. Can be None if sprite has no texture.
pub fn texture(&self) -> Option<Texture> {
pub fn texture(&self) -> Option<TextureResource> {
(*self.texture).clone()
}
/// Returns current texture of sprite by ref. Can be None if sprite has no texture.
pub fn texture_ref(&self) -> Option<&Texture> {
pub fn texture_ref(&self) -> Option<&TextureResource> {
self.texture.as_ref()
}
}
@@ -174,7 +175,7 @@ impl NodeTrait for Sprite {
/// This is typical implementation of Builder pattern.
pub struct SpriteBuilder {
base_builder: BaseBuilder,
texture: Option<Texture>,
texture: Option<TextureResource>,
color: Color,
size: f32,
rotation: f32,
@@ -193,13 +194,13 @@ impl SpriteBuilder {
}
/// Sets desired texture.
pub fn with_texture(mut self, texture: Texture) -> Self {
pub fn with_texture(mut self, texture: TextureResource) -> Self {
self.texture = Some(texture);
self
}
/// Sets desired texture.
pub fn with_opt_texture(mut self, texture: Option<Texture>) -> Self {
pub fn with_opt_texture(mut self, texture: Option<TextureResource>) -> Self {
self.texture = texture;
self
}
+20 -18
View File
@@ -1,5 +1,6 @@
//! Everything related to terrains.
use crate::resource::texture::TextureResourceExtension;
use crate::{
asset::Resource,
core::{
@@ -12,6 +13,7 @@ use crate::{
uuid::{uuid, Uuid},
variable::InheritableVariable,
visitor::{prelude::*, PodVecView},
TypeUuidProvider,
},
material::{Material, PropertyValue, SharedMaterial},
renderer::{
@@ -19,13 +21,13 @@ use crate::{
batch::{RenderContext, SurfaceInstanceData},
framework::geometry_buffer::ElementRange,
},
resource::texture::{Texture, TextureData, TextureKind, TexturePixelKind, TextureWrapMode},
resource::texture::{Texture, TextureKind, TexturePixelKind, TextureResource, TextureWrapMode},
scene::{
base::{Base, BaseBuilder},
debug::SceneDrawingContext,
graph::Graph,
mesh::RenderPath,
node::{Node, NodeTrait, TypeUuidProvider},
node::{Node, NodeTrait},
terrain::{geometry::TerrainGeometry, quadtree::QuadTree},
},
utils::{self, log::Log},
@@ -77,7 +79,7 @@ impl Default for Layer {
}
fn make_quad_tree(
texture: &Option<Texture>,
texture: &Option<TextureResource>,
height_map_size: Vector2<u32>,
block_size: Vector2<u32>,
) -> QuadTree {
@@ -86,8 +88,8 @@ fn make_quad_tree(
QuadTree::new(height_map, height_map_size, block_size)
}
fn make_height_map_texture(height_map: Vec<f32>, size: Vector2<u32>) -> Texture {
let mut data = TextureData::from_bytes(
fn make_height_map_texture(height_map: Vec<f32>, size: Vector2<u32>) -> TextureResource {
let mut data = Texture::from_bytes(
TextureKind::Rectangle {
width: size.x,
height: size.y,
@@ -101,7 +103,7 @@ fn make_height_map_texture(height_map: Vec<f32>, size: Vector2<u32>) -> Texture
data.set_t_wrap_mode(TextureWrapMode::ClampToEdge);
data.set_s_wrap_mode(TextureWrapMode::ClampToEdge);
Texture(Resource::new_ok(data))
Resource::new_ok(data)
}
/// Chunk is smaller block of a terrain. Terrain can have as many chunks as you need.
@@ -116,7 +118,7 @@ pub struct Chunk {
#[reflect(hidden)]
version: u8,
#[reflect(hidden)]
heightmap: Option<Texture>,
heightmap: Option<TextureResource>,
#[reflect(hidden)]
position: Vector3<f32>,
#[reflect(hidden)]
@@ -129,7 +131,7 @@ pub struct Chunk {
grid_position: Vector2<i32>,
/// Layer blending masks of the chunk.
#[reflect(hidden)]
pub layer_masks: Vec<Texture>,
pub layer_masks: Vec<TextureResource>,
}
impl Clone for Chunk {
@@ -237,7 +239,7 @@ impl Chunk {
}
/// Returns a reference to height map.
pub fn heightmap(&self) -> &Texture {
pub fn heightmap(&self) -> &TextureResource {
self.heightmap.as_ref().unwrap()
}
@@ -253,7 +255,7 @@ impl Chunk {
}
/// Sets new height map. New height map must be equal with size of current.
pub fn set_heightmap(&mut self, heightmap: Texture) -> Result<(), Texture> {
pub fn set_heightmap(&mut self, heightmap: TextureResource) -> Result<(), TextureResource> {
let data = heightmap.data_ref();
if let TextureKind::Rectangle { width, height } = data.kind() {
if data.pixel_kind() == TexturePixelKind::R32F
@@ -405,7 +407,7 @@ impl Default for Terrain {
struct OldLayer {
pub material: SharedMaterial,
pub mask_property_name: String,
pub chunk_masks: Vec<Texture>,
pub chunk_masks: Vec<TextureResource>,
}
impl Default for OldLayer {
@@ -964,12 +966,12 @@ impl Terrain {
/// Adds new layer to the chunk. It is possible to have different layer count per chunk
/// in the same terrain, however it seems to not have practical usage, so try to keep
/// equal layer count per each chunk in your terrains.
pub fn add_layer(&mut self, layer: Layer, masks: Vec<Texture>) {
pub fn add_layer(&mut self, layer: Layer, masks: Vec<TextureResource>) {
self.insert_layer(layer, masks, self.layers.len())
}
/// Removes a layer at the given index together with its respective blending masks from each chunk.
pub fn remove_layer(&mut self, layer_index: usize) -> (Layer, Vec<Texture>) {
pub fn remove_layer(&mut self, layer_index: usize) -> (Layer, Vec<TextureResource>) {
let layer = self
.layers
.get_value_mut_and_mark_modified()
@@ -982,7 +984,7 @@ impl Terrain {
}
/// Removes last terrain layer together with its respective blending masks from each chunk.
pub fn pop_layer(&mut self) -> Option<(Layer, Vec<Texture>)> {
pub fn pop_layer(&mut self) -> Option<(Layer, Vec<TextureResource>)> {
if self.layers.is_empty() {
None
} else {
@@ -991,7 +993,7 @@ impl Terrain {
}
/// Inserts the layer at the given index together with its blending masks for each chunk.
pub fn insert_layer(&mut self, layer: Layer, mut masks: Vec<Texture>, index: usize) {
pub fn insert_layer(&mut self, layer: Layer, mut masks: Vec<TextureResource>, index: usize) {
self.layers
.get_value_mut_and_mark_modified()
.insert(index, layer);
@@ -1034,7 +1036,7 @@ impl Terrain {
);
let new_mask = resampled_mask_image.into_raw();
let new_mask_texture = Texture::from_bytes(
let new_mask_texture = TextureResource::from_bytes(
TextureKind::Rectangle {
width: new_size.x,
height: new_size.y,
@@ -1374,8 +1376,8 @@ pub struct TerrainBuilder {
decal_layer_index: u8,
}
fn create_layer_mask(width: u32, height: u32, value: u8) -> Texture {
let mask = Texture::from_bytes(
fn create_layer_mask(width: u32, height: u32, value: u8) -> TextureResource {
let mask = TextureResource::from_bytes(
TextureKind::Rectangle { width, height },
TexturePixelKind::R8,
vec![value; (width * height) as usize],
+1 -1
View File
@@ -4,8 +4,8 @@ use crate::{
core::{
parking_lot::{Mutex, MutexGuard},
uuid::Uuid,
TypeUuidProvider,
},
scene::node::TypeUuidProvider,
script::{Script, ScriptTrait},
};
use std::collections::BTreeMap;
+3 -3
View File
@@ -3,13 +3,14 @@
//! Script is used to add custom logic to scene nodes. See [ScriptTrait] for more info.
use crate::{
asset::manager::ResourceManager,
core::{
pool::Handle,
reflect::{FieldInfo, Reflect, ReflectArray, ReflectList},
uuid::Uuid,
visitor::{Visit, VisitResult, Visitor},
},
engine::{resource_manager::ResourceManager, ScriptMessageDispatcher},
engine::ScriptMessageDispatcher,
event::Event,
plugin::Plugin,
scene::{node::Node, Scene},
@@ -391,8 +392,7 @@ pub trait ScriptTrait: BaseScript + ComponentProvider {
/// ```rust
/// use std::str::FromStr;
/// use fyrox::{
/// scene::node::TypeUuidProvider,
/// core::visitor::prelude::*,
/// /// core::visitor::prelude::*,
/// core::reflect::prelude::*,
/// core::uuid::Uuid,
/// script::ScriptTrait,
+20 -10
View File
@@ -9,9 +9,8 @@
#![forbid(unsafe_code)]
use crate::material::PropertyValue;
use crate::{
asset::Resource,
asset::manager::{ResourceManager, ResourceRegistrationError},
core::{
algebra::{Matrix3, Matrix4, Point3, Vector2, Vector3, Vector4},
arrayvec::ArrayVec,
@@ -20,8 +19,8 @@ use crate::{
pool::Handle,
visitor::{Visit, VisitResult, Visitor},
},
engine::resource_manager::{ResourceManager, TextureRegistrationError},
resource::texture::{Texture, TextureData, TextureKind, TexturePixelKind},
material::PropertyValue,
resource::texture::{Texture, TextureKind, TexturePixelKind, TextureResource},
scene::{
light::{directional::DirectionalLight, point::PointLight, spot::SpotLight},
mesh::{
@@ -55,7 +54,7 @@ pub struct LightmapEntry {
/// TODO: Is single texture enough? There may be surfaces with huge amount of faces
/// which may not fit into texture, because there is hardware limit on most GPUs
/// up to 8192x8192 pixels.
pub texture: Option<Texture>,
pub texture: Option<TextureResource>,
/// List of lights that were used to generate this lightmap. This list is used for
/// masking when applying dynamic lights for surfaces with light, it prevents double
/// lighting.
@@ -457,7 +456,7 @@ impl Lightmap {
let lightmap = generate_lightmap(instance, &instances, &lights, texels_per_unit);
map.entry(instance.owner).or_default().push(LightmapEntry {
texture: Some(Texture(Resource::new_ok(lightmap))),
texture: Some(TextureResource::new_ok(lightmap)),
lights: lights.iter().map(|light| light.handle()).collect(),
});
@@ -472,7 +471,7 @@ impl Lightmap {
&self,
base_path: P,
resource_manager: ResourceManager,
) -> Result<(), TextureRegistrationError> {
) -> Result<(), ResourceRegistrationError> {
if !base_path.as_ref().exists() {
std::fs::create_dir(base_path.as_ref()).unwrap();
}
@@ -482,7 +481,18 @@ impl Lightmap {
for (i, entry) in entries.iter().enumerate() {
let file_path = handle_path.clone() + "_" + i.to_string().as_str() + ".png";
let texture = entry.texture.clone().unwrap();
resource_manager.register_texture(texture, base_path.as_ref().join(file_path))?;
resource_manager.register(
texture.into_inner(),
base_path.as_ref().join(file_path),
|texture, _| {
texture
.as_any()
.downcast_ref::<Texture>()
.unwrap()
.save()
.is_ok()
},
)?;
}
}
Ok(())
@@ -707,7 +717,7 @@ fn generate_lightmap(
other_instances: &[Instance],
lights: &[LightDefinition],
texels_per_unit: u32,
) -> TextureData {
) -> Texture {
// We have to re-generate new set of world-space vertices because UV generator
// may add new vertices on seams.
let atlas_size = estimate_size(instance.data(), texels_per_unit);
@@ -895,7 +905,7 @@ fn generate_lightmap(
}
}
TextureData::from_bytes(
Texture::from_bytes(
TextureKind::Rectangle {
width: atlas_size,
height: atlas_size,
+3 -3
View File
@@ -18,7 +18,7 @@ use crate::{
draw,
message::{ButtonState, KeyCode, KeyboardModifiers, OsEvent},
},
resource::texture::Texture,
resource::texture::TextureResource,
};
use fyrox_core::algebra::Vector3;
use half::f16;
@@ -474,8 +474,8 @@ pub fn into_any_arc<T: Any + Send + Sync>(
}
/// Converts engine's optional texture "pointer" to fyrox-ui's.
pub fn into_gui_texture(this: Texture) -> draw::SharedTexture {
draw::SharedTexture(this.0.into_inner())
pub fn into_gui_texture(this: TextureResource) -> draw::SharedTexture {
draw::SharedTexture(this.into_inner().0)
}
/// "Transmutes" array of any sized type to a slice of bytes.