rendered paste body#include <stdio.h>
#include <math.h>
typedef char bool;
#define FALSE 0
#define TRUE 1
typedef float vec_t;
typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4];
/* plane is the unit normal [0-2] and the distance from pos [3], point on plane can be derived by multiplying the normal by the distance. */
typedef vec4_t plane_t;
typedef struct sphere_s
{
vec3_t pos;
vec_t radius;
} sphere_t;
typedef struct line_s
{
vec3_t pos;
vec3_t dir;
} line_t;
typedef line_t ray_t;
#define EPSILON 0.00000001f
void Vec3Copy(vec3_t r, vec3_t a)
{
r[0] = a[0];
r[1] = a[1];
r[2] = a[2];
}
vec_t DotProduct3(vec3_t a, vec3_t b)
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
void CrossProduct3(vec3_t r, vec3_t a, vec3_t b)
{
r[0] = a[1] * b[2] - a[2] * b[1];
r[1] = a[2] * b[0] - a[0] * b[2];
r[2] = a[0] * b[1] - a[1] * b[0];
}
void Vec3Add(vec3_t r, vec3_t a, vec3_t b)
{
r[0] = a[0] + b[0];
r[1] = a[1] + b[1];
r[2] = a[2] + b[2];
}
void Vec3Subtract(vec3_t r, vec3_t a, vec3_t b)
{
r[0] = a[0] - b[0];
r[1] = a[1] - b[1];
r[2] = a[2] - b[2];
}
void Vec3Scale(vec3_t r, vec_t s, vec3_t a)
{
r[0] = s * a[0];
r[1] = s * a[1];
r[2] = s * a[2];
}
vec_t Vec3Length(vec3_t a)
{
return (float)sqrt((double)DotProduct3(a,a));
}
void Vec3Normalize(vec3_t a)
{
vec_t length = Vec3Length(a);
if (length < EPSILON)
{
return;
}
Vec3Scale(a, 1.0f/Vec3Length(a), a);
}
bool LinePlaneIntersection(line_t line, plane_t plane, vec_t *distance)
{
vec_t u;
vec3_t pointOnPlane;
vec3_t w;
u = DotProduct3(line.dir, plane);
if (fabs(u) < EPSILON)
{
return FALSE;
}
Vec3Scale(pointOnPlane, plane[3], plane);
Vec3Subtract(w, pointOnPlane, line.pos);
*distance = DotProduct3(plane, w) / u;
return TRUE;
}
bool RayPlaneIntersection(ray_t ray, plane_t plane, vec_t *distance)
{
bool result = LinePlaneIntersection(ray, plane, distance);
if (!result || (*distance < 0.0f))
return FALSE;
return TRUE;
}
bool RaySphereIntersection(ray_t ray, sphere_t sphere, vec_t *distance)
{
vec3_t s2ro;
vec_t a, b, c, dd, d, q, t0, t1;
Vec3Subtract(s2ro, ray.pos, sphere.pos);
a = DotProduct3(ray.dir, ray.dir);
b = 2.0f * DotProduct3(ray.dir, s2ro);
c = DotProduct3(s2ro, s2ro) - (sphere.radius * sphere.radius);
dd = b * b - 4.0f * a * c;
if (dd < 0)
{
return FALSE;
}
d = (float)sqrt((double)(dd));
if (b < 0)
{
d = -d;
}
q = (d - b) / 2.0f;
t0 = q / a;
t1 = c / q;
if (t0 > t1)
{
vec_t swap = t0;
t0 = t1;
t1 = swap;
}
if (t1 < 0)
{
return FALSE;
}
if (t0 < 0)
{
*distance = t1;
}
else
{
*distance = t0;
}
return TRUE;
}
int main(int argc, char *argv[])
{
plane_t plane;
sphere_t sphere, sphere2;
vec3_t cameraPos, cameraFacing;
vec3_t lightDir;
char *gradient = "@8OCoc:. ";
int x, y;
plane[0] = 0.0f;
plane[1] = 1.0f;
plane[2] = 0.0f;
plane[3] = 0.0f;
Vec3Normalize(plane);
sphere.pos[0] = 0.0f;
sphere.pos[1] = 1.0f;
sphere.pos[2] = 0.0f;
sphere.radius = 1.0f;
sphere2.pos[0] = 0.0f;
sphere2.pos[1] = 3.5f;
sphere2.pos[2] = 0.0f;
sphere2.radius = 1.0f;
cameraPos[0] = 0.0f;
cameraPos[1] = 1.0f;
cameraPos[2] = 4.0f;
cameraFacing[0] = 0.0f;
cameraFacing[1] = 0.0f;
cameraFacing[2] = -1.0f;
lightDir[0] = 0.0f;
lightDir[1] = 1.0f;
lightDir[2] = 0.0f;
Vec3Normalize(lightDir);
for (y = 0; y < 50; y++)
{
for (x = 0; x < 80; x++)
{
ray_t sample;
vec_t far = 999999.0f, distance;
vec3_t normal;
vec_t brightness = 1.0;
int hitid=0;
Vec3Copy(sample.pos, cameraPos);
sample.dir[0] = cameraFacing[0] + (vec_t)(x - 40) / 40.0f;
sample.dir[1] = cameraFacing[1] + (vec_t)(25 - y) / 25.0f;
sample.dir[2] = cameraFacing[2];
Vec3Normalize(sample.dir);
if (RayPlaneIntersection(sample, plane, &distance))
{
if (far > distance)
{
hitid = 1;
Vec3Copy(normal, plane);
far = distance;
}
}
if (RaySphereIntersection(sample, sphere, &distance))
{
if (far > distance)
{
Vec3Scale(normal, distance, sample.dir);
Vec3Add(normal, normal, sample.pos);
Vec3Subtract(normal, normal, sphere.pos);
Vec3Normalize(normal);
hitid = 2;
far = distance;
//printf("%f %f %f,", normal[0], normal[1], normal[2]);
}
}
if (RaySphereIntersection(sample, sphere2, &distance))
{
if (far > distance)
{
Vec3Scale(normal, distance, sample.dir);
Vec3Add(normal, normal, sample.pos);
Vec3Subtract(normal, normal, sphere2.pos);
Vec3Normalize(normal);
hitid = 2;
far = distance;
//printf("%f %f %f,", normal[0], normal[1], normal[2]);
}
}
if (hitid)
{
vec3_t localLightDir;
Vec3Scale(localLightDir, -1.0f, lightDir);
brightness = DotProduct3(normal, localLightDir);
if (brightness < 0.0f)
brightness = 0.0f;
if (brightness > 1.0f)
brightness = 1.0f;
}
printf("%c", gradient[(int)(brightness * 8.0f)]);
/*
switch(hitid)
{
case 1:
printf("X");
break;
case 2:
printf("O");
break;
default:
printf(" ");
break;
}
*/
}
printf("\n");
}
}