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