1 module evael.graphics.SpriteBatch; 2 3 import evael.graphics.GL; 4 5 import evael.graphics.GraphicsDevice; 6 import evael.graphics.Drawable; 7 import evael.graphics.Vertex; 8 9 import evael.utils.Math; 10 import evael.utils.Color; 11 12 import dnogc.DynamicArray; 13 import dnogc.Utils; 14 15 /** 16 * SpriteBatch 17 * Draw batched quads. 18 */ 19 class SpriteBatch(VertexType) : Drawable 20 { 21 /// Vertices list 22 private DynamicArray!VertexType m_vertices; 23 24 /// Indices list 25 private DynamicArray!uint m_indices; 26 27 /// Indicates if quads data has been sent to opengl 28 private bool m_initialized; 29 30 /// Tilesize 31 private uint m_tileSize; 32 33 /// Triangles number 34 private uint m_trianglesNumber; 35 36 /** 37 * SpriteBatch constructor. 38 */ 39 @nogc @safe 40 public this(GraphicsDevice graphics) pure nothrow 41 { 42 super(graphics); 43 this.m_initialized = false; 44 } 45 46 /** 47 * SpriteBatch destructor. 48 */ 49 public void dispose() 50 { 51 this.m_vertices.dispose(); 52 this.m_indices.dispose(); 53 } 54 55 /** 56 * Initializes SpriteBatch. 57 */ 58 @nogc 59 public void initialize() nothrow 60 { 61 this.m_vao = this.m_graphicsDevice.generateVAO(); 62 this.m_vertexBuffer = this.m_graphicsDevice.createVertexBuffer(VertexType.sizeof * this.m_vertices.length, this.m_vertices.ptr); 63 this.m_indexBuffer = this.m_graphicsDevice.createIndexBuffer(uint.sizeof * this.m_indices.length, this.m_indices.ptr); 64 65 this.m_graphicsDevice.setVertexBuffer!(VertexType)(this.m_vertexBuffer); 66 67 this.m_graphicsDevice.bindVAO(0); 68 69 this.m_trianglesNumber = this.m_indices.length / 3; 70 71 this.m_initialized = true; 72 } 73 74 public override void draw(in float deltaTime, mat4 view, mat4 projection) 75 { 76 if (!this.m_isVisible) 77 return; 78 79 this.m_graphicsDevice.enableShader(this.m_shader); 80 81 if (this.m_texture !is null) 82 { 83 glActiveTexture(GL_TEXTURE0); 84 this.m_graphicsDevice.bindTexture(this.m_texture); 85 } 86 87 mat4 translation = translationMatrix(this.m_position); 88 mat4 rotation = this.m_rotation.toMatrix4x4(); 89 mat4 scale = scaleMatrix(this.m_scale); 90 mat4 model = rotation * scale; 91 92 this.m_graphicsDevice.setMatrix(this.m_shader.modelMatrix, model.arrayof.ptr); 93 this.m_graphicsDevice.setMatrix(this.m_shader.viewMatrix, view.arrayof.ptr); 94 this.m_graphicsDevice.setMatrix(this.m_shader.projectionMatrix, projection.arrayof.ptr); 95 96 this.m_graphicsDevice.bindVAO(this.m_vao); 97 this.m_graphicsDevice.drawIndexedPrimitives!(PrimitiveType.Triangle)(this.m_trianglesNumber); 98 this.m_graphicsDevice.bindVAO(0); 99 100 this.m_graphicsDevice.disableShader(); 101 } 102 103 /** 104 * Add vertices in the batch. 105 * Params: 106 * quad : quad 107 */ 108 @nogc 109 public void addVertices(VertexType[] vertices, uint[] indices) 110 { 111 if (this.m_initialized) 112 { 113 debug dln("Trying to add a quad to an already initialized SpriteBatch."); 114 return; 115 } 116 117 foreach (ref v; vertices) 118 { 119 this.m_vertices.insert(v); 120 } 121 122 foreach (i; indices) 123 { 124 this.m_indices.insert(i); 125 } 126 } 127 128 static if (is(VertexType : Vertex2PositionColorTexture)) 129 { 130 public void addQuad(in vec2 position, in ivec2 textureTilePosition) 131 { 132 immutable int tilePerWidth = this.m_texture.size.width / this.m_tileSize; 133 immutable float v = 1.0f / tilePerWidth; 134 135 import std.algorithm; 136 import std.array; 137 138 uint[] indices = [0, 1, 2, 2, 1, 3].map!(index => index + this.m_vertices.length).array; 139 140 this.addVertices( 141 [ 142 // Bottom-left vertex 143 Vertex2PositionColorTexture(vec2(position.x, position.y), Color.White, vec2(textureTilePosition.x * v, (textureTilePosition.y + 1) * v)), 144 // Top-left vertex 145 Vertex2PositionColorTexture(vec2(position.x, position.y + this.m_tileSize), Color.White, vec2(textureTilePosition.x * v, textureTilePosition.y * v)), 146 // Bottom-right vertex 147 Vertex2PositionColorTexture(vec2(position.x + this.m_tileSize, position.y), Color.White, vec2((textureTilePosition.x + 1) * v, (textureTilePosition.y + 1) * v)), 148 // Top-right vertex 149 Vertex2PositionColorTexture(vec2(position.x + this.m_tileSize, position.y + this.m_tileSize), Color.White, vec2((textureTilePosition.x + 1) * v, textureTilePosition.y * v)) 150 ], 151 indices 152 ); 153 } 154 } 155 156 @nogc @safe 157 @property pure nothrow 158 { 159 public void tileSize(in uint value) 160 { 161 this.m_tileSize = value; 162 } 163 } 164 }