--- /dev/null
+#include "game.h"
+#include "sdl.h"
+
+/* to be removed */
+#define M_PI 3.14159265358979323846
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* mostly from https://www.permadi.com/tutorial/raycast/rayc1.html */
+
+/* Distance from player to plane = (WIDTH/2)/tan(FOV/2) */
+/* Center = (WIDTH/2, HEIGHT/2) */
+/* Angle between rays = FOV/WIDTH */
+
+/*
+Degrees:
+ 90 0x4000
+ |
+0x8000 180---+---0 0x0000
+ |
+ 270 0xC000
+Cordinates:
+ (+y)
+ |
+(-x)---+---(+x)
+ |
+ (-y)
+*/
+#define ANGLE_0 (0x0000)
+#define ANGLE_90 (0x4000)
+#define ANGLE_180 (0x8000)
+#define ANGLE_270 (0xC000)
+
+/* TODO: made adjustable */
+/* #define FOV (90) */
+#define FOV (ANGLE_90)
+
+
+/* Y needs to be indexed as 9-y */
+int map[10][10] = {
+ {1,0,0,0,0,0,0,0,0,0},
+ {1,0,0,0,0,0,0,0,0,0},
+ {1,0,0,0,0,0,0,0,0,0},
+ {1,0,0,0,0,0,0,0,0,0},
+ {1,0,0,2,2,2,0,0,0,0},
+ {1,0,0,2,0,2,0,0,0,0},
+ {1,0,0,2,2,2,0,0,0,0},
+ {1,0,0,0,0,0,0,0,0,0},
+ {1,0,0,0,0,0,0,0,0,0},
+ {1,1,1,1,1,1,1,1,1,1},
+};
+/*
+int map[10][10] = {
+ {0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0},
+};*/
+
+/* 16 bit unsigned number */
+typedef unsigned short bam;
+
+input Input;
+
+struct player {
+ int x;
+ int y;
+ /* TODO: can prob make this work with any size int */
+ /* Needs to be 16bit binary angular measurement */
+ /* 45/8192 of a degree, 1/65536 of a turn */
+ /* 65536/2pi is 1 radian */
+ bam bearing;
+};
+typedef struct player player;
+player Player;
+
+struct ray {
+ int wall_type;
+ int distance;
+ int offset;
+};
+typedef struct ray ray;
+
+float bam_sin(bam bearing) {
+ return sin((bearing*M_PI)/32768);
+}
+float bam_cos(bam bearing) {
+ return cos((bearing*M_PI)/32768);
+}
+float bam_tan(bam bearing) {
+ return tan((bearing*M_PI)/32768);
+}
+
+void game_init(void) {
+ /* Player pos is also in units (TEXTURE_SIZE) */
+ Player.x = 129;
+ Player.y = 129;
+ /* 45 degrees */
+ /*Player.bearing = 8192;*/
+ Player.bearing = ANGLE_90/2;
+}
+
+/* https://www.permadi.com/tutorial/raycast/rayc7.html
+ * Horizontal intersections:
+ * dy = TEXTURE_SIZE
+ * tan(bearing) = TEXTURE_SIZE/dx
+ * dx = TEXTURE_SIZE/tan(bearing)
+*/
+ray *castRay(player *PlayerC, bam bearing) {
+ /* These need program lifetime, they are returned as pointers */
+ static ray Xray;
+ static ray Yray;
+ int y, x, dy, dx;
+
+ /* init */
+ Xray.wall_type = 0;
+ Yray.wall_type = 0;
+
+ /* TODO: force texture size to be a power of 2 and then have a macro for
+ * the bits needed to do * and / */
+
+ /* horizontal intersections */
+ if (bearing != ANGLE_0 && bearing != ANGLE_180) {
+ if (bearing > ANGLE_0 && bearing < ANGLE_180) {
+ /* facing up */
+ y = (PlayerC->y/TEXTURE_SIZE) * TEXTURE_SIZE + TEXTURE_SIZE;
+ dy = TEXTURE_SIZE;
+ } else {
+ /* facing down */
+ y = (PlayerC->y/TEXTURE_SIZE) * TEXTURE_SIZE - 1;
+ dy = -TEXTURE_SIZE;
+ }
+ if (bearing == ANGLE_90 || bearing == ANGLE_270) {
+ x = PlayerC->x;
+ dx = 0;
+ } else {
+ x = PlayerC->x + (y-PlayerC->y)/bam_tan(bearing);
+ dx = dy/bam_tan(bearing);
+ }
+
+ while(y/TEXTURE_SIZE >= 0 && y/TEXTURE_SIZE < 10 && x/TEXTURE_SIZE >= 0 && x/TEXTURE_SIZE < 10) {
+ if(map[9-(y/TEXTURE_SIZE)][x/TEXTURE_SIZE] != 0) {
+ /* TODO: actual fill out properly lol */
+ Xray.wall_type = map[9-(y/TEXTURE_SIZE)][x/TEXTURE_SIZE];
+ setColour(0xff,0xff,0);
+ drawLine2(PlayerC->x, PlayerC->y, x, y);
+ setColour(0,0xff,0xff);
+ break;
+ }
+ y+=dy;
+ x+=dx;
+ }
+ }
+
+ /* vertical intersections */
+ if (bearing != ANGLE_90 && bearing != ANGLE_270) {
+ if (bearing < ANGLE_90 || bearing > ANGLE_270) {
+ /* facing right */
+ x = (PlayerC->x/TEXTURE_SIZE) * TEXTURE_SIZE + TEXTURE_SIZE;
+ dx = TEXTURE_SIZE;
+ } else {
+ /* facing left */
+ x = (PlayerC->x/TEXTURE_SIZE) * TEXTURE_SIZE - 1;
+ dx = -TEXTURE_SIZE;
+ }
+ if (bearing == ANGLE_0 || bearing == ANGLE_180) {
+ y = PlayerC->y;
+ dy = 0;
+ } else {
+ y = PlayerC->y + (x-PlayerC->x)*bam_tan(bearing);
+ dy = dx*bam_tan(bearing);
+ }
+
+ while(y/TEXTURE_SIZE >= 0 && y/TEXTURE_SIZE < 10 && x/TEXTURE_SIZE >= 0 && x/TEXTURE_SIZE < 10) {
+ if(map[9-(y/TEXTURE_SIZE)][x/TEXTURE_SIZE] != 0) {
+ /* TODO: actual fill out properly lol */
+ Yray.wall_type = map[9-(y/TEXTURE_SIZE)][x/TEXTURE_SIZE];
+ setColour(0xff,0xff,0);
+ drawLine2(PlayerC->x, PlayerC->y, x, y);
+ setColour(0,0xff,0xff);
+ break;
+ }
+ y+=dy;
+ x+=dx;
+ }
+ }
+
+ if(Xray.wall_type != 0) {
+ return &Xray;
+ }
+ if(Yray.wall_type != 0) {
+ return &Xray;
+ }
+
+ return NULL;
+}
+
+void game_loop(void) {
+ int scanVector = Player.bearing+(FOV/2);
+ int i;
+ /* debug */
+ int x, y;
+
+ /* Handle Input */
+ Player.x += Input.xmove;
+ Player.y += Input.ymove;
+ Player.bearing += Input.yaw;
+ Input.xmove = 0;
+ Input.ymove = 0;
+ Input.yaw = 0;
+ Input.pitch = 0;
+
+ /* Render */
+ for (i=0;i<SCREEN_WIDTH;++i) {
+ int newVector = scanVector - i*FOV/SCREEN_WIDTH;
+ /* Debug */
+ drawLine2(Player.x, Player.y, Player.x+128*bam_cos(newVector), Player.y+128*bam_sin(newVector));
+ if(castRay(&Player, newVector) != NULL) {
+ drawLine(i, 20, 180);
+ }
+ //scanVector-=FOV/SCREEN_WIDTH;
+ }
+
+ /* Debug */
+ setColour(0xAA,0x00,0x00);
+ for (x = 0; x < 10; x++) {
+ for (y = 0; y < 10; y++) {
+ if (map[9-y][x]) {
+ /* Horizontal lines */
+ drawLine2(64*x, 64*y, 64*x+64, 64*y);
+ drawLine2(64*x, 64*y+64, 64*x+64, 64*y+64);
+ /* Vertical lines */
+ drawLine2(64*x, 64*y, 64*x, 64*y+64);
+ drawLine2(64*x+64, 64*y, 64*x+64, 64*y+64);
+ }
+ }
+ }
+ /* Actual Vector */
+ drawLine2(Player.x, Player.y, Player.x+128*bam_cos(Player.bearing), Player.y+128*bam_sin(Player.bearing));
+ /* FOV as a 2 vectors for min and max */
+ drawLine2(Player.x, Player.y, Player.x+128*bam_cos(Player.bearing-(FOV/2)), Player.y+128*bam_sin(Player.bearing-(FOV/2)));
+ drawLine2(Player.x, Player.y, Player.x+128*bam_cos(Player.bearing+(FOV/2)), Player.y+128*bam_sin(Player.bearing+(FOV/2)));
+ /* Box */
+ drawLine2(Player.x-20, Player.y-20, Player.x-20, Player.y+20);
+ drawLine2(Player.x-20, Player.y+20, Player.x+20, Player.y+20);
+ drawLine2(Player.x+20, Player.y+20, Player.x+20, Player.y-20);
+ drawLine2(Player.x+20, Player.y-20, Player.x-20, Player.y-20);
+
+}
--- /dev/null
+#include "sdl.h"
+#include "game.h"
+#include <SDL2/SDL.h>
+#include <stdio.h>
+
+SDL_Renderer *render;
+int w, h;
+
+int drawLine(int x, int y, int y2) {
+ return SDL_RenderDrawLine(render, x, y, x, y2);
+}
+int drawLine2(int x, int y, int x2, int y2) {
+ return SDL_RenderDrawLine(render, x, h-y, x2, h-y2);
+}
+
+int setColour(unsigned char r, unsigned char g, unsigned char b) {
+ return SDL_SetRenderDrawColor(render, r,g,b, 255);
+}
+
+int main(int argc, char *argv[]) {
+
+ SDL_Window *window;
+ SDL_Event event;
+ int quit = 0;
+
+ game_init();
+
+ /* SDL shit */
+ if(SDL_Init(SDL_INIT_VIDEO) == -1) {
+ puts(SDL_GetError());
+ return 1;
+ }
+ window = SDL_CreateWindow("Raycasting test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, 0);
+ if (window == NULL) {
+ puts(SDL_GetError());
+ return 1;
+ }
+ render = SDL_CreateRenderer(window, -1, 0);
+ if (render == NULL) {
+ puts(SDL_GetError());
+ return 1;
+ }
+
+ while(!quit) {
+ const Uint8 *KeyState;
+ while (SDL_PollEvent(&event)) {
+ if (event.type == SDL_QUIT) {
+ quit = 1;
+ }
+ }
+
+ /* Handle Inputs */
+ KeyState = SDL_GetKeyboardState(NULL);
+ if (KeyState[SDL_SCANCODE_W]) Input.ymove += 1;
+ if (KeyState[SDL_SCANCODE_S]) Input.ymove -= 1;
+ if (KeyState[SDL_SCANCODE_A]) Input.xmove -= 1;
+ if (KeyState[SDL_SCANCODE_D]) Input.xmove += 1;
+ if (KeyState[SDL_SCANCODE_LEFT]) Input.yaw += 20;
+ if (KeyState[SDL_SCANCODE_RIGHT]) Input.yaw -= 20;
+
+ SDL_GetRendererOutputSize(render, &w, &h);
+
+ SDL_SetRenderDrawColor(render, 0x00,0x00,0x00, 255);
+ SDL_RenderClear(render);
+ SDL_SetRenderDrawColor(render, 0x00,0xFF,0xFF, 255);
+ game_loop();
+ SDL_RenderPresent(render);
+ }
+
+ SDL_DestroyRenderer(render);
+ SDL_DestroyWindow(window);
+ SDL_Quit();
+
+ return 0;
+}
+