home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #2 / amigaacscoverdisc1998-021998.iso / games / doom / adoom / src / amiga_video.c < prev    next >
C/C++ Source or Header  |  1998-01-08  |  33KB  |  1,025 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <time.h>
  5.  
  6. #include <exec/exec.h>
  7. #include <dos/dos.h>
  8. #include <graphics/gfx.h>
  9. #include <graphics/gfxbase.h>
  10. #include <graphics/gfxmacros.h>
  11. #include <intuition/intuition.h>
  12. #include <libraries/asl.h>
  13. #include <libraries/lowlevel.h>
  14. #include <cybergraphics/cybergraphics.h>
  15. #include <devices/gameport.h>
  16.  
  17. #include <proto/exec.h>
  18. #include <proto/dos.h>
  19. #include <proto/graphics.h>
  20. #include <proto/layers.h>
  21. #include <proto/intuition.h>
  22. #include <proto/asl.h>
  23. #include <proto/lowlevel.h>
  24. #include <proto/cybergraphics.h>
  25.  
  26. #include "doomtype.h"
  27. #include "doomdef.h"
  28. #include "doomstat.h"
  29. #include "i_system.h"
  30. #include "i_video.h"
  31. #include "v_video.h"
  32. #include "m_argv.h"
  33. #include "d_main.h"
  34.  
  35. #include "amiga_median.h"
  36. #include "c2p_020.h"
  37. #include "c2p_040.h"
  38.  
  39. /**********************************************************************/
  40. struct Library *AslBase = NULL;
  41. struct Library *CyberGfxBase = NULL;
  42. struct Library *LowLevelBase = NULL;
  43.  
  44. extern int cpu_type;
  45.  
  46. static struct ScreenModeRequester *video_smr = NULL;
  47. static struct Screen *video_screen = NULL;
  48. static struct Window *video_window = NULL;
  49. static struct BitMap video_bitmap[2] = {
  50.   {0, 0, 0, 0, 0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}},
  51.   {0, 0, 0, 0, 0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}}
  52. };
  53. static PLANEPTR video_raster[2] = {NULL, NULL};    /* contiguous bitplanes */
  54. static UBYTE *video_compare_buffer[2] = {NULL, NULL};    /* in fastmem */
  55. static struct ScreenBuffer *video_sb[2] = {NULL, NULL};
  56. static int video_which = 0;
  57. static BYTE video_sigbit1 = -1;
  58. static BYTE video_sigbit2 = -1;
  59. static volatile BYTE video_sigbit3 = -1;
  60. static struct Task *video_maintask;
  61. static struct Task *video_fliptask = NULL;
  62. static int video_depth = 0;
  63. static struct RastPort *video_rastport = NULL;
  64. static ULONG video_colourtable[1 + 3*256 + 1];
  65. static volatile WORD video_palette_changed = 0;
  66. static BOOL video_is_ehb_mode = FALSE;
  67. static BOOL video_is_native_mode = FALSE;
  68. static BOOL video_is_cyber_mode = FALSE;
  69. static BOOL video_is_using_blitter = FALSE;
  70. static BOOL video_blit_is_in_progress = FALSE;
  71. static struct RastPort video_temprp;
  72. static struct BitMap video_tmp_bm = {
  73.   0, 0, 0, 0, 0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
  74. };
  75. static UBYTE video_xlate[256];   /* xlate colour from 8-bit to 6-bit EHB */
  76. static UWORD __chip emptypointer[] = {
  77.   0x0000, 0x0000,    /* reserved, must be NULL */
  78.   0x0000, 0x0000,     /* 1 row of image data */
  79.   0x0000, 0x0000    /* reserved, must be NULL */
  80. };
  81.  
  82. /* gameport stuff */
  83. static struct MsgPort *gameport_mp = NULL;
  84. static struct IOStdReq *gameport_io = NULL;
  85. static BOOL gameport_is_open = FALSE;
  86. static BOOL gameport_io_in_progress = FALSE;
  87. static struct InputEvent gameport_ie;
  88. static BYTE gameport_ct;        /* controller type */
  89. struct GamePortTrigger gameport_gpt = {
  90.   GPTF_UPKEYS | GPTF_DOWNKEYS,    /* gpt_Keys */
  91.   0,                /* gpt_Timeout */
  92.   1,                /* gpt_XDelta */
  93.   1                /* gpt_YDelta */
  94. };
  95.  
  96. static unsigned int start_time[2];
  97. static unsigned int blit_time = 0;
  98. static unsigned int safe_time = 0;
  99. static unsigned int c2p_time = 0;
  100. static unsigned int wpa8_time = 0;
  101. static unsigned int total_frames = 0;
  102.  
  103. /****************************************************************************/
  104. static __inline void start_timer (void)
  105. {
  106.   timer (start_time);
  107. }
  108.  
  109. /****************************************************************************/
  110. static __inline unsigned int end_timer (void)
  111. {
  112.   unsigned int end_time[2];
  113.  
  114.   timer (end_time);
  115.   if (end_time[1] >= start_time[1])
  116.     return end_time[1] - start_time[1] + 50;
  117.   else
  118.     return end_time[1] + 1000000 - start_time[1];
  119. }
  120.  
  121. /****************************************************************************/
  122.  
  123. static char *mode_name (ULONG mode)
  124. /* Return a mode name for given mode, compatible with ASL mode requester */
  125. /* Use name in DisplayInfo database if available */
  126. /* else manually construct the name */
  127. {
  128.   APTR handle;
  129.   char *p;
  130.   struct NameInfo nameinfo;
  131.   struct DimensionInfo dimsinfo;
  132.   static char modename[DISPLAYNAMELEN + 4 + 4 + 11 + 1];
  133.  
  134.   p = modename;
  135.   *p = '\0';
  136.   if ((handle = FindDisplayInfo (mode & ~SPRITES)) != NULL) {
  137.     if (GetDisplayInfoData (handle, (UBYTE *)&nameinfo,
  138.                             sizeof(nameinfo), DTAG_NAME,
  139.                             NULL) > sizeof(struct QueryHeader)) {
  140.       p += sprintf (p, "%s", nameinfo.Name);
  141.     } else if (GetDisplayInfoData (handle, (UBYTE *)&dimsinfo,
  142.                                    sizeof(dimsinfo), DTAG_DIMS,
  143.                                    NULL) >= 66 /* sizeof(dimsinfo)*/) {
  144.       switch (mode & MONITOR_ID_MASK) {
  145.         case DEFAULT_MONITOR_ID:
  146.           p += sprintf (p, "DEFAULT:");      /* PAL or NTSC??? */
  147.           break;
  148.         case NTSC_MONITOR_ID:
  149.           p += sprintf (p, "NTSC:");
  150.           break;
  151.         case PAL_MONITOR_ID:
  152.           p += sprintf (p, "PAL:");
  153.           break;
  154.         case VGA_MONITOR_ID:
  155.           p += sprintf (p, "MULTISCAN:");
  156.           break;
  157.         case A2024_MONITOR_ID:
  158.           p += sprintf (p, "A2024:");
  159.           break;
  160.         case PROTO_MONITOR_ID:
  161.           p += sprintf (p, "PROTO:");
  162.           break;
  163.         case EURO72_MONITOR_ID:
  164.           p += sprintf (p, "EURO72:");
  165.           break;
  166.         case EURO36_MONITOR_ID:
  167.           p += sprintf (p, "EURO36:");
  168.           break;
  169.         case SUPER72_MONITOR_ID:
  170.           p += sprintf (p, "SUPER72:");
  171.           break;
  172.         case DBLNTSC_MONITOR_ID:
  173.           p += sprintf (p, "DBLNTSC:");
  174.           break;
  175.         case DBLPAL_MONITOR_ID:
  176.           p += sprintf (p, "DBLPAL:");
  177.           break;
  178.         default:
  179.           p += sprintf (p, "(unknown):");
  180.           break;
  181.       }
  182.       p += sprintf (p, "%d x %d",
  183.                     dimsinfo.Nominal.MaxX - dimsinfo.Nominal.MinX + 1,
  184.                     dimsinfo.Nominal.MaxY - dimsinfo.Nominal.MinY + 1);
  185.       if ((mode & HAM_KEY) != 0)
  186.         p += sprintf (p, " HAM");
  187.       if ((mode & EXTRAHALFBRITE_KEY) != 0)
  188.         p += sprintf (p, " EHB");
  189.       if ((mode & LACE) != 0)
  190.         p += sprintf (p, " Interlaced");
  191.     } else {
  192.       p += sprintf (p, "%s", "(unnamed)");
  193.       if ((mode & HAM_KEY) != 0)
  194.         p += sprintf (p, " HAM");
  195.       if ((mode & EXTRAHALFBRITE_KEY) != 0)
  196.         p += sprintf (p, " EHB");
  197.       if ((mode & LACE) != 0)
  198.         p += sprintf (p, " Interlaced");
  199.     }
  200.   } else {
  201.     p += sprintf (p, "%s", "(unavailable)");
  202.   }
  203.   return (modename);
  204. }
  205.  
  206. /****************************************************************************/
  207.  
  208. static ULONG parse_mode (char *modename)
  209. /* Modename may be descriptive name ("PAL Lores"), or hex ("$00420001" or */
  210. /* "0x12345678") or decimal ("32768"). */
  211. {
  212.   ULONG mode, reason;
  213.  
  214.   mode = INVALID_ID;
  215.   if (modename != NULL) {
  216.     if (modename[0] == '0' && modename[1] == 'x') {
  217.       if (sscanf (&modename[2], "%lx", &mode) != 1)
  218.         mode = INVALID_ID;
  219.     } else if (modename[0] == '$') {
  220.       if (sscanf (&modename[1], "%lx", &mode) != 1)
  221.         mode = INVALID_ID;
  222.     } else if (modename[0] >= '0' && modename[0] <= '9') {
  223.       if (sscanf (modename, "%ld", &mode) != 1)
  224.         mode = INVALID_ID;
  225.     } else {
  226.       while ((mode = NextDisplayInfo (mode)) != INVALID_ID) {
  227.         if ((mode & LORESDPF_KEY) == 0) {
  228.           /* printf ("$%08x  \"%s\"\n", mode, mode_name (mode)); */
  229.           if (strcmp (mode_name (mode), modename) == 0)
  230.             break;
  231.         }
  232.       }
  233.     }
  234.   }
  235.   if (FindDisplayInfo (mode) == NULL)
  236.     I_Error ("ScreenMode not in database: \"%s\"", modename);
  237.   if ((reason = ModeNotAvailable (mode)) != 0)
  238.     I_Error ("Mode $%08x is not available: %ld", mode, reason);
  239.   return (mode);
  240. }
  241.  
  242. /**********************************************************************/
  243. // This asynchronous task waits in a loop for sigbit3 signals.
  244. // Sigbit3 is signalled when the next frame is just finished.
  245. // Sigbit3 may be signalled from the qblit() cleanup function or from the
  246. // main task.
  247. // On receipt of sigbit3, we load the new palette and call ChangeScreenBuffer().
  248. // This way there is no delay calling ChangeScreenBuffer() after the last blit
  249. // has finished.
  250. // The main 3D rendering task may be interrupted to call ChangeScreenBuffer()
  251. // SIGBREAKF_CTRL_F and SIGBREAKF_CTRL_C are used for synchronisation
  252. // with the main task.
  253.  
  254. static void __saveds __interrupt video_flipscreentask (void)
  255. {
  256.   ULONG sig;
  257.   struct MsgPort *video_dispport, *video_safeport;
  258.   BOOL going, video_disp, video_safe;
  259.   int i;
  260.  
  261.   video_sigbit3 = AllocSignal(-1);
  262.   Signal (video_maintask, SIGBREAKF_CTRL_F);
  263.   video_dispport = CreatePort (NULL, 0);
  264.   video_safeport = CreatePort (NULL, 0);
  265.   video_disp = TRUE;
  266.   video_safe = TRUE;
  267.   for (i = 0; i < 2; i++) {
  268.     video_sb[i]->sb_DBufInfo->dbi_DispMessage.mn_ReplyPort = video_dispport;
  269.     video_sb[i]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = video_safeport;
  270.   }
  271.   going = (video_sigbit3 != -1) &&
  272.           (video_dispport != NULL) &&
  273.           (video_safeport != NULL);
  274.   while (going) {
  275.     sig = Wait (1 << video_sigbit3 | SIGBREAKF_CTRL_C);
  276.     if ((sig & (1 << video_sigbit3)) != 0) {
  277.       if (!video_disp) {  /* wait for previous frame to be displayed */
  278.         Wait (1 << video_dispport->mp_SigBit);
  279.         while (GetMsg (video_dispport) != NULL) /* clear message queue */
  280.           /* do nothing */ ;
  281.         video_disp = TRUE;
  282.       }
  283.       LoadRGB32 (&video_screen->ViewPort, video_colourtable);
  284.       if ((ChangeScreenBuffer (video_screen, video_sb[video_which])) != 0) {
  285.         video_disp = FALSE;
  286.         video_safe = FALSE;
  287.       }
  288.       if (!video_safe) {  /* wait until safe */
  289.         Wait (1 << video_safeport->mp_SigBit);
  290.         while (GetMsg (video_safeport) != NULL) /* clear message queue */
  291.           /* do nothing */ ;
  292.         video_safe = TRUE;
  293.       }
  294.       Signal (video_maintask, SIGBREAKF_CTRL_F);
  295.     }
  296.     if ((sig & SIGBREAKF_CTRL_C) != 0) {
  297.       going = FALSE;
  298.     }
  299.   }
  300.   if (!video_safe) {  /* wait for safe */
  301.     Wait (1 << video_safeport->mp_SigBit);
  302.     while (GetMsg (video_safeport) != NULL) /* clear message queue */
  303.       /* do nothing */ ;
  304.     video_safe = TRUE;
  305.   }
  306.   if (!video_disp) {  /* wait for last frame to be displayed */
  307.     Wait (1 << video_dispport->mp_SigBit);
  308.     while (GetMsg (video_dispport) != NULL) /* clear message queue */
  309.       /* do nothing */ ;
  310.     video_disp = TRUE;
  311.   }
  312.   if (video_sigbit3 != -1)
  313.     FreeSignal (video_sigbit3);
  314.   if (video_dispport != NULL)
  315.     DeletePort (video_dispport);
  316.   if (video_safeport != NULL)
  317.     DeletePort (video_safeport);
  318.   Signal (video_maintask, SIGBREAKF_CTRL_F);
  319.   Wait (0);
  320. }
  321.  
  322. /**********************************************************************/
  323. // Called by D_DoomMain,
  324. // determines the hardware configuration
  325. // and sets up the video mode
  326. void I_InitGraphics (void)
  327. {
  328.   int i;
  329.   ULONG propertymask, idcmp, wflags;
  330.   struct Rectangle rect;
  331.   char reqtitle[32];
  332.   int mode, depth, nbytes, p;
  333.   DisplayInfoHandle handle;
  334.   struct DisplayInfo dispinfo;
  335.  
  336.   video_maintask = FindTask(NULL);
  337.  
  338.   if (AslBase == NULL) {
  339.     if ((AslBase = OpenLibrary ("asl.library", 37L)) == NULL ||
  340.         (video_smr = AllocAslRequestTags (ASL_ScreenModeRequest, TAG_DONE)) == NULL) {
  341.       I_Error ("OpenLibrary(""asl.library"", 37) failed");
  342.     }
  343.   }
  344.  
  345.   /* first check tooltypes for SCREENMODE */
  346.   mode = -1;
  347.   p = M_CheckParm ("-screenmode");
  348.   if (p && p < myargc - 1) {
  349.     mode = parse_mode (myargv[p+1]);
  350.   }
  351.  
  352.   /* if not found in icon tooltypes, then put up a ScreenMode requester */
  353.   if (mode == -1) {
  354.     propertymask = /* DIPF_IS_EXTRAHALFBRITE | */ DIPF_IS_DUALPF |
  355.                    DIPF_IS_PF2PRI | DIPF_IS_HAM;
  356.     if (GfxBase->LibNode.lib_Version >= 39)
  357.       mode = BestModeID (BIDTAG_NominalWidth,     SCREENWIDTH,
  358.                          BIDTAG_NominalHeight,    SCREENHEIGHT,
  359.                          BIDTAG_Depth,            video_depth,
  360.                          BIDTAG_DIPFMustNotHave,  propertymask,
  361.                          TAG_DONE);
  362.     else
  363.       mode = EXTRAHALFBRITE_KEY;
  364.     if (AslBase->lib_Version >= 38) {
  365.       sprintf (reqtitle, "ADoom %dx%d", SCREENWIDTH, SCREENHEIGHT);
  366.       if (!AslRequestTags (video_smr,
  367.                            ASLSM_TitleText,        (ULONG)reqtitle,
  368.                            ASLSM_InitialDisplayID, mode,
  369.                            ASLSM_MinWidth,         SCREENWIDTH,
  370.                            ASLSM_MinHeight,        SCREENHEIGHT,
  371.                            ASLSM_MinDepth,         6,
  372.                            ASLSM_MaxDepth,         8,
  373.                            ASLSM_PropertyMask,     propertymask,
  374.                            ASLSM_PropertyFlags,    0,
  375.                            TAG_DONE)) {
  376.         I_Error ("AslRequest() failed");
  377.       }
  378.       mode = video_smr->sm_DisplayID;
  379.     }
  380.   }
  381.  
  382.   if ((handle = FindDisplayInfo (mode)) == NULL) {
  383.     I_Error ("Can't FindDisplayInfo() for mode %08x", mode);
  384.   }
  385.   if ((nbytes = GetDisplayInfoData (handle, (UBYTE *)&dispinfo,
  386.                                     sizeof(struct DisplayInfo), DTAG_DISP,
  387.                                     NULL)) < 40 /*sizeof(struct DisplayInfo)*/) {
  388.     I_Error ("Can't GetDisplayInfoData() for mode %08x, got %d bytes",
  389.              mode, nbytes);
  390.   }
  391.  
  392.   video_is_cyber_mode = 0;
  393.   if ((CyberGfxBase = OpenLibrary ("cybergraphics.library", 0)) != NULL) {
  394.     video_is_cyber_mode = IsCyberModeID (mode);
  395.     CloseLibrary (CyberGfxBase);
  396.   }
  397.  
  398.   /* this test needs improving */
  399.   video_is_native_mode = ((GfxBase->LibNode.lib_Version < 39 ||
  400.                            (dispinfo.PropertyFlags & DIPF_IS_EXTRAHALFBRITE) != 0 ||
  401.                            (dispinfo.PropertyFlags & DIPF_IS_AA) != 0 ||
  402.                            (dispinfo.PropertyFlags & DIPF_IS_ECS) != 0 ||
  403.                            (dispinfo.PropertyFlags & DIPF_IS_DBUFFER) != 0) &&
  404.                           !video_is_cyber_mode &&
  405.                           (dispinfo.PropertyFlags & DIPF_IS_FOREIGN) == 0);
  406.  
  407.   video_is_ehb_mode = ((dispinfo.PropertyFlags & DIPF_IS_EXTRAHALFBRITE) != 0);
  408.  
  409.   printf ("Screen Mode $%08x is ", mode);
  410.   if (video_is_native_mode)
  411.     printf (" NATIVE-PLANAR");
  412.   else
  413.     printf (" FOREIGN");
  414.   if (video_is_ehb_mode)
  415.     printf (" EXTRAHALFBRITE");
  416.   else
  417.     printf (" 8-BIT");
  418.   if (video_is_cyber_mode)
  419.     printf (" CYBERGRAPHX");
  420.   printf ("\n");
  421.  
  422.   if (video_is_ehb_mode)
  423.     video_depth = 6;
  424.   else
  425.     video_depth = 8;
  426.  
  427.   rect.MinX = 0;
  428.   rect.MinY = 0;
  429.   rect.MaxX = SCREENWIDTH - 1;
  430.   rect.MaxY = SCREENHEIGHT - 1;
  431.  
  432.   if (video_is_native_mode) {
  433.     for (i = 0; i < 2; i++) {
  434.       if ((video_raster[i] = (PLANEPTR)AllocRaster (SCREENWIDTH,
  435.                                            video_depth * SCREENHEIGHT)) == NULL)
  436.         I_Error ("AllocRaster() failed");
  437.       memset (video_raster[i], 0, video_depth * RASSIZE (SCREENWIDTH, SCREENHEIGHT));
  438.       InitBitMap (&video_bitmap[i], video_depth, SCREENWIDTH, SCREENHEIGHT);
  439.       for (depth = 0; depth < video_depth; depth++)
  440.         video_bitmap[i].Planes[depth] = video_raster[i] +
  441.                                     depth * RASSIZE (SCREENWIDTH, SCREENHEIGHT);
  442.     }
  443.     if ((video_screen = OpenScreenTags (NULL,
  444.           SA_Type,        CUSTOMSCREEN | CUSTOMBITMAP,
  445.           SA_DisplayID,   mode,
  446.           SA_DClip,       (ULONG)&rect,
  447.           SA_Width,       SCREENWIDTH,
  448.           SA_Height,      SCREENHEIGHT,
  449.           SA_Depth,       video_depth,
  450.           /* SA_Draggable,FALSE, */
  451.           /* SA_AutoScroll,FALSE, */
  452.           /* SA_Exclusive,TRUE, */
  453.           SA_Quiet,       TRUE,
  454.           SA_BitMap,      &video_bitmap[0], /* custom bitmap, contiguous planes */
  455.           TAG_DONE)) == NULL) {
  456.       I_Error ("OpenScreen() failed");
  457.     }
  458.     for (i = 0; i < 2; i++) {
  459.       if ((video_compare_buffer[i] = malloc (SCREENWIDTH * SCREENHEIGHT)) == NULL)
  460.         I_Error ("Out of memory allocating %d bytes", SCREENWIDTH * SCREENHEIGHT);
  461.       memset (video_compare_buffer[i], 0, SCREENWIDTH * SCREENHEIGHT);
  462.     }
  463.     for (i = 0; i < 2; i++) {
  464.       if ((video_sb[i] = AllocScreenBuffer (video_screen, &video_bitmap[i], 0)) == NULL)
  465.         I_Error ("Can't allocate structure for double buffering");
  466.     }
  467.   } else {
  468.     if ((video_screen = OpenScreenTags (NULL,
  469.           SA_Type,        CUSTOMSCREEN,
  470.           SA_DisplayID,   mode,
  471.           SA_DClip,       (ULONG)&rect,
  472.           SA_Width,       SCREENWIDTH,
  473.           SA_Height,      SCREENHEIGHT,
  474.           SA_Depth,       video_depth,
  475.           /* SA_Draggable,FALSE, */
  476.           /* SA_AutoScroll,FALSE, */
  477.           /* SA_Exclusive,TRUE, */
  478.           SA_Quiet,       TRUE,
  479.           TAG_DONE)) == NULL) {
  480.       I_Error ("OpenScreen() failed");
  481.     }
  482.   }
  483.  
  484.   idcmp = IDCMP_RAWKEY;
  485.   wflags = WFLG_ACTIVATE | WFLG_BORDERLESS | WFLG_RMBTRAP;
  486.   if (M_CheckParm("-mouse") != NULL) {
  487.     idcmp |= IDCMP_MOUSEMOVE | IDCMP_DELTAMOVE | IDCMP_MOUSEBUTTONS;
  488.     wflags |= WFLG_REPORTMOUSE;
  489.   }
  490.  
  491.   if ((video_window = OpenWindowTags (NULL,
  492.         WA_Left,         0,
  493.         WA_Top,          0,
  494.         WA_Width,        SCREENWIDTH,
  495.         WA_Height,       SCREENHEIGHT,
  496.         WA_IDCMP,        idcmp,
  497.         WA_Flags,        wflags,
  498.         WA_CustomScreen, video_screen,
  499.         TAG_DONE)) == NULL) {
  500.     I_Error ("OpenWindow() failed");
  501.   }
  502.   video_rastport = video_window->RPort;
  503.  
  504.   InitBitMap (&video_tmp_bm, video_depth, SCREENWIDTH, 1);
  505.   for (depth = 0; depth < video_depth; depth++)
  506.     if ((video_tmp_bm.Planes[depth] = (PLANEPTR)AllocRaster (SCREENWIDTH, 1)) == NULL)
  507.       I_Error ("AllocRaster() failed");
  508.   video_temprp = *video_rastport;
  509.   video_temprp.Layer = NULL;
  510.   video_temprp.BitMap = &video_tmp_bm;
  511.  
  512.   SetPointer (video_window, emptypointer, 1, 16, 0, 0);
  513.  
  514.   if (video_is_native_mode) {
  515.     video_is_using_blitter = (cpu_type < 68040);
  516.     if ((video_sigbit1 = AllocSignal(-1)) == -1 ||
  517.         (video_sigbit2 = AllocSignal(-1)) == -1)
  518.       I_Error ("Can't allocate signal!\n");
  519.     Signal (video_maintask, (1 << video_sigbit1) | (1 << video_sigbit2));
  520.                                                  /* initial state is finished */
  521.     if ((video_fliptask = CreateTask ("ADoom_flipscreen", 5,
  522.                                       video_flipscreentask, 4096)) == NULL)
  523.       I_Error ("Can't create subtask");
  524.     Wait (SIGBREAKF_CTRL_F);
  525.     if (video_sigbit3 == -1)
  526.       I_Error ("Subtask couldn't allocate sigbit");
  527.   }
  528.  
  529.   /* joystick initialisation */
  530.  
  531.   if (M_CheckParm ("-joypad") != NULL) {
  532.  
  533.     if ((LowLevelBase = OpenLibrary ("lowlevel.library", 0)) == NULL)
  534.       I_Error ("-joypad option specified and can't open lowlevel.library");
  535.  
  536.   } else {
  537.  
  538.     if ((gameport_mp = CreatePort (NULL, 0)) == NULL ||
  539.         (gameport_io = (struct IOStdReq *)CreateExtIO (gameport_mp,
  540.                                               sizeof(struct IOStdReq))) == NULL ||
  541.         OpenDevice ("gameport.device", 1, (struct IORequest *)gameport_io, 0) != 0)
  542.       I_Error ("Can't open gameport.device");
  543.  
  544.     gameport_is_open = TRUE;
  545.  
  546.     Forbid ();
  547.  
  548.     gameport_io->io_Command = GPD_ASKCTYPE;
  549.     gameport_io->io_Length = 1;
  550.     gameport_io->io_Data = &gameport_ct;
  551.     DoIO ((struct IORequest *)gameport_io);
  552.  
  553.     if (gameport_ct != GPCT_NOCONTROLLER) {
  554.  
  555.       Permit ();
  556.       fprintf (stderr, "Another task is using the gameport!  Joystick disabled");
  557.       CloseDevice ((struct IORequest *)gameport_io);
  558.       gameport_is_open = FALSE;
  559.  
  560.     } else {
  561.  
  562.       gameport_ct = GPCT_ABSJOYSTICK;
  563.       gameport_io->io_Command = GPD_SETCTYPE;
  564.       gameport_io->io_Length = 1;
  565.       gameport_io->io_Data = &gameport_ct;
  566.       DoIO ((struct IORequest *)gameport_io);
  567.  
  568.       Permit ();
  569.  
  570.       gameport_io->io_Command = GPD_SETTRIGGER;
  571.       gameport_io->io_Length = sizeof(struct GamePortTrigger);
  572.       gameport_io->io_Data = &gameport_gpt;
  573.       DoIO ((struct IORequest *)gameport_io);
  574.  
  575.       gameport_io->io_Command = GPD_READEVENT;
  576.       gameport_io->io_Length = sizeof (struct InputEvent);
  577.       gameport_io->io_Data = &gameport_ie;
  578.       SendIO ((struct IORequest *)gameport_io);
  579.       gameport_io_in_progress = TRUE;
  580.     }
  581.   }
  582. }
  583.  
  584. /**********************************************************************/
  585. void I_ShutdownGraphics (void)
  586. {
  587.   int depth, i;
  588.  
  589.   if (LowLevelBase != NULL) {
  590.     CloseLibrary (LowLevelBase);
  591.     LowLevelBase = NULL;
  592.   }
  593.   if (gameport_io_in_progress) {
  594.     AbortIO ((struct IORequest *)gameport_io);
  595.     WaitIO ((struct IORequest *)gameport_io);
  596.     gameport_io_in_progress = FALSE;
  597.     gameport_ct = GPCT_NOCONTROLLER;
  598.     gameport_io->io_Command = GPD_SETCTYPE;
  599.     gameport_io->io_Length = 1;
  600.     gameport_io->io_Data = &gameport_ct;
  601.     DoIO ((struct IORequest *)gameport_io);
  602.   }
  603.   if (gameport_is_open) {
  604.     CloseDevice ((struct IORequest *)gameport_io);
  605.     gameport_is_open = FALSE;
  606.   }
  607.   if (gameport_io != NULL) {
  608.     DeleteExtIO ((struct IORequest *)gameport_io);
  609.     gameport_io = NULL;
  610.   }
  611.   if (gameport_mp != NULL) {
  612.     DeletePort (gameport_mp);
  613.     gameport_mp = NULL;
  614.   }
  615.   if (video_blit_is_in_progress) {
  616.     Wait (SIGBREAKF_CTRL_F);
  617.     video_blit_is_in_progress = FALSE;
  618.   }
  619.   if (video_fliptask != NULL) {
  620.     Signal (video_fliptask, SIGBREAKF_CTRL_C);
  621.     Wait (SIGBREAKF_CTRL_F);
  622.     DeleteTask (video_fliptask);
  623.     video_fliptask = NULL;
  624.   }
  625.   if (video_sigbit1 != -1) {
  626.     Wait (1 << video_sigbit1);  // wait for last c2p8 to finish pass 3
  627.     FreeSignal (video_sigbit1);
  628.     video_sigbit1 = -1;
  629.   }
  630.   if (video_sigbit2 != -1) {
  631.     Wait (1 << video_sigbit2);  // wait for last c2p8 to completely finish
  632.     FreeSignal (video_sigbit2);
  633.     video_sigbit2 = -1;
  634.   }
  635.   if (video_window != NULL) {
  636.     ClearPointer (video_window);
  637.     CloseWindow (video_window);
  638.     video_window = NULL;
  639.   }
  640.   for (i = 0; i < 2; i++) {
  641.     if (video_sb[i] != NULL) {
  642.       FreeScreenBuffer (video_screen, video_sb[i]);
  643.       video_sb[i] = NULL;
  644.     }
  645.   }
  646.   if (video_screen != NULL) {
  647.     CloseScreen (video_screen);
  648.     video_screen = NULL;
  649.   }
  650.   for (depth = 0; depth < video_depth; depth++) {
  651.     if (video_tmp_bm.Planes[depth] != NULL) {
  652.       FreeRaster (video_tmp_bm.Planes[depth], SCREENWIDTH, 1);
  653.       video_tmp_bm.Planes[depth] = NULL;
  654.     }
  655.   }
  656.   for (i = 0; i < 2; i++) {
  657.     if (video_raster[i] != NULL) {
  658.       FreeRaster (video_raster[i], SCREENWIDTH, video_depth * SCREENHEIGHT);
  659.       video_raster[i] = NULL;
  660.     }
  661.     if (video_compare_buffer[i] != NULL) {
  662.       free (video_compare_buffer[i]);
  663.       video_compare_buffer[i] = NULL;
  664.     }
  665.   }
  666. }
  667.  
  668. /**********************************************************************/
  669. // Takes full 8 bit values.
  670. void I_SetPalette (byte *palette)
  671. {
  672.   int i;
  673.   ULONG c, *p;
  674.   UBYTE *g;
  675.   static UBYTE gpalette[3*256];
  676.  
  677.   /* printf ("I_SetPalette()\n"); */
  678.   if (video_is_ehb_mode) {
  679.     g = gpalette;
  680.     for (i = 0; i < 256; i++) {
  681.       *g++ = gammatable[usegamma][*palette++];
  682.       *g++ = gammatable[usegamma][*palette++];
  683.       *g++ = gammatable[usegamma][*palette++];
  684.     }
  685.     video_colourtable[0] = (32 << 16) + 0;
  686.     median_cut (gpalette, &video_colourtable[1], video_xlate);
  687.     video_colourtable[33] = 0;
  688.   } else {
  689.     p = video_colourtable;
  690.     *p++ = (256 << 16) + 0;
  691.     for (i = 0; i < 256; i++) {
  692.       c = (ULONG)gammatable[usegamma][*palette++];
  693.       c += (c<<8);
  694.       c += (c<<16);
  695.       *p++ = c;
  696.       c = (ULONG)gammatable[usegamma][*palette++];
  697.       c += (c<<8);
  698.       c += (c<<16);
  699.       *p++ = c;
  700.       c = (ULONG)gammatable[usegamma][*palette++];
  701.       c += (c<<8);
  702.       c += (c<<16);
  703.       *p++ = c;
  704.     }
  705.     *p++ = 0;
  706.   }
  707.   if (video_palette_changed == 0 || !video_is_using_blitter)
  708.     video_palette_changed = 2;
  709. }
  710.  
  711. /**********************************************************************/
  712. void I_UpdateNoBlit (void)
  713. {
  714. }
  715.  
  716. /**********************************************************************/
  717. void I_FinishUpdate (void)
  718. /* This needs optimising to copy just the parts that changed,
  719.    especially if the user has shrunk the playscreen. */
  720. {
  721.   total_frames++;
  722.   if (video_is_native_mode) {
  723.     start_timer();
  724.     Wait (1 << video_sigbit1); /* wait for prev c2p() to finish pass 3 */
  725.     blit_time += end_timer();
  726.     if (video_blit_is_in_progress) {
  727.       start_timer();
  728.       Wait (SIGBREAKF_CTRL_F); /* wait for prev ChangeScreenBuffer() safe */
  729.       safe_time += end_timer();
  730.       video_blit_is_in_progress = FALSE;
  731.     }
  732.     video_which = 1 - video_which;  /* render to the hidden bitmap */
  733.     start_timer();
  734.     if (video_is_using_blitter) {
  735.       if (video_is_ehb_mode) {
  736.         c2p_6_020 (screens[0],
  737.                    video_bitmap[video_which].Planes,
  738.                    1 << video_sigbit1, 1 << video_sigbit2, 1 << video_sigbit3,
  739.                    SCREENWIDTH * SCREENHEIGHT, 0, video_xlate, video_fliptask);
  740.       } else {
  741.         c2p_8_020 (screens[0],
  742.                    video_bitmap[video_which].Planes,
  743.                    1 << video_sigbit1, 1 << video_sigbit2, 1 << video_sigbit3,
  744.                    SCREENWIDTH * SCREENHEIGHT, 0, video_fliptask);
  745.       }
  746.       video_blit_is_in_progress = TRUE;
  747.     } else {
  748.       if (video_is_ehb_mode) {
  749.         c2p_6_040 (screens[0], video_raster[video_which],
  750.                    video_compare_buffer[video_which], video_xlate,
  751.                    (SCREENWIDTH * SCREENHEIGHT) >> 3,
  752.                    video_palette_changed);
  753.       } else {
  754.         c2p_8_040 (screens[0], video_raster[video_which],
  755.                    video_compare_buffer[video_which],
  756.                    (SCREENWIDTH * SCREENHEIGHT) >> 3);
  757.       }
  758.       video_blit_is_in_progress = TRUE;
  759.       Signal (video_maintask, 1 << video_sigbit1); /* simulate c2p() pass 3 */
  760.       Signal (video_fliptask, 1 << video_sigbit3); /* start ChangeScreenBuffer() */
  761.     }
  762.     c2p_time += end_timer();
  763.     if (video_palette_changed > 0)
  764.       video_palette_changed--;/* keep it set for 2 frames for doublebuffering */
  765.   } else {
  766.     if (video_palette_changed != 0)
  767.       LoadRGB32 (&video_screen->ViewPort, video_colourtable);
  768.     start_timer();
  769.     WritePixelArray8 (video_rastport, 0, 0, SCREENWIDTH-1, SCREENHEIGHT-1,
  770.                       screens[0], &video_temprp);
  771.     wpa8_time += end_timer();
  772.     video_palette_changed = 0;
  773.   }
  774. }
  775.  
  776. /**********************************************************************/
  777. // Wait for vertical retrace or pause a bit.  Use when quit game.
  778. void I_WaitVBL(int count)
  779. {
  780.   for ( ; count > 0; count--)
  781.     WaitTOF();
  782. }
  783.  
  784. /**********************************************************************/
  785. void I_ReadScreen (byte* scr)
  786. {
  787.   memcpy (scr, screens[0], SCREENWIDTH * SCREENHEIGHT);
  788. }
  789.  
  790. /**********************************************************************/
  791. void I_BeginRead (void)
  792. {
  793. }
  794.  
  795. /**********************************************************************/
  796. void I_EndRead (void)
  797. {
  798. }
  799.  
  800. /**********************************************************************/
  801. void amiga_getevents (void)
  802. {
  803.   event_t event;
  804.   ULONG class;
  805.   UWORD code;
  806.   WORD mousex, mousey;
  807.   struct IntuiMessage *msg;
  808.   static ULONG previous = 0;
  809.   static int xlate[0x68] = {
  810.     '`', '1', '2', '3', '4', '5', '6', '7',
  811.     '8', '9', '0', KEY_MINUS, KEY_EQUALS, '\\', 0, '0',
  812.     'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
  813.     'o', 'p', KEY_F11, KEY_F12, 0, '0', '2', '3',
  814.     'a', 's', 'd', 'f', 'g', 'h', 'j', 'k',
  815.     'l', ';', '\'', KEY_ENTER, 0, '4', '5', '6',
  816.     KEY_RSHIFT, 'z', 'x', 'c', 'v', 'b', 'n', 'm',
  817.     ',', '.', '/', 0, '.', '7', '8', '9',
  818.     ' ', KEY_BACKSPACE, KEY_TAB, KEY_ENTER, KEY_ENTER, KEY_ESCAPE, KEY_BACKSPACE,
  819.     0, 0, 0, KEY_MINUS, 0, KEY_UPARROW, KEY_DOWNARROW, KEY_RIGHTARROW, KEY_LEFTARROW,
  820.     KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8,
  821.     KEY_F9, KEY_F10, '(', ')', '/', '*', KEY_EQUALS, KEY_PAUSE,
  822.     KEY_RSHIFT, KEY_RSHIFT, 0, KEY_RCTRL, KEY_LALT, KEY_RALT, KEY_LALT, KEY_RALT
  823.   };
  824.   static event_t joyevent = {0}, mouseevent = {0};
  825.  
  826.   if (video_window != NULL) {
  827.     while ((msg = (struct IntuiMessage *)GetMsg (video_window->UserPort)) != NULL) {
  828.       class = msg->Class;
  829.       code = msg->Code;
  830.       mousex = msg->MouseX;
  831.       mousey = msg->MouseY;
  832.       ReplyMsg ((struct Message *)msg);
  833.       if (class == IDCMP_RAWKEY) {
  834.         if ((code & 0x80) != 0) {
  835.           code &= ~0x80;
  836.       event.type = ev_keyup;
  837.         } else {
  838.           event.type = ev_keydown;
  839.         }
  840.         if (code < 0x68 && xlate[code] != 0) {
  841.           event.data1 = xlate[code];
  842.           D_PostEvent (&event);
  843.         }
  844.       } else if (class == IDCMP_MOUSEMOVE) {
  845.         mouseevent.type = ev_mouse;
  846.         mouseevent.data2 = (mousex << 3);
  847.         mouseevent.data3 = -(mousey << 5);
  848.         D_PostEvent (&mouseevent);
  849.       } else if (class == IDCMP_MOUSEBUTTONS) {
  850.         mouseevent.type = ev_mouse;
  851.         switch (code) {
  852.           case SELECTDOWN:
  853.             mouseevent.data1 |= 1;
  854.             break;
  855.           case SELECTUP:
  856.             mouseevent.data1 &= ~1;
  857.             break;
  858.           case MENUDOWN:
  859.             mouseevent.data1 |= 2;
  860.             break;
  861.           case MENUUP:
  862.             mouseevent.data1 &= ~2;
  863.             break;
  864.           case MIDDLEDOWN:
  865.             mouseevent.data1 |= 4;
  866.             break;
  867.           case MIDDLEUP:
  868.             mouseevent.data1 &= ~4;
  869.             break;
  870.           default:
  871.             break;
  872.         }
  873.         D_PostEvent (&mouseevent);
  874.       }
  875.     }
  876.   }
  877.  
  878.   if (gameport_is_open && gameport_io_in_progress) {
  879.     while (GetMsg (gameport_mp) != NULL) {
  880.       switch (gameport_ie.ie_Code) {
  881.         case IECODE_LBUTTON:
  882.           joyevent.data1 |= 1;
  883.           break;
  884.         case IECODE_LBUTTON | IECODE_UP_PREFIX:
  885.           joyevent.data1 &= ~1;
  886.           break;
  887.         case IECODE_RBUTTON:
  888.           joyevent.data1 |= 2;
  889.           break;
  890.         case IECODE_RBUTTON | IECODE_UP_PREFIX:
  891.           joyevent.data1 &= ~2;
  892.           break;
  893.         case IECODE_MBUTTON:
  894.           joyevent.data1 |= 4;
  895.           break;
  896.         case IECODE_MBUTTON | IECODE_UP_PREFIX:
  897.           joyevent.data1 &= ~4;
  898.           break;
  899.         case IECODE_NOBUTTON:
  900.           joyevent.data2 = gameport_ie.ie_X;
  901.           joyevent.data3 = gameport_ie.ie_Y;
  902.           break;
  903.         default:
  904.           break;
  905.       }
  906.       joyevent.type = ev_joystick;
  907.       D_PostEvent (&joyevent);
  908.       gameport_io->io_Command = GPD_READEVENT;
  909.       gameport_io->io_Length = sizeof (struct InputEvent);
  910.       gameport_io->io_Data = &gameport_ie;
  911.       SendIO ((struct IORequest *)gameport_io);
  912.     }
  913.   }
  914.  
  915.   /* CD32 joypad handler code supplied by Gabry (ggreco@iol.it) */
  916.  
  917.   if (LowLevelBase != NULL) {
  918.     event_t joyevent;
  919.     ULONG joypos = ReadJoyPort (1);
  920.  
  921.     if (previous == joypos)
  922.       return;
  923.  
  924.     joyevent.type = ev_joystick;
  925.     joyevent.data1 = joyevent.data2 = joyevent.data3 = 0;
  926.  
  927.     if (joypos & JPF_BUTTON_RED)
  928.       joyevent.data1 |= 1;
  929.     else
  930.       joyevent.data1 &= ~1;
  931.  
  932.     if (joypos & JP_DIRECTION_MASK) {
  933.       if (joypos & JPF_JOY_LEFT) {
  934.         joyevent.data2 = -1;
  935.       } else if (joypos & JPF_JOY_RIGHT) {
  936.         joyevent.data2 = 1;
  937.       }
  938.       if (joypos & JPF_JOY_UP) {
  939.         joyevent.data3 = -1;
  940.       } else if (joypos & JPF_JOY_DOWN) {
  941.         joyevent.data3 = 1;
  942.       }
  943.     }
  944.  
  945.     if (joypos & JP_TYPE_GAMECTLR) {
  946.       event_t event;
  947.  
  948.       // Play/Pause = ESC (Menu)
  949.       if (joypos & JPF_BUTTON_PLAY && !(previous & JPF_BUTTON_PLAY)) {
  950.         event.type = ev_keydown;
  951.         event.data1 = KEY_ESCAPE;
  952.         D_PostEvent (&event);
  953.       } else if (previous & JPF_BUTTON_PLAY) {
  954.         event.type = ev_keyup;
  955.         event.data1 = KEY_ESCAPE;
  956.         D_PostEvent (&event);
  957.       }
  958.  
  959.       // YELLOW = SHIFT (button 2) (Run)
  960.       if (joypos & JPF_BUTTON_YELLOW)
  961.         joyevent.data1 |= 4;
  962.       else
  963.         joyevent.data1 &= ~4;
  964.  
  965.       // BLUE = SPACE (button 3) (Open/Operate)
  966.  
  967.       if (joypos & JPF_BUTTON_BLUE)
  968.         joyevent.data1 |= 8;
  969.       else
  970.         joyevent.data1 &= ~8;
  971.  
  972.       // GREEN = RETURN (show msg)
  973.  
  974.       if (joypos & JPF_BUTTON_GREEN && !(previous&JPF_BUTTON_GREEN)) {
  975.         event.type = ev_keydown;
  976.         event.data1 = 13;
  977.         D_PostEvent (&event);
  978.       } else if (previous & JPF_BUTTON_GREEN) {
  979.         event.type = ev_keyup;
  980.         event.data1 = 13;
  981.         D_PostEvent (&event);
  982.       }
  983.  
  984.       // FORWARD & REVERSE - ALT (Button1) Strafe left/right
  985.  
  986.       if (joypos & JPF_BUTTON_FORWARD) {
  987.         joyevent.data1 |= 2;
  988.         joyevent.data2 = 1;
  989.       } else if (joypos & JPF_BUTTON_REVERSE) {
  990.         joyevent.data1 |=2;
  991.         joyevent.data2=-1;
  992.       } else
  993.         joyevent.data1 &= ~2;
  994.     }
  995.  
  996.     D_PostEvent (&joyevent);
  997.  
  998.     previous = joypos;
  999.   }
  1000.  
  1001. }
  1002.  
  1003. /**********************************************************************/
  1004. void _STDvideo_cleanup (void)
  1005. {
  1006.   I_ShutdownGraphics ();
  1007.   if (video_smr != NULL) {
  1008.     FreeAslRequest (video_smr);
  1009.     video_smr = NULL;
  1010.   }
  1011.   if (total_frames > 0) {
  1012.     printf ("Total number of frames = %u\n", total_frames);
  1013.     printf ("Total blit wait time   = %u us  (%u us/frame)\n", blit_time,
  1014.             blit_time / total_frames);
  1015.     printf ("Total safe wait time   = %u us  (%u us/frame)\n", safe_time,
  1016.             safe_time / total_frames);
  1017.     printf ("Total C2P time         = %u us  (%u us/frame)\n", c2p_time,
  1018.             c2p_time / total_frames);
  1019.     printf ("Total WPA8 time        = %u us  (%u us/frame)\n", wpa8_time,
  1020.             wpa8_time / total_frames);
  1021.   }
  1022. }
  1023.  
  1024. /**********************************************************************/
  1025.