#include #include #include #include #include #include #include #include #include #include #include #include #include #include "hardware.h" #include "cop_x.h" #include "global_defs.h" #include "common.h" #define BITMAPWIDTH ((SCREENWIDTH + EXTRAWIDTH) * 2) #define BITMAPBYTESPERROW (BITMAPWIDTH / 8) #define HALFBITMAPWIDTH (BITMAPWIDTH / 2) #define BITMAPBLOCKSPERROW (BITMAPWIDTH / BLOCKWIDTH) #define HALFBITMAPBLOCKSPERROW (BITMAPBLOCKSPERROW / 2) #define BITMAPBLOCKSPERCOL (BITMAPHEIGHT / BLOCKHEIGHT) #define BITMAPPLANELINES (BITMAPHEIGHT * BLOCKSDEPTH) #define BLOCKPLANELINES (BLOCKHEIGHT * BLOCKSDEPTH) #define BLOCKSFILESIZE (BLOCKSWIDTH * BLOCKSHEIGHT * BLOCKSPLANES / 8 + PALSIZE) struct Screen *scr; struct RastPort *ScreenRastPort; struct BitMap *BlocksBitmap, *ScreenBitmap; UBYTE *frontbuffer, *blocksbuffer; WORD mapposx,videoposx; struct LevelMap level_map; UWORD colors[BLOCKSCOLORS]; struct PrgOptions options; char s[256]; struct FetchInfo fetchinfo [] = { {0x30,0xD0,2,0,16}, /* normal */ {0x28,0xC8,4,16,32}, /* BPL32 */ {0x28,0xC8,4,16,32}, /* BPAGEM */ {0x18,0xB8,8,48,64} /* BPL32 + BPAGEM */ }; /************* SETUP/CLEANUP ROUTINES ***************/ static void Cleanup(char *msg) { WORD rc; if (msg) { printf("Error: %s\n",msg); rc = RETURN_WARN; } else rc = RETURN_OK; if (scr) CloseScreen(scr); if (ScreenBitmap) { WaitBlit(); FreeBitMap(ScreenBitmap); } if (BlocksBitmap) { WaitBlit(); FreeBitMap(BlocksBitmap); } if (level_map.raw_map) free(level_map.raw_map); exit(rc); } static void OpenDisplay(void) { ULONG modeid; LONG bmflags; if (!(ScreenBitmap = AllocBitMap(BITMAPWIDTH,BITMAPHEIGHT + 3,BLOCKSDEPTH, BMF_STANDARD | BMF_INTERLEAVED | BMF_CLEAR,0))) { Cleanup("Can't alloc screen bitmap!"); } frontbuffer = ScreenBitmap->Planes[0]; frontbuffer += (fetchinfo[options.fetchmode].bitmapoffset / 8); if (!(TypeOfMem(ScreenBitmap->Planes[0]) & MEMF_CHIP)) { Cleanup("Screen bitmap is not in CHIP RAM!?? If you have a gfx card try disabling \"planes to fast\" or similiar options in your RTG system!"); } if (!IS_BITMAP_INTERLEAVED(ScreenBitmap)) { Cleanup("Screen bitmap is not in interleaved format!??"); } modeid = get_mode_id(options.how, options.ntsc); if (!(scr = OpenScreenTags(0,SA_Width,BITMAPWIDTH, SA_Height,BITMAPHEIGHT + 3, SA_Depth,BLOCKSDEPTH, SA_DisplayID,modeid, SA_BitMap,ScreenBitmap, options.how ? SA_Overscan : TAG_IGNORE,OSCAN_TEXT, options.how ? SA_AutoScroll : TAG_IGNORE,TRUE, SA_Quiet,TRUE, TAG_DONE))) { Cleanup("Can't open screen!"); } if (scr->RastPort.BitMap->Planes[0] != ScreenBitmap->Planes[0]) { Cleanup("Screen was not created with the custom bitmap I supplied!??"); } ScreenRastPort = &scr->RastPort; LoadRGB4(&scr->ViewPort,colors,BLOCKSCOLORS); } static void InitCopperlist(void) { WORD *wp; LONG l; WaitVBL(); custom->dmacon = 0x7FFF; custom->beamcon0 = options.ntsc ? 0 : DISPLAYPAL; CopFETCHMODE[1] = options.fetchmode; // bitplane control registers CopBPLCON0[1] = ((BLOCKSDEPTH * BPL0_BPU0_F) & BPL0_BPUMASK) + ((BLOCKSDEPTH / 8) * BPL0_BPU3_F) + BPL0_COLOR_F + (options.speed ? 0 : BPL0_USEBPLCON3_F); CopBPLCON1[1] = 0; CopBPLCON3[1] = BPLCON3_BRDNBLNK; // bitplane modulos l = BITMAPBYTESPERROW * BLOCKSDEPTH - SCREENBYTESPERROW - fetchinfo[options.fetchmode].modulooffset; CopBPLMODA[1] = l; CopBPLMODB[1] = l; // display window start/stop CopDIWSTART[1] = DIWSTART; CopDIWSTOP[1] = DIWSTOP; // display data fetch start/stop CopDDFSTART[1] = fetchinfo[options.fetchmode].ddfstart; CopDDFSTOP[1] = fetchinfo[options.fetchmode].ddfstop; // plane pointers wp = CopPLANE1H; for (l = 0;l < BLOCKSDEPTH;l++) { wp[1] = (WORD)(((ULONG)ScreenBitmap->Planes[l]) >> 16); wp[3] = (WORD)(((ULONG)ScreenBitmap->Planes[l]) & 0xFFFF); wp += 4; } if (options.sky) { // activate copper sky CopSKY[0] = 0x290f; } custom->intena = 0x7FFF; custom->dmacon = DMAF_SETCLR | DMAF_BLITTER | DMAF_COPPER | DMAF_RASTER | DMAF_MASTER; custom->cop2lc = (ULONG)CopperList; } /******************* SCROLLING **********************/ static void DrawBlock(LONG x, LONG y, LONG mapx, LONG mapy) { UBYTE block; // x = in pixels // y = in "planelines" (1 realline = BLOCKSDEPTH planelines) x = x / 8; y = y * BITMAPBYTESPERROW; block = level_map.data[mapy * level_map.width + mapx]; mapx = (block % BLOCKSPERROW) * (BLOCKWIDTH / 8); mapy = (block / BLOCKSPERROW) * (BLOCKPLANELINES * BLOCKSBYTESPERROW); if (options.how) OwnBlitter(); HardWaitBlit(); custom->bltcon0 = 0x9F0; // use A and D. Op: D = A custom->bltcon1 = 0; custom->bltafwm = 0xFFFF; custom->bltalwm = 0xFFFF; custom->bltamod = BLOCKSBYTESPERROW - (BLOCKWIDTH / 8); custom->bltdmod = BITMAPBYTESPERROW - (BLOCKWIDTH / 8); custom->bltapt = blocksbuffer + mapy + mapx; custom->bltdpt = frontbuffer + y + x; custom->bltsize = BLOCKPLANELINES * 64 + (BLOCKWIDTH / 16); if (options.how) DisownBlitter(); } static void FillScreen(void) { WORD a,b,x,y; for (b = 0;b < BITMAPBLOCKSPERCOL;b++) { for (a = 0;a < HALFBITMAPBLOCKSPERROW;a++) { x = a * BLOCKWIDTH; y = b * BLOCKPLANELINES; DrawBlock(x,y,a,b); DrawBlock(x + HALFBITMAPWIDTH,y,a,b); } } } static void ScrollLeft(void) { WORD mapx,mapy,x,y; if (mapposx < 1) return; mapposx--; videoposx = mapposx % HALFBITMAPWIDTH; mapx = mapposx / BLOCKWIDTH; mapy = mapposx & (NUMSTEPS - 1); x = ROUND2BLOCKWIDTH(videoposx); y = mapy * BLOCKPLANELINES; DrawBlock(x,y,mapx,mapy); DrawBlock(x + HALFBITMAPWIDTH,y,mapx,mapy); } static void ScrollRight(void) { WORD mapx,mapy,x,y; if (mapposx >= (level_map.width * BLOCKWIDTH - SCREENWIDTH - BLOCKWIDTH)) return; mapx = mapposx / BLOCKWIDTH + HALFBITMAPBLOCKSPERROW; mapy = mapposx & (NUMSTEPS - 1); x = ROUND2BLOCKWIDTH(videoposx); y = mapy * BLOCKPLANELINES; DrawBlock(x,y,mapx,mapy); DrawBlock(x + HALFBITMAPWIDTH,y,mapx,mapy); mapposx++; videoposx = mapposx % HALFBITMAPWIDTH; } static void CheckJoyScroll(void) { WORD i,count; if (JoyFire()) count = 8; else count = 1; if (JoyLeft()) { for (i = 0; i < count; i++) ScrollLeft(); } if (JoyRight()) { for (i = 0; i < count; i++) ScrollRight(); } } static void UpdateCopperlist(void) { ULONG pl; WORD xpos,planeaddx,scroll,i; WORD *wp; i = fetchinfo[options.fetchmode].scrollpixels; xpos = videoposx + i - 1; planeaddx = (xpos / i) * (i / 8); i = (i - 1) - (xpos & (i - 1)); scroll = (i & 15) * 0x11; if (i & 16) scroll |= (0x400 + 0x4000); if (i & 32) scroll |= (0x800 + 0x8000); // set scroll register in BPLCON1 CopBPLCON1[1] = scroll; // set plane pointers wp = CopPLANE1H; for (i = 0;i < BLOCKSDEPTH;i++) { pl = ((ULONG)ScreenBitmap->Planes[i]) + planeaddx; wp[1] = (WORD)(pl >> 16); wp[3] = (WORD)(pl & 0xFFFF); wp += 4; } } static void ShowWhatCopperWouldDo(void) { SetWriteMask(ScreenRastPort,1); SetAPen(ScreenRastPort,0); RectFill(ScreenRastPort,0,BITMAPHEIGHT + 1,BITMAPWIDTH - 1,BITMAPHEIGHT + 1); SetAPen(ScreenRastPort,1); RectFill(ScreenRastPort,videoposx + BLOCKWIDTH,BITMAPHEIGHT + 1, videoposx + BLOCKWIDTH + SCREENWIDTH - 1,BITMAPHEIGHT + 1); } static void MainLoop(void) { if (!options.how) { // activate copperlist HardWaitBlit(); WaitVBL(); custom->copjmp2 = 0; } while (!LMBDown()) { if (!options.how) { WaitVBeam(199); WaitVBeam(200); } else Delay(1); if (options.speed) *(WORD *)0xdff180 = 0xFF0; CheckJoyScroll(); if (options.speed) *(WORD *)0xdff180 = 0xF00; if (!options.how) UpdateCopperlist(); else ShowWhatCopperWouldDo(); } } /********************* MAIN *************************/ int main(int argc, char **argv) { BOOL res = get_arguments(&options, s); if (!res) Cleanup(s); res = read_level_map(&level_map, s); if (!res) Cleanup(s); BlocksBitmap = read_blocks(colors, s); if (!BlocksBitmap) Cleanup(s); blocksbuffer = BlocksBitmap->Planes[0]; OpenDisplay(); if (!options.how) { Delay(2*50); KillSystem(); InitCopperlist(); } FillScreen(); MainLoop(); if (!options.how) ActivateSystem(); Cleanup(0); return 0; }