1 module Engine.Texture; 2 3 import Engine.Atlas; 4 import derelict.freeimage.freeimage; 5 import std.stdio; 6 import derelict.opengl3.gl; 7 import Engine.math; 8 import Engine.Buffer; 9 import Engine.Material; 10 11 struct UV { 12 public float U1; 13 public float V1; 14 public float U2; 15 public float V2; 16 } 17 18 interface ITexture { 19 @property GLenum id(); 20 @property recti rect(); 21 @property ubyte pixelSize(); 22 @property GLenum format(); 23 24 package static GLuint currentTexture = -1; 25 26 @property final int width() { 27 return rect.max.x - rect.min.x; 28 } 29 30 @property final int height() { 31 return rect.max.y - rect.min.y; 32 } 33 34 final void Bind() { 35 if (id != currentTexture) { 36 currentTexture = id; 37 glBindTexture(GL_TEXTURE_2D,id); 38 } 39 } 40 41 42 43 } 44 45 class DynamicTexture : Texture { 46 47 Buffer buffer; 48 int nextIndex = 1; 49 int index = 0; 50 int pboMode = 2; 51 52 this(ITexture texture) { 53 super(texture); 54 this.buffer = new Buffer(this.rect.Dx() * this.rect.Dy() * this.pixelSize,GL_PIXEL_UNPACK_BUFFER,GL_STREAM_DRAW); 55 } 56 57 final void Update(T)(void delegate(T[] arr) update) { 58 buffer.Update(update); 59 this.Bind(); 60 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rect.Dx(), rect.Dy(), format, GL_UNSIGNED_BYTE, null); 61 } 62 63 final void CopyToBuffer() { 64 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rect.Dx(), rect.Dy(), format, GL_UNSIGNED_BYTE, null); 65 } 66 67 } 68 69 class Texture : ITexture { 70 @property GLenum id() { return _id;}; 71 @property recti rect() { return _rect;}; 72 @property ubyte pixelSize() { return _pixelSize;}; 73 @property GLenum format() { return _format; }; 74 75 package GLenum _id; 76 package recti _rect; 77 package ubyte _pixelSize; 78 package GLenum _format; 79 80 package Material material; 81 82 package static immutable bool littleEndian; 83 84 static this() { 85 DerelictFI.load(); 86 littleEndian = cast(bool)FreeImage_IsLittleEndian(); 87 } 88 89 final Material GetMaterial() { 90 if (material is null) { 91 material = new Material(this); 92 } 93 return material; 94 } 95 96 package this() {} 97 98 this(ITexture texture) { 99 this._id = texture.id; 100 this._rect = texture.rect; 101 this._pixelSize = texture.pixelSize; 102 this._format = texture.format; 103 //this._pixelType = texture.pixelType; 104 } 105 106 this(ubyte[] buffer, int width, int height) { 107 this._rect = recti(width,height); 108 this._pixelSize = 2; 109 this._format = GL_RGBA; 110 //generate an OpenGL texture ID for this texture 111 glGenTextures(1, &_id); 112 //bind to the new texture ID 113 glBindTexture(GL_TEXTURE_2D, id); 114 115 glTexImage2D(GL_TEXTURE_2D, 0, this._format, width, height, 116 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, cast(void*)buffer); 117 118 SetFiltering(GL_LINEAR,GL_LINEAR); 119 } 120 121 this(int width, int height) { 122 this._rect = recti(width,height); 123 this._pixelSize = 4*4; 124 this._format = GL_RGBA32F; 125 //generate an OpenGL texture ID for this texture 126 glGenTextures(1, &_id); 127 //bind to the new texture ID 128 glBindTexture(GL_TEXTURE_2D, id); 129 130 glTexImage2D(GL_TEXTURE_2D, 0, this._format, width, height, 131 0, 0, GL_FLOAT, null); 132 133 SetFiltering(GL_NEAREST,GL_NEAREST); 134 } 135 136 this(string filename) { 137 auto fif = FreeImage_GetFileType(filename.ptr, 0); 138 //if still unknown, try to guess the file format from the file extension 139 if(fif == FIF_UNKNOWN) 140 fif = FreeImage_GetFIFFromFilename(filename.ptr); 141 //if still unkown, return failure 142 if(fif == FIF_UNKNOWN) 143 throw new Exception("Unkown format " ~ filename); 144 145 if(!FreeImage_FIFSupportsReading(fif)) { 146 throw new Exception("Cannot read the file " ~ filename); 147 } 148 auto dib = FreeImage_Load(fif, filename.ptr, 0); 149 if (dib == null) { 150 throw new Exception("Cannot load the file " ~ filename); 151 } 152 153 scope(exit) FreeImage_Unload(dib); 154 155 //retrieve the image data 156 auto pixels = FreeImage_GetBits(dib); 157 158 //get the image width and height 159 auto width = FreeImage_GetWidth(dib); 160 auto height = FreeImage_GetHeight(dib); 161 162 _rect = recti(width,height); 163 164 //if this somehow one of these failed (they shouldn't), return failure 165 if((pixels is null) || (width == 0) || (height == 0)) 166 throw new Exception("Unexcepted error there is no width/height/pixels."); 167 168 auto colorType = FreeImage_GetColorType(dib); 169 //generate an OpenGL texture ID for this texture 170 glGenTextures(1, &_id); 171 //bind to the new texture ID 172 glBindTexture(GL_TEXTURE_2D, id); 173 174 175 //store the texture data for OpenGL use 176 switch(colorType) { 177 case FIC_RGB: 178 this._format = GL_RGB; 179 GLenum inFormat; 180 if (littleEndian) { 181 inFormat = GL_BGR; 182 } else { 183 inFormat = GL_RGB; 184 } 185 glTexImage2D(GL_TEXTURE_2D, 0, this._format, width, height, 186 0,inFormat, GL_UNSIGNED_BYTE, pixels); 187 this._pixelSize = 3; 188 break; 189 case FIC_RGBALPHA: 190 this._format = GL_RGBA; 191 GLenum inFormat; 192 if (littleEndian) { 193 inFormat = GL_BGRA; 194 } else { 195 inFormat = GL_RGBA; 196 } 197 glTexImage2D(GL_TEXTURE_2D, 0, this._format, width, height, 198 0, inFormat, GL_UNSIGNED_BYTE, pixels); 199 this._pixelSize = 4; 200 break; 201 default: 202 throw new Exception("Cannot this handle pixel type."); 203 } 204 205 SetFiltering(GL_NEAREST,GL_NEAREST); 206 } 207 208 UV RectUV(recti rect) { 209 auto w = cast(double)width; 210 auto h = cast(double)height; 211 return UV((cast(double)rect.min.x)/w, 212 (cast(double)rect.min.y)/h, 213 (cast(double)rect.max.x)/w, 214 (cast(double)rect.max.y)/h); 215 //return vec2(cast(double)width = r. 216 } 217 218 void SetFiltering(GLenum mag, GLenum min) { 219 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag); 220 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min); 221 } 222 223 224 225 }