# include "main.h"
# include "types.h"
# include "vect.h"
# include "camera.h"
# define SOFT_LIGHT 1
# define HARD_LIGHT 2
# define WHITE_LIGHT 2
double divid_fp ( double a , double b ) {
return a / b ;
}
/*
*
* float sdEllipsoid ( vec3 p , vec3 r )
{
float k0 = length ( p / r ) ;
float k1 = length ( p / ( r * r ) ) ;
return k0 * ( k0 - 1.0 ) / k1 ;
}
*
*/
double sdf_4ellipsoid ( struct vec * x ) {
double r = 1 ;
struct vec * shape = new_vec4 ( 1.5 , 3 , 1 , 4 ) ;
struct vec * v = copy_vec ( x ) ;
double dim = 0 ;
for ( int i = 0 ; i < v - > dimension ; i + + ) {
v - > elements [ i ] = v - > elements [ i ] / shape - > elements [ i ] ;
}
double k0 = magnitude_vec ( v ) ;
free_vec ( v ) ;
v = copy_vec ( x ) ;
for ( int i = 0 ; i < v - > dimension ; i + + ) {
v - > elements [ i ] = v - > elements [ i ] / pow ( shape - > elements [ i ] , 2 ) ;
}
double k1 = magnitude_vec ( v ) ;
double result = k0 * ( k0 - 1.0 ) / k1 ;
free_vec ( v ) ;
return result ;
}
double sdf_3ellipsoid ( struct vec * x ) {
double r = 1 ;
struct vec * shape = new_vec3 ( 1.5 , 3 , 1 ) ;
struct vec * v = copy_vec ( x ) ;
double dim = 0 ;
for ( int i = 0 ; i < 3 ; i + + ) {
v - > elements [ i ] = v - > elements [ i ] / shape - > elements [ i ] ;
}
double k0 = magnitude_vec ( v ) ;
free_vec ( v ) ;
v = copy_vec ( x ) ;
for ( int i = 0 ; i < 3 ; i + + ) {
v - > elements [ i ] = v - > elements [ i ] / pow ( shape - > elements [ i ] , 2 ) ;
}
double k1 = magnitude_vec ( v ) ;
double result = k0 * ( k0 - 1.0 ) / k1 ;
free_vec ( v ) ;
free_vec ( shape ) ;
return result ;
}
double sdf_sphere ( struct vec * x ) {
static const double r = 1.4 ;
struct vec * v = copy_vec ( x ) ;
// v->elements[2] -= 5;
// v->elements[1] += (SDL_GetTicks()/1000.0) - 5;
// v->elements[2] -= 2;
// v->elements[1] += (SDL_GetTicks()/1000.0) - 5;
double res = magnitude_vec ( v ) - r ;
free_vec ( v ) ;
return res ;
}
double sdf_hplane ( struct vec * x ) {
static const double h = - 0.5 ;
return - ( x - > elements [ 1 ] + h ) ;
}
double clamp ( double val , double min , double max ) {
if ( val < min )
return min ;
if ( val > max )
return max ;
return val ;
}
/*
double sdf_cone ( struct vec * x ) {
double height = 3 ;
struct vec * v = copy_vec ( x ) ;
double cx = 1 ;
double cy = 1 ;
static struct vec * cone = NULL ;
static struct vec * w , * a , * b ;
if ( ! cone ) {
cone = scalar_multiply_vec_ip ( new_vec2 ( cx / cy , - 1 ) , height ) ;
}
struct vec * temp ;
double cone2 =
struct vec * temp = new_vec2 ( v - > e - > x , v - > e - > z ) ;
double aaa = magnitude_vec ( temp ) ;
free_vec ( temp ) ;
w = new_vec2 ( aaa , v - > e - > y ) ;
double t2 = clamp ( ( dot_product_vec ( w , v ) / dot_product_vec ( cone , cone ) ) , 0.0 , 1.0 ) ;
temp = scalar_multiply_vec ( cone , t2 ) ;
a = subtract_vec ( w , temp ) ;
free_vec ( temp ) ;
temp = new_vec2 ( clamp ( w - > e - > x / cone - > e - > x , 0.0 , 1.0 ) , 1.0 ) ;
scalar_multiply_vec_ip ( temp , )
double result = - 1 ;
free_vec ( v ) ;
return result ;
}
*/
double is_pos ( double a ) {
if ( a > 0 ) {
return a ;
}
return 0 ;
}
double sdf_phat_vert_line ( struct vec * x ) {
static const double h = 2 ;
static const double r = 0.5 ;
struct vec * v = copy_vec ( x ) ;
v - > e - > y - = clamp ( v - > e - > y , 0.0 , h ) ;
double val = magnitude_vec ( v ) - r ;
free_vec ( v ) ;
return val ;
}
/* https://www.alanzucconi.com/2016/07/01/signed-distance-functions/#part3 */
/* http://mercury.sexy/hg_sdf/ */
double sdf_box ( struct vec * x ) {
struct vec * v = copy_vec ( x ) ;
do_on_vec_ip ( v , fabs ) ;
struct vec * box_shape = new_vec_of ( v - > dimension , 5 ) ;
subtract_vec_ip ( box_shape , v ) ;
do_on_vec_ip ( v , is_pos ) ;
double result = magnitude_vec ( v ) ;
free_vec ( v ) ;
free ( box_shape ) ;
return result ;
}
struct colour yeet_pho ( struct ray * ray , struct object * o ) {
double specular = 0.8 ;
double diffuse = 0.55 ;
double ambient = 0.3 ;
double shin = 51 ;
int light_type = SOFT_LIGHT ;
struct colour light_col = { . r = 200 , . g = 0 , . b = 100 , . sp = CS_RGB } ;
//struct vec *light = new_vec4(-1, 1, 1, 0);
struct vec * light = copy_vec ( camera - > light ) ;
//struct vec *light = add_vec_ip(new_vec4(50,50,-50,0), &o->sol.pos);
//struct vec *colour = new_vec3(o->base_col.r, o->base_col.g, o->base_col.b);
/* ambient */
//scalar_multiply_vec_ip(colour, ambient);
double intensity = ambient ;
struct vec * surf_norm = estimateNormal ( ray - > pos , & o - > sol ) ;
// struct vec *light_vec = normalise_vec_ip(subtract_vec(ray->pos, light));
struct vec * light_vec = normalise_vec_ip ( subtract_vec_ip ( scalar_multiply_vec ( light , - 1 ) , ray - > pos ) ) ;
double diffuse_val = clamp ( dot_product_vec ( light_vec , surf_norm ) * diffuse , 0 , 1 ) ;
// r = 2 * (l . n) * n - L
struct vec * camera_vec = normalise_vec_ip ( scalar_multiply_vec ( ray - > pos , - 1 ) ) ;
struct vec * reflection = scalar_multiply_vec ( surf_norm ,
2 * dot_product_vec ( light_vec , surf_norm ) ) ;
subtract_vec_ip ( reflection , light_vec ) ;
double spec_val = clamp ( pow ( clamp ( dot_product_vec ( reflection , camera_vec ) , - 1 , 1 ) , shin ) * specular , 0 , 1 ) ;
struct colour c = get_hsl ( o - > base_col ) ;
intensity = ambient + diffuse_val + spec_val ;
light_col = get_hsl ( light_col ) ;
light_col . l = spec_val ;
light_col = get_rgb ( light_col ) ;
c . l = intensity ;
c = get_rgb ( c ) ;
if ( 1 & & spec_val > 0.0 ) {
if ( light_type = = HARD_LIGHT ) {
c . r = light_col . r > c . r ? c . r + ( light_col . r - c . r ) / 2 : c . r ;
c . g = light_col . g > c . g ? c . g + ( light_col . g - c . g ) / 2 : c . g ;
c . b = light_col . b > c . b ? c . b + ( light_col . b - c . b ) / 2 : c . b ;
} else if ( light_type = = SOFT_LIGHT ) {
c . r = light_col . r > c . r ? light_col . r : c . r ;
c . b = light_col . b > c . b ? light_col . b : c . b ;
c . g = light_col . g > c . g ? light_col . g : c . g ;
}
}
free_vec ( camera_vec ) ;
free_vec ( reflection ) ;
free_vec ( surf_norm ) ;
free_vec ( light_vec ) ;
free_vec ( light ) ;
return c ;
}
struct colour yeet_col_og ( struct ray * ray , struct object * obj ) {
struct vec * l = new_vec4 ( 1 , 1 , 1 , 1 ) ;
struct vec * n = subtract_vec_ip ( l , ray - > pos ) ;
struct vec * nl = normalise_vec ( l ) ;
struct colour c = { . r = nl - > e - > x * 555 , . g = nl - > e - > y * 555 , . b = nl - > e - > z * 555 , . a = 255 , . sp = CS_RGB } ;
free_vec ( n ) ;
return ( c ) ;
}
/*
struct object new_sphere ( double radius ) {
struct object s ;
struct vec * v = new_vec4 ( 0 , 0 , 5 , 0 ) ;
s . base_col = get_random_color ( ) ;
s . sol . pos = * v ;
s . sol . op = B_ADD ;
s . col = yeet_pho ;
s . sol . dist = sdf_sphere ;
return s ;
*/
/**
* Creates a new struct object with the given parameters . The position passed
* in should be a vec4 as this is converted to a vec3 when the object is added
* to the scene .
*/
struct object
new_object ( struct vec * position , double rotation , double scale ,
double ( * dist ) ( struct vec * ) , struct colour ( * col ) ( struct ray * , struct object * ) )
{
struct object new_obj ;
struct colour default_col = { . r = 255 , . g = 255 , . b = 255 , . a = 255 , . sp = CS_RGB } ;
new_obj . base_col = default_col ;
new_obj . col = col ;
new_obj . sol . dist = dist ;
new_obj . sol . pos = * position ;
new_obj . sol . rotation = rotation ;
new_obj . sol . scale = scale ;
new_obj . sol . op = B_ADD ;
return new_obj ;
}
struct colour yeet_whit ( struct ray * ray , struct object * obj ) {
struct colour c = { . r = 200 , . g = 200 , . b = 0 , . a = 255 , . sp = CS_RGB } ;
return c ;
}
struct object new_plane ( struct vec * position , double rotation , double scale ) {
return new_object ( position , rotation , scale , sdf_hplane , yeet_whit ) ;
}
struct object new_sphere ( struct vec * position , double rotation , double scale ) {
return new_object ( position , rotation , scale , sdf_sphere , yeet_pho ) ;
}
struct object new_ellipse ( struct vec * position , double rotation , double scale ) {
return new_object ( position , rotation , scale , sdf_3ellipsoid , yeet_pho ) ;
}
struct object new_box ( struct vec * position , double rotation , double scale ) {
return new_object ( position , rotation , scale , sdf_box , yeet_pho ) ;
}
/* DON'T CALL THIS */
struct object new_cone ( struct vec * position , double rotation , double scale ) {
return new_object ( position , rotation , scale , NULL , NULL ) ;
}
struct object new_vert_line ( struct vec * position , double rotation , double scale ) {
return new_object ( position , rotation , scale , sdf_phat_vert_line , yeet_pho ) ;
}
struct colour yeet_green ( struct ray * ray , struct object * obj ) {
struct colour c = { . r = 0 , . g = ( rand ( ) % 127 ) + 127 , . b = 0 , . a = 255 , . sp = CS_RGB } ;
return c ;
}
struct colour yeet_brown ( struct ray * ray , struct object * obj ) {
struct colour c = { . r = 210 , . g = 105 , . b = 30 , . sp = CS_RGB } ;
return c ;
}
/**
* The absolute jankiest way to make a tree but I couldn ' t think of anything
* better .
*
* Returns a pointer to the first element of an array of the components of the
* tree ( trunk and leaves ) . Iterate over the array when adding to a scene .
*/
struct object * new_tree ( struct vec * position , double rotation , double scale ) {
struct object * tree = malloc ( 2 * sizeof ( struct object ) ) ;
struct object trunk = new_object ( position , rotation , scale , sdf_phat_vert_line , yeet_pho ) ;
trunk . base_col = ( struct colour ) { . r = 0x92 , . g = 0x2D , . b = 0x50 , . sp = CS_RGB } ;
trunk . base_col . g + = rand ( ) % 20 ;
struct vec * leaf_pos = add_vec_ip ( new_vec3 ( 0 , - 1.5 , 0 ) , position ) ;
struct object leaves = new_object ( leaf_pos , rotation , scale , sdf_3ellipsoid , yeet_pho ) ;
leaves . base_col = ( struct colour ) { . r = 0xC0 , . g = 0xDA , . b = 0x74 , . sp = CS_RGB } ;
// leaves.base_col = (struct colour){.r = 30 + random() % 20, .g = 155 + random() % 100, .b = random() % 90, .sp = CS_RGB};
tree [ 0 ] = trunk ;
tree [ 1 ] = leaves ;
return tree ;
}