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