forked from SpaceManiac/SpacemanDMM
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmap_renderer.rs
More file actions
366 lines (319 loc) · 11.7 KB
/
map_renderer.rs
File metadata and controls
366 lines (319 loc) · 11.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
//! GPU map renderer.
use std::time::Instant;
use std::sync::Arc;
use gfx;
use gfx::traits::{Factory as FactoryTrait, FactoryExt};
use crate::{Resources, Factory, Encoder, ColorFormat, RenderTargetView, Texture};
use slice_of_array::prelude::*;
use dm::objtree::ObjectTree;
use dmm_tools::dmm::Prefab;
use dmm_tools::minimap::{Sprite, Category, Layer};
use crate::dmi::*;
use crate::map_repr::AtomMap;
use imgui::TextureId;
const TILE_SIZE: u32 = 32;
gfx_defines! {
#[derive(Default)]
vertex Vertex {
position: [f32; 2] = "position",
color: [f32; 4] = "color",
uv: [f32; 2] = "uv",
}
constant Transform {
transform: [[f32; 4]; 4] = "transform",
}
#[derive(Default)]
constant RenderPop {
category: Category = "category",
texture: u32 = "texture", // icon
size: [f32; 2] = "size", // icon
uv: [f32; 4] = "uv", // icon_state + dir
color: [f32; 4] = "color", // color + alpha
// TODO: transform
ofs_x: i32 = "ofs_x", // pixel_x + pixel_w + step_x
ofs_y: i32 = "ofs_y", // pixel_y + pixel_z + step_y
plane: i32 = "plane",
layer: Layer = "layer",
}
pipeline pipe {
vbuf: gfx::VertexBuffer<Vertex> = (),
transform: gfx::ConstantBuffer<Transform> = "Transform",
tex: gfx::TextureSampler<[f32; 4]> = "tex",
out: gfx::BlendTarget<ColorFormat> = ("Target0", gfx::state::ColorMask::all(), gfx::preset::blend::ALPHA),
}
}
pub struct MapRenderer {
pub icons: Arc<IconCache>,
pub icon_textures: TextureCache,
pub zoom: f32,
pub layers: [bool; 5],
pub factory: Factory,
pso: gfx::PipelineState<Resources, pipe::Meta>,
transform_buffer: gfx::handle::Buffer<Resources, Transform>,
pub sampler: gfx::handle::Sampler<Resources>,
}
pub struct RenderedMap {
pub duration: [f32; 2],
pub thumbnail: Texture,
pub thumbnail_target: RenderTargetView,
pub thumbnail_id: Option<TextureId>,
vbuf: gfx::handle::Buffer<Resources, Vertex>,
ibuf: gfx::handle::Buffer<Resources, u32>,
}
#[derive(Debug, Clone)]
pub struct DrawCall {
pub category: Category,
pub texture: u32,
pub len: u32,
}
impl MapRenderer {
pub fn new(factory: &mut Factory, _view: &RenderTargetView) -> MapRenderer {
let pso = factory.create_pipeline_simple(
include_bytes!("shaders/main_150.glslv"),
include_bytes!("shaders/main_150.glslf"),
pipe::new()
).expect("create_pipeline_simple failed");
let transform_buffer = factory.create_constant_buffer(1);
let sampler = factory.create_sampler(gfx::texture::SamplerInfo::new(
gfx::texture::FilterMethod::Scale,
gfx::texture::WrapMode::Clamp,
));
MapRenderer {
icons: Arc::new(IconCache::new(".".as_ref())),
icon_textures: TextureCache::default(),
zoom: 1.0,
layers: [true, false, true, true, true],
factory: factory.clone(),
pso,
transform_buffer,
sampler,
}
}
#[must_use]
pub fn render(&mut self, map: &AtomMap, z: u32) -> RenderedMap {
let start = Instant::now();
let vbuf_data = map.vertex_buffer(z).flat();
let ibuf_data = map.index_buffer(z);
let ibuf_data = ibuf_data.flat();
let vbuf = self.factory.create_buffer::<Vertex>(
vbuf_data.len(),
gfx::buffer::Role::Vertex,
gfx::memory::Usage::Dynamic,
gfx::memory::Bind::empty(),
).expect("create vertex buffer");
let ibuf = self.factory.create_buffer::<u32>(
ibuf_data.len(),
gfx::buffer::Role::Index,
gfx::memory::Usage::Dynamic,
gfx::memory::Bind::empty(),
).expect("create index buffer");
let texture = self.factory.create_texture::<gfx::format::R8_G8_B8_A8>(
gfx::texture::Kind::D2(crate::THUMBNAIL_SIZE, crate::THUMBNAIL_SIZE, gfx::texture::AaMode::Single),
1,
gfx::memory::Bind::RENDER_TARGET | gfx::memory::Bind::SHADER_RESOURCE,
gfx::memory::Usage::Data,
Some(gfx::format::ChannelType::Unorm),
).expect("create thumbnail texture");
let thumbnail = self.factory.view_texture_as_shader_resource::<ColorFormat>(
&texture,
(0, 0),
gfx::format::Swizzle::new(),
).expect("view thumbnail as shader resource");
let thumbnail_target = self.factory.view_texture_as_render_target::<ColorFormat>(
&texture,
0,
None,
).expect("view thumbnail as render target");
RenderedMap {
duration: [to_seconds(map.duration), to_seconds(Instant::now() - start)],
thumbnail,
thumbnail_target,
thumbnail_id: None,
vbuf,
ibuf,
}
}
}
impl RenderedMap {
fn update_buffers(&mut self, map: &AtomMap, z: u32, factory: &mut Factory, encoder: &mut Encoder) {
let vbuf_data = map.vertex_buffer(z).flat();
let ibuf_data = map.index_buffer(z);
let ibuf_data = ibuf_data.flat();
if self.vbuf.len() < vbuf_data.len() {
self.vbuf = factory.create_buffer::<Vertex>(
vbuf_data.len(),
gfx::buffer::Role::Vertex,
gfx::memory::Usage::Dynamic,
gfx::memory::Bind::empty(),
).expect("create vertex buffer");
}
encoder.update_buffer(&self.vbuf, vbuf_data, 0).expect("update vbuf");
if self.ibuf.len() < ibuf_data.len() {
self.ibuf = factory.create_buffer::<u32>(
ibuf_data.len(),
gfx::buffer::Role::Index,
gfx::memory::Usage::Dynamic,
gfx::memory::Bind::empty(),
).expect("create index buffer");
}
encoder.update_buffer(&self.ibuf, ibuf_data, 0).expect("update ibuf");
}
fn inner_paint(
&self,
parent: &mut MapRenderer,
map: &AtomMap,
z: u32,
factory: &mut Factory,
encoder: &mut Encoder,
view: &RenderTargetView,
transform: [[f32; 4]; 4],
) {
encoder
.update_buffer(&parent.transform_buffer, &[Transform { transform }], 0)
.expect("update_buffer failed");
let mut start = 0;
for call in map.levels[z as usize].draw_calls.iter() {
if !call.category.matches_basic_layers(&parent.layers) {
start += call.len;
continue;
}
let texture = parent
.icon_textures
.retrieve(factory, &parent.icons, call.texture as usize);
let slice = gfx::Slice {
start: start,
end: start + call.len,
base_vertex: 0,
instances: None,
buffer: gfx::IndexBuffer::Index32(self.ibuf.clone()),
};
// TODO: use borrowing to avoid having to clone so much here?
let data = pipe::Data {
vbuf: self.vbuf.clone(),
transform: parent.transform_buffer.clone(),
tex: (texture.clone(), parent.sampler.clone()),
out: view.clone(),
};
encoder.draw(&slice, &parent.pso, &data);
start += call.len;
}
}
pub fn paint(
&mut self,
parent: &mut MapRenderer,
map: &AtomMap,
z: u32,
center: [f32; 2],
factory: &mut Factory,
encoder: &mut Encoder,
view: &RenderTargetView,
) {
// update vertex and index buffers from the map
if map.levels[z as usize].buffers_dirty.replace(false) {
self.update_buffers(map, z, factory, encoder);
}
// thumbnail render
encoder.clear(&self.thumbnail_target, [0.0, 0.0, 0.0, 0.0]);
self.inner_paint(parent, map, z, factory, encoder, &self.thumbnail_target, [
[2.0 / map.size.0 as f32 / TILE_SIZE as f32, 0.0, 0.0, -1.0],
[0.0, -2.0 / map.size.1 as f32 / TILE_SIZE as f32, 0.0, 1.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0],
]);
// regular render
let (x, y, _, _) = view.get_dimensions();
let zoom = parent.zoom;
self.inner_paint(parent, map, z, factory, encoder, view, [
// (0, 0) is the center of the screen, 1.0 = 1 pixel
[2.0 / x as f32, 0.0, 0.0, -2.0 * (center[0] * zoom).round() / zoom / x as f32],
[0.0, 2.0 / y as f32, 0.0, -2.0 * (center[1] * zoom).round() / zoom / y as f32],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0 / zoom],
]);
}
}
// forgive me
impl std::cmp::Eq for RenderPop {}
impl std::hash::Hash for RenderPop {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.category.hash(state);
self.texture.hash(state);
for each in self.size.iter() {
state.write_u32(each.to_bits());
}
for each in self.uv.iter() {
state.write_u32(each.to_bits());
}
for each in self.color.iter() {
state.write_u32(each.to_bits());
}
self.ofs_x.hash(state);
self.ofs_y.hash(state);
self.plane.hash(state);
self.layer.hash(state);
}
}
impl RenderPop {
pub fn from_prefab(icons: &IconCache, objtree: &ObjectTree, fab: &Prefab) -> Option<RenderPop> {
RenderPop::from_sprite(icons, &Sprite::from_vars(objtree, &fab))
}
pub fn from_sprite(icons: &IconCache, sprite: &Sprite) -> Option<RenderPop> {
if sprite.icon.is_empty() {
return None;
}
let texture_id = match icons.get_index(sprite.icon.as_ref()) {
Some(id) => id,
None => return None, // couldn't load
};
let icon_file = icons.get_icon(texture_id);
let width = icon_file.metadata.width as f32;
let height = icon_file.metadata.height as f32;
let uv = match icon_file.uv_of(sprite.icon_state, sprite.dir) {
Some(rect) => rect,
None => return None,
};
let color = [
sprite.color[0] as f32 / 255.0,
sprite.color[1] as f32 / 255.0,
sprite.color[2] as f32 / 255.0,
sprite.color[3] as f32 / 255.0,
];
Some(RenderPop {
category: sprite.category,
texture: texture_id as u32,
uv,
color,
size: [width, height],
ofs_x: sprite.ofs_x,
ofs_y: sprite.ofs_y,
plane: sprite.plane,
layer: sprite.layer,
})
}
pub fn instance(&self, loc: (u32, u32)) -> [Vertex; 4] {
let uv = self.uv;
let loc = (
((loc.0 * TILE_SIZE) as i32 + self.ofs_x) as f32,
((loc.1 * TILE_SIZE) as i32 + self.ofs_y) as f32,
);
let (width, height) = (self.size[0], self.size[1]);
let color = self.color;
[
Vertex { color, position: [loc.0, loc.1], uv: [uv[0], uv[3]] },
Vertex { color, position: [loc.0, loc.1 + height], uv: [uv[0], uv[1]] },
Vertex { color, position: [loc.0 + width, loc.1 + height], uv: [uv[2], uv[1]] },
Vertex { color, position: [loc.0 + width, loc.1], uv: [uv[2], uv[3]] },
]
}
pub fn sort_key(&self) -> impl Ord {
(self.plane, self.layer, self.texture)
}
}
impl DrawCall {
pub fn can_contain(&self, rpop: &RenderPop) -> bool {
self.category == rpop.category && self.texture == rpop.texture
}
}
fn to_seconds(duration: std::time::Duration) -> f32 {
duration.as_secs() as f32 + duration.subsec_nanos() as f32 / 1_000_000_000.0
}