00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <SDL.h>
00026
00027
00028
00029
00030
00031 #include "util/base/exception.h"
00032 #include "util/math/fife_math.h"
00033 #include "util/log/logger.h"
00034 #include "video/devicecaps.h"
00035
00036 #include "renderbackendsdl.h"
00037 #include "sdlimage.h"
00038 #include "SDL_image.h"
00039 #include "SDL_getenv.h"
00040
00041 namespace FIFE {
00042 static Logger _log(LM_VIDEO);
00043
00044 RenderBackendSDL::RenderBackendSDL(const SDL_Color& colorkey) :
00045 RenderBackend(colorkey){
00046 }
00047
00048 RenderBackendSDL::~RenderBackendSDL() {
00049 deinit();
00050 }
00051
00052 const std::string& RenderBackendSDL::getName() const {
00053 static std::string backend_name = "SDL";
00054 return backend_name;
00055 }
00056
00057 void RenderBackendSDL::init(const std::string& driver) {
00058 char* buf;
00059 if (driver != "") {
00060 std::string envVar = std::string("SDL_VIDEODRIVER=") + driver;
00061 buf = const_cast<char*>(envVar.c_str());
00062 putenv(buf);
00063 }
00064
00065 if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
00066 throw SDLException(SDL_GetError());
00067
00068 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
00069 }
00070
00071 void RenderBackendSDL::clearBackBuffer() {
00072 SDL_Rect rect;
00073 rect.x = 0;
00074 rect.y = 0;
00075 rect.w = getWidth();
00076 rect.h = getHeight();
00077 SDL_SetClipRect(m_screen, &rect);
00078 SDL_FillRect(m_screen, 0, 0x00);
00079 }
00080
00081 void RenderBackendSDL::createMainScreen(const ScreenMode& mode, const std::string& title, const std::string& icon){
00082 if(icon != "") {
00083 SDL_Surface *img = IMG_Load(icon.c_str());
00084 if(img != NULL) {
00085 SDL_WM_SetIcon(img, 0);
00086 SDL_FreeSurface(img);
00087 }
00088 }
00089
00090 setScreenMode(mode);
00091 SDL_WM_SetCaption(title.c_str(), 0);
00092 }
00093
00094 void RenderBackendSDL::setScreenMode(const ScreenMode& mode) {
00095 uint16_t width = mode.getWidth();
00096 uint16_t height = mode.getHeight();
00097 uint16_t bitsPerPixel = mode.getBPP();
00098 bool fs = mode.isFullScreen();
00099 uint32_t flags = mode.getSDLFlags();
00100
00101 if (bitsPerPixel != 0) {
00102 uint16_t bpp = SDL_VideoModeOK(width, height, bitsPerPixel, flags);
00103 if (!bpp){
00104 throw SDLException("Selected video mode not supported!");
00105 }
00106 }
00107
00108 if(m_screen) {
00109 SDL_FreeSurface(m_screen);
00110 }
00111 m_screen = SDL_SetVideoMode(width, height, bitsPerPixel, flags);
00112 if( !m_screen ) {
00113 throw SDLException("Unable to set video mode selected!");
00114 }
00115 m_target = m_screen;
00116
00117 FL_LOG(_log, LMsg("RenderBackendSDL")
00118 << "Videomode " << width << "x" << height
00119 << " at " << int32_t(m_screen->format->BitsPerPixel) << " bpp");
00120
00121 m_rgba_format = *(m_screen->format);
00122 m_rgba_format.Rmask = RMASK;
00123 m_rgba_format.Gmask = GMASK;
00124 m_rgba_format.Bmask = BMASK;
00125 m_rgba_format.Amask = AMASK;
00126
00127
00128 m_screenMode = ScreenMode(width,
00129 height,
00130 bitsPerPixel,
00131 m_screen->flags);
00132 }
00133
00134 void RenderBackendSDL::startFrame() {
00135 RenderBackend::startFrame();
00136 }
00137
00138 void RenderBackendSDL::endFrame() {
00139 SDL_Flip(m_screen);
00140 RenderBackend::endFrame();
00141 }
00142
00143 Image* RenderBackendSDL::createImage(IResourceLoader* loader) {
00144 return new SDLImage(loader);
00145 }
00146
00147 Image* RenderBackendSDL::createImage(const std::string& name, IResourceLoader* loader) {
00148 return new SDLImage(name, loader);
00149 }
00150
00151 Image* RenderBackendSDL::createImage(SDL_Surface* surface) {
00152 return new SDLImage(surface);
00153 }
00154
00155 Image* RenderBackendSDL::createImage(const std::string& name, SDL_Surface* surface) {
00156 return new SDLImage(name, surface);
00157 }
00158
00159 Image* RenderBackendSDL::createImage(const uint8_t* data, uint32_t width, uint32_t height) {
00160 return new SDLImage(data, width, height);
00161 }
00162
00163 Image* RenderBackendSDL::createImage(const std::string& name, const uint8_t* data, uint32_t width, uint32_t height) {
00164 return new SDLImage(name, data, width, height);
00165 }
00166
00167 void RenderBackendSDL::setLightingModel(uint32_t lighting) {
00168 SDLException("Lighting not available under SDL");
00169 }
00170
00171 uint32_t RenderBackendSDL::getLightingModel() const {
00172 return 0;
00173 }
00174
00175 void RenderBackendSDL::setLighting(float red, float green, float blue) {
00176 }
00177
00178 void RenderBackendSDL::resetLighting() {
00179 }
00180
00181 void RenderBackendSDL::resetStencilBuffer(uint8_t buffer) {
00182 }
00183
00184 void RenderBackendSDL::changeBlending(int32_t scr, int32_t dst){
00185 }
00186
00187 void RenderBackendSDL::renderVertexArrays() {
00188 }
00189
00190 void RenderBackendSDL::addImageToArray(uint32_t id, const Rect& rec, float const* st, uint8_t alpha, uint8_t const* rgb) {
00191 }
00192
00193 void RenderBackendSDL::changeRenderInfos(uint16_t elements, int32_t src, int32_t dst, bool light, bool stentest, uint8_t stenref, GLConstants stenop, GLConstants stenfunc) {
00194 }
00195
00196 bool RenderBackendSDL::putPixel(int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00197 return Image::putPixel(m_target, x, y, r, g, b, a);
00198 }
00199
00200 void RenderBackendSDL::drawLine(const Point& p1, const Point& p2, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00201
00202 int32_t x1 = p1.x;
00203 int32_t x2 = p2.x;
00204 int32_t y1 = p1.y;
00205 int32_t y2 = p2.y;
00206 int32_t dx = ABS(x2 - x1);
00207 int32_t dy = ABS(y2 - y1);
00208
00209 if (dx > dy) {
00210 if (x1 > x2) {
00211
00212 x1 ^= x2;
00213 x2 ^= x1;
00214 x1 ^= x2;
00215
00216
00217 y1 ^= y2;
00218 y2 ^= y1;
00219 y1 ^= y2;
00220 }
00221
00222 if (y1 < y2) {
00223 int32_t y = y1;
00224 int32_t p = 0;
00225
00226 for (int32_t x = x1; x <= x2; x++) {
00227 putPixel(x, y, r, g, b, a);
00228 p += dy;
00229 if (p * 2 >= dx) {
00230 y++;
00231 p -= dx;
00232 }
00233 }
00234 }
00235 else {
00236 int32_t y = y1;
00237 int32_t p = 0;
00238
00239 for (int32_t x = x1; x <= x2; x++) {
00240 putPixel(x, y, r, g, b, a);
00241
00242 p += dy;
00243 if (p * 2 >= dx) {
00244 y--;
00245 p -= dx;
00246 }
00247 }
00248 }
00249 }
00250 else {
00251 if (y1 > y2) {
00252
00253 y1 ^= y2;
00254 y2 ^= y1;
00255 y1 ^= y2;
00256
00257
00258 x1 ^= x2;
00259 x2 ^= x1;
00260 x1 ^= x2;
00261 }
00262
00263 if (x1 < x2) {
00264 int32_t x = x1;
00265 int32_t p = 0;
00266
00267 for (int32_t y = y1; y <= y2; y++) {
00268 putPixel(x, y, r, g, b, a);
00269 p += dx;
00270 if (p * 2 >= dy) {
00271 x++;
00272 p -= dy;
00273 }
00274 }
00275 }
00276 else {
00277 int32_t x = x1;
00278 int32_t p = 0;
00279
00280 for (int32_t y = y1; y <= y2; y++) {
00281 putPixel(x, y, r, g, b, a);
00282 p += dx;
00283 if (p * 2 >= dy) {
00284 x--;
00285 p -= dy;
00286 }
00287 }
00288 }
00289 }
00290 }
00291
00292 void RenderBackendSDL::drawTriangle(const Point& p1, const Point& p2, const Point& p3, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00293 drawLine(p1, p2, r, g, b, a);
00294 drawLine(p2, p3, r, g, b, a);
00295 drawLine(p3, p1, r, g, b, a);
00296 }
00297
00298 void RenderBackendSDL::drawRectangle(const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00299 Point p1, p2, p3, p4;
00300
00301 p1.x = p.x;
00302 p1.y = p.y;
00303 p2.x = p.x+w;
00304 p2.y = p.y;
00305 p3.x = p.x+w;
00306 p3.y = p.y+h;
00307 p4.x = p.x;
00308 p4.y = p.y+h;
00309
00310 drawLine(p1, p2, r, g, b, a);
00311 drawLine(p2, p3, r, g, b, a);
00312 drawLine(p3, p4, r, g, b, a);
00313 drawLine(p4, p1, r, g, b, a);
00314 }
00315
00316 void RenderBackendSDL::fillRectangle(const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00317 SDL_Rect rect;
00318 rect.x = p.x;
00319 rect.y = p.y;
00320 rect.w = w;
00321 rect.h = h;
00322
00323 Uint32 color = SDL_MapRGBA(m_target->format, r, g, b, a);
00324 SDL_FillRect(m_target, &rect, color);
00325 }
00326
00327 void RenderBackendSDL::drawQuad(const Point& p1, const Point& p2, const Point& p3, const Point& p4, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00328 fillRectangle(p1, static_cast<uint16_t>(p3.x-p1.x), static_cast<uint16_t>(p3.y-p1.y), r, g, b, a);
00329 }
00330
00331 void RenderBackendSDL::drawVertex(const Point& p, const uint8_t size, uint8_t r, uint8_t g, uint8_t b, uint8_t a){
00332 Point p1 = Point(p.x-size, p.y+size);
00333 Point p2 = Point(p.x+size, p.y+size);
00334 Point p3 = Point(p.x+size, p.y-size);
00335 Point p4 = Point(p.x-size, p.y-size);
00336
00337 drawLine(p1, p2, r, g, b, a);
00338 drawLine(p2, p3, r, g, b, a);
00339 drawLine(p3, p4, r, g, b, a);
00340 drawLine(p4, p1, r, g, b, a);
00341 }
00342
00343 void RenderBackendSDL::drawLightPrimitive(const Point& p, uint8_t intensity, float radius, int32_t subdivisions, float xstretch, float ystretch, uint8_t red, uint8_t green, uint8_t blue) {
00344 }
00345
00346 void RenderBackendSDL::captureScreen(const std::string& filename) {
00347 if(m_screen) {
00348 const uint32_t swidth = getWidth();
00349 const uint32_t sheight = getHeight();
00350
00351 SDL_Surface* surface = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth, sheight, 24,
00352 RMASK, GMASK, BMASK, NULLMASK);
00353
00354 if(!surface) {
00355 return;
00356 }
00357
00358 SDL_BlitSurface(m_screen, NULL, surface, NULL);
00359
00360 Image::saveAsPng(filename, *surface);
00361 SDL_FreeSurface(surface);
00362 }
00363 }
00364
00365 void RenderBackendSDL::captureScreen(const std::string& filename, uint32_t width, uint32_t height) {
00366 if(m_screen) {
00367 const uint32_t swidth = getWidth();
00368 const uint32_t sheight = getHeight();
00369 const bool same_size = (width == swidth && height == sheight);
00370
00371 if (width < 1 || height < 1) {
00372 return;
00373 }
00374
00375 if (same_size) {
00376 captureScreen(filename);
00377 return;
00378 }
00379
00380 SDL_Surface* src = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth, sheight, 32,
00381 RMASK, GMASK, BMASK, AMASK);
00382
00383 if(!src) {
00384 return;
00385 }
00386
00387 SDL_BlitSurface(m_screen, NULL, src, NULL);
00388
00389 SDL_Surface* dst = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32,
00390 RMASK, GMASK, BMASK, AMASK);
00391
00392 uint32_t* src_pointer = static_cast<uint32_t*>(src->pixels);
00393 uint32_t* src_help_pointer = src_pointer;
00394 uint32_t* dst_pointer = static_cast<uint32_t*>(dst->pixels);
00395
00396 int32_t x, y, *sx_ca, *sy_ca;
00397 int32_t sx = static_cast<int32_t>(0xffff * src->w / dst->w);
00398 int32_t sy = static_cast<int32_t>(0xffff * src->h / dst->h);
00399 int32_t sx_c = 0;
00400 int32_t sy_c = 0;
00401
00402
00403 int32_t* sx_a = new int32_t[dst->w + 1];
00404 sx_ca = sx_a;
00405 for (x = 0; x <= dst->w; x++) {
00406 *sx_ca = sx_c;
00407 sx_ca++;
00408 sx_c &= 0xffff;
00409 sx_c += sx;
00410 }
00411
00412 int32_t* sy_a = new int32_t[dst->h + 1];
00413 sy_ca = sy_a;
00414 for (y = 0; y <= dst->h; y++) {
00415 *sy_ca = sy_c;
00416 sy_ca++;
00417 sy_c &= 0xffff;
00418 sy_c += sy;
00419 }
00420 sy_ca = sy_a;
00421
00422
00423
00424 if (SDL_MUSTLOCK(src)) {
00425 SDL_LockSurface(src);
00426 }
00427
00428 if (SDL_MUSTLOCK(dst)) {
00429 SDL_LockSurface(dst);
00430 }
00431
00432 for (y = 0; y < dst->h; y++) {
00433 src_pointer = src_help_pointer;
00434 sx_ca = sx_a;
00435 for (x = 0; x < dst->w; x++) {
00436 *dst_pointer = *src_pointer;
00437 sx_ca++;
00438 src_pointer += (*sx_ca >> 16);
00439 dst_pointer++;
00440 }
00441 sy_ca++;
00442 src_help_pointer = (uint32_t*)((uint8_t*)src_help_pointer + (*sy_ca >> 16) * src->pitch);
00443 }
00444
00445 if (SDL_MUSTLOCK(dst)) {
00446 SDL_UnlockSurface(dst);
00447 }
00448 if (SDL_MUSTLOCK(src)) {
00449 SDL_UnlockSurface(src);
00450 }
00451
00452 Image::saveAsPng(filename, *dst);
00453
00454
00455 SDL_FreeSurface(src);
00456 SDL_FreeSurface(dst);
00457 delete[] sx_a;
00458 delete[] sy_a;
00459 }
00460 }
00461
00462 void RenderBackendSDL::setClipArea(const Rect& cliparea, bool clear) {
00463 SDL_Rect rect;
00464 rect.x = cliparea.x;
00465 rect.y = cliparea.y;
00466 rect.w = cliparea.w;
00467 rect.h = cliparea.h;
00468 SDL_SetClipRect(m_target, &rect);
00469 if (clear) {
00470 uint32_t color = 0;
00471 if (m_isbackgroundcolor) {
00472 color = SDL_MapRGB(m_target->format, m_backgroundcolor.r, m_backgroundcolor.g, m_backgroundcolor.b);
00473 }
00474 SDL_FillRect(m_target, &rect, color);
00475 }
00476 }
00477
00478 void RenderBackendSDL::attachRenderTarget(ImagePtr& img, bool discard) {
00479 m_target = img->getSurface();
00480 if (discard) {
00481 setClipArea(img->getArea(), true);
00482 }
00483 }
00484
00485 void RenderBackendSDL::detachRenderTarget(){
00486 m_target = m_screen;
00487 }
00488 }