1 /** 2 * This module provides classes used to display graphics. 3 * It builds uppon $(LINK2 https://www.libsdl.org/download-2.0.php, SDL2) 4 * and if you'd rather use sdl it's functions can be called directly by 5 * imporrting like this: `import caLit_util.graphics.derelict.sdl2.sdl` 6 */ 7 8 module caLib_util.graphics; 9 10 import std.stdio : writeln; 11 import std.file : dirName, thisExePath; 12 import std.exception : enforce; 13 import std.conv : to; 14 import caLib_util.build : arch, os; 15 16 public import derelict.sdl2.sdl; 17 18 19 20 shared static this() 21 { 22 DerelictSDL2.load(); 23 } 24 25 26 27 /** 28 * A class representing a window 29 * 30 * It wrapps a $(B SDL_Window) and $(B SDL_Renderer) wich can both be freely retrived 31 * and manipulated 32 */ 33 class Window 34 { 35 36 private: 37 38 uint screenWidth; 39 uint screenHeight; 40 41 SDL_Window* window; 42 SDL_Renderer* renderer; 43 44 public: 45 46 /// 47 this(int screenWidth, int screenHeight) 48 { 49 this(screenWidth, screenHeight, "GCaL"); 50 } 51 52 /// 53 this(uint screenWidth, uint screenHeight, string title) 54 in { assert(title !is null); } 55 body 56 { 57 58 this.screenWidth = screenWidth; 59 this.screenHeight = screenHeight; 60 61 SDL_Window* window; 62 63 int err = SDL_Init(SDL_INIT_EVERYTHING); 64 65 assert(err >= 0, "SDL could not initialize! SDL_Error: " 66 ~ to!string(SDL_GetError()) ~ "\n"); 67 68 window = SDL_CreateWindow(cast(const char*)title, 69 SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 70 screenWidth, screenHeight, SDL_WINDOW_SHOWN); 71 72 assert(window !is(null), "Window could not be created! SDL_Error: " 73 ~ to!string(SDL_GetError()) ~ "\n"); 74 75 renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); 76 } 77 78 ~this() 79 { 80 SDL_DestroyRenderer(renderer); 81 SDL_DestroyWindow(window); 82 } 83 84 /// Returns the width of the screen in pixels 85 int getWidth() 86 { 87 return screenWidth; 88 } 89 90 /// Returns the height of the screen in pixels 91 int getHeight() 92 { 93 return screenHeight; 94 } 95 96 /// Returns a reference to the $(B SDL_Window) wrapped in this class 97 SDL_Window* getWindow() 98 { 99 return window; 100 } 101 102 /// Returns a reference to the $(B SDL_Renderer) wrapped in this class 103 SDL_Renderer* getRenderer() 104 { 105 return renderer; 106 } 107 } 108 109 110 111 /** 112 * A class representing a texture. A texture contains the pixeldata that can 113 * be rendered to its associated $(B Window). 114 * 115 * It wrapps a $(B SDL_Texture) wich can be freely retrived and manipulated 116 */ 117 class Texture 118 { 119 120 private: 121 122 uint textureWidth; 123 uint textureHeight; 124 125 SDL_Texture* texture; 126 127 int pitch; 128 129 immutable bpp = 4; 130 immutable depth = 8*bpp; 131 immutable pixelFormat = SDL_PIXELFORMAT_ARGB8888; 132 133 public: 134 135 /// 136 this(Window window, int textureWidth, int textureHeight) 137 in 138 { assert(window !is null); } 139 body 140 { 141 DerelictSDL2.load(); 142 143 this.textureWidth = textureWidth; 144 this.textureHeight = textureHeight; 145 pitch = textureWidth * bpp; 146 depth = 8*bpp; 147 148 texture = SDL_CreateTexture(window.getRenderer(), 149 pixelFormat, 150 SDL_TEXTUREACCESS_STREAMING, 151 textureWidth, textureHeight); 152 } 153 154 ~this() 155 { 156 SDL_DestroyTexture(texture); 157 } 158 159 /** 160 * Lock the texture to manipulate its pixeldata 161 * 162 * Locks the thexture meaning that the texture can't be used for anything 163 * untill its $(CU unlock) method is called 164 * 165 * A pointer is returned. It points to the pixeldata wich can be manipulated. 166 * The length of the pixeldata is the textures width*height. The value for 167 * a pixel at location x, y can be obtained by getting the element at index 168 * y * width + x 169 * 170 * Examples: 171 * ---- 172 * auto window = new Window(800, 400, "myTestWindow"); //create a window 173 * auto texture = new Texture(window, 300, 100); //create a texture 174 * uint* pixels = texture.lock() //lock the texture and get the pixeldata pointer 175 * pixels[10 * texture.getWidth() + 20] = 0x00FF0000; // make the pixel at position 20, 10 red 176 * texture.lock() //now were done manipulating the pixels, unlock the texture 177 * 178 * // render the texture to the window 179 * SDL_RenderCopy(window.getRenderer(), texture.getTexture(), SDL_Rect(0,0,300,100), SDL_Rect(0,0,800,400)); 180 * SDL_RenderPresent(window.getRenderer()); 181 * ---- 182 * 183 * Returns: 184 * A pointer to the pixeldata, 185 */ 186 uint* lock() 187 { 188 void* pixelsptr; 189 int[] pitch = [pitch]; 190 SDL_LockTexture(texture, null, &pixelsptr, pitch.ptr); 191 uint* pixels = cast(uint*)(pixelsptr); 192 return pixels; 193 } 194 195 /// Unlocks the texture 196 void unlock() 197 { 198 SDL_UnlockTexture(texture); 199 } 200 201 /// Returns the texture's width in pixels 202 uint getWidth() 203 { 204 return textureWidth; 205 } 206 207 /// Return the texture's height in pixels 208 uint getHeight() 209 { 210 return textureHeight; 211 } 212 213 /** 214 * Returns the pixel format 215 * 216 * The pixel format is a SDL_PIXELFORMAT and the default is 217 * SDL_PIXELFORMAT_ARGB8888 218 */ 219 int getPixelFormat() 220 { 221 return pixelFormat; 222 } 223 224 /// Returns the pixels depth 225 int getDepth() 226 { 227 return depth; 228 } 229 230 /// Returns the pitch 231 int getPitch() 232 { 233 return pitch; 234 } 235 236 /// Retuens the internal $(B SDL_Texture) 237 SDL_Texture* getTexture() 238 { 239 return texture; 240 } 241 } 242 243 244 245 /// Creates a $(B SDL_Surface) from a $(B Texture). 246 SDL_Surface* createRGBSurfaceFromTexture(Texture texture) 247 { 248 uint* pixels = texture.lock(); 249 scope(exit) texture.unlock(); 250 return SDL_CreateRGBSurfaceFrom(pixels, texture.getWidth(), 251 texture.getHeight(), texture.getDepth(), texture.getPitch(), 252 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); 253 } 254 255 256 257 /// Saves a $(B Texture) as a bitmap picture 258 void saveTextureAsBmp(Texture texture, string path) 259 { 260 SDL_Surface* sshot = createRGBSurfaceFromTexture(texture); 261 scope(exit) SDL_FreeSurface(sshot); 262 263 int err = SDL_SaveBMP(sshot, cast(const char*)(path)); 264 265 enforce(err != -1, "Could not save image \"" ~ path ~ "\" SDL_Error: " 266 ~ to!string(SDL_GetError())); 267 }