#include "renderer.h" #include "screen.h" #include #define PI 3.14159265358979323846 #define PIH 1.57079632679489661923 #define PI2 6.28318530718 void init_camera(Camera* camera) { camera->x = 3; camera->y = 3; camera->angle = PI / 4; } typedef struct { float x, y; } v2; typedef struct { int x, y; } v2i; #define MOVE_SPEED 1 #define ROTATE_SPEED PI / 2 void update_camera(Camera* camera, Screen* screen) { double rotate = 0; if (key_pressed(screen, SDL_SCANCODE_LEFT)) rotate -= ROTATE_SPEED; if (key_pressed(screen, SDL_SCANCODE_RIGHT)) rotate += ROTATE_SPEED; rotate *= screen->delta; rotate += camera->angle; while (rotate >= PI2) rotate -= PI2; while (rotate < 0) rotate += PI2; camera->angle = rotate; v2 forward = { cos(camera->angle), sin(camera->angle) }; v2 left = { forward.y, -forward.x }; v2 move = { 0, 0 }; if (key_pressed(screen, SDL_SCANCODE_W)) { move.x += forward.x; move.y += forward.y; } if (key_pressed(screen, SDL_SCANCODE_S)) { move.x -= forward.x; move.y -= forward.y; } if (key_pressed(screen, SDL_SCANCODE_A)) { move.x += left.x; move.y += left.y; } if (key_pressed(screen, SDL_SCANCODE_D)) { move.x -= left.x; move.y -= left.y; } camera->x += move.x * MOVE_SPEED * screen->delta; camera->y += move.y * MOVE_SPEED * screen->delta; } #define MAP_SIZE 8 static uint8_t MAPDATA[MAP_SIZE * MAP_SIZE] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 3, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 2, 0, 4, 4, 0, 1, 1, 0, 0, 0, 4, 0, 0, 1, 1, 0, 3, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; static void verline(Screen* screen, int x, int y0, int y1, uint32_t color) { for (int y = y0; y <= y1; y++) { screen->pixels[(y * screen->width) + x] = color; } } static float v2_cross(v2 a, v2 b) { return fabs(a.x * b.y - a.y * b.x); } static float v2_len(v2 a) { return sqrt(a.x * a.x + a.y * a.y); } static float v2_square_dist(v2 a, v2 b) { return pow(a.x - b.x, 2) + pow(a.y - b.y, 2); } #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) #define sign(a) ((a) < 0 ? -1 : 1) #define value(x, y) (MAPDATA[(x) + MAP_SIZE * (y)]) void render(Screen* screen, const Camera* camera) { const double fov = PI / 3; const v2 cam_right = { -sin(camera->angle), cos(camera->angle) }; const v2 pos = { camera->x, camera->y }; for (int sx = 0; sx < screen->width; sx++) { const float xcam = (2 * (sx / (float) (screen->width))) - 1; const float change = fov * atan(xcam); const v2i move = { sign(cos(camera->angle + change)), sign(sin(camera->angle + change)), }; const v2i offset = { move.x == -1 ? 1 : 0, move.y == -1 ? 1 : 0 }; const float tanc = tan(camera->angle + change); const float cotc = tan(PIH - (camera->angle + change)); v2i posi = { (int)pos.x + offset.x, (int)pos.y + offset.y }; bool fx = false; uint32_t vx = 0; float x; while (!fx) { posi.y += move.y; x = cotc * (posi.y - pos.y) + pos.x; if (fabs(x) - pos.x >= MAP_SIZE) break; vx = value((int)x, posi.y - offset.y); if (vx != 0) { fx = true; } } bool fy = false; uint32_t vy = 0; float y; while (!fy) { posi.x += move.x; y = tanc * (posi.x - pos.x) + pos.y; if (fabs(y) - pos.y >= MAP_SIZE) break; vy = value(posi.x - offset.x, (int)y); if (vy != 0) { fy = true; } } uint32_t hit; if (!fx && !fy) { hit = 0; x = pos.x + 1000 * move.x; y = pos.y + 1000 * move.y; } else if (fx && !fy) { hit = vx; y = posi.y; } else if (fy && !fx) { hit = vy; x = posi.x; } else { const v2 posx = {x, posi.y}; const v2 posy = {posi.x, y}; if (v2_square_dist(posx, pos) < v2_square_dist(posy, pos)) { hit = vx; y = posi.y; } else { hit = vy; x = posi.x; } } const v2 relative = { x - pos.x, y - pos.y }; float len = v2_cross(relative, cam_right) / v2_len(cam_right); if (len < 0.00001) len = 0.00001; uint32_t color; switch (hit) { case 1: color = 0xFF0000FF; break; case 2: color = 0x00FF00FF; break; case 3: color = 0x0000FFFF; break; case 4: color = 0xFF00FFFF; break; case 5: color = 0x00FFFFFF; break; default: color = 0x000000FF; break; } const int h = (int) (screen->height / len), y0 = max((screen->height / 2) - (h / 2), 0), y1 = min((screen->height / 2) + (h / 2), screen->height - 1); verline(screen, sx, 0, y0, 0x202020FF); verline(screen, sx, y0, y1, color); verline(screen, sx, y1, screen->height - 1, 0x505050FF); } }