#include #include "sinTable.h" #include "cosTable.h" #define TABLE_LENGTH 720 #define SPEED 5 #define FRAC_BITS 8 #define TILE_WIDTH 8 #define TILE_HEIGHT 8 #define TILE_SIZE (TILE_WIDTH * TILE_HEIGHT / 2) #define SCREEN_WIDTH 320 #define SCREEN_HEIGHT 224 #define SCREEN_TILES_X 40 #define SCREEN_TILES_Y 28 #define TILE_EMPTY 0 #define TILE_FILLED 1 #define MAP_WIDTH 10 #define MAP_HEIGHT 10 Line l; s16 angle = 0; s16 x, y; u8 tileBuffer[TILE_SIZE]; u16 tileIndex = 0; const u8 map[10][10] = {{1,1,1,1,1,1,1,1,1,1}, {1,0,0,0,0,0,0,0,0,1}, {1,1,1,1,0,0,1,1,1,1}, {1,0,0,1,0,0,1,0,0,1}, {1,0,0,0,0,0,1,0,0,1}, {1,0,0,1,0,0,1,1,0,1}, {1,1,1,1,0,0,1,0,0,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,1,0,0,1}, {1,1,1,1,1,1,1,1,1,1}}; int dist(int ax, int ay, int bx, int by){ return (ax-bx)*(ax-bx) + (ay-by)*(ay-by); } void castRay(s16 angle){ if(angle >= 360) angle = angle - 360; if(angle < 0) angle = 360 + angle; u16 r,mx,my,mp,dof; s16 rx,ry,ra,xo,yo; s16 dy = sinTable[angle << 1]; s16 dx = cosTable[angle << 1]; s16 tan = 0; if(dx != 0) tan = (dy << FRAC_BITS)/dx; s16 aTan = 0; if(tan != 0) aTan = -(1 << (FRAC_BITS*2))/tan; s16 threshold = (20 << FRAC_BITS); if(aTan > threshold){ aTan = threshold; } if(aTan < -threshold){ aTan = -threshold; } dof = 0; s16 distH = 30000; s16 hx = l.pt1.x << FRAC_BITS; s16 hy = l.pt1.y << FRAC_BITS; if(dy == 0){ rx = l.pt1.x << FRAC_BITS; ry = l.pt1.y << FRAC_BITS; dof = 8; }else { if(angle > 180) { ry = ((l.pt1.y / 10 * 10)-1) << FRAC_BITS; rx = (((l.pt1.y - (ry >> FRAC_BITS))*aTan)) + (l.pt1.x << FRAC_BITS); yo = -(10 << FRAC_BITS); xo = ((-yo >> FRAC_BITS)*aTan); } if(angle < 180) { ry = ((l.pt1.y / 10 * 10)+10) << FRAC_BITS; rx = (((l.pt1.y - (ry >> FRAC_BITS))*aTan)) + (l.pt1.x << FRAC_BITS); yo = 10 << FRAC_BITS; xo = (-(yo >> FRAC_BITS)*aTan); } } while(dof<8){ mx = (rx >> FRAC_BITS) / 10; my = (ry >> FRAC_BITS) / 10; if(rx < 0 || ry < 0){ dof = 8; continue; } if(mx < 10 && my < 10 && map[my][mx] == 1){ dof = 8; hx = rx; hy = ry; distH = dist(l.pt1.x, l.pt1.y, rx >> FRAC_BITS, ry >> FRAC_BITS); }else{ rx = rx + xo; ry = ry + yo; dof += 1; } } dof = 0; s16 distV = 30000; s16 vx = l.pt1.x << FRAC_BITS; s16 vy = l.pt1.y << FRAC_BITS; s16 nTan = -tan; threshold = (20 << FRAC_BITS); if(nTan > threshold){ nTan = threshold; } if(nTan < -threshold){ nTan = -threshold; } if(angle > 90 && angle < 270) { // Facing Left rx = ((l.pt1.x / 10 * 10)-1) << FRAC_BITS; ry = (((l.pt1.x) - (rx >> FRAC_BITS))*nTan) + (l.pt1.y << FRAC_BITS); xo = -(10 << FRAC_BITS); yo = ((-xo >> FRAC_BITS)*nTan); } if(angle < 90 || angle > 270) { // Facing Right rx = ((l.pt1.x / 10 * 10)+10) << FRAC_BITS; ry = (((l.pt1.x) - (rx >> FRAC_BITS))*nTan) + (l.pt1.y << FRAC_BITS); xo = 10 << FRAC_BITS; yo = -(xo >> FRAC_BITS)*nTan; } if(dx == 0){ rx = l.pt1.x << FRAC_BITS; ry = l.pt1.y << FRAC_BITS; xo = 0; yo = 0; dof = 8; } while(dof<8){ mx = (rx >> FRAC_BITS) / 10; my = (ry >> FRAC_BITS) / 10; if(rx < 0 || ry < 0){ dof = 8; continue; } if(mx < 10 && my < 10 && map[my][mx] == 1){ dof = 8; vx = rx; vy = ry; distV = dist(l.pt1.x, l.pt1.y, rx >> FRAC_BITS, ry >> FRAC_BITS); }else{ rx = rx + xo; ry = ry + yo; dof += 1; } } if(distV < distH){ l.pt2.x = vx >> FRAC_BITS; l.pt2.y = vy >> FRAC_BITS; }else { l.pt2.x = hx >> FRAC_BITS; l.pt2.y = hy >> FRAC_BITS; } } void initTileBuffer(u8 color) { u8 colorValue = (color << 4) | color; // Color for both nibbles for (int i = 0; i < TILE_SIZE; i++) { tileBuffer[i] = colorValue; } } void uploadTileDataToVRAM(u16 vramTileIndex) { VDP_loadTileData(tileBuffer, vramTileIndex, 1, DMA); // Load 1 tile to VRAM } void mapscan() { u8 mapcolor = 12; // map color mapcolor |= mapcolor << 4; for (u8 x = 0; x < 10; x++) { for (u8 y = 0; y < 10; y++) { if (map[y][x] == 1) { // Draw a filled tile for the map block for (u8 px = 0; px < TILE_WIDTH; px++) { for (u8 py = 0; py < TILE_HEIGHT; py++) { setPixelInBuffer(px, py, mapcolor); } } // Upload the filled tile to VRAM uploadTileDataToVRAM(tileIndex); VDP_setTileMapXY(VDP_BG_A, tileIndex, x, y); } } } } void clearScreenWithTile(u16 tileIndex) { // Fill the entire screen with the background tile VDP_fillTileMapRect(BG_A, TILE_ATTR_FULL(PAL1, 0, FALSE, FALSE, tileIndex), 0, 0, SCREEN_TILES_X, SCREEN_TILES_Y); } void drawMap() { for (u16 y = 0; y < MAP_HEIGHT; y++) { for (u16 x = 0; x < MAP_WIDTH; x++) { u8 tileType = map[y][x] ? TILE_FILLED : TILE_EMPTY; VDP_setTileMapXY(BG_A, TILE_ATTR_FULL(PAL1, 0, FALSE, FALSE, tileType), x, y); } } } void render() { clearScreenWithTile(TILE_EMPTY); initTileBuffer(12); // map color uploadTileDataToVRAM(TILE_FILLED); initTileBuffer(0); // background color uploadTileDataToVRAM(TILE_EMPTY); drawMap(); VDP_setTextPlane(BG_B); VDP_setTextPalette(2); VDP_showFPS(0); SYS_doVBlankProcess(); } void update() { u16 joy = JOY_readJoypad(JOY_1); if (joy & BUTTON_LEFT) { angle -= 1; } if (joy & BUTTON_RIGHT) { angle += 1; } if (joy & BUTTON_UP) { s16 ind = (int)((float)angle / 360.0f * 1024.0f); fix16 dy = sinFix16(ind); fix16 dx = cosFix16(ind); y += fix16ToInt(fix16Mul(dy, FIX16(SPEED))); x += fix16ToInt(fix16Mul(dx, FIX16(SPEED))); } if (joy & BUTTON_DOWN) { s16 ind = (int)((float)angle / 360.0f * 1024.0f); fix16 dy = sinFix16(ind); fix16 dx = cosFix16(ind); y -= fix16ToInt(fix16Mul(dy, FIX16(SPEED))); x -= fix16ToInt(fix16Mul(dx, FIX16(SPEED))); } } void initVDP() { SYS_disableInts(); VDP_setPlaneSize(64, 32, TRUE); SYS_enableInts(); } int main() { SYS_disableInts(); VDP_setPlaneSize(64, 32, TRUE); SYS_enableInts(); PAL_setColor(14, RGB24_TO_VDPCOLOR(0x0000ff)); PAL_setColor(15, RGB24_TO_VDPCOLOR(0xff0000)); VDP_setBackgroundColor(14); // Initialize and upload tile data for TILE_EMPTY and TILE_FILLED initTileBuffer(12); // Color for TILE_FILLED VDP_loadTileData(tileBuffer, TILE_FILLED, 1, DMA); initTileBuffer(0); // Color for TILE_EMPTY VDP_loadTileData(tileBuffer, TILE_EMPTY, 1, DMA); while (TRUE) { render(); } return 0; }