1 module prova.graphics.spritebatch; 2 3 import prova.assets; 4 import prova.attachables; 5 import prova.graphics; 6 import prova.math; 7 import prova.util; 8 import std.typecons; 9 10 /// 11 final class SpriteBatch 12 { 13 /// Copy of GraphicsContext.spriteShader 14 ShaderProgram shaderProgram; 15 private bool begun; 16 private Mesh mesh; 17 private GraphicsContext context; 18 private RenderTarget renderTarget; 19 private Matrix projection; 20 private LinkedList!(Tuple!(Sprite, Matrix)) sprites; 21 22 /// 23 this(GraphicsContext context) 24 { 25 shaderProgram = context.spriteShader; 26 27 sprites = new LinkedList!(Tuple!(Sprite, Matrix)); 28 29 mesh = new SpriteMesh(); 30 } 31 32 /// 33 void begin(RenderTarget renderTarget, Matrix projection) 34 { 35 assert(!begun, "Batch should not already be started"); 36 37 this.renderTarget = renderTarget; 38 this.projection = projection; 39 begun = true; 40 } 41 42 /// 43 void batchSprite(AnimatedSprite sprite, Matrix transform) 44 { 45 sprite.update(); 46 47 batchSprite(cast(Sprite) sprite, transform); 48 } 49 50 /// 51 void batchSprite(Sprite sprite, Matrix transform) 52 { 53 assert(begun, "Batch should have started with begin(RenderTarget, Matrix projection)"); 54 55 sprites.insertBack(tuple(sprite, transform)); 56 } 57 58 /// Draws batched sprites 59 void end() 60 { 61 assert(begun, "Batch should have started with begin(RenderTarget, Matrix projection)"); 62 63 Color lastTint; 64 uint lastTexture = -1; 65 66 // set the inital value for the tint 67 shaderProgram.setVector4("tint", lastTint); 68 69 foreach(Tuple!(Sprite, Matrix) spriteTuple; sprites) { 70 Sprite sprite = spriteTuple[0]; 71 Matrix transform = spriteTuple[1]; 72 73 if(sprite.texture.id != lastTexture) { 74 shaderProgram.setTexture(0, sprite.texture); 75 lastTexture = sprite.texture.id; 76 } 77 78 if(sprite.tint != lastTint) { 79 shaderProgram.setVector4("tint", sprite.tint); 80 lastTint = sprite.tint; 81 } 82 83 drawSprite(sprite, transform); 84 } 85 86 sprites.clear(); 87 begun = false; 88 } 89 90 /// 91 void drawSprite(Sprite sprite, Matrix transform) 92 { 93 Vector2 size = sprite.clip.getSize(); 94 Vector3 center = size / 2; 95 96 Rect clip; 97 clip.left = sprite.clip.left / sprite.texture.width; 98 clip.top = 1 - (sprite.clip.top + sprite.clip.height) / sprite.texture.height; 99 clip.width = sprite.clip.width / sprite.texture.width; 100 clip.height = sprite.clip.height / sprite.texture.height; 101 102 Matrix offset = Matrix.identity; 103 offset = offset.scale(size); 104 offset = offset.translate(-sprite.origin - center); 105 106 shaderProgram.setMatrix("transform", projection * (transform * offset)); 107 shaderProgram.setVector4("clip", clip); 108 shaderProgram.drawMesh(mesh, renderTarget, DrawMode.TRIANGLE_FAN); 109 } 110 }