1 #include "osd_sdl_gfx.h"
2 
3 //! PC Engine rendered screen
4 SDL_Surface *screen = NULL;
5 
6 /* Overlay for hardware scaling */
7 SDL_Overlay *olay = NULL;
8 SDL_Color olay_cmap[256];
9 
10 //! Host machine rendered screen
11 SDL_Surface *physical_screen = NULL;
12 
13 SDL_Rect physical_screen_rect;
14 
15 int blit_x,blit_y;
16 // where must we blit the screen buffer on screen
17 
18 int screen_blit_x, screen_blit_y;
19 // where on the screen we must blit XBuf
20 
21 extern UChar* XBuf;
22 // buffer for video flipping
23 
24 UChar index_to_RGB[256];
25 // convertion array from bero's reduced pce palette to x11 palette
26 
27 int osd_gfx_init();
28 int osd_gfx_init_normal_mode();
29 void osd_gfx_put_image_normal();
30 void osd_gfx_shut_normal_mode();
31 
32 void osd_gfx_dummy_func();
33 
34 osd_gfx_driver osd_gfx_driver_list[3] =
35 {
36   { osd_gfx_init, osd_gfx_init_normal_mode, osd_gfx_put_image_normal, osd_gfx_shut_normal_mode },
37   { osd_gfx_init, osd_gfx_init_normal_mode, osd_gfx_put_image_normal, osd_gfx_shut_normal_mode },
38   { osd_gfx_init, osd_gfx_init_normal_mode, osd_gfx_put_image_normal, osd_gfx_shut_normal_mode }
39 };
40 
osd_gfx_dummy_func(void)41 void osd_gfx_dummy_func(void)
42 {
43  return;
44  }
45 
DrawPixel(SDL_Surface * screen,int x,int y,Uint8 R,Uint8 G,Uint8 B)46  void DrawPixel(SDL_Surface *screen, int x, int y,
47                                     Uint8 R, Uint8 G, Uint8 B)
48 {
49   Uint32 color = SDL_MapRGB(screen->format, R, G, B);
50   switch (screen->format->BytesPerPixel)
51   {
52     case 1: // Assuming 8-bpp
53       {
54         Uint8 *bufp;
55         bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;
56         *bufp = color;
57       }
58       break;
59     case 2: // Probably 15-bpp or 16-bpp
60       {
61         Uint16 *bufp;
62         bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x;
63         *bufp = color;
64       }
65       break;
66     case 3: // Slow 24-bpp mode, usually not used
67       {
68         Uint8 *bufp;
69         bufp = (Uint8 *)screen->pixels + y*screen->pitch + x * 3;
70         if(SDL_BYTEORDER == SDL_LIL_ENDIAN)
71         {
72           bufp[0] = color;
73           bufp[1] = color >> 8;
74           bufp[2] = color >> 16;
75         } else {
76           bufp[2] = color;
77           bufp[1] = color >> 8;
78           bufp[0] = color >> 16;
79         }
80       }
81       break;
82     case 4: // Probably 32-bpp
83       {
84         Uint32 *bufp;
85         bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;
86         *bufp = color;
87       }
88       break;
89   }
90 }
91 
Slock(SDL_Surface * screen)92 void Slock(SDL_Surface *screen)
93 {
94   if ( SDL_MUSTLOCK(screen) )
95   {
96     if ( SDL_LockSurface(screen) < 0 )
97     {
98       return;
99     }
100   }
101 }
102 
Sulock(SDL_Surface * screen)103 void Sulock(SDL_Surface *screen)
104 {
105   if ( SDL_MUSTLOCK(screen) )
106   {
107     SDL_UnlockSurface(screen);
108   }
109 }
110 
111 /*****************************************************************************
112 
113     Function: osd_gfx_put_image_normal
114 
115     Description: draw the raw computed picture to screen, without any effect
116        trying to center it (I bet there is still some work on this, maybe not
117                             in this function)
118     Parameters: none
119     Return: nothing
120 
121 *****************************************************************************/
osd_gfx_put_image_normal(void)122 void osd_gfx_put_image_normal(void)
123 {
124   UInt16 y;
125 
126   if (!host.video.hardware_scaling)
127   {
128     Slock(screen);
129 
130     for (y = 0; y < io.screen_h; y++)
131 		#if defined(NEW_GFX_ENGINE)
132 			memmove(screen->pixels + y * io.screen_w, osd_gfx_buffer + y * XBUF_WIDTH, io.screen_w);
133 		#else
134       memmove(screen->pixels + y * io.screen_w, XBuf + y * WIDTH + (WIDTH - io.screen_w) / 2, io.screen_w);
135 		#endif
136 
137     Sulock(screen);
138 
139     if (physical_screen->flags & SDL_FULLSCREEN)
140       SDL_SoftStretch(screen, NULL, physical_screen, &physical_screen_rect);
141     else if (option.window_size > 1)
142       SDL_SoftStretch(screen, NULL, physical_screen, &physical_screen_rect);
143     else
144       memmove(physical_screen->pixels, screen->pixels, io.screen_w * io.screen_h);
145 
146     SDL_Flip(physical_screen);
147   }
148   else
149   {
150     UInt16 x;
151     UChar *p, *op;
152 
153     SDL_LockYUVOverlay(olay);
154 
155     for (y = 0; y < io.screen_h; y++)
156     {
157 		#if defined(NEW_GFX_ENGINE)
158 			p = osd_gfx_buffer + y * XBUF_WIDTH;
159 		#else
160       p = XBuf + y * XBUF_WIDTH + (WIDTH - io.screen_w) / 2;
161 		#endif
162 
163       op = olay->pixels[0] + olay->pitches[0] * y;
164 
165       for (x = 0; x < io.screen_w; x++)
166       {
167         if (!(x % 2))
168         {
169           if (olay->format == SDL_UYVY_OVERLAY)
170           {
171             *(op++) = olay_cmap[*p].g; // 1
172             *(op++) = olay_cmap[*p].r; // 0
173             *(op++) = olay_cmap[*p].b; // 2
174           }
175           else if (olay->format == SDL_YUY2_OVERLAY)
176           {
177             *(op++) = olay_cmap[*p].r;
178             *(op++) = olay_cmap[*p].g;
179             op[1] = olay_cmap[*p].b;
180           } else
181 					{
182 						Log("Unsupported hardware packing : %x\n", olay->format);
183 					}
184         }
185         else
186         {
187           *(op++) = olay_cmap[*p].r;	// 2
188           if (olay->format == SDL_YUY2_OVERLAY)
189             op++;
190         }
191 
192         p++;
193       }
194     }
195     SDL_UnlockYUVOverlay(olay);
196 
197     SDL_DisplayYUVOverlay(olay, &physical_screen_rect);
198   }
199 }
200 
201 /*****************************************************************************
202 
203     Function: osd_gfx_set_message
204 
205     Description: compute the message that will be displayed to create a sprite
206        to blit on screen
207     Parameters: char* mess, the message to display
208     Return: nothing but set OSD_MESSAGE_SPR
209 
210 *****************************************************************************/
osd_gfx_set_message(char * mess)211 void osd_gfx_set_message(char* mess)
212 {
213 /*
214  if (OSD_MESSAGE_SPR)
215    destroy_bitmap(OSD_MESSAGE_SPR);
216 
217  OSD_MESSAGE_SPR=create_bitmap(text_length(font,mess)+1,text_height(font)+1);
218  clear(OSD_MESSAGE_SPR);
219  textout(OSD_MESSAGE_SPR,font,mess,1,1,3);
220  textout(OSD_MESSAGE_SPR,font,mess,0,0,255);
221 */
222 
223 #warning implement set_message
224   printf("%s\n",mess);
225 }
226 
227 
228 /*
229  * osd_gfx_init:
230  * One time initialization of the main output screen
231  */
osd_gfx_init(void)232 int osd_gfx_init(void)
233 {
234   struct generic_rect rect;
235 
236 	// We can't rely anymore on io variable being accessible at this stage of a game launching
237 	const int fake_io_screen_w = 352;
238   const int fake_io_screen_h = 256;
239 
240 	if (!SDL_WasInit(SDL_INIT_VIDEO))
241    	{
242    		if (SDL_InitSubSystem(SDL_INIT_VIDEO))
243    		{
244    			printf("SDL_InitSubSystem(VIDEO) failed at %s:%d - %s\n", __FILE__, __LINE__, SDL_GetError());
245    			return 0;
246 		}
247    	}
248 
249   if ((physical_screen = SDL_SetVideoMode(option.want_fullscreen ? option.fullscreen_width : fake_io_screen_w * option.window_size,
250                                           option.want_fullscreen ? option.fullscreen_height : fake_io_screen_h * option.window_size,
251                                           (option.want_hardware_scaling ? 0 : 8), (option.want_fullscreen ? SDL_FULLSCREEN : 0) |
252                                           (option.want_hardware_scaling ? SDL_HWSURFACE : SDL_SWSURFACE) |
253                                           (option.want_hardware_scaling ? 0 : SDL_HWPALETTE))) == NULL)
254   {
255     printf("SDL_SetVideoMode failed at %s:%d - %s\n", __FILE__, __LINE__, SDL_GetError());
256     return 0;
257   }
258 
259   SDL_WM_SetCaption("Hu-Go! (www.zeograd.com)",NULL);
260 
261   if (option.want_fullscreen)
262     SDL_ShowCursor(SDL_DISABLE);
263 
264   if (option.want_hardware_scaling)
265   {
266     host.video.hardware_scaling = TRUE;
267 
268 		if (option.wanted_hardware_format != 0) // Try this first if asked to
269 			{
270 				olay = SDL_CreateYUVOverlay(fake_io_screen_w, fake_io_screen_h, option.wanted_hardware_format, physical_screen);
271 				if (olay->hw_overlay == 1)
272 					Log("Hardware scaling enabled using a %x overlay.\n", option.wanted_hardware_format);
273 			}
274 
275 		if ((option.wanted_hardware_format == 0) || (olay->hw_overlay != 1))
276 			{
277 				if (((olay = SDL_CreateYUVOverlay(fake_io_screen_w, fake_io_screen_h, SDL_UYVY_OVERLAY, physical_screen)) == NULL) ||
278 						(olay->hw_overlay != 1))
279 				{
280 					if (((olay = SDL_CreateYUVOverlay(fake_io_screen_w, fake_io_screen_h, SDL_YUY2_OVERLAY, physical_screen)) == NULL) ||
281 							(olay->hw_overlay != 1))
282 					{
283 						host.video.hardware_scaling = FALSE;
284 
285 						Log("Hardware scaling isn't available--falling back to software.\n");
286 
287 						if ((physical_screen = SDL_SetVideoMode(option.want_fullscreen ? option.fullscreen_width : fake_io_screen_w * option.window_size,
288 																										option.want_fullscreen ? option.fullscreen_width : fake_io_screen_h * option.window_size,
289 																										8, (option.want_fullscreen ? SDL_FULLSCREEN : 0) |
290 																										SDL_SWSURFACE | SDL_HWPALETTE)) == NULL)
291 						{
292 							printf("SDL_SetVideoMode failed at %s:%d - %s\n", __FILE__, __LINE__, SDL_GetError());
293 							return 0;
294 						}
295 					}
296 					else
297 						Log("Hardware scaling enabled using a YUY2 overlay.\n");
298 				}
299 				else
300 					Log("Hardware scaling enabled using a UYVY overlay.\n");
301 			}
302   }
303   else
304     host.video.hardware_scaling = FALSE;
305 
306   calc_fullscreen_aspect(physical_screen->w, physical_screen->h, &rect, fake_io_screen_w, fake_io_screen_h);
307 
308   physical_screen_rect.x = rect.start_x;
309   physical_screen_rect.y = rect.start_y;
310   physical_screen_rect.w = rect.end_x;
311   physical_screen_rect.h = rect.end_y;
312 
313   SetPalette();
314 
315   if (!host.video.hardware_scaling)
316   {
317     if ((screen = SDL_CreateRGBSurface(SDL_SWSURFACE, fake_io_screen_w, fake_io_screen_h, 8, 0, 0, 0, 0)) == NULL)
318     {
319       printf("SDL_CreateRGBSurface failed at %s:%d - %s\n", __FILE__, __LINE__, SDL_GetError());
320       return 0;
321     }
322   }
323 
324   return 1;
325 }
326 
327 
328 /*****************************************************************************
329 
330     Function:  osd_gfx_init_normal_mode
331 
332     Description: initialize the classic 256*224 video mode for normal video_driver
333     Parameters: none
334     Return: 0 on error
335             1 on success
336 
337 *****************************************************************************/
osd_gfx_init_normal_mode()338 int osd_gfx_init_normal_mode()
339 {
340   struct generic_rect rect;
341 
342 	if (!host.video.hardware_scaling)
343 		{
344 			if ((screen->w == io.screen_w) && (screen->h == io.screen_h))
345 				return;
346 		}
347 	else
348 		{
349 			if ((olay->w == io.screen_w) && (olay->h == io.screen_h))
350 				return;
351 		}
352 
353   if (!host.video.hardware_scaling)
354     SDL_FreeSurface(screen);
355   else
356     SDL_FreeYUVOverlay(olay);
357 
358 #ifdef GFX_DEBUG
359   printf("Mode change: %dx%d\n", io.screen_w, io.screen_h);
360 #endif
361 
362   if (io.screen_w == 0)
363   {
364     printf("This shouldn't happen? (io.screen_w == 0 in osd_gfx_init_normal_mode)\n");
365     io.screen_w = 256;
366   }
367 
368   if (io.screen_h == 0)
369   {
370     printf("This shouldn't happen? (io.screen_h == 0 in osd_gfx_init_normal_mode)\n");
371     io.screen_h = 224;
372   }
373 
374   if (physical_screen->flags & SDL_FULLSCREEN)
375   {
376     SDL_FillRect(physical_screen, NULL, 0);
377   }
378   else if (((physical_screen->w / option.window_size) != io.screen_w) ||
379            ((physical_screen->h / option.window_size) != io.screen_h))
380   {
381     physical_screen = SDL_SetVideoMode(io.screen_w * option.window_size, io.screen_h * option.window_size,
382                                        (host.video.hardware_scaling ? 0 : 8),
383                                        (host.video.hardware_scaling ? SDL_HWSURFACE : SDL_SWSURFACE) |
384                                        (host.video.hardware_scaling ? 0 : SDL_HWPALETTE));
385 
386     SetPalette();
387   }
388 
389   calc_fullscreen_aspect(physical_screen->w, physical_screen->h, &rect, io.screen_w, io.screen_h);
390 
391   physical_screen_rect.x = rect.start_x;
392   physical_screen_rect.y = rect.start_y;
393   physical_screen_rect.w = rect.end_x;
394   physical_screen_rect.h = rect.end_y;
395 
396   if (!host.video.hardware_scaling)
397     screen = SDL_CreateRGBSurface(SDL_SWSURFACE, io.screen_w, io.screen_h, 8, 0, 0, 0, 0);
398   else
399 		if (option.wanted_hardware_format == 0)
400   	  olay = SDL_CreateYUVOverlay(io.screen_w, io.screen_h, SDL_UYVY_OVERLAY, physical_screen);
401 		else
402 			olay = SDL_CreateYUVOverlay(io.screen_w, io.screen_h, option.wanted_hardware_format, physical_screen);
403 
404   return (screen && physical_screen) ? 1 : 0;
405 }
406 
407 
408 //! Delete the window
osd_gfx_shut_normal_mode(void)409 void osd_gfx_shut_normal_mode(void)
410 {
411   if (!host.video.hardware_scaling)
412   {
413     SDL_FreeSurface(screen);
414     screen = NULL;
415   }
416   else
417   {
418     SDL_FreeYUVOverlay(olay);
419     olay = NULL;
420   }
421 
422   /* SDL will free physical_screen internally */
423   SDL_QuitSubSystem(SDL_INIT_VIDEO);
424 
425   physical_screen = NULL;
426 }
427 
428 /*****************************************************************************
429 
430     Function: osd_gfx_savepict
431 
432     Description: save a picture in the current directory
433     Parameters: none
434     Return: the numeric part of the created filename, 0xFFFF meaning that no more
435       names were available
436 
437 *****************************************************************************/
osd_gfx_savepict()438 UInt16 osd_gfx_savepict()
439   {
440     short unsigned tmp=0;
441     char filename[PATH_MAX];
442     char filename_base[PATH_MAX];
443     char* frame_buffer;
444     FILE* output_file;
445     time_t current_time;
446 
447     time(&current_time);
448 
449     if (!strftime(filename_base, PATH_MAX, "%%s/screenshot_%F_%R-%%d.ppm", localtime(&current_time)))
450       return 0xFFFF;
451 
452     do {
453       snprintf(filename, PATH_MAX, filename_base, video_path, tmp);
454     } while (file_exists(filename) && ++tmp < 0xFFFF);
455 
456     frame_buffer = malloc(3 * (io.screen_w & 0xFFFE) * (io.screen_h & 0xFFFE));
457 
458     if (frame_buffer == NULL)
459       return 0xFFFF;
460 
461     dump_rgb_frame(frame_buffer);
462 
463     output_file = fopen(filename, "wb");
464     if (output_file != NULL)
465       {
466 	char buf[100];
467 
468 	snprintf(buf, sizeof(buf),
469 		 "P6\n%d %d\n%d\n",
470 		 io.screen_w & 0xFFFE, io.screen_h & 0xFFFE, 255);
471 	fwrite(buf, strlen(buf), 1, output_file);
472 	fwrite(frame_buffer, 3 * (io.screen_w & 0xFFFE) * (io.screen_h & 0xFFFE), 1, output_file);
473 	fclose(output_file);
474       }
475 
476     return tmp;
477   }
478 
479 
480 /*****************************************************************************
481 
482     Function:  osd_gfx_set_hugo_mode
483 
484     Description: change the video mode
485     Parameters: mode : mode of video screen
486                 width, height : minimum size of screen required
487     Return: 0 on success
488                  1 on error
489 
490 *****************************************************************************/
osd_gfx_set_hugo_mode(SInt32 mode,SInt32 width,SInt32 height)491 SInt32 osd_gfx_set_hugo_mode(SInt32 mode,SInt32 width,SInt32 height)
492 {
493 
494   screen = SDL_SetVideoMode(320,200, 8, SDL_SWSURFACE);
495   SetPalette();
496   return !screen;
497 
498  }
499 
500 /*****************************************************************************
501 
502     Function: osd_gfx_set_color
503 
504     Description: Change the component of the choosen color
505     Parameters: UChar index : index of the color to change
506     			UChar r	: new red component of the color
507                 UChar g : new green component of the color
508                 UChar b : new blue component of the color
509     Return:
510 
511 *****************************************************************************/
osd_gfx_set_color(UChar index,UChar r,UChar g,UChar b)512 void osd_gfx_set_color(UChar index,
513                        UChar r,
514                        UChar g,
515                        UChar b)
516 {
517   SDL_Color R;
518 
519   r <<= 2;
520   g <<= 2;
521   b <<= 2;
522 
523   if (!host.video.hardware_scaling)
524   {
525     R.r = r;
526     R.g = g;
527     R.b = b;
528 
529     SDL_SetColors(physical_screen, &R, index, 1);
530   }
531   else
532   {
533     olay_cmap[index].r = (0.299 * r) + (0.587 * g) + (0.114 * b);
534     olay_cmap[index].g = (b - olay_cmap[index].r) * 0.565 + 128;
535     olay_cmap[index].b = (r - olay_cmap[index].r) * 0.713 + 128;
536   }
537 }
538 
539 
ToggleFullScreen(void)540 int ToggleFullScreen(void)
541 {
542   struct generic_rect rect;
543 
544   SDL_PauseAudio(SDL_ENABLE);
545 
546   if (physical_screen->flags & SDL_FULLSCREEN)
547   {
548     if ((physical_screen = SDL_SetVideoMode(io.screen_w * option.window_size, io.screen_h * option.window_size,
549                                             (host.video.hardware_scaling ? 0 : 8),
550                                             (host.video.hardware_scaling ? SDL_HWSURFACE : SDL_SWSURFACE) |
551                                             (host.video.hardware_scaling ? 0 : SDL_HWPALETTE))) == NULL)
552     {
553       Log("Can't get physical_screen for full screen\n");
554       printf("Can't get physical screen\n");
555     }
556   } else {
557     if ((physical_screen = SDL_SetVideoMode(option.fullscreen_width, option.fullscreen_height,
558                                             (host.video.hardware_scaling ? 0 : 8),
559                                             (host.video.hardware_scaling ? SDL_HWSURFACE : SDL_SWSURFACE) |
560                                             (host.video.hardware_scaling ? 0 : SDL_HWPALETTE) | SDL_FULLSCREEN)) == NULL)
561     {
562       Log("Can't get physical_screen for full screen\n");
563       printf("Can't get physical screen\n");
564     }
565   }
566 
567   SetPalette();
568 
569   calc_fullscreen_aspect(physical_screen->w, physical_screen->h, &rect, io.screen_w, io.screen_h);
570 
571   physical_screen_rect.x = rect.start_x;
572   physical_screen_rect.y = rect.start_y;
573   physical_screen_rect.w = rect.end_x;
574   physical_screen_rect.h = rect.end_y;
575 
576   SDL_PauseAudio(SDL_DISABLE);
577 
578   return (physical_screen->flags & SDL_FULLSCREEN) ? 0 : 1;
579 }
580