1 /* 2 ******************************************************************************************* 3 * Dgame (a D game framework) - Copyright (c) Randy Schütt 4 * 5 * This software is provided 'as-is', without any express or implied warranty. 6 * In no event will the authors be held liable for any damages arising from 7 * the use of this software. 8 * 9 * Permission is granted to anyone to use this software for any purpose, 10 * including commercial applications, and to alter it and redistribute it 11 * freely, subject to the following restrictions: 12 * 13 * 1. The origin of this software must not be misrepresented; you must not claim 14 * that you wrote the original software. If you use this software in a product, 15 * an acknowledgment in the product documentation would be appreciated but is 16 * not required. 17 * 18 * 2. Altered source versions must be plainly marked as such, and must not be 19 * misrepresented as being the original software. 20 * 21 * 3. This notice may not be removed or altered from any source distribution. 22 ******************************************************************************************* 23 */ 24 module Dgame.Graphics.Sprite; 25 26 private { 27 import derelict.opengl3.gl; 28 29 import Dgame.Graphics.Drawable; 30 import Dgame.Graphics.Transformable; 31 import Dgame.Graphics.Texture; 32 import Dgame.Graphics.Shape; 33 import Dgame.Graphics.Blend; 34 import Dgame.Math.Vector2; 35 import Dgame.Math.Rect; 36 import Dgame.System.VertexRenderer; 37 } 38 39 /** 40 * Sprite represents a drawable object and maintains a texture and his position. 41 * 42 * Author: rschuett 43 */ 44 class Sprite : Transformable, Drawable, Blendable { 45 protected: 46 Texture _tex; 47 Blend _blend; 48 49 protected: 50 void _render() const in { 51 assert(this._tex !is null, "Sprite couldn't rendered, because the Texture is null."); 52 } body { 53 glPushMatrix(); 54 scope(exit) glPopMatrix(); 55 56 super._applyTranslation(); 57 58 if (!glIsEnabled(GL_TEXTURE_2D)) 59 glEnable(GL_TEXTURE_2D); 60 61 glPushAttrib(GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT); 62 scope(exit) glPopAttrib(); 63 64 if (this._blend !is null) 65 this._blend.applyBlending(); 66 67 const ShortRect clipRect = this.getClipRect(); 68 69 float dx = 0f; 70 float dy = 0f; 71 float dw = clipRect.width; 72 float dh = clipRect.height; 73 74 float[12] vertices = [ 75 dx, dy, 0f, 76 dx + dw, dy, 0f, 77 dx + dw, dy + dh, 0f, 78 dx, dy + dh, 0f 79 ]; 80 81 float[8] texCoords = this._getTextureCoordinates(); 82 83 VertexRenderer.pointTo(Target.Vertex, &vertices[0]); 84 VertexRenderer.pointTo(Target.TexCoords, &texCoords[0]); 85 86 scope(exit) { 87 VertexRenderer.disableAllStates(); 88 this._tex.unbind(); 89 } 90 91 this._tex.bind(); 92 VertexRenderer.drawArrays(Shape.Type.TriangleFan, vertices.length); 93 } 94 95 float[8] _getTextureCoordinates() const pure nothrow { 96 return [0f, 0f, 1f, 0f, 1f, 1f, 0f, 1f]; 97 } 98 99 public: 100 /** 101 * CTor 102 */ 103 this() { 104 this(null); 105 } 106 107 /** 108 * CTor 109 */ 110 this(Texture tex) { 111 this.setTexture(tex); 112 } 113 114 /** 115 * Calculate, store and return the center point. 116 * Usefull for e.g. rotate. 117 */ 118 override ref const(Vector2s) calculateCenter() pure nothrow { 119 super.setCenter(this._tex.width / 2, this._tex.height / 2); 120 return super.getCenter(); 121 } 122 123 /** 124 * Check whether the bounding box of this Sprite collide 125 * with the bounding box of another Sprite 126 */ 127 bool collideWith(const Sprite rhs) const { 128 const ShortRect rhs_clip = rhs.getClipRect(); 129 130 return this.collideWith(rhs_clip); 131 } 132 133 /** 134 * Check whether the bounding box of this Sprite collide 135 * with the given Rect 136 */ 137 bool collideWith(ref const ShortRect rect) const { 138 return this.getClipRect().intersects(rect); 139 } 140 141 /** 142 * Rvalue version 143 */ 144 bool collideWith(const ShortRect rect) const { 145 return this.collideWith(rect); 146 } 147 148 /** 149 * Returns the current Clip Rect, the area, 150 * where the Sprite lies with the same size as the Sprite. 151 */ 152 ShortRect getClipRect() const pure nothrow { 153 return ShortRect(cast(short) super.position.x, cast(short) super.position.y, 154 this._tex.width, this._tex.height); 155 } 156 157 final: 158 /** 159 * Set (or reset) the current Blend instance. 160 */ 161 void setBlend(Blend blend) pure nothrow { 162 this._blend = blend; 163 } 164 165 /** 166 * Returns the current Blend instance, or null. 167 */ 168 inout(Blend) getBlend() inout pure nothrow { 169 return this._blend; 170 } 171 172 /** 173 * Returns the current width (the width of the current texture). 174 */ 175 @property 176 ushort width() const pure nothrow 177 in { 178 assert(this._tex !is null); 179 } body { 180 return this._tex.width; 181 } 182 183 /** 184 * Returns the current height (the height of the current texture). 185 */ 186 @property 187 ushort height() const pure nothrow 188 in { 189 assert(this._tex !is null); 190 } body { 191 return this._tex.height; 192 } 193 194 /** 195 * Check if the current Sprite has already a Texture/Image. 196 * If not, nothing can be drawn. 197 * But it does not check if the current Texture is valid. 198 */ 199 bool hasTexture() const pure nothrow { 200 return this._tex !is null; 201 } 202 203 /** 204 * Set or replace the current Texture. 205 */ 206 void setTexture(Texture tex) in { 207 assert(tex !is null, "Cannot set a null Texture."); 208 } body { 209 this._tex = tex; 210 } 211 212 /** 213 * Returns the current Texture or null if there is none. 214 */ 215 inout(Texture) getTexture() inout pure nothrow { 216 return this._tex; 217 } 218 }