FIFE
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
renderbackendsdl.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2013 by the FIFE team *
3  * http://www.fifengine.net *
4  * This file is part of FIFE. *
5  * *
6  * FIFE is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Lesser General Public *
8  * License as published by the Free Software Foundation; either *
9  * version 2.1 of the License, or (at your option) any later version. *
10  * *
11  * This library is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14  * Lesser General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU Lesser General Public *
17  * License along with this library; if not, write to the *
18  * Free Software Foundation, Inc., *
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 
24 // 3rd party library includes
25 #include <SDL.h>
26 
27 // FIFE includes
28 // These includes are split up in two parts, separated by one empty line
29 // First block: files included from the FIFE root src directory
30 // Second block: files included from the same folder
31 #include "util/base/exception.h"
32 #include "util/math/fife_math.h"
33 #include "util/log/logger.h"
34 #include "video/devicecaps.h"
35 
36 #include "renderbackendsdl.h"
37 #include "sdlimage.h"
38 #include "SDL_image.h"
39 #include "SDL_getenv.h"
40 
41 namespace FIFE {
45  static Logger _log(LM_VIDEO);
46 
47  RenderBackendSDL::RenderBackendSDL(const SDL_Color& colorkey) :
48  RenderBackend(colorkey){
49  }
50 
52  deinit();
53  }
54 
55  const std::string& RenderBackendSDL::getName() const {
56  static std::string backend_name = "SDL";
57  return backend_name;
58  }
59 
60  void RenderBackendSDL::init(const std::string& driver) {
61  char* buf;
62  if (driver != "") {
63  std::string envVar = std::string("SDL_VIDEODRIVER=") + driver;
64  buf = const_cast<char*>(envVar.c_str());
65  putenv(buf);
66  }
67 
68  if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
69  throw SDLException(SDL_GetError());
70 
71  SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); // temporary hack
72  }
73 
75  SDL_Rect rect;
76  rect.x = 0;
77  rect.y = 0;
78  rect.w = getWidth();
79  rect.h = getHeight();
80  SDL_SetClipRect(m_screen, &rect);
81  SDL_FillRect(m_screen, 0, 0x00);
82  }
83 
84  void RenderBackendSDL::createMainScreen(const ScreenMode& mode, const std::string& title, const std::string& icon){
85  if(icon != "") {
86  SDL_Surface *img = IMG_Load(icon.c_str());
87  if(img != NULL) {
88  SDL_WM_SetIcon(img, 0);
89  SDL_FreeSurface(img);
90  }
91  }
92 
93  SDL_WM_SetCaption(title.c_str(), 0);
94  setScreenMode(mode);
95  }
96 
98  uint16_t width = mode.getWidth();
99  uint16_t height = mode.getHeight();
100  uint16_t bitsPerPixel = mode.getBPP();
101  uint32_t flags = mode.getSDLFlags();
102 
103  if (bitsPerPixel != 0) {
104  uint16_t bpp = SDL_VideoModeOK(width, height, bitsPerPixel, flags);
105  if (!bpp){
106  throw SDLException("Selected video mode not supported!");
107  }
108  }
109 
110  if(m_screen) {
111  SDL_FreeSurface(m_screen);
112  }
113  m_screen = SDL_SetVideoMode(width, height, bitsPerPixel, flags);
114  if( !m_screen ) {
115  throw SDLException("Unable to set video mode selected!");
116  }
117  m_target = m_screen;
118 
119  FL_LOG(_log, LMsg("RenderBackendSDL")
120  << "Videomode " << width << "x" << height
121  << " at " << int32_t(m_screen->format->BitsPerPixel) << " bpp");
122 
123  m_rgba_format = *(m_screen->format);
124  m_rgba_format.Rmask = RMASK;
125  m_rgba_format.Gmask = GMASK;
126  m_rgba_format.Bmask = BMASK;
127  m_rgba_format.Amask = AMASK;
128 
129  //update the screen mode with the actual flags used
130  m_screenMode = ScreenMode(width,
131  height,
132  bitsPerPixel,
133  m_screen->flags);
134  }
135 
138  }
139 
141  SDL_Flip(m_screen);
143  }
144 
146  return new SDLImage(loader);
147  }
148 
149  Image* RenderBackendSDL::createImage(const std::string& name, IResourceLoader* loader) {
150  return new SDLImage(name, loader);
151  }
152 
153  Image* RenderBackendSDL::createImage(SDL_Surface* surface) {
154  return new SDLImage(surface);
155  }
156 
157  Image* RenderBackendSDL::createImage(const std::string& name, SDL_Surface* surface) {
158  return new SDLImage(name, surface);
159  }
160 
162  return new SDLImage(data, width, height);
163  }
164 
165  Image* RenderBackendSDL::createImage(const std::string& name, const uint8_t* data, uint32_t width, uint32_t height) {
166  return new SDLImage(name, data, width, height);
167  }
168 
170  SDLException("Lighting not available under SDL");
171  }
172 
174  return 0;
175  }
176 
177  void RenderBackendSDL::setLighting(float red, float green, float blue) {
178  }
179 
181  }
182 
184  }
185 
186  void RenderBackendSDL::changeBlending(int32_t scr, int32_t dst){
187  }
188 
190  }
191 
192  void RenderBackendSDL::addImageToArray(uint32_t id, const Rect& rec, float const* st, uint8_t alpha, uint8_t const* rgba) {
193  }
194 
195  void RenderBackendSDL::changeRenderInfos(uint16_t elements, int32_t src, int32_t dst, bool light, bool stentest, uint8_t stenref, GLConstants stenop, GLConstants stenfunc) {
196  }
197 
198  bool RenderBackendSDL::putPixel(int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
199  return Image::putPixel(m_target, x, y, r, g, b, a);
200  }
201 
202  void RenderBackendSDL::drawLine(const Point& p1, const Point& p2, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
203  // Draw a line with Bresenham, imitated from guichan
204  int32_t x1 = p1.x;
205  int32_t x2 = p2.x;
206  int32_t y1 = p1.y;
207  int32_t y2 = p2.y;
208  int32_t dx = ABS(x2 - x1);
209  int32_t dy = ABS(y2 - y1);
210 
211  if (dx > dy) {
212  if (x1 > x2) {
213  // swap x1, x2
214  x1 ^= x2;
215  x2 ^= x1;
216  x1 ^= x2;
217 
218  // swap y1, y2
219  y1 ^= y2;
220  y2 ^= y1;
221  y1 ^= y2;
222  }
223 
224  if (y1 < y2) {
225  int32_t y = y1;
226  int32_t p = 0;
227 
228  for (int32_t x = x1; x <= x2; x++) {
229  putPixel(x, y, r, g, b, a);
230  p += dy;
231  if (p * 2 >= dx) {
232  y++;
233  p -= dx;
234  }
235  }
236  }
237  else {
238  int32_t y = y1;
239  int32_t p = 0;
240 
241  for (int32_t x = x1; x <= x2; x++) {
242  putPixel(x, y, r, g, b, a);
243 
244  p += dy;
245  if (p * 2 >= dx) {
246  y--;
247  p -= dx;
248  }
249  }
250  }
251  }
252  else {
253  if (y1 > y2) {
254  // swap y1, y2
255  y1 ^= y2;
256  y2 ^= y1;
257  y1 ^= y2;
258 
259  // swap x1, x2
260  x1 ^= x2;
261  x2 ^= x1;
262  x1 ^= x2;
263  }
264 
265  if (x1 < x2) {
266  int32_t x = x1;
267  int32_t p = 0;
268 
269  for (int32_t y = y1; y <= y2; y++) {
270  putPixel(x, y, r, g, b, a);
271  p += dx;
272  if (p * 2 >= dy) {
273  x++;
274  p -= dy;
275  }
276  }
277  }
278  else {
279  int32_t x = x1;
280  int32_t p = 0;
281 
282  for (int32_t y = y1; y <= y2; y++) {
283  putPixel(x, y, r, g, b, a);
284  p += dx;
285  if (p * 2 >= dy) {
286  x--;
287  p -= dy;
288  }
289  }
290  }
291  }
292  }
293 
294  void RenderBackendSDL::drawTriangle(const Point& p1, const Point& p2, const Point& p3, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
295  drawLine(p1, p2, r, g, b, a);
296  drawLine(p2, p3, r, g, b, a);
297  drawLine(p3, p1, r, g, b, a);
298  }
299 
301  Point p1, p2, p3, p4;
302 
303  p1.x = p.x;
304  p1.y = p.y;
305  p2.x = p.x+w;
306  p2.y = p.y;
307  p3.x = p.x+w;
308  p3.y = p.y+h;
309  p4.x = p.x;
310  p4.y = p.y+h;
311 
312  drawLine(p1, p2, r, g, b, a);
313  drawLine(p2, p3, r, g, b, a);
314  drawLine(p3, p4, r, g, b, a);
315  drawLine(p4, p1, r, g, b, a);
316  }
317 
319  SDL_Rect rect;
320  rect.x = p.x;
321  rect.y = p.y;
322  rect.w = w;
323  rect.h = h;
324 
325  Uint32 color = SDL_MapRGBA(m_target->format, r, g, b, a);
326  SDL_FillRect(m_target, &rect, color);
327  }
328 
329  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) {
330  fillRectangle(p1, static_cast<uint16_t>(p3.x-p1.x), static_cast<uint16_t>(p3.y-p1.y), r, g, b, a);
331  }
332 
333  void RenderBackendSDL::drawVertex(const Point& p, const uint8_t size, uint8_t r, uint8_t g, uint8_t b, uint8_t a){
334  Point p1 = Point(p.x-size, p.y+size);
335  Point p2 = Point(p.x+size, p.y+size);
336  Point p3 = Point(p.x+size, p.y-size);
337  Point p4 = Point(p.x-size, p.y-size);
338 
339  drawLine(p1, p2, r, g, b, a);
340  drawLine(p2, p3, r, g, b, a);
341  drawLine(p3, p4, r, g, b, a);
342  drawLine(p4, p1, r, g, b, a);
343  }
344 
345  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) {
346  }
347 
348  void RenderBackendSDL::captureScreen(const std::string& filename) {
349  if(m_screen) {
350  const uint32_t swidth = getWidth();
351  const uint32_t sheight = getHeight();
352 
353  SDL_Surface* surface = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth, sheight, 24,
355 
356  if(!surface) {
357  return;
358  }
359 
360  SDL_BlitSurface(m_screen, NULL, surface, NULL);
361 
362  Image::saveAsPng(filename, *surface);
363  SDL_FreeSurface(surface);
364  }
365  }
366 
367  void RenderBackendSDL::captureScreen(const std::string& filename, uint32_t width, uint32_t height) {
368  if(m_screen) {
369  const uint32_t swidth = getWidth();
370  const uint32_t sheight = getHeight();
371  const bool same_size = (width == swidth && height == sheight);
372 
373  if (width < 1 || height < 1) {
374  return;
375  }
376 
377  if (same_size) {
378  captureScreen(filename);
379  return;
380  }
381  // create source surface
382  SDL_Surface* src = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth, sheight, 32,
383  RMASK, GMASK, BMASK, AMASK);
384 
385  if(!src) {
386  return;
387  }
388  // copy screen suface to source surface
389  SDL_BlitSurface(m_screen, NULL, src, NULL);
390  // create destination surface
391  SDL_Surface* dst = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32,
392  RMASK, GMASK, BMASK, AMASK);
393 
394  uint32_t* src_pointer = static_cast<uint32_t*>(src->pixels);
395  uint32_t* src_help_pointer = src_pointer;
396  uint32_t* dst_pointer = static_cast<uint32_t*>(dst->pixels);
397 
398  int32_t x, y, *sx_ca, *sy_ca;
399  int32_t sx = static_cast<int32_t>(0xffff * src->w / dst->w);
400  int32_t sy = static_cast<int32_t>(0xffff * src->h / dst->h);
401  int32_t sx_c = 0;
402  int32_t sy_c = 0;
403 
404  // Allocates memory and calculates row wide&height
405  int32_t* sx_a = new int32_t[dst->w + 1];
406  sx_ca = sx_a;
407  for (x = 0; x <= dst->w; x++) {
408  *sx_ca = sx_c;
409  sx_ca++;
410  sx_c &= 0xffff;
411  sx_c += sx;
412  }
413 
414  int32_t* sy_a = new int32_t[dst->h + 1];
415  sy_ca = sy_a;
416  for (y = 0; y <= dst->h; y++) {
417  *sy_ca = sy_c;
418  sy_ca++;
419  sy_c &= 0xffff;
420  sy_c += sy;
421  }
422  sy_ca = sy_a;
423 
424  // Transfers the image data
425 
426  if (SDL_MUSTLOCK(src)) {
427  SDL_LockSurface(src);
428  }
429 
430  if (SDL_MUSTLOCK(dst)) {
431  SDL_LockSurface(dst);
432  }
433 
434  for (y = 0; y < dst->h; y++) {
435  src_pointer = src_help_pointer;
436  sx_ca = sx_a;
437  for (x = 0; x < dst->w; x++) {
438  *dst_pointer = *src_pointer;
439  sx_ca++;
440  src_pointer += (*sx_ca >> 16);
441  dst_pointer++;
442  }
443  sy_ca++;
444  src_help_pointer = (uint32_t*)((uint8_t*)src_help_pointer + (*sy_ca >> 16) * src->pitch);
445  }
446 
447  if (SDL_MUSTLOCK(dst)) {
448  SDL_UnlockSurface(dst);
449  }
450  if (SDL_MUSTLOCK(src)) {
451  SDL_UnlockSurface(src);
452  }
453 
454  Image::saveAsPng(filename, *dst);
455 
456  // Free memory
457  SDL_FreeSurface(src);
458  SDL_FreeSurface(dst);
459  delete[] sx_a;
460  delete[] sy_a;
461  }
462  }
463 
464  void RenderBackendSDL::setClipArea(const Rect& cliparea, bool clear) {
465  SDL_Rect rect;
466  rect.x = cliparea.x;
467  rect.y = cliparea.y;
468  rect.w = cliparea.w;
469  rect.h = cliparea.h;
470  SDL_SetClipRect(m_target, &rect);
471  if (clear) {
472  uint32_t color = 0;
473  if (m_isbackgroundcolor) {
474  color = SDL_MapRGB(m_target->format, m_backgroundcolor.r, m_backgroundcolor.g, m_backgroundcolor.b);
475  }
476  SDL_FillRect(m_target, &rect, color);
477  }
478  }
479 
481  m_target = img->getSurface();
482  setClipArea(img->getArea(), discard);
483  }
484 
486  m_target = m_screen;
487  }
488 }
Abstract interface for all the renderbackends.
Definition: renderbackend.h:92
SDL_Surface * m_target
const uint32_t NULLMASK
Definition: fife_stdint.h:63
static bool putPixel(SDL_Surface *surface, int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Definition: image.cpp:346
virtual void createMainScreen(const ScreenMode &mode, const std::string &title, const std::string &icon)
Creates the mainscreen (the display window).
virtual void changeRenderInfos(uint16_t elements, int32_t src, int32_t dst, bool light, bool stentest, uint8_t stenref, GLConstants stenop, GLConstants stenfunc)
Dirty helper function to change the render infos.
Base Class for Images.
Definition: image.h:47
#define ABS(x)
Definition: fife_math.h:40
virtual void renderVertexArrays()
Render the Vertex Arrays, only for primitives (points, lines,...)
T h
Height of the rectangle.
Definition: rect.h:93
Helper class to create log strings out from separate parts Usage: LMsg(&quot;some text&quot;) &lt;&lt; variable &lt;&lt; &quot;...
Definition: logger.h:82
SDL_PixelFormat m_rgba_format
virtual void drawTriangle(const Point &p1, const Point &p2, const Point &p3, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Draws triangle between given points with given RGBA.
virtual void resetStencilBuffer(uint8_t buffer)
Reset stencil buffer with given value.
T x
The X Coordinate.
Definition: rect.h:84
uint32_t getHeight() const
uint32_t getSDLFlags() const
Returns the SDL flags used when testing this mode.
Definition: devicecaps.h:74
The SDL implementation of the Image base class.
Definition: sdlimage.h:40
static void saveAsPng(const std::string &filename, const SDL_Surface &surface)
Saves the SDL_Surface to png format.
Definition: image.cpp:226
virtual void captureScreen(const std::string &filename)
Creates a Screenshot and saves it to a file.
uint16_t getBPP() const
Returns the number of bits per pixel this mode uses.
Definition: devicecaps.h:70
virtual void setClipArea(const Rect &cliparea, bool clear)
Sets given clip area into image.
const uint32_t RMASK
Definition: fife_stdint.h:53
static Logger _log(LM_AUDIO)
virtual void 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=255)
Draws quad between given points with given RGBA.
virtual const std::string & getName() const
The name of the renderbackend.
virtual Image * createImage(IResourceLoader *loader=0)
const uint32_t AMASK
Definition: fife_stdint.h:56
virtual uint32_t getLightingModel() const
Gets the current light model.
const Rect & getArea() const
Definition: image.cpp:171
virtual void startFrame()
Called when a new frame starts.
virtual void setScreenMode(const ScreenMode &mode)
Sets the mainscreen display mode.
virtual bool putPixel(int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Writes pixel to given position.
unsigned char uint8_t
Definition: core.h:38
PointType2D< int32_t > Point
Definition: point.h:194
const uint32_t GMASK
Definition: fife_stdint.h:54
SDL_Surface * getSurface()
Definition: image.h:91
virtual void 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)
Draws a light primitive that based on a triangle fan.
virtual void startFrame()
Called when a new frame starts.
virtual void drawRectangle(const Point &p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Draws an axis parallel rectangle.
RenderBackendSDL(const SDL_Color &colorkey)
virtual void detachRenderTarget()
Detaches current render surface.
uint16_t getHeight() const
Returns the height of the screen mode.
Definition: devicecaps.h:66
virtual void resetLighting()
Reset lighting with default values.
const uint32_t BMASK
Definition: fife_stdint.h:55
unsigned short uint16_t
Definition: core.h:39
T y
The Y Coordinate.
Definition: rect.h:87
uint16_t getWidth() const
Returns the width of the screen mode.
Definition: devicecaps.h:60
SDL_Surface * m_screen
SDL_Color m_backgroundcolor
virtual void fillRectangle(const Point &p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Draws a filled axis parallel rectangle.
#define FL_LOG(logger, msg)
Definition: logger.h:71
uint32_t getWidth() const
virtual void endFrame()
Called when a frame is finished and ready to be displayed.
virtual void clearBackBuffer()
Forces a clear of the backbuffer.
virtual void endFrame()
Called when a frame is finished and ready to be displayed.
virtual void changeBlending(int32_t scr, int32_t dst)
Change the Blendingmodel.
virtual void setLighting(float red, float green, float blue)
Set colors for lighting.
virtual void drawLine(const Point &p1, const Point &p2, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Draws line between given points with given RGBA.
virtual void attachRenderTarget(ImagePtr &img, bool discard)
Attaches given image as a new render surface.
ScreenMode m_screenMode
void deinit()
Performs cleanup actions.
unsigned int uint32_t
Definition: core.h:40
virtual void addImageToArray(uint32_t id, const Rect &rec, float const *st, uint8_t alpha, uint8_t const *rgba)
Add the Image data to the array.
T w
Width of the rectangle.
Definition: rect.h:90
virtual void setLightingModel(uint32_t lighting)
Initializes the light.
virtual void drawVertex(const Point &p, const uint8_t size, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Draws a quad that represents a vertex with given RGBA.
virtual void init(const std::string &driver)
Initializes the backend.