home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / misc / emu / Frodo.lha / Frodo / src / Display.c < prev    next >
C/C++ Source or Header  |  1995-12-03  |  14KB  |  639 lines

  1. /*
  2.  *  Display.c - Darstellung der C64-Grafik,
  3.  *              Handhabung des Emulatorfensters
  4.  *
  5.  *  Copyright (C) 1994-1995 by Christian Bauer
  6.  */
  7.  
  8. /*
  9.  *  Anmerkungen:
  10.  *  ------------
  11.  *
  12.  *  - Die Farbpalette besteht aus den 16 C64-Farben, 16mal wiederholt.
  13.  *    Dadurch spart man sich das Ausmaskieren der unteren 4 Bit bei den
  14.  *    VIC-Farbcodes. Allerdings muß dieses bei der Chunky->Planar-
  15.  *    Konvertierung für die Amiga-Chips erfolgen (der Algorithmus
  16.  *    setzt voraus, daß die oberen Nibbles Null sind).
  17.  */
  18.  
  19. #include <exec/types.h>
  20. #include <exec/libraries.h>
  21. #include <exec/memory.h>
  22. #include <intuition/intuition.h>
  23. #include <intuition/screens.h>
  24. #include <libraries/gadtools.h>
  25. #include <devices/timer.h>
  26. #include <clib/exec_protos.h>
  27. #include <clib/intuition_protos.h>
  28. #include <clib/graphics_protos.h>
  29. #include <clib/gadtools_protos.h>
  30. #include <clib/timer_protos.h>
  31. #include <string.h>
  32.  
  33. #include "Display.h"
  34. #include "SAM.h"
  35. #include "Prefs.h"
  36. #define CATCOMP_NUMBERS 1
  37. #include "LocStrings.h"
  38.  
  39.  
  40. // Aus Main.asm
  41. extern struct Library *GfxBase;
  42. extern struct Library *IntuitionBase;
  43. extern void ShowPrefs(void);
  44. extern void PutChProc(void);
  45. extern char *GetStr(int strnum);
  46.  
  47. // Aus 6510.asm
  48. extern struct Task *CPUTask;
  49. extern void Pause6510(void);
  50. extern void Resume6510(void);
  51.  
  52. // Aus 6526.asm
  53. extern void KeyPressed(char c);
  54.  
  55. // Aus 6569.asm
  56. extern APTR CURRENTA5;
  57. extern BYTE ChunkyBuf[];
  58. extern UWORD SkipLatch;
  59. extern UWORD LimitSpeed;
  60.  
  61. // Aus 6581.asm
  62. extern void PauseSound(void);
  63. extern void ResumeSound(void);
  64.  
  65. // Aus c2p4.asm
  66. extern void c2p4(UBYTE *fBUFFER, UBYTE *fBUFFER_CMP, APTR *planes, struct Task *task, ULONG signals);
  67. extern int Initc2p4(void);
  68. extern void Exitc2p4(void);
  69.  
  70.  
  71. // Prototypes
  72. void open_double_buf(int type, int width, int height);
  73. int handle_IDCMP(int done);
  74. int handle_menu(int menu, int item, int done);
  75.  
  76.  
  77. char has_gfx_39, has_gfx_40;  // Flags für Version der graphics.library
  78.  
  79. int current_type, current_width, current_height;
  80.  
  81. struct Screen *the_screen;
  82. struct Window *the_window;
  83. struct VisualInfo *the_visual_info;
  84. struct RastPort *the_rast_port;
  85. struct ViewPort *the_view_port;
  86. struct TextFont *topaz_font;
  87. struct Menu *the_menus;
  88.  
  89. // Für WritePixelArray8()
  90. struct BitMap *temp_bm;
  91. struct BitMap v37_temp_bm;
  92. struct RastPort temp_rp;
  93.  
  94. // Double Buffering
  95. struct ScreenBuffer *scr_buf[2];
  96. int inv_buf_num;
  97. char using_db;                // Flag: Double Buffering wird benutzt
  98.  
  99. // c2p4
  100. APTR comparison_buf[2];
  101. char c2p4_signal;            // Signal: c2p4 fertig
  102. LONGBITS c2p4_set;
  103. char must_wait_for_c2p4;    // Flag: Auf c2p4 muß gewartet werden
  104.  
  105. // Geschwindigkeitsanzeige
  106. struct MsgPort *timer_port;
  107. struct timerequest *timer_io;
  108.  
  109.  
  110. const struct TextAttr topaz_attr = {
  111.   "topaz.font", 8, FS_NORMAL, 0
  112. };
  113.  
  114. struct NewMenu new_menus[] = {
  115.   NM_TITLE, MSG_EMULATION_MENU, NULL, 0, 0, NULL,
  116.   NM_ITEM, MSG_SETTINGS_MENU, NULL, 0, 0, NULL,
  117.   NM_ITEM, MSG_SAM_MENU, "M", 0, 0, NULL,
  118.   NM_ITEM, NM_BARLABEL, NULL, 0, 0, NULL,
  119.   NM_ITEM, MSG_QUIT_MENU, "Q", 0, 0, NULL,
  120.   NM_END, NULL, NULL, 0, 0, NULL
  121. };
  122.  
  123. const UBYTE palette_red[16] = {
  124.   0, 15, 12, 0, 15, 0, 0, 15, 15, 8, 15, 4, 8, 8, 8, 12
  125. };
  126.  
  127. const UBYTE palette_green[16] = {
  128.   0, 15, 0, 15, 0, 12, 0, 15, 8, 4, 8, 4, 8, 15, 8, 12
  129. };
  130.  
  131. const UBYTE palette_blue[16] = {
  132.   0, 15, 0, 12, 15, 0, 12, 0, 0, 0, 8, 4, 8, 8, 15, 12
  133. };
  134.  
  135.  
  136. /*
  137.  *  Screen und Fenster öffnen, alles vorbereiten
  138.  *  0: OK, 1: Fehler beim Screen-Öffnen, 2: Kein Speicher
  139.  */
  140.  
  141. int OpenDisplay(int type, ULONG display_id, UWORD overscan, int width, int height)
  142. {
  143.   int depth;
  144.   int i;
  145.  
  146.   has_gfx_39 = (GfxBase->lib_Version >= 39);
  147.   has_gfx_40 = (GfxBase->lib_Version >= 40);
  148.  
  149.   must_wait_for_c2p4 = FALSE;
  150.   using_db = FALSE;
  151.  
  152.   current_type = type;
  153.   current_width = width;
  154.   current_height = height;
  155.  
  156.   switch (type) {
  157.     case SCRTYPE_8BIT: depth = 8; break;
  158.     case SCRTYPE_4BIT: depth = 4; break;
  159.     case SCRTYPE_1BIT: depth = 1; break;
  160.   }
  161.  
  162.   if (!(the_screen = OpenScreenTags(NULL,
  163.     SA_Width, width,
  164.     SA_Height, height,
  165.     SA_DisplayID, display_id,
  166.     SA_Overscan, overscan,
  167.     SA_Depth, depth,
  168.     SA_Quiet, TRUE,
  169.     SA_AutoScroll, TRUE,
  170.     TAG_DONE)))
  171.     return 1;
  172.  
  173.   the_rast_port = &the_screen->RastPort;
  174.   the_view_port = &the_screen->ViewPort;
  175.  
  176.   if (topaz_font = OpenFont(&topaz_attr))
  177.     SetFont(the_rast_port, topaz_font);
  178.   SetAPen(the_rast_port, 1);
  179.  
  180.   if (!(the_visual_info = GetVisualInfo(the_screen, NULL)))
  181.     return 2;
  182.  
  183.   if (!(the_menus = CreateMenus(new_menus, GTMN_FullMenu, TRUE, TAG_DONE)))
  184.     return 2;
  185.   LayoutMenus(the_menus, the_visual_info, GTMN_NewLookMenus, TRUE, TAG_DONE);
  186.  
  187.   if (!(the_window = OpenWindowTags(NULL,
  188.     WA_Left, 0,
  189.     WA_Top, 0,
  190.     WA_Width, width,
  191.     WA_Height, height,
  192.     WA_CustomScreen, the_screen,
  193.     WA_IDCMP, IDCMP_RAWKEY | IDCMP_MENUPICK | IDCMP_MENUVERIFY,
  194.     WA_Backdrop, TRUE,
  195.     WA_Borderless, TRUE,
  196.     WA_NoCareRefresh, TRUE,
  197.     WA_Activate, TRUE,
  198.     WA_NewLookMenus, TRUE,
  199.     TAG_DONE)))
  200.     return 2;
  201.  
  202.   SetMenuStrip(the_window, the_menus);
  203.  
  204.   switch (type) {
  205.     case SCRTYPE_8BIT:
  206.  
  207.       // Farbpalette laden
  208.       for (i=0; i<256; i++)
  209.         SetRGB4(the_view_port, i,
  210.           palette_red[i & 0xf], palette_green[i & 0xf], palette_blue[i & 0xf]);
  211.  
  212.       // Temporären RastPort für WritePixelArray8() anlegen
  213.       if (has_gfx_39) {
  214.         if (!(temp_bm = AllocBitMap(width, 1, 8, 0, NULL)))
  215.           return 2;
  216.       } else {
  217.         InitBitMap(temp_bm = &v37_temp_bm, depth, width, 1);
  218.         for (i=0; i<8; i++)
  219.           if (!(v37_temp_bm.Planes[i] = AllocRaster(width, 1)))
  220.             return 2;
  221.       }
  222.  
  223.       InitRastPort(&temp_rp);
  224.       temp_rp.BitMap = temp_bm;
  225.  
  226.       CURRENTA5 = ChunkyBuf;  // Wird nicht mehr verändert
  227.       break;
  228.  
  229.     case SCRTYPE_4BIT:
  230.  
  231.       if (!Initc2p4())
  232.         return 2;
  233.  
  234.       // Speicher für Comparison Buffer holen
  235.       if (!(comparison_buf[0] = AllocVec(width * height, MEMF_PUBLIC | MEMF_CLEAR)))
  236.         return 2;
  237.  
  238.       // Farbpalette laden
  239.       for (i=0; i<16; i++)
  240.         SetRGB4(the_view_port, i,
  241.           palette_red[i & 0xf], palette_green[i & 0xf], palette_blue[i & 0xf]);
  242.  
  243.       CURRENTA5 = ChunkyBuf;
  244.  
  245.       open_double_buf(type, width, height);
  246.       must_wait_for_c2p4 = FALSE;
  247.       break;
  248.  
  249.     case SCRTYPE_1BIT:
  250.  
  251.       SetRGB4(the_view_port, 0, 0, 0, 0);        // schwarz
  252.       SetRGB4(the_view_port, 1, 15, 15, 15);    // weiß
  253.  
  254.       CURRENTA5 = the_rast_port->BitMap->Planes[0];
  255.  
  256.       open_double_buf(type, width, height);
  257.       break;
  258.   }
  259.  
  260.   return 0;
  261. }
  262.  
  263.  
  264. /*
  265.  *  Double Buffering einrichten
  266.  */
  267.  
  268. void open_double_buf(int type, int width, int height)
  269. {
  270.   using_db = FALSE;
  271.   if (IntuitionBase->lib_Version >= 39) {
  272.  
  273.     if (!(scr_buf[0] = AllocScreenBuffer(the_screen, NULL, SB_SCREEN_BITMAP)))
  274.       return;
  275.  
  276.     if (!(scr_buf[1] = AllocScreenBuffer(the_screen, NULL, SB_COPY_BITMAP)))
  277.       return;
  278.  
  279.     WaitTOF(); WaitTOF();
  280.     inv_buf_num = 1;
  281.  
  282.     if (type == SCRTYPE_4BIT) {
  283.       CURRENTA5 = ChunkyBuf;
  284.       if (!(comparison_buf[1] = AllocVec(width * height, MEMF_PUBLIC | MEMF_CLEAR)))
  285.         return;
  286.     } else {
  287.       CURRENTA5 = scr_buf[1]->sb_BitMap->Planes[0];
  288.     }
  289.  
  290.     using_db = TRUE;
  291.   }
  292. }
  293.  
  294.  
  295. /*
  296.  *  Screen und Fenster schließen
  297.  */
  298.  
  299. void CloseDisplay(void)
  300. {
  301.   int i;
  302.  
  303.   if (current_type == SCRTYPE_4BIT)
  304.     Exitc2p4();
  305.  
  306.   if (comparison_buf[0]) {
  307.     FreeVec(comparison_buf[0]);
  308.     comparison_buf[0] = NULL;
  309.   }
  310.  
  311.   if (comparison_buf[1]) {
  312.     FreeVec(comparison_buf[1]);
  313.     comparison_buf[1] = NULL;
  314.   }
  315.  
  316.   FreeScreenBuffer(the_screen, scr_buf[0]);  // NULL ist OK
  317.   scr_buf[0] = NULL;
  318.   FreeScreenBuffer(the_screen, scr_buf[1]);
  319.   scr_buf[1] = NULL;
  320.  
  321.   if (the_menus) {
  322.     ClearMenuStrip(the_window);
  323.     FreeMenus(the_menus);
  324.     the_menus = NULL;
  325.   }
  326.  
  327.   if (the_window) {
  328.     CloseWindow(the_window);
  329.     the_window = NULL;
  330.   }
  331.  
  332.   // Temporären RastPort schließen
  333.   if (temp_bm) {
  334.     if (has_gfx_39)
  335.       FreeBitMap(temp_bm);
  336.     else {
  337.       for (i=0; i<8; i++) {
  338.         FreeRaster(v37_temp_bm.Planes[i], current_width, current_height);
  339.         v37_temp_bm.Planes[i] = NULL;
  340.       }
  341.     }
  342.     temp_bm = NULL;
  343.   }
  344.  
  345.   if (the_visual_info) {
  346.     FreeVisualInfo(the_visual_info);
  347.     the_visual_info = NULL;
  348.   }
  349.  
  350.   if (topaz_font) {
  351.     CloseFont(topaz_font);
  352.     topaz_font = NULL;
  353.   }
  354.  
  355.   if (the_screen) {
  356.     CloseScreen(the_screen);
  357.     the_screen = NULL;
  358.   }
  359. }
  360.  
  361.  
  362. /*
  363.  *  Vom 6510-Task aus nötige Initialisierungen
  364.  *  Wird vom 6510-Task aufgerufen
  365.  */
  366.  
  367. void InitDisplayFrom6510(void)
  368. {
  369.   // Signal für c2p4
  370.   c2p4_signal = AllocSignal(-1);
  371.   c2p4_set = 1 << c2p4_signal;
  372.  
  373.   // TimerIO einrichten
  374.   if (timer_port = CreateMsgPort()) {
  375.     if (timer_io = CreateIORequest(timer_port, sizeof(struct timerequest))) {
  376.       OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timer_io, 0);
  377.  
  378.       // timer_io für Speed Limiter starten
  379.       timer_io->tr_node.io_Command = TR_ADDREQUEST;
  380.       timer_io->tr_time.tv_secs = 0;
  381.       timer_io->tr_time.tv_micro = SkipLatch * 20000;  // 20ms pro Bild
  382.       SendIO((struct IORequest *)timer_io);
  383.     }
  384.   }
  385. }
  386.  
  387.  
  388. /*
  389.  *  Vom 6510-Task aus nötige Aufräumarbeiten
  390.  *  Wird vom 6510-Task aufgerufen
  391.  */
  392.  
  393. void ExitDisplayFrom6510(void)
  394. {
  395.   if (timer_io) {
  396.     if (!CheckIO((struct IORequest *)timer_io))
  397.       WaitIO((struct IORequest *)timer_io);
  398.     CloseDevice((struct IORequest *)timer_io);
  399.     DeleteIORequest((struct IORequest *)timer_io);
  400.     timer_io = NULL;
  401.   }
  402.  
  403.   if (timer_port) {
  404.     DeleteMsgPort(timer_port);
  405.     timer_port = NULL;
  406.   }
  407.  
  408.   // Ggf. auf Signal von c2p4 warten
  409.   if (must_wait_for_c2p4)
  410.     Wait(c2p4_set);
  411.  
  412.   FreeSignal(c2p4_signal);
  413. }
  414.  
  415.  
  416. /*
  417.  *  C64-Grafik neu darstellen (VBlank, Double Buffering)
  418.  *  Wird vom 6510-Task aufgerufen
  419.  */
  420.  
  421. struct timeval start_time, end_time;
  422. char speed_str[20];
  423. int percent;
  424.  
  425. void RedrawDisplay(void)
  426. {
  427.   switch (current_type) {
  428.     // SCRTYPE_8BIT: WritePixelLine in 6569.asm
  429.  
  430.     case SCRTYPE_4BIT:        // Double Buffering und c2p-Konvertierung
  431.       if (must_wait_for_c2p4)
  432.         Wait(c2p4_set);
  433.  
  434.       if (using_db) {
  435.         while (!ChangeScreenBuffer(the_screen, scr_buf[inv_buf_num]))
  436.           WaitTOF();
  437.         inv_buf_num ^= 1;
  438.         c2p4(ChunkyBuf, comparison_buf[inv_buf_num], scr_buf[inv_buf_num]->sb_BitMap->Planes, CPUTask, c2p4_set);
  439.       } else
  440.         c2p4(ChunkyBuf, comparison_buf[0], the_rast_port->BitMap->Planes, CPUTask, c2p4_set);
  441.  
  442.       must_wait_for_c2p4 = TRUE;
  443.       CURRENTA5 = ChunkyBuf;
  444.       break;
  445.  
  446.     case SCRTYPE_1BIT:        // Double Buffering
  447.       if (using_db) {
  448.         while (!ChangeScreenBuffer(the_screen, scr_buf[inv_buf_num]))
  449.           WaitTOF();
  450.         inv_buf_num ^= 1;
  451.         CURRENTA5 = scr_buf[inv_buf_num]->sb_BitMap->Planes[0];
  452.       } else
  453.         CURRENTA5 = the_rast_port->BitMap->Planes[0];
  454.       break;
  455.   }
  456.  
  457.   if (timer_io) {
  458.     // timer_io abbrechen, wenn Speed Limiter aus ist
  459.     if (!LimitSpeed)
  460.       if (!CheckIO((struct IORequest *)timer_io))
  461.         AbortIO((struct IORequest *)timer_io);
  462.  
  463.     WaitIO((struct IORequest *)timer_io);
  464.  
  465.     // timer_io neu starten
  466.     timer_io->tr_node.io_Command = TR_ADDREQUEST;
  467.     timer_io->tr_time.tv_secs = 0;
  468.     timer_io->tr_time.tv_micro = SkipLatch * 20000;  // 20ms pro Bild
  469.     SendIO((struct IORequest *)timer_io);
  470.   }
  471.  
  472.   // Zeit seit letztem Aufruf ermitteln
  473.   GetSysTime(&end_time);
  474.   SubTime(&end_time, &start_time);
  475.   GetSysTime(&start_time);
  476.  
  477.   // Ein Bild sollte 20ms dauern
  478.   percent = (20000 * 100 / end_time.tv_micro + 1) * SkipLatch;
  479.  
  480.   RawDoFmt("%ld%%", &percent, &PutChProc, speed_str);
  481.   Move(the_rast_port, 4, current_height-6);
  482.   Text(the_rast_port, speed_str, strlen(speed_str));
  483. }
  484.  
  485.  
  486. /*
  487.  *  C64-Grafik nach hinten
  488.  */
  489.  
  490. void EmulToBack(void)
  491. {
  492.   ScreenToBack(the_screen);
  493.   ModifyIDCMP(the_window, IDCMP_RAWKEY);
  494.   ClearMenuStrip(the_window);
  495. }
  496.  
  497.  
  498. /*
  499.  *  C64-Grafik nach vorne
  500.  */
  501.  
  502. void EmulToFront(void)
  503. {
  504.   ScreenToFront(the_screen);
  505.   ModifyIDCMP(the_window, IDCMP_RAWKEY | IDCMP_MENUPICK | IDCMP_MENUVERIFY);
  506.   SetMenuStrip(the_window, the_menus);
  507. }
  508.  
  509.  
  510. /*
  511.  *  Event-Schleife des Fensters
  512.  */
  513.  
  514. void EventLoop(void)
  515. {
  516.   int done = FALSE;
  517.  
  518.   while (!done) {
  519.     WaitPort(the_window->UserPort);
  520.     done = handle_IDCMP(done);
  521.   }
  522. }
  523.  
  524.  
  525. /*
  526.  *  IDCMP-Messages handhaben
  527.  */
  528.  
  529. int handle_IDCMP(int done)
  530. {
  531.   struct IntuiMessage *msg;
  532.   ULONG class;
  533.   UWORD code;
  534.   UWORD menu_number;
  535.   struct MenuItem *item;
  536.  
  537.   while (!done && (msg = GetMsg(the_window->UserPort))) {
  538.     class = msg->Class;
  539.     code = msg->Code;
  540.  
  541.     if (class == IDCMP_MENUVERIFY)
  542.       Pause6510();    // Subtask stoppen
  543.  
  544.     ReplyMsg((struct Message *)msg);
  545.  
  546.     switch (class) {
  547.       case IDCMP_MENUPICK:
  548.         Resume6510();  // Subtask fortführen
  549.  
  550.         menu_number = code;
  551.         while (!done && (menu_number != MENUNULL)) {
  552.           item = ItemAddress(the_window->MenuStrip, menu_number);
  553.           done = handle_menu(MENUNUM(menu_number), ITEMNUM(menu_number), done);
  554.           menu_number = item->NextSelect;
  555.         }
  556.         break;
  557.  
  558.       case IDCMP_RAWKEY:
  559.         if (code == 0x58)    // F9 -> Einstellungen
  560.           handle_menu(0, 0, done);
  561.         else
  562.           KeyPressed(code);
  563.         break;
  564.     }
  565.   }
  566.  
  567.   return done;
  568. }
  569.  
  570.  
  571. /*
  572.  *  Menü wurde ausgewählt
  573.  */
  574.  
  575. int handle_menu(int menu, int item, int done)
  576. {
  577.   if (menu == 0) {
  578.     switch (item) {
  579.       case 0:        // Einstellungen
  580.         Pause6510();
  581.         PauseSound();
  582.         EmulToBack();
  583.         ShowPrefs();
  584.         EmulToFront();
  585.         ResumeSound();
  586.         Resume6510();
  587.         break;
  588.  
  589.       case 1:        // SAM
  590.         Pause6510();
  591.         PauseSound();
  592.         EmulToBack();
  593.         SAM();
  594.         EmulToFront();
  595.         ResumeSound();
  596.         Resume6510();
  597.         break;
  598.  
  599.       case 3:        // Quit
  600.         done = TRUE;
  601.         break;
  602.     }
  603.   }
  604.  
  605.   return done;
  606. }
  607.  
  608.  
  609. /*
  610.  *  Requester anzeigen
  611.  */
  612.  
  613. int ShowRequester(int text, int gads, APTR args)
  614. {
  615.   struct EasyStruct es;
  616.  
  617.   es.es_StructSize = sizeof(struct EasyStruct);
  618.   es.es_Flags = 0;
  619.   es.es_Title = GetStr(MSG_REQTITLE);
  620.   es.es_TextFormat = GetStr(text);
  621.   es.es_GadgetFormat = GetStr(gads);
  622.  
  623.   return EasyRequestArgs(NULL, &es, NULL, args);
  624. }
  625.  
  626.  
  627. /*
  628.  *  Lokalisierungen vornehmen
  629.  */
  630.  
  631. void LocalizeDisplay(void)
  632. {
  633.   int i;
  634.  
  635.   for (i=0; new_menus[i].nm_Type != NM_END; i++)
  636.     if (new_menus[i].nm_Label != NM_BARLABEL)
  637.       new_menus[i].nm_Label = GetStr((int)new_menus[i].nm_Label);
  638. }
  639.