diff --git a/Makefile b/Makefile index 5c79afe..dfb9014 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ CCFLAGS = -std=c99 -Wall -Wextra -pedantic -O2 CCFLAGS += $(INCFLAGS) LDFLAGS += $(INCFLAGS) -LDFLAGS += -lSDL2 +LDFLAGS += -lX11 LDFLAGS += -lm BIN = bin diff --git a/src/main.c b/src/main.c index 36b819f..385d0d1 100644 --- a/src/main.c +++ b/src/main.c @@ -1,20 +1,21 @@ #include "renderer.h" #include "screen.h" +#include +#include + int main (void) { Screen screen; - init_screen(&screen, "test", 1920, 1080); + init_screen(&screen, 2160, 1440); Camera camera; init_camera(&camera); - - while(screen.open) { - poll_screen(&screen); - draw_screen(&screen); + + while (poll_screen(&screen)) { render(&screen, &camera); - update_camera(&camera, &screen); } + free_screen(&screen); return EXIT_SUCCESS; diff --git a/src/renderer.c b/src/renderer.c index c64be51..a77f855 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -19,16 +19,16 @@ static double fov = PI / 4; #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)) + if (key_down(KEY_LEFT)) rotate -= ROTATE_SPEED; - if (key_pressed(screen, SDL_SCANCODE_RIGHT)) + if (key_down(KEY_RIGHT)) rotate += ROTATE_SPEED; - rotate *= screen->delta; rotate += camera->angle; while (rotate >= PI2) rotate -= PI2; @@ -39,31 +39,31 @@ void update_camera(Camera* camera, Screen* screen) { v2 left = { forward.y, -forward.x }; v2 move = { 0, 0 }; - if (key_pressed(screen, SDL_SCANCODE_W)) { + if (key_down(KEY_W)) { move.x += forward.x; move.y += forward.y; } - if (key_pressed(screen, SDL_SCANCODE_S)) { + if (key_down(KEY_S)) { move.x -= forward.x; move.y -= forward.y; } - if (key_pressed(screen, SDL_SCANCODE_A)) { + if (key_down(KEY_A)) { move.x += left.x; move.y += left.y; } - if (key_pressed(screen, SDL_SCANCODE_D)) { + if (key_down(KEY_D)) { move.x -= left.x; move.y -= left.y; } - if (key_pressed(screen, SDL_SCANCODE_EQUALS)) { + if (key_down(KEY_EQUALS)) { fov += FOV_CHANGE_SPEED * screen->delta; } - if (key_pressed(screen, SDL_SCANCODE_MINUS)) { + if (key_down(KEY_MINUS)) { fov -= FOV_CHANGE_SPEED * screen->delta; } @@ -94,6 +94,7 @@ void render(Screen* screen, const Camera* camera) { }; 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; @@ -109,20 +110,31 @@ void render(Screen* screen, const Camera* camera) { 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; + case 2: color = 0xFF00FF00; break; + case 3: color = 0xFFFF0000; break; + case 4: color = 0xFFFF00FF; break; + case 5: color = 0xFFFFFF00; break; + default: color = 0xFF000000; break; } + // 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, 0, y0, 0xFF202020); verline(screen, x, y0, y1, color); - verline(screen, x, y1, screen->height - 1, 0x505050FF); + verline(screen, x, y1, screen->height - 1, 0xFF505050); + // verline(screen, x, 0, y0, 0x202020FF); + // verline(screen, x, y0, y1, color); + // verline(screen, x, y1, screen->height - 1, 0x505050FF); } } diff --git a/src/screen.c b/src/screen.c index 5e23e0b..dca9b79 100644 --- a/src/screen.c +++ b/src/screen.c @@ -1,130 +1,257 @@ #include "screen.h" +#include +#undef Screen +#include #include #include #include #include +#include + +#define XLIB_ILLEGAL_ACCESS +#include +#include + +static Display* dpy; +static int scr; +static Window root; + +static int count = 0; +static size_t bit_depth = sizeof(uint32_t) * 8; +static int key_count; + +static bool* key_state; +static bool* key_checked; + +typedef struct { + Window window; + GC graphics_ctx; + Pixmap pixel_map; + XImage* image; + int width, height; +} WindowState; + +static void init_x() { + if ((dpy = XOpenDisplay(NULL)) == NULL) { + printf("error: failed to open x11 display\n"); + exit(EXIT_FAILURE); + } + +#ifdef DEBUG + XSynchronize(dpy, True); +#endif + + scr = DefaultScreen(dpy); + root = RootWindow(dpy, scr); + + key_count = dpy->max_keycode - dpy->min_keycode; + key_state = malloc(sizeof(bool) * key_count); + key_checked = malloc(sizeof(bool) * key_count); +} + +static Window create_window(int x, int y, int w, int h, int d) { + + XVisualInfo vis_info; + if(!XMatchVisualInfo(dpy, scr, d, TrueColor, &vis_info)) { + printf("error: %d depth not supported\n", d); + exit(EXIT_FAILURE); + } + + Visual* visual = vis_info.visual;; + + XSetWindowAttributes xwa; + xwa.background_pixel = 0; + xwa.border_pixel = 0; + xwa.event_mask = KeyPressMask | KeyReleaseMask | StructureNotifyMask; + xwa.colormap = XCreateColormap(dpy, root, visual, AllocNone); + + long wm = CWBackPixel | CWColormap | CWBorderPixel | CWEventMask; + + Window window = XCreateWindow(dpy, root, x, y, w, h, 0, d, InputOutput, visual, wm, &xwa); + + return window; +} + +static XImage* create_image(int width, int height) { + return XCreateImage( + dpy, + CopyFromParent, + bit_depth, + ZPixmap, + 0, + malloc(width * height * bit_depth / 8), + width, + height, + bit_depth, + 0 + ); +} + + +void init_screen(struct Screen* screen, uint16_t width, uint16_t height) { + + if (dpy == NULL) { + init_x(); + } -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; + + size_t pixel_count = screen->width * screen->height; + + screen->pixels = malloc(pixel_count * bit_depth / 8); + memset(screen->pixels, 0, pixel_count * bit_depth / 8); + + Window window = create_window(0, 0, width, height, bit_depth); + XMapWindow(dpy, window); + + Pixmap pixel_map = XCreatePixmap(dpy, window, width, height, bit_depth); + + GC gc = XCreateGC(dpy, pixel_map, 0, NULL); + + WindowState* state = malloc(sizeof(WindowState)); + state->window = window; + state->graphics_ctx = gc; + state->pixel_map = pixel_map; + + XWindowAttributes xwa; + XGetWindowAttributes(dpy, window, &xwa); + state->width = xwa.width; + state->height = xwa.height; + screen->internal = state; + + XImage* image = create_image(state->width, state->height); + state->image = image; + + count++; +} + +static long get_time() { + struct timespec spec; + clock_gettime(CLOCK_MONOTONIC, &spec); + return round(spec.tv_nsec / 1.0e6) + spec.tv_sec * 1000; } 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; + +static void update_delta(struct Screen* screen) { + long now = get_time(); if (last == 0) { screen->delta = 0; } else { screen->delta = (now - last) / 1000.0; } last = now; +} + +static void draw_screen(struct Screen* screen) { + WindowState* state = (WindowState*) screen->internal; + + uint32_t* src = screen->pixels; + uint32_t* dst = (uint32_t*) state->image->data; + + float x_step = screen->width / (float) state->width; + float y_step = screen->height / (float) state->height; + + for (int x = 0; x < state->width; x++) { + int px = (int) (x * x_step); + + for (int y = 0; y < state->height; y++) { + int py = (int) (y * y_step); + + dst[x + y * state->width] = src[px + py * screen->width]; + } + } + + XPutImage( + dpy, + state->window, + state->graphics_ctx, + state->image, + 0, 0, 0, 0, + state->width, + state->height + ); +} + + +static void handle_event(WindowState* state) { + XEvent event; + XNextEvent(dpy, &event); - SDL_Event ev; - while (SDL_PollEvent(&ev)) { - switch (ev.type) { - case SDL_QUIT: - screen->open = false; - break; - default: - break; + switch(event.type) { + + case KeyPress: { + XKeyEvent xkpe = event.xkey; + uint32_t code = xkpe.keycode - dpy->min_keycode; + key_state[code] = true; + key_checked[code] = false; + 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) - ); + case KeyRelease: { + XKeyEvent xkre = event.xkey; + uint32_t code = xkre.keycode - dpy->min_keycode; + key_state[code] = false; + break; } + + case ConfigureNotify: { + XConfigureEvent xce = event.xconfigure; + state->width = xce.width; + state->height = xce.height; + + XDestroyImage(state->image); + state->image = create_image(state->width, state->height); + + break; + } + + default: break; } - 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 poll_screen(struct Screen* screen) { + + draw_screen(screen); + + WindowState* state = (WindowState*) screen->internal; + + while (XPending(dpy)) + handle_event(state); + + update_delta(screen); + return true; } -bool key_pressed(Screen* screen, SDL_Scancode code) { - return screen->key_state[code & 0xFFFF]; +void free_screen(struct Screen* screen) { + WindowState* state = (WindowState*) screen->internal; + + XUnmapWindow(dpy, state->window); + XFreePixmap(dpy, state->pixel_map); + XDestroyImage(state->image); + XFreeGC(dpy, state->graphics_ctx); + XDestroyWindow(dpy, state->window); + free(screen->internal); + + count--; + + if(count == 0) { + XCloseDisplay(dpy); + free(key_state); + free(key_checked); + } +} + +bool key_pressed(int keycode) { + if (key_checked[keycode]) return false; + if (!key_state[keycode]) return false; + key_checked[keycode] = true; + return true; +} + +bool key_down(int keycode) { + return key_state[keycode]; } diff --git a/src/screen.h b/src/screen.h index 1b601d8..c2165f9 100644 --- a/src/screen.h +++ b/src/screen.h @@ -1,24 +1,34 @@ #pragma once #define _POSIX_C_SOURCE 200809L -#include +#include #include -typedef struct { +struct Screen { 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* internal; +}; -void init_screen(Screen* screen, const char* title, uint16_t width, uint16_t height); -void draw_screen(Screen* screen); -void poll_screen(Screen* screen); +#define Screen struct Screen + +#define KEY_W 17 +#define KEY_A 30 +#define KEY_S 31 +#define KEY_D 32 +#define KEY_UP 103 +#define KEY_DOWN 108 +#define KEY_LEFT 105 +#define KEY_RIGHT 106 +#define KEY_MINUS 12 +#define KEY_EQUALS 13 +#define KEY_ESC 1 + +void init_screen(Screen* screen, uint16_t width, uint16_t height); +bool poll_screen(Screen* screen); void free_screen(Screen* screen); -bool key_pressed(Screen* screen, SDL_Scancode code); +bool key_pressed(int keycode); +bool key_down(int keycode);