1 /** 2 * ae.ui.video.sdl.renderer 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.ui.video.sdl2.renderer; 15 16 import std.exception; 17 18 import derelict.sdl2.sdl; 19 20 import ae.ui.shell.sdl2.shell; 21 import ae.ui.video.renderer; 22 import ae.ui.video.software.common; 23 24 enum PIXEL_FORMAT = SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_XRGB, SDL_PACKEDLAYOUT_8888, 32, 4); 25 26 /// Draw on a streaming SDL_Texture, and present it 27 final class SDL2SoftwareRenderer : Renderer 28 { 29 SDL_Texture* t; 30 SDL_Renderer* renderer; 31 uint w, h; 32 33 this(SDL_Renderer* renderer, uint w, uint h) 34 { 35 this.renderer = renderer; 36 this.w = w; 37 this.h = h; 38 39 t = sdlEnforce(SDL_CreateTexture(renderer, PIXEL_FORMAT, SDL_TEXTUREACCESS_STREAMING, w, h), "SDL_CreateTexture failed"); 40 } 41 42 override Bitmap fastLock() 43 { 44 assert(false, "Can't fastLock SDL2SoftwareRenderer"); 45 } 46 47 override Bitmap lock() 48 { 49 if (!locked) 50 { 51 void* pixels; 52 int pitch; 53 sdlEnforce(SDL_LockTexture(t, null, &pixels, &pitch)==0, "SDL_LockTexture failed"); 54 _bitmap = Bitmap(cast(COLOR*)pixels, w, h, pitch / cast(int)COLOR.sizeof); 55 locked = true; 56 } 57 return _bitmap; 58 } 59 60 override void unlock() 61 { 62 assert(locked); 63 SDL_UnlockTexture(t); 64 locked = false; 65 } 66 67 override void present() 68 { 69 if (locked) 70 unlock(); 71 72 SDL_RenderCopy(renderer, t, null, null); 73 SDL_RenderPresent(renderer); 74 } 75 76 override void shutdown() 77 { 78 SDL_DestroyTexture(t); 79 } 80 81 // ********************************************************************** 82 83 override @property uint width() 84 { 85 return w; 86 } 87 88 override @property uint height() 89 { 90 return h; 91 } 92 93 mixin SoftwareRenderer; 94 95 private: 96 Bitmap _bitmap; 97 bool locked; 98 99 @property Bitmap bitmap() 100 { 101 if (!locked) 102 return lock(); 103 return _bitmap; 104 } 105 } 106 107 /// Use SDL 2 drawing APIs. 108 final class SDL2Renderer : Renderer 109 { 110 SDL_Renderer* renderer; 111 uint w, h; 112 113 this(SDL_Renderer* renderer, uint w, uint h) 114 { 115 this.renderer = renderer; 116 this.w = w; 117 this.h = h; 118 } 119 120 override Bitmap fastLock() 121 { 122 assert(false, "Can't fastLock SDL2Renderer"); 123 } 124 125 override Bitmap lock() 126 { 127 assert(false, "Not possible"); 128 } 129 130 override void unlock() 131 { 132 assert(false, "Not possible"); 133 } 134 135 override void present() 136 { 137 SDL_RenderPresent(renderer); 138 } 139 140 override void shutdown() {} 141 142 // ********************************************************************** 143 144 override void putPixel(int x, int y, COLOR color) 145 { 146 SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.x); 147 SDL_RenderDrawPoint(renderer, x, y); 148 } 149 150 override void putPixels(Pixel[] pixels) 151 { 152 foreach (ref pixel; pixels) 153 putPixel(pixel.x, pixel.y, pixel.color); 154 } 155 156 override void line(float x0, float y0, float x1, float y1, COLOR color) 157 { 158 SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.x); 159 SDL_RenderDrawLine(renderer, cast(int)x0, cast(int)y0, cast(int)x1, cast(int)y1); 160 } 161 162 override void vline(int x, int y0, int y1, COLOR color) 163 { 164 SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.x); 165 SDL_RenderDrawLine(renderer, x, y0, x, y1); 166 } 167 168 override void hline(int x0, int x1, int y, COLOR color) 169 { 170 SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.x); 171 SDL_RenderDrawLine(renderer, x0, y, x1, y); 172 } 173 174 override void fillRect(int x0, int y0, int x1, int y1, COLOR color) 175 { 176 SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.x); 177 auto rect = SDL_Rect(x0, y0, x1-x0, y1-y0); 178 SDL_RenderFillRect(renderer, &rect); 179 } 180 181 override void fillRect(float x0, float y0, float x1, float y1, COLOR color) 182 { 183 fillRect(cast(int)x0, cast(int)y0, cast(int)x1, cast(int)y1, color); 184 } 185 186 override void clear() 187 { 188 SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); 189 SDL_RenderClear(renderer); 190 } 191 192 override void draw(int x, int y, TextureSource source, int u0, int v0, int u1, int v1) 193 { 194 auto data = updateTexture(source); 195 auto srcRect = SDL_Rect(u0, v0, u1-u0, v1-v0); 196 auto dstRect = SDL_Rect(x, y, u1-u0, v1-v0); 197 sdlEnforce(SDL_RenderCopy(renderer, data.t, &srcRect, &dstRect)==0, "SDL_RenderCopy"); 198 } 199 200 override void draw(float x0, float y0, float x1, float y1, TextureSource source, int u0, int v0, int u1, int v1) 201 { 202 auto data = updateTexture(source); 203 auto srcRect = SDL_Rect(u0, v0, u1-u0, v1-v0); 204 auto dstRect = SDL_Rect(cast(int)x0, cast(int)y0, cast(int)(x1-x0), cast(int)(y1-y0)); 205 sdlEnforce(SDL_RenderCopy(renderer, data.t, &srcRect, &dstRect)==0, "SDL_RenderCopy"); 206 } 207 208 // ********************************************************************** 209 210 private SDLTextureRenderData updateTexture(TextureSource source) 211 { 212 auto data = cast(SDLTextureRenderData) cast(void*) source.renderData[Renderers.SDL2]; 213 if (data is null || data.invalid) 214 { 215 source.renderData[Renderers.SDL2] = data = new SDLTextureRenderData; 216 data.next = SDLTextureRenderData.head; 217 SDLTextureRenderData.head = data; 218 rebuildTexture(data, source); 219 } 220 else 221 { 222 if (SDL_QueryTexture(data.t, null, null, null, null) != 0) 223 { 224 data.destroy(); 225 rebuildTexture(data, source); 226 } 227 else 228 if (data.textureVersion != source.textureVersion) 229 { 230 auto pixelInfo = source.getPixels(); 231 sdlEnforce(SDL_UpdateTexture(data.t, null, pixelInfo.pixels, cast(uint)pixelInfo.pitch)==0, "SDL_UpdateTexture"); 232 data.textureVersion = source.textureVersion; 233 } 234 } 235 return data; 236 } 237 238 private void rebuildTexture(SDLTextureRenderData data, TextureSource source) 239 { 240 auto pixelInfo = source.getPixels(); 241 data.t = sdlEnforce(SDL_CreateTexture(renderer, PIXEL_FORMAT, SDL_TEXTUREACCESS_STREAMING, pixelInfo.w, pixelInfo.h), "SDL_CreateTexture"); 242 sdlEnforce(SDL_UpdateTexture(data.t, null, pixelInfo.pixels, cast(uint)pixelInfo.pitch)==0, "SDL_UpdateTexture"); 243 data.textureVersion = source.textureVersion; 244 data.invalid = false; 245 } 246 247 // ********************************************************************** 248 249 override @property uint width() 250 { 251 return w; 252 } 253 254 override @property uint height() 255 { 256 return h; 257 } 258 } 259 260 private final class SDLTextureRenderData : TextureRenderData 261 { 262 SDL_Texture* t; 263 SDLTextureRenderData next; 264 static SDLTextureRenderData head; 265 bool invalid; 266 uint w, h; 267 268 void destroy() 269 { 270 invalid = true; 271 SDL_DestroyTexture(t); 272 } 273 }