raytracer

raytracer.git
git clone git://git.lenczewski.org/raytracer.git
Log | Files | Refs | README | LICENSE

rt.h (14139B)


      1 #ifndef RT_H
      2 #define RT_H
      3 
      4 #include <assert.h>
      5 #include <stdint.h>
      6 #include <stdio.h>
      7 #include <stdlib.h>
      8 #include <string.h>
      9 #include <unistd.h>
     10 
     11 #include <fcntl.h>
     12 
     13 // memory utilities
     14 // ===========================================================================
     15 
     16 #include <stdalign.h>
     17 #include <stddef.h>
     18 
     19 #define IS_POW2(v) (((v) & ((v) - 1)) == 0)
     20 
     21 #define IS_ALIGNED(v, align) (((v) & ((align) - 1)) == 0)
     22 #define ALIGN_PREV(v, align) ((v) & ~((align) - 1))
     23 #define ALIGN_NEXT(v, align) ALIGN_PREV((v) + ((align) - 1), (align))
     24 
     25 struct arena {
     26 	void *ptr;
     27 	size_t cap, len;
     28 };
     29 
     30 inline void
     31 arena_reset(struct arena *arena)
     32 {
     33 	arena->len = 0;
     34 }
     35 
     36 inline void *
     37 arena_alloc(struct arena *arena, size_t size, size_t alignment)
     38 {
     39 	assert(size);
     40 	assert(alignment);
     41 	assert(IS_POW2(alignment));
     42 
     43 	uintptr_t cur_ptr = (uintptr_t) arena->ptr, end_ptr = cur_ptr + arena->cap;
     44 
     45 	uintptr_t aligned_ptr = ALIGN_NEXT(cur_ptr, alignment);
     46 	if (aligned_ptr + size > end_ptr)
     47 		return NULL;
     48 
     49 	arena->len = (aligned_ptr + size) - end_ptr;
     50 
     51 	return (void *) aligned_ptr;
     52 }
     53 
     54 #define ARENA_ALLOC_ARRAY(arena, T, n) \
     55 	arena_alloc((arena), sizeof(T) * (n), alignof(T))
     56 
     57 #define ARENA_ALLOC_SIZED(arena, T) ARENA_ALLOC_ARRAY((arena), T, 1)
     58 
     59 #define TO_PARENT_PTR(ptr, T, member) \
     60 	((ptr) ? ((T *) (((uintptr_t) (ptr)) - offsetof(T, member))) : NULL)
     61 
     62 struct list_node {
     63 	struct list_node *prev, *next;
     64 };
     65 
     66 #define LIST_INIT(list) ((struct list_node) { &(list), &(list), })
     67 
     68 #define LIST_HEAD(list) ((list)->next)
     69 #define LIST_TAIL(list) ((list)->prev)
     70 
     71 #define LIST_IS_EMPTY(list) \
     72 	(LIST_HEAD(list) == (list) && LIST_TAIL(list) == (list))
     73 
     74 #define LIST_NODE_ITER(list, it) \
     75 	for ((it) = LIST_HEAD(list); (it) != (list); (it) = LIST_HEAD(it))
     76 
     77 #define LIST_NODE_RITER(list, it) \
     78 	for ((it) = LIST_TAIL(list); (it) != (list); (it) = LIST_TAIL(it))
     79 
     80 #define LIST_NODE_ENTRY(node, T, member) TO_PARENT_PTR((node), T, member)
     81 
     82 #define LIST_ENTRY_ITER(list, it, member) \
     83 	for ((it) = LIST_NODE_ENTRY(LIST_HEAD(list), __typeof__ (*(it)), member); \
     84 	     &(it)->member != (list); \
     85 	     (it) = LIST_NODE_ENTRY(LIST_HEAD(&(it)->member), __typeof__ (*(it)), member))
     86 
     87 #define LIST_ENTRY_RITER(list, it, member) \
     88 	for ((it) = LIST_NODE_ENTRY(LIST_TAIL(list), __typeof__ (*(it)), member); \
     89 	     &(it)->member != (list); \
     90 	     (it) = LIST_NODE_ENTRY(LIST_TAIL(&(it)->member), __typeof__ (*(it)), member))
     91 
     92 inline void
     93 list_node_link(struct list_node *node, struct list_node *prev, struct list_node *next)
     94 {
     95 	node->prev = prev;
     96 	prev->next = node;
     97 	node->next = next;
     98 	next->prev = node;
     99 }
    100 
    101 inline struct list_node *
    102 list_node_unlink(struct list_node *node)
    103 {
    104 	node->prev->next = node->next;
    105 	node->next->prev = node->prev;
    106 	return node;
    107 }
    108 
    109 inline void
    110 list_push_head(struct list_node *list, struct list_node *node)
    111 {
    112 	list_node_link(node, list, LIST_HEAD(list));
    113 }
    114 
    115 inline void
    116 list_push_tail(struct list_node *list, struct list_node *node)
    117 {
    118 	list_node_link(node, LIST_TAIL(list), list);
    119 }
    120 
    121 inline struct list_node *
    122 list_pop_head(struct list_node *list)
    123 {
    124 	struct list_node *res = list_node_unlink(LIST_HEAD(list));
    125 	return res;
    126 }
    127 
    128 inline struct list_node *
    129 list_pop_tail(struct list_node *list)
    130 {
    131 	struct list_node *res = list_node_unlink(LIST_TAIL(list));
    132 	return res;
    133 }
    134 
    135 // math utilities
    136 // ===========================================================================
    137 
    138 #include <tgmath.h>
    139 
    140 typedef union vec3i {
    141 	int32_t vs[3];
    142 	struct {
    143 		int32_t x, y, z;
    144 	} xyz;
    145 } vec3i_t;
    146 
    147 typedef union vec3u {
    148 	uint32_t vs[3];
    149 	struct {
    150 		uint32_t x, y, z;
    151 	} xyz;
    152 } vec3u_t;
    153 
    154 typedef union vec3f {
    155 	float vs[3];
    156 	struct {
    157 		float x, y, z;
    158 	} xyz;
    159 } vec3f_t;
    160 
    161 typedef union vec3d {
    162 	double vs[3];
    163 	struct {
    164 		double x, y, z;
    165 	} xyz;
    166 } vec3d_t;
    167 
    168 #define VEC3(T, x, y, z) ((T) { .vs = { (x), (y), (z), }, })
    169 
    170 #define VEC30(T) VEC3(T, 0, 0, 0)
    171 #define VEC31(T) VEC3(T, 1, 1, 1)
    172 
    173 #define VEC3NEG(lhs) \
    174 	VEC3(__typeof__ (lhs), -(lhs).xyz.x, -(lhs).xyz.y, -(lhs).xyz.z)
    175 
    176 #define VEC3ADD(T, lhs, rhs) \
    177 	VEC3(T, (lhs).xyz.x + (rhs).xyz.x, (lhs).xyz.y + (rhs).xyz.y, (lhs).xyz.z + (rhs).xyz.z)
    178 #define VEC3SUB(T, lhs, rhs) \
    179 	VEC3(T, (lhs).xyz.x - (rhs).xyz.x, (lhs).xyz.y - (rhs).xyz.y, (lhs).xyz.z - (rhs).xyz.z)
    180 #define VEC3MUL(T, lhs, rhs) \
    181 	VEC3(T, (lhs).xyz.x * (rhs).xyz.x, (lhs).xyz.y * (rhs).xyz.y, (lhs).xyz.z * (rhs).xyz.z)
    182 #define VEC3DIV(T, lhs, rhs) \
    183 	VEC3(T, (lhs).xyz.x / (rhs).xyz.x, (lhs).xyz.y / (rhs).xyz.y, (lhs).xyz.z / (rhs).xyz.z)
    184 
    185 #define VEC3ADDS(T, lhs, scalar) \
    186 	VEC3(T, (lhs).xyz.x + scalar, (lhs).xyz.y + scalar, (lhs).xyz.z + scalar)
    187 #define VEC3SUBS(T, lhs, scalar) \
    188 	VEC3(T, (lhs).xyz.x - scalar, (lhs).xyz.y - scalar, (lhs).xyz.z - scalar)
    189 #define VEC3MULS(T, lhs, scalar) \
    190 	VEC3(T, (lhs).xyz.x * scalar, (lhs).xyz.y * scalar, (lhs).xyz.z * scalar)
    191 #define VEC3DIVS(T, lhs, scalar) \
    192 	VEC3(T, (lhs).xyz.x / scalar, (lhs).xyz.y / scalar, (lhs).xyz.z / scalar)
    193 
    194 #define VEC3LEN2(lhs) \
    195 	(((lhs).xyz.x * (lhs).xyz.x) + ((lhs).xyz.y * (lhs).xyz.y) + ((lhs).xyz.z * (lhs).xyz.z))
    196 
    197 #define VEC3LEN(lhs) sqrt(VEC3LEN2(lhs))
    198 
    199 #define VEC3LERP(a, b, t) \
    200 	VEC3ADD(__typeof__ (a), \
    201 		VEC3MULS(__typeof__ (a), (a), (1 - (t))), \
    202 		VEC3MULS(__typeof__ (b), (b), (t)))
    203 
    204 #define VEC3DOT(lhs, rhs) \
    205 	(((lhs).xyz.x * (rhs).xyz.x) + ((lhs).xyz.y * (rhs).xyz.y) + ((lhs).xyz.z * (rhs).xyz.z))
    206 
    207 #define VEC3CROSS(T, lhs, rhs) \
    208 	VEC3(T, \
    209 	     (((lhs).xyz.y * (rhs).xyz.z) - ((lhs).xyz.z * (rhs).xyz.y)), \
    210 	     (((lhs).xyz.z * (rhs).xyz.x) - ((lhs).xyz.x * (rhs).xyz.z)), \
    211 	     (((lhs).xyz.x * (rhs).xyz.y) - ((lhs).xyz.y * (rhs).xyz.x)))
    212 
    213 #define VEC3UNIT(lhs) \
    214 	VEC3(__typeof__ (lhs), \
    215 	     (lhs).xyz.x / VEC3LEN(lhs), \
    216 	     (lhs).xyz.y / VEC3LEN(lhs), \
    217 	     (lhs).xyz.z / VEC3LEN(lhs))
    218 
    219 typedef union vec4i {
    220 	int32_t vs[4];
    221 	struct {
    222 		int32_t x, y, z, w;
    223 	} xyzw;
    224 } vec4i_t;
    225 
    226 typedef union vec4u {
    227 	uint32_t vs[4];
    228 	struct {
    229 		uint32_t x, y, z, w;
    230 	} xyzw;
    231 } vec4u_t;
    232 
    233 typedef union vec4f {
    234 	float vs[4];
    235 	struct {
    236 		float x, y, z, w;
    237 	} xyzw;
    238 } vec4f_t;
    239 
    240 typedef union vec4d {
    241 	double vs[4];
    242 	struct {
    243 		double x, y, z, w;
    244 	} xyzw;
    245 } vec4d_t;
    246 
    247 #define VEC4(T, x, y, z, w) ((T) { .vs = { (x), (y), (z), (w), }, })
    248 
    249 #define VEC40(T) VEC4(T, 0, 0, 0, 0)
    250 #define VEC41(T) VEC4(T, 1, 1, 1, 1)
    251 
    252 #define VEC4NEG(lhs) \
    253 	VEC4(__typeof__ (lhs), -(lhs).xyzw.x, -(lhs).xyzw.y, -(lhs).xyzw.z, -(lhs).xyzw.w)
    254 
    255 #define VEC4ADD(T, lhs, rhs) \
    256 	VEC4(T, (lhs).xyzw.x + (rhs).xyzw.x, (lhs).xyzw.y + (rhs).xyzw.y, (lhs).xyzw.z + (rhs).xyzw.z, (lhs).xyzw.w + (rhs).xyzw.w)
    257 #define VEC4SUB(T, lhs, rhs) \
    258 	VEC4(T, (lhs).xyzw.x - (rhs).xyzw.x, (lhs).xyzw.y - (rhs).xyzw.y, (lhs).xyzw.z - (rhs).xyzw.z, (lhs).xyzw.w - (rhs).xyzw.w)
    259 #define VEC4MUL(T, lhs, rhs) \
    260 	VEC4(T, (lhs).xyzw.x * (rhs).xyzw.x, (lhs).xyzw.y * (rhs).xyzw.y, (lhs).xyzw.z * (rhs).xyzw.z, (lhs).xyzw.w * (rhs).xyzw.w)
    261 #define VEC4DIV(T, lhs, rhs) \
    262 	VEC4(T, (lhs).xyzw.x / (rhs).xyzw.x, (lhs).xyzw.y / (rhs).xyzw.y, (lhs).xyzw.z / (rhs).xyzw.z, (lhs).xyzw.w / (rhs).xyzw.w)
    263 
    264 #define VEC4ADDS(T, lhs, scalar) \
    265 	VEC4(T, (lhs).xyzw.x + scalar, (lhs).xyzw.y + scalar, (lhs).xyzw.z + scalar, (lhs).xyzw.w + scalar)
    266 #define VEC4SUBS(T, lhs, scalar) \
    267 	VEC4(T, (lhs).xyzw.x - scalar, (lhs).xyzw.y - scalar, (lhs).xyzw.z - scalar, (lhs).xyzw.w - scalar)
    268 #define VEC4MULS(T, lhs, scalar) \
    269 	VEC4(T, (lhs).xyzw.x * scalar, (lhs).xyzw.y * scalar, (lhs).xyzw.z * scalar, (lhs).xyzw.w * scalar)
    270 #define VEC4DIVS(T, lhs, scalar) \
    271 	VEC4(T, (lhs).xyzw.x / scalar, (lhs).xyzw.y / scalar, (lhs).xyzw.z / scalar, (lhs).xyzw.w / scalar)
    272 
    273 #define VEC4LEN2(lhs) \
    274 	(((lhs).xyzw.x * (lhs).xyzw.x) + ((lhs).xyzw.y * (lhs).xyzw.y) + ((lhs).xyzw.z * (lhs).xyzw.z) + ((lhs).xyzw.w * (lhs).xyzw.w))
    275 
    276 #define VEC4LEN(lhs) sqrt(VEC4LEN2(lhs))
    277 
    278 #define VEC4LERP(a, b, t) \
    279 	VEC4ADD(__typeof__ (a), \
    280 		VEC4MULS(__typeof__ (a), (a), (1 - (t))), \
    281 		VEC4MULS(__typeof__ (b), (b), (t)))
    282 
    283 #define VEC4DOT(lhs, rhs) \
    284 	(((lhs).xyzw.x * (rhs).xyzw.x) + ((lhs).xyzw.y * (rhs).xyzw.y) + ((lhs).xyzw.z * (rhs).xyzw.z))
    285 
    286 #define VEC4UNIT(lhs) \
    287 	VEC4(__typeof__ (lhs), \
    288 	     (lhs).xyzw.x / VEC4LEN(lhs), \
    289 	     (lhs).xyzw.y / VEC4LEN(lhs), \
    290 	     (lhs).xyzw.z / VEC4LEN(lhs), \
    291 	     (lhs).xyzw.w / VEC4LEN(lhs))
    292 
    293 #define DEG2RAD(degrees) (((degrees) * M_PI) / 180)
    294 
    295 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
    296 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
    297 
    298 #define CLAMP(max, min, v) MAX(MIN((max), (v)), (min))
    299 
    300 // raytracing utilities
    301 // ==========================================================================
    302 
    303 typedef vec3f_t point_t;
    304 
    305 struct ray {
    306 	point_t origin;
    307 	vec3f_t direction;
    308 };
    309 
    310 inline vec3f_t
    311 ray_at(struct ray const *ray, float t)
    312 {
    313 	return VEC3ADD(vec3f_t, ray->origin, VEC3MULS(vec3f_t, ray->direction, t));
    314 }
    315 
    316 struct hit_record {
    317 	point_t point;
    318 	vec3f_t normal;
    319 	float t;
    320 
    321 	int front_face;
    322 };
    323 
    324 inline void
    325 hit_record_set_face_normal(struct hit_record *record, struct ray const *ray,
    326 			   vec3f_t outward_normal)
    327 {
    328 	record->front_face = VEC3DOT(ray->direction, outward_normal) < 0;
    329 	record->normal = record->front_face ? outward_normal : VEC3NEG(outward_normal);
    330 }
    331 
    332 struct interval {
    333 	float min, max;
    334 };
    335 
    336 #define EMPTY_INTERVAL ((struct interval) { +INFINITY, -INFINITY, })
    337 #define UNIVERSE_INTERVAL ((struct interval) { -INFINITY, +INFINITY, })
    338 
    339 inline int
    340 interval_contains(struct interval interval, float v)
    341 {
    342 	return interval.min <= v && v <= interval.max;
    343 }
    344 
    345 inline int
    346 interval_surrounds(struct interval interval, float v)
    347 {
    348 	return interval.min < v && v < interval.max;
    349 }
    350 
    351 struct hittable {
    352 	int (*impl)(struct hittable *data, struct ray const *ray,
    353 		    struct interval t, struct hit_record *record);
    354 
    355 	struct list_node list_node;
    356 };
    357 
    358 struct sphere {
    359 	point_t centre;
    360 	float radius;
    361 
    362 	struct hittable hittable;
    363 };
    364 
    365 inline int
    366 sphere_hittable_impl(struct hittable *data, struct ray const *ray,
    367 		     struct interval t, struct hit_record *record)
    368 {
    369 	struct sphere *self = TO_PARENT_PTR(data, struct sphere, hittable);
    370 
    371 	vec3f_t oc = VEC3SUB(point_t, self->centre, ray->origin);
    372 
    373 	float a = VEC3LEN2(ray->direction);
    374 	float h = VEC3DOT(ray->direction, oc);
    375 	float c = VEC3LEN2(oc) - (self->radius * self->radius);
    376 	float discriminant = (h * h) - (a * c);
    377 
    378 	if (discriminant < 0)
    379 		return 0;
    380 
    381 	float sqrtd = sqrt(discriminant);
    382 
    383 	float root = (h - sqrtd) / a;
    384 	if (interval_surrounds(t, root))
    385 		goto found_valid_root;
    386 
    387 	root = (h + sqrtd) / a;
    388 	if (interval_surrounds(t, root))
    389 		goto found_valid_root;
    390 
    391 	return 0;
    392 
    393 found_valid_root:
    394 	record->t = root;
    395 	record->point = ray_at(ray, record->t);
    396 
    397 	vec3f_t outward_normal = VEC3DIVS(vec3f_t,
    398 					VEC3SUB(vec3f_t, record->point, self->centre),
    399 					self->radius);
    400 	hit_record_set_face_normal(record, ray, outward_normal);
    401 
    402 	return 1;
    403 }
    404 
    405 typedef vec3f_t color_t;
    406 
    407 // bitmap utilities
    408 // ===========================================================================
    409 
    410 typedef uint32_t pixel_t;
    411 
    412 enum pixel_format {
    413 	PIXEL_FORMAT_ARGB32,
    414 };
    415 
    416 inline pixel_t
    417 pixel_from_argb32(uint8_t a, uint8_t r, uint8_t g, uint8_t b)
    418 {
    419 	return (((uint32_t) a) << 24) | \
    420 	       (((uint32_t) r) << 16) | \
    421 	       (((uint32_t) g) << 8) | \
    422 	       (((uint32_t) b));
    423 }
    424 
    425 inline pixel_t
    426 pixel_from_color(color_t color, enum pixel_format format)
    427 {
    428 	assert(format == PIXEL_FORMAT_ARGB32);
    429 
    430 	uint8_t a = 255;
    431 	uint8_t r = color.xyz.x * 255;
    432 	uint8_t g = color.xyz.y * 255;
    433 	uint8_t b = color.xyz.z * 255;
    434 
    435 	switch (format) {
    436 	case PIXEL_FORMAT_ARGB32: return pixel_from_argb32(a, r, g, b);
    437 	}
    438 }
    439 
    440 inline void
    441 pixel_format_set_masks(enum pixel_format format,
    442 		       uint32_t *r, uint32_t *g, uint32_t *b, uint32_t *a)
    443 {
    444 	/* NOTE: bitmap field masks are big endian! */
    445 	switch (format) {
    446 	case PIXEL_FORMAT_ARGB32:
    447 		*r = 0x0000ff00;
    448 		*g = 0x00ff0000;
    449 		*b = 0xff000000;
    450 		*a = 0x000000ff;
    451 		break;
    452 	}
    453 }
    454 
    455 /* see: https://en.wikipedia.org/wiki/BMP_file_format */
    456 inline void
    457 bitmap_write(int fd, pixel_t *buf, size_t width, size_t height, enum pixel_format format)
    458 {
    459 	uint32_t pixels = width * height;
    460 	uint32_t pixel_bytes = pixels * sizeof(pixel_t);
    461 
    462 	uint32_t dib_header_size = 108;
    463 	uint32_t bitmap_header_size = 14;
    464 	uint32_t header_size = bitmap_header_size + dib_header_size;
    465 
    466 	uint32_t file_size = header_size + pixel_bytes;
    467 	uint32_t reserved = 0;
    468 
    469 	int32_t xres = width, yres = -height;
    470 	uint16_t planes = 1, bits_per_pixel = sizeof(pixel_t) * 8;
    471 	uint32_t compression = 3; /* 3 = bitfields */
    472 	uint32_t xdpi = 0, ydpi = 0;
    473 	uint32_t palette = 0, important = 0;
    474 
    475 	uint32_t r_mask, g_mask, b_mask, a_mask;
    476 	pixel_format_set_masks(format, &r_mask, &g_mask, &b_mask, &a_mask);
    477 
    478 	unsigned char colorspace[4] = "sRGB";
    479 	unsigned char endpoints[36];
    480 	memset(endpoints, 0, sizeof endpoints);
    481 
    482 	uint32_t r_gamma = 0, g_gamma = 0, b_gamma = 0;
    483 
    484 	/* bitmap header */
    485 	write(fd, "BM", 2);
    486 	write(fd, &file_size, sizeof file_size);
    487 	write(fd, &reserved, sizeof reserved);
    488 	write(fd, &header_size, sizeof header_size);
    489 
    490 	/* dib header: BITMAPV4HEADER */
    491 	write(fd, &dib_header_size, sizeof dib_header_size);
    492 	write(fd, &xres, sizeof xres);
    493 	write(fd, &yres, sizeof yres);
    494 	write(fd, &planes, sizeof planes);
    495 	write(fd, &bits_per_pixel, sizeof bits_per_pixel);
    496 	write(fd, &compression, sizeof compression);
    497 	write(fd, &pixel_bytes, sizeof pixel_bytes);
    498 	write(fd, &xdpi, sizeof xdpi);
    499 	write(fd, &ydpi, sizeof ydpi);
    500 	write(fd, &palette, sizeof palette);
    501 	write(fd, &important, sizeof important);
    502 	write(fd, &r_mask, sizeof r_mask);
    503 	write(fd, &g_mask, sizeof g_mask);
    504 	write(fd, &b_mask, sizeof b_mask);
    505 	write(fd, &a_mask, sizeof a_mask);
    506 	write(fd, colorspace, sizeof colorspace);
    507 	write(fd, endpoints, sizeof endpoints);
    508 	write(fd, &r_gamma, sizeof r_gamma);
    509 	write(fd, &g_gamma, sizeof g_gamma);
    510 	write(fd, &b_gamma, sizeof b_gamma);
    511 
    512 	/* pixel data */
    513 	write(fd, buf, pixel_bytes);
    514 }
    515 
    516 // rt definitions
    517 // ===========================================================================
    518 
    519 struct world {
    520 	struct list_node objects;
    521 };
    522 
    523 inline void
    524 world_init(struct world *world)
    525 {
    526 	world->objects = LIST_INIT(world->objects);
    527 }
    528 
    529 inline void
    530 world_push(struct world *world, struct hittable *hittable)
    531 {
    532 	list_push_tail(&world->objects, &hittable->list_node);
    533 }
    534 
    535 void
    536 render(pixel_t *image, size_t image_width, size_t image_height, struct world *world);
    537 
    538 #endif /* RT_H */