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.
 
 

320 lines
8.7 KiB

#include "main.h"
#include "types.h"
#include "math.h"
#include "vect.h"
#include "distfuncs.h"
#include "camera.h"
#define DRAW_DIST 255.0
#define MAX_ITERATIONS 255
#define EPSILON 0.1
#define NORMAL_EPSILON 0.0001
double dabs(double yeet) {
if (yeet > 0) {
return yeet;
} else {
return -yeet;
}
}
double dsign(double yeet) {
if (yeet < 0) {
return -1;
} else {
return 1;
}
}
double manidist(struct vec *v)
{
return v->elements[3];
//double yeet = (SDL_GetTicks() / 10);
double yeet = 300;
v->elements[3] -= yeet;
double out = magnitude_vec(v) - yeet;
v->elements[3] += yeet;
return out;
}
struct solid manifold = (struct solid) {
.dist = manidist,
};
struct colour
solid_col(struct object *s, struct ray *r) {
subtract_vec_ip(r->pos, &(s->sol.pos));
struct colour out = s->col(r, s);
add_vec_ip(r->pos, &(s->sol.pos));
return out;
}
double solid_dist(struct solid *s, struct vec *v) {
subtract_vec_ip(v, &(s->pos));
double out = s->dist(v);
add_vec_ip(v, &s->pos);
return out;
}
/* return a malloced vector, normal to sol at r */
struct vec *
estimateNormal(struct vec *r, struct solid *sol)
{
struct vec *out = new_vec(r->dimension);
struct vec *tmp = new_vec(r->dimension);
for (int i = 0; i < out->dimension; i++) {
tmp->elements[i] = NORMAL_EPSILON;
double s1 = solid_dist(sol, tmp);
tmp->elements[i] = -NORMAL_EPSILON;
double s2 = solid_dist(sol, tmp);
tmp->elements[i] = 0;
out->elements[i] = s1 - s2;
}
free_vec(tmp);
return normalise_vec_ip(out);
}
struct vec *
reyeet(struct vec *v, struct vec *k) {
struct vec *vs [2];
// struct vec *tmp = new_vec_of(v->dimension, 1);
vs[0] = k;
vs[1] = v;
// for (int i = 1; i < v->dimension; i++) vs[i] = k;
struct vec *out = perpendicular_vec(2, vs);
// free_vec(tmp);
return out;
}
void
rotateaxis(struct vec *v, struct vec *k, double a)
{
double cosa = cos(a);
struct vec *p = add_scaled_vec_ip(
add_scaled_vec_ip(scalar_multiply_vec_ip(reyeet(v, k), sin(a)), v, cosa),
k, dot_product_vec(k, v)*(1 - cosa));
free(v->elements);
v->elements = p->elements;
free(p);
}
int vectorisnan(struct vec *v)
{
for (int i = 0; i < v->dimension; i++) {
if (v->elements[i] != v->elements[i])
return 1;
}
return 0;
}
void
manifoldstepaxees(struct vec *pos, struct vec *dir, struct vec **lads, int numlads, double distance)
{
if (numlads == 0) {
*((int *) 0) = 0;
}
struct vec *yaxisold = estimateNormal(pos, &manifold);
/* move the vector foward in euclid */
add_scaled_vec_ip(pos, dir, distance);
struct vec *yaxisnew = estimateNormal(pos, &manifold);
/* stick it to the manifold */
add_scaled_vec_ip(pos, yaxisnew, manifold.dist(pos));
double protamtloc = acos(dot_product_vec(yaxisold,yaxisnew));
struct vec *protaxisloc = normalise_vec_ip(reyeet(yaxisold, yaxisnew));
for (int i = 0; i < numlads; i++) {
struct vec *temp = copy_vec(lads[i]);
rotateaxis(temp, protaxisloc, protamtloc); /* change the direction */
if (!vectorisnan(temp)) {
free(lads[i]->elements);
lads[i]->elements = temp->elements;
free(temp);
} else {
free_vec(temp);
}
}
free_vec(yaxisnew);
free_vec(yaxisold);
free_vec(protaxisloc);
}
void
manifoldturn(struct ray *r, struct vec *v, double distance)
{
struct vec *yaxisold = estimateNormal(r->pos, &manifold);
/* move the vector foward in euclid */
add_scaled_vec_ip(r->pos, r->dir, distance);
struct vec *yaxisnew = estimateNormal(r->pos, &manifold);
/* stick it to the manifold */
add_scaled_vec_ip(r->pos, yaxisnew, manifold.dist(r->pos));
double protamtloc = acos(dot_product_vec(yaxisold,yaxisnew));
struct vec *protaxisloc = normalise_vec_ip(reyeet(yaxisold, yaxisnew));
struct vec *temp = copy_vec(v);
rotateaxis(temp, protaxisloc, protamtloc); /* change the direction */
if (!vectorisnan(temp)) {
free(v->elements);
v->elements = temp->elements;
free(temp);
} else {
free_vec(temp);
}
free_vec(yaxisnew);
free_vec(yaxisold);
free_vec(protaxisloc);
}
void
manifoldstep(struct ray *r, double distance)
{
manifoldturn(r, r->dir, distance);
}
void
place(struct solid *v) {
struct vec **dirs = malloc(sizeof(struct vec *) * v->pos.dimension);
for (int d = 0; d < v->pos.dimension; d++) {
dirs[d] = new_vec(v->pos.dimension);
dirs[d]->elements[d] = 1;
}
struct vec *tdir = new_vec(v->pos.dimension);
struct vec *tpos = new_vec(v->pos.dimension);
for (int d = 0; d < v->pos.dimension; d++) {
for (double yee = v->pos.elements[d]; dabs(yee) > EPSILON; yee -= dsign(yee) * EPSILON) {
struct vec *temp = copy_vec(dirs[d]);
manifoldstepaxees(tpos, temp, dirs, v->pos.dimension, EPSILON);
free_vec(temp);
}
tpos->elements[d] = v->pos.elements[d];
}
v->pos.elements = tpos->elements;
free(tpos);
free_vec(tdir);
for (int d = 0; d < v->pos.dimension; d++) free_vec(dirs[d]);
free(dirs);
}
struct pixel_info
march(struct ray *r, struct object *scene)
{
double travel_dist = 0;
double scene_dist;
double min_dist = DRAW_DIST;
int i;
int fligs = 0;
struct colour out = (struct colour) {.sp = CS_RGB};
for (i = 0; (i < MAX_ITERATIONS) && (travel_dist < DRAW_DIST); i++) {
/* calculate the distance to the scene */
scene_dist = solid_dist(&(scene->sol), r->pos);
if (scene_dist < EPSILON) { /* we've hit an object */
out = solid_col(scene, r);
fligs |= 0x01;
break;
}
if (min_dist > scene_dist)
min_dist = scene_dist;
/* step foward the calculated distance */
manifoldstep(r, scene_dist);
travel_dist += scene_dist;
}
/* no colour reached */
return (struct pixel_info) {
.flags = fligs,
.iterations = i,
.col = out,
.travel_dist = travel_dist,
.scene_dist = min_dist
};
}
union badpixelformat {
struct {
Uint8 b;
Uint8 g;
Uint8 r;
Uint8 a;
};
Uint32 pixel;
};
Uint32 get_stl_colour(struct colour *cl) {
struct colour c = get_rgb(*cl);
union badpixelformat p;
p.r = c.r;
p.g = c.g;
p.b = c.b;
p.a = c.a;
return p.pixel;
}
Uint32
process_pixel(int i, int j)
{
struct ray r = (struct ray) {
.pos = new_vec(4),
.dir = normalise_vec_ip(new_vec4(i - B_INTERNAL_WIDTH/2, j - B_INTERNAL_HEIGHT/2, 100, 0))
};
struct pixel_info p = march(&r, scene_object);
// p.col.r += p.travel_dist;
if (!(p.flags & 0x01)) {
p.col.b = 255;
p.col.r = j * 7;
p.col.g += (16.0 / p.scene_dist);
p.col.b += (16.0 / p.scene_dist);
} else {
}
p.col.r -= p.iterations / 2;
p.col.g -= p.iterations / 2;
p.col.b -= p.iterations / 2;
double fade_intensity = 50;
// if (p.travel_dist < DRAW_DIST) {
p.col.r += fade_intensity * p.travel_dist / DRAW_DIST;
p.col.g += fade_intensity * p.travel_dist / DRAW_DIST;
p.col.b += fade_intensity * p.travel_dist / DRAW_DIST;
//}
p.col.r = clamp(p.col.r, 0, 255);
p.col.g = clamp(p.col.g, 0, 255);
p.col.b = clamp(p.col.b, 0, 255);
// p.col.g = 0;
// printf("%d, ", p.iterations);
// p.col.b = 255.0 / p.scene_dist;
// if (p.col.b > 255) p.col.b = 255;
free_vec(r.pos);
free_vec(r.dir);
return get_stl_colour(&p.col);
}