initial
This commit is contained in:
commit
2a88947f03
7 changed files with 457 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
bin
|
42
Makefile
Normal file
42
Makefile
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
CC = gcc
|
||||||
|
|
||||||
|
INCFLAGS = -Isrc
|
||||||
|
|
||||||
|
CCFLAGS = -std=c99 -Wall -Wextra -pedantic -O2
|
||||||
|
CCFLAGS += $(INCFLAGS)
|
||||||
|
|
||||||
|
LDFLAGS += $(INCFLAGS)
|
||||||
|
LDFLAGS += -lSDL2
|
||||||
|
LDFLAGS += -lm
|
||||||
|
|
||||||
|
BIN = bin
|
||||||
|
APP = $(BIN)/app
|
||||||
|
SRC = $(shell find src -name "*.c")
|
||||||
|
OBJ = $(SRC:%.c=$(BIN)/%.o)
|
||||||
|
|
||||||
|
.PHONY: dirs run clean build install uninstall
|
||||||
|
|
||||||
|
EOF: clean build
|
||||||
|
|
||||||
|
dirs:
|
||||||
|
mkdir -p ./$(BIN)
|
||||||
|
mkdir -p ./$(BIN)/src
|
||||||
|
|
||||||
|
run: build
|
||||||
|
$(APP)
|
||||||
|
|
||||||
|
build: dirs ${OBJ}
|
||||||
|
${CC} -o $(APP) $(filter %.o,$^) $(LDFLAGS)
|
||||||
|
|
||||||
|
$(BIN)/%.o: %.c
|
||||||
|
$(CC) -o $@ -c $< $(CCFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(APP)
|
||||||
|
rm -rf $(BIN)
|
||||||
|
|
||||||
|
install:
|
||||||
|
cp $(APP) /usr/local/bin/wrapper
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm /usr/local/bin/wrapper
|
21
src/main.c
Normal file
21
src/main.c
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#include "renderer.h"
|
||||||
|
#include "screen.h"
|
||||||
|
|
||||||
|
int main (void) {
|
||||||
|
Screen screen;
|
||||||
|
init_screen(&screen, "test", 1920, 1080);
|
||||||
|
|
||||||
|
Camera camera;
|
||||||
|
init_camera(&camera);
|
||||||
|
|
||||||
|
while(screen.open) {
|
||||||
|
poll_screen(&screen);
|
||||||
|
draw_screen(&screen);
|
||||||
|
render(&screen, &camera);
|
||||||
|
|
||||||
|
update_camera(&camera, &screen);
|
||||||
|
}
|
||||||
|
free_screen(&screen);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
226
src/renderer.c
Normal file
226
src/renderer.c
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
#include "renderer.h"
|
||||||
|
#include "screen.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
13
src/renderer.h
Normal file
13
src/renderer.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "screen.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float x, y;
|
||||||
|
float angle;
|
||||||
|
} Camera;
|
||||||
|
|
||||||
|
void init_camera(Camera* camera);
|
||||||
|
void update_camera(Camera* camera, Screen* screeen);
|
||||||
|
|
||||||
|
void render(Screen* screen, const Camera* camera);
|
130
src/screen.c
Normal file
130
src/screen.c
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
#include "screen.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
void init_screen(Screen* screen, const char* title, uint16_t width, uint16_t height) {
|
||||||
|
screen->width = width;
|
||||||
|
screen->height = height;
|
||||||
|
size_t pixel_count = screen->width * screen->height;
|
||||||
|
screen->pixels = malloc(pixel_count * sizeof(uint32_t));
|
||||||
|
memset(screen->pixels, 0, pixel_count * sizeof(uint32_t));
|
||||||
|
|
||||||
|
SDL_Init(SDL_INIT_VIDEO);
|
||||||
|
|
||||||
|
screen->window =
|
||||||
|
SDL_CreateWindow(
|
||||||
|
title,
|
||||||
|
SDL_WINDOWPOS_CENTERED_DISPLAY(0),
|
||||||
|
SDL_WINDOWPOS_CENTERED_DISPLAY(0),
|
||||||
|
screen->width,
|
||||||
|
screen->height,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!screen->window) {
|
||||||
|
printf("fatal: failed to create sdl window\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
screen->renderer =
|
||||||
|
SDL_CreateRenderer(
|
||||||
|
screen->window,
|
||||||
|
-1,
|
||||||
|
SDL_RENDERER_ACCELERATED
|
||||||
|
| SDL_RENDERER_PRESENTVSYNC
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!screen->renderer) {
|
||||||
|
printf("fatal: failed to create sdl renderer\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
screen->texture =
|
||||||
|
SDL_CreateTexture(
|
||||||
|
screen->renderer,
|
||||||
|
SDL_PIXELFORMAT_RGBA8888,
|
||||||
|
SDL_TEXTUREACCESS_STREAMING,
|
||||||
|
screen->width,
|
||||||
|
screen->height
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!screen->texture) {
|
||||||
|
printf("fatal: failed to create window texture\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
screen->open = true;
|
||||||
|
screen->delta = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long last = 0;
|
||||||
|
void poll_screen(Screen* screen) {
|
||||||
|
struct timespec spec;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &spec);
|
||||||
|
long now = round(spec.tv_nsec / 1.0e6) + spec.tv_sec * 1000;
|
||||||
|
if (last == 0) {
|
||||||
|
screen->delta = 0;
|
||||||
|
} else {
|
||||||
|
screen->delta = (now - last) / 1000.0;
|
||||||
|
}
|
||||||
|
last = now;
|
||||||
|
|
||||||
|
SDL_Event ev;
|
||||||
|
while (SDL_PollEvent(&ev)) {
|
||||||
|
switch (ev.type) {
|
||||||
|
case SDL_QUIT:
|
||||||
|
screen->open = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
screen->key_state = SDL_GetKeyboardState(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_screen(Screen* screen) {
|
||||||
|
void *px;
|
||||||
|
int pitch;
|
||||||
|
SDL_LockTexture(screen->texture, NULL, &px, &pitch);
|
||||||
|
{
|
||||||
|
for (uint16_t y = 0; y < screen->height; y++) {
|
||||||
|
memcpy(
|
||||||
|
&((uint8_t*) px)[y * pitch],
|
||||||
|
&screen->pixels[y * screen->width],
|
||||||
|
screen->width * sizeof(uint32_t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDL_UnlockTexture(screen->texture);
|
||||||
|
|
||||||
|
SDL_SetRenderTarget(screen->renderer, NULL);
|
||||||
|
SDL_SetRenderDrawColor(screen->renderer, 0, 0, 0, 0xFF);
|
||||||
|
SDL_SetRenderDrawBlendMode(screen->renderer, SDL_BLENDMODE_NONE);
|
||||||
|
|
||||||
|
SDL_RenderClear(screen->renderer);
|
||||||
|
SDL_RenderCopyEx(
|
||||||
|
screen->renderer,
|
||||||
|
screen->texture,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0.0,
|
||||||
|
NULL,
|
||||||
|
SDL_FLIP_VERTICAL);
|
||||||
|
|
||||||
|
SDL_RenderCopy(screen->renderer, NULL, NULL, &((SDL_Rect) { 0, 0, 512, 512 }));
|
||||||
|
SDL_RenderPresent(screen->renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_screen(Screen* screen) {
|
||||||
|
SDL_DestroyTexture(screen->texture);
|
||||||
|
SDL_DestroyRenderer(screen->renderer);
|
||||||
|
SDL_DestroyWindow(screen->window);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool key_pressed(Screen* screen, SDL_Scancode code) {
|
||||||
|
return screen->key_state[code & 0xFFFF];
|
||||||
|
}
|
24
src/screen.h
Normal file
24
src/screen.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t width;
|
||||||
|
uint16_t height;
|
||||||
|
SDL_Window* window;
|
||||||
|
SDL_Renderer* renderer;
|
||||||
|
SDL_Texture* texture;
|
||||||
|
uint32_t* pixels;
|
||||||
|
const uint8_t* key_state;
|
||||||
|
bool open;
|
||||||
|
float delta;
|
||||||
|
} Screen;
|
||||||
|
|
||||||
|
void init_screen(Screen* screen, const char* title, uint16_t width, uint16_t height);
|
||||||
|
void draw_screen(Screen* screen);
|
||||||
|
void poll_screen(Screen* screen);
|
||||||
|
void free_screen(Screen* screen);
|
||||||
|
|
||||||
|
bool key_pressed(Screen* screen, SDL_Scancode code);
|
Loading…
Reference in a new issue