1 #include <SDL.h>
2 #include "screen.h"
3 #include "exceptions.h"
4 #include "unicode.h"
5 
6 
Screen()7 Screen::Screen()
8 {
9     screen = NULL;
10     mouseImage = NULL;
11     mouseSave = NULL;
12     mouseVisible = false;
13     regionsList = NULL;
14     maxRegionsList = 0;
15 }
16 
~Screen()17 Screen::~Screen()
18 {
19     SDL_SetCursor(cursor);
20     if (mouseImage) SDL_FreeSurface(mouseImage);
21     if (mouseSave) SDL_FreeSurface(mouseSave);
22     if (regionsList) free(regionsList);
23 }
24 
25 
getVideoMode() const26 const VideoMode Screen::getVideoMode() const
27 {
28     return VideoMode(screen->w, screen->h, screen->format->BitsPerPixel, fullScreen);
29 }
30 
31 
setMode(const VideoMode & mode)32 void Screen::setMode(const VideoMode& mode)
33 {
34     fullScreen = mode.isFullScreen();
35 
36     int flags = SDL_SWSURFACE /*| SDL_OPENGL*/;
37     if (fullScreen)
38         flags = flags | SDL_FULLSCREEN;
39     screen = SDL_SetVideoMode(mode.getWidth(), mode.getHeight(), mode.getBpp(), flags);
40     if (! screen)
41         throw Exception(L"Couldn't set video mode: " +
42                 fromMbcs((SDL_GetError())));
43 }
44 
45 
getFullScreenModes() const46 std::vector<VideoMode> Screen::getFullScreenModes() const
47 {
48     std::vector<VideoMode> modes;
49     return modes;
50 }
51 
52 
getWidth() const53 int Screen::getWidth() const
54 {
55     if (screen)
56         return screen->w;
57     else
58         throw Exception(L"No video mode selected");
59 }
60 
61 
getHeight() const62 int Screen::getHeight() const
63 {
64     if (screen)
65         return screen->h;
66     else
67         throw Exception(L"No video mode selected");
68 }
69 
centerMouse()70 void Screen::centerMouse()
71 {
72     if (screen)
73         SDL_WarpMouse(screen->w / 2, screen->h / 2);
74     else
75         throw Exception(L"No video mode selected");
76 }
77 
setMouseImage(SDL_Surface * image)78 void Screen::setMouseImage(SDL_Surface *image)
79 {
80     if (mouseImage) {
81         SDL_FreeSurface(mouseImage);
82         mouseImage = NULL;
83     }
84     if (mouseSave) {
85         SDL_FreeSurface(mouseSave);
86         mouseSave = NULL;
87     }
88 
89     if (! image) return;
90 
91     mouseImage = SDL_DisplayFormat(image);
92     if (! mouseImage)
93         throw Exception(L"Error creating surface");
94     //mouseSave = SDL_DisplayFormat(image);
95     mouseSave = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCCOLORKEY,
96             image->w, image->h, screen->format->BitsPerPixel,
97             screen->format->Rmask, screen->format->Gmask,
98             screen->format->Bmask, screen->format->Amask);
99     if (! mouseSave) {
100         SDL_FreeSurface(mouseImage);
101         throw Exception(L"Error creating buffer surface");
102     }
103     SDL_SetColorKey(mouseImage, SDL_SRCCOLORKEY,
104             SDL_MapRGB(mouseImage->format, 0, 0, 0));
105 }
106 
107 
hideMouse()108 void Screen::hideMouse()
109 {
110     if (! mouseVisible)
111         return;
112 
113     if (! niceCursor) {
114         mouseVisible = false;
115         return;
116     }
117 
118     if (mouseSave) {
119         SDL_Rect src = { 0, 0, mouseSave->w, mouseSave->h };
120         SDL_Rect dst = { saveX, saveY, mouseSave->w, mouseSave->h };
121         if (src.w > 0) {
122             SDL_BlitSurface(mouseSave, &src, screen, &dst);
123             addRegionToUpdate(dst.x, dst.y, dst.w, dst.h);
124         }
125     }
126     mouseVisible = false;
127 }
128 
showMouse()129 void Screen::showMouse()
130 {
131     if (mouseVisible)
132         return;
133 
134     if (! niceCursor) {
135         mouseVisible = true;
136         return;
137     }
138 
139     if (mouseImage && mouseSave) {
140         int x, y;
141         SDL_GetMouseState(&x, &y);
142         saveX = x;
143         saveY = y;
144         SDL_Rect src = { 0, 0, mouseSave->w, mouseSave->h };
145         SDL_Rect dst = { x, y, mouseImage->w, mouseImage->h };
146         if (src.w > 0) {
147             SDL_BlitSurface(screen, &dst, mouseSave, &src);
148             SDL_BlitSurface(mouseImage, &src, screen, &dst);
149             addRegionToUpdate(dst.x, dst.y, dst.w, dst.h);
150         }
151     }
152     mouseVisible = true;
153 }
154 
updateMouse()155 void Screen::updateMouse()
156 {
157     hideMouse();
158     showMouse();
159 }
160 
flush()161 void Screen::flush()
162 {
163     if (! regions.size()) return;
164 
165     if (! regionsList) {
166         regionsList = (SDL_Rect*)malloc(sizeof(SDL_Rect) * regions.size());
167         if (! regionsList) {
168             regions.clear();
169             throw Exception(L"Error allocating regions buffer");
170         }
171         maxRegionsList = regions.size();
172     } else {
173         if (maxRegionsList < (int)regions.size()) {
174             SDL_Rect *r = (SDL_Rect*)realloc(regionsList,
175                     sizeof(SDL_Rect) * regions.size());
176             if (! r) {
177                 regions.clear();
178                 free(regionsList);
179                 throw Exception(L"Error incrementing regions buffer");
180             }
181             regionsList = r;
182             maxRegionsList = regions.size();
183         }
184     }
185 
186     int j = 0;
187     for (std::list<SDL_Rect>::iterator i = regions.begin();
188             i != regions.end(); i++, j++)
189         regionsList[j] = *i;
190 
191     SDL_UpdateRects(screen, regions.size(), regionsList);
192     regions.clear();
193 }
194 
195 
addRegionToUpdate(int x,int y,int w,int h)196 void Screen::addRegionToUpdate(int x, int y, int w, int h)
197 {
198     if (((x >= getWidth()) || (y >= getHeight())) || (0 >= w) || (0 >= h))
199         return;
200     if ((x + w < 0) || (y + h < 0))
201         return;
202     if (x + w > getWidth())
203         w = getWidth() - x;
204     if (y + h > getHeight())
205         h = getHeight() - y;
206     if (0 > x) {
207         w = w + x;
208         x = 0;
209     }
210     if (0 > y) {
211         h = h + y;
212         y = 0;
213     }
214     SDL_Rect r = { x, y, w, h };
215     regions.push_back(r);
216 }
217 
218 
setPixel(int x,int y,int r,int g,int b)219 void Screen::setPixel(int x, int y, int r, int g, int b)
220 {
221     SDL_LockSurface(screen);
222     int bpp = screen->format->BytesPerPixel;
223     Uint32 pixel = SDL_MapRGB(screen->format, r, g, b);
224     /* Here p is the address to the pixel we want to set */
225     Uint8 *p = (Uint8*)screen->pixels + y * screen->pitch + x * bpp;
226 
227     switch(bpp) {
228         case 1:
229             *p = pixel;
230             break;
231 
232         case 2:
233             *(Uint16 *)p = pixel;
234             break;
235 
236         case 3:
237             if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
238                 p[0] = (pixel >> 16) & 0xff;
239                 p[1] = (pixel >> 8) & 0xff;
240                 p[2] = pixel & 0xff;
241             } else {
242                 p[0] = pixel & 0xff;
243                 p[1] = (pixel >> 8) & 0xff;
244                 p[2] = (pixel >> 16) & 0xff;
245             }
246             break;
247 
248         case 4:
249             *(Uint32 *)p = pixel;
250             break;
251     }
252     SDL_UnlockSurface(screen);
253 }
254 
255 
draw(int x,int y,SDL_Surface * tile)256 void Screen::draw(int x, int y, SDL_Surface *tile)
257 {
258     SDL_Rect src = { 0, 0, tile->w, tile->h };
259     SDL_Rect dst = { x, y, tile->w, tile->h };
260     SDL_BlitSurface(tile, &src, screen, &dst);
261 }
262 
setCursor(bool nice)263 void Screen::setCursor(bool nice)
264 {
265     if (nice == niceCursor)
266         return;
267 
268     bool oldVisible = mouseVisible;
269     if (mouseVisible)
270         hideMouse();
271     niceCursor = nice;
272 
273     if (niceCursor)
274         SDL_SetCursor(emptyCursor);
275     else
276         SDL_SetCursor(cursor);
277 
278     if (oldVisible)
279         showMouse();
280 }
281 
initCursors()282 void Screen::initCursors()
283 {
284     cursor = SDL_GetCursor();
285     Uint8 t = 0;
286     emptyCursor = SDL_CreateCursor(&t, &t, 8, 1, 0, 0);
287 }
288 
doneCursors()289 void Screen::doneCursors()
290 {
291     if (niceCursor)
292         SDL_SetCursor(cursor);
293     SDL_FreeCursor(emptyCursor);
294 }
295 
createSubimage(int x,int y,int width,int height)296 SDL_Surface* Screen::createSubimage(int x, int y, int width, int height)
297 {
298     SDL_Surface *s = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCCOLORKEY,
299             width, height, screen->format->BitsPerPixel,
300             screen->format->Rmask, screen->format->Gmask,
301             screen->format->Bmask, screen->format->Amask);
302     if (! s)
303         throw Exception(L"Error creating buffer surface");
304     SDL_Rect src = { x, y, width, height };
305     SDL_Rect dst = { 0, 0, width, height };
306     SDL_BlitSurface(screen, &src, s, &dst);
307     return s;
308 }
309 
310