wde_terrain/render/dependencies/
terrain_buffer.rs1use bevy::{ecs::system::SystemParamItem, prelude::*};
2use wde_renderer::prelude::*;
3
4use crate::{
5 manager::{CHUNK_HEIGHT, CHUNK_RENDER_SUBDIVISIONS, CHUNK_SIZE},
6 render::renderer_gpu::TerrainRendererGPU
7};
8
9const MAX_TERRAIN_TILES: usize = 1000;
10
11#[derive(Resource, ExtractResource, Clone, Debug)]
13pub struct TerrainRenderSettings {
14 pub displacement_scales: [f32; 4],
15 pub tiling_scales: [f32; 4]
16}
17impl Default for TerrainRenderSettings {
18 fn default() -> Self {
19 Self {
20 displacement_scales: [0.0, 0.16, 0.07, 0.0],
21 tiling_scales: [1.0, 9.5, 8.5, 1.0]
22 }
23 }
24}
25
26#[repr(C)]
27#[derive(Clone, Copy, Debug, bytemuck::Pod, bytemuck::Zeroable)]
28pub struct TerrainDescription {
29 pub tile_size: [f32; 3],
30 pub tile_subdivisions: f32,
31 pub displacement_scales: [f32; 4],
32 pub tiling_scales: [f32; 4]
33}
34impl Default for TerrainDescription {
35 fn default() -> Self {
36 Self {
37 tile_size: [CHUNK_SIZE, CHUNK_HEIGHT, CHUNK_SIZE],
38 tile_subdivisions: CHUNK_RENDER_SUBDIVISIONS as f32,
39 displacement_scales: TerrainRenderSettings::default().displacement_scales,
40 tiling_scales: TerrainRenderSettings::default().tiling_scales
41 }
42 }
43}
44
45#[repr(C)]
48#[derive(Clone, Copy, Debug, bytemuck::Pod, bytemuck::Zeroable)]
49pub struct TerrainTileDescription {
50 pub pos: [f32; 2],
51 pub lod: f32,
52 pub tile_layer: u32
53}
54
55#[derive(Asset, Clone, Debug, Default, TypePath)]
56pub struct TerrainBuffer;
57impl TerrainBuffer {
58 pub const DESC_BIND: u32 = 0;
59 pub const TILES_BIND: u32 = 1;
60}
61impl RenderData for TerrainBuffer {
62 type Params = ();
63
64 fn describe(_params: &mut SystemParamItem<Self::Params>, builder: &mut RenderDataBuilder) {
65 builder
66 .add_buffer(
67 Self::DESC_BIND,
68 Buffer {
69 label: "terrain-description-buffer".to_string(),
70 size: std::mem::size_of::<TerrainDescription>(),
71 usage: BufferUsage::UNIFORM | BufferUsage::COPY_DST,
72 content: Some(bytemuck::cast_slice(&[TerrainDescription::default()]).into())
73 }
74 )
75 .add_buffer(
76 Self::TILES_BIND,
77 Buffer {
78 label: "terrain-tiles-buffer".to_string(),
79 size: std::mem::size_of::<TerrainTileDescription>() * MAX_TERRAIN_TILES,
80 usage: BufferUsage::STORAGE | BufferUsage::COPY_DST,
81 content: None
82 }
83 );
84 }
85}
86
87#[derive(Asset, Clone, TypePath, Default)]
88pub struct TerrainBufferBinding;
89impl RenderBinding for TerrainBufferBinding {
90 type Params = SRenderData<TerrainBuffer>;
91
92 fn describe(
93 &mut self,
94 buffer: &SystemParamItem<Self::Params>,
95 builder: &mut RenderBindingBuilder
96 ) {
97 builder
98 .add_buffer(buffer, TerrainBuffer::DESC_BIND)
99 .add_buffer(buffer, TerrainBuffer::TILES_BIND);
100 }
101
102 fn label(&self) -> &str {
103 "terrain_buffer_binding"
104 }
105}
106
107pub(crate) fn update_terrain_description_buffer(
108 render_instance: Res<RenderInstance>,
109 terrain_buffer: ResRenderData<TerrainBuffer>,
110 buffers: Res<RenderAssets<GpuBuffer>>,
111 settings: Res<TerrainRenderSettings>
112) {
113 if !settings.is_changed() {
114 return;
115 }
116 let terrain_buffer = match terrain_buffer.iter().next() {
117 Some((_, b)) => b,
118 None => return
119 };
120 let buf = match buffers.get(&terrain_buffer.get_buffer(TerrainBuffer::DESC_BIND).unwrap()) {
121 Some(b) => b,
122 None => return
123 };
124 let render_instance = render_instance.0.read().unwrap();
125 buf.buffer.write(
126 &render_instance,
127 bytemuck::cast_slice(&[TerrainDescription {
128 tile_size: [CHUNK_SIZE, CHUNK_HEIGHT, CHUNK_SIZE],
129 tile_subdivisions: CHUNK_RENDER_SUBDIVISIONS as f32,
130 displacement_scales: settings.displacement_scales,
131 tiling_scales: settings.tiling_scales
132 }]),
133 0
134 );
135}
136
137pub(crate) fn update_terrain_tiles_buffer(
138 render_instance: Res<RenderInstance>,
139 terrain_buffer: ResRenderData<TerrainBuffer>,
140 buffers: Res<RenderAssets<GpuBuffer>>,
141 terrain: Res<TerrainRendererGPU>,
142 mut is_set: Local<bool>
143) {
144 if *is_set || !terrain.ready {
145 return;
146 }
147
148 let terrain_buffer = match terrain_buffer.iter().next() {
149 Some((_, b)) => b,
150 None => return
151 };
152 let tile_buffer = match buffers.get(
153 &terrain_buffer
154 .get_buffer(TerrainBuffer::TILES_BIND)
155 .unwrap()
156 ) {
157 Some(b) => b,
158 None => return
159 };
160
161 let mut tiles: Vec<(&crate::manager::ChunkPos, &u32)> = terrain.pos_to_layer.iter().collect();
163 tiles.sort_by_key(|&(_, layer)| *layer);
164
165 let data: Vec<TerrainTileDescription> = tiles
166 .iter()
167 .map(|&(pos, layer)| TerrainTileDescription {
168 pos: [pos.x as f32, pos.y as f32],
169 lod: 1.0,
170 tile_layer: *layer
171 })
172 .collect();
173
174 let render_instance = render_instance.0.read().unwrap();
175 tile_buffer
176 .buffer
177 .write(&render_instance, bytemuck::cast_slice(&data), 0);
178
179 *is_set = true;
180}