1
2 /**
3 *
4 * @file video.cpp
5 *
6 * Part of the OpenJazz project
7 *
8 * @par History:
9 * - 23rd August 2005: Created main.c
10 * - 22nd July 2008: Created util.c from parts of main.c
11 * - 3rd February 2009: Renamed util.c to util.cpp
12 * - 13th July 2009: Created graphics.cpp from parts of util.cpp
13 * - 26th July 2009: Renamed graphics.cpp to video.cpp
14 *
15 * @par Licence:
16 * Copyright (c) 2005-2017 Alister Thomson
17 *
18 * OpenJazz is distributed under the terms of
19 * the GNU General Public License, version 2.0
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 * @par Description:
26 * Contains graphics utility functions.
27 *
28 */
29
30
31 #include "paletteeffects.h"
32 #include "video.h"
33
34 #ifdef SCALE
35 #include "io/gfx/scale2x/scalebit.h"
36 #endif
37
38 #include "util.h"
39
40 #include <string.h>
41
42
43 /**
44 * Creates a surface.
45 *
46 * @param pixels Pixel data to copy into the surface. Can be NULL.
47 * @param width Width of the pixel data and of the surface to be created
48 * @param height Height of the pixel data and of the surface to be created
49 *
50 * @return The completed surface
51 */
createSurface(unsigned char * pixels,int width,int height)52 SDL_Surface* createSurface (unsigned char * pixels, int width, int height) {
53
54 SDL_Surface *ret;
55 int y;
56
57 // Create the surface
58 ret = SDL_CreateRGBSurface(SDL_HWSURFACE, width, height, 8, 0, 0, 0, 0);
59
60 // Set the surface's palette
61 video.restoreSurfacePalette(ret);
62
63 if (pixels) {
64
65 // Upload pixel data to the surface
66 if (SDL_MUSTLOCK(ret)) SDL_LockSurface(ret);
67
68 for (y = 0; y < height; y++)
69 memcpy(((unsigned char *)(ret->pixels)) + (ret->pitch * y),
70 pixels + (width * y), width);
71
72 if (SDL_MUSTLOCK(ret)) SDL_UnlockSurface(ret);
73
74 }
75
76 return ret;
77
78 }
79
80
81 /**
82 * Create the video output object.
83 */
Video()84 Video::Video () {
85
86 int count;
87
88 screen = NULL;
89
90 #ifdef SCALE
91 scaleFactor = 1;
92 #endif
93
94 // Generate the logical palette
95 for (count = 0; count < 256; count++)
96 logicalPalette[count].r = logicalPalette[count].g =
97 logicalPalette[count].b = count;
98
99 currentPalette = logicalPalette;
100
101 return;
102
103 }
104
105
106 /**
107 * Find the maximum horizontal and vertical resolutions.
108 */
findMaxResolution()109 void Video::findMaxResolution () {
110
111 #ifdef NO_RESIZE
112 maxW = DEFAULT_SCREEN_WIDTH;
113 maxH = DEFAULT_SCREEN_HEIGHT;
114 #else
115 SDL_Rect **resolutions;
116 int count;
117
118 resolutions = SDL_ListModes(NULL, fullscreen? FULLSCREEN_FLAGS: WINDOWED_FLAGS);
119
120 if (resolutions == (SDL_Rect **)(-1)) {
121
122 maxW = MAX_SCREEN_WIDTH;
123 maxH = MAX_SCREEN_HEIGHT;
124
125 } else {
126
127 maxW = SW;
128 maxH = SH;
129
130 for (count = 0; resolutions[count] != NULL; count++) {
131
132 if (resolutions[count]->w > maxW) maxW = resolutions[count]->w;
133 if (resolutions[count]->h > maxH) maxH = resolutions[count]->h;
134
135 }
136
137 if (maxW > MAX_SCREEN_WIDTH) maxW = MAX_SCREEN_WIDTH;
138 if (maxH > MAX_SCREEN_HEIGHT) maxH = MAX_SCREEN_HEIGHT;
139 }
140 #endif
141
142 return;
143 }
144
145
146 /**
147 * Initialise video output.
148 *
149 * @param width Width of the window or screen
150 * @param height Height of the window or screen
151 * @param startFullscreen Whether or not to start in full-screen mode
152 *
153 * @return Success
154 */
init(int width,int height,bool startFullscreen)155 bool Video::init (int width, int height, bool startFullscreen) {
156
157 fullscreen = startFullscreen;
158
159 if (fullscreen) SDL_ShowCursor(SDL_DISABLE);
160
161 if (!reset(width, height)) {
162
163 logError("Could not set video mode", SDL_GetError());
164
165 return false;
166
167 }
168
169 SDL_WM_SetCaption("OpenJazz", NULL);
170
171 findMaxResolution();
172
173 return true;
174
175 }
176
177
178 /**
179 * Sets the size of the video window or the resolution of the screen.
180 *
181 * @param width New width of the window or screen
182 * @param height New height of the window or screen
183 *
184 * @return Success
185 */
reset(int width,int height)186 bool Video::reset (int width, int height) {
187
188 screenW = width;
189 screenH = height;
190
191 #ifdef SCALE
192 if (canvas != screen) SDL_FreeSurface(canvas);
193 #endif
194
195 #ifdef NO_RESIZE
196 screen = SDL_SetVideoMode(DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT, 8, FULLSCREEN_FLAGS);
197 #else
198 screen = SDL_SetVideoMode(screenW, screenH, 8, fullscreen? FULLSCREEN_FLAGS: WINDOWED_FLAGS);
199 #endif
200
201 if (!screen) return false;
202
203
204 #ifdef SCALE
205 // Check that the scale will fit in the current resolution
206 while ( ((screenW/SW < scaleFactor) || (screenH/SH < scaleFactor)) && (scaleFactor > 1) ) {
207
208 scaleFactor--;
209
210 }
211
212 if (scaleFactor > 1) {
213
214 canvasW = screenW / scaleFactor;
215 canvasH = screenH / scaleFactor;
216 canvas = createSurface(NULL, canvasW, canvasH);
217
218 } else
219 #endif
220 {
221
222 canvasW = screenW;
223 canvasH = screenH;
224 canvas = screen;
225
226 }
227
228 #if !defined(WIZ) && !defined(GP2X)
229 expose();
230 #endif
231
232
233 /* A real 8-bit display is quite likely if the user has the right video
234 card, the right video drivers, the right version of DirectX/whatever, and
235 the right version of SDL. In other words, it's not likely enough. If a real
236 palette is assumed when
237 a) there really is a real palette, there will be an extremely small speed
238 gain.
239 b) the palette is emulated, there will be a HUGE speed loss.
240 Therefore, assume the palette is emulated. */
241 /// @todo Find a better way to determine if palette is emulated
242 fakePalette = true;
243
244 return true;
245
246 }
247
248
249 /**
250 * Sets the display palette.
251 *
252 * @param palette The new palette
253 */
setPalette(SDL_Color * palette)254 void Video::setPalette (SDL_Color *palette) {
255
256 // Make palette changes invisible until the next draw. Hopefully.
257 clearScreen(SDL_MapRGB(screen->format, 0, 0, 0));
258 flip(0, NULL);
259
260 SDL_SetPalette(screen, SDL_PHYSPAL, palette, 0, 256);
261 currentPalette = palette;
262
263 return;
264
265 }
266
267
268 /**
269 * Returns the current display palette.
270 *
271 * @return The current display palette
272 */
getPalette()273 SDL_Color* Video::getPalette () {
274
275 return currentPalette;
276
277 }
278
279
280 /**
281 * Sets some colours of the display palette.
282 *
283 * @param palette The palette containing the new colours
284 * @param first The index of the first colour in both the display palette and the specified palette
285 * @param amount The number of colours
286 */
changePalette(SDL_Color * palette,unsigned char first,unsigned int amount)287 void Video::changePalette (SDL_Color *palette, unsigned char first, unsigned int amount) {
288
289 SDL_SetPalette(screen, SDL_PHYSPAL, palette, first, amount);
290
291 return;
292
293 }
294
295
296 /**
297 * Restores a surface's palette.
298 *
299 * @param surface Surface with a modified palette
300 */
restoreSurfacePalette(SDL_Surface * surface)301 void Video::restoreSurfacePalette (SDL_Surface* surface) {
302
303 SDL_SetPalette(surface, SDL_LOGPAL, logicalPalette, 0, 256);
304
305 return;
306
307 }
308
309
310 /**
311 * Returns the maximum possible screen width.
312 *
313 * @return The maximum width
314 */
getMaxWidth()315 int Video::getMaxWidth () {
316
317 return maxW;
318
319 }
320
321
322 /**
323 * Returns the maximum possible screen height.
324 *
325 * @return The maximum height
326 */
getMaxHeight()327 int Video::getMaxHeight () {
328
329 return maxH;
330
331 }
332
333
334 /**
335 * Returns the current width of the window or screen.
336 *
337 * @return The width
338 */
getWidth()339 int Video::getWidth () {
340
341 return screenW;
342
343 }
344
345
346 /**
347 * Returns the current height of the window or screen.
348 *
349 * @return The height
350 */
getHeight()351 int Video::getHeight () {
352
353 return screenH;
354
355 }
356
357
358 #ifdef SCALE
359 /**
360 * Returns the current scaling factor.
361 *
362 * @return The scaling factor
363 */
getScaleFactor()364 int Video::getScaleFactor () {
365
366 return scaleFactor;
367
368 }
369
370
371 /**
372 * Sets the scaling factor.
373 *
374 * @param newScaleFactor The new scaling factor
375 */
setScaleFactor(int newScaleFactor)376 int Video::setScaleFactor (int newScaleFactor) {
377
378 if ((SW * newScaleFactor <= screenW) && (SH * newScaleFactor <= screenH)) {
379
380 scaleFactor = newScaleFactor;
381
382 if (screen) reset(screenW, screenH);
383
384 }
385
386 return scaleFactor;
387
388 }
389 #endif
390
391 #ifndef FULLSCREEN_ONLY
392 /**
393 * Determines whether or not full-screen mode is being used.
394 *
395 * @return Whether or not full-screen mode is being used
396 */
isFullscreen()397 bool Video::isFullscreen () {
398
399 return fullscreen;
400
401 }
402 #endif
403
404
405 /**
406 * Refresh display palette.
407 */
expose()408 void Video::expose () {
409
410 SDL_SetPalette(screen, SDL_LOGPAL, logicalPalette, 0, 256);
411 SDL_SetPalette(screen, SDL_PHYSPAL, currentPalette, 0, 256);
412
413 return;
414
415 }
416
417
418 /**
419 * Update video based on a system event.
420 *
421 * @param event The system event. Events not affecting video will be ignored
422 */
update(SDL_Event * event)423 void Video::update (SDL_Event *event) {
424
425 #if !defined(FULLSCREEN_ONLY) || !defined(NO_RESIZE)
426 switch (event->type) {
427
428 #ifndef FULLSCREEN_ONLY
429 case SDL_KEYDOWN:
430
431 // If Alt + Enter has been pressed, switch between windowed and full-screen mode.
432 if ((event->key.keysym.sym == SDLK_RETURN) &&
433 (event->key.keysym.mod & KMOD_ALT)) {
434
435 fullscreen = !fullscreen;
436
437 if (fullscreen) SDL_ShowCursor(SDL_DISABLE);
438
439 reset(screenW, screenH);
440
441 if (!fullscreen) SDL_ShowCursor(SDL_ENABLE);
442
443 findMaxResolution();
444
445 }
446
447 break;
448 #endif
449
450 #ifndef NO_RESIZE
451 case SDL_VIDEORESIZE:
452
453 reset(event->resize.w, event->resize.h);
454
455 break;
456 #endif
457
458 case SDL_VIDEOEXPOSE:
459
460 expose();
461
462 break;
463
464 }
465 #endif
466
467 return;
468
469 }
470
471
472 /**
473 * Draw graphics to screen.
474 *
475 * @param mspf Ticks per frame
476 * @param paletteEffects Palette effects to use
477 */
flip(int mspf,PaletteEffect * paletteEffects)478 void Video::flip (int mspf, PaletteEffect* paletteEffects) {
479
480 SDL_Color shownPalette[256];
481
482 #ifdef SCALE
483 if (canvas != screen) {
484
485 // Copy everything that has been drawn so far
486 scale(scaleFactor,
487 screen->pixels, screen->pitch,
488 canvas->pixels, canvas->pitch,
489 screen->format->BytesPerPixel, canvas->w, canvas->h);
490
491 }
492 #endif
493
494 // Apply palette effects
495 if (paletteEffects) {
496
497 /* If the palette is being emulated, compile all palette changes and
498 apply them all at once.
499 If the palette is being used directly, apply all palette effects
500 directly. */
501
502 if (fakePalette) {
503
504 memcpy(shownPalette, currentPalette, sizeof(SDL_Color) * 256);
505
506 paletteEffects->apply(shownPalette, false, mspf);
507
508 SDL_SetPalette(screen, SDL_PHYSPAL, shownPalette, 0, 256);
509
510 } else {
511
512 paletteEffects->apply(shownPalette, true, mspf);
513
514 }
515
516 }
517
518 // Show what has been drawn
519 SDL_Flip(screen);
520
521 return;
522
523 }
524
525
526 /**
527 * Fill the screen with a colour.
528 *
529 * @param index Index of the colour to use
530 */
clearScreen(int index)531 void Video::clearScreen (int index) {
532
533 #if defined(CAANOO) || defined(WIZ) || defined(GP2X) || defined(GAMESHELL)
534 // always 240 lines cleared to black
535 memset(video.screen->pixels, index, 320*240);
536 #else
537 SDL_FillRect(canvas, NULL, index);
538 #endif
539
540 return;
541
542 }
543
544
545 /**
546 * Fill a specified rectangle of the screen with a colour.
547 *
548 * @param x X-coordinate of the left side of the rectangle
549 * @param y Y-coordinate of the top of the rectangle
550 * @param width Width of the rectangle
551 * @param height Height of the rectangle
552 * @param index Index of the colour to use
553 */
drawRect(int x,int y,int width,int height,int index)554 void drawRect (int x, int y, int width, int height, int index) {
555
556 SDL_Rect dst;
557
558 dst.x = x;
559 dst.y = y;
560 dst.w = width;
561 dst.h = height;
562
563 SDL_FillRect(canvas, &dst, index);
564
565 return;
566
567 }
568
569