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