summaryrefslogtreecommitdiff
path: root/src/renderer.c
blob: c64be5112b07c0f4a4ab2a511820776677ed5657 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "renderer.h"
#include "screen.h"
#include "ray.h"

#include <math.h>
#include <string.h>


void init_camera(Camera* camera) {
    camera->pos.x = 3;
    camera->pos.y = 3;
    camera->angle = PI / 4;
}

static double fov = PI / 4;

#define MOVE_SPEED      1
#define ROTATE_SPEED    PI / 2
#define FOV_CHANGE_SPEED 1
#define PLAYER_SIZE .1

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;
    }

    if (key_pressed(screen, SDL_SCANCODE_EQUALS)) {
        fov += FOV_CHANGE_SPEED * screen->delta; 
    }

    if (key_pressed(screen, SDL_SCANCODE_MINUS)) {
        fov -= FOV_CHANGE_SPEED * screen->delta;
    }

    v2 hit_pos;
    bool movex, movey;

    cast_ray(camera->pos, sign(move.x) == 1 ? 0 : PI, &hit_pos);
    movex = v2_dist(hit_pos, camera->pos) > PLAYER_SIZE;

    cast_ray(camera->pos, sign(move.y) == 1 ? PIH : -PIH, &hit_pos);
    movey = v2_dist(hit_pos, camera->pos) > PLAYER_SIZE;

    if (movex) camera->pos.x += move.x * MOVE_SPEED * screen->delta;
    if (movey) camera->pos.y += move.y * MOVE_SPEED * screen->delta;
}

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;
    }
}

void render(Screen* screen, const Camera* camera) {

    const v2 cam_right = {
        -sin(camera->angle),
        cos(camera->angle)
    };

    for (int x = 0; x < screen->width; x++) {
        const float xcam = (2 * (x / (float) (screen->width))) - 1;
        const float change = fov * atan(xcam);
        const float theta = camera->angle + change;

        v2 hit_pos;
        uint32_t hit = cast_ray(camera->pos, theta, &hit_pos);

        hit_pos.x -= camera->pos.x;
        hit_pos.y -= camera->pos.y;

        float len = v2_cross(hit_pos, cam_right) / v2_len(cam_right);

        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, x, 0, y0, 0x202020FF);
        verline(screen, x, y0, y1, color);
        verline(screen, x, y1, screen->height - 1, 0x505050FF);
    }
}