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