// BGEDIT - Background Map Editor v1.2 (c)1998 James Shaughnessy // // Edits upto 512x512 cell BgMaps (defaults to 256x256) // // Uses input cellfile of 16x16 16x16 cells (256x256x8-bit) // Output mapfile ncellw*ncellh cell index array (ncellw*ncellh x 8-bit) // // Effective playarea upto 8192x8192 pixels (default 4096x4096) // with 256 different celltypes // // See enclosed README.TXT for full details of use // // You are only permitted to alter and recompile this source for your own // personal use, and can NOT distribute any altered versions without prior // permission from me. Let me know if you find it useful or have any // suggestions for future updates (thanks go to Robert Swan for his input) // // Cheers, // Jim (c)23rd July 1998 // ----------------------------------------- // James Shaughnessy james@manc.u-net.com // http://www.netyaroze-europe.com/~shaughnj // ----------------------------------------- #include #include "pad.h" // Debug text flag //#define DEBUG #define OT_LENGTH (1) #define NUM_SPRITES (256) #define MAP_ADDR (0x80090000) #define CELLS_ADDR (0x800d0000) #define SCREENW (320) #define SCREENH (256) #define MAX_NCELLW (512) // Maximum legal size #define MAX_NCELLH (512) // Actual size is variable #define NUMCELLS (256) // 'ncellw' and 'ncellh' #define FALSE (0) #define TRUE (1) struct COORD { u_short x, y; u_long type; u_short xold, yold; // Used for undo } cellcoord, mapcoord; // Global Variables int activeBuff; int hsyncs; u_long padStatus, padStatus2, tmppadStatus; u_long timer = 0; u_long flash = 0; long mode = 0; long oldmode = 0; long menuitem; long drawStuff = 3; // Draw coords (bit1) and icon (bit2) long quit = FALSE; // Exit flag u_short ncellw = 256; u_short ncellh = 256; // Actual map size width and height extern DISPENV GsDISPENV; // Allow full 256 PAL lines GsCELL gscell[NUMCELLS]; GsMAP gsmap; GsBG gsbg; u_short map[MAX_NCELLW*MAX_NCELLH]; GsSPRITE cellsSprite; // Cell selector sprite (all cells) GsSPRITE activecell; // Active cell icon (double size) GsSPRITE crosshair; // Hard-coded crosshair sprite (4x17 pixels (=68) on FB at 896,256) u_short crosshairdata[68] = { 4369, 1, 4096, 4369, 1, 0, 0, 4096, 1, 0, 0, 4096, 1, 0, 0, 4096, 1, 0, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 4096, 1, 0, 0, 4096, 1, 0, 0, 4096, 1, 0, 0, 4096, 4369, 1, 4096, 4369, 0, 31, 0, 0 }; //Shadow boxes GsBOXF boxfcell = {(1<<30), 268, 204, 35, 35, 0, 0, 0}; GsBOXF boxfcoord = {(1<<30), 19, 18, 72, 12, 0, 0, 0}; GsBOXF boxftext = {(1<<30), 56, 55, 192, 160, 0, 0, 0}; GsBOXF boxfmenuitem = {(1<<30), 70, 0, 160, 12, 224, 0, 0}; // Background colour gradation GsGLINE gline = {0, 0, 0, 319, 0, 0, 0, 0, 0, 0, 0}; // BG work base primitive area u_long bgworkbase[(((SCREENW/16+1)*(SCREENH/16+2)*6+4)*2+2)]; // Two Ordering Tables, one for each buffer GsOT WorldOT[2]; // Two Ordering Table Tags, one for each buffer GsOT_TAG OTTag[2][1< 20)) && (!(timer%5)))) padStatus2 = padStatus; activeBuff = GsGetActiveBuff(); // Set packet work base GsSetWorkBase((PACKET *)GpuPacketArea[activeBuff]); // Clear the Ordering Table GsClearOt(0, 0, &WorldOT[activeBuff]); DoPadTests(); SetCrosshair(); DrawOnscreenStuff(); DrawGradientBg(); #ifdef DEBUG FntPrint("\n\n\n\nHSyncs = %d\n\n", hsyncs); FntPrint("\nscrollx = %d\nscrolly = %d\n", gsbg.scrollx, gsbg.scrolly); #endif FntFlush(-1); // Wait for end of drawing, a vertical blank then swap buffers DrawSync(0); hsyncs = VSync(0); GsSwapDispBuff(); // Register Clear in OT GsSortClear(0, 0, 0, &WorldOT[activeBuff]); // Draw the Ordering Table GsDrawOt(&WorldOT[activeBuff]); flash++; timer++; // Update timers } ResetGraph(0); } // Set, clear or undo setting of current map cell void SetMapCell() { mapcoord.type = map[mapcoord.x + (mapcoord.y*ncellw)]; cellcoord.type = cellcoord.x + (cellcoord.y<<4); if (cellcoord.type) map[mapcoord.x + (mapcoord.y*ncellw)] = cellcoord.type; else map[mapcoord.x + (mapcoord.y*ncellw)] = 0xffff; mapcoord.xold = mapcoord.x; mapcoord.yold = mapcoord.y; } void CopyMapCell() { u_short type = map[mapcoord.x + (mapcoord.y*ncellw)]; if (type != 0xffff) { cellcoord.x = type%16; cellcoord.y = (type>>4); } else { cellcoord.x = 0; cellcoord.y = 0; } } void UndoMapCell() { u_short tmptype = mapcoord.type; mapcoord.type = map[mapcoord.xold + (mapcoord.yold*ncellw)]; if (mapcoord.type) map[mapcoord.xold + (mapcoord.yold*ncellw)] = tmptype; else map[mapcoord.xold + (mapcoord.yold*ncellw)] = 0xffff; mapcoord.x = mapcoord.xold; mapcoord.y = mapcoord.yold; } // Initializes user variables void InitVariables() { mapcoord.x = ncellw/2; mapcoord.y = ncellh/2; mapcoord.xold = mapcoord.x; mapcoord.yold = mapcoord.y; mapcoord.type = map[mapcoord.x + (mapcoord.y * ncellw)]; cellcoord.x = 7; cellcoord.y = 7; cellcoord.type = cellcoord.x + (cellcoord.y<<4); gsbg.scrollx = (mapcoord.x<<4) - SCREENW/2; gsbg.scrolly = (mapcoord.y<<4) - SCREENH/2; } // Sets position of the crosshair, and moves if necessary void SetCrosshair() { // Set sprite brightness crosshair.r = abs(((flash%33)<<3)-128); // Make sure crosshair is not moved off the screen // Move smoothly. Nice. if (crosshair.x < 0) gsbg.scrollx += (crosshair.x>>1); else if (crosshair.x > (SCREENW-16)) gsbg.scrollx += ((crosshair.x-(SCREENW-16))>>1); if (crosshair.y < 0) gsbg.scrolly += (crosshair.y>>1); else if (crosshair.y > (SCREENH-16)) gsbg.scrolly += ((crosshair.y-(SCREENH-16))>>1); switch (mode) { case 0 : if (padStatus & PADR2) padStatus2 = padStatus; else if (padStatus & PADR1) padStatus2 = 0; if (padStatus2 & PADleft) if (mapcoord.x) mapcoord.x--; else mapcoord.x = ncellw - 1; if (padStatus2 & PADright) if (mapcoord.x != ncellw-1) mapcoord.x++; else mapcoord.x = 0; if (padStatus2 & PADup) if (mapcoord.y) mapcoord.y--; else mapcoord.y = ncellh - 1; if (padStatus2 & PADdown) if (mapcoord.y != ncellh-1) mapcoord.y++; else mapcoord.y = 0; crosshair.x = (mapcoord.x<<4) - gsbg.scrollx; crosshair.y = (mapcoord.y<<4) - gsbg.scrolly; // Ensure map cell selection is in new legal range if (mapcoord.x >= ncellw) mapcoord.x = ncellw-1; if (mapcoord.y >= ncellh) mapcoord.y = ncellh-1; break; case 1 : if (padStatus2 & PADleft) if (cellcoord.x) cellcoord.x--; else cellcoord.x = 15; if (padStatus2 & PADright) if (cellcoord.x != 15) cellcoord.x++; else cellcoord.x = 0; if (padStatus2 & PADup) if (cellcoord.y) cellcoord.y--; else cellcoord.y = 15; if (padStatus2 & PADdown) if (cellcoord.y != 15) cellcoord.y++; else cellcoord.y = 0; crosshair.x = 32 + (cellcoord.x<<4); crosshair.y = (cellcoord.y<<4); break; default : crosshair.x = (mapcoord.x<<4) - gsbg.scrollx; crosshair.y = (mapcoord.y<<4) - gsbg.scrolly; break; } // Sort crosshair in OT GsSortFastSprite(&crosshair, &WorldOT[activeBuff], 0); } // Scrolls Bgmap if necessary void ScrollBg() { int scroll; // Set scroll if (!mode && padStatus & (PADR1 | PADR2)) { if (padStatus & PADR2) scroll = 16; else scroll = 4; if (padStatus & PADup) gsbg.scrolly-=scroll; if (padStatus & PADdown) gsbg.scrolly+=scroll; if (padStatus & PADleft) gsbg.scrollx-=scroll; if (padStatus & PADright) gsbg.scrollx+=scroll; } } // Initialise Background map void InitBg() { RECT r; GsIMAGE im; int i; GsGetTimInfo((u_long *)CELLS_ADDR+1, &im); r.x = im.px; r.y = im.py; r.w = im.pw; r.h = im.ph; LoadImage(&r, im.pixel); r.x = im.cx; r.y = im.cy; r.w = im.cw; r.h = im.ch; LoadImage(&r, im.clut); DrawSync(0); for (i=0; i < NUMCELLS; i++) { gscell[i].u = ((i%16)<<4); gscell[i].v = ((i/16)<<4); gscell[i].cba = GetClut(im.cx, im.cy); gscell[i].tpage = GetTPage(im.pmode, 0, im.px, im.py); } gsmap.cellw = 16; gsmap.cellh = 16; gsmap.ncellw = ncellw; gsmap.ncellh = ncellh; gsmap.base = gscell; gsmap.index = map; gsbg.attribute = (im.pmode<<24); gsbg.x = 0; gsbg.y = 0; gsbg.w = SCREENW; gsbg.h = SCREENH; gsbg.scrollx = 0; gsbg.scrolly = 0; gsbg.r = gsbg.g = gsbg.b = 128; gsbg.map = &gsmap; GsInitFixBg16(&gsbg, bgworkbase); // Initialize cellsSprite - cell selector sprite cellsSprite.attribute = (im.pmode<<24); cellsSprite.x = 32; cellsSprite.y = 0; cellsSprite.w = 256; cellsSprite.h = 256; cellsSprite.tpage = GetTPage(im.pmode, 0, im.px, im.py); cellsSprite.u = 0; cellsSprite.v = 0; cellsSprite.cx = im.cx; cellsSprite.cy = im.cy; cellsSprite.r = cellsSprite.g = cellsSprite.b = 128; cellsSprite.mx = 0; cellsSprite.mx = 0; cellsSprite.scalex = ONE; cellsSprite.scaley = ONE; cellsSprite.rotate = 0; activecell.attribute = (im.pmode<<24) + (1<<27) + (1<<30); // Translucent activecell.x = 270; activecell.y = 206; activecell.w = 16; activecell.h = 16; activecell.tpage = GetTPage(im.pmode, 0, im.px, im.py); activecell.u = 0; activecell.v = 0; activecell.cx = im.cx; activecell.cy = im.cy; activecell.r = activecell.g = activecell.b = 128; activecell.mx = 0; activecell.mx = 0; activecell.scalex = 8191; activecell.scaley = 8191; activecell.rotate = 0; // Initialize crosshair sprite r.x = 896; r.y = 256; r.w = 4; r.h = 17; LoadImage(&r, (u_long *)crosshairdata); DrawSync(0); crosshair.attribute = 0; // 4-bit CLUT crosshair.x = 160; crosshair.y = 128; crosshair.w = 16; crosshair.h = 16; crosshair.tpage = GetTPage(0, 0, 896, 256); crosshair.u = 0; crosshair.v = 0; crosshair.cx = 896; crosshair.cy = 256+16; crosshair.r = crosshair.g = crosshair.b = 128; crosshair.mx = crosshair.mx = 0; crosshair.scalex = ONE; crosshair.scaley = ONE; crosshair.rotate = 0; // Loads map data from MAP_ADDR into map[] array by default LoadMapData(); } // Saves map data (map.dat) from map[] array to MAP_ADDR void SaveMapData() { int i; u_char *pmap = (u_char *)MAP_ADDR; // NULL cell (transparent) map[i] = 0xffff // This is taken as cell index ZERO // Set map array to that of mapfile for (i = 0; i < (MAX_NCELLW*MAX_NCELLH); i++) { if (map[i] != 0xffff) pmap[i] = map[i]; else pmap[i] = 0; } } // Loads map data (map.dat) from MAP_ADDR into map[] array void LoadMapData() { int i; u_char *pmap = (u_char *)MAP_ADDR; // NULL cell (transparent) map[i] = 0xffff // This is set as index ZERO in map.dat // Set map array to that of mapfile for (i = 0; i < (MAX_NCELLW*MAX_NCELLH); i++) { if (pmap[i]) map[i] = pmap[i]; else map[i] = 0xffff; } } // Clears map data // Sets all indices to currently selected cell void ClearMapData() { int i; cellcoord.type = cellcoord.x + (cellcoord.y<<4); if (cellcoord.type) for (i = 0; i < (MAX_NCELLW*MAX_NCELLH); i++) map[i] = cellcoord.type; else for (i = 0; i < (MAX_NCELLW*MAX_NCELLH); i++) map[i] = 0xffff; } // Draws editor background (coloured gradient) to show NULL cells void DrawGradientBg() { int i; for (i=0; i < SCREENH; i++) { gline.r0 = (i>>1); gline.g1 = gline.r0; gline.b1 = 128 - gline.g1; gline.y0 = i; gline.y1 = i; GsSortGLine(&gline, &WorldOT[activeBuff], 1); } } // Draws on-screen info: current active cell sprite and/or map coords void DrawOnscreenStuff() { activecell.u = (cellcoord.x<<4); activecell.v = (cellcoord.y<<4); // Print map cell coordinates if (!mode && (drawStuff & 1)) { FntPrint("(%3d,%3d)\n", mapcoord.x, mapcoord.y); GsSortBoxFill(&boxfcoord, &WorldOT[activeBuff], 0); } if (drawStuff & 2) { GsSortSprite(&activecell, &WorldOT[activeBuff], 0); GsSortBoxFill(&boxfcell, &WorldOT[activeBuff], 0); } } // Test PAD buttons and act upon accordingly void DoPadTests() { // Toggle drawStuff (onscreen info variable) if (padStatus2 & PADselect) if (++drawStuff > 3) drawStuff = 0; // Exit menu with start, triangle, or cross if ( padStatus2 & PADstart || (mode == 2 && (padStatus2 & PADtriangle || (menuitem == 0 && (padStatus & PADcross) ))) ) if (mode == 2) { mode = 0; padStatus2 = 0; } else { mode = 2; menuitem = 0; } // Cell selector display if (padStatus & PADcircle) { if (mode != 1) oldmode = mode; mode = 1; } else { if (mode == 1) mode = oldmode; } switch (mode) { case 0 : ScrollBg(); if (padStatus2 & PADcross) SetMapCell(); if (padStatus2 & PADsquare) CopyMapCell(); if (padStatus2 & PADtriangle) UndoMapCell(); GsSortFixBg16(&gsbg, bgworkbase, &WorldOT[activeBuff], 1); break; case 1 : GsSortFastSprite(&cellsSprite, &WorldOT[activeBuff], 1); break; case 2 : FntPrint("\n\n\n\n\n\n BGEDIT v1.2 (c)1998\n\n by James Shaughnessy\n\n\n Back\n\n Save Map\n\n Load Map\n\n Clear to current\n\n"); FntPrint(" Map Size: %3d %3d\n %3dK = %5xh\n\n Quit\n", ncellw, ncellh, (ncellw*ncellh>>10), ncellw*ncellh); // Bar colour if (padStatus & PADcross) boxfmenuitem.g = boxfmenuitem.b = 0; else boxfmenuitem.g = 128; if (padStatus2 & PADcross) { switch (menuitem) { case 1 : SaveMapData(); break; case 2 : LoadMapData(); break; case 3 : ClearMapData(); break; case 4 : if (padStatus2 & PADleft) if (ncellw > 1) ncellw--; if (padStatus2 & PADright) if (ncellw < MAX_NCELLW) ncellw++; if (padStatus2 & PADup) if (ncellh > 1) ncellh--; if (padStatus2 & PADdown) if (ncellh < MAX_NCELLH) ncellh++; gsmap.ncellw = ncellw; gsmap.ncellh = ncellh; break; case 5 : quit = TRUE; break; default : break; } } else { if (padStatus2 & PADdown) if (++menuitem > 5) menuitem = 0; if (padStatus2 & PADup) if (--menuitem < 0) menuitem = 5; } // Reset to normal height (if case 4, need two lines) boxfmenuitem.h = 12; switch (menuitem) { case 0 : boxfmenuitem.y = 106; break; case 1 : boxfmenuitem.y = 122; break; case 2 : boxfmenuitem.y = 138; break; case 3 : boxfmenuitem.y = 154; break; case 4 : boxfmenuitem.y = 170; boxfmenuitem.h = 20; break; case 5 : boxfmenuitem.y = 194; break; default : break; } GsSortBoxFill(&boxfmenuitem, &WorldOT[activeBuff], 0); GsSortBoxFill(&boxftext, &WorldOT[activeBuff], 0); GsSortFixBg16(&gsbg, bgworkbase, &WorldOT[activeBuff], 1); break; default : break; } } // Initialises Video and the Frame Buffer void InitGraphics() { int i; // Setup graphics PAL 320x256 SetVideoMode(MODE_PAL); GsInitGraph(SCREENW, SCREENH, 4, 0, 0); GsDISPENV.screen.y = 20; GsDISPENV.screen.h = 256; GsDefDispBuff(0, 0, 0, 256); // Init Ordering Tables for (i = 0; i < 2; i++) { WorldOT[i].length = OT_LENGTH; WorldOT[i].org = OTTag[i]; GsClearOt(0, 0, &WorldOT[i]); } // Loads the font into Frame Buffer FntLoad(960, 256); // Font printing location FntOpen(18, 20, 240, 236, 0, 512); } // ****** PAD routines ****** // call once only in program initialisation void PadInit (void) { GetPadBuf(&bb0, &bb1); } // call once per VSync(0) // puts controller pad status into unsigned long integer // please refer to the manuals if you want explanation // of the internals of this function u_long PadRead(void) { return(~(*(bb0+3) | *(bb0+2) << 8 | *(bb1+3) << 16 | *(bb1+2) << 24)); }