323 lines
8.6 KiB
C
323 lines
8.6 KiB
C
#include <genesis.h>
|
|
#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 TILE_GREEN 4
|
|
#define MAP_WIDTH 10
|
|
#define MAP_HEIGHT 10
|
|
#define WALL_HEIGHT_SCALE FIX16(1)
|
|
|
|
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, s16 column){
|
|
if(angle >= 360) angle = angle - 360;
|
|
if(angle < 0) angle = 360 + angle;
|
|
u16 r,mx,my,mp,dof;
|
|
fix16 rx,ry,ra,xo,yo;
|
|
s16 ind = (int)((float)angle/360.0f*1024.0f);
|
|
fix16 dy = sinFix16(ind);
|
|
fix16 dx = cosFix16(ind);
|
|
fix16 tan = FIX16(0);
|
|
if(dx != 0) tan = fix16Div(dy, dx);
|
|
fix16 aTan = FIX16(0);
|
|
if(tan != 0) aTan = fix16Div(FIX16(-1), tan);
|
|
s16 tanInt = fix16ToInt(fix16Mul(aTan, FIX16(100)));
|
|
dof = 0;
|
|
fix16 distH = FIX16(500);
|
|
fix16 hx = FIX16(l.pt1.x);
|
|
fix16 hy = FIX16(l.pt1.y);
|
|
if(dy == 0){
|
|
rx = FIX16(l.pt1.x);
|
|
ry = FIX16(l.pt1.y);
|
|
dof = 8;
|
|
}else {
|
|
if(angle > 180) {
|
|
ry = FIX16(l.pt1.y / 10 * 10)-FIX16(1);
|
|
rx = fix16Mul(FIX16(l.pt1.y) - ry,aTan) + FIX16(l.pt1.x);
|
|
yo = FIX16(-10);
|
|
xo = fix16Mul(0-yo,aTan);
|
|
}
|
|
if(angle < 180) {
|
|
ry = FIX16((l.pt1.y / 10 * 10)+10);
|
|
rx = fix16Mul(FIX16(l.pt1.y) - ry,aTan) + FIX16(l.pt1.x);
|
|
yo = FIX16(10);
|
|
xo = fix16Mul(0-yo,aTan);
|
|
}
|
|
}
|
|
while(dof<8){
|
|
mx = fix16ToInt(rx) / 10;
|
|
my = fix16ToInt(ry) / 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, fix16ToInt(rx), fix16ToInt(ry));
|
|
}else{
|
|
rx = rx + xo;
|
|
ry = ry + yo;
|
|
dof += 1;
|
|
}
|
|
}
|
|
|
|
dof = 0;
|
|
fix16 distV = FIX16(500);
|
|
fix16 vx = FIX16(l.pt1.x);
|
|
fix16 vy = FIX16(l.pt1.y);
|
|
fix16 nTan = 0-tan;
|
|
if(fix16ToInt(nTan) > 51){
|
|
nTan = FIX16(51);
|
|
}
|
|
if(fix16ToInt(nTan) < -51){
|
|
nTan = FIX16(-51);
|
|
}
|
|
if(angle > 90 && r < 270) {
|
|
rx = FIX16(l.pt1.x / 10 * 10)-FIX16(1);
|
|
ry = fix16Mul(FIX16(l.pt1.x) - rx,nTan) + FIX16(l.pt1.y);
|
|
xo = FIX16(-10);
|
|
yo = fix16Mul(0-xo,nTan);
|
|
}
|
|
if(angle < 90 || angle > 270) {
|
|
rx = FIX16((l.pt1.x / 10 * 10)+10);
|
|
ry = fix16Mul(FIX16(l.pt1.x) - rx,nTan) + FIX16(l.pt1.y);
|
|
xo = FIX16(10);
|
|
yo = fix16Mul(0-xo,nTan);
|
|
}
|
|
if(dx == 0){
|
|
rx = FIX16(l.pt1.x);
|
|
ry = FIX16(l.pt1.y);
|
|
xo = FIX16(0);
|
|
yo = FIX16(0);
|
|
dof = 8;
|
|
}
|
|
while(dof<8){
|
|
mx = fix16ToInt(rx) / 10;
|
|
my = fix16ToInt(ry) / 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, fix16ToInt(rx), fix16ToInt(ry));
|
|
}else{
|
|
rx = rx + xo;
|
|
ry = ry + yo;
|
|
dof += 1;
|
|
}
|
|
}
|
|
u8 tile = TILE_FILLED;
|
|
fix16 shortestDist = distH;
|
|
if(distV < distH){
|
|
shortestDist = distV;
|
|
l.pt2.x = fix16ToInt(vx);
|
|
l.pt2.y = fix16ToInt(vy);
|
|
tile = TILE_GREEN;
|
|
}else {
|
|
l.pt2.x = fix16ToInt(hx);
|
|
l.pt2.y = fix16ToInt(hy);
|
|
}
|
|
|
|
|
|
//Wall height calcs
|
|
shortestDist = fix16Sqrt(shortestDist);
|
|
//shortestDist = fix16Mul(dx, shortestDist);
|
|
if(shortestDist < 0){
|
|
shortestDist = -shortestDist;
|
|
}
|
|
fix16 wallHeightFix16 = fix16Div(FIX16(SCREEN_HEIGHT), (shortestDist + FIX16(1)));
|
|
wallHeightFix16 = fix16Mul(wallHeightFix16, WALL_HEIGHT_SCALE);
|
|
int wallHeight = fix16ToInt(wallHeightFix16);
|
|
int wallTop = (SCREEN_HEIGHT / 2) - (wallHeight / 2);
|
|
int wallBottom = (SCREEN_HEIGHT / 2) + (wallHeight / 2);
|
|
if (wallTop < 0) wallTop = 0;
|
|
if (wallBottom >= SCREEN_HEIGHT) wallBottom = SCREEN_HEIGHT - 1;
|
|
u16 tileTop = wallTop / TILE_HEIGHT;
|
|
u16 tileBottom = wallBottom / TILE_HEIGHT;
|
|
u16 tileHeight = tileBottom - tileTop + 1;
|
|
for (int yTile = 0; yTile <= SCREEN_TILES_Y; yTile++) {
|
|
if(yTile >= tileTop && yTile <= tileBottom){
|
|
VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, 0, FALSE, FALSE, tile), column, yTile);
|
|
}else{
|
|
VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, 0, FALSE, FALSE, TILE_EMPTY), column, yTile);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
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 = 15; // 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(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);
|
|
//VDP_fillTileMapRect(BG_B, 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() {
|
|
l.pt1.x = x;
|
|
l.pt1.y = y;
|
|
//clearScreenWithTile(TILE_EMPTY);
|
|
s16 castStart = angle - 20;
|
|
if(angle >= 360) angle = angle - 360;
|
|
if(angle < 0) angle = 360 + angle;
|
|
if(castStart >= 360) castStart = castStart - 360;
|
|
if(castStart < 0) castStart = 360 + castStart;
|
|
|
|
for(int i = 0; i < 40; i++){
|
|
s16 cast = castStart+i;
|
|
if(cast >= 360) cast = cast - 360;
|
|
if(cast < 0) cast = 360 + cast;
|
|
castRay(cast, i);
|
|
//VDP_waitVSync();
|
|
}
|
|
//drawMap();
|
|
VDP_setTextPlane(BG_A);
|
|
VDP_setTextPalette(2);
|
|
VDP_showFPS(1);
|
|
char debugCastText[20];
|
|
sprintf(debugCastText, "Cast: %03d", castStart);
|
|
VDP_drawText(debugCastText, 20, 2);
|
|
//angle = angle + 1;
|
|
|
|
|
|
SYS_doVBlankProcess();
|
|
}
|
|
|
|
void update() {
|
|
u16 joy = JOY_readJoypad(JOY_1);
|
|
if (joy & BUTTON_LEFT) {
|
|
angle -= 2;
|
|
}
|
|
if (joy & BUTTON_RIGHT) {
|
|
angle += 2;
|
|
}
|
|
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(13, RGB24_TO_VDPCOLOR(0x00ff00));
|
|
PAL_setColor(14, RGB24_TO_VDPCOLOR(0x1c1c14));
|
|
PAL_setColor(15, RGB24_TO_VDPCOLOR(0x17ffe8));
|
|
VDP_setBackgroundColor(14);
|
|
|
|
// Initialize and upload tile data for TILE_EMPTY and TILE_FILLED
|
|
initTileBuffer(15); // Color for TILE_FILLED
|
|
VDP_loadTileData(tileBuffer, TILE_FILLED, 1, DMA);
|
|
|
|
initTileBuffer(13); // Color for TILE_FILLED
|
|
VDP_loadTileData(tileBuffer, TILE_GREEN, 1, DMA);
|
|
|
|
initTileBuffer(0); // Color for TILE_EMPTY
|
|
VDP_loadTileData(tileBuffer, TILE_EMPTY, 1, DMA);
|
|
|
|
l.pt1.x = 15;
|
|
l.pt1.y = 15;
|
|
x = 15;
|
|
y = 15;
|
|
l.pt2.x = 0;
|
|
l.pt2.y = 0;
|
|
|
|
while (TRUE) {
|
|
render();
|
|
update();
|
|
}
|
|
|
|
return 0;
|
|
} |