1 module dgt.texture; 2 import derelict.sdl2.sdl, derelict.sdl2.image; 3 import derelict.opengl; 4 import dgt.array : Array; 5 import dgt.io; 6 import dgt.geom : Rectangle; 7 import dgt.util : nullTerminate; 8 9 import core.stdc..string; 10 11 ///The format of each pixel in byte order 12 enum PixelFormat : GLenum 13 { 14 RGB = GL_RGB, 15 RGBA = GL_RGBA, 16 BGR = GL_BGR, 17 BGRA = GL_BGRA 18 } 19 20 /** 21 A drawable texture which can also be a region of a larger texture 22 */ 23 struct Texture 24 { 25 package uint id; 26 private: 27 int width, height; 28 Rectangle region; 29 30 @disable this(); 31 32 @nogc nothrow public: 33 ///Create a Texture from data in memory 34 this(ubyte* data, int w, int h, PixelFormat format) 35 { 36 GLuint texture; 37 glGenTextures(1, &texture); 38 glBindTexture(GL_TEXTURE_2D, texture); 39 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 40 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 41 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 42 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 43 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, format, GL_UNSIGNED_BYTE, data); 44 glGenerateMipmap(GL_TEXTURE_2D); 45 id = texture; 46 width = w; 47 height = h; 48 region = Rectangle(0, 0, w, h); 49 } 50 51 ///Load a texture from a file with a given path 52 this(string name) 53 { 54 auto nameNullTerminated = nullTerminate(name); 55 SDL_Surface* surface = IMG_Load(nameNullTerminated.ptr); 56 nameNullTerminated.destroy(); 57 if (surface == null) 58 { 59 auto buffer = IMG_GetError(); 60 println("Image loading error: ", buffer[0..strlen(buffer)]); 61 this(null, 0, 0, PixelFormat.RGB); 62 } 63 else 64 { 65 this(surface); 66 SDL_FreeSurface(surface); 67 } 68 } 69 70 ///Load a texture from an SDL_Surface in memory 71 this(SDL_Surface* sur) 72 { 73 PixelFormat format; 74 if(sur.format.BytesPerPixel == 4) 75 if(sur.format.Rmask == 0x000000ff) 76 format = PixelFormat.RGBA; 77 else 78 format = PixelFormat.BGRA; 79 else 80 if(sur.format.Rmask == 0x000000ff) 81 format = PixelFormat.RGB; 82 else 83 format = PixelFormat.BGR; 84 this(cast(ubyte*)sur.pixels, sur.w, sur.h, format); 85 } 86 87 ///Remove the texture from GPU memory 88 void destroy() 89 { 90 glDeleteTextures(1, &id); 91 } 92 93 pure: 94 ///Get a texture that represents a region of a larger texture 95 Texture getSlice(Rectangle region) 96 { 97 Texture tex = this; 98 tex.region = Rectangle(this.region.x + region.x, 99 this.region.y + region.y, region.width, region.height); 100 return tex; 101 } 102 ///Get the width of the source image 103 @property int sourceWidth() const { return width; } 104 ///Get the height of the source image 105 @property int sourceHeight() const { return height; } 106 ///Get the size of the texture's region 107 @property Rectangle size() const { return region; } 108 }