SegaRaycast/src/main.c

269 lines
6.8 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 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);
drawMap();
VDP_setTextPlane(BG_B);
VDP_setTextPalette(2);
VDP_showFPS(1);
for(int i = 0; i < 50; i++){
castRay(10);
}
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;
}