TextureCopy render graph node, texture_resource_system
Removed textures are now freed
This commit is contained in:
parent
33d4d5f562
commit
c5a78d4616
1
.vscode/launch.json
vendored
1
.vscode/launch.json
vendored
@ -1809,6 +1809,7 @@
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug example 'text'",
|
||||
"env": { "CARGO_MANIFEST_DIR": "${workspaceFolder}" },
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
update_asset_storage_system, AssetChannel, AssetLoader, AssetServer, ChannelAssetHandler,
|
||||
Handle, HandleId,
|
||||
};
|
||||
use bevy_app::{stage, AppBuilder, Events};
|
||||
use bevy_app::{AppBuilder, Events};
|
||||
use bevy_core::bytes::GetBytes;
|
||||
use legion::prelude::*;
|
||||
use std::{
|
||||
@ -146,7 +146,10 @@ impl AddAsset for AppBuilder {
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
self.init_resource::<Assets<T>>()
|
||||
.add_system_to_stage(stage::POST_UPDATE, Assets::<T>::asset_event_system.system())
|
||||
.add_system_to_stage(
|
||||
super::stage::ASSET_EVENTS,
|
||||
Assets::<T>::asset_event_system.system(),
|
||||
)
|
||||
.add_event::<AssetEvent<T>>()
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
mod asset_server;
|
||||
mod assets;
|
||||
#[cfg(feature = "filesystem_watcher")]
|
||||
pub mod filesystem_watcher;
|
||||
mod handle;
|
||||
mod load_request;
|
||||
mod loader;
|
||||
#[cfg(feature = "filesystem_watcher")]
|
||||
pub mod filesystem_watcher;
|
||||
|
||||
pub use asset_server::*;
|
||||
pub use assets::*;
|
||||
@ -17,6 +17,7 @@ use legion::prelude::IntoSystem;
|
||||
|
||||
pub mod stage {
|
||||
pub const LOAD_ASSETS: &str = "load_assets";
|
||||
pub const ASSET_EVENTS: &str = "asset_events";
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@ -24,9 +25,13 @@ pub struct AssetPlugin;
|
||||
|
||||
impl AppPlugin for AssetPlugin {
|
||||
fn build(&self, app: &mut AppBuilder) {
|
||||
app.add_stage_before(bevy_app::stage::PRE_UPDATE, stage::LOAD_ASSETS)
|
||||
app.add_stage_before(bevy_app::stage::PRE_UPDATE, stage::LOAD_ASSETS)
|
||||
.add_stage_after(bevy_app::stage::POST_UPDATE, stage::ASSET_EVENTS)
|
||||
.init_resource::<AssetServer>();
|
||||
#[cfg(feature = "filesystem_watcher")]
|
||||
app.add_system_to_stage(stage::LOAD_ASSETS, AssetServer::filesystem_watcher_system.system());
|
||||
app.add_system_to_stage(
|
||||
stage::LOAD_ASSETS,
|
||||
AssetServer::filesystem_watcher_system.system(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ struct EntityArchetypeAttributeArgs {
|
||||
pub tag: Option<bool>,
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Resource)]
|
||||
#[proc_macro_derive(Resource, attributes(module))]
|
||||
pub fn derive_resource(input: TokenStream) -> TokenStream {
|
||||
let ast = parse_macro_input!(input as DeriveInput);
|
||||
let fields = match &ast.data {
|
||||
|
@ -4,13 +4,19 @@ use crate::{
|
||||
RenderPassDepthStencilAttachmentDescriptor, StoreOp, TextureAttachment,
|
||||
},
|
||||
render_graph::{
|
||||
nodes::{Camera2dNode, CameraNode, PassNode, WindowSwapChainNode, WindowTextureNode},
|
||||
nodes::{
|
||||
Camera2dNode, CameraNode, PassNode, TextureCopyNode, WindowSwapChainNode,
|
||||
WindowTextureNode,
|
||||
},
|
||||
RenderGraph,
|
||||
},
|
||||
texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage},
|
||||
texture::{
|
||||
Extent3d, Texture, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage,
|
||||
},
|
||||
Color,
|
||||
};
|
||||
use bevy_app::GetEventReader;
|
||||
use bevy_asset::AssetEvent;
|
||||
use bevy_window::{WindowCreated, WindowReference, WindowResized};
|
||||
use legion::prelude::Resources;
|
||||
|
||||
@ -27,6 +33,7 @@ pub mod node {
|
||||
pub const PRIMARY_SWAP_CHAIN: &str = "swapchain";
|
||||
pub const CAMERA: &str = "camera";
|
||||
pub const CAMERA2D: &str = "camera2d";
|
||||
pub const TEXTURE_COPY: &str = "texture_copy";
|
||||
pub const MAIN_DEPTH_TEXTURE: &str = "main_pass_depth_texture";
|
||||
pub const MAIN_PASS: &str = "main_pass";
|
||||
}
|
||||
@ -60,6 +67,10 @@ impl BaseRenderGraphBuilder for RenderGraph {
|
||||
resources: &Resources,
|
||||
config: &BaseRenderGraphConfig,
|
||||
) -> &mut Self {
|
||||
self.add_node(
|
||||
node::TEXTURE_COPY,
|
||||
TextureCopyNode::new(resources.get_event_reader::<AssetEvent<Texture>>()),
|
||||
);
|
||||
if config.add_3d_camera {
|
||||
self.add_system_node(node::CAMERA, CameraNode::default());
|
||||
}
|
||||
@ -115,6 +126,8 @@ impl BaseRenderGraphBuilder for RenderGraph {
|
||||
}),
|
||||
);
|
||||
|
||||
self.add_node_edge(node::TEXTURE_COPY, node::MAIN_PASS)
|
||||
.unwrap();
|
||||
if config.add_3d_camera {
|
||||
self.add_node_edge(node::CAMERA, node::MAIN_PASS).unwrap();
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ use legion::prelude::IntoSystem;
|
||||
use mesh::mesh_resource_provider_system;
|
||||
use render_graph::RenderGraph;
|
||||
use render_resource::EntitiesWaitingForAssets;
|
||||
use texture::PngTextureLoader;
|
||||
use texture::{PngTextureLoader, TextureResourceSystemState};
|
||||
|
||||
pub static RENDER_RESOURCE_STAGE: &str = "render_resource";
|
||||
pub static RENDER_STAGE: &str = "render";
|
||||
@ -66,31 +66,37 @@ impl Default for RenderPlugin {
|
||||
|
||||
impl AppPlugin for RenderPlugin {
|
||||
fn build(&self, app: &mut AppBuilder) {
|
||||
let mut render_graph = RenderGraph::default();
|
||||
if let Some(ref config) = self.base_render_graph_config {
|
||||
render_graph.add_base_graph(app.resources(), config);
|
||||
}
|
||||
|
||||
app.add_stage_after(stage::POST_UPDATE, RENDER_RESOURCE_STAGE)
|
||||
app.add_stage_after(bevy_asset::stage::ASSET_EVENTS, RENDER_RESOURCE_STAGE)
|
||||
.add_stage_after(RENDER_RESOURCE_STAGE, RENDER_STAGE)
|
||||
.add_asset::<Mesh>()
|
||||
.add_asset::<Texture>()
|
||||
.add_asset::<Shader>()
|
||||
.add_asset::<PipelineDescriptor>()
|
||||
.add_asset_loader(PngTextureLoader::default())
|
||||
.add_resource(render_graph)
|
||||
.init_resource::<RenderGraph>()
|
||||
.init_resource::<PipelineAssignments>()
|
||||
.init_resource::<PipelineCompiler>()
|
||||
.init_resource::<RenderResourceAssignments>()
|
||||
.init_resource::<VertexBufferDescriptors>()
|
||||
.init_resource::<EntityRenderResourceAssignments>()
|
||||
.init_resource::<EntitiesWaitingForAssets>()
|
||||
.init_resource::<TextureResourceSystemState>()
|
||||
.add_system(entity_render_resource_assignments_system())
|
||||
.init_system_to_stage(stage::POST_UPDATE, camera::camera_update_system)
|
||||
.add_system_to_stage(
|
||||
stage::PRE_UPDATE,
|
||||
EntitiesWaitingForAssets::clear_system.system(),
|
||||
)
|
||||
.init_system_to_stage(RENDER_RESOURCE_STAGE, mesh_resource_provider_system);
|
||||
.init_system_to_stage(RENDER_RESOURCE_STAGE, mesh_resource_provider_system)
|
||||
.add_system_to_stage(
|
||||
RENDER_RESOURCE_STAGE,
|
||||
Texture::texture_resource_system.system(),
|
||||
);
|
||||
|
||||
if let Some(ref config) = self.base_render_graph_config {
|
||||
let resources = app.resources();
|
||||
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
|
||||
render_graph.add_base_graph(resources, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ mod pass_node;
|
||||
mod uniform_node;
|
||||
mod window_swapchain_node;
|
||||
mod window_texture_node;
|
||||
mod texture_copy_node;
|
||||
|
||||
pub use camera2d_node::*;
|
||||
pub use camera_node::*;
|
||||
@ -11,3 +12,4 @@ pub use pass_node::*;
|
||||
pub use uniform_node::*;
|
||||
pub use window_swapchain_node::*;
|
||||
pub use window_texture_node::*;
|
||||
pub use texture_copy_node::*;
|
||||
|
@ -0,0 +1,71 @@
|
||||
use crate::{
|
||||
render_graph::{Node, ResourceSlots},
|
||||
render_resource::{BufferInfo, BufferUsage},
|
||||
renderer::RenderContext,
|
||||
texture::{Texture, TextureDescriptor, TEXTURE_ASSET_INDEX},
|
||||
};
|
||||
use bevy_app::{EventReader, Events};
|
||||
use bevy_asset::{AssetEvent, Assets};
|
||||
|
||||
use legion::prelude::*;
|
||||
|
||||
pub struct TextureCopyNode {
|
||||
pub texture_event_reader: EventReader<AssetEvent<Texture>>,
|
||||
}
|
||||
|
||||
impl TextureCopyNode {
|
||||
pub fn new(texture_event_reader: EventReader<AssetEvent<Texture>>) -> Self {
|
||||
TextureCopyNode {
|
||||
texture_event_reader,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for TextureCopyNode {
|
||||
fn update(
|
||||
&mut self,
|
||||
_world: &World,
|
||||
resources: &Resources,
|
||||
render_context: &mut dyn RenderContext,
|
||||
_input: &ResourceSlots,
|
||||
_output: &mut ResourceSlots,
|
||||
) {
|
||||
let texture_events = resources.get::<Events<AssetEvent<Texture>>>().unwrap();
|
||||
let textures = resources.get::<Assets<Texture>>().unwrap();
|
||||
for event in self.texture_event_reader.iter(&texture_events) {
|
||||
match event {
|
||||
AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
|
||||
if let Some(texture) = textures.get(&handle) {
|
||||
let texture_descriptor: TextureDescriptor = texture.into();
|
||||
let texture_buffer = render_context.resources().create_buffer_with_data(
|
||||
BufferInfo {
|
||||
buffer_usage: BufferUsage::COPY_SRC,
|
||||
..Default::default()
|
||||
},
|
||||
&texture.data,
|
||||
);
|
||||
|
||||
let texture_resource = render_context
|
||||
.resources()
|
||||
.get_asset_resource(*handle, TEXTURE_ASSET_INDEX)
|
||||
.unwrap();
|
||||
|
||||
// TODO: bytes_per_row could be incorrect for some texture formats
|
||||
render_context.copy_buffer_to_texture(
|
||||
texture_buffer,
|
||||
0,
|
||||
(4 * texture.width) as u32,
|
||||
texture_resource,
|
||||
[0, 0, 0],
|
||||
0,
|
||||
0,
|
||||
texture_descriptor.size.clone(),
|
||||
);
|
||||
render_context.resources().remove_buffer(texture_buffer);
|
||||
}
|
||||
}
|
||||
AssetEvent::Removed { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -13,7 +13,6 @@ use crate::{
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use legion::prelude::*;
|
||||
use std::{collections::HashMap, marker::PhantomData};
|
||||
use texture::{SamplerDescriptor, Texture, TextureDescriptor};
|
||||
|
||||
pub const BIND_BUFFER_ALIGNMENT: usize = 256;
|
||||
#[derive(Debug)]
|
||||
@ -398,7 +397,6 @@ where
|
||||
"uniform_resource_provider::<{}>",
|
||||
std::any::type_name::<T>()
|
||||
))
|
||||
.read_resource::<Assets<Texture>>()
|
||||
.read_resource::<RenderResources>()
|
||||
.read_resource::<EntitiesWaitingForAssets>()
|
||||
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
|
||||
@ -407,7 +405,7 @@ where
|
||||
.build(
|
||||
move |_,
|
||||
world,
|
||||
(textures, render_resources, entities_waiting_for_assets),
|
||||
(render_resources, entities_waiting_for_assets),
|
||||
(read_uniform_query, write_uniform_query)| {
|
||||
let render_resource_context = &*render_resources.context;
|
||||
|
||||
@ -442,8 +440,6 @@ where
|
||||
setup_uniform_texture_resources::<T>(
|
||||
entity,
|
||||
&uniforms,
|
||||
&mut command_queue,
|
||||
textures,
|
||||
render_resource_context,
|
||||
entities_waiting_for_assets,
|
||||
&mut renderable.render_resource_assignments,
|
||||
@ -557,7 +553,6 @@ where
|
||||
// TODO: maybe run "update" here
|
||||
SystemBuilder::new("uniform_resource_provider")
|
||||
.read_resource::<Assets<T>>()
|
||||
.read_resource::<Assets<Texture>>()
|
||||
.read_resource::<RenderResources>()
|
||||
.read_resource::<EntitiesWaitingForAssets>()
|
||||
// TODO: this write on RenderResourceAssignments will prevent this system from running in parallel with other systems that do the same
|
||||
@ -566,7 +561,7 @@ where
|
||||
.build(
|
||||
move |_,
|
||||
world,
|
||||
(assets, textures, render_resources, entities_waiting_for_assets),
|
||||
(assets, render_resources, entities_waiting_for_assets),
|
||||
(read_handle_query, write_handle_query)| {
|
||||
let render_resource_context = &*render_resources.context;
|
||||
uniform_buffer_arrays.reset_new_item_counts();
|
||||
@ -607,8 +602,6 @@ where
|
||||
setup_uniform_texture_resources::<T>(
|
||||
entity,
|
||||
&uniforms,
|
||||
&mut command_queue,
|
||||
textures,
|
||||
render_resource_context,
|
||||
entities_waiting_for_assets,
|
||||
&mut renderable.render_resource_assignments,
|
||||
@ -694,87 +687,37 @@ where
|
||||
fn setup_uniform_texture_resources<T>(
|
||||
entity: Entity,
|
||||
uniforms: &T,
|
||||
command_queue: &mut CommandQueue,
|
||||
textures: &Assets<Texture>,
|
||||
render_resource_context: &dyn RenderResourceContext,
|
||||
entities_waiting_for_assets: &EntitiesWaitingForAssets,
|
||||
render_resource_assignments: &mut RenderResourceAssignments,
|
||||
) where
|
||||
T: AsUniforms,
|
||||
T: AsUniforms,
|
||||
{
|
||||
for field_info in T::get_field_infos().iter() {
|
||||
let bind_type = uniforms.get_field_bind_type(&field_info.name);
|
||||
match bind_type {
|
||||
Some(FieldBindType::Texture) => {
|
||||
let texture_handle = uniforms
|
||||
.get_uniform_texture(&field_info.texture_name)
|
||||
.unwrap();
|
||||
let (texture_resource, sampler_resource) = match render_resource_context
|
||||
if let Some(FieldBindType::Texture) = bind_type {
|
||||
if let Some(texture_handle) = uniforms.get_uniform_texture(&field_info.texture_name) {
|
||||
if let Some(texture_resource) = render_resource_context
|
||||
.get_asset_resource(texture_handle, texture::TEXTURE_ASSET_INDEX)
|
||||
{
|
||||
Some(texture_resource) => (
|
||||
texture_resource,
|
||||
render_resource_context
|
||||
.get_asset_resource(texture_handle, texture::SAMPLER_ASSET_INDEX)
|
||||
.unwrap(),
|
||||
),
|
||||
None => {
|
||||
if let Some(texture) = textures.get(&texture_handle) {
|
||||
let texture_descriptor: TextureDescriptor = texture.into();
|
||||
let texture_resource =
|
||||
render_resource_context.create_texture(texture_descriptor);
|
||||
let texture_buffer = render_resource_context.create_buffer_with_data(
|
||||
BufferInfo {
|
||||
buffer_usage: BufferUsage::COPY_SRC,
|
||||
..Default::default()
|
||||
},
|
||||
&texture.data,
|
||||
);
|
||||
// TODO: bytes_per_row could be incorrect for some texture formats
|
||||
command_queue.copy_buffer_to_texture(
|
||||
texture_buffer,
|
||||
0,
|
||||
(4 * texture.width) as u32,
|
||||
texture_resource,
|
||||
[0, 0, 0],
|
||||
0,
|
||||
0,
|
||||
texture_descriptor.size.clone(),
|
||||
);
|
||||
command_queue.free_buffer(texture_buffer);
|
||||
|
||||
let sampler_descriptor: SamplerDescriptor = texture.into();
|
||||
let sampler_resource =
|
||||
render_resource_context.create_sampler(&sampler_descriptor);
|
||||
|
||||
render_resource_context.set_asset_resource(
|
||||
texture_handle,
|
||||
texture_resource,
|
||||
0,
|
||||
);
|
||||
render_resource_context.set_asset_resource(
|
||||
texture_handle,
|
||||
sampler_resource,
|
||||
1,
|
||||
);
|
||||
(texture_resource, sampler_resource)
|
||||
} else {
|
||||
entities_waiting_for_assets.add(entity);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render_resource_assignments.set(
|
||||
field_info.texture_name,
|
||||
RenderResourceAssignment::Texture(texture_resource),
|
||||
);
|
||||
render_resource_assignments.set(
|
||||
field_info.sampler_name,
|
||||
RenderResourceAssignment::Sampler(sampler_resource),
|
||||
);
|
||||
let sampler_resource = render_resource_context
|
||||
.get_asset_resource(texture_handle, texture::SAMPLER_ASSET_INDEX)
|
||||
.unwrap();
|
||||
render_resource_assignments.set(
|
||||
field_info.texture_name,
|
||||
RenderResourceAssignment::Texture(texture_resource),
|
||||
);
|
||||
render_resource_assignments.set(
|
||||
field_info.sampler_name,
|
||||
RenderResourceAssignment::Sampler(sampler_resource),
|
||||
);
|
||||
continue;
|
||||
} else {
|
||||
entities_waiting_for_assets.add(entity);
|
||||
}
|
||||
} else {
|
||||
entities_waiting_for_assets.add(entity);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,13 @@
|
||||
use crate::shader::ShaderDefSuffixProvider;
|
||||
use bevy_asset::Handle;
|
||||
use std::fs::File;
|
||||
use super::{SamplerDescriptor, TextureDescriptor};
|
||||
use crate::{
|
||||
renderer::{RenderResourceContext, RenderResources},
|
||||
shader::ShaderDefSuffixProvider,
|
||||
};
|
||||
use bevy_app::{EventReader, Events};
|
||||
use bevy_asset::{AssetEvent, Assets, Handle};
|
||||
use bevy_derive::Resource;
|
||||
use legion::prelude::*;
|
||||
use std::{collections::HashSet, fs::File};
|
||||
|
||||
pub const TEXTURE_ASSET_INDEX: usize = 0;
|
||||
pub const SAMPLER_ASSET_INDEX: usize = 1;
|
||||
@ -38,6 +45,74 @@ impl Texture {
|
||||
height,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn texture_resource_system(
|
||||
mut state: ResMut<TextureResourceSystemState>,
|
||||
render_resources: Res<RenderResources>,
|
||||
textures: Res<Assets<Texture>>,
|
||||
texture_events: Res<Events<AssetEvent<Texture>>>,
|
||||
) {
|
||||
let render_resources = &*render_resources.context;
|
||||
let mut changed_textures = HashSet::new();
|
||||
for event in state.event_reader.iter(&texture_events) {
|
||||
match event {
|
||||
AssetEvent::Created { handle } => {
|
||||
changed_textures.insert(*handle);
|
||||
}
|
||||
AssetEvent::Modified { handle } => {
|
||||
changed_textures.insert(*handle);
|
||||
Self::remove_current_texture_resources(render_resources, *handle);
|
||||
}
|
||||
AssetEvent::Removed { handle } => {
|
||||
Self::remove_current_texture_resources(render_resources, *handle);
|
||||
// if texture was modified and removed in the same update, ignore the modification
|
||||
// events are ordered so future modification events are ok
|
||||
changed_textures.remove(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for texture_handle in changed_textures.iter() {
|
||||
if let Some(texture) = textures.get(texture_handle) {
|
||||
let texture_descriptor: TextureDescriptor = texture.into();
|
||||
let texture_resource = render_resources.create_texture(texture_descriptor);
|
||||
|
||||
let sampler_descriptor: SamplerDescriptor = texture.into();
|
||||
let sampler_resource = render_resources.create_sampler(&sampler_descriptor);
|
||||
|
||||
render_resources.set_asset_resource(
|
||||
*texture_handle,
|
||||
texture_resource,
|
||||
TEXTURE_ASSET_INDEX,
|
||||
);
|
||||
render_resources.set_asset_resource(
|
||||
*texture_handle,
|
||||
sampler_resource,
|
||||
SAMPLER_ASSET_INDEX,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_current_texture_resources(
|
||||
render_resources: &dyn RenderResourceContext,
|
||||
handle: Handle<Texture>,
|
||||
) {
|
||||
if let Some(resource) = render_resources.get_asset_resource(handle, TEXTURE_ASSET_INDEX) {
|
||||
render_resources.remove_texture(resource);
|
||||
render_resources.remove_asset_resource(handle, TEXTURE_ASSET_INDEX);
|
||||
}
|
||||
if let Some(resource) = render_resources.get_asset_resource(handle, SAMPLER_ASSET_INDEX) {
|
||||
render_resources.remove_sampler(resource);
|
||||
render_resources.remove_asset_resource(handle, SAMPLER_ASSET_INDEX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
#[module(meta = false)]
|
||||
pub struct TextureResourceSystemState {
|
||||
event_reader: EventReader<AssetEvent<Texture>>,
|
||||
}
|
||||
|
||||
impl ShaderDefSuffixProvider for Option<Handle<Texture>> {
|
||||
|
@ -23,7 +23,7 @@ impl Default for Label {
|
||||
}
|
||||
|
||||
impl Label {
|
||||
// PERF: this is horrendously inefficient. (1) new texture every frame (2) no atlas (3) new texture for every label
|
||||
// PERF: this is horrendously inefficient. (1) new texture per label per frame (2) no atlas
|
||||
pub fn label_system(
|
||||
mut color_materials: ResMut<Assets<ColorMaterial>>,
|
||||
mut textures: ResMut<Assets<Texture>>,
|
||||
@ -41,11 +41,12 @@ impl Label {
|
||||
);
|
||||
|
||||
let material = color_materials.get_or_insert_with(*color_material_handle, || ColorMaterial::from(Handle::<Texture>::new()));
|
||||
if let Some(texture) = material.texture {
|
||||
// TODO: remove texture
|
||||
}
|
||||
if let Some(texture_handle) = material.texture {
|
||||
textures.set(texture_handle, texture);
|
||||
|
||||
material.texture = Some(textures.add(texture));
|
||||
} else {
|
||||
material.texture = Some(textures.add(texture));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user