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(¤t_time);
448
449 if (!strftime(filename_base, PATH_MAX, "%%s/screenshot_%F_%R-%%d.ppm", localtime(¤t_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