1use super::Vector;
8use color::Color;
9use draw::*;
10use gl;
11use gl::types::*;
12use nalgebra::{Matrix4, Vector3};
13use nalgebra::{Scalar, Vector4};
14use rect::Rect;
15use shader::BATCH_SHADER;
16use std::mem;
17use std::ptr;
18use std::rc::Rc;
19use texture::Texture;
20use transform::*;
21use vertex::Vertex;
22
23pub enum BatchError {
24 BadTextureRect,
25}
26
27#[derive(Debug, Clone)]
28pub struct SpriteData {
30 pos: Vector<f32>,
31 rotation: f32,
32 model: Matrix4<f32>,
33 need_update: bool,
34 text_coord: [Vector<f32>; 2],
35 color: Option<Color>,
36}
37
38impl SpriteData {
39 pub fn new(pos: Vector<f32>) -> Self {
41 SpriteData {
42 pos,
43 ..Self::default()
44 }
45 }
46
47 pub fn set_texture_raw(&mut self, text_coord: [Vector<f32>; 2]) {
49 self.text_coord = text_coord;
50 }
51
52 pub fn set_texture_rect(&mut self, text_rect: Rect<u32>, texture_size: u32) {
54 self.text_coord = [
55 Vector::new(
56 text_rect.left as f32 / texture_size as f32,
57 text_rect.top as f32 / texture_size as f32,
58 ),
59 Vector::new(
60 text_rect.width as f32 / texture_size as f32,
61 text_rect.height as f32 / texture_size as f32,
62 ),
63 ];
64 }
65
66 pub fn texture_rect<T>(&self, texture_size: T) -> Rect<u32>
68 where
69 T: Into<f32> + Copy,
70 {
71 Rect::new(
72 (self.text_coord[0].x * texture_size.into()) as u32,
73 (self.text_coord[0].y * texture_size.into()) as u32,
74 (self.text_coord[1].x * texture_size.into()) as u32,
75 (self.text_coord[1].y * texture_size.into()) as u32,
76 )
77 }
78}
79
80impl Default for SpriteData {
81 fn default() -> SpriteData {
82 SpriteData {
83 pos: Vector::new(0.0, 0.0),
84 rotation: 0.0,
85 model: Matrix4::identity(),
86 need_update: true,
87 text_coord: [Vector::new(0.0, 0.0), Vector::new(1.0, 1.0)],
88 color: None,
89 }
90 }
91}
92
93impl Transformable for SpriteData {
94 fn contain<T>(&self, _vec: ::Point<T>) -> bool
95 where
96 T: Scalar + Into<f32>,
97 {
98 true
99 }
100
101 fn set_origin<T>(&mut self, _origin: Vector<T>)
102 where
103 T: Scalar + Into<f32>,
104 {
105 unimplemented!("No origin for now in SpriteData.");
106 }
107
108 fn get_origin(&self) -> Vector<f32> {
109 unimplemented!("No origin for now in SpriteData.");
110 }
111}
112
113impl Scalable for SpriteData {
114 fn set_scale<T>(&mut self, _vec: Vector<T>)
115 where
116 T: Scalar + Into<f32>,
117 {
118 unimplemented!("For instance no scale to SpriteData.");
119 }
120
121 fn get_scale(&self) -> Vector<f32> {
122 unimplemented!("For instance no scale to SpriteData.");
123 }
124
125 fn scale<T>(&mut self, _factor: Vector<T>)
126 where
127 T: Scalar + Into<f32>,
128 {
129 unimplemented!("For instance no scale to SpriteData.");
130 }
131}
132
133impl Rotable for SpriteData {
134 fn rotate<T>(&mut self, angle: T)
135 where
136 T: Into<f32> + Scalar,
137 {
138 self.rotation += angle.into();
139 self.need_update = true;
140 }
141
142 fn set_rotation<T>(&mut self, angle: T)
143 where
144 T: Into<f32> + Scalar,
145 {
146 self.rotation = angle.into();
147 self.need_update = true;
148 }
149
150 fn get_rotation(&self) -> f32 {
151 self.rotation
152 }
153}
154
155impl Movable for SpriteData {
156 fn translate<T>(&mut self, vec: Vector<T>)
157 where
158 T: Into<f32> + Scalar,
159 {
160 self.pos.x += vec.x.into();
161 self.pos.y += vec.y.into();
162 self.need_update = true;
163 }
164
165 fn get_position(&self) -> Vector<f32> {
166 self.pos
167 }
168
169 fn set_position<T>(&mut self, vec: Vector<T>)
170 where
171 T: Into<f32> + Scalar,
172 {
173 self.pos.x = vec.x.into();
174 self.pos.y = vec.y.into();
175 self.need_update = true;
176 }
177}
178
179#[derive(Clone, Debug)]
180pub struct SpriteBatch {
195 texture: Option<Rc<Texture>>,
196 sprites: Vec<SpriteData>,
197 vertice: Vec<Vertex>,
198 gl_objects: (u32, u32),
199 glob_origin: Vector<f32>,
200 glob_pos: Vector<f32>,
201 glob_scale: Vector<f32>,
202 glob_rotation: f32,
203 len: usize,
204 need_update: bool,
205 model: Matrix4<f32>,
206}
207
208impl SpriteBatch {
210 pub fn new() -> SpriteBatch {
212 SpriteBatch::default()
213 }
214
215 pub fn extend_from_slice(&mut self, slice: &mut [SpriteData]) {
216 {
217 let vertice = &mut self.vertice;
218
219 let (w, h) = self
220 .texture
221 .as_ref()
222 .map_or((0.0, 0.0), |x| (x.width() as f32, x.height() as f32));
223
224 for x in slice.iter_mut() {
225 x.need_update = true;
226 vertice.extend_from_slice(&[
227 Vertex::new(
228 Vector::new(0.0, 0.0),
229 Vector::new(x.text_coord[0].x, x.text_coord[0].y),
230 x.color.unwrap_or(Color::white()),
231 ),
232 Vertex::new(
233 Vector::new(0.0, h),
234 Vector::new(x.text_coord[0].x, x.text_coord[1].y),
235 x.color.unwrap_or(Color::white()),
236 ),
237 Vertex::new(
238 Vector::new(w, 0.0),
239 Vector::new(x.text_coord[1].x, x.text_coord[0].y),
240 x.color.unwrap_or(Color::white()),
241 ),
242 Vertex::new(
243 Vector::new(w, h),
244 Vector::new(x.text_coord[1].x, x.text_coord[1].y),
245 x.color.unwrap_or(Color::white()),
246 ),
247 ]);
248 }
249 }
250 self.sprites.extend_from_slice(slice);
251 self.need_update = true;
252 }
253
254 pub fn clear(&mut self) {
256 self.sprites.clear();
257 self.vertice.clear();
258 }
259
260 pub fn reserve(&mut self, len: usize) {
262 self.sprites.reserve(len);
263 self.vertice.reserve(len * 4);
264 }
265
266 pub fn sprites(&self) -> &[SpriteData] {
268 &self.sprites
269 }
270
271 pub fn sprites_mut(&mut self) -> &mut [SpriteData] {
273 &mut self.sprites
274 }
275
276 pub fn get_sprite_mut(&mut self, idx: usize) -> Option<&mut SpriteData> {
278 self.sprites.get_mut(idx)
279 }
280
281 pub fn get_sprite(&self, idx: usize) -> Option<&SpriteData> {
283 self.sprites.get(idx)
284 }
285
286 pub fn push_sprite(&mut self, mut sprites: SpriteData) {
287 sprites.need_update = true;
288 let (w, h) = if let Some(ref texture) = self.texture {
289 (texture.width() as f32, texture.height() as f32)
290 } else {
291 (0.0, 0.0)
292 };
293
294 self.vertice.extend_from_slice(&[
295 Vertex::new(
296 Vector::new(0.0, 0.0),
297 Vector::new(sprites.text_coord[0].x, sprites.text_coord[0].y),
298 Color::white(),
299 ),
300 Vertex::new(
301 Vector::new(0.0, h),
302 Vector::new(sprites.text_coord[0].x, sprites.text_coord[1].y),
303 Color::white(),
304 ),
305 Vertex::new(
306 Vector::new(w, 0.0),
307 Vector::new(sprites.text_coord[1].x, sprites.text_coord[0].y),
308 Color::white(),
309 ),
310 Vertex::new(
311 Vector::new(w, h),
312 Vector::new(sprites.text_coord[1].x, sprites.text_coord[1].y),
313 Color::white(),
314 ),
315 ]);
316 self.sprites.push(sprites);
317 }
318
319 pub fn pop_sprite(&mut self) -> Option<SpriteData> {
321 self.need_update = true;
322 self.vertice.truncate(self.len - 4);
323 self.sprites.pop()
324 }
325
326 fn update_vbo(&mut self) {
327 unsafe {
328 gl::BindBuffer(gl::ARRAY_BUFFER, self.gl_objects.1);
329
330 if self.len != self.vertice.len() / 4 {
331 gl::BufferData(
332 gl::ARRAY_BUFFER,
333 (std::mem::size_of::<GLfloat>() * self.vertice.len() * 8) as GLsizeiptr,
334 self.vertice.as_ptr() as *const GLvoid,
335 gl::STATIC_DRAW,
336 );
337 self.len = self.vertice.len() / 4;
338 }
339 gl::BufferSubData(
340 gl::ARRAY_BUFFER,
341 0,
342 (std::mem::size_of::<GLfloat>() * self.vertice.len() * 8) as GLsizeiptr,
343 self.vertice.as_ptr() as *const GLvoid,
344 );
345 self.update_vao();
346 gl::BindBuffer(gl::ARRAY_BUFFER, 0);
347 }
348 }
349
350 fn create_vbo() -> (u32, u32) {
351 let (mut vao, mut vbo) = (0, 0);
352 unsafe {
353 gl::GenVertexArrays(1, &mut vao);
354
355 gl::GenBuffers(1, &mut vbo);
356
357 gl::BindVertexArray(0);
358 }
359 (vao, vbo)
360 }
361
362 fn update_vao(&mut self) {
363 unsafe {
364 gl::BindVertexArray(self.gl_objects.0);
365 gl::VertexAttribPointer(
367 0,
368 2,
369 gl::FLOAT,
370 gl::FALSE,
371 (8 * mem::size_of::<GLfloat>()) as GLsizei,
372 ptr::null(),
373 );
374 gl::EnableVertexAttribArray(0);
375 gl::VertexAttribPointer(
377 1,
378 2,
379 gl::FLOAT,
380 gl::FALSE,
381 (8 * mem::size_of::<GLfloat>()) as GLsizei,
382 (2 * mem::size_of::<GLfloat>()) as *const _,
383 );
384 gl::EnableVertexAttribArray(1);
385 gl::VertexAttribPointer(
387 2,
388 3,
389 gl::FLOAT,
390 gl::FALSE,
391 (8 * mem::size_of::<GLfloat>()) as GLsizei,
392 (4 * mem::size_of::<GLfloat>()) as *const _,
393 );
394 gl::EnableVertexAttribArray(2);
395
396 gl::BindVertexArray(0);
397 }
398 }
399
400 fn fill_vbo(&mut self) {
401 unsafe {
402 gl::BindVertexArray(self.gl_objects.0);
403 gl::BindBuffer(gl::ARRAY_BUFFER, self.gl_objects.1);
404
405 gl::BufferData(
406 gl::ARRAY_BUFFER,
407 (std::mem::size_of::<GLfloat>() * self.vertice.len() * 8) as GLsizeiptr,
408 self.vertice.as_ptr() as *const GLvoid,
409 gl::STATIC_DRAW,
410 );
411 self.update_vao();
412
413 gl::BindBuffer(gl::ARRAY_BUFFER, 0);
414 }
415 }
416
417 fn update_model(&mut self) {
418 self.model = Matrix4::<f32>::identity().append_translation(&Vector3::new(
420 self.glob_pos.x - self.glob_origin.x,
421 self.glob_pos.y - self.glob_origin.y,
422 0.0,
423 ));
424 if self.glob_origin.x != 0.0 && self.glob_origin.y != 0.0 {
425 self.model.append_translation_mut(&Vector3::new(
426 self.glob_origin.x,
427 self.glob_origin.y,
428 0.0,
429 ));
430 self.model *=
431 Matrix4::from_euler_angles(0.0, 0.0, self.glob_rotation * (3.14116 * 180.0));
432 self.model.prepend_translation_mut(&Vector3::new(
433 -self.glob_origin.x,
434 -self.glob_origin.y,
435 0.0,
436 ));
437 } else {
438 self.model *=
439 Matrix4::from_euler_angles(0.0, 0.0, self.glob_rotation * (3.14116 * 180.0));
440 }
441 self.model.append_nonuniform_scaling_mut(&Vector3::new(
442 self.glob_scale.x,
443 self.glob_scale.y,
444 0.0,
445 ));
446 if self.glob_rotation > 360.0 {
447 self.glob_rotation = 0.0;
448 }
449 self.need_update = false;
450 }
451
452 fn len(&self) -> usize {
453 self.len
454 }
455}
456
457impl Transformable for SpriteBatch {
458 fn contain<T: nalgebra::Scalar + Into<f32>>(&self, _vec: ::Point<T>) -> bool {
459 true
460 }
461
462 fn set_origin<T: nalgebra::Scalar + Into<f32>>(&mut self, origin: Vector<T>) {
463 self.glob_origin.x = origin.x.into();
464 self.glob_origin.y = origin.y.into();
465 self.need_update = true;
466 }
467
468 fn get_origin(&self) -> Vector<f32> {
469 self.glob_origin
470 }
471}
472
473impl Scalable for SpriteBatch {
474 fn set_scale<T>(&mut self, vec: Vector<T>)
475 where
476 T: Scalar + Into<f32>,
477 {
478 self.glob_scale.x = vec.x.into();
479 self.glob_scale.y = vec.y.into();
480 self.need_update = true;
481 }
482
483 fn get_scale(&self) -> Vector<f32> {
484 self.glob_scale
485 }
486
487 fn scale<T>(&mut self, factor: Vector<T>)
488 where
489 T: Scalar + Into<f32>,
490 {
491 self.glob_scale.x += factor.x.into();
492 self.glob_scale.y += factor.y.into();
493 self.need_update = true;
494 }
495}
496
497impl Rotable for SpriteBatch {
498 fn rotate<T>(&mut self, angle: T)
499 where
500 T: Scalar + Into<f32>,
501 {
502 self.glob_rotation += angle.into();
503 self.need_update = true;
504 }
505
506 fn set_rotation<T>(&mut self, angle: T)
507 where
508 T: Scalar + Into<f32>,
509 {
510 self.glob_rotation = angle.into();
511 self.need_update = true;
512 }
513
514 fn get_rotation(&self) -> f32 {
515 self.glob_rotation
516 }
517}
518
519impl Movable for SpriteBatch {
520 fn translate<T>(&mut self, vec: Vector<T>)
521 where
522 T: Scalar + Into<f32>,
523 {
524 self.glob_pos.x += vec.x.into();
525 self.glob_pos.y += vec.y.into();
526 self.need_update = true;
527 }
528
529 fn get_position(&self) -> Vector<f32> {
530 self.glob_pos
531 }
532
533 fn set_position<T>(&mut self, vec: Vector<T>)
534 where
535 T: Scalar + Into<f32>,
536 {
537 self.glob_pos.x = vec.x.into();
538 self.glob_pos.y = vec.y.into();
539 self.need_update = true;
540 }
541}
542
543impl DrawableMut for SpriteBatch {
544 fn draw_mut<T: Drawer>(&mut self, target: &mut T) {
545 self.update();
546 self.draw(target);
547 }
548}
549
550impl Drawable for SpriteBatch {
551 fn draw<T: Drawer>(&self, target: &mut T) {
552 let texture = if let Some(ref rc_texture) = self.texture {
553 Some(rc_texture.as_ref())
554 } else {
555 None
556 };
557
558 let mut context = Context::new(
559 texture,
560 &*BATCH_SHADER,
561 vec![
562 ("projection".to_string(), target.projection()),
563 ("glob_model".to_string(), &self.model),
564 ],
565 BlendMode::Alpha,
566 );
567
568 self.setup_draw(&mut context);
569 unsafe {
570 gl::BindVertexArray(self.gl_objects.0);
571 gl::BindBuffer(gl::ARRAY_BUFFER, self.gl_objects.1);
572
573 gl::DrawArrays(gl::TRIANGLE_STRIP, 0, self.vertice.len() as i32);
574
575 gl::BindVertexArray(0);
576 gl::BindBuffer(gl::ARRAY_BUFFER, 0);
577 }
578 }
579
580 fn draw_with_context(&self, _context: &mut Context) {
581 unimplemented!(
582 "Put an issue here please if I forgot to implement it https://github.com/Afourcat/Gust/issues");
583 }
584
585 fn update(&mut self) {
586 let mut sprite_mod = false;
589 {
590 let sprites = &mut self.sprites;
592 let vertices = &mut self.vertice;
594
595 for (i, mut elem) in sprites.iter_mut().enumerate() {
596 if elem.need_update {
597 let vert = &mut vertices[(i * 4)..(i * 4 + 4)];
598 self::update_sprite(&mut elem, Vector::new(0.0, 0.0), vert);
599 sprite_mod = true;
600 }
601 }
602 }
603
604 if sprite_mod {
605 self.update_vbo();
606 }
607 if self.need_update {
608 self.update_model();
609 }
610 }
611}
612
613fn update_sprite(data: &mut SpriteData, origin: Vector<f32>, vertice: &mut [Vertex]) {
614 data.model = Matrix4::identity().append_translation(&Vector3::new(
615 data.pos.x - origin.x,
616 data.pos.y - origin.y,
617 0.0,
618 ));
619
620 data.model *= Matrix4::from_euler_angles(0.0, 0.0, data.rotation * (3.14116 * 180.0));
621
622 for vertex in vertice {
623 let b = data.model * Vector4::new(vertex.pos.x, vertex.pos.y, 0.0, 1.0);
624 vertex.pos = Vector::new(b.x, b.y);
625 }
626
627 if data.rotation > 360.0 {
628 data.rotation = 0.0;
629 }
630
631 data.need_update = false;
632}
633
634impl Default for SpriteBatch {
635 fn default() -> Self {
636 SpriteBatch {
637 texture: None,
638 sprites: Vec::new(),
639 vertice: Vec::new(),
640 gl_objects: Self::create_vbo(),
641 glob_origin: Vector::new(0.0, 0.0),
642 glob_pos: Vector::new(0.0, 0.0),
643 glob_scale: Vector::new(0.0, 0.0),
644 glob_rotation: 0.0,
645 len: 0,
646 need_update: false,
647 model: Matrix4::identity(),
648 }
649 }
650}
651
652impl From<&Rc<Texture>> for SpriteBatch {
653 fn from(what: &Rc<Texture>) -> SpriteBatch {
654 let (width, height) = (what.width(), what.height());
655
656 SpriteBatch {
657 texture: Some(Rc::clone(what)),
658 sprites: Vec::new(),
659 vertice: Vec::new(),
660 gl_objects: Self::create_vbo(),
661 glob_origin: Vector::new((width / 2) as f32, (height / 2) as f32),
662 glob_pos: Vector::new(0.0, 0.0),
663 glob_scale: Vector::new(1.0, 1.0),
664 glob_rotation: 0.0,
665 len: 0,
666 need_update: false,
667 model: Matrix4::identity(),
668 }
669 }
670}
671
672#[cfg(test)]
673mod test {
674 extern crate test;
675
676 use self::test::Bencher;
677 use super::{SpriteBatch, SpriteData};
678 use draw::Drawable;
679 use std::rc::Rc;
680 use transform::Movable;
681 use window::Window;
682 use {texture::Texture, Vector};
683
684 #[bench]
685 fn sprite_batch_create(bencher: &mut Bencher) {
686 Window::new(100, 100, "Loader");
687
688 bencher.iter(|| {
689 SpriteBatch::new();
690 });
691 }
692
693 #[bench]
694 fn batch_create_with_data(bencher: &mut Bencher) {
695 Window::new(100, 100, "Loader");
696 let texture = Rc::new(Texture::from_path("examples/texture/test.jpg").unwrap());
697 let mut vec = Vec::with_capacity(1000);
698 (0..1000)
699 .into_iter()
700 .for_each(|i| vec.push(SpriteData::new(Vector::new((i * 10 + 10) as f32, 10.0))));
701
702 bencher.iter(|| {
703 let mut batch = SpriteBatch::from(&texture);
704 batch.extend_from_slice(&mut vec);
705 });
706 }
707
708 #[bench]
709 fn batch_update_create(bencher: &mut Bencher) {
710 Window::new(100, 100, "Loader");
711 let texture = Rc::new(Texture::from_path("examples/texture/test.jpg").unwrap());
712 let mut vec = Vec::with_capacity(1000);
713 (0..1000)
714 .into_iter()
715 .for_each(|i| vec.push(SpriteData::new(Vector::new((i * 10 + 10) as f32, 10.0))));
716 let mut batch = SpriteBatch::from(&texture);
717 batch.extend_from_slice(&mut vec);
718
719 bencher.iter(|| {
720 batch.update();
721 });
722 }
723
724 #[bench]
725 fn batch_update_translation_with_bad_update(bencher: &mut Bencher) {
726 Window::new(100, 100, "Loader");
727 let texture = Rc::new(Texture::from_path("examples/texture/test.jpg").unwrap());
728 let mut vec = Vec::with_capacity(1000);
729 (0..1000)
730 .into_iter()
731 .for_each(|i| vec.push(SpriteData::new(Vector::new((i * 10 + 10) as f32, 10.0))));
732 let mut batch = SpriteBatch::from(&texture);
733 batch.extend_from_slice(&mut vec);
734
735 bencher.iter(|| {
736 batch.update();
740 batch.translate(Vector::new(100.0, 0.0));
741 batch
742 .get_sprite_mut(0)
743 .unwrap()
744 .translate(Vector::new(100.0, 0.0));
745 batch.update();
746 });
747 }
748
749 #[bench]
750 fn batch_update_translation(bencher: &mut Bencher) {
751 Window::new(100, 100, "Loader");
752 let texture = Rc::new(Texture::from_path("examples/texture/test.jpg").unwrap());
753 let mut vec = Vec::with_capacity(1000);
754 (0..1000)
755 .into_iter()
756 .for_each(|i| vec.push(SpriteData::new(Vector::new((i * 10 + 10) as f32, 10.0))));
757 let mut batch = SpriteBatch::from(&texture);
758 batch.extend_from_slice(&mut vec);
759
760 bencher.iter(|| {
761 batch.translate(Vector::new(100.0, 0.0));
762 batch
763 .get_sprite_mut(0)
764 .map(|x| x.translate(Vector::new(100.0, 0.0)));
765 batch.update();
766 });
767 }
768
769 #[bench]
770 fn batch_update_content(bencher: &mut Bencher) {
771 Window::new(100, 100, "Loader");
772 let texture = Rc::new(Texture::from_path("examples/texture/Dirt.png").unwrap());
773 let mut vec = Vec::with_capacity(100000);
774 (0..100000)
775 .into_iter()
776 .for_each(|i| vec.push(SpriteData::new(Vector::new((i * 10 + 10) as f32, 10.0))));
777 let mut batch = SpriteBatch::from(&texture);
778 batch.extend_from_slice(&mut vec);
779
780 bencher.iter(|| {
781 batch
782 .sprites_mut()
783 .iter_mut()
784 .for_each(|x| x.translate(Vector::new(10.0, 0.0)));
785 batch.update();
786 });
787 }
788}