1 /**
2  * @file handler_display.cc
3  * @briefi Handle displaying and updating with SDL
4  * @created 2002-08-17
5  * @date 2014-08-15
6  * @copyright 1991-2014 TLK Games
7  * @author Bruno Ethvignot
8  * @version $Revision: 24 $
9  */
10 /*
11  * copyright (c) 1991-2014 TLK Games all rights reserved
12  * $Id: handler_display.cc 24 2014-09-28 15:30:04Z bruno.ethvignot@gmail.com $
13  *
14  * TecnoballZ is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * TecnoballZ is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
27  * MA  02110-1301, USA.
28  */
29 #include "../include/handler_display.h"
30 #include "../include/handler_keyboard.h"
31 #include "../include/handler_audio.h"
32 #include "../include/handler_resources.h"
33 
34 char
35 handler_display::window_title[25] = "TecnoballZ by TLK Games\0";
36 bool handler_display::optionfull = false;
37 bool handler_display::optionsync = true;
38 
39 /**
40  * Create the object
41  */
handler_display()42 handler_display::handler_display ()
43 {
44   sdl_screen = (SDL_Surface *) NULL;
45   game_surface = (SDL_Surface *) NULL;
46   sdl_ticks_amount = 0;
47   frames_counter_modulo = 0;
48   tilt_offset = 0;
49   /* 1000 / 50 = 20 */
50   game_speed = 20;
51   delay_change_counter = 0;
52   delay_ticks_amount = 0;
53   delay_change_counter = DELAY_CHANGE_MAX;
54 }
55 
56 /**
57  * Release the display handler object
58  */
~handler_display()59 handler_display::~handler_display ()
60 {
61   if (NULL != game_screen)
62     {
63       delete game_screen;
64       game_screen = NULL;
65     }
66   if (NULL != background_screen)
67     {
68       delete background_screen;
69       background_screen = NULL;
70     }
71   if (SDL_WasInit (SDL_INIT_VIDEO) != 0)
72     {
73       if (is_verbose)
74         {
75           std::
76           cout << ">handler_display::~handler_display() SDL_VideoQuit()" <<
77                std::endl;
78         }
79       SDL_VideoQuit ();
80     }
81   SDL_Quit ();
82 }
83 
84 /**
85  * Initialize the SDL display and allocate surfaces
86  */
87 void
initialize()88 handler_display::initialize ()
89 {
90   set_video_mode ();
91   Uint32 height = window_height + offsetplus * 2;
92   /** Create the main game offscreen */
93   game_screen =
94     new offscreen_surface (window_width, height, bitspixels, offsetplus);
95   game_surface = game_screen->get_surface ();
96   game_screen_pitch = game_surface->pitch;
97   game_screen_pixels =
98     (char *) game_surface->pixels + game_screen_pitch * offsetplus;
99   /** Create the background offscreen */
100   background_screen =
101     new offscreen_surface (window_width, height, bitspixels, offsetplus);
102   SDL_Surface *surface = background_screen->get_surface ();
103   background_pixels = (char *) surface->pixels + surface->pitch * offsetplus;
104   previous_sdl_ticks = SDL_GetTicks ();
105   delay_value = 0;
106 }
107 
108 /**
109  * Initializes the video with SDL
110  */
111 void
set_video_mode()112 handler_display::set_video_mode ()
113 {
114   window_width = 320 * resolution;
115   window_height = 240 * resolution;
116   offsetplus = 64 * resolution;
117   if (is_verbose)
118     {
119       std::cout << ">handler_display::set_video_mode() " << window_width
120                 << "x" << window_height << std::endl;
121     }
122 
123   /* initializes SDL */
124   if (SDL_Init
125       (SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE |
126        SDL_INIT_JOYSTICK) < 0)
127     {
128       std::cerr << "!handler_display::set_video_mode() " <<
129                 "SDL_Init() return " << SDL_GetError () << std::endl;
130       throw std::runtime_error ("!handler_display::set_video_mode() "
131                                 "SDL_Init() failed!");
132     }
133 
134   /* test if the video mode is available */
135   Uint32 flag = SDL_ANYFORMAT;
136 #ifdef TECNOBALLZ_HANDHELD_CONSOLE
137   flag = SDL_SWSURFACE | SDL_FULLSCREEN;
138 #endif
139   if (optionfull)
140     {
141       flag = flag | SDL_FULLSCREEN;
142     }
143   Uint32 bpp =
144     SDL_VideoModeOK (window_width, window_height, bitspixels, flag);
145   if (0 == bpp)
146     {
147       std::cerr << "!handler_display::set_video_mode() " <<
148                 "SDL_VideoModeOK() " << "return " << SDL_GetError () << std::endl;
149       throw std::runtime_error ("!handler_display::set_video_mode() "
150                                 "SDL_VideoModeOK() failed!");
151     }
152 
153   /* initialize the video mode */
154   sdl_screen =
155     SDL_SetVideoMode (window_width, window_height, bitspixels, flag);
156   if (NULL == sdl_screen)
157     {
158       std::cerr << "!handler_display::set_video_mode() " <<
159                 "SDL_SetVideoMode() " << "return " << SDL_GetError () << std::endl;
160       throw std::runtime_error ("!handler_display::set_video_mode() "
161                                 "SDL_SetVideoMode() failed!");
162     }
163   SDL_WM_SetCaption (window_title, window_title);
164 
165 #ifdef UNDER_DEVELOPMENT
166   SDL_ShowCursor (SDL_ENABLE);
167 #else
168   SDL_ShowCursor (SDL_DISABLE);
169 #endif
170   SDL_EnableUNICODE (1);
171 }
172 
173 /**
174  * Return the screen's width
175  * @return the width of the screen in pixels
176  */
177 Uint32
get_width()178 handler_display::get_width ()
179 {
180   return sdl_screen->w;
181 }
182 
183 /**
184  * Return the screen's height
185  * @return the height of the screen in lines
186  */
187 Uint32
get_height()188 handler_display::get_height ()
189 {
190   return sdl_screen->h;
191 }
192 
193 /**
194  * Lock surfaces of the game offscreen and the background offscreen
195  */
196 void
lock_surfaces()197 handler_display::lock_surfaces ()
198 {
199   game_screen->lock_surface ();
200   background_screen->lock_surface ();
201 }
202 
203 /**
204  * Unlock surfaces of the game offscreen and background offscreen
205  */
206 void
unlock_surfaces()207 handler_display::unlock_surfaces ()
208 {
209   game_screen->unlock_surface ();
210   background_screen->unlock_surface ();
211 }
212 
213 /**
214  * Return the number of bits per pixel
215  * @return then number of bits per pixel, 8 for 256 colors
216  */
217 Uint32
get_bits_per_pixel()218 handler_display::get_bits_per_pixel ()
219 {
220   return bitspixels;
221 }
222 
223 /**
224  * Display some SDL infos
225  */
226 void
get_info()227 handler_display::get_info ()
228 {
229   const SDL_VideoInfo *vi;
230   char namebuf[32] = { "123456789012345678901234567890\0" };
231   SDL_Rect **modes;
232   Sint32 i;
233   modes = SDL_ListModes (NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
234   if (modes == (SDL_Rect **) 0)
235     {
236       printf ("No modes available!\n");
237       return;
238     }
239   if (modes == (SDL_Rect **) - 1)
240     printf ("All resolutions available.\n");
241   else
242     {
243       printf ("Available Modes\n");
244       for (i = 0; modes[i]; ++i)
245         printf (" %d x %d\n", modes[i]->w, modes[i]->h);
246     }
247   SDL_WM_SetCaption ("TecnoballZ", 0);
248   vi = SDL_GetVideoInfo ();
249   printf
250   ("The number of bits used to represent each pixel in a surface.Usually 8, 16, 24 or 32. BitsPerPixel=%d \n",
251    vi->vfmt->BitsPerPixel);
252   printf
253   ("The number of bytes used to represent each pixel in a surface. Usually one to four BytesPerPixel=%d\n",
254    vi->vfmt->BytesPerPixel);
255   printf ("Rmask=%i Gmask=%i Bmask=%i Amask=%i \n", vi->vfmt->Rmask,
256           vi->vfmt->Gmask, vi->vfmt->Bmask, vi->vfmt->Amask);
257   printf ("Rshift=%i Gshift=%i Bshift=%i Ashift=%i \n", vi->vfmt->Rshift,
258           vi->vfmt->Gshift, vi->vfmt->Bshift, vi->vfmt->Ashift);
259   printf ("Rloss=%i Gloss=%i Bloss=%i Aloss=%i \n", vi->vfmt->Rloss,
260           vi->vfmt->Gloss, vi->vfmt->Bloss, vi->vfmt->Aloss);
261   printf ("Pixel value of transparent pixels. colorkey=%i \n",
262           vi->vfmt->colorkey);
263   printf ("Overall surface alpha value. alpha=%i \n", vi->vfmt->alpha);
264   printf ("Is it possible to create hardware surfaces? hw_available=%i \n",
265           vi->hw_available);
266   printf ("Is there a window manager available wm_available=%i \n",
267           vi->wm_available);
268   printf ("Are hardware to hardware blits accelerated? blit_hw=%i \n",
269           vi->blit_hw);
270   printf
271   ("Are hardware to hardware colorkey blits accelerated? blit_hw_CC=%i \n",
272    vi->blit_hw_CC);
273   printf ("Are hardware to hardware alpha blits accelerated? blit_hw_A=%i\n",
274           vi->blit_hw_A);
275   printf ("Are software to hardware blits accelerated? blit_sw=%i \n",
276           vi->blit_sw);
277   printf
278   ("Are software to hardware colorkey blits accelerated? blit_sw_CC=%i \n",
279    vi->blit_sw_CC);
280   printf ("Are software to hardware alpha blits accelerated? blit_sw_A=%i \n",
281           vi->blit_sw_A);
282   printf ("Are color fills accelerated? blit_fill=%i \n", vi->blit_fill);
283   printf ("Total amount of video memory in Kilobytes. video_mem=%i\n",
284           vi->video_mem);
285   char *c = SDL_VideoDriverName (namebuf, 32);
286   printf ("the name of the video driver=%s\n", c);
287 }
288 
289 
290 /**
291  * Switch to fullscreen or windows mode
292  */
293 void
check_if_toggle_fullscreen()294 handler_display::check_if_toggle_fullscreen ()
295 {
296   if (keyboard->command_is_pressed (handler_keyboard::TOGGLE_FULLSCREEN) &&
297       keyboard->get_input_cursor_pos () < 0)
298     {
299       if (optionfull)
300         {
301           optionfull = false;
302         }
303       else
304         {
305           optionfull = true;
306         }
307       display->set_video_mode ();
308       display->enable_palette (sdl_palette);
309     }
310 }
311 
312 /**
313  * Synchronize the game's speed to the machine it's running on
314  */
315 void
wait_frame()316 handler_display::wait_frame ()
317 {
318 
319   frame_counter++;
320 
321   /* Get the number of milliseconds since the SDL library initialization */
322   Uint32 sdl_ticks = SDL_GetTicks () - previous_sdl_ticks;
323   optionsync = true;
324   if (optionsync)
325     {
326       delay_ticks_amount += sdl_ticks;
327       if (--delay_change_counter <= 0)
328         {
329           delay_value =
330             ((game_speed * DELAY_CHANGE_MAX) -
331              delay_ticks_amount) / DELAY_CHANGE_MAX;
332           delay_change_counter = DELAY_CHANGE_MAX;
333           delay_ticks_amount = 0;
334           if (delay_value <= 0)
335             {
336               delay_value = 1;
337             }
338         }
339       if (delay_value > 0)
340         {
341           SDL_Delay (delay_value);
342         }
343     }
344   previous_sdl_ticks = SDL_GetTicks ();
345 
346   /** Calculate the number of frames per second */
347   sdl_ticks_amount += sdl_ticks;
348   if (++frames_counter_modulo >= 100)
349     {
350       if (0 != sdl_ticks_amount)
351         {
352           frames_per_second = 1000 * frames_counter_modulo / sdl_ticks_amount;
353         }
354       frames_counter_modulo = 0;
355       sdl_ticks_amount = 0;
356     }
357 
358   keyboard->read_events ();
359   check_if_toggle_fullscreen ();
360 #ifndef SOUNDISOFF
361   audio->run ();
362 #endif
363   return;
364 }
365 
366 /**
367  * Return tne number of frames per second
368  * @return the frame frequency
369  */
370 Uint32
get_frames_per_second()371 handler_display::get_frames_per_second ()
372 {
373   return frames_per_second;
374 }
375 
376 //------------------------------------------------------------------------------
377 // buffer & tampon: convert (x,y) to offset
378 //      input   => zbase: start offset
379 //                      => offsx: x coordinate
380 //                      => offsy: y coordinate
381 //------------------------------------------------------------------------------
382 Sint32
ecran_next(Sint32 zbase,Sint32 offsx,Sint32 offsy)383 handler_display::ecran_next (Sint32 zbase, Sint32 offsx, Sint32 offsy)
384 {
385   return (zbase + offsy * game_screen_pitch + offsx);
386 }
387 
388 /**
389  * Initialize color palette for the current screen
390  * @param pal pointer to color components
391  */
392 void
enable_palette(unsigned char * pal)393 handler_display::enable_palette (unsigned char *pal)
394 {
395   if (is_verbose)
396     {
397       std::cout << "handler_display::enable_palette() " << std::endl;
398     }
399   unsigned char *p = pal;
400   SDL_Color *color = &sdl_palette[0];
401   Uint32 k = 0;
402   for (Uint32 i = 0; i < 256; i++)
403     {
404       color->r = p[k++];
405       color->g = p[k++];
406       color->b = p[k++];
407       color++;
408     }
409 
410   game_screen->set_palette (sdl_palette);
411   background_screen->set_palette (sdl_palette);
412   SDL_SetPalette (sdl_screen, SDL_LOGPAL | SDL_PHYSPAL, sdl_palette, 0, 256);
413 }
414 
415 /**
416  * Initialize color palette for the current screen
417  * @param pal pointer to color components of a SDL_Color structure
418  */
419 void
enable_palette(SDL_Color * pal)420 handler_display::enable_palette (SDL_Color * pal)
421 {
422   if (is_verbose)
423     {
424       std::cout << "handler_display::enable_palette(SDL) " << std::endl;
425     }
426   game_screen->set_palette (pal);
427   background_screen->set_palette (pal);
428   SDL_SetPalette (sdl_screen, SDL_LOGPAL | SDL_PHYSPAL, pal, 0, 256);
429 }
430 
431 /**
432  * Return the current SDL palette
433  * @return a pointer to a SDL_Color structure
434  */
435 SDL_Color *
get_palette()436 handler_display::get_palette ()
437 {
438   return sdl_palette;
439 }
440 
441 /**
442  * Recopy the game offscreen in the main window
443  */
444 void
window_update()445 handler_display::window_update ()
446 {
447   SDL_Rect source =
448   {
449     0,
450     (Sint16) (offsetplus + tilt_offset),
451     (Uint16) window_width,
452     (Uint16) (window_height + offsetplus + tilt_offset)
453   };
454   SDL_Rect destination =
455   {
456     0, 0,
457     (Uint16) window_width, (Uint16) window_height
458   };
459   if (SDL_BlitSurface (game_surface, &source, sdl_screen, &destination) < 0)
460     {
461       std::cerr << "(!)handler_display::window_update():" <<
462                 "BlitSurface() return " << SDL_GetError () << std::endl;
463     }
464   SDL_UpdateRect (sdl_screen, 0, 0, sdl_screen->w, sdl_screen->h);
465   if (tilt_offset > 0)
466     {
467       tilt_offset--;
468     }
469 }
470 
471 //-------------------------------------------------------------------------------
472 // buffer & tampon: clear shadow box
473 //      input   =>      offst: offset adresse ecran
474 //                              large: width box in pixels
475 //                              haute: height box en pixels
476 //-------------------------------------------------------------------------------
477 void
clr_shadow(Sint32 offst,Sint32 large,Sint32 haute)478 handler_display::clr_shadow (Sint32 offst, Sint32 large, Sint32 haute)
479 {
480   char zmask = 0x7F;
481   char *bffer = game_screen_pixels + offst;
482   char *tmpon = background_pixels + offst;
483   Sint32 a = large;
484   Sint32 b = haute;
485   Sint32 n = game_screen_pitch - a;
486   for (Sint32 j = 0; j < b; j++, bffer += n, tmpon += n)
487     {
488       for (Sint32 i = 0; i < a; i++)
489         {
490           char pixel = *bffer;
491           pixel &= zmask;
492           *(bffer++) = pixel;
493           pixel = *tmpon;
494           pixel &= zmask;
495           *(tmpon++) = pixel;
496         }
497     }
498 }
499 
500 /**
501  * Clear a shadow region
502  * @param xcoord
503  * @param ycoord
504  * @param width
505  * @param height
506  */
507 void
clr_shadow(Sint32 xcoord,Sint32 ycoord,Sint32 width,Sint32 height)508 handler_display::clr_shadow (Sint32 xcoord, Sint32 ycoord, Sint32 width,
509                              Sint32 height)
510 {
511   char zmask = 0x7F;
512   char *screen = background_screen->get_pixel_data (xcoord, ycoord);
513   char *bkgd = game_screen->get_pixel_data (xcoord, ycoord);
514 
515   Sint32 h = width;
516   Sint32 v = height;
517   Sint32 n = game_screen_pitch - h;
518   for (Sint32 j = 0; j < v; j++, screen += n, bkgd += n)
519     {
520       for (Sint32 i = 0; i < h; i++)
521         {
522           char pixel = *screen;
523           pixel &= zmask;
524           *(screen++) = pixel;
525           pixel = *bkgd;
526           pixel &= zmask;
527           *(bkgd++) = pixel;
528         }
529     }
530 }
531 
532 //------------------------------------------------------------------------------
533 // buffer & tampon: display shadow box
534 //      input   => offst: buffer offset in bytes
535 //                      => large: width box in pixels
536 //                      => haute: height box en pixels
537 //------------------------------------------------------------------------------
538 void
set_shadow(Sint32 offst,Sint32 large,Sint32 haute)539 handler_display::set_shadow (Sint32 offst, Sint32 large, Sint32 haute)
540 {
541   char zmask = (char) (0x80);
542   char *bffer = game_screen_pixels + offst;
543   char *tmpon = background_pixels + offst;
544   Sint32 a = large;
545   Sint32 b = haute;
546   Sint32 n = game_screen_pitch - a;
547   for (Sint32 j = 0; j < b; j++, bffer += n, tmpon += n)
548     {
549       for (Sint32 i = 0; i < a; i++)
550         {
551           char pixel = *bffer;
552           pixel |= zmask;
553           *(bffer++) = pixel;
554           pixel = *tmpon;
555           pixel |= zmask;
556           *(tmpon++) = pixel;
557         }
558     }
559 }
560 
561 //------------------------------------------------------------------------------
562 // buffer: copy an image of 32 width pixels into buffer memory
563 //------------------------------------------------------------------------------
564 void
buf_affx32(char * srcPT,char * desPT,Sint32 width,Sint32 heigh)565 handler_display::buf_affx32 (char *srcPT, char *desPT, Sint32 width,
566                              Sint32 heigh)
567 {
568   Sint32 *d = (Sint32 *) desPT;
569   Sint32 *s = (Sint32 *) srcPT;
570   Sint32 j = heigh;
571   Sint32 ms = width;
572   Sint32 md = game_screen_pitch;
573   for (Sint32 i = 0; i < j; i++)
574     {
575       d[0] = s[0];
576       d[1] = s[1];
577       d[2] = s[2];
578       d[3] = s[3];
579       d[4] = s[4];
580       d[5] = s[5];
581       d[6] = s[6];
582       d[7] = s[7];
583       s = (Sint32 *) ((char *) s + ms);
584       d = (Sint32 *) ((char *) d + md);
585     }
586 }
587 
588 //------------------------------------------------------------------------------
589 // buffer: copy an image of 64 width pixels into buffer memory
590 //------------------------------------------------------------------------------
591 void
buf_affx64(char * srcPT,char * desPT,Sint32 width,Sint32 heigh)592 handler_display::buf_affx64 (char *srcPT, char *desPT, Sint32 width,
593                              Sint32 heigh)
594 {
595   double *d = (double *) desPT;
596   double *s = (double *) srcPT;
597   Sint32 j = heigh;
598   Sint32 ms = width;
599   Sint32 md = game_screen_pitch;
600   for (Sint32 i = 0; i < j; i++)
601     {
602       d[0] = s[0];
603       d[1] = s[1];
604       d[2] = s[2];
605       d[3] = s[3];
606       d[4] = s[4];
607       d[5] = s[5];
608       d[6] = s[6];
609       d[7] = s[7];
610       s = (double *) ((char *) s + ms);
611       d = (double *) ((char *) d + md);
612     }
613 }
614 
615 //------------------------------------------------------------------------------
616 // copy an image
617 //------------------------------------------------------------------------------
618 /*
619 void
620 handler_display::genericGFX (char *sAdre, Sint32 sLarg, Sint32 sHaut,
621                              Sint32 sNext, char *dAdre, Sint32 dLarg,
622                              Sint32 dHaut, Sint32 dNext)
623 {
624   Sint32 h, l;
625   Sint32 a = sNext;
626   Sint32 b = dNext;
627   if (sLarg > dLarg)
628     l = sLarg;
629   else
630     l = dLarg;
631   if (sHaut > dHaut)
632     h = dHaut;
633   else
634     h = sHaut;
635   char *d = dAdre;
636   char *s = sAdre;
637   for (Sint32 i = 0; i < h; i++, s += a, d += b)
638     {
639       for (Sint32 j = 0; j < l; j++)
640         d[j] = s[j];
641     }
642 }
643 */
644 
645 /**
646  * Tilt the screen 10 or 20 pixels upwards
647  */
648 void
tilt_screen()649 handler_display::tilt_screen ()
650 {
651   tilt_offset = 10 * resolution;
652 }
653 
654 /**
655  * Select colour gradation
656  */
657 void
set_color_gradation()658 handler_display::set_color_gradation ()
659 {
660   SDL_Color *palette = display->get_palette ();
661   SDL_Color *pal = palette + 239;
662   Sint32 i = random_counter & 0x0F;
663   if (i >= 10)
664     {
665       i = i - 10;
666     }
667   const Uint32 *color_scale = (handler_resources::color_gradations + i * 18);
668   for (i = 0; i < 17; i++)
669     {
670       Uint32 vacol = color_scale[i];
671       Uint32 vablu = vacol & 0x000000ff;
672       Uint32 vagre = vacol & 0x0000ff00;
673       vagre = vagre >> 8;
674       Uint32 vared = vacol & 0x00ff0000;
675       vared = vared >> 16;
676       pal->r = vared;
677       pal->g = vagre;
678       pal->b = vablu;
679       pal++;
680     }
681   display->enable_palette (palette);
682 }
683