zengine_graphic/
texture.rs1use crate::{Device, Image, Queue, TextureBindGroupLayout};
2use std::num::NonZeroU32;
3use zengine_asset::{AssetEvent, Assets, Handle};
4use zengine_ecs::system::{EventStream, Res, ResMut};
5use zengine_macro::Asset;
6
7#[derive(Debug)]
8pub(crate) struct GpuImage {
9 pub texture: wgpu::Texture,
10 pub _view: wgpu::TextureView,
11 pub _sampler: wgpu::Sampler,
12 pub diffuse_bind_group: wgpu::BindGroup,
13}
14
15impl Drop for GpuImage {
16 fn drop(&mut self) {
17 self.texture.destroy();
18 }
19}
20
21#[derive(Asset, Debug)]
23pub struct Texture {
24 image: Handle<Image>,
25 pub(crate) gpu_image: Option<GpuImage>,
26}
27
28impl Texture {
29 fn new(image: Handle<Image>) -> Self {
30 Self {
31 image,
32 gpu_image: None,
33 }
34 }
35
36 pub(crate) fn convert_to_gpu_image(
37 &mut self,
38 device: &Device,
39 queue: &Queue,
40 texture_bind_group_layout: &TextureBindGroupLayout,
41 images: &Assets<Image>,
42 ) {
43 if let Some(image) = images.get(&self.image) {
44 let size = wgpu::Extent3d {
45 width: image.width,
46 height: image.height,
47 depth_or_array_layers: 1,
48 };
49 let texture = device.create_texture(&wgpu::TextureDescriptor {
50 size,
51 mip_level_count: 1,
52 sample_count: 1,
53 dimension: wgpu::TextureDimension::D2,
54 format: wgpu::TextureFormat::Rgba8UnormSrgb,
55 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
56 label: Some("diffuse_texture"),
57 });
58
59 queue.write_texture(
60 wgpu::ImageCopyTexture {
61 aspect: wgpu::TextureAspect::All,
62 texture: &texture,
63 mip_level: 0,
64 origin: wgpu::Origin3d::ZERO,
65 },
66 &image.data,
67 wgpu::ImageDataLayout {
68 offset: 0,
69 bytes_per_row: NonZeroU32::new(4 * image.width),
70 rows_per_image: NonZeroU32::new(image.height),
71 },
72 size,
73 );
74
75 let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
76 let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
77 address_mode_u: wgpu::AddressMode::ClampToEdge,
78 address_mode_v: wgpu::AddressMode::ClampToEdge,
79 address_mode_w: wgpu::AddressMode::ClampToEdge,
80 mag_filter: wgpu::FilterMode::Nearest,
81 min_filter: wgpu::FilterMode::Nearest,
82 mipmap_filter: wgpu::FilterMode::Nearest,
83 ..Default::default()
84 });
85
86 let diffuse_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
87 layout: texture_bind_group_layout,
88 entries: &[
89 wgpu::BindGroupEntry {
90 binding: 0,
91 resource: wgpu::BindingResource::TextureView(&view),
92 },
93 wgpu::BindGroupEntry {
94 binding: 1,
95 resource: wgpu::BindingResource::Sampler(&sampler),
96 },
97 ],
98 label: Some("diffuse_bind_group"),
99 });
100
101 self.image = self.image.as_weak();
102 self.gpu_image = Some(GpuImage {
103 texture,
104 _view: view,
105 _sampler: sampler,
106 diffuse_bind_group,
107 })
108 }
109 }
110}
111
112pub trait TextureAssets {
114 fn create_texture(&mut self, image: &Handle<Image>) -> Handle<Texture>;
116}
117
118impl TextureAssets for Assets<Texture> {
119 fn create_texture(&mut self, image_handle: &Handle<Image>) -> Handle<Texture> {
120 let handle = Handle::weak(image_handle.get_id().clone_with_different_type::<Texture>());
121 self.set(handle, Texture::new(image_handle.clone()))
122 }
123}
124
125pub(crate) fn prepare_texture_asset(
126 texture_bind_group_layout: Option<Res<TextureBindGroupLayout>>,
127 device: Option<Res<Device>>,
128 queue: Option<Res<Queue>>,
129 textures: Option<ResMut<Assets<Texture>>>,
130 images: Option<Res<Assets<Image>>>,
131 images_asset_event: EventStream<AssetEvent<Image>>,
132) {
133 let events = images_asset_event.read();
134 if let (
135 Some(mut textures),
136 Some(images),
137 Some(device),
138 Some(queue),
139 Some(texture_bind_group_layout),
140 ) = (textures, images, device, queue, texture_bind_group_layout)
141 {
142 for e in events {
143 if let AssetEvent::Loaded(handle) = e {
144 let handle = Handle::weak(handle.get_id().clone_with_different_type::<Texture>());
145 if let Some(texture) = textures.get_mut(&handle) {
146 texture.convert_to_gpu_image(
147 &device,
148 &queue,
149 &texture_bind_group_layout,
150 &images,
151 )
152 }
153 }
154 }
155 }
156}