A tiny software raymarcher that attempts to render "n-dimension" manofold insertions as an image appearing to be a non-euclidean 3-dimensional space. Written for the uqcs hackathon 2020. This repo is a mirror of:
https://github.com/ailrst/blackpink
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
261 lines
7.5 KiB
261 lines
7.5 KiB
#include "main.h" |
|
#include "queue.h" |
|
#include "camera.h" |
|
#include "distfuncs.h" |
|
#include "scene.h" |
|
#include "types.h" |
|
#include "vect.h" |
|
#include <SDL2/SDL_blendmode.h> |
|
#include <SDL2/SDL_gamecontroller.h> |
|
#include <SDL2/SDL_mutex.h> |
|
#include <SDL2/SDL_render.h> |
|
#include <SDL2/SDL_stdinc.h> |
|
#include <SDL2/SDL_thread.h> |
|
#include <SDL2/SDL_timer.h> |
|
#include <SDL2/SDL_video.h> |
|
#include <stdlib.h> |
|
|
|
int keyboardstate[322] = {}; // 322 is the number of SDLK_DOWN events |
|
int exitnow = 0; |
|
SDL_Renderer * ren; |
|
Uint32 pixels[B_INTERNAL_HEIGHT][B_INTERNAL_WIDTH]; |
|
|
|
struct object *scene_object; |
|
struct camera *camera; |
|
|
|
SDL_mutex *frame_mutex; |
|
|
|
struct SDL_Window* make_window(void) { |
|
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { |
|
printf("error initializing SDL: %s\n", SDL_GetError()); |
|
} |
|
|
|
return SDL_CreateWindow("𝕧 𝕒 𝕡 𝕠 𝕣 𝕨 𝕒 𝕧 𝕖", |
|
SDL_WINDOWPOS_CENTERED, |
|
SDL_WINDOWPOS_CENTERED, |
|
B_WINDOW_WIDTH, B_WINDOW_HEIGHT, |
|
SDL_WINDOW_RESIZABLE); |
|
} |
|
|
|
|
|
void handle_inputs(void) |
|
{ |
|
/* this is so broken it leaks memory everywhere and crashes and idek why |
|
* Pressing UP will crash immediately and anything else will crash |
|
* eventually |
|
* |
|
* It also makes the object disappear off into the 4th dimension |
|
*/ |
|
|
|
struct ray r; |
|
r.dir = new_vec(4); |
|
r.pos = new_vec(4); |
|
|
|
const double dist = 0.1; |
|
|
|
struct vec ** in = malloc(sizeof(struct vec *) * 3); |
|
in[0] = camera->x; |
|
in[1] = camera->y; |
|
in[2] = camera->z; |
|
|
|
if (keyboardstate[SDL_SCANCODE_J]) { |
|
manifoldstepaxees(camera->pos, camera->y, in, 3, -dist); |
|
} |
|
if (keyboardstate[SDL_SCANCODE_K]) { |
|
manifoldstepaxees(camera->pos, camera->y, in, 3, dist); |
|
} |
|
|
|
if (keyboardstate[SDL_SCANCODE_UP] ) { |
|
manifoldstepaxees(camera->pos, camera->z, in, 3, -dist); |
|
} |
|
if (keyboardstate[SDL_SCANCODE_DOWN]) { |
|
manifoldstepaxees(camera->pos, camera->z, in, 3, dist); |
|
} |
|
if (keyboardstate[SDL_SCANCODE_LEFT] || keyboardstate[SDL_SCANCODE_H]) { |
|
manifoldstepaxees(camera->pos, camera->x, in, 3, dist); |
|
} |
|
if (keyboardstate[SDL_SCANCODE_RIGHT] || keyboardstate[SDL_SCANCODE_L]) { |
|
manifoldstepaxees(camera->pos, camera->x, in, 3, -dist); |
|
} |
|
r.dir->elements[0] = -1; |
|
if (keyboardstate[SDL_SCANCODE_ESCAPE]) { |
|
exitnow = 1; |
|
} |
|
|
|
free(in); |
|
} |
|
|
|
|
|
int input_loop(void *ptr) { |
|
int close = 0; |
|
while (!close) { |
|
SDL_Event event; |
|
while(SDL_PollEvent(&event)) { |
|
switch (event.type) { |
|
case SDL_QUIT: |
|
exitnow = 1; |
|
// *(int *)0 = 1; // segfault |
|
break; |
|
case SDL_KEYDOWN: |
|
keyboardstate[event.key.keysym.scancode] = 1; |
|
break; |
|
case SDL_KEYUP: |
|
keyboardstate[event.key.keysym.scancode] = 0; |
|
break; |
|
} |
|
} |
|
SDL_Delay(50); |
|
SDL_LockMutex(frame_mutex); |
|
handle_inputs(); |
|
SDL_UnlockMutex(frame_mutex); |
|
} |
|
return 0; |
|
} |
|
|
|
static int raymarch_threadfn(void *data) { |
|
int id = *(int *)data; |
|
|
|
/* draw stuff */ |
|
/* march the rays */ |
|
for (int i = 0; i < B_INTERNAL_WIDTH; i++) { |
|
for (int j = 0; j < B_INTERNAL_HEIGHT; j++) { |
|
/* checkerboard rendering */ |
|
if ((i + j * B_INTERNAL_WIDTH) % B_NUM_RAYMARCH_THREADS != id) { |
|
continue; |
|
} |
|
//sdlb_draw_col_pixel(p.col, j, i); |
|
pixels[j][i] = process_pixel(i, j); |
|
} |
|
} |
|
|
|
free(data); |
|
return 0; |
|
|
|
} |
|
|
|
void setup_camera_scene() |
|
{ |
|
//struct object white_sphere = new_object(new_vec3(0.75, 0, 8), 0, 1, sdf_box, yeet_whit); |
|
|
|
camera = calloc(1, sizeof(struct camera)); |
|
camera->pos = new_vec(4); |
|
camera->x = new_vec(4); |
|
camera->y = new_vec(4); |
|
camera->z = new_vec(4); |
|
camera->x->elements[0] = 1; |
|
camera->y->elements[1] = 1; |
|
camera->z->elements[2] = 1; |
|
|
|
camera->light = new_vec4(0, 0, 0, 0); |
|
|
|
// struct object white_sphere = new_box(new_vec3(-0.75, 0, 8), 0, 1); |
|
// struct object other_white_sphere = new_sphere(new_vec3(0.75, 0, 8), 0, 1); |
|
|
|
const double lower_pos_bound = -5; |
|
const double upper_pos_bound = 1; |
|
const int num_trees = 4; |
|
int lastelem = 1; |
|
|
|
struct object* scene_objects = malloc((lastelem + 2 * num_trees) * sizeof(struct object)); |
|
|
|
struct vec *plane_pos = new_vec4(0,1,-5,0); |
|
scene_objects[0] = new_plane(plane_pos, 1, 1); |
|
|
|
for (int i = lastelem; i < lastelem + 2 * num_trees; i+=2) { |
|
struct vec* random_pos = new_random_vec(3, lower_pos_bound, upper_pos_bound); |
|
random_pos->elements[1] = 0; |
|
|
|
struct object* tree = new_tree(random_pos, 0, 1); |
|
scene_objects[i] = tree[0]; |
|
scene_objects[i + 1] = tree[1]; |
|
} |
|
|
|
scene_object = new_scene(2 * num_trees, scene_objects); |
|
scene_object->sol.pos.dimension = 3; |
|
scene_object->sol.pos.elements = camera->pos->elements; |
|
} |
|
|
|
int main(int argc, char **argv) { |
|
SDL_Window *win = make_window(); |
|
ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); |
|
// SDL_RenderSetLogicalSize(ren, B_INTERNAL_HEIGHT, B_INTERNAL_HEIGHT); |
|
|
|
// use this to turn on antristroptic filtering |
|
// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2"); |
|
frame_mutex = SDL_CreateMutex(); |
|
|
|
|
|
double elapsed; |
|
int framct = 0; |
|
Uint64 start, end; |
|
|
|
/* texture for drawing into */ |
|
SDL_Texture *texture = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ARGB8888, |
|
SDL_TEXTUREACCESS_STATIC, B_INTERNAL_WIDTH, B_INTERNAL_HEIGHT); |
|
|
|
SDL_Thread ** threads = calloc(B_NUM_RAYMARCH_THREADS, sizeof(SDL_Thread *)); |
|
|
|
SDL_Thread *input_thread = SDL_CreateThread(input_loop, "input", (void *)NULL); |
|
setup_camera_scene(); |
|
|
|
while (!exitnow) { |
|
/* clear the view */ |
|
start = SDL_GetPerformanceCounter(); |
|
SDL_LockMutex(frame_mutex); |
|
SDL_RenderClear(ren); |
|
|
|
for (int i = 0; i < B_NUM_RAYMARCH_THREADS; i++) { |
|
int *tid = malloc(sizeof(int)); |
|
*tid = i; |
|
threads[i] = SDL_CreateThread(raymarch_threadfn, "raymarch", tid); |
|
// tid is freed in raymarch_threadfn |
|
} |
|
|
|
for (int i = 0; i < B_NUM_RAYMARCH_THREADS; i++) { |
|
int status; |
|
SDL_WaitThread(threads[i], &status); |
|
} |
|
|
|
SDL_UnlockMutex(frame_mutex); |
|
SDL_UpdateTexture(texture, NULL, pixels, B_INTERNAL_WIDTH * sizeof(Uint32)); |
|
|
|
SDL_RenderCopy(ren, texture, NULL, NULL); |
|
|
|
SDL_RenderPresent(ren); |
|
|
|
end = SDL_GetPerformanceCounter(); |
|
double el = (1000 * (end - start) / SDL_GetPerformanceFrequency()); |
|
if (el > 0) { |
|
elapsed = 1000 / el; |
|
} |
|
printf("\rframerate: %f", elapsed); |
|
// fflush(stdout); |
|
framct++; |
|
if (framct++ > 2) { |
|
} |
|
|
|
} |
|
|
|
SDL_DestroyTexture(texture); |
|
SDL_DestroyRenderer(ren); |
|
SDL_DestroyWindow(win); |
|
SDL_Quit(); |
|
} |
|
|
|
/******************************************************************************** |
|
* |
|
* DRAWING UTILITIES |
|
* |
|
*/ |
|
|
|
|
|
void sdlb_set_colour(struct colour col) { |
|
struct colour c = get_rgb(col); |
|
SDL_SetRenderDrawColor(ren, c.r, c.g, c.b, c.a); |
|
} |
|
|
|
void sdlb_draw_col_pixel(struct colour col, int x, int y) { |
|
sdlb_set_colour(col); |
|
SDL_RenderDrawPoint(ren, x, y); |
|
} |
|
|
|
|