1#![deny(missing_docs)]
4
5extern crate graphics;
6extern crate image;
7extern crate range;
8extern crate texture;
9
10use std::sync::{Arc, RwLock};
11use std::collections::HashMap;
12
13use graphics::{DrawState, Graphics, ImageSize};
14use graphics::types::Color;
15use image::RgbaImage;
16use range::Range;
17use texture::CreateTexture;
18
19pub struct GraphicsTree {
21 commands: Vec<Command>,
22 vertices: Vec<[f32; 2]>,
23 uvs: Vec<[f32; 2]>,
24 colors: Vec<[f32; 4]>,
25 current_color: Color,
26 current_draw_state: DrawState,
27}
28
29enum Command {
30 ClearColor(Color),
31 ClearStencil(u8),
32 ChangeColor(Color),
33 ChangeDrawState(DrawState),
34 Colored(Range),
35 Colors(Range, Range),
36 Textured(Texture, Range, Range),
37 TexturedColor(Texture, Range, Range, Range),
38}
39
40#[derive(Clone)]
42pub struct Texture(pub Arc<RwLock<TextureInner>>);
43
44pub struct TextureInner {
46 pub id: Option<u64>,
48 pub needs_update: bool,
50 pub image: RgbaImage,
52}
53
54pub struct TextureBuffer<F, T> {
56 pub factory: F,
58 textures: HashMap<u64, T>,
59 next_id: u64,
60}
61
62impl GraphicsTree {
63 pub fn new() -> GraphicsTree {
65 GraphicsTree {
66 commands: vec![],
67 vertices: vec![],
68 uvs: vec![],
69 colors: vec![],
70 current_color: [0.0; 4],
71 current_draw_state: Default::default(),
72 }
73 }
74
75 pub fn is_empty(&self) -> bool {
77 self.commands.len() == 0 &&
78 self.vertices.len() == 0 &&
79 self.uvs.len() == 0 &&
80 self.colors.len() == 0
81 }
82
83 pub fn clear(&mut self) {
85 self.commands.clear();
86 self.vertices.clear();
87 self.uvs.clear();
88 self.colors.clear();
89 }
90
91 pub fn draw<F, T, G>(
93 &self,
94 texture_buffer: &mut TextureBuffer<F, T>,
95 g: &mut G
96 )
97 where
98 T: ImageSize + CreateTexture<F>,
99 G: Graphics<Texture=T>
100 {
101 use Command::*;
102 use graphics::BACK_END_MAX_VERTEX_COUNT;
103
104 let bufsize = 2 * BACK_END_MAX_VERTEX_COUNT;
105 let mut color: Color = [0.0; 4];
106 let mut draw_state: DrawState = Default::default();
107 for command in &self.commands {
108 match *command {
109 ClearColor(color) => g.clear_color(color),
110 ClearStencil(value) => g.clear_stencil(value),
111 ChangeColor(new_color) => color = new_color,
112 ChangeDrawState(new_draw_state) => draw_state = new_draw_state,
113 Colored(range) => {
114 let offset = range.offset;
116 let length = range.length;
117 let chunks = length / bufsize;
118 g.tri_list(&draw_state, &color, |f| {
119 for i in 0..chunks {
120 let start = offset + chunks * i;
121 let end = start + bufsize;
122 f(&self.vertices[start..end]);
123 }
124 if chunks * bufsize < length {
125 let start = chunks * bufsize;
126 let len = length - start;
127 f(&self.vertices[offset + start..offset + len]);
128 }
129 });
130 }
131 Colors(vertex_range, color_range) => {
132 let offset_v = vertex_range.offset;
133 let length_v = vertex_range.length;
134 let chunks_v = length_v / bufsize;
135 let offset_c = color_range.offset;
136 let length_c = color_range.length;
137 let chunks_c = length_c / bufsize;
138 g.tri_list_c(&draw_state, |f| {
139 for i in 0..chunks_v {
140 let start_v = offset_v + chunks_v * i;
141 let end_v = start_v + bufsize;
142 let start_c = offset_c + chunks_c * i;
143 let end_c = start_c + bufsize;
144 f(&self.vertices[start_v..end_v], &self.colors[start_c..end_c]);
145 }
146 if chunks_v * bufsize < length_v {
147 let start_v = chunks_v * bufsize;
148 let len_v = length_v - start_v;
149 let start_c = chunks_c * bufsize;
150 let len_c = length_c - start_c;
151 f(&self.vertices[offset_v + start_v..offset_v + len_v],
152 &self.colors[offset_c + start_c..offset_c + len_c]);
153 }
154 });
155 }
156 Textured(ref tex, vertex_range, uv_range) => {
157 let offset_v = vertex_range.offset;
159 let length_v = vertex_range.length;
160 let chunks_v = length_v / bufsize;
161 let offset_uv = uv_range.offset;
162 let length_uv = uv_range.length;
163 let chunks_uv = length_uv / bufsize;
164
165 let texture = if let Ok(mut inner) = tex.0.write() {
166 if inner.id.is_none() {
167 use texture::{Format, TextureSettings};
168
169 let (width, height) = inner.image.dimensions();
170 let new_texture: T = CreateTexture::create(
171 &mut texture_buffer.factory,
172 Format::Rgba8,
173 &inner.image,
174 [width, height],
175 &TextureSettings::new()
176 ).unwrap_or_else(|_| panic!("Could not create texture"));
177 texture_buffer.textures.insert(texture_buffer.next_id, new_texture);
178 inner.id = Some(texture_buffer.next_id);
179 texture_buffer.next_id += 1;
180 } else if inner.needs_update {
181 use texture::{Format, TextureSettings};
184
185 let id = inner.id.unwrap();
186 let (width, height) = inner.image.dimensions();
187 let new_texture: T = CreateTexture::create(
188 &mut texture_buffer.factory,
189 Format::Rgba8,
190 &inner.image,
191 [width, height],
192 &TextureSettings::new()
193 ).unwrap_or_else(|_| panic!("Could not create texture"));
194 texture_buffer.textures.insert(id, new_texture);
195 inner.needs_update = false;
196 }
197 if let Some(texture) = texture_buffer.textures.get(&inner.id.unwrap()) {
198 texture
199 } else {
200 panic!("Texture does not exist");
201 }
202 } else {
203 panic!("Image is used elsewhere");
204 };
205
206 g.tri_list_uv(&draw_state, &color, texture, |f| {
207 for i in 0..chunks_v {
208 let start_v = offset_v + chunks_v * i;
209 let end_v = start_v + bufsize;
210 let start_uv = offset_uv + chunks_uv * i;
211 let end_uv = start_uv + bufsize;
212 f(&self.vertices[start_v..end_v],
213 &self.uvs[start_uv..end_uv]);
214 }
215 if chunks_v * bufsize < length_v {
216 let start_v = chunks_v * bufsize;
217 let len_v = length_v - start_v;
218 let start_uv = chunks_uv * bufsize;
219 let len_uv = length_uv - start_uv;
220 f(&self.vertices[offset_v + start_v..offset_v + len_v],
221 &self.uvs[offset_uv + start_uv..offset_uv + len_uv]);
222 }
223 });
224 }
225 TexturedColor(ref tex, vertex_range, uv_range, color_range) => {
226 let offset_v = vertex_range.offset;
228 let length_v = vertex_range.length;
229 let chunks_v = length_v / bufsize;
230 let offset_uv = uv_range.offset;
231 let length_uv = uv_range.length;
232 let chunks_uv = length_uv / bufsize;
233 let offset_c = color_range.offset;
234 let length_c = color_range.length;
235 let chunks_c = length_c / bufsize;
236
237 let texture = if let Ok(mut inner) = tex.0.write() {
238 if inner.id.is_none() {
239 use texture::{Format, TextureSettings};
240
241 let (width, height) = inner.image.dimensions();
242 let new_texture: T = CreateTexture::create(
243 &mut texture_buffer.factory,
244 Format::Rgba8,
245 &inner.image,
246 [width, height],
247 &TextureSettings::new()
248 ).unwrap_or_else(|_| panic!("Could not create texture"));
249 texture_buffer.textures.insert(texture_buffer.next_id, new_texture);
250 inner.id = Some(texture_buffer.next_id);
251 texture_buffer.next_id += 1;
252 } else if inner.needs_update {
253 use texture::{Format, TextureSettings};
256
257 let id = inner.id.unwrap();
258 let (width, height) = inner.image.dimensions();
259 let new_texture: T = CreateTexture::create(
260 &mut texture_buffer.factory,
261 Format::Rgba8,
262 &inner.image,
263 [width, height],
264 &TextureSettings::new()
265 ).unwrap_or_else(|_| panic!("Could not create texture"));
266 texture_buffer.textures.insert(id, new_texture);
267 inner.needs_update = false;
268 }
269 if let Some(texture) = texture_buffer.textures.get(&inner.id.unwrap()) {
270 texture
271 } else {
272 panic!("Texture does not exist");
273 }
274 } else {
275 panic!("Image is used elsewhere");
276 };
277
278 g.tri_list_uv_c(&draw_state, texture, |f| {
279 for i in 0..chunks_v {
280 let start_v = offset_v + chunks_v * i;
281 let end_v = start_v + bufsize;
282 let start_uv = offset_uv + chunks_uv * i;
283 let end_uv = start_uv + bufsize;
284 let start_c = offset_c + chunks_c * i;
285 let end_c = start_c + bufsize;
286 f(&self.vertices[start_v..end_v],
287 &self.uvs[start_uv..end_uv],
288 &self.colors[start_c..end_c]);
289 }
290 if chunks_v * bufsize < length_v {
291 let start_v = chunks_v * bufsize;
292 let len_v = length_v - start_v;
293 let start_uv = chunks_uv * bufsize;
294 let len_uv = length_uv - start_uv;
295 let start_c = chunks_c * bufsize;
296 let len_c = length_c - start_c;
297 f(&self.vertices[offset_v + start_v..offset_v + len_v],
298 &self.uvs[offset_uv + start_uv..offset_uv + len_uv],
299 &self.colors[offset_c + start_c..offset_c + len_c]);
300 }
301 });
302 }
303 }
304 }
305 }
306}
307
308impl ImageSize for Texture {
309 fn get_size(&self) -> (u32, u32) {
310 use std::ops::Deref;
311
312 self.0.read().unwrap().deref().image.dimensions()
313 }
314}
315
316impl Graphics for GraphicsTree {
317 type Texture = Texture;
318
319 fn clear_color(&mut self, color: Color) {
320 self.commands.push(Command::ClearColor(color));
321 }
322
323 fn clear_stencil(&mut self, value: u8) {
324 self.commands.push(Command::ClearStencil(value));
325 }
326
327 fn tri_list<F>(
328 &mut self,
329 draw_state: &DrawState,
330 color: &Color,
331 mut f: F
332 ) where F: FnMut(&mut dyn FnMut(&[[f32; 2]])) {
333 if color != &self.current_color {
334 self.commands.push(Command::ChangeColor(*color));
335 }
336 if draw_state != &self.current_draw_state {
337 self.commands.push(Command::ChangeDrawState(*draw_state));
338 }
339 let start = self.vertices.len();
340 f(&mut |chunk| self.vertices.extend_from_slice(chunk));
341 self.commands.push(Command::Colored(Range::new(start, self.vertices.len() - start)));
342 }
343
344 fn tri_list_c<F>(
345 &mut self,
346 draw_state: &DrawState,
347 mut f: F
348 ) where F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 4]])) {
349 if draw_state != &self.current_draw_state {
350 self.commands.push(Command::ChangeDrawState(*draw_state));
351 }
352 let start_v = self.vertices.len();
353 let start_c = self.colors.len();
354 f(&mut |chunk, chunk_color| {
355 self.vertices.extend_from_slice(chunk);
356 self.colors.extend_from_slice(chunk_color);
357 });
358 self.commands.push(Command::Colors(
359 Range::new(start_v, self.vertices.len() - start_v),
360 Range::new(start_c, self.colors.len() - start_c)
361 ));
362 }
363
364 fn tri_list_uv<F>(
365 &mut self,
366 draw_state: &DrawState,
367 color: &[f32; 4],
368 texture: &Self::Texture,
369 mut f: F
370 ) where F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 2]])) {
371 if color != &self.current_color {
372 self.commands.push(Command::ChangeColor(*color));
373 }
374 if draw_state != &self.current_draw_state {
375 self.commands.push(Command::ChangeDrawState(*draw_state));
376 }
377 let start_vertices = self.vertices.len();
378 let start_uvs = self.uvs.len();
379 f(&mut |chunk, chunk_uvs| {
380 self.vertices.extend_from_slice(chunk);
381 self.uvs.extend_from_slice(chunk_uvs);
382 });
383 self.commands.push(Command::Textured(
384 texture.clone(),
385 Range::new(start_vertices, self.vertices.len() - start_vertices),
386 Range::new(start_uvs, self.uvs.len() - start_uvs)
387 ));
388 }
389
390 fn tri_list_uv_c<F>(
391 &mut self,
392 draw_state: &DrawState,
393 texture: &Self::Texture,
394 mut f: F
395 ) where F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 2]], &[[f32; 4]])) {
396 if draw_state != &self.current_draw_state {
397 self.commands.push(Command::ChangeDrawState(*draw_state));
398 }
399 let start_vertices = self.vertices.len();
400 let start_uvs = self.uvs.len();
401 let start_c = self.colors.len();
402 f(&mut |chunk, chunk_uvs, chunk_c| {
403 self.vertices.extend_from_slice(chunk);
404 self.uvs.extend_from_slice(chunk_uvs);
405 self.colors.extend_from_slice(chunk_c);
406 });
407 self.commands.push(Command::TexturedColor(
408 texture.clone(),
409 Range::new(start_vertices, self.vertices.len() - start_vertices),
410 Range::new(start_uvs, self.uvs.len() - start_uvs),
411 Range::new(start_c, self.colors.len() - start_c)
412 ));
413 }
414}
415
416impl From<RgbaImage> for Texture {
417 fn from(image: RgbaImage) -> Texture {
418 Texture(Arc::new(RwLock::new(TextureInner {
419 id: None,
420 needs_update: false,
421 image: image
422 })))
423 }
424}
425
426
427impl<F, T> TextureBuffer<F, T> {
428 pub fn new(factory: F) -> TextureBuffer<F, T> {
430 TextureBuffer {
431 factory: factory,
432 textures: HashMap::new(),
433 next_id: 0,
434 }
435 }
436}
437
438impl Texture {
439 pub fn with_image_mut<F>(&self, f: F)
441 where F: FnOnce(&mut RgbaImage) {
442 let mut inner = self.0.write().unwrap();
443 f(&mut inner.image);
444 inner.needs_update = true;
445 }
446}