1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Library General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 */
16
17 /**************************************************************************/
18 /* Generic Graphic source file */
19 /* */
20 /* Adapted by Zeograd (Olivier Jolly) for using Allegro */
21 /* */
22 /**************************************************************************/
23
24 #include "pce.h"
25 #include "utils.h"
26 #include "config.h"
27
28 typedef struct {
29 UChar r,g,b;
30 } rgb_map_struct;
31
32 rgb_map_struct rgb_map[256];
33
SetPalette(void)34 void SetPalette(void)
35 {
36 UChar i;
37
38 osd_gfx_set_color(255, 0x3f, 0x3f, 0x3f);
39 rgb_map[255].r = 255;
40 rgb_map[255].b = 255;
41 rgb_map[255].g = 255;
42
43 for (i = 0; i < 255; i++)
44 {
45 osd_gfx_set_color(i, (i & 0x1C) << 1, (i & 0xe0) >> 2, (i & 0x03) << 4);
46 rgb_map[i].r = (i & 0x1C) << 3;
47 rgb_map[i].g = (i & 0xe0);
48 rgb_map[i].b = (i & 0x03) << 6;
49 }
50 #if defined(SDL)
51
52 olay_cmap[255].r = (Uint8) ((0.299 * 0xff) + (0.587 * 0xff) + (0.114 * 0xff));
53 olay_cmap[255].g = (Uint8) ((0xff - olay_cmap[i].r) * 0.565 + 128);
54 olay_cmap[255].b = (Uint8) ((0xff - olay_cmap[i].r) * 0.713 + 128);
55
56 for (i = 0; i < 255; i++)
57 {
58 int r,g,b;
59 r = (i & 0x1C) << 3;
60 g = (i & 0xe0);
61 b = (i & 0x03) << 6;
62 olay_cmap[i].r = (Uint8)((0.299 * r) + (0.587 * g) + (0.114 * b));
63 olay_cmap[i].g = (Uint8)((b - olay_cmap[i].r) * 0.565 + 128);
64 olay_cmap[i].b = (Uint8)((r - olay_cmap[i].r) * 0.713 + 128);
65 }
66
67 #endif
68 }
69
70
71 /*!
72 * calc_fullscreen_aspect:
73 * Generic utility that takes the width x height of the current output screen
74 * and sets up a gfx lib independent struct generic_rect (gfx.h) with the
75 * aspect-correct scaling values, provided option.want_fullscreen_aspect
76 * has been set in the config or via the command line.
77 */
calc_fullscreen_aspect(unsigned short physical_screen_width,unsigned short physical_screen_height,struct generic_rect * rect,unsigned short pce_screen_width,unsigned short pce_screen_height)78 void calc_fullscreen_aspect(unsigned short physical_screen_width,
79 unsigned short physical_screen_height,
80 struct generic_rect *rect,
81 unsigned short pce_screen_width,
82 unsigned short pce_screen_height)
83 {
84 /*
85 * Routine not called often so extra sanity checks pose no penalty.
86 */
87 if (physical_screen_height == 0)
88 {
89 printf("calc_fullscreen_aspect: physical_screen_height is 0! Aborting . . .\n");
90 exit(0);
91 }
92
93 if (pce_screen_width == 0)
94 {
95 printf("calc_fullscreen_aspect: pce_screen_width is 0! Aborting . . .\n");
96 exit(0);
97 }
98
99 if (option.want_fullscreen_aspect)
100 {
101 float physical_screen_ratio, pce_ratio;
102 int new_size;
103
104 physical_screen_ratio = (float) physical_screen_width / physical_screen_height;
105
106 pce_ratio = (pce_screen_width / physical_screen_ratio) / pce_screen_height;
107
108 if (pce_ratio < 1.0)
109 {
110 new_size = (int)(physical_screen_width * pce_ratio);
111
112 (*rect).start_x = (unsigned short int)((physical_screen_width - new_size) / 2);
113 (*rect).start_y = 0;
114 (*rect).end_x = (unsigned short int)new_size;
115 (*rect).end_y = physical_screen_height;
116 }
117 else
118 {
119 new_size = (int)(physical_screen_height / pce_ratio);
120
121 (*rect).start_x = 0;
122 (*rect).start_y = (unsigned short int)((physical_screen_height - new_size) / 2);
123 (*rect).end_x = physical_screen_width;
124 (*rect).end_y = (unsigned short int)new_size;
125 }
126 }
127 else
128 {
129 (*rect).start_x = (*rect).start_y = 0;
130 (*rect).end_x = physical_screen_width;
131 (*rect).end_y = physical_screen_height;
132 }
133 }
134
135 //! Computes the new screen height and eventually change the screen mode
change_pce_screen_height()136 void change_pce_screen_height()
137 {
138 //! minimal theorical line where to begin drawing
139 int min_display;
140
141 //! maximal theorical line where to end drawing
142 int max_display;
143
144 int cur_display;
145
146 int temp_vds = io.VDC[VPR].B.h;
147 int temp_vsw = io.VDC[VPR].B.l;
148 int temp_vdw = (int)io.VDC[VDW].W;
149 int temp_vcr = (int)io.VDC[VCR].W;
150
151 #if defined(GFX_DEBUG)
152 printf("Changing pce screen mode\nVDS = %04x VSW = %04x VDW = %04x VCR = %04x\n",
153 temp_vds,
154 temp_vsw,
155 temp_vdw,
156 temp_vcr
157 );
158 // getchar();
159 #endif
160
161 if (temp_vdw == 0)
162 return;
163
164 min_display = temp_vds + temp_vsw;
165
166 max_display = cur_display = min_display;
167 while (cur_display < 242 + 14)
168 {
169 cur_display += temp_vdw;
170 max_display = cur_display;
171
172 cur_display += 3 + temp_vcr;
173
174 #if defined(GFX_DEBUG)
175 printf("Adding vdw to the height of graphics, cur_display = %d\n", cur_display);
176 #endif
177 }
178
179 min_display = (min_display > 14 ? min_display : 14);
180 max_display = (max_display < 242 + 14 ? max_display : 242 + 14);
181
182
183 /*
184 if (option.want_television_size_emulation)
185 {
186 if (max_display - min_display >= 224)
187 {
188 int offset;
189
190 offset = (max_display - min_display + 1 - 224) / 2;
191
192 min_display += offset;
193 max_display = min_display + 223;
194 }
195 }
196 */
197
198 io.vdc_min_display = (UInt16)min_display;
199 io.vdc_max_display = (UInt16)max_display;
200
201 #if defined(GFX_DEBUG)
202 // printf("min_display = %d\tmax_display = %d\n", min_display, max_display);
203 #endif
204
205 //! Number of lines to render
206 io.screen_h = max_display - min_display + 1;
207
208 #if defined(GFX_DEBUG)
209 // printf("%d lines to render\n", io.screen_h);
210 #endif
211
212 (*osd_gfx_driver_list[video_driver].mode) ();
213 }
214
215 #if defined(NEW_GFX_ENGINE)
216
217 #define MAX_GFX_CONTEXT_SLOT_NUMBER 2
218
219 static gfx_context saved_gfx_context[MAX_GFX_CONTEXT_SLOT_NUMBER];
220
221 //! Whether we need to draw pending lines
222 static int gfx_need_redraw;
223
224 //! Frame to skip before the next frame to render
225 static int UCount = 0;
226
227 //! Whether we should change video mode after drawing the current frame
228 int gfx_need_video_mode_change = 0;
229
230 void
save_gfx_context(int slot_number)231 save_gfx_context(int slot_number)
232 {
233
234 gfx_context *destination_context;
235
236 destination_context = saved_gfx_context + slot_number;
237
238 if (slot_number == 0)
239 {
240 /*
241 if ((destination_context->scroll_x == ScrollX) &&
242 (destination_context->scroll_y == ScrollY) &&
243 (destination_context->scroll_y_diff == ScrollYDiff) &&
244 (destination_context->cr == io.VDC[CR].W))
245 {
246 #if defined(GFX_DEBUG)
247 gfx_debug_printf("Canceled primary context saving, nothing changed");
248 #endif
249 return;
250 }
251 */
252
253 if (gfx_need_redraw == 0)
254 gfx_need_redraw = 1;
255 else // Context is already saved and we haven't render the lines using it
256 {
257 #if defined(GFX_DEBUG)
258 gfx_debug_printf("Canceled context saving as a previous one wasn't consumed yet");
259 #endif
260 return;
261 }
262 }
263 if (slot_number >= MAX_GFX_CONTEXT_SLOT_NUMBER)
264 {
265 Log("Internal error in %s(%s), slot %d >= %d\n",
266 __FUNCTION__,
267 __FILE__,
268 slot_number,
269 MAX_GFX_CONTEXT_SLOT_NUMBER
270 );
271
272 return;
273 }
274
275 #if defined(GFX_DEBUG)
276 gfx_debug_printf("Saving context %d, scroll = (%d,%d,%d), CR = 0x%02d",
277 slot_number,
278 ScrollX,
279 ScrollY,
280 ScrollYDiff,
281 io.VDC[CR].W);
282 #endif
283
284 destination_context->scroll_x = ScrollX;
285 destination_context->scroll_y = ScrollY;
286 destination_context->scroll_y_diff = ScrollYDiff;
287 destination_context->cr = io.VDC[CR].W;
288 }
289
290 void
load_gfx_context(int slot_number)291 load_gfx_context(int slot_number)
292 {
293
294 gfx_context *source_context;
295
296 if (slot_number >= MAX_GFX_CONTEXT_SLOT_NUMBER)
297 {
298 Log("Internal error in %s(%s), slot %d >= %d\n",
299 __FUNCTION__,
300 __FILE__,
301 slot_number,
302 MAX_GFX_CONTEXT_SLOT_NUMBER
303 );
304
305 return;
306 }
307
308 source_context = saved_gfx_context + slot_number;
309
310 ScrollX = source_context->scroll_x;
311 ScrollY = source_context->scroll_y;
312 ScrollYDiff = source_context->scroll_y_diff;
313 io.VDC[CR].W = source_context->cr;
314
315 #if defined(GFX_DEBUG)
316 gfx_debug_printf("Restoring context %d, scroll = (%d,%d,%d), CR = 0x%02d",
317 slot_number,
318 ScrollX,
319 ScrollY,
320 ScrollYDiff,
321 io.VDC[CR].W);
322 #endif
323
324 }
325
326
327 //! render lines
328 /*
329 render lines into the buffer from min_line to max_line, inclusive
330 Refresh* draw things from min to max line given, with max exclusive
331 */
332 void
render_lines(int min_line,int max_line)333 render_lines(int min_line, int max_line)
334 {
335
336 #if !defined(FINAL_RELEASE)
337 //printf("render lines %3d - %3d in %s\n", min_line, max_line, __FILE__);
338 #endif
339
340 save_gfx_context(1);
341
342 load_gfx_context(0);
343
344 if (!UCount) // Either we're in frameskip = 0 or we're in the frame to draw
345 {
346 if (SpriteON && SPONSwitch)
347 RefreshSpriteExact (min_line, max_line - 1, 0);
348
349 RefreshLine (min_line, max_line - 1);
350
351 if (SpriteON && SPONSwitch)
352 RefreshSpriteExact (min_line, max_line - 1, 1);
353 }
354
355 load_gfx_context(1);
356
357 gfx_need_redraw = 0;
358 }
359
360 //! Rewritten version of Loop6502 from scratch, called when each line drawing should occur
361 /* TODO:
362 - sprite #0 collision checking (occur as soon as the sprite #0 is shown and overlap another sprite
363 - frame skipping to test
364 */
365 UChar
Loop6502()366 Loop6502()
367 {
368 static int video_dump_countdown = 0;
369 static int display_counter = 0;
370 static int last_display_counter = 0;
371 static int satb_dma_counter = 0;
372 UChar return_value = INT_NONE;
373
374 io.vdc_status &= ~(VDC_RasHit | VDC_SATBfinish);
375
376 // Count dma delay
377
378 if (satb_dma_counter > 0)
379 {
380 // A dma is in progress
381 satb_dma_counter --;
382
383 if (!satb_dma_counter)
384 {
385 // dma has just finished
386 if (SATBIntON)
387 {
388 io.vdc_status |= VDC_SATBfinish;
389 return_value = INT_IRQ;
390 }
391 }
392 }
393
394 // Test raster hit
395 if (RasHitON)
396 {
397 if (((io.VDC[RCR].W & 0x3FF) >= 0x40) && ((io.VDC[RCR].W & 0x3FF) <= 0x146))
398 {
399 UInt16 temp_rcr = (UInt16)((io.VDC[RCR].W & 0x3FF) - 0x40);
400
401 if (scanline == (temp_rcr + io.VDC[VPR].B.l + io.VDC[VPR].B.h) % 263)
402 {
403 // printf("\n---------------------\nRASTER HIT (%d)\n----------------------\n", scanline);
404 io.vdc_status |= VDC_RasHit;
405 return_value = INT_IRQ;
406 }
407
408 }
409 else
410 {
411 // printf("Raster counter out of bounds (%d)\n", io.VDC[RCR].W);
412 }
413 }
414 // else
415 // printf("Raster disabled\n");
416
417 // Rendering of tiles / sprites
418
419 if (scanline < 14)
420 {
421 gfx_need_redraw = 0;
422 }
423 else if (scanline < 14 + 242)
424 {
425
426 if (scanline == 14)
427 {
428
429 last_display_counter = 0;
430 display_counter = 0;
431 ScrollYDiff = 0;
432 oldScrollYDiff = 0;
433
434 // Signal that we've left the VBlank area
435 io.vdc_status &= ~VDC_InVBlank;
436 #if defined(GFX_DEBUG)
437 gfx_debug_printf("Cleaning VBlank bit from vdc_status (now, 0x%02x)", io.vdc_status);
438 #endif
439 }
440
441 if (scanline == io.vdc_min_display)
442 {
443 gfx_need_redraw = 0;
444
445 save_gfx_context(0);
446
447 #if defined(GFX_DEBUG) && !defined(FINAL_RELEASE)
448 printf("FORCED SAVE OF GFX CONTEXT\n");
449 #endif
450
451 }
452
453 if ((scanline >= io.vdc_min_display) && (scanline <= io.vdc_max_display))
454 {
455 if (gfx_need_redraw) // && scanline > io.vdc_min_display) // We got render things before being on the second line
456 {
457 render_lines(last_display_counter, display_counter);
458 last_display_counter = display_counter;
459 }
460
461 display_counter ++;
462 }
463 }
464 else if (scanline < 14 + 242 + 4)
465 {
466
467 if (scanline == 14 + 242)
468 {
469
470 save_gfx_context(0);
471
472 render_lines(last_display_counter, display_counter);
473
474 if (video_dump_flag)
475 {
476 if (video_dump_countdown)
477 video_dump_countdown--;
478 else
479 {
480 dump_video_frame();
481 video_dump_countdown = 3;
482 }
483 }
484
485 if (gfx_need_video_mode_change)
486 {
487 gfx_need_video_mode_change = 0;
488 change_pce_screen_height();
489 }
490
491 if (osd_keyboard ())
492 return INT_QUIT;
493
494 if (!UCount)
495 RefreshScreen();
496
497 #if defined(GTK)
498 /*@ -unrecog */
499 while (gtk_events_pending())
500 {
501 if (gtk_main_iteration())
502 {
503 return INT_QUIT;
504 }
505 }
506 /*@ =unrecog */
507 #endif
508 /*@-preproc */
509 #warning "place this better"
510 /*@=preproc */
511 if (CheckSprites ())
512 io.vdc_status |= VDC_SpHit;
513 else
514 io.vdc_status &= ~VDC_SpHit;
515
516 if (!UCount)
517 {
518 #if defined(ENABLE_NETPLAY)
519 if (option.want_netplay != INTERNET_PROTOCOL)
520 {
521 /* When in internet protocol mode, it's the server which is in charge of throlling */
522 wait_next_vsync();
523 }
524 #else
525 wait_next_vsync();
526 #endif /* NETPLAY_ENABLE */
527
528 UCount = UPeriod;
529 }
530 else
531 UCount--;
532
533 /* VRAM to SATB DMA */
534 if (io.vdc_satb == 1 || io.VDC[DCR].W & 0x0010)
535 {
536 #if defined(WORDS_BIGENDIAN)
537 swab(VRAM + io.VDC[SATB].W * 2, SPRAM, 64 * 8);
538 #else
539 memcpy (SPRAM, VRAM + io.VDC[SATB].W * 2, 64 * 8);
540 #endif
541 io.vdc_satb = 1;
542 io.vdc_status &= ~VDC_SATBfinish;
543
544 // Mark satb dma end interuption to happen in 4 scanlines
545 satb_dma_counter = 4;
546 }
547
548 if (return_value == INT_IRQ)
549 io.vdc_pendvsync = 1;
550 else
551 {
552 if (VBlankON)
553 {
554 io.vdc_status |= VDC_InVBlank;
555 return_value = INT_IRQ;
556 }
557 }
558 }
559
560 }
561 else
562 {
563 //Three last lines of ntsc scanlining
564 }
565
566 // Incrementing the scanline
567
568 scanline ++;
569
570 if (scanline >= 263)
571 scanline = 0;
572
573 if ((return_value != INT_IRQ) && io.vdc_pendvsync)
574 {
575 io.vdc_status |= VDC_InVBlank;
576 return_value = INT_IRQ;
577 io.vdc_pendvsync = 0;
578 }
579
580 if (return_value == INT_IRQ)
581 {
582 if (!(io.irq_mask & IRQ1))
583 {
584 io.irq_status |= IRQ1;
585 return return_value;
586 }
587 }
588
589 return INT_NONE;
590 }
591 #endif
592
593 int video_dump_flag = 0;
594
595 //! Raw dump the current frame into the buffer, for video output purposes
dump_uyvy_frame(char * output_buffer)596 void dump_uyvy_frame(char* output_buffer)
597 {
598 int x,y;
599 UChar* xbuf_pointer;
600
601 xbuf_pointer = osd_gfx_buffer;
602
603 for (y = 0; y < io.screen_h; y++, xbuf_pointer += XBUF_WIDTH - io.screen_w)
604 for (x = 0; x < io.screen_w - 1; x+=2, xbuf_pointer+=2)
605 {
606 *(output_buffer++) = (char)olay_cmap[*xbuf_pointer].g;
607 *(output_buffer++) = (char)olay_cmap[*xbuf_pointer].r;
608 *(output_buffer++) = (char)olay_cmap[*xbuf_pointer].b;
609 *(output_buffer++) = (char)olay_cmap[*(xbuf_pointer+1)].r;
610 }
611 }
612
613
614 //! Raw dump the current frame into the buffer, for video output purposes
dump_yyuv_frame(char * output_buffer)615 void dump_yyuv_frame(char* output_buffer)
616 {
617 int x,y;
618 UChar* xbuf_pointer;
619
620 xbuf_pointer = osd_gfx_buffer;
621
622 for (y = 0; y < io.screen_h; y++, xbuf_pointer += XBUF_WIDTH - io.screen_w)
623 for (x = 0; x < io.screen_w - 1; x+=2, xbuf_pointer+=2)
624 {
625 *(output_buffer++) = (char)olay_cmap[*xbuf_pointer].r;
626 *(output_buffer++) = (char)olay_cmap[*(xbuf_pointer+1)].r;
627 *(output_buffer++) = (char)olay_cmap[*xbuf_pointer].g;
628 *(output_buffer++) = (char)olay_cmap[*xbuf_pointer].b;
629 }
630 }
631
632 //! Raw dump the current frame into the buffer, for video output purposes
dump_rgb_frame(char * output_buffer)633 void dump_rgb_frame(char* output_buffer)
634 {
635 int x,y;
636 UChar* xbuf_pointer;
637
638 xbuf_pointer = osd_gfx_buffer;
639
640 for (y = 0; y < io.screen_h; y++, xbuf_pointer += XBUF_WIDTH - io.screen_w)
641 for (x = 0; x < io.screen_w; x++, xbuf_pointer++)
642 {
643 *(output_buffer++) = (char)rgb_map[*xbuf_pointer].r;
644 *(output_buffer++) = (char)rgb_map[*xbuf_pointer].g;
645 *(output_buffer++) = (char)rgb_map[*xbuf_pointer].b;
646 }
647 }
648
649 //! Raw dump the current frame into the buffer, for video output purposes
dump_raw_frame(char * output_buffer)650 void dump_raw_frame(char* output_buffer)
651 {
652 int y;
653 UChar* xbuf_pointer;
654
655 xbuf_pointer = osd_gfx_buffer;
656
657 for (y = 0; y < (io.screen_h & 0xFFFE); y++, xbuf_pointer += XBUF_WIDTH, output_buffer += (io.screen_w & 0xFFFE))
658 memcpy(output_buffer, xbuf_pointer, (size_t)(io.screen_w & 0xFFFE));
659 }
660
661
662 //! Raw dump the current frame into the buffers, for video output purposes
dump_uyv_frame_separated(char * output_buffer_u,char * output_buffer_y,char * output_buffer_v)663 void dump_uyv_frame_separated(char* output_buffer_u, char* output_buffer_y, char* output_buffer_v)
664 {
665 int x,y;
666 UChar* xbuf_pointer;
667
668 xbuf_pointer = osd_gfx_buffer;
669
670 for (y = 0; y < (io.screen_h & 0xFFFE); y++, xbuf_pointer += XBUF_WIDTH - io.screen_w)
671 for (x = 0; x < io.screen_w - 1; x+=2, xbuf_pointer+=2)
672 {
673 *(output_buffer_u++) = (char)olay_cmap[*xbuf_pointer].g;
674 *(output_buffer_y++) = (char)olay_cmap[*xbuf_pointer].r;
675 *(output_buffer_v++) = (char)olay_cmap[*xbuf_pointer].b;
676 *(output_buffer_y++) = (char)olay_cmap[*(xbuf_pointer+1)].r;
677 }
678 }
679
680 #if defined(DUMP_UYVY_SINGLE_FILE)
681
682 static FILE* video_output_file = NULL;
683
684 //! Start the video dump process
685 //! return 1 if video dumping began, else 0
start_dump_video()686 int start_dump_video()
687 {
688 char video_output_filename[PATH_MAX];
689 struct tm * tm_current_time;
690 time_t time_t_current_time;
691
692 if (video_output_file != NULL)
693 return 0;
694
695 time(&time_t_current_time);
696 tm_current_time = localtime(&time_t_current_time);
697
698 snprintf(video_output_filename, PATH_MAX, "%svideo-%04d-%02d-%02d %02d-%02d-%02d",
699 video_path,
700 tm_current_time->tm_year + 1900,
701 tm_current_time->tm_mon,
702 tm_current_time->tm_mday,
703 tm_current_time->tm_hour,
704 tm_current_time->tm_min,
705 tm_current_time->tm_sec);
706
707 video_output_file = fopen(video_output_filename, "wb");
708
709 return (video_output_file != NULL ? 1 : 0);
710 }
711
712 //! Dump the current frame into the video file
dump_video_frame()713 void dump_video_frame()
714 {
715 char* frame_buffer;
716
717 if (video_output_file == NULL)
718 return;
719
720 frame_buffer = malloc(4 * io.screen_w * io.screen_h);
721
722 if (frame_buffer == NULL)
723 return;
724
725 dump_uyvy_frame(frame_buffer);
726
727 fwrite(frame_buffer, 4 * io.screen_w * io.screen_h, 1, video_output_file);
728
729 free(frame_buffer);
730 }
731
732 //! Stop the dump video process
stop_dump_video()733 void stop_dump_video()
734 {
735 if (video_output_file != NULL)
736 fclose(video_output_file);
737
738 printf("Video dump finished on a %dx%d resolution\n", io.screen_w, io.screen_h & 0xFFFE);
739 }
740
741 #elif defined(DUMP_UYVY_MULTI_FILE)
742
743 static char video_output_base_filename[PATH_MAX];
744 static int video_output_frame_count;
745
746 //! Start the video dump process
747 //! return 1 if video dumping began, else 0
start_dump_video()748 int start_dump_video()
749 {
750 struct tm * tm_current_time;
751 time_t time_t_current_time;
752
753 if (video_dump_flag)
754 return 0;
755
756 time(&time_t_current_time);
757 tm_current_time = localtime(&time_t_current_time);
758
759 snprintf(video_output_base_filename, PATH_MAX, "%svideo-%04d-%02d-%02d %02d-%02d-%02d",
760 video_path,
761 tm_current_time->tm_year + 1900,
762 tm_current_time->tm_mon,
763 tm_current_time->tm_mday,
764 tm_current_time->tm_hour,
765 tm_current_time->tm_min,
766 tm_current_time->tm_sec);
767
768 video_output_frame_count = 0;
769
770 // We can't do much in this case, as we don't open a global handle for dumping
771 return 1;
772 }
773
774 //! Dump the current frame into the video file
dump_video_frame()775 void dump_video_frame()
776 {
777 char *frame_buffer_u;
778 char *frame_buffer_v;
779 char *frame_buffer_y;
780
781 char video_output_filename_u[PATH_MAX];
782 char video_output_filename_v[PATH_MAX];
783 char video_output_filename_y[PATH_MAX];
784
785 FILE* tmp_video_output_file;
786
787 snprintf(video_output_filename_u, PATH_MAX, "%s-%d.U",
788 video_output_base_filename,
789 video_output_frame_count);
790
791 snprintf(video_output_filename_v, PATH_MAX, "%s-%d.V",
792 video_output_base_filename,
793 video_output_frame_count);
794
795 snprintf(video_output_filename_y, PATH_MAX, "%s-%d.Y",
796 video_output_base_filename,
797 video_output_frame_count);
798
799 frame_buffer_u = malloc((io.screen_w & 0xFFFE) * (io.screen_h & 0xFFFE));
800 frame_buffer_v = malloc((io.screen_w & 0xFFFE) * (io.screen_h & 0xFFFE));
801 frame_buffer_y = malloc(2 * (io.screen_w & 0xFFFE) * (io.screen_h & 0xFFFE));
802
803 if ((frame_buffer_u == NULL) || (frame_buffer_v == NULL) || (frame_buffer_y == NULL))
804 return;
805
806 dump_uyv_frame_separated(frame_buffer_u, frame_buffer_y, frame_buffer_v);
807
808 tmp_video_output_file = fopen(video_output_filename_u, "wb");
809 if (tmp_video_output_file != NULL)
810 {
811 fwrite(frame_buffer_u, (io.screen_w & 0xFFFE) * (io.screen_h & 0xFFFE), 1, tmp_video_output_file);
812 fclose(tmp_video_output_file);
813 }
814
815 tmp_video_output_file = fopen(video_output_filename_y, "wb");
816 if (tmp_video_output_file != NULL)
817 {
818 fwrite(frame_buffer_y, 2 * (io.screen_w & 0xFFFE) * (io.screen_h & 0xFFFE), 1, tmp_video_output_file);
819 fclose(tmp_video_output_file);
820 }
821
822 tmp_video_output_file = fopen(video_output_filename_v, "wb");
823 if (tmp_video_output_file != NULL)
824 {
825 fwrite(frame_buffer_v,(io.screen_w & 0xFFFE) * (io.screen_h & 0xFFFE), 1, tmp_video_output_file);
826 fclose(tmp_video_output_file);
827 }
828
829 video_output_frame_count ++;
830
831 free(frame_buffer_u);
832 free(frame_buffer_v);
833 free(frame_buffer_y);
834 }
835
836 //! Stop the dump video process
stop_dump_video()837 void stop_dump_video()
838 {
839 printf("Video dump finished on a %dx%d resolution\n", io.screen_w & 0xFFFE, io.screen_h & 0xFFFE);
840 }
841
842 #elif defined(DUMP_YYUV_SINGLE_FILE)
843
844 static FILE* video_output_file = NULL;
845
846 //! Start the video dump process
847 //! return 1 if video dumping began, else 0
start_dump_video()848 int start_dump_video()
849 {
850 char video_output_filename[PATH_MAX];
851 struct tm * tm_current_time;
852 time_t time_t_current_time;
853
854 if (video_output_file != NULL)
855 return 0;
856
857 time(&time_t_current_time);
858 tm_current_time = localtime(&time_t_current_time);
859
860 snprintf(video_output_filename, PATH_MAX, "%svideo-%04d-%02d-%02d %02d-%02d-%02d",
861 video_path,
862 tm_current_time->tm_year + 1900,
863 tm_current_time->tm_mon,
864 tm_current_time->tm_mday,
865 tm_current_time->tm_hour,
866 tm_current_time->tm_min,
867 tm_current_time->tm_sec);
868
869 video_output_file = fopen(video_output_filename, "wb");
870
871 return (video_output_file != NULL ? 1 : 0);
872 }
873
874 //! Dump the current frame into the video file
dump_video_frame()875 void dump_video_frame()
876 {
877 char* frame_buffer;
878
879 if (video_output_file == NULL)
880 return;
881
882 frame_buffer = malloc(4 * io.screen_w * io.screen_h);
883
884 if (frame_buffer == NULL)
885 return;
886
887 dump_yyuv_frame(frame_buffer);
888
889 fwrite(frame_buffer, 4 * io.screen_w * io.screen_h, 1, video_output_file);
890
891 free(frame_buffer);
892 }
893
894 //! Stop the dump video process
stop_dump_video()895 void stop_dump_video()
896 {
897 if (video_output_file != NULL)
898 fclose(video_output_file);
899
900 printf("Video dump finished on a %dx%d resolution\n", io.screen_w, io.screen_h & 0xFFFE);
901 }
902
903 #elif defined(DUMP_PPM_MULTI_FILE)
904
905 static char video_output_base_filename[PATH_MAX];
906 static int video_output_frame_count;
907
908 //! Start the video dump process
909 //! return 1 if video dumping began, else 0
start_dump_video()910 int start_dump_video()
911 {
912 struct tm * tm_current_time;
913 time_t time_t_current_time;
914
915 if (video_dump_flag)
916 return 0;
917
918 time(&time_t_current_time);
919 tm_current_time = localtime(&time_t_current_time);
920
921 snprintf(video_output_base_filename, PATH_MAX, "%svideo-%04d-%02d-%02d %02d-%02d-%02d",
922 video_path,
923 tm_current_time->tm_year + 1900,
924 tm_current_time->tm_mon,
925 tm_current_time->tm_mday,
926 tm_current_time->tm_hour,
927 tm_current_time->tm_min,
928 tm_current_time->tm_sec);
929
930 video_output_frame_count = 0;
931
932 // We can't do much in this case, as we don't open a global handle for dumping
933 return 1;
934 }
935
936 //! Dump the current frame into the video file
dump_video_frame()937 void dump_video_frame()
938 {
939 char *frame_buffer;
940 char video_output_filename[PATH_MAX];
941 FILE* tmp_video_output_file;
942
943 snprintf(video_output_filename, PATH_MAX, "%s-%d.ppm",
944 video_output_base_filename,
945 video_output_frame_count);
946
947 frame_buffer = malloc(3 * (io.screen_w & 0xFFFE) * (io.screen_h & 0xFFFE));
948
949 if (frame_buffer == NULL)
950 return;
951
952 dump_rgb_frame(frame_buffer);
953
954 tmp_video_output_file = fopen(video_output_filename, "wb");
955 if (tmp_video_output_file != NULL)
956 {
957 char buf[100];
958
959 snprintf(buf, sizeof(buf),
960 "P6\n%d %d\n%d\n",
961 io.screen_w & 0xFFFE, io.screen_h & 0xFFFE, 255);
962 fwrite(buf, strlen(buf), 1, tmp_video_output_file);
963 fwrite(frame_buffer, 3 * (io.screen_w & 0xFFFE) * (io.screen_h & 0xFFFE), 1, tmp_video_output_file);
964 fclose(tmp_video_output_file);
965 }
966
967 video_output_frame_count ++;
968
969 free(frame_buffer);
970 }
971
972 //! Stop the dump video process
stop_dump_video()973 void stop_dump_video()
974 {
975 printf("Video dump finished on a %dx%d resolution\n", io.screen_w & 0xFFFE, io.screen_h & 0xFFFE);
976 }
977
978 #else
979
980 static FILE* video_output_file = NULL;
981 static unsigned int old_dump_crc = (unsigned)-1;
982 static UInt16 old_screen_w, old_screen_h;
983
984 static int video_frame_total, video_frame_skipped;
985
986 //! Start the video dump process
987 //! return 1 if video dumping began, else 0
start_dump_video()988 int start_dump_video()
989 {
990 char video_output_filename[PATH_MAX];
991 struct tm * tm_current_time;
992 time_t time_t_current_time;
993
994 if (video_output_file != NULL)
995 return 0;
996
997 (void)time(&time_t_current_time);
998 tm_current_time = localtime(&time_t_current_time);
999
1000 snprintf(video_output_filename, PATH_MAX, "%svideo-%04d-%02d-%02d %02d-%02d-%02d",
1001 video_path,
1002 tm_current_time->tm_year + 1900,
1003 tm_current_time->tm_mon + 1,
1004 tm_current_time->tm_mday,
1005 tm_current_time->tm_hour,
1006 tm_current_time->tm_min,
1007 tm_current_time->tm_sec);
1008
1009 video_output_file = fopen(video_output_filename, "wb");
1010
1011 old_dump_crc = (unsigned)-1;
1012 old_screen_w = -1;
1013 old_screen_h = -1;
1014
1015 video_frame_total = 0;
1016 video_frame_skipped = 0;
1017
1018 return (video_output_file != NULL ? 1 : 0);
1019 }
1020
1021 //! Dump the current frame into the video file
dump_video_frame()1022 void dump_video_frame()
1023 {
1024 char* frame_buffer;
1025 int index;
1026 unsigned char tmp_data;
1027 unsigned int CRC = (unsigned)0xFFFFFFFF;
1028
1029 if (video_output_file == NULL)
1030 return;
1031
1032 frame_buffer = malloc((size_t)((io.screen_w & ~1) * (io.screen_h & ~1)));
1033
1034 if (frame_buffer == NULL)
1035 return;
1036
1037 dump_raw_frame(frame_buffer);
1038
1039 // Compute the rendered buffer CRC
1040 for (index = 0; index < ((io.screen_w & ~1) * (io.screen_h & ~1)); index++)
1041 {
1042 tmp_data = (unsigned char)frame_buffer[index];
1043 tmp_data ^= CRC;
1044 CRC >>= 8;
1045 CRC ^= TAB_CONST[tmp_data];
1046 }
1047
1048 if ((old_screen_w != (UInt16)(io.screen_w & ~1)) || (old_screen_h != (UInt16)(io.screen_h & ~1)) || (CRC != old_dump_crc))
1049 {
1050 UInt16 dum;
1051
1052 dum = htons(io.screen_w & ~1);
1053 (void)fwrite(&dum, 2, 1, video_output_file);
1054
1055 dum = htons(io.screen_h & ~1);
1056 (void)fwrite(&dum, 2, 1, video_output_file);
1057
1058 (void)fwrite(frame_buffer, (size_t)((io.screen_w & ~1) * (io.screen_h & ~1)), 1, video_output_file);
1059
1060 }
1061 else
1062 {
1063 UInt32 dum;
1064
1065 dum = 0;
1066
1067 (void)fwrite(&dum, 4, 1, video_output_file);
1068
1069 video_frame_skipped ++;
1070 }
1071
1072 free(frame_buffer);
1073 old_screen_h = (UInt16)(io.screen_h & ~1);
1074 old_screen_w = (UInt16)(io.screen_w & ~1);
1075 old_dump_crc = CRC;
1076 video_frame_total ++;
1077 }
1078
1079 //! Stop the dump video process
stop_dump_video()1080 void stop_dump_video()
1081 {
1082 char finish_message[100];
1083
1084 if (video_output_file != NULL)
1085 fclose(video_output_file);
1086
1087 snprintf(finish_message, 100, "Video dump finished, %d frames dumped, %d frames compressed (%.2f%% compression)",
1088 video_frame_total,
1089 video_frame_skipped,
1090 (video_frame_total != 0 ? 100.0 * video_frame_skipped / video_frame_total : 100));
1091
1092 osd_gfx_set_message(finish_message);
1093 }
1094
1095 #endif
1096
1097 #if defined(GFX_DEBUG)
gfx_debug_printf(char * format,...)1098 void gfx_debug_printf(char *format, ...)
1099 {
1100 FILE *log_file;
1101 char buf[256];
1102
1103 va_list ap;
1104 va_start (ap, format);
1105 vsprintf (buf, format, ap);
1106 va_end (ap);
1107
1108 fprintf (stderr, "%3d: ", scanline);
1109 fprintf (stderr, buf);
1110 fprintf (stderr, "\n");
1111
1112 fflush (stderr);
1113 }
1114 #endif
1115