home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 25
/
amigaformatcd25.iso
/
websites
/
amidoom
/
adoom_src-0.7.lha
/
ADoom_src
/
amiga_video.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-16
|
41KB
|
1,251 lines
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <exec/exec.h>
#include <dos/dos.h>
#include <graphics/gfx.h>
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <intuition/intuition.h>
#include <libraries/asl.h>
#include <libraries/lowlevel.h>
#include <cybergraphics/cybergraphics.h>
#include <devices/gameport.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/layers.h>
#include <proto/intuition.h>
#include <proto/asl.h>
#include <proto/lowlevel.h>
#include <proto/cybergraphics.h>
#include "doomtype.h"
#include "doomdef.h"
#include "doomstat.h"
#include "i_system.h"
#include "i_video.h"
#include "v_video.h"
#include "m_argv.h"
#include "d_main.h"
#include "amiga_median.h"
#include "c2p_020.h"
#include "c2p_030.h"
#include "c2p_040.h"
#include "c2p8_040_amlaukka.h"
#include "mmu.h"
/*experimental_c2p_stuff***********************************************/
extern int scaledviewwidth;
void REGARGS (*c2p)(REG(a0, const UBYTE *chunky),
REG(a1, UBYTE *raster),
REG(a2, const UBYTE *chunky_end)) = NULL;
/**********************************************************************/
extern struct ExecBase *SysBase;
struct Library *AslBase = NULL;
struct Library *CyberGfxBase = NULL;
struct Library *LowLevelBase = NULL;
extern int cpu_type;
static struct ScreenModeRequester *video_smr = NULL;
static struct Screen *video_screen = NULL;
static struct Window *video_window = NULL;
static struct BitMap video_bitmap[3] = {
{0, 0, 0, 0, 0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}},
{0, 0, 0, 0, 0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}},
{0, 0, 0, 0, 0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}}
};
static PLANEPTR video_raster[3] = {NULL, NULL, NULL}; /* contiguous bitplanes */
static UBYTE *video_compare_buffer[3] = {NULL, NULL, NULL}; /* in fastmem */
static struct ScreenBuffer *video_sb[2] = {NULL, NULL};
static struct DBufInfo *video_db = NULL;
static struct MsgPort *video_mp = NULL;
static int video_which = 0;
static BYTE video_sigbit1 = -1;
static BYTE video_sigbit2 = -1;
static volatile BYTE video_sigbit3 = -1;
static struct Task *video_maintask;
static struct Task *video_fliptask = NULL;
static int video_depth = 0;
static int video_oscan_height;
static struct RastPort *video_rastport = NULL;
static ULONG video_colourtable[1 + 3*256 + 1];
static volatile WORD video_palette_changed = 0;
static BOOL video_is_ehb_mode = FALSE;
static BOOL video_is_native_mode = FALSE;
static BOOL video_is_cyber_mode = FALSE;
static BOOL video_is_using_blitter = FALSE;
static BOOL video_blit_is_in_progress = FALSE;
static BOOL video_use_mmu = FALSE;
static BOOL video_is_directcgx = FALSE;
static BOOL video_bitmap_is_locked = FALSE;
static APTR video_bitmap_handle;
static int video_f_cache_mode;
static int video_c_cache_mode;
static struct RastPort video_temprp;
static struct BitMap video_tmp_bm = {
0, 0, 0, 0, 0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
};
static UBYTE video_xlate[256]; /* xlate colour from 8-bit to 6-bit EHB */
static UWORD __chip emptypointer[] = {
0x0000, 0x0000, /* reserved, must be NULL */
0x0000, 0x0000, /* 1 row of image data */
0x0000, 0x0000 /* reserved, must be NULL */
};
/* gameport stuff */
static struct MsgPort *gameport_mp = NULL;
static struct IOStdReq *gameport_io = NULL;
static BOOL gameport_is_open = FALSE;
static BOOL gameport_io_in_progress = FALSE;
static struct InputEvent gameport_ie;
static BYTE gameport_ct; /* controller type */
struct GamePortTrigger gameport_gpt = {
GPTF_UPKEYS | GPTF_DOWNKEYS, /* gpt_Keys */
0, /* gpt_Timeout */
1, /* gpt_XDelta */
1 /* gpt_YDelta */
};
static unsigned int start_time[2];
static unsigned int blit_time = 0;
static unsigned int safe_time = 0;
static unsigned int c2p_time = 0;
static unsigned int wpa8_time = 0;
static unsigned int lock_time = 0;
static unsigned int total_frames = 0;
/****************************************************************************/
static __inline void start_timer (void)
{
timer (start_time);
}
/****************************************************************************/
static __inline unsigned int end_timer (void)
{
unsigned int end_time[2];
timer (end_time);
if (end_time[1] >= start_time[1])
return end_time[1] - start_time[1] + 50;
else
return end_time[1] + 1000000 - start_time[1];
}
/****************************************************************************/
static char *mode_name (ULONG mode)
/* Return a mode name for given mode, compatible with ASL mode requester */
/* Use name in DisplayInfo database if available */
/* else manually construct the name */
{
APTR handle;
char *p;
struct NameInfo nameinfo;
struct DimensionInfo dimsinfo;
static char modename[DISPLAYNAMELEN + 4 + 4 + 11 + 1];
p = modename;
*p = '\0';
if ((handle = FindDisplayInfo (mode & ~SPRITES)) != NULL) {
if (GetDisplayInfoData (handle, (UBYTE *)&nameinfo,
sizeof(nameinfo), DTAG_NAME,
NULL) > sizeof(struct QueryHeader)) {
p += sprintf (p, "%s", nameinfo.Name);
} else if (GetDisplayInfoData (handle, (UBYTE *)&dimsinfo,
sizeof(dimsinfo), DTAG_DIMS,
NULL) >= 66 /* sizeof(dimsinfo)*/) {
switch (mode & MONITOR_ID_MASK) {
case DEFAULT_MONITOR_ID:
p += sprintf (p, "DEFAULT:"); /* PAL or NTSC??? */
break;
case NTSC_MONITOR_ID:
p += sprintf (p, "NTSC:");
break;
case PAL_MONITOR_ID:
p += sprintf (p, "PAL:");
break;
case VGA_MONITOR_ID:
p += sprintf (p, "MULTISCAN:");
break;
case A2024_MONITOR_ID:
p += sprintf (p, "A2024:");
break;
case PROTO_MONITOR_ID:
p += sprintf (p, "PROTO:");
break;
case EURO72_MONITOR_ID:
p += sprintf (p, "EURO72:");
break;
case EURO36_MONITOR_ID:
p += sprintf (p, "EURO36:");
break;
case SUPER72_MONITOR_ID:
p += sprintf (p, "SUPER72:");
break;
case DBLNTSC_MONITOR_ID:
p += sprintf (p, "DBLNTSC:");
break;
case DBLPAL_MONITOR_ID:
p += sprintf (p, "DBLPAL:");
break;
default:
p += sprintf (p, "(unknown):");
break;
}
p += sprintf (p, "%d x %d",
dimsinfo.Nominal.MaxX - dimsinfo.Nominal.MinX + 1,
dimsinfo.Nominal.MaxY - dimsinfo.Nominal.MinY + 1);
if ((mode & HAM_KEY) != 0)
p += sprintf (p, " HAM");
if ((mode & EXTRAHALFBRITE_KEY) != 0)
p += sprintf (p, " EHB");
if ((mode & LACE) != 0)
p += sprintf (p, " Interlaced");
} else {
p += sprintf (p, "%s", "(unnamed)");
if ((mode & HAM_KEY) != 0)
p += sprintf (p, " HAM");
if ((mode & EXTRAHALFBRITE_KEY) != 0)
p += sprintf (p, " EHB");
if ((mode & LACE) != 0)
p += sprintf (p, " Interlaced");
}
} else {
p += sprintf (p, "%s", "(unavailable)");
}
return (modename);
}
/****************************************************************************/
static ULONG parse_mode (char *modename)
/* Modename may be descriptive name ("PAL Lores"), or hex ("$00420001" or */
/* "0x12345678") or decimal ("32768"). */
{
ULONG mode, reason;
mode = INVALID_ID;
if (modename != NULL) {
if (modename[0] == '0' && modename[1] == 'x') {
if (sscanf (&modename[2], "%lx", &mode) != 1)
mode = INVALID_ID;
} else if (modename[0] == '$') {
if (sscanf (&modename[1], "%lx", &mode) != 1)
mode = INVALID_ID;
} else if (modename[0] >= '0' && modename[0] <= '9') {
if (sscanf (modename, "%ld", &mode) != 1)
mode = INVALID_ID;
} else {
while ((mode = NextDisplayInfo (mode)) != INVALID_ID) {
if ((mode & LORESDPF_KEY) == 0) {
/* printf ("$%08x \"%s\"\n", mode, mode_name (mode)); */
if (strcmp (mode_name (mode), modename) == 0)
break;
}
}
}
}
if (FindDisplayInfo (mode) == NULL)
I_Error ("ScreenMode not in database: \"%s\"", modename);
if ((reason = ModeNotAvailable (mode)) != 0)
I_Error ("Mode $%08x is not available: %ld", mode, reason);
return (mode);
}
/**********************************************************************/
// This asynchronous task waits in a loop for sigbit3 signals.
// Sigbit3 is signalled when the next frame is just finished.
// Sigbit3 may be signalled from the qblit() cleanup function or from the
// main task.
// On receipt of sigbit3, we load the new palette and call ChangeScreenBuffer().
// This way there is no delay calling ChangeScreenBuffer() after the last blit
// has finished.
// The main 3D rendering task may be interrupted to call ChangeScreenBuffer()
// SIGBREAKF_CTRL_F and SIGBREAKF_CTRL_C are used for synchronisation
// with the main task.
static void __saveds __interrupt video_flipscreentask (void)
{
ULONG sig;
struct MsgPort *video_dispport, *video_safeport;
BOOL going, video_disp, video_safe;
int i;
video_sigbit3 = AllocSignal(-1);
Signal (video_maintask, SIGBREAKF_CTRL_F);
video_dispport = CreatePort (NULL, 0);
video_safeport = CreatePort (NULL, 0);
video_disp = TRUE;
video_safe = TRUE;
for (i = 0; i < 2; i++) {
video_sb[i]->sb_DBufInfo->dbi_DispMessage.mn_ReplyPort = video_dispport;
video_sb[i]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = video_safeport;
}
going = (video_sigbit3 != -1) &&
(video_dispport != NULL) &&
(video_safeport != NULL);
while (going) {
sig = Wait (1 << video_sigbit3 | SIGBREAKF_CTRL_C);
if ((sig & (1 << video_sigbit3)) != 0) {
LoadRGB32 (&video_screen->ViewPort, video_colourtable);
if ((ChangeScreenBuffer (video_screen, video_sb[video_which])) != 0) {
video_disp = FALSE;
video_safe = FALSE;
}
if (!video_safe) { /* wait until safe */
Wait (1 << video_safeport->mp_SigBit);
while (GetMsg (video_safeport) != NULL) /* clear message queue */
/* do nothing */ ;
video_safe = TRUE;
}
Signal (video_maintask, SIGBREAKF_CTRL_F);
if (!video_disp) { /* wait for previous frame to be displayed */
Wait (1 << video_dispport->mp_SigBit);
while (GetMsg (video_dispport) != NULL) /* clear message queue */
/* do nothing */ ;
video_disp = TRUE;
}
}
if ((sig & SIGBREAKF_CTRL_C) != 0) {
going = FALSE;
}
}
if (!video_safe) { /* wait for safe */
Wait (1 << video_safeport->mp_SigBit);
while (GetMsg (video_safeport) != NULL) /* clear message queue */
/* do nothing */ ;
video_safe = TRUE;
}
if (!video_disp) { /* wait for last frame to be displayed */
Wait (1 << video_dispport->mp_SigBit);
while (GetMsg (video_dispport) != NULL) /* clear message queue */
/* do nothing */ ;
video_disp = TRUE;
}
if (video_sigbit3 != -1)
FreeSignal (video_sigbit3);
if (video_dispport != NULL)
DeletePort (video_dispport);
if (video_safeport != NULL)
DeletePort (video_safeport);
Signal (video_maintask, SIGBREAKF_CTRL_F);
Wait (0);
}
/**********************************************************************/
// Called by D_DoomMain,
// determines the hardware configuration
// and sets up the video mode
void I_InitGraphics (void)
{
int i;
ULONG propertymask, idcmp, wflags, width, pixfmt;
struct Rectangle rect;
char reqtitle[32];
int mode, depth, nbytes, p;
DisplayInfoHandle handle;
struct DisplayInfo dispinfo;
struct DimensionInfo dimsinfo;
video_maintask = FindTask(NULL);
if (AslBase == NULL) {
if ((AslBase = OpenLibrary ("asl.library", 37L)) == NULL ||
(video_smr = AllocAslRequestTags (ASL_ScreenModeRequest, TAG_DONE)) == NULL) {
I_Error ("OpenLibrary(""asl.library"", 37) failed");
}
}
/* first check tooltypes for SCREENMODE */
mode = -1;
p = M_CheckParm ("-screenmode");
if (p && p < myargc - 1) {
mode = parse_mode (myargv[p+1]);
}
/* if not found in icon tooltypes, then put up a ScreenMode requester */
if (mode == -1) {
propertymask = /* DIPF_IS_EXTRAHALFBRITE | */ DIPF_IS_DUALPF |
DIPF_IS_PF2PRI | DIPF_IS_HAM;
if (GfxBase->LibNode.lib_Version >= 39)
mode = BestModeID (BIDTAG_NominalWidth, SCREENWIDTH,
BIDTAG_NominalHeight, SCREENHEIGHT,
BIDTAG_Depth, video_depth,
BIDTAG_DIPFMustNotHave, propertymask,
TAG_DONE);
else
mode = EXTRAHALFBRITE_KEY;
if (AslBase->lib_Version >= 38) {
sprintf (reqtitle, "ADoom %dx%d", SCREENWIDTH, SCREENHEIGHT);
if (!AslRequestTags (video_smr,
ASLSM_TitleText, (ULONG)reqtitle,
ASLSM_InitialDisplayID, mode,
ASLSM_MinWidth, SCREENWIDTH,
ASLSM_MinHeight, SCREENHEIGHT,
ASLSM_MinDepth, 6,
ASLSM_MaxDepth, 8,
ASLSM_PropertyMask, propertymask,
ASLSM_PropertyFlags, 0,
TAG_DONE)) {
I_Error ("AslRequest() failed");
}
mode = video_smr->sm_DisplayID;
}
}
if ((handle = FindDisplayInfo (mode)) == NULL) {
I_Error ("Can't FindDisplayInfo() for mode %08x", mode);
}
if ((nbytes = GetDisplayInfoData (handle, (UBYTE *)&dispinfo,
sizeof(struct DisplayInfo), DTAG_DISP,
NULL)) < 40 /*sizeof(struct DisplayInfo)*/) {
I_Error ("Can't GetDisplayInfoData() for mode %08x, got %d bytes",
mode, nbytes);
}
if ((nbytes = GetDisplayInfoData (handle, (UBYTE *)&dimsinfo,
sizeof(dimsinfo), DTAG_DIMS,
NULL)) < 66 /* sizeof(dimsinfo)*/) {
I_Error ("Can't GetDisplayInfoData() for mode %08x, got %d bytes",
mode, nbytes);
}
video_oscan_height = dimsinfo.MaxOScan.MaxY - dimsinfo.MaxOScan.MinY + 1;
video_is_cyber_mode = 0;
if ((CyberGfxBase = OpenLibrary ("cybergraphics.library", 0)) != NULL) {
video_is_cyber_mode = IsCyberModeID (mode);
}
/* this test needs improving */
video_is_native_mode = ((GfxBase->LibNode.lib_Version < 39 ||
(dispinfo.PropertyFlags & DIPF_IS_EXTRAHALFBRITE) != 0 ||
(dispinfo.PropertyFlags & DIPF_IS_AA) != 0 ||
(dispinfo.PropertyFlags & DIPF_IS_ECS) != 0 ||
(dispinfo.PropertyFlags & DIPF_IS_DBUFFER) != 0) &&
!video_is_cyber_mode &&
(dispinfo.PropertyFlags & DIPF_IS_FOREIGN) == 0);
video_is_ehb_mode = ((dispinfo.PropertyFlags & DIPF_IS_EXTRAHALFBRITE) != 0);
printf ("Screen Mode $%08x is ", mode);
if (video_is_native_mode)
printf (" NATIVE-PLANAR");
else
printf (" FOREIGN");
if (video_is_ehb_mode)
printf (" EXTRAHALFBRITE");
else
printf (" 8-BIT");
if (video_is_cyber_mode)
printf (" CYBERGRAPHX");
printf ("\n");
if (video_is_ehb_mode)
video_depth = 6;
else
video_depth = 8;
rect.MinX = 0;
rect.MinY = 0;
rect.MaxX = SCREENWIDTH - 1;
rect.MaxY = SCREENHEIGHT - 1;
if (M_CheckParm ("-mmu") && cpu_type >= 68040)
video_use_mmu = true;
if (video_is_native_mode) {
video_is_using_blitter = (cpu_type < 68040);
for (i = 0; i < (video_is_using_blitter ? 2 : 3); i++) {
/* use the mmu hack only if cpu is 68040+ and user specified -mmu */
if (video_use_mmu) {
ULONG *ptr, mem;
mem = (ULONG)AllocVec (SCREENWIDTH * SCREENHEIGHT / 8 * video_depth +
4100, MEMF_CHIP);
if (!mem)
I_Error ("AllocVec() failed");
ptr = (ULONG*)((mem & ~0xfff) + 4096);
ptr[-1] = 4096 - (mem & 0xfff);
video_raster[i] = (byte *)ptr;
video_c_cache_mode = mmu_mark (video_raster[i],
SCREENWIDTH * SCREENHEIGHT / 8 * video_depth,
CM_IMPRECISE, SysBase);
} else {
if ((video_raster[i] = (PLANEPTR)AllocRaster (SCREENWIDTH,
video_depth * SCREENHEIGHT)) == NULL)
I_Error ("AllocRaster() failed");
}
memset (video_raster[i], 0, video_depth * RASSIZE (SCREENWIDTH, SCREENHEIGHT));
InitBitMap (&video_bitmap[i], video_depth, SCREENWIDTH, SCREENHEIGHT);
for (depth = 0; depth < video_depth; depth++)
video_bitmap[i].Planes[depth] = video_raster[i] +
depth * RASSIZE (SCREENWIDTH, SCREENHEIGHT);
}
/* experimental c2p stuff */
if (!video_is_using_blitter)
c2p = c2p8_reloc (screens[0], &video_bitmap[0], SysBase);
if ((video_screen = OpenScreenTags (NULL,
SA_Type, CUSTOMSCREEN | CUSTOMBITMAP,
SA_DisplayID, mode,
SA_DClip, (ULONG)&rect,
SA_Width, SCREENWIDTH,
SA_Height, SCREENHEIGHT,
SA_Depth, video_depth,
/* SA_Draggable,FALSE, */
/* SA_AutoScroll,FALSE, */
/* SA_Exclusive,TRUE, */
SA_Quiet, TRUE,
SA_BitMap, &video_bitmap[0], /* custom bitmap, contiguous planes */
TAG_DONE)) == NULL) {
I_Error ("OpenScreen() failed");
}
for (i = 0; i < (video_is_using_blitter ? 2 : 3); i++) {
if ((video_compare_buffer[i] = malloc (SCREENWIDTH * SCREENHEIGHT)) == NULL)
I_Error ("Out of memory allocating %d bytes", SCREENWIDTH * SCREENHEIGHT);
memset (video_compare_buffer[i], 0, SCREENWIDTH * SCREENHEIGHT);
}
if (video_is_using_blitter) {
for (i = 0; i < 2; i++) {
if ((video_sb[i] = AllocScreenBuffer (video_screen, &video_bitmap[i], 0)) == NULL)
I_Error ("Can't allocate structure for double buffering");
}
} else {
video_db = AllocDBufInfo (&video_screen->ViewPort);
video_mp = CreateMsgPort ();
if (!video_db || !video_mp)
I_Error ("Can't allocate dbuffer information");
video_db->dbi_DispMessage.mn_ReplyPort = video_mp;
video_which = 1;
ChangeVPBitMap (&video_screen->ViewPort, &video_bitmap[0], video_db);
}
} else {
if (video_is_cyber_mode && M_CheckParm ("-directcgx"))
video_is_directcgx = TRUE;
if ((video_screen = OpenScreenTags (NULL,
SA_Type, CUSTOMSCREEN,
SA_DisplayID, mode,
SA_DClip, (ULONG)&rect,
SA_Width, SCREENWIDTH,
SA_Height, video_is_directcgx ? video_oscan_height << 1 : SCREENHEIGHT,
SA_Depth, video_depth,
/* SA_Draggable,FALSE, */
/* SA_AutoScroll,FALSE, */
/* SA_Exclusive,TRUE, */
SA_Quiet, TRUE,
TAG_DONE)) == NULL) {
I_Error ("OpenScreen() failed");
}
}
if (video_is_directcgx) {
video_bitmap_handle = LockBitMapTags (video_screen->ViewPort.RasInfo->BitMap,
LBMI_WIDTH, &width,
LBMI_DEPTH, &depth,
LBMI_PIXFMT, &pixfmt,
LBMI_BASEADDRESS, &screens[0],
TAG_DONE);
UnLockBitMap (video_bitmap_handle);
if (/* width != SCREENWIDTH || */
depth != video_depth ||
pixfmt != PIXFMT_LUT8) {
I_Error ("ScreenMode of width %d, depth %d, pixfmt %d cannot be used with -directcgx",
width, depth, pixfmt);
}
} else {
if (video_use_mmu) {
video_f_cache_mode = mmu_mark (screens[0],
(SCREENWIDTH * SCREENHEIGHT + 4096) & ~0xfff,
CM_WRITETHROUGH, SysBase);
}
}
idcmp = IDCMP_RAWKEY;
wflags = WFLG_ACTIVATE | WFLG_BORDERLESS | WFLG_RMBTRAP;
if (M_CheckParm("-mouse") != NULL) {
idcmp |= IDCMP_MOUSEMOVE | IDCMP_DELTAMOVE | IDCMP_MOUSEBUTTONS;
wflags |= WFLG_REPORTMOUSE;
}
if ((video_window = OpenWindowTags (NULL,
WA_Left, 0,
WA_Top, 0,
WA_Width, SCREENWIDTH,
WA_Height, SCREENHEIGHT,
WA_IDCMP, idcmp,
WA_Flags, wflags,
WA_CustomScreen, video_screen,
TAG_DONE)) == NULL) {
I_Error ("OpenWindow() failed");
}
video_rastport = video_window->RPort;
InitBitMap (&video_tmp_bm, video_depth, SCREENWIDTH, 1);
for (depth = 0; depth < video_depth; depth++)
if ((video_tmp_bm.Planes[depth] = (PLANEPTR)AllocRaster (SCREENWIDTH, 1)) == NULL)
I_Error ("AllocRaster() failed");
video_temprp = *video_rastport;
video_temprp.Layer = NULL;
video_temprp.BitMap = &video_tmp_bm;
SetPointer (video_window, emptypointer, 1, 16, 0, 0);
if (video_is_native_mode) {
if (video_is_using_blitter) {
if ((video_sigbit1 = AllocSignal(-1)) == -1 ||
(video_sigbit2 = AllocSignal(-1)) == -1)
I_Error ("Can't allocate signal!\n");
Signal (video_maintask, (1 << video_sigbit1) | (1 << video_sigbit2));
/* initial state is finished */
if ((video_fliptask = CreateTask ("ADoom_flipscreen", 5,
video_flipscreentask, 4096)) == NULL)
I_Error ("Can't create subtask");
Wait (SIGBREAKF_CTRL_F);
if (video_sigbit3 == -1)
I_Error ("Subtask couldn't allocate sigbit");
if (!video_is_ehb_mode)
c2p1x1_cpu3blit1_queue_init (SCREENWIDTH, SCREENHEIGHT, 0,
SCREENWIDTH * SCREENHEIGHT / 8,
1 << video_sigbit1, 1 << video_sigbit3,
video_maintask, video_fliptask);
}
}
/* joystick initialisation */
if (M_CheckParm ("-joypad") != NULL) {
if ((LowLevelBase = OpenLibrary ("lowlevel.library", 0)) == NULL)
I_Error ("-joypad option specified and can't open lowlevel.library");
} else {
if ((gameport_mp = CreatePort (NULL, 0)) == NULL ||
(gameport_io = (struct IOStdReq *)CreateExtIO (gameport_mp,
sizeof(struct IOStdReq))) == NULL ||
OpenDevice ("gameport.device", 1, (struct IORequest *)gameport_io, 0) != 0)
I_Error ("Can't open gameport.device");
gameport_is_open = TRUE;
Forbid ();
gameport_io->io_Command = GPD_ASKCTYPE;
gameport_io->io_Length = 1;
gameport_io->io_Data = &gameport_ct;
DoIO ((struct IORequest *)gameport_io);
if (gameport_ct != GPCT_NOCONTROLLER) {
Permit ();
fprintf (stderr, "Another task is using the gameport! Joystick disabled");
CloseDevice ((struct IORequest *)gameport_io);
gameport_is_open = FALSE;
} else {
gameport_ct = GPCT_ABSJOYSTICK;
gameport_io->io_Command = GPD_SETCTYPE;
gameport_io->io_Length = 1;
gameport_io->io_Data = &gameport_ct;
DoIO ((struct IORequest *)gameport_io);
Permit ();
gameport_io->io_Command = GPD_SETTRIGGER;
gameport_io->io_Length = sizeof(struct GamePortTrigger);
gameport_io->io_Data = &gameport_gpt;
DoIO ((struct IORequest *)gameport_io);
gameport_io->io_Command = GPD_READEVENT;
gameport_io->io_Length = sizeof (struct InputEvent);
gameport_io->io_Data = &gameport_ie;
SendIO ((struct IORequest *)gameport_io);
gameport_io_in_progress = TRUE;
}
}
}
/**********************************************************************/
void I_ShutdownGraphics (void)
{
int depth, i;
if (video_is_directcgx && video_bitmap_is_locked) {
UnLockBitMap (video_bitmap_handle);
video_bitmap_is_locked = FALSE;
}
if (LowLevelBase != NULL) {
CloseLibrary (LowLevelBase);
LowLevelBase = NULL;
}
if (gameport_io_in_progress) {
AbortIO ((struct IORequest *)gameport_io);
WaitIO ((struct IORequest *)gameport_io);
gameport_io_in_progress = FALSE;
gameport_ct = GPCT_NOCONTROLLER;
gameport_io->io_Command = GPD_SETCTYPE;
gameport_io->io_Length = 1;
gameport_io->io_Data = &gameport_ct;
DoIO ((struct IORequest *)gameport_io);
}
if (gameport_is_open) {
CloseDevice ((struct IORequest *)gameport_io);
gameport_is_open = FALSE;
}
if (gameport_io != NULL) {
DeleteExtIO ((struct IORequest *)gameport_io);
gameport_io = NULL;
}
if (gameport_mp != NULL) {
DeletePort (gameport_mp);
gameport_mp = NULL;
}
if (video_blit_is_in_progress) {
Wait (SIGBREAKF_CTRL_F);
video_blit_is_in_progress = FALSE;
}
if (video_fliptask != NULL) {
Signal (video_fliptask, SIGBREAKF_CTRL_C);
Wait (SIGBREAKF_CTRL_F);
DeleteTask (video_fliptask);
video_fliptask = NULL;
}
if (video_is_using_blitter) {
if (video_sigbit1 != -1) {
Wait (1 << video_sigbit1); // wait for last c2p8 to finish pass 3
FreeSignal (video_sigbit1);
video_sigbit1 = -1;
}
if (video_sigbit2 != -1) {
Wait (1 << video_sigbit2); // wait for last c2p8 to completely finish
FreeSignal (video_sigbit2);
video_sigbit2 = -1;
}
}
if (video_window != NULL) {
ClearPointer (video_window);
CloseWindow (video_window);
video_window = NULL;
}
if (video_is_using_blitter) {
for (i = 0; i < 2; i++) {
if (video_sb[i] != NULL) {
FreeScreenBuffer (video_screen, video_sb[i]);
video_sb[i] = NULL;
}
}
} else {
if (video_mp) {
WaitPort (video_mp);
while (GetMsg(video_mp));
DeleteMsgPort (video_mp);
video_mp = NULL;
}
if (video_db) {
FreeDBufInfo (video_db);
video_db = NULL;
}
}
if (video_screen != NULL) {
CloseScreen (video_screen);
video_screen = NULL;
}
for (depth = 0; depth < video_depth; depth++) {
if (video_tmp_bm.Planes[depth] != NULL) {
FreeRaster (video_tmp_bm.Planes[depth], SCREENWIDTH, 1);
video_tmp_bm.Planes[depth] = NULL;
}
}
for (i = 0; i < (video_is_using_blitter ? 2 : 3); i++) {
if (video_raster[i] != NULL) {
if (video_use_mmu) {
ULONG *ptr = (ULONG *)video_raster[i];
UBYTE *p2 = (UBYTE *)ptr;
mmu_mark (video_raster[i], SCREENWIDTH * SCREENHEIGHT / 8 * video_depth,
video_c_cache_mode, SysBase);
FreeVec (p2 - ptr[-1]);
} else
FreeRaster (video_raster[i], SCREENWIDTH, video_depth * SCREENHEIGHT);
video_raster[i] = NULL;
}
if (video_compare_buffer[i] != NULL) {
free (video_compare_buffer[i]);
video_compare_buffer[i] = NULL;
}
}
if (video_use_mmu && !video_is_directcgx) {
if (screens[0] != NULL)
mmu_mark (screens[0], (SCREENWIDTH * SCREENHEIGHT + 4096) & ~0xfff,
video_f_cache_mode, SysBase);
}
if (CyberGfxBase == NULL) {
CloseLibrary (CyberGfxBase);
CyberGfxBase = NULL;
}
/* experimental c2p stuff */
if (c2p && !video_is_using_blitter) {
c2p8_deinit (c2p, SysBase);
c2p = NULL;
}
}
/**********************************************************************/
// Takes full 8 bit values.
void I_SetPalette (byte *palette)
{
int i;
ULONG c, *p;
UBYTE *g;
static UBYTE gpalette[3*256];
/* printf ("I_SetPalette()\n"); */
if (video_is_ehb_mode) {
g = gpalette;
for (i = 0; i < 256; i++) {
*g++ = gammatable[usegamma][*palette++];
*g++ = gammatable[usegamma][*palette++];
*g++ = gammatable[usegamma][*palette++];
}
video_colourtable[0] = (32 << 16) + 0;
median_cut (gpalette, &video_colourtable[1], video_xlate);
video_colourtable[33] = 0;
} else {
p = video_colourtable;
*p++ = (256 << 16) + 0;
for (i = 0; i < 256; i++) {
c = (ULONG)gammatable[usegamma][*palette++];
c += (c<<8);
c += (c<<16);
*p++ = c;
c = (ULONG)gammatable[usegamma][*palette++];
c += (c<<8);
c += (c<<16);
*p++ = c;
c = (ULONG)gammatable[usegamma][*palette++];
c += (c<<8);
c += (c<<16);
*p++ = c;
}
*p++ = 0;
}
if (video_is_ehb_mode)
if (video_is_using_blitter) {
video_palette_changed = 2; /* double buffering */
} else
video_palette_changed = 3; /* triple buffering */
else
video_palette_changed = 1;
}
/**********************************************************************/
void I_StartUpdate (void)
{
UBYTE *base_address;
if (video_is_directcgx) {
if (video_palette_changed != 0) {
LoadRGB32 (&video_screen->ViewPort, video_colourtable);
video_palette_changed = 0;
}
if (!video_bitmap_is_locked) {
start_timer ();
video_bitmap_handle = LockBitMapTags (video_screen->ViewPort.RasInfo->BitMap,
LBMI_BASEADDRESS, &base_address,
TAG_DONE);
lock_time += end_timer ();
video_bitmap_is_locked = TRUE;
/*
video_which = 1 - video_which;
if (video_which != 0)
screens[0] = base_address + (SCREENWIDTH * video_oscan_height);
else
*/
screens[0] = base_address;
}
}
}
/**********************************************************************/
void I_UpdateNoBlit (void)
{
}
/**********************************************************************/
void I_FinishUpdate (void)
/* This needs optimising to copy just the parts that changed,
especially if the user has shrunk the playscreen. */
{
total_frames++;
if (video_is_directcgx) {
if (video_bitmap_is_locked) {
UnLockBitMap (video_bitmap_handle);
video_bitmap_is_locked = FALSE;
/*
video_screen->ViewPort.RasInfo->RyOffset = video_which != 0 ?
video_oscan_height : 0;
ScrollVPort (&video_screen->ViewPort);
*/
} else
I_Error ("I_FinishUpdate() called without calling I_StartUpdate() first");
return;
}
if (video_is_native_mode) {
if (video_is_using_blitter) {
start_timer();
Wait (1 << video_sigbit1); /* wait for prev c2p() to finish pass 3 */
blit_time += end_timer();
if (video_blit_is_in_progress) {
start_timer();
Wait (SIGBREAKF_CTRL_F); /* wait for prev ChangeScreenBuffer() safe */
safe_time += end_timer();
video_blit_is_in_progress = FALSE;
}
video_which = 1 - video_which; /* render to the hidden bitmap */
start_timer();
if (video_is_ehb_mode) {
c2p_6_020 (screens[0],
video_bitmap[video_which].Planes,
1 << video_sigbit1, 1 << video_sigbit2, 1 << video_sigbit3,
SCREENWIDTH * SCREENHEIGHT, 0, video_xlate, video_fliptask);
} else {
if (cpu_type < 68030)
c2p_8_020 (screens[0],
video_bitmap[video_which].Planes,
1 << video_sigbit1, 1 << video_sigbit2, 1 << video_sigbit3,
SCREENWIDTH * SCREENHEIGHT, 0, video_fliptask);
else
c2p1x1_cpu3blit1_queue (screens[0], video_raster[video_which]);
}
c2p_time += end_timer();
video_blit_is_in_progress = TRUE;
if (video_palette_changed > 0) {
video_palette_changed--; /* keep it set for 2 frames for dblbuffering */
}
} else {
start_timer();
if (video_is_ehb_mode) {
c2p_6_040 (screens[0], video_raster[video_which],
video_compare_buffer[video_which], video_xlate,
(SCREENWIDTH * SCREENHEIGHT) >> 3,
video_palette_changed);
if (video_palette_changed > 0) {
if (video_palette_changed == 3)
LoadRGB32 (&video_screen->ViewPort, video_colourtable);
video_palette_changed--;
}
} else {
if (c2p && scaledviewwidth == SCREENWIDTH)
c2p (screens[0], video_raster[video_which],
screens[0] + SCREENWIDTH * SCREENHEIGHT);
else
c2p_8_040 (screens[0], video_raster[video_which],
video_compare_buffer[video_which],
(SCREENWIDTH * SCREENHEIGHT) >> 3);
if (video_palette_changed != 0) {
LoadRGB32 (&video_screen->ViewPort, video_colourtable);
video_palette_changed = 0;
}
}
c2p_time += end_timer();
WaitPort (video_mp);
while (GetMsg (video_mp))
/* do nothing */ ;
ChangeVPBitMap (&video_screen->ViewPort, &video_bitmap[video_which],
video_db);
if (++video_which == 3)
video_which = 0;
}
} else {
if (video_palette_changed != 0) {
LoadRGB32 (&video_screen->ViewPort, video_colourtable);
video_palette_changed = 0;
}
start_timer();
WritePixelArray8 (video_rastport, 0, 0, SCREENWIDTH-1, SCREENHEIGHT-1,
screens[0], &video_temprp);
wpa8_time += end_timer();
}
}
/**********************************************************************/
// Wait for vertical retrace or pause a bit. Use when quit game.
void I_WaitVBL(int count)
{
for ( ; count > 0; count--)
WaitTOF();
}
/**********************************************************************/
void I_ReadScreen (byte* scr)
{
/*
if (video_is_directcgx) {
printf ("I_ReadScreen() %d %d\n", video_which, video_bitmap_is_locked);
ReadPixelArray8 (video_rastport, 0,
video_which != 0 ? 0 : video_oscan_height,
SCREENWIDTH-1, SCREENHEIGHT-1, scr, &video_temprp);
} else
*/
/*
if (video_is_directcgx)
if (video_which)
memcpy (scr, screens[0] - SCREENWIDTH * video_oscan_height,
SCREENWIDTH * SCREENHEIGHT);
else
memcpy (scr, screens[0] + SCREENWIDTH * video_oscan_height,
SCREENWIDTH * SCREENHEIGHT);
else
*/
memcpy (scr, screens[0], SCREENWIDTH * SCREENHEIGHT);
}
/**********************************************************************/
void I_BeginRead (void)
{
}
/**********************************************************************/
void I_EndRead (void)
{
}
/**********************************************************************/
void amiga_getevents (void)
{
event_t event;
ULONG class;
UWORD code;
WORD mousex, mousey;
struct IntuiMessage *msg;
static ULONG previous = 0;
static int xlate[0x68] = {
'`', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '0', KEY_MINUS, KEY_EQUALS, '\\', 0, '0',
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
'o', 'p', KEY_F11, KEY_F12, 0, '0', '2', '3',
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k',
'l', ';', '\'', KEY_ENTER, 0, '4', '5', '6',
KEY_RSHIFT, 'z', 'x', 'c', 'v', 'b', 'n', 'm',
',', '.', '/', 0, '.', '7', '8', '9',
' ', KEY_BACKSPACE, KEY_TAB, KEY_ENTER, KEY_ENTER, KEY_ESCAPE, KEY_BACKSPACE,
0, 0, 0, KEY_MINUS, 0, KEY_UPARROW, KEY_DOWNARROW, KEY_RIGHTARROW, KEY_LEFTARROW,
KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8,
KEY_F9, KEY_F10, '(', ')', '/', '*', KEY_EQUALS, KEY_PAUSE,
KEY_RSHIFT, KEY_RSHIFT, 0, KEY_RCTRL, KEY_LALT, KEY_RALT, 0, KEY_RCTRL
};
static event_t joyevent = {0}, mouseevent = {0};
if (video_window != NULL) {
while ((msg = (struct IntuiMessage *)GetMsg (video_window->UserPort)) != NULL) {
class = msg->Class;
code = msg->Code;
mousex = msg->MouseX;
mousey = msg->MouseY;
ReplyMsg ((struct Message *)msg);
if (class == IDCMP_RAWKEY) {
if ((code & 0x80) != 0) {
code &= ~0x80;
event.type = ev_keyup;
} else {
event.type = ev_keydown;
}
if (code < 0x68 && xlate[code] != 0) {
event.data1 = xlate[code];
D_PostEvent (&event);
}
} else if (class == IDCMP_MOUSEMOVE) {
mouseevent.type = ev_mouse;
mouseevent.data2 = (mousex << 3);
mouseevent.data3 = -(mousey << 5);
D_PostEvent (&mouseevent);
} else if (class == IDCMP_MOUSEBUTTONS) {
mouseevent.type = ev_mouse;
switch (code) {
case SELECTDOWN:
mouseevent.data1 |= 1;
break;
case SELECTUP:
mouseevent.data1 &= ~1;
break;
case MENUDOWN:
mouseevent.data1 |= 2;
break;
case MENUUP:
mouseevent.data1 &= ~2;
break;
case MIDDLEDOWN:
mouseevent.data1 |= 4;
break;
case MIDDLEUP:
mouseevent.data1 &= ~4;
break;
default:
break;
}
D_PostEvent (&mouseevent);
}
}
}
if (gameport_is_open && gameport_io_in_progress) {
while (GetMsg (gameport_mp) != NULL) {
switch (gameport_ie.ie_Code) {
case IECODE_LBUTTON:
joyevent.data1 |= 1;
break;
case IECODE_LBUTTON | IECODE_UP_PREFIX:
joyevent.data1 &= ~1;
break;
case IECODE_RBUTTON:
joyevent.data1 |= 2;
break;
case IECODE_RBUTTON | IECODE_UP_PREFIX:
joyevent.data1 &= ~2;
break;
case IECODE_MBUTTON:
joyevent.data1 |= 4;
break;
case IECODE_MBUTTON | IECODE_UP_PREFIX:
joyevent.data1 &= ~4;
break;
case IECODE_NOBUTTON:
joyevent.data2 = gameport_ie.ie_X;
joyevent.data3 = gameport_ie.ie_Y;
break;
default:
break;
}
joyevent.type = ev_joystick;
D_PostEvent (&joyevent);
gameport_io->io_Command = GPD_READEVENT;
gameport_io->io_Length = sizeof (struct InputEvent);
gameport_io->io_Data = &gameport_ie;
SendIO ((struct IORequest *)gameport_io);
}
}
/* CD32 joypad handler code supplied by Gabry (ggreco@iol.it) */
if (LowLevelBase != NULL) {
event_t joyevent;
ULONG joypos = ReadJoyPort (1);
if (previous == joypos)
return;
joyevent.type = ev_joystick;
joyevent.data1 = joyevent.data2 = joyevent.data3 = 0;
if (joypos & JPF_BUTTON_RED)
joyevent.data1 |= 1;
else
joyevent.data1 &= ~1;
if (joypos & JP_DIRECTION_MASK) {
if (joypos & JPF_JOY_LEFT) {
joyevent.data2 = -1;
} else if (joypos & JPF_JOY_RIGHT) {
joyevent.data2 = 1;
}
if (joypos & JPF_JOY_UP) {
joyevent.data3 = -1;
} else if (joypos & JPF_JOY_DOWN) {
joyevent.data3 = 1;
}
}
if (joypos & JP_TYPE_GAMECTLR) {
event_t event;
// Play/Pause = ESC (Menu)
if (joypos & JPF_BUTTON_PLAY && !(previous & JPF_BUTTON_PLAY)) {
event.type = ev_keydown;
event.data1 = KEY_ESCAPE;
D_PostEvent (&event);
} else if (previous & JPF_BUTTON_PLAY) {
event.type = ev_keyup;
event.data1 = KEY_ESCAPE;
D_PostEvent (&event);
}
// YELLOW = SHIFT (button 2) (Run)
if (joypos & JPF_BUTTON_YELLOW)
joyevent.data1 |= 4;
else
joyevent.data1 &= ~4;
// BLUE = SPACE (button 3) (Open/Operate)
if (joypos & JPF_BUTTON_BLUE)
joyevent.data1 |= 8;
else
joyevent.data1 &= ~8;
// GREEN = RETURN (show msg)
if (joypos & JPF_BUTTON_GREEN && !(previous&JPF_BUTTON_GREEN)) {
event.type = ev_keydown;
event.data1 = 13;
D_PostEvent (&event);
} else if (previous & JPF_BUTTON_GREEN) {
event.type = ev_keyup;
event.data1 = 13;
D_PostEvent (&event);
}
// FORWARD & REVERSE - ALT (Button1) Strafe left/right
if (joypos & JPF_BUTTON_FORWARD) {
joyevent.data1 |= 2;
joyevent.data2 = 1;
} else if (joypos & JPF_BUTTON_REVERSE) {
joyevent.data1 |=2;
joyevent.data2=-1;
} else
joyevent.data1 &= ~2;
}
D_PostEvent (&joyevent);
previous = joypos;
}
}
/**********************************************************************/
void _STDvideo_cleanup (void)
{
I_ShutdownGraphics ();
if (video_smr != NULL) {
FreeAslRequest (video_smr);
video_smr = NULL;
}
if (total_frames > 0) {
printf ("Total number of frames = %u\n", total_frames);
printf ("Total blit wait time = %u us (%u us/frame)\n", blit_time,
blit_time / total_frames);
printf ("Total safe wait time = %u us (%u us/frame)\n", safe_time,
safe_time / total_frames);
printf ("Total C2P time = %u us (%u us/frame)\n", c2p_time,
c2p_time / total_frames);
printf ("Total WPA8 time = %u us (%u us/frame)\n", wpa8_time,
wpa8_time / total_frames);
printf ("Total LockBitMap time = %u us (%u us/frame)\n", lock_time,
lock_time / total_frames);
}
}
/**********************************************************************/