diff options
89 files changed, 1983 insertions, 1863 deletions
@@ -15,28 +15,8 @@ Makefile Makefile.in # Documentation files created by make -/doc/*.aux -/doc/*.cp -/doc/*.cps -/doc/*.dvi -/doc/*.fn -/doc/*.fns -/doc/*.html/ -/doc/*.info -/doc/*.ky -/doc/*.kys -/doc/*.log -/doc/*.pdf -/doc/*.pg -/doc/*.pgs -/doc/*.ps -/doc/*.tmp -/doc/*.toc -/doc/*.tp -/doc/*.tps -/doc/*.vr -/doc/*.vrs -/doc/texinfo.tex +/doc/libdimension +Doxyfile # pkg-config files *.pc diff --git a/Makefile.am b/Makefile.am index 6c6848a..5f9bd53 100644 --- a/Makefile.am +++ b/Makefile.am @@ -28,7 +28,7 @@ EXTRA_DIST = autogen.sh if PGO -.PHONY: pgo bench +.PHONY: pgo bench doc pgo: @if [ ! -d $(top_builddir)/libdimension/pgo/.libs ] || [ -z "$$(ls $(top_builddir)/libdimension/pgo/.libs/*.gcda 2>/dev/null)" ]; then \ $(MAKE) $(AM_MAKEFLAGS) -C libdimension libdimension-pgo.la && \ @@ -44,8 +44,11 @@ pgo: all-recursive check-recursive install-recursive installcheck-recursive distdir: pgo else ## PGO -.PHONY: bench +.PHONY: bench doc endif ## PGO bench: all-recursive cd bench && $(MAKE) $(AM_MAKEFLAGS) bench + +doc: + cd libdimension && $(MAKE) $(AM_MAKEFLAGS) doc @@ -1,9 +1,5 @@ This is Dimension, a project to create a GPLed, POV-Ray compatible ray tracer. -It is currently stable but lacking in features, to the point of unusability. -But if you want to try it anyway, see the INSTALL file for how to compile and -run it. For a quick demo, run ./autogen.sh && ./configure && make check, and -look at tests/dimension/demo.{pov,png}. - -Documentation for the `dimension' program will eventually be in the doc/ -directory. (Out of date) API documentation for the ray tracing library -libdimension is also in doc/. +It is currently stable but lacking in features. But if you want to try it +anyway, see the INSTALL file for how to compile and run it. For a quick demo, +run ./autogen.sh && ./configure && make check, and look at +tests/dimension/demo.{pov,png}. diff --git a/bench/libdimension/geometry.c b/bench/libdimension/geometry.c index bc351b5..99757ae 100644 --- a/bench/libdimension/geometry.c +++ b/bench/libdimension/geometry.c @@ -169,11 +169,5 @@ main(void) }); printf("dmnsn_line_point(): %ld\n", sandglass.grains); - /* dmnsn_line_index() */ - sandglass_bench_fine(&sandglass, { - result = dmnsn_line_index(line, vector); - }); - printf("dmnsn_line_index(): %ld\n", sandglass.grains); - return EXIT_SUCCESS; } diff --git a/configure.ac b/configure.ac index 0170fa0..266e990 100644 --- a/configure.ac +++ b/configure.ac @@ -128,6 +128,7 @@ dnl Generate Makefiles AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_FILES([Makefile libdimension/Makefile + libdimension/Doxyfile libdimension/libdimension.pc dimension/Makefile tests/Makefile diff --git a/dimension/realize.c b/dimension/realize.c index e6de1a4..40ff114 100644 --- a/dimension/realize.c +++ b/dimension/realize.c @@ -435,7 +435,6 @@ dmnsn_realize_camera(dmnsn_astnode astnode) ); camera = dmnsn_new_perspective_camera(); - dmnsn_set_perspective_camera_trans(camera, trans); break; } @@ -443,6 +442,7 @@ dmnsn_realize_camera(dmnsn_astnode astnode) dmnsn_assert(false, "Unsupported camera type."); } + camera->trans = trans; return camera; } @@ -990,7 +990,7 @@ dmnsn_realize_box(dmnsn_astnode astnode) } static dmnsn_object * -dmnsn_realize_cylinder(dmnsn_astnode astnode) +dmnsn_realize_cone(dmnsn_astnode astnode) { dmnsn_astnode pnode1, rnode1, pnode2, rnode2, open; @@ -1021,28 +1021,27 @@ dmnsn_realize_cylinder(dmnsn_astnode astnode) double theta1 = dmnsn_vector_axis_angle(dmnsn_y, dir, dmnsn_x); double theta2 = dmnsn_vector_axis_angle(dmnsn_y, dir, dmnsn_z); - dmnsn_object *cylinder - = dmnsn_new_cylinder(r1, r2, dmnsn_realize_integer(open)); - /* Transformations: lift the cylinder to start at the origin, scale, rotate, + dmnsn_object *cone = dmnsn_new_cone(r1, r2, dmnsn_realize_integer(open)); + /* Transformations: lift the cone to start at the origin, scale, rotate, and translate properly */ - cylinder->trans = dmnsn_translation_matrix(dmnsn_new_vector(0.0, 1.0, 0.0)); - cylinder->trans = dmnsn_matrix_mul( + cone->trans = dmnsn_translation_matrix(dmnsn_new_vector(0.0, 1.0, 0.0)); + cone->trans = dmnsn_matrix_mul( dmnsn_scale_matrix(dmnsn_new_vector(1.0, l/2.0, 1.0)), - cylinder->trans + cone->trans ); - cylinder->trans = dmnsn_matrix_mul( + cone->trans = dmnsn_matrix_mul( dmnsn_rotation_matrix(dmnsn_new_vector(theta1, 0.0, 0.0)), - cylinder->trans + cone->trans ); - cylinder->trans = dmnsn_matrix_mul( + cone->trans = dmnsn_matrix_mul( dmnsn_rotation_matrix(dmnsn_new_vector(0.0, 0.0, theta2)), - cylinder->trans + cone->trans ); - cylinder->trans = dmnsn_matrix_mul( + cone->trans = dmnsn_matrix_mul( dmnsn_translation_matrix(p1), - cylinder->trans + cone->trans ); - return cylinder; + return cone; } static dmnsn_object * @@ -1210,7 +1209,7 @@ dmnsn_realize_object(dmnsn_astnode astnode, dmnsn_array *lights) break; case DMNSN_AST_CONE: case DMNSN_AST_CYLINDER: - object = dmnsn_realize_cylinder(onode); + object = dmnsn_realize_cone(onode); break; case DMNSN_AST_DIFFERENCE: object = dmnsn_realize_difference(onode, modifiers, lights); diff --git a/doc/Makefile.am b/doc/Makefile.am index 5f5c9db..7aed436 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -16,7 +16,3 @@ ## You should have received a copy of the GNU General Public License ## ## along with this program. If not, see <http://www.gnu.org/licenses/>. ## ########################################################################### - -info_TEXINFOS = libdimension.texi - -libdimension_la_TEXI = libdimension.texi diff --git a/doc/libdimension.texi b/doc/libdimension.texi deleted file mode 100644 index 5939a20..0000000 --- a/doc/libdimension.texi +++ /dev/null @@ -1,1032 +0,0 @@ -\input texinfo @c -*- Texinfo -*- -@c %**start of header -@setfilename libdimension.info -@settitle The Dimension 3-D Rendering Library -@c %**end of header - -@c Combine variable and function indicies -@syncodeindex vr fn - -@c Wrap code examples at 72 chars, please - -@copying -Copyright @copyright{} 2009-2010 Tavian Barnes -@end copying - -@titlepage -@title The Dimension Library -@page -@vskip 0pt plus 1filll -@insertcopying -@end titlepage - -@contents - -@ifnottex -@node Top -@top The Dimension Library - -@insertcopying -@end ifnottex - -@menu -* Introduction:: An introduction to the Dimension Library -* Error Handling:: How libdimension handles warnings and errors -* Arrays:: A generic interface for arrays of arbitrary objects -* Lists:: A generic interface for lists of arbitrary objects -* Asynchronicity:: An interface for controlling background tasks -* Geometry:: Geometric types like vectors, transformation matricies, and lines -* Color:: Correct color handling -* Canvases:: Where the results of rendering are stored -* Objects:: Physical objects in a scene -* Cameras:: How a 3-D image is seen in 2-D -* Scenes:: Scene objects which hold everything needed to render an image -* Type Index:: -* Function and Constant Index:: -* Concept Index:: -@end menu - - -@node Introduction -@chapter Introduction - -@cindex introduction -@cindex overview -The Dimension Library is a C library for rendering photo-realistic 3-D scenes. -It is the workhorse for the ``dimension'' program. -The Dimension Library is currently in the very early stages of development, but does support rendering scenes with transparency and reflection. - -The C library is probably not the interface you want to use; the ``dimension'' program will render scenes specified in POV-Ray's Scene Description Language. -This documentation gives a bottom-up overview of the Dimension Library, to allow readers to have a full and complete understanding of the library, rather than a simple top-down overview. - -@menu -* Common Definitions:: Definitions used across the Dimension Library -* Memory Allocation:: Wrappers for malloc() and friends -@end menu - -@node Common Definitions -@section Common Definitions - -@example -@tindex dmnsn_free_fn -typedef void dmnsn_free_fn(void *ptr); -@end example - -@code{dmnsn_free_fn} is a type whose signature matches that of @code{free()}, and which is used as a destructor callback type across the Dimension Library. - -@node Memory Allocation -@section Memory Allocation -@example -@findex dmnsn_malloc() -void *dmnsn_malloc(size_t size); -@findex dmnsn_realloc() -void *dmnsn_realloc(void *ptr, size_t size); -@findex dmnsn_strdup() -char *dmnsn_strdup(const char *s); -@end example - -@code{dmnsn_malloc()} is a wrapper for @code{malloc()} which is guaranteed to have succeeded if it returns, hence eliminating the need for checking its return value for @code{NULL}. -If @code{malloc()} should fail, @code{dmnsn_malloc()} reports an error with @code{dmnsn_error()}, which cancels the calling thread (@pxref{Error Handling}). -@code{dmnsn_realloc()} and @code{dmnsn_strdup()} behave similarly, wrapping @code{realloc()} and @code{strdup()} respectively. - - -@node Error Handling -@chapter Error Handling - -@example -@tindex dmnsn_severity -typedef enum @{ - @vindex DMNSN_SEVERITY_LOW - DMNSN_SEVERITY_LOW, /* Only die on low resilience */ - @vindex DMNSN_SEVERITY_MEDIUM - DMNSN_SEVERITY_MEDIUM, /* Die on low or medium resilience */ - @vindex DMNSN_SEVERITY_HIGH - DMNSN_SEVERITY_HIGH /* Always die */ -@} dmnsn_severity; - -@findex dmnsn_error() -#define dmnsn_error(severity, str) /* ... */ - -@findex dmnsn_assert() -#define dmnsn_assert(expression, str) /* ... */ - -@findex dmnsn_get_resilience() -dmnsn_severity dmnsn_get_resilience(); -@findex dmnsn_set_resilience() -void dmnsn_set_resilience(dmnsn_severity resilience); -@end example - -@cindex errors -@cindex warnings -When it makes sense, libdimension reports errors by returning error codes from its functions. -However, when errors are not severe, when said function should not fail, or when the error is very serious, libdimension reports errors using the macro @code{dmnsn_error()}. -@code{dmnsn_error()} takes two parameters: the severity of the error, and a string description of the error. -The macro will conveniently report the description, as well as the function name and code line where the error occured, to standard error. -The severity can be either @code{DMNSN_SEVERITY_LOW}, @code{DMNSN_SEVERITY_MEDIUM}, or @code{DMNSN_SEVERITY_HIGH}. - -@code{dmnsn_assert()} is used for checking invariants. -Like @code{assert()}, when @code{NDEBUG} is defined, this macro generates no code. -However, when @code{NDEBUG} is not defined and @code{expression} evaluates to @code{false}, @code{dmnsn_assert()} will terminate the current thread with @code{dmnsn_error(DMNSN_SEVERITY_HIGH, str)}. - -@cindex resilience -The Dimension Library has also has a user-settable resilience. -The resilience controls the minimum severity at which the library considers an error to be fatal, and terminates the calling thread. -As such, errors of severity @code{DMNSN_SEVERITY_HIGH} are always fatal. -libdimension's resilience defaults to @code{DMNSN_SEVERITY_MEDIUM}, but can be inspected or changed thread-safely by @code{dmnsn_get_resilience()} or @code{dmnsn_set_resilience()}, respectively. -Warnings (non-fatal errors) are formatted like this: - -@example -Dimension WARNING: <function>, <file>:<line>: <description> -@end example - -@noindent while errors are formatted like this: - -@example -Dimension ERROR: <function>, <file>:<line>: <description> -@end example - -@noindent possibly followed by a backtrace. - - -@node Arrays -@chapter Arrays - -@example -@tindex dmnsn_array * -typedef struct @{ - /* ... */ -@} dmnsn_array; - -/* Array allocation */ -@findex dmnsn_new_array() -dmnsn_array *dmnsn_new_array(size_t obj_size); -@findex dmnsn_delete_array() -void dmnsn_delete_array(dmnsn_array *array); - -@findex dmnsn_array_push() -void dmnsn_array_push(dmnsn_array *array, const void *obj); -@findex dmnsn_array_pop() -void dmnsn_array_pop(dmnsn_array *array, void *obj); -@findex dmnsn_array_get() -void dmnsn_array_get(const dmnsn_array *array, size_t i, void *obj); -@findex dmnsn_array_set() -void dmnsn_array_set(dmnsn_array *array, size_t i, const void *obj); - -@findex dmnsn_array_first() -void *dmnsn_array_first(const dmnsn_array *array); -@findex dmnsn_array_last() -void *dmnsn_array_last(const dmnsn_array *array); -@findex dmnsn_array_at() -void *dmnsn_array_at(const dmnsn_array *array, size_t i); - -@findex dmnsn_array_insert() -void dmnsn_array_insert(dmnsn_array *array, size_t i, const void *obj) -@findex dmnsn_array_remove() -void dmnsn_array_remove(dmnsn_array *array, size_t i) - -@findex dmnsn_array_size() -size_t dmnsn_array_size(const dmnsn_array *array); -@findex dmnsn_array_resize() -void dmnsn_array_resize(dmnsn_array *array, size_t length); - -@findex DMNSN_ARRAY_FOREACH () -#define DMNSN_ARRAY_FOREACH (type, i, array) /* ... */ -@end example - -@cindex array -The Dimension Library often has cause to work with adjustable-size arrays. -It provides an interface for dynamically-allocated arrays of arbitrary objects. -Arrays are allocated with the @code{dmnsn_new_array()} function, and freed with the @code{dmnsn_delete_array()} function, a pattern common in libdimension. -@code{dmnsn_new_array()} takes the size of the new array's elements as its parameter. - -Arrays support the push, pop, get, set, insert, and remove operations for arrays, taking a pointer to an object to read or write as their last parameter, the array index (when applicable) as the second-last parameter, and the @code{dmnsn_array *} as the first parameter. -The get, remove, and pop operations are bounds-checked; other operations dynamically resize the array as needed. -The array's length may be queried with @code{dmnsn_array_size()}, or set with @code{dmnsn_array_resize()}. -A pointer to the first object is returned by @code{dmnsn_array_first()}, the last object by @code{dmnsn_array_last()}, and a pointer to the @code{i}'th object may be obtained with @code{dmnsn_array_at()}. - -The @code{DMNSN_ARRAY_FOREACH ()} macro expands to an appropriate for loop iterating over an array. -@code{type} should be a type that points to the type of objects in the array, @code{i} will be the name of the pointer which iterates over the array, and @code{array} is the array to iterate over. For example: - -@example -DMNSN_ARRAY_FOREACH (int *, i, array) @{ - printf("%d\n", *i); -@} -@end example - - -@node Lists -@chapter Lists - -@example -@tindex dmnsn_list * -typedef struct @{ - /* ... */ -@} dmnsn_list; - -@tindex dmnsn_list_iterator * -typedef struct @{ - /* ... */ -@} dmnsn_list_iterator; - -/* List allocation */ -@findex dmnsn_new_list() -dmnsn_array *dmnsn_new_list(size_t obj_size); -@findex dmnsn_delete_list() -void dmnsn_delete_list(dmnsn_array *array); - -/* Construction to/from arrays */ -@findex dmnsn_list_from_array() -dmnsn_list *dmnsn_list_from_array(const dmnsn_array *array); -@findex dmnsn_array_from_list() -dmnsn_array *dmnsn_array_from_list(const dmnsn_list *list); - -/* Iteration */ - -@findex dmnsn_list_first() -dmnsn_list_iterator *dmnsn_list_first(const dmnsn_list *list); -@findex dmnsn_list_last() -dmnsn_list_iterator *dmnsn_list_last(const dmnsn_list *list); -@findex dmnsn_list_size() -size_t dmnsn_list_size(const dmnsn_list *list); - -@findex dmnsn_list_prev() -dmnsn_list_iterator *dmnsn_list_prev(const dmnsn_list_iterator *i); -@findex dmnsn_list_next() -dmnsn_list_iterator *dmnsn_list_next(const dmnsn_list_iterator *i); - -/* Element access */ -@findex dmnsn_list_get() -void dmnsn_list_get(const dmnsn_list_iterator *i, void *obj); -@findex dmnsn_list_set() -void dmnsn_list_set(dmnsn_list_iterator *i, const void *obj); -@findex dmnsn_list_swap() -void dmnsn_list_swap(dmnsn_list_iterator *a, dmnsn_list_iterator *b); - -/* Insertion/removal */ -@findex dmnsn_list_push() -void dmnsn_list_push(dmnsn_list *list, const void *obj); -@findex dmnsn_list_pop() -void dmnsn_list_pop(dmnsn_list *list, void *obj); -@findex dmnsn_list_insert() -void dmnsn_list_insert(dmnsn_list *list, dmnsn_list_iterator *i, - const void *obj) -@findex dmnsn_list_remove() -void dmnsn_list_remove(dmnsn_list *list, dmnsn_list_iterator *i) - -/* Splits a list in half, and returns the second half */ -@findex dmnsn_list_split() -dmnsn_list *dmnsn_list_split(dmnsn_list *list); - -/* Sort a list */ -@tindex dmnsn_list_comparator_fn -typedef bool dmnsn_list_comparator_fn(dmnsn_list_iterator *l, - dmnsn_list_iterator *r); -@findex dmnsn_list_sort() -void dmnsn_list_sort(dmnsn_list *list, - dmnsn_list_comparator_fn *comparator); -@end example - -@cindex list -Generic doubly-linked lists are also provided by the Dimension Library. -They are allocated and freed by @code{dmnsn_new_list()} and @code{dmnsn_delete_list()}, respectively. -They can also be constructed from @code{dmnsn_array *}'s by @code{dmnsn_list_from_array()}, and converted to @code{dmnsn_array *}'s by @code{dmnsn_array_from_list()}. - -List elements are accessed with an iterator type, @code{dmnsn_list_iterator *}. -The previous or next list element is found with @code{dmnsn_list_prev()} or @code{dmnsn_list_next()}, respectively. -@code{NULL} indicates that you've fallen off the beginning or end of the list. -An iterator to the first or last element of a list is obtained with @code{dmnsn_list_first()} or @code{dmnsn_list_last()}. -The size of a list is given by @code{dmnsn_list_size()}. - -An object can be retrieved from a @code{dmnsn_list_iterator *} with @code{dmnsn_list_get()}, and set with @code{dmnsn_list_set()}. The objects of two list iterators can be swapped with @code{dmnsn_list_swap()}. - -Objects can be added or removed from the end of a list with @code{dmnsn_list_push()} and @code{dmnsn_list_pop()}. -Elements can be added at arbitrary locations with @code{dmnsn_list_insert()}, which inserts the object before the iterator @code{i} (pass NULL to insert it at the end). -The element at @code{i} can be removed with @code{dmnsn_list_remove()}. - -@code{dmnsn_list_split()} splits the given list in half, and returns the second, possibly smaller half. - -@code{dmnsn_list_sort()} sorts a given list, using a comparison function matching the signature of the @code{dmnsn_list_comparator_fn} type. - - -@node Asynchronicity -@chapter Asynchronicity - -@example -@tindex dmnsn_progress * -typedef struct @{ - /* ... */ -@} dmnsn_progress; - -/* Progress allocation */ -@findex dmnsn_new_progress() -dmnsn_progress *dmnsn_new_progress(); -@findex dmnsn_delete_progress() -void dmnsn_delete_progress(dmnsn_progress *progress); - -/* Ensures completion of the worker thread */ -@findex dmnsn_finish_progress() -int dmnsn_finish_progress(dmnsn_progress *progress); - -/* Routines for users */ -@findex dmnsn_get_progress() -double dmnsn_get_progress(const dmnsn_progress *progress); -@findex dmnsn_wait_progress() -void dmnsn_wait_progress(const dmnsn_progress *progress, double prog); - -/* Routines for worker threads */ -@findex dmnsn_new_progress_element() -void dmnsn_new_progress_element(dmnsn_progress *progress, - unsigned int total); -@findex dmnsn_increment_progress() -void dmnsn_increment_progress(dmnsn_progress *progress); -@findex dmnsn_done_progress() -void dmnsn_done_progress(dmnsn_progress *progress); -@end example - -@cindex asynchronous task -@cindex background task -@cindex progress indicator -As the Dimension Library is a raytracing engine, some routines are likely to take a long time. -These routines may be run in a background thread, and controlled with a common interface. -Routines supporting this interface end in @code{_async}, such as @code{dmnsn_raytrace_scene_async()}, and return a @code{dmnsn_progress *} object, so named because it allows an application to be query the progress of the background task. -By necessity, all @code{dmnsn_progress *} operations are atomic and thread-safe. - -Progress objects are allocated and deallocated in the standard libdimension way, but also support a unique @code{dmnsn_finish_progress()} function. -This function waits for the background thread to complete, and then destroys the @code{dmnsn_progress *} object. -Never use the result of a background task before calling @code{dmnsn_finish_progress()}, even if the progress seems to be at 100%! @code{dmnsn_delete_progress()} should only be called from within failed @code{*_async()} functions, to deallocate a progress object before it is associated with a running thread. - -Users of these asynchronous tasks will mainly be interested in the functions @code{dmnsn_get_progress()} and @code{dmnsn_wait_progress()}. -@code{dmnsn_get_progress()} returns the progress of the background task, a value between 0.0 and 1.0. -@code{dmnsn_wait_progress()} simply waits for @code{dmnsn_get_progress()} to be >= @code{prog}, but in a much better way than spinlocking (internally, a condition variable is used). - -Background tasks themselves will be interested in three more functions. -To indicate progress to the user, progress objects store one "element" for each level of loop nesting a task would like to report the progress of. -Only the innermost loop need increment the progress counter, as in this example: - -@example -dmnsn_new_progress_element(progress, i_max); -for (i = 0; i < i_max; ++i) @{ - dmnsn_new_progress_element(progress, j_max); - for (j = 0; j < j_max; ++j) @{ - /* Do stuff */ - dmnsn_increment_progress(progress); - @} -@} -@end example - -For robustness, tasks should call @code{dmnsn_done_progress()} when they finish, even if they fail. -This function immediately sets the progress to 100%, which wakes up all waiters. -Otherwise, a user's application may hang calling @code{dmnsn_wait_progress()}. - - -@node Geometry -@chapter Geometry - -@example -/* Vector and matrix types. */ - -@tindex dmnsn_vector -typedef struct @{ - double x, y, z; -@} dmnsn_vector; - -@tindex dmnsn_matrix -typedef struct @{ - double n[4][4]; -@} dmnsn_matrix; - -/* A line, or ray. */ -@tindex dmnsn_line -typedef struct @{ - dmnsn_vector x0; /* A point on the line */ - dmnsn_vector n; /* A normal vector; the direction of the line */ -@} dmnsn_line; - -@tindex dmnsn_bounding_box -typedef struct @{ - dmnsn_vector min; - dmnsn_vector max; -@} dmnsn_bounding_box; - -/* Vector/matrix construction */ - -@findex dmnsn_new_vector() -dmnsn_vector dmnsn_new_vector(double x, double y, double z); - -@findex dmnsn_new_matrix() -dmnsn_matrix -dmnsn_new_matrix(double a0, double a1, double a2, double a3, - double b0, double b1, double b2, double b3, - double c0, double c1, double c2, double c3, - double d0, double d1, double d2, double d3); - -@findex dmnsn_identity_matrix() -dmnsn_matrix dmnsn_identity_matrix(); -@findex dmnsn_scale_matrix() -dmnsn_matrix dmnsn_scale_matrix(dmnsn_vector s); -@findex dmnsn_translation_matrix() -dmnsn_matrix dmnsn_translation_matrix(dmnsn_vector d); -@findex dmnsn_rotation_matrix() -dmnsn_matrix dmnsn_rotation_matrix(dmnsn_vector theta); - -@findex dmnsn_new_line() -dmnsn_line dmnsn_new_line(dmnsn_vector x0, dmnsn_vector n); - -/* Vector and matrix arithmetic */ - -@findex dmnsn_vector_add() -dmnsn_vector dmnsn_vector_add(dmnsn_vector lhs, dmnsn_vector rhs); -@findex dmnsn_vector_sub() -dmnsn_vector dmnsn_vector_sub(dmnsn_vector lhs, dmnsn_vector rhs); -@findex dmnsn_vector_mul() -dmnsn_vector dmnsn_vector_mul(double lhs, dmnsn_vector rhs); -@findex dmnsn_vector_div() -dmnsn_vector dmnsn_vector_div(dmnsn_vector lhs, double rhs); - -@findex dmnsn_vector_dot() -double dmnsn_vector_dot(dmnsn_vector lhs, dmnsn_vector rhs); -@findex dmnsn_vector_cross() -dmnsn_vector dmnsn_vector_cross(dmnsn_vector lhs, dmnsn_vector rhs); - -@findex dmnsn_vector_norm() -double dmnsn_vector_norm(dmnsn_vector n); -@findex dmnsn_vector_normalize() -dmnsn_vector dmnsn_vector_normalize(dmnsn_vector n); - -@findex dmnsn_matrix_inverse() -dmnsn_matrix dmnsn_matrix_inverse(dmnsn_matrix A); -@findex dmnsn_matrix_mul() -dmnsn_matrix dmnsn_matrix_mul(dmnsn_matrix lhs, dmnsn_matrix rhs); -@findex dmnsn_transform_vector() -dmnsn_vector dmnsn_transform_vector(dmnsn_matrix lhs, - dmnsn_vector rhs); -@findex dmnsn_transform_bounding_box() -dmnsn_bounding_box dmnsn_transform_bounding_box(dmnsn_matrix lhs, - dmnsn_bounding_box rhs); -@findex dmnsn_transform_line() -dmnsn_line dmnsn_transform_line(dmnsn_matrix lhs, dmnsn_line rhs); - -@findex dmnsn_line_point() -dmnsn_vector dmnsn_line_point(dmnsn_line l, double t); -@findex dmnsn_line_index() -double dmnsn_line_index(dmnsn_line l, dmnsn_vector x); -@end example - -@cindex scalar -@cindex vector -@cindex matrix -@cindex line -@cindex ray -For performing 3-D computational geometry, the Dimension Library supports geometric types and many operations on these types. -libdimension defines the @code{dmnsn_vector}, @code{dmnsn_matrix}, and @code{dmnsn_line} geometric types. -They may be easily constructed by the self-explanatory @code{dmnsn_new_vector()}, @code{dmnsn_new_matrix()}, or @code{dmnsn_new_line()}. - -@cindex transformation -@cindex norm -@cindex normalization -@cindex dot product -@cindex cross product -Vectors support addition and subtraction, multiplication and division by a scalar, the dot and cross products, the norm and normalization operations, and transformation by a matrix (@code{dmnsn_transform_vector()}). - -@cindex matrix inversion -Matricies support matrix multiplication, and inversion. -Inversion uses a very fast partitioning algorithm. -As well, there are four special matrix constructors. -@code{dmnsn_identity_matrix()} simply returns the identity matrix. -@code{dmnsn_scale_matrix(s)} returns a matrix which scales each dimension by a factor of the corresponding dimension of the @code{s}. -@code{dmnsn_translate_matrix(d)} returns a matrix which translates by @code{d}. -Finally, @code{dmnsn_rotation_matrix(theta)} returns a matrix which rotates by an angle of @code{dmnsn_vector_norm(theta)}, about the axis @code{dmnsn_vector_normalize(theta)}. - -Lines support transformation by a matrix (@code{dmnsn_transform_line(A, l) = dmnsn_new_line(A*l.x0, A*(l.x0 + l.n) - A*l.x0)}). -Also, @code{dmnsn_line_point(l, t) = l.x0 + t*l.n} gives the point @code{t} on the line, and @code{dmnsn_line_index(l, x)} gives the @code{t} value such that @code{dmnsn_line_point(l, t) == x}. - -@cindex bounding boxes -@cindex axis-aligned bounding boxes -Axis-aligned bounding boxes are represented by the @code{dmnsn_bounding_box} type, with their minimum extent in the @code{.min} field, and their maximum extent in the @code{.max} field. -They may be transformed by a matrix with @code{dmnsn_transform_bounding_box()}. - - -@node Color -@chapter Color - -@example -@tindex dmnsn_color -typedef struct @{ - double filter, trans; /* Filter transparancy only lets light of this - color through; regular transparancy lets all - colors through. filter + trans should be - <= 1.0. */ - /* ... */ -@} dmnsn_color; - -@tindex dmnsn_CIE_XYZ -typedef struct @{ - double X, Y, Z; /* X, Y, and Z are tristimulus values, unbounded - above zero. -Diffuse white is (0.9505, 1, - 1.089). */ -@} dmnsn_CIE_XYZ; - -@tindex dmnsn_CIE_xyY -typedef struct @{ - double x, y, Y; /* x and y are chromaticity coordinates, and Y is - luminance, in the CIE 1931 xyZ color space. -We - use an unlimited light model, so x,y in [0, 1] and - Y >= 0, with 1 = diffuse white */ -@} dmnsn_CIE_xyY; - -@tindex dmnsn_CIE_Lab -typedef struct @{ - double L, a, b; /* L is luminence (100 = diffuse white); a and b are - color-opponent dimensions. -This color space is - used for color arithmetic. */ -@} dmnsn_CIE_Lab; - -@tindex dmnsn_CIE_Luv -typedef struct @{ - double L, u, v; /* L is luminence (100 = diffuse white); u and v are - chromaticity coordinates. */ -@} dmnsn_CIE_Luv; - -@tindex dmnsn_sRGB -typedef struct @{ - double R, G, B; /* sRGB R, G, and B values */ -@} dmnsn_sRGB; - -/* Standard colors */ -@vindex dmnsn_black -@vindex dmnsn_white -@vindex dmnsn_red -@vindex dmnsn_green -@vindex dmnsn_blue -@vindex dmnsn_magenta -@vindex dmnsn_yellow -@vindex dmnsn_cyan -extern const dmnsn_color dmnsn_black, dmnsn_white, dmnsn_red, - dmnsn_green, dmnsn_blue, dmnsn_magenta, dmnsn_yellow, dmnsn_cyan; - -/* Standard whitepoint, determined by the conversion of sRGB white to - CIE XYZ */ -@vindex dmnsn_whitepoint -extern const dmnsn_CIE_XYZ dmnsn_whitepoint; - -/* Color conversions */ - -@findex dmnsn_color_from_XYZ() -dmnsn_color dmnsn_color_from_XYZ(dmnsn_CIE_XYZ XYZ); -@findex dmnsn_color_from_xyY() -dmnsn_color dmnsn_color_from_xyY(dmnsn_CIE_xyY xyY); -@findex dmnsn_color_from_Lab() -dmnsn_color dmnsn_color_from_Lab(dmnsn_CIE_Lab Lab, - dmnsn_CIE_XYZ white); -@findex dmnsn_color_from_Luv() -dmnsn_color dmnsn_color_from_Luv(dmnsn_CIE_Luv Luv, - dmnsn_CIE_XYZ white); -@findex dmnsn_color_from_sRGB() -dmnsn_color dmnsn_color_from_sRGB(dmnsn_sRGB sRGB); - -@findex dmnsn_XYZ_from_color() -dmnsn_CIE_XYZ dmnsn_XYZ_from_color(dmnsn_color color); -@findex dmnsn_xyY_from_color() -dmnsn_CIE_xyY dmnsn_xyY_from_color(dmnsn_color color); -@findex dmnsn_Lab_from_color() -dmnsn_CIE_Lab dmnsn_Lab_from_color(dmnsn_color color, - dmnsn_CIE_XYZ white); -@findex dmnsn_Luv_from_color() -dmnsn_CIE_Luv dmnsn_Luv_from_color(dmnsn_color color, - dmnsn_CIE_XYZ white); -@findex dmnsn_sRGB_from_color() -dmnsn_sRGB dmnsn_sRGB_from_color(dmnsn_color color); - -/* Is this color black? */ -@findex dmsnn_color_is_black() -bool dmnsn_color_is_black(dmnsn_color color); - -/* Perceptual color manipulation */ -@findex dmnsn_color_add() -dmnsn_color dmnsn_color_add(dmnsn_color color1, dmnsn_color color2); -@findex dmnsn_color_mul() -dmnsn_color dmnsn_color_mul(double n, dmnsn_color color); -@findex dmnsn_color_gradient() -dmnsn_color dmnsn_color_gradient(dmnsn_color c1, dmnsn_color c2, - double n); -@findex dmnsn_color_filter() -dmnsn_color dmnsn_color_filter(dmnsn_color color, dmnsn_color filter); -@findex dmnsn_color_illuminate() -dmnsn_color dmnsn_color_illuminate(dmnsn_color light, - dmnsn_color color); - -/* Perceptual color difference */ -@findex dmnsn_color_difference() -double dmnsn_color_difference(dmnsn_color color1, dmnsn_color color2); -@end example - -@cindex color -@cindex CIE XYZ -@cindex CIE xyY -@cindex CIE L*a*b* -@cindex CIE L*u*v* -@cindex sRGB -@cindex RGB -The Dimension Library supports many different representations of color. -The details of each representation are beyond the scope of this manual, but libdimension supports CIE XYZ, xyY, L*a*b*, L*u*v*, and sRGB color. -CIE L*a*b* and L*u*v* are designed to be perceptually uniform, meaning changes in their color coordinates correspond to perceptual changes of equal magnitude. -The @code{dmnsn_color} type is used by libdimension itself to represent colors, internally in the sRGB color space. -The @code{.filter} field gives the color's filtered transparency, which lets same-colored light through, while the @code{.trans} field stores non-filtered transparency. - -The @code{dmnsn_color_from_*()} and @code{dmnsn_*_from_color()} functions are used to convert to and from the @code{dmnsn_color} type. -The conversions to @code{dmnsn_color} set the @code{.filter} and @code{.trans} fields to zero, and those fields are ignored by the inverse conversions. -Conversions to and from CIE L*a*b* and L*u*v* colors take an extra parameter, which specifies the absolute color value of the whitepoint the conversions are relative to. -@code{dmnsn_whitepoint} is a good value for this parameter. - -@code{dmnsn_color_add()} adds two colors in a perceptually-correct way. -@code{dmnsn_color_mul()} scales the brightness of a color. -@code{dmnsn_color_gradient()} returns the color at point @code{n} on a gradient from @code{c1} at 0 to @code{c2} at 1. -@code{dmnsn_color_filter()} returns the color obtained by filtering @code{color} through @code{filter}. -@code{dmnsn_color_illuminate()} return the color obtained by illuminating @code{color} with @code{light}-colored light. -@code{dmnsn_color_difference()} returns the magnatude of the perceptual difference between two colors. - - -@node Canvases -@chapter Canvases - -@example -@tindex dmnsn_canvas * -typedef struct @{ - /* width, height */ - unsigned int x, y; - - /* An array of dmnsn_canvas_optimizer's - see below */ - dmnsn_array *optimizers; - - /* ... */ -@} dmnsn_canvas; - -/* Allocate and free a canvas */ -@findex dmnsn_new_canvas() -dmnsn_canvas *dmnsn_new_canvas(unsigned int x, unsigned int y); -@findex dmnsn_delete_canvas() -void dmnsn_delete_canvas(dmnsn_canvas *canvas); - -/* Pixel accessors */ -@findex dmnsn_get_pixel() -dmnsn_color dmnsn_get_pixel(const dmnsn_canvas *canvas, - unsigned int x, unsigned int y); -@findex dmnsn_set_pixel() -void dmnsn_set_pixel(dmnsn_canvas *canvas, - unsigned int x, unsigned int y, - dmnsn_color color); -@end example - -@cindex canvas -@cindex rendering target -The target of a rendering operation in the Dimension Library is a canvas object, represented by the type @code{dmnsn_canvas *}. -This type stores the dimensions of the canvas in the @code{->x} and @code{->y} fields. -The pixel at (x,y) can be examined or set by the accessors @code{dmnsn_get_pixel()} and @code{dmnsn_set_pixel()}. - -Canvases may be imported from or exported to images. -In the future, canvases will also be able to be treated as object textures, to support images as textures. - -@menu -* PNG Import and Export:: Importing and exporting canvases to and from PNG files -* OpenGL:: Drawing and reading canvases to and from OpenGL buffers -* Canvas Optimization:: Optimizing a canvas for a later export -@end menu - -@node PNG Import and Export -@section PNG Import and Export - -@example -/* Optimize canvas for PNG exporting */ -@findex dmnsn_png_optimize_canvas() -int dmnsn_png_optimize_canvas(dmnsn_canvas *canvas); - -/* Write canvas to file in PNG format. Returns 0 on success, nonzero - on failure */ -@findex dmnsn_png_write_canvas() -int dmnsn_png_write_canvas(const dmnsn_canvas *canvas, FILE *file); -@findex dmnsn_png_write_canvas_async() -dmnsn_progress * -dmnsn_png_write_canvas_async(const dmnsn_canvas *canvas, FILE *file); - -/* Read a canvas from a PNG file. -Returns NULL on failure. */ -@findex dmnsn_png_read_canvas() -dmnsn_canvas *dmnsn_png_read_canvas(FILE *file); -@findex dmnsn_png_read_canvas_async() -dmnsn_progress *dmnsn_png_read_canvas_async(dmnsn_canvas **canvas, - FILE *file); -@end example - -@cindex PNG -The Dimension Library supports import and export of canvas to and from PNG files; this is currently the only supported image type. -The interface is simple: @code{dmnsn_png_write_canvas()} writes the canvas in PNG format to the given file, at maximum quality; @code{dmnsn_png_read_canvas()} imports a PNG file to a canvas. -The @code{*_async()} versions work as described in @ref{Asynchronicity}. -If it is known in advance that a canvas will be exported to a PNG file, calling @code{dmnsn_png_optimize_canvas()} on it before it is written to will speed up the export process; see @ref{Canvas Optimization}. - -@node OpenGL -@section OpenGL - -@example -/* Optimize canvas for GL drawing */ -@findex dmnsn_gl_optimize_canvas() -int dmnsn_gl_optimize_canvas(dmnsn_canvas *canvas); - -/* Write canvas to GL framebuffer. Returns 0 on success, nonzero on - failure. */ -@findex dmnsn_gl_write_canvas() -int dmnsn_gl_write_canvas(const dmnsn_canvas *canvas); - -/* Read a canvas from a GL framebuffer. -Returns NULL on failure. */ -@findex dmnsn_gl_read_canvas() -dmnsn_canvas *dmnsn_gl_read_canvas(unsigned int x0, unsigned int y0, - unsigned int width, - unsigned int height); -@end example - -@cindex GL -@cindex OpenGL -Canvases may be written to or read from an OpenGL buffer with the @code{dmnsn_gl_write_canvas()} and @code{dmnsn_gl_read_canvas()} functions, respectively. -Writing uses the @code{glDrawPixels()} GL function, and reading uses the @code{glReadPixels()} function. -@code{dmnsn_gl_read_canvas()} starts reading at (@code{x0}, @code{y0}), and reads a @code{width}*@code{height} sized image. -These operations should be fast (especially if optimized), so no @code{..._async()} versions are supplied. -If it is known in advance that a canvas will be drawn to an OpenGL buffer, calling @code{dmnsn_gl_optimize_canvas()} on it before it is written to will speed up the export process; see @ref{Canvas Optimization}. - -@node Canvas Optimization -@section Canvas Optimization - -@example -/* Canvas optimizer callback types */ -@tindex dmnsn_canvas_optimizer_fn -typedef void dmnsn_canvas_optimizer_fn(dmnsn_canvas *canvas, - dmnsn_canvas_optimizer optimizer, - unsigned int x, unsigned int y); - -/* Canvas optimizer */ -@tindex dmnsn_canvas_optimizer -typedef struct @{ - dmnsn_canvas_optimizer_fn *optimizer_fn; - dmnsn_free_fn *free_fn; - void *ptr; -@} dmnsn_canvas_optimizer; - -/* Set a canvas optimizer */ -@findex dmnsn_optimize_canvas() -int dmnsn_optimize_canvas(dmnsn_canvas *canvas, - dmnsn_canvas_optimizer optimizer); -@end example - -@cindex optimization, canvas -@cindex optimization, export -If a canvas is to be exported to a different format, the export process can be sped up if the pixels are stored in the target format as they are written to a canvas. -This is what canvas optimizers do: they register callbacks that are triggered upon a @code{dmnsn_set_pixel()} call, generally storing the color in the appropriate format for the target (sRGB for PNG, for example) in some other buffer. -Then the exporting process is a breeze, because the canvas doesn't have to be converted to another format. - -The @code{dmnsn_canvas_optimizer} type stores a pointer to a callback function to be executed upon calls to @code{dmnsn_set_pixel()} in its @code{.optimizer_fn} field. -This function should match the signature of the @code{dmnsn_canvas_optimizer_fn} type. -Its @code{.ptr} field stores a generic pointer to any type of data the optimizer may wish to store. -This pointer will be provided to its @code{.free_fn} callback when @code{dmnsn_delete_canvas()} is called, and may simply point to the standard library @code{free} function. - -To register a new canvas optimizer, the program should first check that the same optimization hasn't already been applied by examining the @code{dmnsn_canvas *}'s @code{->optimizers} array, and testing each @code{dmnsn_canvas_optimizer}'s @code{.optimizer_fn} for equality with the address of the new callback. -If the optimization hasn't yet been applied, the program should call @code{dmnsn_optimize_canvas()}, which returns 0 if it succeeded, and nonzero otherwise. -Note that this function will fail if @code{dmnsn_set_pixel()} has ever been called on the target canvas, since pixels which have already been set would not be known to the optimizer. - -@node Objects -@chapter Objects - -@example -@tindex dmnsn_object * -typedef struct @{ - /* Surface properties */ - dmnsn_texture *texture; - - /* Transformation matrix */ - dmnsn_matrix trans, trans_inv; - - /* Bounding box */ - dmnsn_vector min, max; - - /* Callback functions */ - dmnsn_object_intersection_fn *intersection_fn; - dmnsn_object_inside_fn *inside_fn; - dmnsn_free_fn *free_fn; - - /* Generic pointer for object info */ - void *ptr; -@} dmnsn_object; - -/* Object callback types */ -@tindex dmnsn_object_intersections_fn -typedef dmnsn_intersection * -dmnsn_object_intersection_fn(const dmnsn_object *object, - dmnsn_line line); -@tindex dmnsn_object_inside_fn -typedef bool dmnsn_object_inside_fn(const dmnsn_object *object, - dmnsn_vector point); - -/* Allocate a dummy object */ -@findex dmnsn_new_object() -dmnsn_object *dmnsn_new_object(); -@findex dmnsn_delete_object() -void dmnsn_delete_object(dmnsn_object *object); -@end example - -@cindex object -The Dimension Library renders 3-D objects, represented by the @code{dmnsn_object *} type. -This type has callback functions for determining if and where a ray intersects the object, and whether a point is inside the object. -In the future, many more callbacks will be added. -libdimension comes with a few simple object types like spheres and cubes, or you may create your own by customizing the object callbacks. -The field @code{->ptr} is a void pointer which may be used to store additional information about an object. -The @code{->trans} field is a transformation matrix, transforming the rays which intersect the object, rather than the object itself. -Thus, @code{->trans} should be set to the inverse of the transformations you wish to apply to the object. - -@cindex object callbacks -The @code{->intersection_fn} callback should point to a function with the same signature as the @code{dmnsn_object_intersection_fn} type. -It should return a @code{dmnsn_intersection *} corresponding to the closest intersection, or @code{NULL} if the ray does not intersect the object. - -The @code{->inside_fn} callback should point to a function matching the signature of the @code{dmnsn_object_inside_fn} type. -It should return 0 if the given @code{point} is outside the object, and nonzero when that point is inside the object. -The callback is free to return any value in the case that the point lies directly on the surface of the object. - -@menu -* Spheres:: Spheres -* Cubes:: Cubes -@end menu - -@node Spheres -@section Spheres - -@example -@findex dmnsn_new_sphere() -dmnsn_object *dmnsn_new_sphere(); -@end example - -@cindex sphere -The Dimension Library has a few built-in basic shape primitives. -One of them is the sphere; @code{dmnsn_new_sphere()} returns a sphere of radius 1, centered at the origin. -Use the object's transformation matrix to scale, translate, and/or rotate it. - -@node Cubes -@section Cubes - -@example -@findex dmnsn_new_cube() -dmnsn_object *dmnsn_new_cube(); -@end example - -@cindex cube -@code{dmnsn_new_cube()} returns a cube, axis-aligned, from (-1, -1, -1) to (1, 1, 1). -Use its transformation matrix to scale, translate, and/or rotate it. - - -@node Cameras -@chapter Cameras - -@example -@tindex dmnsn_camera * -typedef struct @{ - /* Callback functions */ - dmnsn_camera_ray_fn *ray_fn; - dmnsn_free_fn *free_fn; - - /* Generic pointer for camera info */ - void *ptr; -@} dmnsn_camera; - -/* Camera callback types */ -@tindex dmnsn_camera_ray_fn -typedef dmnsn_line dmnsn_camera_ray_fn(const dmnsn_camera *camera, - double x, double y); - -@findex dmnsn_new_camera() -dmnsn_camera *dmnsn_new_camera(); -@findex dmnsn_delete_camera() -void dmnsn_delete_camera(dmnsn_camera *camera); -@end example - -@cindex camera -In order to project a 3-D scene onto a 2-D plane, the Dimension Library uses a generic camera type. -A camera provides the Dimension Library the camera ray corresponding to each pixel in the canvas, by its @code{->ray_fn} callback. - -@code{->ray_fn} should point to a function matching the signature of the type @code{dmnsn_camera_ray_fn}, and should return the ray corresponding to the pixel at (@code{x}, @code{y}) in a hypothetical square canvas from (0, 0) to (1, 1). - -@menu -* Perspective Cameras:: Simple perspective cameras -@end menu - -@node Perspective Cameras -@section Perspective Cameras - -@example -@findex dmnsn_new_perspective_camera() -dmnsn_camera *dmnsn_new_perspective_camera(); - -/* Get or set the transformation matrix */ -dmnsn_matrix -dmnsn_get_perspective_camera_trans(const dmnsn_camera *camera); -void dmnsn_set_perspective_camera_trans(dmnsn_camera *camera, - dmnsn_matrix T); -@end example - -@cindex perspective -The function @code{dmnsn_new_perspective_camera} creates a perspective camera, situated at the origin, looking toward (0, 0, 1), and aiming at a screen from (-0.5, -0.5) to (0.5, 0.5) on the z = 1 plane. -Camera rays may be transformed by a matrix set by @code{dmnsn_set_perspective_camera_trans()} and retrieved by @code{dmnsn_get_perspective_camera_trans()}. - - -@node Scenes -@chapter Scenes - -@example - -enum @{ - DMNSN_RENDER_NONE = /* ... */, - DMNSN_RENDER_PIGMENT = /* ... */, - DMNSN_RENDER_LIGHTS = /* ... */, - DMNSN_RENDER_FINISH = /* ... */, - DMNSN_RENDER_TRANSLUCENCY = /* ... */, - DMNSN_RENDER_REFLECTION = /* ... */, - DMNSN_RENDER_FULL = ~DMNSN_RENDER_NONE -@}; - -@tindex dmnsn_quality -typedef unsigned int dmnsn_quality; - -@tindex dmnsn_scene * -typedef struct @{ - /* World attributes */ - dmnsn_color background; - dmnsn_texture *default_texture; - - /* Camera */ - dmnsn_camera *camera; - - /* Canvas */ - dmnsn_canvas *canvas; - - /* Objects */ - dmnsn_array *objects; - - /* Lights */ - dmnsn_array *lights; - - /* Rendering quality */ - dmnsn_quality quality; - - /* Recursion limit */ - unsigned int limit; - - /* Number of paralell threads */ - unsigned int nthreads; -@} dmnsn_scene; - -@findex dmnsn_new_scene() -dmnsn_scene *dmnsn_new_scene(); -@findex dmnsn_delete_scene() -void dmnsn_delete_scene(dmnsn_scene *scene); -@end example - -@cindex scene -The @code{dmnsn_scene *} type ties all the components of a 3-D world together. -A scene stores a background color in its @code{->background} field, a @code{dmnsn_array *} of @code{const dmnsn_object *}'s in its @code{->objects} field, a @code{dmnsn_camera *} in its @code{->camera} field, and a @code{dmnsn_canvas *} in its @code{->canvas} field. -Scenes can be rendered, producing an image in their canvas field. - -@menu -* Raytracing:: Rendering a scene by raytracing -@end menu - -@node Raytracing -@section Raytracing - -@example -@findex dmnsn_raytrace_scene() -int dmnsn_raytrace_scene(dmnsn_scene *scene); -@findex dmnsn_raytrace_scene_async() -dmnsn_progress *dmnsn_raytrace_scene_async(dmnsn_scene *scene); -@end example - -@cindex raytracing -The @code{dmnsn_raytrace_scene()} function renders a scene by raytracing - casting rays from the camera to objects in its view. -The @code{..._async()} version works as described in @ref{Asynchronicity}. - - -@node Type Index -@unnumbered Type Index - -@printindex tp - - -@node Function and Constant Index -@unnumbered Function and Constant Index - -@printindex fn - - -@node Concept Index -@unnumbered Concept Index - -@printindex cp - -@bye diff --git a/libdimension/Doxyfile.in b/libdimension/Doxyfile.in new file mode 100644 index 0000000..23d7bfb --- /dev/null +++ b/libdimension/Doxyfile.in @@ -0,0 +1,43 @@ +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = libdimension +PROJECT_NUMBER = @VERSION@ +OUTPUT_DIRECTORY = @top_builddir@/doc/libdimension +OUTPUT_LANGUAGE = English +FULL_PATH_NAMES = YES +OPTIMIZE_OUTPUT_FOR_C = YES +IGNORE_PREFIX = dmnsn_ DMNSN_ +JAVADOC_AUTOBRIEF = YES +TYPEDEF_HIDES_STRUCT = YES +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_STATIC = YES +SORT_MEMBER_DOCS = NO +ALWAYS_DETAILED_SEC = YES +HIDE_UNDOC_MEMBERS = YES +INPUT = dimension.h dimension +INPUT_ENCODING = UTF-8 +# Hack to get DMNSN_INLINE documentation to show up. +INPUT_FILTER = "sed 's/#ifndef DMNSN_INLINE/#if 1/g'" +FILE_PATTERNS = *.h +EXCLUDE_PATTERNS = *-stubs.c +SOURCE_BROWSER = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +EXPAND_AS_DEFINED = "DMNSN_INLINE" +PREDEFINED = "__STDC_VERSION__=199901L" "__GNUC__" + +INTERNAL_DOCS = NO +#INTERNAL_DOCS = YES +#INPUT = . dimension +#FILE_PATTERNS = *.c *.h +#EXTRACT_LOCAL_CLASSES = YES +#REFERENCED_BY_RELATION = YES +#REFERENCES_RELATION = YES + +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html + +GENERATE_LATEX = YES +LATEX_OUTPUT = latex + +PREDEFINED = "__STDC_VERSION__=199901L" "__GNUC__" diff --git a/libdimension/Makefile.am b/libdimension/Makefile.am index 87742e0..542e684 100644 --- a/libdimension/Makefile.am +++ b/libdimension/Makefile.am @@ -31,6 +31,7 @@ nobase_include_HEADERS = dimension.h \ dimension/finishes.h \ dimension/geometry.h \ dimension/gl.h \ + dimension/inline.h \ dimension/interior.h \ dimension/light.h \ dimension/lights.h \ @@ -42,6 +43,7 @@ nobase_include_HEADERS = dimension.h \ dimension/patterns.h \ dimension/pigments.h \ dimension/png.h \ + dimension/polynomial.h \ dimension/progress.h \ dimension/raytrace.h \ dimension/scene.h \ @@ -58,9 +60,9 @@ libdimension_la_SOURCES = $(nobase_include_HEADERS) \ checker.c \ color.c \ color_map.c \ + cone.c \ cube.c \ csg.c \ - cylinder.c \ diffuse.c \ dimension-impl.h \ error.c \ @@ -128,9 +130,17 @@ all-local: libdimension.la true; \ done -clean-local: +clean-pgo: rm -rf pgo +clean-local: clean-docs clean-pgo +else +clean-local: clean-docs endif +doc: + doxygen Doxyfile +clean-docs: + rm -rf $(top_builddir)/doc/libdimension + pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libdimension.pc diff --git a/libdimension/ambient.c b/libdimension/ambient.c index 7c68b4c..d00b031 100644 --- a/libdimension/ambient.c +++ b/libdimension/ambient.c @@ -18,14 +18,16 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Ambient finish. + */ + #include "dimension.h" #include <math.h> #include <stdlib.h> -/* - * Ambient finish - */ - +/** Ambient finish callback. */ static dmnsn_color dmnsn_ambient_finish_fn(const dmnsn_finish *finish, dmnsn_color pigment) { diff --git a/libdimension/camera.c b/libdimension/camera.c index 08c4e1a..d963d1b 100644 --- a/libdimension/camera.c +++ b/libdimension/camera.c @@ -18,6 +18,11 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Cameras. + */ + #include "dimension.h" #include <stdlib.h> @@ -27,6 +32,7 @@ dmnsn_new_camera() { dmnsn_camera *camera = dmnsn_malloc(sizeof(dmnsn_camera)); camera->free_fn = NULL; + camera->trans = dmnsn_identity_matrix(); return camera; } @@ -41,3 +47,11 @@ dmnsn_delete_camera(dmnsn_camera *camera) dmnsn_free(camera); } } + +/* Invoke the camera ray function */ +dmnsn_line +dmnsn_camera_ray(const dmnsn_camera *camera, double x, double y) +{ + dmnsn_line ray = (*camera->ray_fn)(camera, x, y); + return dmnsn_transform_line(camera->trans, ray); +} diff --git a/libdimension/canvas.c b/libdimension/canvas.c index da4f1aa..53dd980 100644 --- a/libdimension/canvas.c +++ b/libdimension/canvas.c @@ -18,25 +18,30 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Canveses. + */ + #include "dimension.h" #include <stdlib.h> /* For dmnsn_free() */ /* Allocate a new canvas, of width x and height y */ dmnsn_canvas * -dmnsn_new_canvas(size_t x, size_t y) +dmnsn_new_canvas(size_t width, size_t height) { /* Allocate the dmnsn_canvas struct */ dmnsn_canvas *canvas = dmnsn_malloc(sizeof(dmnsn_canvas)); /* Set the width and height */ - canvas->x = x; - canvas->y = y; + canvas->width = width; + canvas->height = height; /* Allocate room for the optimizers */ canvas->optimizers = dmnsn_new_array(sizeof(dmnsn_canvas_optimizer)); /* Allocate the pixels */ - canvas->pixels = dmnsn_malloc(sizeof(dmnsn_color)*x*y); + canvas->pixels = dmnsn_malloc(sizeof(dmnsn_color)*width*height); return canvas; } @@ -72,8 +77,11 @@ void dmnsn_set_pixel(dmnsn_canvas *canvas, size_t x, size_t y, dmnsn_color color) { + dmnsn_assert(x < canvas->width && y < canvas->height, + "Canvas access out of bounds."); + /* Set the pixel */ - canvas->pixels[y*canvas->x + x] = color; + canvas->pixels[y*canvas->width + x] = color; /* Call the optimizers */ DMNSN_ARRAY_FOREACH (dmnsn_canvas_optimizer *, i, canvas->optimizers) { @@ -85,8 +93,8 @@ dmnsn_set_pixel(dmnsn_canvas *canvas, size_t x, size_t y, void dmnsn_clear_canvas(dmnsn_canvas *canvas, dmnsn_color color) { - for (size_t x = 0; x < canvas->x; ++x) { - for (size_t y = 0; y < canvas->y; ++y) { + for (size_t x = 0; x < canvas->width; ++x) { + for (size_t y = 0; y < canvas->height; ++y) { dmnsn_set_pixel(canvas, x, y, color); } } diff --git a/libdimension/canvas_pigment.c b/libdimension/canvas_pigment.c index c86fc66..a1820c4 100644 --- a/libdimension/canvas_pigment.c +++ b/libdimension/canvas_pigment.c @@ -18,25 +18,14 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -#include "dimension.h" - -/* Canvas color pigment callback */ -static dmnsn_color dmnsn_canvas_pigment_fn(const dmnsn_pigment *pigment, - dmnsn_vector v); -static void dmnsn_canvas_pigment_free_fn(void *ptr); +/** + * @file + * Image maps. + */ -/* Create a canvas color */ -dmnsn_pigment * -dmnsn_new_canvas_pigment(dmnsn_canvas *canvas) -{ - dmnsn_pigment *pigment = dmnsn_new_pigment(); - pigment->pigment_fn = &dmnsn_canvas_pigment_fn; - pigment->free_fn = &dmnsn_canvas_pigment_free_fn; - pigment->ptr = canvas; - return pigment; -} +#include "dimension.h" -/* Canvas color callback */ +/** Canvas pigment color callback. */ static dmnsn_color dmnsn_canvas_pigment_fn(const dmnsn_pigment *pigment, dmnsn_vector v) { @@ -44,14 +33,26 @@ dmnsn_canvas_pigment_fn(const dmnsn_pigment *pigment, dmnsn_vector v) dmnsn_canvas *canvas = pigment->ptr; - int x = (fmod(v.x, 1.0) + 1.0)*(canvas->x - 1) + 0.5; - int y = (fmod(v.y, 1.0) + 1.0)*(canvas->y - 1) + 0.5; - dmnsn_color c = dmnsn_get_pixel(canvas, x%canvas->x, y%canvas->y); + int x = (fmod(v.x, 1.0) + 1.0)*(canvas->width - 1) + 0.5; + int y = (fmod(v.y, 1.0) + 1.0)*(canvas->height - 1) + 0.5; + dmnsn_color c = dmnsn_get_pixel(canvas, x%canvas->width, y%canvas->height); return c; } +/** Canvas pigment destructor. */ static void dmnsn_canvas_pigment_free_fn(void *ptr) { dmnsn_delete_canvas(ptr); } + +/* Create a canvas color */ +dmnsn_pigment * +dmnsn_new_canvas_pigment(dmnsn_canvas *canvas) +{ + dmnsn_pigment *pigment = dmnsn_new_pigment(); + pigment->pigment_fn = &dmnsn_canvas_pigment_fn; + pigment->free_fn = &dmnsn_canvas_pigment_free_fn; + pigment->ptr = canvas; + return pigment; +} diff --git a/libdimension/checker.c b/libdimension/checker.c index 9c1de34..0424cd6 100644 --- a/libdimension/checker.c +++ b/libdimension/checker.c @@ -18,12 +18,14 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -#include "dimension.h" - -/* - * Checker pattern +/** + * @file + * Checker pattern. */ +#include "dimension.h" + +/** Checker pattern callback. */ static double dmnsn_checker_pattern_fn(const dmnsn_pattern *checker, dmnsn_vector v) { @@ -50,7 +52,7 @@ dmnsn_checker_pattern_fn(const dmnsn_pattern *checker, dmnsn_vector v) } dmnsn_pattern * -dmnsn_new_checker_pattern() +dmnsn_new_checker_pattern(void) { dmnsn_pattern *checker = dmnsn_new_pattern(); checker->pattern_fn = &dmnsn_checker_pattern_fn; diff --git a/libdimension/color.c b/libdimension/color.c index eee1f0e..e91ebc1 100644 --- a/libdimension/color.c +++ b/libdimension/color.c @@ -18,6 +18,11 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Color handling. + */ + #include "dimension.h" #include <math.h> /* For pow(), sqrt() */ @@ -97,7 +102,21 @@ dmnsn_color_is_black(dmnsn_color color) return color.R == 0.0 && color.G == 0.0 && color.B == 0.0; } -/* sRGB's `C' function */ +/* Convert an sRGB color to a dmnsn_color (actually a no-op) */ +dmnsn_color +dmnsn_color_from_sRGB(dmnsn_sRGB sRGB) +{ + dmnsn_color ret = { + .R = sRGB.R, + .G = sRGB.G, + .B = sRGB.B, + .filter = 0.0, + .trans = 0.0 + }; + return ret; +} + +/** sRGB's `C' function. */ static double dmnsn_sRGB_C(double Clinear) { @@ -144,7 +163,8 @@ dmnsn_color_from_xyY(dmnsn_CIE_xyY xyY) return dmnsn_color_from_XYZ(ret); } -/* Inverse function of CIE L*a*b*'s `f' function, for the reverse conversion */ +/** Inverse function of CIE L*a*b*'s `f' function, for the reverse + conversion. */ static double dmnsn_Lab_finv(double t) { @@ -195,21 +215,15 @@ dmnsn_color_from_Luv(dmnsn_CIE_Luv Luv, dmnsn_CIE_XYZ white) return dmnsn_color_from_XYZ(ret); } -/* Convert an sRGB color to a dmnsn_color (actually a no-op) */ -dmnsn_color -dmnsn_color_from_sRGB(dmnsn_sRGB sRGB) +/* Convert a dmnsn_color to an sRGB color (actually a no-op) */ +dmnsn_sRGB +dmnsn_sRGB_from_color(dmnsn_color color) { - dmnsn_color ret = { - .R = sRGB.R, - .G = sRGB.G, - .B = sRGB.B, - .filter = 0.0, - .trans = 0.0 - }; - return ret; + dmnsn_sRGB sRGB = { .R = color.R, .G = color.G, .B = color.B }; + return sRGB; } -/* Inverse function of sRGB's `C' function, for the reverse conversion */ +/** Inverse function of sRGB's `C' function, for the reverse conversion. */ static double dmnsn_sRGB_Cinv(double CsRGB) { @@ -260,7 +274,7 @@ dmnsn_xyY_from_color(dmnsn_color color) return ret; } -/* CIE L*a*b*'s `f' function */ +/** CIE L*a*b*'s `f' function. */ static double dmnsn_Lab_f(double t) { @@ -305,14 +319,7 @@ dmnsn_Luv_from_color(dmnsn_color color, dmnsn_CIE_XYZ white) return ret; } -/* Convert a dmnsn_color to an sRGB color (actually a no-op) */ -dmnsn_sRGB -dmnsn_sRGB_from_color(dmnsn_color color) -{ - dmnsn_sRGB sRGB = { .R = color.R, .G = color.G, .B = color.B }; - return sRGB; -} - +/** Greyscale color intensity. */ static double dmnsn_color_intensity(dmnsn_color color) { diff --git a/libdimension/color_map.c b/libdimension/color_map.c index 1123789..f839335 100644 --- a/libdimension/color_map.c +++ b/libdimension/color_map.c @@ -18,19 +18,21 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -#include "dimension.h" - -/* - * Color-mapped patterned pigments +/** + * @file + * Color-mapped pigment patterns. */ +#include "dimension.h" + +/** An [index, color] pair. */ typedef struct dmnsn_color_map_entry { double n; dmnsn_color color; } dmnsn_color_map_entry; dmnsn_color_map * -dmnsn_new_color_map() +dmnsn_new_color_map(void) { return dmnsn_new_array(sizeof(dmnsn_color_map_entry)); } @@ -84,11 +86,13 @@ dmnsn_color_map_value(const dmnsn_color_map *map, double n) return c2; } +/** Payload for a color_map pigment */ typedef struct dmnsn_color_map_payload { dmnsn_pattern *pattern; dmnsn_color_map *map; } dmnsn_color_map_payload; +/** Free a color_map payload. */ static void dmnsn_delete_color_map_payload(void *ptr) { @@ -98,6 +102,7 @@ dmnsn_delete_color_map_payload(void *ptr) dmnsn_free(payload); } +/** color_map pigment callback. */ static dmnsn_color dmnsn_color_map_pigment_fn(const dmnsn_pigment *pigment, dmnsn_vector v) { @@ -106,6 +111,7 @@ dmnsn_color_map_pigment_fn(const dmnsn_pigment *pigment, dmnsn_vector v) dmnsn_pattern_value(payload->pattern, v)); } +/** color_map initialization callback. */ static void dmnsn_color_map_init_fn(dmnsn_pigment *pigment) { diff --git a/libdimension/cylinder.c b/libdimension/cone.c index 9f5b7ff..9f5340a 100644 --- a/libdimension/cylinder.c +++ b/libdimension/cone.c @@ -18,52 +18,26 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -#include "dimension.h" -#include <math.h> - -/* - * Cylinder +/** + * @file + * Cones/cylinders. */ -/* Cylinder callbacks */ -static bool dmnsn_cylinder_intersection_fn(const dmnsn_object *cylinder, - dmnsn_line line, - dmnsn_intersection *intersection); -static bool dmnsn_cylinder_inside_fn(const dmnsn_object *cylinder, - dmnsn_vector point); +#include "dimension.h" +#include <math.h> -/* Payload type */ -typedef struct dmnsn_cylinder_payload { +/** Cone payload type. */ +typedef struct dmnsn_cone_payload { double r1, r2; bool open; -} dmnsn_cylinder_payload; +} dmnsn_cone_payload; -/* Allocate a new cylinder object */ -dmnsn_object * -dmnsn_new_cylinder(double r1, double r2, bool open) -{ - dmnsn_object *cylinder = dmnsn_new_object(); - cylinder->intersection_fn = &dmnsn_cylinder_intersection_fn; - cylinder->inside_fn = &dmnsn_cylinder_inside_fn; - cylinder->bounding_box.min = dmnsn_new_vector(-1.0, -1.0, -1.0); - cylinder->bounding_box.max = dmnsn_new_vector(1.0, 1.0, 1.0); - - dmnsn_cylinder_payload *payload - = dmnsn_malloc(sizeof(dmnsn_cylinder_payload)); - payload->r1 = r1; - payload->r2 = r2; - payload->open = open; - cylinder->ptr = payload; - cylinder->free_fn = &dmnsn_free; - return cylinder; -} - -/* Intersections callback for a cylinder */ +/** Intersection callback for a cone. */ static bool -dmnsn_cylinder_intersection_fn(const dmnsn_object *cylinder, dmnsn_line l, - dmnsn_intersection *intersection) +dmnsn_cone_intersection_fn(const dmnsn_object *cone, dmnsn_line l, + dmnsn_intersection *intersection) { - const dmnsn_cylinder_payload *payload = cylinder->ptr; + const dmnsn_cone_payload *payload = cone->ptr; double r1 = payload->r1, r2 = payload->r2; /* Solve (x0 + nx*t)^2 + (z0 + nz*t)^2 @@ -130,8 +104,8 @@ dmnsn_cylinder_intersection_fn(const dmnsn_object *cylinder, dmnsn_line l, intersection->ray = l; intersection->t = tcap; intersection->normal = norm; - intersection->texture = cylinder->texture; - intersection->interior = cylinder->interior; + intersection->texture = cone->texture; + intersection->interior = cone->interior; return true; } } @@ -143,8 +117,8 @@ dmnsn_cylinder_intersection_fn(const dmnsn_object *cylinder, dmnsn_line l, intersection->ray = l; intersection->t = t; intersection->normal = norm; - intersection->texture = cylinder->texture; - intersection->interior = cylinder->interior; + intersection->texture = cone->texture; + intersection->interior = cone->interior; return true; } } @@ -152,13 +126,33 @@ dmnsn_cylinder_intersection_fn(const dmnsn_object *cylinder, dmnsn_line l, return false; } -/* Inside callback for a cylinder */ +/** Inside callback for a cone. */ static bool -dmnsn_cylinder_inside_fn(const dmnsn_object *cylinder, dmnsn_vector point) +dmnsn_cone_inside_fn(const dmnsn_object *cone, dmnsn_vector point) { - const dmnsn_cylinder_payload *payload = cylinder->ptr; + const dmnsn_cone_payload *payload = cone->ptr; double r1 = payload->r1, r2 = payload->r2; double r = (point.y*(r2 - r1) + r1 + r2)/2.0; return point.x*point.x + point.z*point.z < r*r && point.y > -1.0 && point.y < 1.0; } + +/* Allocate a new cone object */ +dmnsn_object * +dmnsn_new_cone(double r1, double r2, bool open) +{ + dmnsn_object *cone = dmnsn_new_object(); + cone->intersection_fn = &dmnsn_cone_intersection_fn; + cone->inside_fn = &dmnsn_cone_inside_fn; + double rmax = dmnsn_max(r1, r2); + cone->bounding_box.min = dmnsn_new_vector(-rmax, -1.0, -rmax); + cone->bounding_box.max = dmnsn_new_vector(rmax, 1.0, rmax); + + dmnsn_cone_payload *payload = dmnsn_malloc(sizeof(dmnsn_cone_payload)); + payload->r1 = r1; + payload->r2 = r2; + payload->open = open; + cone->ptr = payload; + cone->free_fn = &dmnsn_free; + return cone; +} diff --git a/libdimension/csg.c b/libdimension/csg.c index 58104ff..ff45158 100644 --- a/libdimension/csg.c +++ b/libdimension/csg.c @@ -18,10 +18,15 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Constructive solid geometry. + */ + #include "dimension-impl.h" #include <stdlib.h> -/* Apply the properties of `csg' to its children */ +/** Apply the properties of \p csg to its children. */ static void dmnsn_csg_cascade(const dmnsn_object *csg, dmnsn_object *object) { @@ -38,8 +43,11 @@ dmnsn_csg_cascade(const dmnsn_object *csg, dmnsn_object *object) object->trans = dmnsn_matrix_mul(csg->trans, object->trans); } -/* Unions */ +/* + * Unions + */ +/** CSG union intersection callback. */ static bool dmnsn_csg_union_intersection_fn(const dmnsn_object *csg, dmnsn_line line, @@ -49,6 +57,7 @@ dmnsn_csg_union_intersection_fn(const dmnsn_object *csg, return dmnsn_prtree_intersection(prtree, line, intersection); } +/** CSG union inside callback. */ static bool dmnsn_csg_union_inside_fn(const dmnsn_object *csg, dmnsn_vector point) { @@ -56,6 +65,7 @@ dmnsn_csg_union_inside_fn(const dmnsn_object *csg, dmnsn_vector point) return dmnsn_prtree_inside(prtree, point); } +/** CSG union initialization callback. */ static void dmnsn_csg_union_init_fn(dmnsn_object *csg) { @@ -70,6 +80,7 @@ dmnsn_csg_union_init_fn(dmnsn_object *csg) csg->bounding_box = prtree->bounding_box; } +/** CSG union destruction callback. */ static void dmnsn_csg_union_free_fn(void *ptr) { @@ -78,7 +89,7 @@ dmnsn_csg_union_free_fn(void *ptr) /* Bulk-load a union */ dmnsn_object * -dmnsn_new_csg_union(dmnsn_array *objects) +dmnsn_new_csg_union(const dmnsn_array *objects) { dmnsn_object *csg = dmnsn_new_object(); @@ -94,7 +105,7 @@ dmnsn_new_csg_union(dmnsn_array *objects) return csg; } -/* Generic CSG free function */ +/** Generic CSG destruction callback. */ static void dmnsn_csg_free_fn(void *ptr) { @@ -104,15 +115,22 @@ dmnsn_csg_free_fn(void *ptr) dmnsn_free(ptr); } -/* Generic CSG intersection function */ +/** + * Generic CSG intersection callback. + * @param[in] csg The CSG object. + * @param[in] line The intersection ray. + * @param[out] intersection The intersection data. + * @param[in] inside1 Whether the first object is allowed inside the + * second object. + * @param[in] inside2 Whether the second object is allowed inside the + * first object. + * @return Whether \p line intersected \p csg. + */ static bool dmnsn_csg_intersection_fn(const dmnsn_object *csg, dmnsn_line line, dmnsn_intersection *intersection, bool inside1, bool inside2) { - /* inside1 is whether the second object is allowed inside the first object; - respectively for inside2 */ - const dmnsn_object **params = csg->ptr; dmnsn_intersection i1, i2; @@ -170,8 +188,11 @@ dmnsn_csg_intersection_fn(const dmnsn_object *csg, dmnsn_line line, return true; } -/* Intersections */ +/* + * Intersections + */ +/** CSG intersection intersection callback. */ static bool dmnsn_csg_intersection_intersection_fn(const dmnsn_object *csg, dmnsn_line line, @@ -180,6 +201,7 @@ dmnsn_csg_intersection_intersection_fn(const dmnsn_object *csg, return dmnsn_csg_intersection_fn(csg, line, intersection, true, true); } +/** CSG intersection inside callback. */ static bool dmnsn_csg_intersection_inside_fn(const dmnsn_object *csg, dmnsn_vector point) { @@ -188,6 +210,7 @@ dmnsn_csg_intersection_inside_fn(const dmnsn_object *csg, dmnsn_vector point) && dmnsn_object_inside(params[1], point); } +/** CSG intersection initialization callback. */ static void dmnsn_csg_intersection_init_fn(dmnsn_object *csg) { @@ -226,8 +249,11 @@ dmnsn_new_csg_intersection(dmnsn_object *A, dmnsn_object *B) return csg; } -/* Differences */ +/* + * Differences + */ +/** CSG difference intersection callback. */ static bool dmnsn_csg_difference_intersection_fn(const dmnsn_object *csg, dmnsn_line line, @@ -236,6 +262,7 @@ dmnsn_csg_difference_intersection_fn(const dmnsn_object *csg, return dmnsn_csg_intersection_fn(csg, line, intersection, true, false); } +/** CSG difference inside callback. */ static bool dmnsn_csg_difference_inside_fn(const dmnsn_object *csg, dmnsn_vector point) { @@ -244,6 +271,7 @@ dmnsn_csg_difference_inside_fn(const dmnsn_object *csg, dmnsn_vector point) && !dmnsn_object_inside(params[1], point); } +/** CSG difference initialization callback. */ static void dmnsn_csg_difference_init_fn(dmnsn_object *csg) { @@ -279,8 +307,11 @@ dmnsn_new_csg_difference(dmnsn_object *A, dmnsn_object *B) return csg; } -/* Merges */ +/* + * Merges + */ +/** CSG merge intersection callback. */ static bool dmnsn_csg_merge_intersection_fn(const dmnsn_object *csg, dmnsn_line line, @@ -289,6 +320,7 @@ dmnsn_csg_merge_intersection_fn(const dmnsn_object *csg, return dmnsn_csg_intersection_fn(csg, line, intersection, false, false); } +/** CSG merge inside callback. */ static bool dmnsn_csg_merge_inside_fn(const dmnsn_object *csg, dmnsn_vector point) { @@ -297,6 +329,7 @@ dmnsn_csg_merge_inside_fn(const dmnsn_object *csg, dmnsn_vector point) || dmnsn_object_inside(params[1], point); } +/** CSG merge initialization callback. */ static void dmnsn_csg_merge_init_fn(dmnsn_object *csg) { diff --git a/libdimension/cube.c b/libdimension/cube.c index c70ebf6..6e3120e 100644 --- a/libdimension/cube.c +++ b/libdimension/cube.c @@ -18,33 +18,15 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -#include "dimension.h" -#include <math.h> - -/* - * Cube +/** + * @file + * Cubes. */ -/* Cube callbacks */ -static bool dmnsn_cube_intersection_fn(const dmnsn_object *cube, - dmnsn_line line, - dmnsn_intersection *intersection); -static bool dmnsn_cube_inside_fn(const dmnsn_object *cube, - dmnsn_vector point); - -/* Allocate a new cube object */ -dmnsn_object * -dmnsn_new_cube() -{ - dmnsn_object *cube = dmnsn_new_object(); - cube->intersection_fn = &dmnsn_cube_intersection_fn; - cube->inside_fn = &dmnsn_cube_inside_fn; - cube->bounding_box.min = dmnsn_new_vector(-1.0, -1.0, -1.0); - cube->bounding_box.max = dmnsn_new_vector(1.0, 1.0, 1.0); - return cube; -} +#include "dimension.h" +#include <math.h> -/* Intersections callback for a cube */ +/** Intersection callback for a cube. */ static bool dmnsn_cube_intersection_fn(const dmnsn_object *cube, dmnsn_line line, dmnsn_intersection *intersection) @@ -141,7 +123,7 @@ dmnsn_cube_intersection_fn(const dmnsn_object *cube, dmnsn_line line, } } -/* Inside callback for a cube */ +/** Inside callback for a cube. */ static bool dmnsn_cube_inside_fn(const dmnsn_object *cube, dmnsn_vector point) { @@ -149,3 +131,15 @@ dmnsn_cube_inside_fn(const dmnsn_object *cube, dmnsn_vector point) && point.y > -1.0 && point.y < 1.0 && point.z > -1.0 && point.z < 1.0; } + +/* Allocate a new cube object */ +dmnsn_object * +dmnsn_new_cube() +{ + dmnsn_object *cube = dmnsn_new_object(); + cube->intersection_fn = &dmnsn_cube_intersection_fn; + cube->inside_fn = &dmnsn_cube_inside_fn; + cube->bounding_box.min = dmnsn_new_vector(-1.0, -1.0, -1.0); + cube->bounding_box.max = dmnsn_new_vector(1.0, 1.0, 1.0); + return cube; +} diff --git a/libdimension/diffuse.c b/libdimension/diffuse.c index beafbd8..64a2953 100644 --- a/libdimension/diffuse.c +++ b/libdimension/diffuse.c @@ -18,14 +18,16 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Diffuse finish. + */ + #include "dimension.h" #include <math.h> #include <stdlib.h> -/* - * Diffuse finish - */ - +/** Diffuse finish callback. */ static dmnsn_color dmnsn_diffuse_finish_fn(const dmnsn_finish *finish, dmnsn_color light, dmnsn_color color, diff --git a/libdimension/dimension-impl.h b/libdimension/dimension-impl.h index 7d1f943..2746b1c 100644 --- a/libdimension/dimension-impl.h +++ b/libdimension/dimension-impl.h @@ -18,6 +18,12 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * The internal libdimension API. These functions and types are used to + * implement libdimension, but are not part of its public API. + */ + #ifndef DIMENSION_IMPL_H #define DIMENSION_IMPL_H diff --git a/libdimension/dimension.h b/libdimension/dimension.h index 5f84054..55b3b87 100644 --- a/libdimension/dimension.h +++ b/libdimension/dimension.h @@ -18,8 +18,22 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * libdimension - a library for photo-realistic 3-D rendering +/** + * @file + * The main #include file for libdimension. This file declares all public + * functions and types used by the Dimension library. You should never attempt + * to include any of the component headers in the dimension/ subdirectory + * directly; only this file. + */ + +/** + * @mainpage libdimension - A library for photo-realistic 3-D rendering + * + * The Dimension library (libdimension) is the ray-tracing library that handles + * all rendering-related tasks for Dimension. It is written in C and designed + * with performance and concurrency in mind. It is also generic enough to be + * used for applications other than Dimension, though that is its primary + * purpose. */ #ifndef DIMENSION_H @@ -31,6 +45,11 @@ extern "C" { #endif /* Common types */ + +/** + * Destructor callback type. + * @param[in,out] ptr The pointer to free. + */ typedef void dmnsn_free_fn(void *ptr); /* Include all the libdimension headers */ diff --git a/libdimension/dimension/array.h b/libdimension/dimension/array.h index 87af84a..514e13e 100644 --- a/libdimension/dimension/array.h +++ b/libdimension/dimension/array.h @@ -18,24 +18,30 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Simple generalized arrays, for returning variable-length arrays from - * functions, and other fun stuff. All functions are inline for performance - * reasons. +/** + * @file + * Simple dynamic arrays. */ #ifndef DIMENSION_ARRAY_H #define DIMENSION_ARRAY_H -#include <stdlib.h> /* For size_t */ +#include <stddef.h> /* For size_t */ #include <string.h> /* For memcpy */ -typedef struct { - void *ptr; - size_t obj_size, length, capacity; +/** Dynamic array type */ +typedef struct dmnsn_array { + void *ptr; /**< @internal The actual memory */ + size_t obj_size; /**< @internal The size of each object */ + size_t length; /**< @internal The current size of the array */ + size_t capacity; /**< @internal The size of the allocated space */ } dmnsn_array; -/* Array allocation */ +/** + * Allocate an array. + * @param[in] obj_size The size of the objects to store in the array. + * @return An empty array. + */ DMNSN_INLINE dmnsn_array * dmnsn_new_array(size_t obj_size) { @@ -50,7 +56,10 @@ dmnsn_new_array(size_t obj_size) return array; } -/* Delete an array */ +/** + * Delete an array. + * @param[in,out] array The array to delete. + */ DMNSN_INLINE void dmnsn_delete_array(dmnsn_array *array) { @@ -60,14 +69,22 @@ dmnsn_delete_array(dmnsn_array *array) } } -/* Get the size of the array */ +/** + * Get the size of the array. + * @param[in] array The array in question. + * @return The number of elements in the array. + */ DMNSN_INLINE size_t dmnsn_array_size(const dmnsn_array *array) { return array->length; } -/* Set the size of the array */ +/** + * Set the size of the array. + * @param[in,out] array The array to resize. + * @param[in] length The new length of the array. + */ DMNSN_INLINE void dmnsn_array_resize(dmnsn_array *array, size_t length) { @@ -80,7 +97,12 @@ dmnsn_array_resize(dmnsn_array *array, size_t length) array->length = length; } -/* Get the i'th object, bailing out if i is out of range */ +/** + * Get the i'th element. + * @param[in] array The array to access. + * @param[in] i The index of the element to extract. + * @param[out] obj The location to store the extracted object. + */ DMNSN_INLINE void dmnsn_array_get(const dmnsn_array *array, size_t i, void *obj) { @@ -89,7 +111,12 @@ dmnsn_array_get(const dmnsn_array *array, size_t i, void *obj) } -/* Set the i'th object, expanding the array if necessary */ +/** + * Set the i'th object, expanding the array if necessary. + * @param[in,out] array The array to modify. + * @param[in] i The index to update. + * @param[in] obj The location of the object to copy into the array. + */ DMNSN_INLINE void dmnsn_array_set(dmnsn_array *array, size_t i, const void *obj) { @@ -100,21 +127,34 @@ dmnsn_array_set(dmnsn_array *array, size_t i, const void *obj) memcpy((char *)array->ptr + array->obj_size*i, obj, array->obj_size); } -/* First element */ +/** + * First element. + * @param[in] array The array to index. + * @return The address of the first element of the array. + */ DMNSN_INLINE void * dmnsn_array_first(const dmnsn_array *array) { return array->ptr; } -/* Last element */ +/** + * Last element. + * @param[in] array The array to index. + * @return The address of the last element of the array. + */ DMNSN_INLINE void * dmnsn_array_last(const dmnsn_array *array) { return (char *)array->ptr + array->obj_size*(array->length - 1); } -/* Arbitrary element access */ +/** + * Arbitrary element access. + * @param[in] array The array to index. + * @param[in] i The index to access. + * @return The address of the i'th element of the array. + */ DMNSN_INLINE void * dmnsn_array_at(const dmnsn_array *array, size_t i) { @@ -122,14 +162,22 @@ dmnsn_array_at(const dmnsn_array *array, size_t i) return (char *)array->ptr + array->obj_size*i; } -/* Push obj to the end of the array */ +/** + * Push an object to the end of the array. + * @param[in,out] array The array to append to. + * @param[in] obj The location of the object to push. + */ DMNSN_INLINE void dmnsn_array_push(dmnsn_array *array, const void *obj) { dmnsn_array_set(array, dmnsn_array_size(array), obj); } -/* Pop obj from the end of the array */ +/** + * Pop an object from the end of the array. + * @param[in,out] array The array to pop from. + * @param[out] obj The location to store the extracted object. + */ DMNSN_INLINE void dmnsn_array_pop(dmnsn_array *array, void *obj) { @@ -139,7 +187,12 @@ dmnsn_array_pop(dmnsn_array *array, void *obj) dmnsn_array_resize(array, size - 1); /* Shrink the array */ } -/* Insert an item into the middle of the array */ +/** + * Insert an item into the middle of the array. This is O(n). + * @param[in,out] array The array to insert to. + * @param[in] i The index at which to insert. + * @param[in] obj The object to insert. + */ DMNSN_INLINE void dmnsn_array_insert(dmnsn_array *array, size_t i, const void *obj) { @@ -156,7 +209,11 @@ dmnsn_array_insert(dmnsn_array *array, size_t i, const void *obj) memcpy((char *)array->ptr + array->obj_size*i, obj, array->obj_size); } -/* Remove an item from the middle of the array */ +/** + * Remove an item from the middle of the array. This is O(n). + * @param[in,out] array The array to remove from. + * @param[in] i The index to remove. + */ DMNSN_INLINE void dmnsn_array_remove(dmnsn_array *array, size_t i) { @@ -172,11 +229,29 @@ dmnsn_array_remove(dmnsn_array *array, size_t i) /* Macros to shorten array iteration */ +/** + * Iterate over an array. For example, + * @code + * DMNSN_ARRAY_FOREACH (int *, i, array) { + * printf("%d\n", *i); + * } + * @endcode + * + * @param type The (pointer) type to use as an iterator. + * @param i The name of the iterator within the loop body. + * @param[in] array The array to loop over. + */ #define DMNSN_ARRAY_FOREACH(type, i, array) \ for (type i = dmnsn_array_first(array); \ i - (type)dmnsn_array_first(array) < dmnsn_array_size(array); \ ++i) +/** + * Iterate over an array, in reverse order. + * @param type The (pointer) type to use as an iterator. + * @param i The name of the iterator within the loop body. + * @param[in] array The array to loop over. + */ #define DMNSN_ARRAY_FOREACH_REVERSE(type, i, array) \ for (type i = dmnsn_array_last(array); \ i - (type)dmnsn_array_first(array) >= 0; \ diff --git a/libdimension/dimension/camera.h b/libdimension/dimension/camera.h index e95ad18..e63cd80 100644 --- a/libdimension/dimension/camera.h +++ b/libdimension/dimension/camera.h @@ -18,8 +18,9 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * A camera. +/** + * @file + * Cameras. */ #ifndef DIMENSION_CAMERA_H @@ -28,20 +29,47 @@ /* Forward-declare dmnsn_camera */ typedef struct dmnsn_camera dmnsn_camera; -/* Camera callback types */ +/** + * Camera ray callback. + * @param[in] camera The camera itself. + * @param[in] x The x coordinate of the pixel (in [0, 1]). + * @param[in] y The y coordinate of the pixel (in [0, 1]). + * @return The ray through (\p x, \p y). + */ typedef dmnsn_line dmnsn_camera_ray_fn(const dmnsn_camera *camera, double x, double y); +/** A camera. */ struct dmnsn_camera { /* Callback functions */ - dmnsn_camera_ray_fn *ray_fn; - dmnsn_free_fn *free_fn; + dmnsn_camera_ray_fn *ray_fn; /**< Camera ray callback. */ + dmnsn_free_fn *free_fn; /**< Destructor callback. */ + + dmnsn_matrix trans; /**< Transformation matrix. */ - /* Generic pointer for camera info */ + /** Generic pointer for camera info */ void *ptr; }; +/** + * Create a dummy camera. + * @return The allocated camera. + */ dmnsn_camera *dmnsn_new_camera(void); + +/** + * Delete a camera. + * @param[in,out] camera The camera to delete. + */ void dmnsn_delete_camera(dmnsn_camera *camera); +/** + * Invoke the camera ray callback, then correctly transform the ray. + * @param[in] camera The camera itself. + * @param[in] x The x coordinate of the pixel (in [0, 1]). + * @param[in] y The y coordinate of the pixel (in [0, 1]). + * @return The ray through (\p x, \p y). + */ +dmnsn_line dmnsn_camera_ray(const dmnsn_camera *camera, double x, double y); + #endif /* DIMENSION_CAMERA_H */ diff --git a/libdimension/dimension/cameras.h b/libdimension/dimension/cameras.h index 7f4d549..077aebc 100644 --- a/libdimension/dimension/cameras.h +++ b/libdimension/dimension/cameras.h @@ -18,20 +18,21 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Types of cameras. +/** + * @file + * Pre-defined camera types. */ #ifndef DIMENSION_CAMERAS_H #define DIMENSION_CAMERAS_H -/* A perspective camera, at the origin, looking at (0, 0, 1). The feild of view - is the section of the plane z = 1 from (-0.5, -0.5) to (0.5, 0.5). Rays are - transformed by the camera's transformation matrix. */ +/** + * A perspective camera. The camera is located at the origin, looking at + * (0, 0, 1). The feild of view is the section of the plane z = 1 from + * (-0.5, -0.5) to (0.5, 0.5). Rays are transformed by the camera's + * transformation matrix. + * @return A perspective camera. + */ dmnsn_camera *dmnsn_new_perspective_camera(void); -/* Get or set the transformation matrix */ -dmnsn_matrix dmnsn_get_perspective_camera_trans(const dmnsn_camera *camera); -void dmnsn_set_perspective_camera_trans(dmnsn_camera *camera, dmnsn_matrix T); - #endif /* DIMENSION_CAMERAS_H */ diff --git a/libdimension/dimension/canvas.h b/libdimension/dimension/canvas.h index 018dcda..bc98e71 100644 --- a/libdimension/dimension/canvas.h +++ b/libdimension/dimension/canvas.h @@ -18,7 +18,8 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* +/** + * @file * A canvas which is rendered to. */ @@ -27,16 +28,18 @@ #include <stddef.h> +/** A canvas, or image. */ typedef struct { - /* width, height */ - size_t x, y; + size_t width; /**< Canvas width */ + size_t height; /**< Canvas height */ - /* An array of dmnsn_canvas_optimizer's */ + /** An array of <tt>dmnsn_canvas_optimizer</tt>s */ dmnsn_array *optimizers; - /* + /** + * @internal * Stored in first-quadrant representation (origin is bottom-left). The pixel - * at (a,b) is accessible as pixels[b*x + a]. + * at (a,b) is accessible as pixels[b*width + a]. */ dmnsn_color *pixels; } dmnsn_canvas; @@ -44,39 +47,79 @@ typedef struct { /* Forward-declare dmnsn_canvas_optimizer */ typedef struct dmnsn_canvas_optimizer dmnsn_canvas_optimizer; -/* Canvas optimizer callback types */ -typedef void dmnsn_canvas_optimizer_fn(dmnsn_canvas *canvas, +/** + * Canvas optimizer callback type. + * @param[in] canvas The canvas that was just updated. + * @param[in] optimizer The canvas optimizer itself. + * @param[in] x The x-coordinate that was just updated. + * @param[in] y The y-coordinate that was just updated. + */ +typedef void dmnsn_canvas_optimizer_fn(const dmnsn_canvas *canvas, dmnsn_canvas_optimizer optimizer, size_t x, size_t y); -/* Canvas optimizer */ +/** Canvas optimizer */ struct dmnsn_canvas_optimizer { - /* Callback types */ - dmnsn_canvas_optimizer_fn *optimizer_fn; - dmnsn_free_fn *free_fn; + dmnsn_canvas_optimizer_fn *optimizer_fn; /**< Optimizer callback */ + dmnsn_free_fn *free_fn; /**< Destructor callback */ - /* Generic pointer */ - void *ptr; + void *ptr; /**< Generic pointer. */ }; -/* Allocate and free a canvas */ -dmnsn_canvas *dmnsn_new_canvas(size_t x, size_t y); +/** + * Allocate a new canvas. + * @param[in] width The width of the canvas to allocate (in pixels). + * @param[in] height The height of the canvas to allocate (in pixels). + * @return The allocated canvas. + */ +dmnsn_canvas *dmnsn_new_canvas(size_t width, size_t height); + +/** + * Delete a canvas. + * @param[in,out] canvas The canvas to delete. + */ void dmnsn_delete_canvas(dmnsn_canvas *canvas); -/* Set a canvas optimizer */ +/** + * Set a canvas optimizer + * @param[in,out] canvas The canvas to optimize. + * @param[in] optimizer The optimizer to use. + */ void dmnsn_optimize_canvas(dmnsn_canvas *canvas, dmnsn_canvas_optimizer optimizer); /* Pixel accessors */ +/** + * Get the color of a pixel. + * @param[in] canvas The canvas to access. + * @param[in] x The x coordinate. + * @param[in] y The y coordinate. + * @return The color of the canvas at (\p x, \p y). + */ DMNSN_INLINE dmnsn_color dmnsn_get_pixel(const dmnsn_canvas *canvas, size_t x, size_t y) { - return canvas->pixels[y*canvas->x + x]; + dmnsn_assert(x < canvas->width && y < canvas->height, + "Canvas access out of bounds."); + return canvas->pixels[y*canvas->width + x]; } +/** + * Set the color of a pixel. + * @param[in,out] canvas The canvas to modify. + * @param[in] x The x coordinate of the pixel. + * @param[in] y The y coordinate of the pixel. + * @param[in] color The color to set the pixel at (\p x, \p y) to. + */ void dmnsn_set_pixel(dmnsn_canvas *canvas, size_t x, size_t y, dmnsn_color color); + +/** + * Clear a canvas uniformly with a given color. + * @param[in,out] canvas The canvas to erase. + * @param[in] color The color to paint it with. + */ void dmnsn_clear_canvas(dmnsn_canvas *canvas, dmnsn_color color); #endif /* DIMENSION_CANVAS_H */ diff --git a/libdimension/dimension/color.h b/libdimension/dimension/color.h index 9e47282..393778d 100644 --- a/libdimension/dimension/color.h +++ b/libdimension/dimension/color.h @@ -18,8 +18,9 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Types to represent color. +/** + * @file + * Color-related types and operations. */ #ifndef DIMENSION_COLOR_H @@ -27,71 +28,110 @@ #include <stdbool.h> -/* Internally, we use sRGB color. */ +/** A color value. */ typedef struct { - double filter, trans; /* Filter transparancy only lets light of this color - through; regular transparancy lets all colors - through. filter + trans should be <= 1.0. */ - double R, G, B; + /** Filtered transparency. */ + double filter; + /** Unfiltered transparency; <tt>filter + trans</tt> should be <= 1. */ + double trans; + + /* Internally we use sRGB color. */ + double R; /**< @internal sRGB red value. */ + double G; /**< @internal sRGB green value. */ + double B; /**< @internal sRGB blue value. */ } dmnsn_color; +/** sRGB color. */ typedef struct { - double X, Y, Z; /* X, Y, and Z are tristimulus values, unbounded above zero. - Diffuse white is (0.9505, 1, 1.089). */ + double R; /**< sRGB red value. */ + double G; /**< sRGB green value. */ + double B; /**< sRGB blue value. */ +} dmnsn_sRGB; + +/** CIE XYZ color. */ +typedef struct { + double X; /**< X component. */ + double Y; /**< Y (luminance) component. */ + double Z; /**< Z component. */ } dmnsn_CIE_XYZ; +/** CIE xyY color. */ typedef struct { - double x, y, Y; /* x and y are chromaticity coordinates, and Y is luminance, - in the CIE 1931 xyZ color space. We use an unlimited light - model, so x,y in [0, 1] and Y >= 0, with 1 = diffuse - white */ + double x; /**< x chromaticity coordinate (in [0, 1]) */ + double y; /**< y chromaticity coordinate (in [0, 1]) */ + double Y; /**< Luminance, unbounded >= 0; 1 is diffuse white. */ } dmnsn_CIE_xyY; +/** CIE 1976 (L*, a*, b*) color. */ typedef struct { - double L, a, b; /* L is luminence (100 = diffuse white); a and b are color- - opponent dimensions. This color space is used for color - arithmetic. */ + double L; /**< Luminance (100 is diffuse white). */ + double a; /**< Red/greed color-opponent value. */ + double b; /**< Yellow/blue color-opponent value. */ } dmnsn_CIE_Lab; +/** CIE 1976 (L*, u*, v*) color. */ typedef struct { - double L, u, v; /* L is luminence (100 = diffuse white); u and v are - chromaticity coordinates. */ + double L; /**< Luminance (same L* as CIE L*, a*, b*) */ + double u; /**< u* coordinate. */ + double v; /**< v* coordinate. */ } dmnsn_CIE_Luv; -typedef struct { - double R, G, B; /* sRGB R, G, and B values */ -} dmnsn_sRGB; - /* Standard colors */ -extern const dmnsn_color dmnsn_black, dmnsn_white, dmnsn_red, dmnsn_green, - dmnsn_blue, dmnsn_magenta, dmnsn_orange, dmnsn_yellow, dmnsn_cyan; - -/* Standard whitepoint, determined by the conversion of sRGB white to CIE XYZ */ +extern const dmnsn_color dmnsn_black; /**< Black. */ +extern const dmnsn_color dmnsn_white; /**< White. */ +extern const dmnsn_color dmnsn_red; /**< Red. */ +extern const dmnsn_color dmnsn_green; /**< Green. */ +extern const dmnsn_color dmnsn_blue; /**< Blue. */ +extern const dmnsn_color dmnsn_magenta; /**< Magenta. */ +extern const dmnsn_color dmnsn_orange; /**< Orange. */ +extern const dmnsn_color dmnsn_yellow; /**< Yellow. */ +extern const dmnsn_color dmnsn_cyan; /**< Cyan. */ + +/** Standard whitepoint, determined by the conversion of sRGB white to + CIE XYZ */ extern const dmnsn_CIE_XYZ dmnsn_whitepoint; -/* Is this color black? */ +/** Is this color black? */ bool dmnsn_color_is_black(dmnsn_color color); /* Color conversions */ +/** Convert an sRGB color to a Dimension color */ +dmnsn_color dmnsn_color_from_sRGB(dmnsn_sRGB sRGB); +/** Convert a CIE XYZ color to a Dimension color */ dmnsn_color dmnsn_color_from_XYZ(dmnsn_CIE_XYZ XYZ); +/** Convert a CIE xyY color to a Dimension color */ dmnsn_color dmnsn_color_from_xyY(dmnsn_CIE_xyY xyY); +/** Convert a CIE L*, a*, b* color to a Dimension color */ dmnsn_color dmnsn_color_from_Lab(dmnsn_CIE_Lab Lab, dmnsn_CIE_XYZ white); +/** Convert a CIE L*, u*, v* color to a Dimension color */ dmnsn_color dmnsn_color_from_Luv(dmnsn_CIE_Luv Luv, dmnsn_CIE_XYZ white); -dmnsn_color dmnsn_color_from_sRGB(dmnsn_sRGB sRGB); +/** Convert a Dimension color to sRGB */ +dmnsn_sRGB dmnsn_sRGB_from_color(dmnsn_color color); +/** Convert a Dimension color to CIE XYZ */ dmnsn_CIE_XYZ dmnsn_XYZ_from_color(dmnsn_color color); +/** Convert a Dimension color to CIE xyY */ dmnsn_CIE_xyY dmnsn_xyY_from_color(dmnsn_color color); +/** Convert a Dimension color to CIE L*, a*, b* */ dmnsn_CIE_Lab dmnsn_Lab_from_color(dmnsn_color color, dmnsn_CIE_XYZ white); +/** Convert a Dimension color to CIE L*, u*, v* */ dmnsn_CIE_Luv dmnsn_Luv_from_color(dmnsn_color color, dmnsn_CIE_XYZ white); -dmnsn_sRGB dmnsn_sRGB_from_color(dmnsn_color color); /* Perceptual color manipulation */ + +/** Add two colors together */ dmnsn_color dmnsn_color_add(dmnsn_color color1, dmnsn_color color2); +/** Multiply a color's intensity by \p n */ dmnsn_color dmnsn_color_mul(double n, dmnsn_color color); +/** Return the color at \p n on a gradient from \p c1 at 0 to \p c2 at 1 */ dmnsn_color dmnsn_color_gradient(dmnsn_color c1, dmnsn_color c2, double n); +/** Filter \p color through \p filter. */ dmnsn_color dmnsn_color_filter(dmnsn_color color, dmnsn_color filter); +/** Illuminate \p color with \p light. */ dmnsn_color dmnsn_color_illuminate(dmnsn_color light, dmnsn_color color); + +/** Return the perceptual difference between two colors. */ double dmnsn_color_difference(dmnsn_color color1, dmnsn_color color2); #endif /* DIMENSION_COLOR_H */ diff --git a/libdimension/dimension/csg.h b/libdimension/dimension/csg.h index 176467a..5d923bf 100644 --- a/libdimension/dimension/csg.h +++ b/libdimension/dimension/csg.h @@ -18,16 +18,43 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* +/** + * @file * Constructive solid geometry */ #ifndef DIMENSION_CSG_H #define DIMENSION_CSG_H -dmnsn_object *dmnsn_new_csg_union(dmnsn_array *objects); +/** + * CSG union. + * @param[in] objects The objects from which to compose the union. + * @return A union of the objects in \p objects. + */ +dmnsn_object *dmnsn_new_csg_union(const dmnsn_array *objects); + +/** + * CSG intersection. + * @param[in,out] A The first object. + * @param[in,out] B The second object. + * @return The intersection of \p A and \p B. + */ dmnsn_object *dmnsn_new_csg_intersection(dmnsn_object *A, dmnsn_object *B); + +/** + * CSG intersection. + * @param[in,out] A The outer object. + * @param[in,out] B The inner object. + * @return The difference between \p A and \p B. + */ dmnsn_object *dmnsn_new_csg_difference(dmnsn_object *A, dmnsn_object *B); + +/** + * CSG Merge. + * @param[in,out] A The first object. + * @param[in,out] B The second object. + * @return The merge of \p A and \p B. + */ dmnsn_object *dmnsn_new_csg_merge(dmnsn_object *A, dmnsn_object *B); #endif /* DIMENSION_CSG_H */ diff --git a/libdimension/dimension/error.h b/libdimension/dimension/error.h index a0b3857..8482266 100644 --- a/libdimension/dimension/error.h +++ b/libdimension/dimension/error.h @@ -18,22 +18,29 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Error handling. Errors are reported at a given severity by the dmnsn_error() - * macro at a given severity, which prints a warning if it is below the set - * resilience, or prints an error and exits if it's at or above the set - * resilience. +/** + * @file + * Error reporting interface. Errors are reported at a given severity by the + * dmnsn_error() macro at a given severity, which prints a warning if it is + * below the set resilience, or prints an error and exits if it's at or above + * the set resilience. */ #ifndef DIMENSION_ERROR_H #define DIMENSION_ERROR_H -typedef enum { - DMNSN_SEVERITY_LOW, /* Only die on low resilience */ - DMNSN_SEVERITY_MEDIUM, /* Die on low or medium resilience */ - DMNSN_SEVERITY_HIGH /* Always die */ +/** Error severity codes */ +typedef enum dmnsn_severity { + DMNSN_SEVERITY_LOW, /**< Only die on low resilience */ + DMNSN_SEVERITY_MEDIUM, /**< Die on low or medium resilience */ + DMNSN_SEVERITY_HIGH /**< Always die */ } dmnsn_severity; +/** + * @internal + * @def DMNSN_FUNC + * @brief Expands to the name of the current function + */ #ifdef __GNUC__ #define DMNSN_FUNC __PRETTY_FUNCTION__ #elif __STDC_VERSION__ >= 199901L @@ -42,13 +49,24 @@ typedef enum { #define DMNSN_FUNC "<unknown function>" #endif -/* Use this macro to report an error */ +/** + * Report an error. + * @param[in] severity A @ref dmnsn_severity representing the severity of the + * error. DMNSN_SEVERITY_HIGH will always terminate the + * running thread. + * @param[in] str A string to print explaining the error. + */ #define dmnsn_error(severity, str) \ dmnsn_report_error((dmnsn_severity)(severity), \ DMNSN_FUNC, __FILE__, __LINE__, \ str) -/* Make an assertion */ +/** + * @def dmnsn_assert + * Make an assertion. + * @param[in] expr The expression to assert. + * @param[in] str A string to print if the assertion fails. + */ #ifdef NDEBUG #define dmnsn_assert(expr, str) ((void)0) #else @@ -60,21 +78,50 @@ typedef enum { } while (0) #endif -/* Called by dmnsn_error() - don't call directly */ +/** + * @internal + * Called by dmnsn_error(); don't call directly. + * @param[in] severity The severity of the error. + * @param[in] func The name of the function where the error originated. + * @param[in] file The file where the error originated. + * @param[in] line The line number where the error originated. + * @param[in] str A string describing the error. + */ void dmnsn_report_error(dmnsn_severity severity, const char *func, const char *file, unsigned int line, const char *str); -/* Get and set the library resilience, thread-safely */ +/** + * Get the library resilience, thread-safely. + * @return The error severity considered fatal. + */ dmnsn_severity dmnsn_get_resilience(void); + +/** + * Set the library resilience, thread-safely. + * @param[in] resilience The new minimum severity that will cause a fatal + * error. + */ void dmnsn_set_resilience(dmnsn_severity resilience); -/* Fatal error callback type */ +/** + * Fatal error callback type. This function should never return. + */ typedef void dmnsn_fatal_error_fn(void); -/* Get and set libdimension fatal error handling strategy - the default is - exit(EXIT_FAILURE) */ +/** + * Get the libdimension fatal error handler, thread-safely. The default fatal + * error handler terminates the current thread, or the entire program if the + * current thread is the main thread. + * @return The current fatal error handler. + */ dmnsn_fatal_error_fn *dmnsn_get_fatal_error_fn(void); + +/** + * Set the libdimension fatal error handler, thread-safely. + * @param[in] fatal The new fatal error handler. This function must never + * return. + */ void dmnsn_set_fatal_error_fn(dmnsn_fatal_error_fn *fatal); #endif /* DIMENSION_ERROR_H */ diff --git a/libdimension/dimension/finishes.h b/libdimension/dimension/finishes.h index b84b5fb..bc07759 100644 --- a/libdimension/dimension/finishes.h +++ b/libdimension/dimension/finishes.h @@ -18,23 +18,51 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Custom finishes. +/** + * @file + * Pre-defined finishes. */ #ifndef DIMENSION_FINISHES_H #define DIMENSION_FINISHES_H -/* Add two finishes */ +/** + * Add two finishes together. + * @param[in,out] f1 The first finish. + * @param[in,out] f2 The second finish. + * @return A finish that adds the values of two finishes together. + */ dmnsn_finish *dmnsn_new_finish_combination(dmnsn_finish *f1, dmnsn_finish *f2); +/** + * Ambient finish. + * @param[in] ambient The color of the ambient light. + * @return A finish with ambient light. + */ dmnsn_finish *dmnsn_new_ambient_finish(dmnsn_color ambient); + +/** + * Diffuse finish. + * @param[in] diffuse The diffuse reflection coefficient. + * @return A finish with diffuse reflection. + */ dmnsn_finish *dmnsn_new_diffuse_finish(double diffuse); -/* A phong specular highlight */ +/** + * A phong specular highlight. + * @param[in] specular The specular reflection coefficient. + * @param[in] exp The exponent (roughly the highlight size). + * @return A finish with phong specular highlight. + */ dmnsn_finish *dmnsn_new_phong_finish(double specular, double exp); -/* Specular reflection */ +/** + * Specular (mirror) reflection. + * @param[in] min Reflection at paralell angles. + * @param[in] max Reflection at perpendicular angles (often == \p min). + * @param[in] falloff Degree of exponential falloff (usually 1). + * @return A finish with specular reflection. + */ dmnsn_finish *dmnsn_new_reflective_finish(dmnsn_color min, dmnsn_color max, double falloff); diff --git a/libdimension/dimension/geometry.h b/libdimension/dimension/geometry.h index adf41dc..a62fb75 100644 --- a/libdimension/dimension/geometry.h +++ b/libdimension/dimension/geometry.h @@ -18,7 +18,8 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* +/** + * @file * Core geometric types like vectors, matricies, and rays. */ @@ -28,74 +29,105 @@ #include <math.h> #include <stdbool.h> -/* Vector and matrix types */ +/** A vector in 3 dimensions. */ +typedef struct dmnsn_vector { + double x; /**< The x component. */ + double y; /**< The y component. */ + double z; /**< The z component. */ +} dmnsn_vector; -typedef struct dmnsn_vector { double x, y, z; } dmnsn_vector; +/** A standard format string for vectors. */ #define DMNSN_VECTOR_FORMAT "<%g, %g, %g>" +/** The appropriate arguements to printf() a vector. */ #define DMNSN_VECTOR_PRINTF(v) (v).x, (v).y, (v).z -typedef struct dmnsn_matrix { double n[4][4]; } dmnsn_matrix; +/** A 4x4 affine transformation matrix. */ +typedef struct dmnsn_matrix { + double n[4][4]; /**< The matrix elements in row-major order. */ +} dmnsn_matrix; + +/** A standard format string for matricies. */ #define DMNSN_MATRIX_FORMAT \ "[%g\t%g\t%g\t%g]\n" \ "[%g\t%g\t%g\t%g]\n" \ "[%g\t%g\t%g\t%g]\n" \ "[%g\t%g\t%g\t%g]" +/** The appropriate arguements to printf() a matrix. */ #define DMNSN_MATRIX_PRINTF(m) \ (m).n[0][0], (m).n[0][1], (m).n[0][2], (m).n[0][3], \ (m).n[1][0], (m).n[1][1], (m).n[1][2], (m).n[1][3], \ (m).n[2][0], (m).n[2][1], (m).n[2][2], (m).n[2][3], \ (m).n[3][0], (m).n[3][1], (m).n[3][2], (m).n[3][3] -/* A line, or ray */ +/** A line, or ray. */ typedef struct dmnsn_line { - dmnsn_vector x0; /* A point on the line */ - dmnsn_vector n; /* A normal vector; the direction of the line */ + dmnsn_vector x0; /**< A point on the line. */ + dmnsn_vector n; /**< A normal vector; the direction of the line. */ } dmnsn_line; + +/** A standard format string for lines. */ #define DMNSN_LINE_FORMAT "(<%g, %g, %g> + t*<%g, %g, %g>)" +/** The appropriate arguements to printf() a line. */ #define DMNSN_LINE_PRINTF(l) \ DMNSN_VECTOR_PRINTF((l).x0), DMNSN_VECTOR_PRINTF((l).n) -/* A bounding box */ -typedef struct dmnsn_bounding_box { dmnsn_vector min, max; } dmnsn_bounding_box; +/** An axis-aligned bounding box (AABB). */ +typedef struct dmnsn_bounding_box { + dmnsn_vector min; /**< The coordinate-wise minimum extent of the box */ + dmnsn_vector max; /**< The coordinate-wise maximum extent of the box */ +} dmnsn_bounding_box; + +/** A standard format string for bounding boxes. */ #define DMNSN_BOUNDING_BOX_FORMAT "(<%g, %g, %g> ==> <%g, %g, %g>)" +/** The appropriate arguements to printf() a bounding box. */ #define DMNSN_BOUNDING_BOX_PRINTF(box) \ DMNSN_VECTOR_PRINTF((box).min), DMNSN_VECTOR_PRINTF((box).max) /* Constants */ +/** The smallest value considered non-zero by some numerical algorithms */ #define dmnsn_epsilon 1.0e-10 +/** The zero vector */ static const dmnsn_vector dmnsn_zero = { 0.0, 0.0, 0.0 }; -static const dmnsn_vector dmnsn_x = { 1.0, 0.0, 0.0 }; -static const dmnsn_vector dmnsn_y = { 0.0, 1.0, 0.0 }; -static const dmnsn_vector dmnsn_z = { 0.0, 0.0, 1.0 }; +/** The x vector. */ +static const dmnsn_vector dmnsn_x = { 1.0, 0.0, 0.0 }; +/** The y vector. */ +static const dmnsn_vector dmnsn_y = { 0.0, 1.0, 0.0 }; +/** The z vector. */ +static const dmnsn_vector dmnsn_z = { 0.0, 0.0, 1.0 }; /* Scalar functions */ +/** Find the minimum of two scalars. */ DMNSN_INLINE double dmnsn_min(double a, double b) { return a < b ? a : b; } +/** Find the maximum of two scalars. */ DMNSN_INLINE double dmnsn_max(double a, double b) { return a > b ? a : b; } +/** Convert degrees to radians */ DMNSN_INLINE double dmnsn_radians(double degrees) { return degrees*atan(1.0)/45.0; } +/** Convert radians to degrees */ DMNSN_INLINE double dmnsn_degrees(double radians) { return radians*45.0/atan(1.0); } +/** Return the sign bit of a scalar. */ DMNSN_INLINE int dmnsn_signbit(double n) { @@ -105,6 +137,7 @@ dmnsn_signbit(double n) /* Shorthand for vector/matrix construction */ +/** Construct a new vector */ DMNSN_INLINE dmnsn_vector dmnsn_new_vector(double x, double y, double z) { @@ -112,6 +145,7 @@ dmnsn_new_vector(double x, double y, double z) return v; } +/** Construct a new matrix */ DMNSN_INLINE dmnsn_matrix dmnsn_new_matrix(double a0, double a1, double a2, double a3, double b0, double b1, double b2, double b3, @@ -125,12 +159,37 @@ dmnsn_new_matrix(double a0, double a1, double a2, double a3, return m; } +/** Return the identity matrix */ dmnsn_matrix dmnsn_identity_matrix(void); + +/** + * A scale transformation. + * @param[in] s A vector with components representing the scaling factor in + * each axis. + * @return The transformation matrix. + */ dmnsn_matrix dmnsn_scale_matrix(dmnsn_vector s); +/** + * A translation. + * @param[in] d The vector to translate by. + * @return The transformation matrix. + */ dmnsn_matrix dmnsn_translation_matrix(dmnsn_vector d); -/* Left-handed rotation; theta/|theta| = axis, |theta| = angle */ +/** + * A left-handed rotation. + * @param[in] theta A vector representing an axis and angle. + * @f$ axis = \vec{\theta}/|\vec{\theta}| @f$, + * @f$ angle = |\vec{\theta}| @f$ + * @return The transformation matrix. + */ dmnsn_matrix dmnsn_rotation_matrix(dmnsn_vector theta); +/** + * Construct a new line. + * @param[in] x0 A point on the line. + * @param[in] n The direction of the line. + * @return The new line. + */ DMNSN_INLINE dmnsn_line dmnsn_new_line(dmnsn_vector x0, dmnsn_vector n) { @@ -138,6 +197,7 @@ dmnsn_new_line(dmnsn_vector x0, dmnsn_vector n) return l; } +/** Return the bounding box which contains nothing. */ DMNSN_INLINE dmnsn_bounding_box dmnsn_zero_bounding_box(void) { @@ -148,6 +208,7 @@ dmnsn_zero_bounding_box(void) return box; } +/** Return the bounding box which contains everything. */ DMNSN_INLINE dmnsn_bounding_box dmnsn_infinite_bounding_box(void) { @@ -160,12 +221,20 @@ dmnsn_infinite_bounding_box(void) /* Vector element access */ +/** Constants for indexing a vector like an array. */ enum { - DMNSN_X, - DMNSN_Y, - DMNSN_Z + DMNSN_X, /**< The x component. */ + DMNSN_Y, /**< The y component. */ + DMNSN_Z /**< The z component. */ }; +/** + * Index a vector like an array. + * @param[in] n The vector to index. + * @param[in] elem Which element to access; one of \ref DMNSN_X, \ref DMNSN_Y, + * or \ref DMNSN_Z. + * @return The requested element. + */ DMNSN_INLINE double dmnsn_vector_element(dmnsn_vector n, int elem) { @@ -179,12 +248,13 @@ dmnsn_vector_element(dmnsn_vector n, int elem) default: dmnsn_assert(false, "Wrong vector element requested."); - return 0.0; /* Shut up compiler */ + return 0.0; } } /* Vector and matrix arithmetic */ +/** Negate a vector */ DMNSN_INLINE dmnsn_vector dmnsn_vector_negate(dmnsn_vector rhs) { @@ -193,6 +263,7 @@ dmnsn_vector_negate(dmnsn_vector rhs) return v; } +/** Add two vectors */ DMNSN_INLINE dmnsn_vector dmnsn_vector_add(dmnsn_vector lhs, dmnsn_vector rhs) { @@ -201,6 +272,7 @@ dmnsn_vector_add(dmnsn_vector lhs, dmnsn_vector rhs) return v; } +/** Subtract two vectors */ DMNSN_INLINE dmnsn_vector dmnsn_vector_sub(dmnsn_vector lhs, dmnsn_vector rhs) { @@ -209,6 +281,7 @@ dmnsn_vector_sub(dmnsn_vector lhs, dmnsn_vector rhs) return v; } +/** Multiply a vector by a scalar. */ DMNSN_INLINE dmnsn_vector dmnsn_vector_mul(double lhs, dmnsn_vector rhs) { @@ -217,6 +290,7 @@ dmnsn_vector_mul(double lhs, dmnsn_vector rhs) return v; } +/** Divide a vector by a scalar. */ DMNSN_INLINE dmnsn_vector dmnsn_vector_div(dmnsn_vector lhs, double rhs) { @@ -225,6 +299,7 @@ dmnsn_vector_div(dmnsn_vector lhs, double rhs) return v; } +/** Return the dot product of two vectors. */ DMNSN_INLINE double dmnsn_vector_dot(dmnsn_vector lhs, dmnsn_vector rhs) { @@ -232,6 +307,7 @@ dmnsn_vector_dot(dmnsn_vector lhs, dmnsn_vector rhs) return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z; } +/** Return the cross product of two vectors. */ DMNSN_INLINE dmnsn_vector dmnsn_vector_cross(dmnsn_vector lhs, dmnsn_vector rhs) { @@ -242,6 +318,7 @@ dmnsn_vector_cross(dmnsn_vector lhs, dmnsn_vector rhs) return v; } +/** Return the projection of \p u onto \p d. */ DMNSN_INLINE dmnsn_vector dmnsn_vector_proj(dmnsn_vector u, dmnsn_vector d) { @@ -249,6 +326,7 @@ dmnsn_vector_proj(dmnsn_vector u, dmnsn_vector d) return dmnsn_vector_mul(dmnsn_vector_dot(u, d)/dmnsn_vector_dot(d, d), d); } +/** Return the magnitude of a vector. */ DMNSN_INLINE double dmnsn_vector_norm(dmnsn_vector n) { @@ -256,6 +334,7 @@ dmnsn_vector_norm(dmnsn_vector n) return sqrt(dmnsn_vector_dot(n, n)); } +/** Return the direction of a vector. */ DMNSN_INLINE dmnsn_vector dmnsn_vector_normalize(dmnsn_vector n) { @@ -263,6 +342,7 @@ dmnsn_vector_normalize(dmnsn_vector n) return dmnsn_vector_div(n, dmnsn_vector_norm(n)); } +/** Return the component-wise minimum of two vectors. */ DMNSN_INLINE dmnsn_vector dmnsn_vector_min(dmnsn_vector a, dmnsn_vector b) { @@ -273,6 +353,7 @@ dmnsn_vector_min(dmnsn_vector a, dmnsn_vector b) ); } +/** Return the component-wise maximum of two vectors. */ DMNSN_INLINE dmnsn_vector dmnsn_vector_max(dmnsn_vector a, dmnsn_vector b) { @@ -283,54 +364,65 @@ dmnsn_vector_max(dmnsn_vector a, dmnsn_vector b) ); } +/** Return the angle between two vectors with respect to an axis. */ double dmnsn_vector_axis_angle(dmnsn_vector v1, dmnsn_vector v2, dmnsn_vector axis); +/** Invert a matrix. */ dmnsn_matrix dmnsn_matrix_inverse(dmnsn_matrix A); + +/** Multiply two matricies. */ dmnsn_matrix dmnsn_matrix_mul(dmnsn_matrix lhs, dmnsn_matrix rhs); -/* Affine transformation; lhs*(x,y,z,1), normalized so the fourth element is - 1 */ +/** Transform a vector by a matrix. */ DMNSN_INLINE dmnsn_vector -dmnsn_transform_vector(dmnsn_matrix lhs, dmnsn_vector rhs) +dmnsn_transform_vector(dmnsn_matrix T, dmnsn_vector v) { /* 12 multiplications, 3 divisions, 12 additions */ dmnsn_vector r; double w; - r.x = lhs.n[0][0]*rhs.x + lhs.n[0][1]*rhs.y + lhs.n[0][2]*rhs.z + lhs.n[0][3]; - r.y = lhs.n[1][0]*rhs.x + lhs.n[1][1]*rhs.y + lhs.n[1][2]*rhs.z + lhs.n[1][3]; - r.z = lhs.n[2][0]*rhs.x + lhs.n[2][1]*rhs.y + lhs.n[2][2]*rhs.z + lhs.n[2][3]; - w = lhs.n[3][0]*rhs.x + lhs.n[3][1]*rhs.y + lhs.n[3][2]*rhs.z + lhs.n[3][3]; + r.x = T.n[0][0]*v.x + T.n[0][1]*v.y + T.n[0][2]*v.z + T.n[0][3]; + r.y = T.n[1][0]*v.x + T.n[1][1]*v.y + T.n[1][2]*v.z + T.n[1][3]; + r.z = T.n[2][0]*v.x + T.n[2][1]*v.y + T.n[2][2]*v.z + T.n[2][3]; + w = T.n[3][0]*v.x + T.n[3][1]*v.y + T.n[3][2]*v.z + T.n[3][3]; return dmnsn_vector_div(r, w); } -dmnsn_bounding_box dmnsn_transform_bounding_box(dmnsn_matrix lhs, - dmnsn_bounding_box rhs); +/** Transform a bounding box by a matrix. */ +dmnsn_bounding_box dmnsn_transform_bounding_box(dmnsn_matrix T, + dmnsn_bounding_box box); -/* Affine line transformation; n = lhs*(x0 + n) - lhs*x0, x0 *= lhs */ +/** + * Transform a line by a matrix. + * \f$ n' = T(l.\vec{x_0} + l.\vec{n}) - T(l.\vec{x_0}) \f$, + * \f$ \vec{x_0}' = T(l.\vec{x_0}) \f$ + */ DMNSN_INLINE dmnsn_line -dmnsn_transform_line(dmnsn_matrix lhs, dmnsn_line rhs) +dmnsn_transform_line(dmnsn_matrix T, dmnsn_line l) { /* 24 multiplications, 6 divisions, 30 additions */ - dmnsn_line l; - l.x0 = dmnsn_transform_vector(lhs, rhs.x0); - l.n = dmnsn_vector_sub( - dmnsn_transform_vector(lhs, dmnsn_vector_add(rhs.x0, rhs.n)), - l.x0 + dmnsn_line ret; + ret.x0 = dmnsn_transform_vector(T, l.x0); + ret.n = dmnsn_vector_sub( + dmnsn_transform_vector(T, dmnsn_vector_add(l.x0, l.n)), + ret.x0 ); - return l; + return ret; } -/* A point on a line, defined by x0 + t*n */ +/** + * Return the point at \p t on a line. + * The point is defined by \f$ l.\vec{x_0} + t \cdot l.\vec{n} \f$ + */ DMNSN_INLINE dmnsn_vector dmnsn_line_point(dmnsn_line l, double t) { return dmnsn_vector_add(l.x0, dmnsn_vector_mul(t, l.n)); } -/* Add epsilon*l.n to l.x0, to avoid self-intersections */ +/** Add epsilon*l.n to l.x0, to avoid self-intersections */ DMNSN_INLINE dmnsn_line dmnsn_line_add_epsilon(dmnsn_line l) { @@ -343,10 +435,7 @@ dmnsn_line_add_epsilon(dmnsn_line l) ); } -/* Solve for the t value such that x0 + t*n = x */ -double dmnsn_line_index(dmnsn_line l, dmnsn_vector x); - -/* Return whether p is within the axis-aligned bounding box */ +/** Return whether \p p is within the axis-aligned bounding box */ DMNSN_INLINE bool dmnsn_bounding_box_contains(dmnsn_bounding_box box, dmnsn_vector p) { @@ -354,7 +443,7 @@ dmnsn_bounding_box_contains(dmnsn_bounding_box box, dmnsn_vector p) && (p.x <= box.max.x && p.y <= box.max.y && p.z <= box.max.z); } -/* Return whether `box' is infinite */ +/** Return whether a bounding box is infinite */ DMNSN_INLINE bool dmnsn_bounding_box_is_infinite(dmnsn_bounding_box box) { diff --git a/libdimension/dimension/gl.h b/libdimension/dimension/gl.h index 3eb292c..25979c4 100644 --- a/libdimension/dimension/gl.h +++ b/libdimension/dimension/gl.h @@ -18,21 +18,36 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Draw a canvas to a GL framebuffer with glDrawPixels, or read one with - * glReadPixels. Should be fast, so no _async() versions. +/** + * @file + * OpenGL export/import of canvases. */ #ifndef DIMENSION_GL_H #define DIMENSION_GL_H -/* Optimize canvas for GL drawing */ +/** + * Optimize a canvas for GL drawing + * @param[in,out] canvas The canvas to optimize. + * @return Whether the canvas was successfully optimized. + */ int dmnsn_gl_optimize_canvas(dmnsn_canvas *canvas); -/* Write canvas to GL framebuffer. Returns 0 on success, nonzero on failure. */ +/** + * Write canvas to GL framebuffer. + * @param[in] canvas The canvas to write. + * @return 0 on success, non-zero on failure. + */ int dmnsn_gl_write_canvas(const dmnsn_canvas *canvas); -/* Read a canvas from a GL framebuffer. Returns NULL on failure. */ +/** + * Read a canvas from a GL framebuffer. + * @param[in] x0 The \a x screen coordinate to start copying from. + * @param[in] y0 The \a y screen coordinate to start copying from. + * @param[in] width The width of the read area. + * @param[in] height The height of the read area. + * @return The allocated canvas, or NULL on failure. + */ dmnsn_canvas *dmnsn_gl_read_canvas(size_t x0, size_t y0, size_t width, size_t height); diff --git a/libdimension/dimension/inline.h b/libdimension/dimension/inline.h index edf92b1..4f12c28 100644 --- a/libdimension/dimension/inline.h +++ b/libdimension/dimension/inline.h @@ -18,16 +18,22 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Handle inlines nicely without cheating and making them static. The - * DMNSN_INLINE macro is set appropriately for the version of C you're using, - * and non-inline versions are emitted in exactly one translation unit when - * necessary. +/** + * @file + * Inline function support. Handle inlines nicely without cheating and making + * them static. The DMNSN_INLINE macro is set appropriately for the version of + * C you're using, and non-inline versions are emitted in exactly one + * translation unit when necessary. */ #ifndef DIMENSION_INLINE_H #define DIMENSION_INLINE_H +/** + * @def DMNSN_INLINE + * A portable inline specifier. Expands to the correct method of declaring + * inline functions for the version of C you are using. + */ #ifndef DMNSN_INLINE #ifdef __cplusplus /* C++ inline semantics */ diff --git a/libdimension/dimension/interior.h b/libdimension/dimension/interior.h index 96168cf..7302426 100644 --- a/libdimension/dimension/interior.h +++ b/libdimension/dimension/interior.h @@ -18,28 +18,37 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* +/** + * @file * Object interiors. */ #ifndef DIMENSION_INTERIOR_H #define DIMENSION_INTERIOR_H +/** An interior */ typedef struct dmnsn_interior { - /* Refractive index */ - double ior; + double ior; /**< Refractive index. */ - /* Callbacks */ - dmnsn_free_fn *free_fn; + dmnsn_free_fn *free_fn; /**< Destructor callback. */ - /* Generic pointer */ + /** Generic pointer. */ void *ptr; - /* Reference count */ + /** @internal Reference count. */ unsigned int *refcount; } dmnsn_interior; +/** + * Create an interior object. + * @return The new interior. + */ dmnsn_interior *dmnsn_new_interior(void); + +/** + * Delete an interior. + * @param[in,out] interior The interior to delete. + */ void dmnsn_delete_interior(dmnsn_interior *interior); #endif /* DIMENSION_INTERIOR_H */ diff --git a/libdimension/dimension/light.h b/libdimension/dimension/light.h index 69ed9e7..dfda157 100644 --- a/libdimension/dimension/light.h +++ b/libdimension/dimension/light.h @@ -18,30 +18,47 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* +/** + * @file * Lights. */ #ifndef DIMENSION_LIGHT_H #define DIMENSION_LIGHT_H +/* Forward-declar dmnsn_light */ typedef struct dmnsn_light dmnsn_light; +/** + * Light callback. + * @param[in] light The light itself. + * @param[in] v The point to illuminate. + * @return The color of the light at \p v. + */ typedef dmnsn_color dmnsn_light_fn(const dmnsn_light *light, dmnsn_vector v); +/** A light. */ struct dmnsn_light { - /* Origin of light rays */ - dmnsn_vector x0; + dmnsn_vector x0; /**< Origin of light rays */ /* Callbacks */ - dmnsn_light_fn *light_fn; - dmnsn_free_fn *free_fn; + dmnsn_light_fn *light_fn; /**< Light callback. */ + dmnsn_free_fn *free_fn; /**< Desctructor callback. */ - /* Generic pointer for light info */ + /** Generic pointer for light info */ void *ptr; }; +/** + * Create a dummy light. + * @return The allocated light. + */ dmnsn_light *dmnsn_new_light(void); + +/** + * Delete a light. + * @param[in,out] light The light to delete. + */ void dmnsn_delete_light(dmnsn_light *light); #endif /* DIMENSION_LIGHT_H */ diff --git a/libdimension/dimension/lights.h b/libdimension/dimension/lights.h index 7b7385e..7c0f140 100644 --- a/libdimension/dimension/lights.h +++ b/libdimension/dimension/lights.h @@ -18,13 +18,20 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Types of lights. +/** + * @file + * Pre-defined light types. */ #ifndef DIMENSION_LIGHTS_H #define DIMENSION_LIGHTS_H +/** + * A point light. + * @param[in] x0 The origin of the light. + * @param[in] color The color of the light. + * @return A point light. + */ dmnsn_light *dmnsn_new_point_light(dmnsn_vector x0, dmnsn_color color); #endif /* DIMENSION_LIGHTS_H */ diff --git a/libdimension/dimension/list.h b/libdimension/dimension/list.h index dba18dc..9046583 100644 --- a/libdimension/dimension/list.h +++ b/libdimension/dimension/list.h @@ -18,8 +18,9 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Simple generalized doubly-linked lists. +/** + * @file + * Simple doubly-linked lists. */ #ifndef DIMENSION_LIST_H @@ -29,14 +30,22 @@ #include <stdlib.h> #include <string.h> +/** + * A list iterator. + */ typedef struct dmnsn_list_iterator { - void *ptr; - size_t obj_size; - struct dmnsn_list_iterator *prev, *next; + void *ptr; /**< @internal The stored object */ + size_t obj_size; /**< @internal The object size */ + struct dmnsn_list_iterator *prev; /**< @internal The previous iterator */ + struct dmnsn_list_iterator *next; /**< @internal The next iterator */ } dmnsn_list_iterator; -/* Internal iterator allocation */ - +/** + * @internal + * Iterator allocation. + * @param[in] obj The location of the object to store in the iterator. + * @param[in] obj_size The size of the object to store in the iterator. + */ DMNSN_INLINE dmnsn_list_iterator * dmnsn_new_list_iterator(const void *obj, size_t obj_size) { @@ -50,6 +59,11 @@ dmnsn_new_list_iterator(const void *obj, size_t obj_size) return i; } +/** + * @internal + * Iterator release. + * @param[in,out] i The iterator to free. + */ DMNSN_INLINE void dmnsn_delete_list_iterator(dmnsn_list_iterator *i) { @@ -59,12 +73,19 @@ dmnsn_delete_list_iterator(dmnsn_list_iterator *i) } } +/** A doubly-linked list. */ typedef struct dmnsn_list { - dmnsn_list_iterator *first, *last; - size_t obj_size, length; + dmnsn_list_iterator *first; /**< @internal The first iterator in the list */ + dmnsn_list_iterator *last; /**< @internal The last iterator in the list */ + size_t length; /**< @internal The size of the list */ + size_t obj_size; /**< @internal The size of list objects */ } dmnsn_list; -/* List allocation */ +/** + * Allocate a list. + * @param[in] obj_size The size of the objects to be stored. + * @return An empty list. + */ DMNSN_INLINE dmnsn_list * dmnsn_new_list(size_t obj_size) { @@ -76,25 +97,53 @@ dmnsn_new_list(size_t obj_size) return list; } -/* Construction to/from arrays */ +/** + * Delete a list. + * @param[in,out] list The list to delete. + */ +void dmnsn_delete_list(dmnsn_list *list); + +/** + * Construct a list from an array. + * @param[in] array The array to copy. + * @return A list with the same contents as \p array. + */ dmnsn_list *dmnsn_list_from_array(const dmnsn_array *array); -dmnsn_array *dmnsn_array_from_list(const dmnsn_list *list); -/* Delete a list */ -void dmnsn_delete_list(dmnsn_list *list); +/** + * Construct an array from a list. + * @param[in] list The list to copy. + * @return An array with the same contents as \p list. + */ +dmnsn_array *dmnsn_array_from_list(const dmnsn_list *list); +/** + * First element. + * @param[in] list The list to index. + * @return An iterator to the first list element, or NULL if the list is empty. + */ DMNSN_INLINE dmnsn_list_iterator * dmnsn_list_first(const dmnsn_list *list) { return list->first; } +/** + * Last element. + * @param[in] list The list to index. + * @return An iterator to the last list element, or NULL if the list is empty. + */ DMNSN_INLINE dmnsn_list_iterator * dmnsn_list_last(const dmnsn_list *list) { return list->last; } +/** + * Previous element. + * @param[in] i The iterator to follow. + * @return The iterator preceding \c i. + */ DMNSN_INLINE dmnsn_list_iterator * dmnsn_list_prev(const dmnsn_list_iterator *i) { @@ -102,6 +151,11 @@ dmnsn_list_prev(const dmnsn_list_iterator *i) return i->prev; } +/** + * Next element. + * @param[in] i The iterator to follow. + * @return The iterator following \c i. + */ DMNSN_INLINE dmnsn_list_iterator * dmnsn_list_next(const dmnsn_list_iterator *i) { @@ -109,13 +163,22 @@ dmnsn_list_next(const dmnsn_list_iterator *i) return i->next; } +/** + * Get the size of the list. + * @param[in] list The list in question. + * @return The number of elements in the list. + */ DMNSN_INLINE size_t dmnsn_list_size(const dmnsn_list *list) { return list->length; } -/* Get the i'th object */ +/** + * Get the i'th object. + * @param[in] i The iterator to dereference. + * @param[out] obj The location to store the object. + */ DMNSN_INLINE void dmnsn_list_get(const dmnsn_list_iterator *i, void *obj) { @@ -123,7 +186,11 @@ dmnsn_list_get(const dmnsn_list_iterator *i, void *obj) memcpy(obj, i->ptr, i->obj_size); } -/* Get a pointer to the i'th object */ +/** + * Get a pointer to the i'th object. + * @param[in] i The iterator to dereference. + * @return A pointer to the object stored at \c i. + */ DMNSN_INLINE void * dmnsn_list_at(const dmnsn_list_iterator *i) { @@ -131,7 +198,11 @@ dmnsn_list_at(const dmnsn_list_iterator *i) return i->ptr; } -/* Set the i'th object, expanding the list if necessary */ +/** + * Set the i'th object. + * @param[in,out] i The iterator to dereference. + * @param[in] obj The object to store at \c i. + */ DMNSN_INLINE void dmnsn_list_set(dmnsn_list_iterator *i, const void *obj) { @@ -139,7 +210,11 @@ dmnsn_list_set(dmnsn_list_iterator *i, const void *obj) memcpy(i->ptr, obj, i->obj_size); } -/* Swap two iterators */ +/** + * Swap the objects in two iterators. + * @param[in,out] a The first iterator. + * @param[in,out] b The second iterator. + */ DMNSN_INLINE void dmnsn_list_swap(dmnsn_list_iterator *a, dmnsn_list_iterator *b) { @@ -148,7 +223,13 @@ dmnsn_list_swap(dmnsn_list_iterator *a, dmnsn_list_iterator *b) b->ptr = temp; } -/* Insert `j' before `i' */ +/** + * Insert a detached iterator into a list. + * @param[in,out] list The list to insert into. + * @param[in,out] i The detached iterator to insert. + * @param[in,out] j The iterator before which to insert, or NULL for the end + * of the list. + */ DMNSN_INLINE void dmnsn_list_iterator_insert(dmnsn_list *list, dmnsn_list_iterator *i, dmnsn_list_iterator *j) @@ -170,7 +251,13 @@ dmnsn_list_iterator_insert(dmnsn_list *list, ++list->length; } -/* Insert an item before `i' (NULL means at the end) */ +/** + * Insert an object. + * @param[in,out] list The list to insert into. + * @param[in,out] i The iterator before which to insert, or NULL for the end + * of the list. + * @param[in] obj The location of the object to insert. + */ DMNSN_INLINE void dmnsn_list_insert(dmnsn_list *list, dmnsn_list_iterator *i, const void *obj) { @@ -178,7 +265,11 @@ dmnsn_list_insert(dmnsn_list *list, dmnsn_list_iterator *i, const void *obj) dmnsn_list_iterator_insert(list, i, j); } -/* Remove the given iterator */ +/** + * Detach an iterator from a list. + * @param[in,out] list The list to remove from. + * @param[in,out] i The iterator to detach. + */ DMNSN_INLINE void dmnsn_list_iterator_remove(dmnsn_list *list, dmnsn_list_iterator *i) { @@ -197,7 +288,11 @@ dmnsn_list_iterator_remove(dmnsn_list *list, dmnsn_list_iterator *i) --list->length; } -/* Remove the specified item */ +/** + * Remove the specified item from a list. + * @param[in,out] list The list to remove from. + * @param[in,out] i The iterator to delete. + */ DMNSN_INLINE void dmnsn_list_remove(dmnsn_list *list, dmnsn_list_iterator *i) { @@ -205,14 +300,22 @@ dmnsn_list_remove(dmnsn_list *list, dmnsn_list_iterator *i) dmnsn_delete_list_iterator(i); } -/* Push obj to the end of the list */ +/** + * Push an object to the end of the list. + * @param[in,out] list The list to append to. + * @param[in] obj The location of the object to push. + */ DMNSN_INLINE void dmnsn_list_push(dmnsn_list *list, const void *obj) { dmnsn_list_insert(list, NULL, obj); } -/* Pop obj from the end of the list */ +/** + * Pop an object from the end of the list. + * @param[in,out] list The list to extract from. + * @param[out] obj The location to store the extracted object. + */ DMNSN_INLINE void dmnsn_list_pop(dmnsn_list *list, void *obj) { @@ -221,11 +324,22 @@ dmnsn_list_pop(dmnsn_list *list, void *obj) dmnsn_list_remove(list, list->last); } -/* Splits a list in half, and returns the second half */ +/** + * Split a list in half, and return the second half. + * @param[in,out] list The list to split. + * @return A the second half of the list. + */ dmnsn_list *dmnsn_list_split(dmnsn_list *list); -/* Sort a list */ + +/** List object comparator function type */ typedef bool dmnsn_list_comparator_fn(dmnsn_list_iterator *l, dmnsn_list_iterator *r); + +/** + * Sort a list, with O(n*log(n)) comparisons. + * @param[in,out] list The list to sort. + * @param[in] comparator The comparator to use for comparisons. + */ void dmnsn_list_sort(dmnsn_list *list, dmnsn_list_comparator_fn *comparator); #endif /* DIMENSION_LIST_H */ diff --git a/libdimension/dimension/malloc.h b/libdimension/dimension/malloc.h index 3c9e84b..7a5295a 100644 --- a/libdimension/dimension/malloc.h +++ b/libdimension/dimension/malloc.h @@ -18,15 +18,41 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Seriously, how often does malloc fail? And how often can you do something - * better than bail out when it does? dmnsn_malloc() is like malloc in every - * way except it calls dmnsn_error() on failure. +/** + * @file + * Dynamic memory. dmnsn_malloc() and friends behave like their + * non-dmnsn_-prefixed counterparts, but never return NULL. If allocation + * fails, they instead call dmnsn_error(DMNSN_SEVERITY_HIGH). */ #include <stddef.h> /* For size_t */ +/** + * Allocate some memory. Always use dmnsn_free() to free this memory, never + * free(). + * @param[in] size The size of the memory block to allocate. + * @return The allocated memory area. + */ void *dmnsn_malloc(size_t size); + +/** + * Expand or shrink an allocation created by dmnsn_malloc(). + * @param[in] ptr The block to resize. + * @param[in] size The new size. + * @return The resized memory area. + */ void *dmnsn_realloc(void *ptr, size_t size); + +/** + * Duplicate a string. + * @param[in] s The string to duplicate. + * @return A string with the same contents as \p s, suitable for release by + * dmnsn_free(). + */ char *dmnsn_strdup(const char *s); -void dmnsn_free(void *ptr); + +/** + * Free memory allocated by dmnsn_malloc() or dmnsn_strdup(). + * @param[in] ptr The memory block to free, or NULL. + */ +void dmnsn_free(void *ptr); diff --git a/libdimension/dimension/object.h b/libdimension/dimension/object.h index 56cfacd..28682a2 100644 --- a/libdimension/dimension/object.h +++ b/libdimension/dimension/object.h @@ -18,7 +18,8 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* +/** + * @file * Objects. */ @@ -27,70 +28,104 @@ #include <stdbool.h> -/* A type to represent a ray-object intersection */ +/** A type to represent a ray-object intersection. */ typedef struct dmnsn_intersection { - /* The ray and point which intersected */ - dmnsn_line ray; - double t; + dmnsn_line ray; /**< The ray that intersected. */ + double t; /**< The line index that intersected */ - /* The surface normal at the intersection point */ - dmnsn_vector normal; + dmnsn_vector normal; /**< The surface normal at the intersection point */ - /* The object properties at the intersection point */ - const dmnsn_texture *texture; - const dmnsn_interior *interior; + const dmnsn_texture *texture; /**< The texture at the intersection point */ + const dmnsn_interior *interior; /**< The interior at the intersection point */ } dmnsn_intersection; /* Forward-declare dmnsn_object */ typedef struct dmnsn_object dmnsn_object; -/* Object callback types */ - +/** + * Object initialization callback. + * @param[in,out] object The object to initialize. + */ typedef void dmnsn_object_init_fn(dmnsn_object *object); + +/** + * Ray-object intersection callback. + * @param[in] object The object to test. + * @param[in] line The line to test. + * @param[out] intersection Where to store the intersection details of the + * closest (if any) intersection. + * @return Whether \p line intersected \p object. + */ typedef bool dmnsn_object_intersection_fn(const dmnsn_object *object, dmnsn_line line, dmnsn_intersection *intersection); + +/** + * Object inside callback. + * @param[in] object The object to test. + * @param[in] point The point to test. + * @return Whether \p point is inside \p object. + */ typedef bool dmnsn_object_inside_fn(const dmnsn_object *object, dmnsn_vector point); -/* dmnsn_object definition */ +/** An object. */ struct dmnsn_object { - /* Surface properties */ - dmnsn_texture *texture; - - /* Interior properties */ - dmnsn_interior *interior; + dmnsn_texture *texture; /**< Surface properties */ + dmnsn_interior *interior; /**< Interior properties */ - /* Transformation matrix */ - dmnsn_matrix trans, trans_inv; + dmnsn_matrix trans; /**< Transformation matrix */ + dmnsn_matrix trans_inv; /**< Inverse of the transformation matrix */ - /* Bounding box */ - dmnsn_bounding_box bounding_box; + dmnsn_bounding_box bounding_box; /**< Object bounding box */ - /* Child objects */ + /** Child objects. This array lists objects that can be split into + sub-objects for bounding purposes (for unions and meshes, for example). */ dmnsn_array *children; - /* Callback functions */ - dmnsn_object_init_fn *init_fn; - dmnsn_object_intersection_fn *intersection_fn; - dmnsn_object_inside_fn *inside_fn; - dmnsn_free_fn *free_fn; + dmnsn_object_init_fn *init_fn; /**< Initialization callback. */ + dmnsn_object_intersection_fn *intersection_fn; /**< Intersection callback. */ + dmnsn_object_inside_fn *inside_fn; /**< Inside callback. */ + dmnsn_free_fn *free_fn; /**< Destruction callback. */ - /* Generic pointer for object info */ + /** Generic pointer for object info */ void *ptr; }; -/* Allocate a dummy object */ +/** + * Allocate a dummy object. + * @return The allocated object. + */ dmnsn_object *dmnsn_new_object(void); -/* Free an object */ + +/** + * Free an object + * @param[in,out] object The object to destroy. + */ void dmnsn_delete_object(dmnsn_object *object); -/* Initialize an object and potentially its children */ +/** + * Initialize an object and potentially its children. + * @param[in,out] object The object to initialize. + */ void dmnsn_object_init(dmnsn_object *object); -/* Helpers for invoking object callbacks with correct transformations */ +/** + * Appropriately transform a ray, then test for an intersection. + * @param[in] object The object to test. + * @param[in] line The ray to test. + * @param[out] intersection Where to store the intersection details. + * @return Whether there was an intersection. + */ bool dmnsn_object_intersection(const dmnsn_object *object, dmnsn_line line, dmnsn_intersection *intersection); + +/** + * Appropriately transform a point, then test for containment. + * @param[in] object The object to test. + * @param[in] point The point to test. + * @return Whether \p point was inside \p object. + */ bool dmnsn_object_inside(const dmnsn_object *object, dmnsn_vector point); #endif /* DIMENSION_OBJECT_H */ diff --git a/libdimension/dimension/objects.h b/libdimension/dimension/objects.h index 41706a0..a98541b 100644 --- a/libdimension/dimension/objects.h +++ b/libdimension/dimension/objects.h @@ -18,8 +18,9 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Custom objects. +/** + * @file + * Pre-defined objects. */ #ifndef DIMENSION_OBJECTS_H @@ -27,19 +28,40 @@ #include <stdbool.h> -/* A plane through the origin, with the given normal */ +/** + * A plane. + * @param[in] normal The normal vector of the plane. + * @return A plane through the origin, with the given normal. + */ dmnsn_object *dmnsn_new_plane(dmnsn_vector normal); -/* A sphere object, of radius 1, centered at the origin. */ +/** + * A sphere. + * @return A sphere of radius 1, centered at the origin. + */ dmnsn_object *dmnsn_new_sphere(void); -/* A cube, axis-aligned, from (-1, -1, -1) to (1, 1, 1) */ +/** + * A cube. + * @return An axis-aligned cube, from (-1, -1, -1) to (1, 1, 1). + */ dmnsn_object *dmnsn_new_cube(void); -/* A cylinder/cone, from r = r1 at y = -1, to r = r2 at y = 1 */ -dmnsn_object *dmnsn_new_cylinder(double r1, double r2, bool open); +/** + * A cylinder/cone. + * @param[in] r1 The bottom radius. + * @param[in] r2 The top radius. + * @param[in] open Whether to render caps. + * @return A cone slice, from r = \p r1 at y = -1, to r = \p r2 at y = 1 + */ +dmnsn_object *dmnsn_new_cone(double r1, double r2, bool open); -/* A torus, centered at the origin and lying in the x-z plane */ +/** + * A torus. + * @param[in] major The major radius. + * @param[in] minor The minor radius. + * @return A torus, centered at the origin and lying in the x-z plane. + */ dmnsn_object *dmnsn_new_torus(double major, double minor); #endif /* DIMENSION_OBJECTS_H */ diff --git a/libdimension/dimension/pattern.h b/libdimension/dimension/pattern.h index 6301372..9636155 100644 --- a/libdimension/dimension/pattern.h +++ b/libdimension/dimension/pattern.h @@ -18,8 +18,10 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Patterns +/** + * @file + * Patterns. Patterns are functions which map vectors to scalars, which are + * used for pigments and normals. */ #ifndef DIMENSION_PATTERN_H @@ -28,28 +30,52 @@ /* Forward-declare dmnsn_pattern */ typedef struct dmnsn_pattern dmnsn_pattern; -/* Pattern callback */ +/** + * Pattern callback. + * @param[in] pattern The pattern itself. + * @param[in] v The point at which to evaluate the pattern. + * @return The value of the pattern at \p v. + */ typedef double dmnsn_pattern_fn(const dmnsn_pattern *pattern, dmnsn_vector v); -/* Generic pattern */ +/** A pattern. */ struct dmnsn_pattern { - /* Callbacks */ - dmnsn_pattern_fn *pattern_fn; - dmnsn_free_fn *free_fn; + dmnsn_pattern_fn *pattern_fn; /**< The pattern callback. */ + dmnsn_free_fn *free_fn; /**< The destructor callback. */ - /* Transformation matrix */ - dmnsn_matrix trans, trans_inv; + dmnsn_matrix trans; /**< The transformation matrix of the pattern */ + dmnsn_matrix trans_inv; /**< The inverse of the transformation matrix */ - /* Generic pointer */ - void *ptr; + void *ptr; /**< Generic pointer */ }; +/** + * Allocate an dummy pattern. + * @return A pattern with no callbacks set. + */ dmnsn_pattern *dmnsn_new_pattern(void); + +/** + * Delete a pattern. + * @param[in,out] pattern The pattern to destroy. + */ void dmnsn_delete_pattern(dmnsn_pattern *pattern); +/** + * Initialize a pattern. This precomputes some values that are used during + * ray-tracing; the pattern will not work until it has been initialized, but + * should not be modified after it has been initialized. Patterns are generally + * initialized for you. + * @param[in,out] pattern The pattern to initialize. + */ void dmnsn_pattern_init(dmnsn_pattern *pattern); -/* Invoke the pattern callback with the right transformation */ +/** + * Invoke the pattern callback with the right transformation. + * @param[in] pattern The pattern to evaluate. + * @param[in] v The point to get the pattern value for. + * @return The value of the pattern at \p v. + */ double dmnsn_pattern_value(const dmnsn_pattern *pattern, dmnsn_vector v); #endif /* DIMENSION_PATTERN_H */ diff --git a/libdimension/dimension/patterns.h b/libdimension/dimension/patterns.h index cd4aa35..5dd44bf 100644 --- a/libdimension/dimension/patterns.h +++ b/libdimension/dimension/patterns.h @@ -18,14 +18,27 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Custom patterns +/** + * @file + * Pre-defined patterns. */ #ifndef DIMENSION_PATTERNS_H #define DIMENSION_PATTERNS_H -dmnsn_pattern *dmnsn_new_checker_pattern(); +/** + * A checker pattern. The pattern is composed of tesselating unit cubes + * alternating between 0 and 1. + * @return A checker pattern. + */ +dmnsn_pattern *dmnsn_new_checker_pattern(void); + +/** + * A gradient. The value starts at 0 at the origin, and goes linearly to 1 in + * the direction of \p orientation, then repeats after a distance of 1. + * @param[in] orientation The direction of the gradient. + * @return A gradient pattern. + */ dmnsn_pattern *dmnsn_new_gradient_pattern(dmnsn_vector orientation); #endif /* DIMENSION_PATTERNS_H */ diff --git a/libdimension/dimension/pigments.h b/libdimension/dimension/pigments.h index 31c0598..68a9c66 100644 --- a/libdimension/dimension/pigments.h +++ b/libdimension/dimension/pigments.h @@ -18,28 +18,67 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Custom pigments. +/** + * @file + * Pre-defined pigments. */ #ifndef DIMENSION_PIGMENTS_H #define DIMENSION_PIGMENTS_H -/* A solid color */ +/** + * A solid color. + * @param[in] color The color of the pigment. + * @return A pigment with the color \p color everywhere. + */ dmnsn_pigment *dmnsn_new_solid_pigment(dmnsn_color color); -/* An image map */ + +/** + * An image map. The image (regardless of its real dimensions) is projected + * on the x-y plane in tesselating unit squares. + * @param[in] canvas The canvas holding the image. + * @return An image-mapped pigment. + */ dmnsn_pigment *dmnsn_new_canvas_pigment(dmnsn_canvas *canvas); -/* Color maps */ +/** Color map. */ typedef dmnsn_array dmnsn_color_map; -dmnsn_color_map *dmnsn_new_color_map(); +/** + * Create an empty color map. + * @return A color map with no entries. + */ +dmnsn_color_map *dmnsn_new_color_map(void); + +/** + * Delete a color map. + * @param[in,out] map The color map to delete. + */ void dmnsn_delete_color_map(dmnsn_color_map *map); +/** + * Add an entry (a scalar-color pair) to a color map. + * @param[in,out] map The color map to add to. + * @param[in] n The index of the entry. + * @param[in] c The value of the entry. + */ void dmnsn_add_color_map_entry(dmnsn_color_map *map, double n, dmnsn_color c); + +/** + * Evaluate a color map. + * @param[in] map The map to evaluate. + * @param[in] n The index to evaluate. + * @return The value of the gradient between the the two indicies closest to + * \p n. + */ dmnsn_color dmnsn_color_map_value(const dmnsn_color_map *map, double n); -/* Color-mapped pigments */ +/** + * A color-mapped pigment. + * @param[in,out] pattern The pattern of the pigment. + * @param[in,out] map The color map to apply to the pattern. + * @return A pigment mapping the pattern to color values. + */ dmnsn_pigment *dmnsn_new_color_map_pigment(dmnsn_pattern *pattern, dmnsn_color_map *map); diff --git a/libdimension/dimension/png.h b/libdimension/dimension/png.h index cf21116..296331a 100644 --- a/libdimension/dimension/png.h +++ b/libdimension/dimension/png.h @@ -18,8 +18,9 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Support for exporting/importing canvases to/from PNG files +/** + * @file + * PNG import/export of canvases */ #ifndef DIMENSION_PNG_H @@ -27,17 +28,46 @@ #include <stdio.h> -/* Optimize canvas for PNG exporting */ +/** + * Optimize a canvas for PNG exporting + * @param[in,out] canvas The canvas to optimize. + * @return Whether the canvas was successfully optimized. + */ int dmnsn_png_optimize_canvas(dmnsn_canvas *canvas); -/* Write canvas to file in PNG format. Returns 0 on success, nonzero on - failure */ +/** + * Write a canvas to a file in PNG format. + * @param[in] canvas The canvas to write. + * @param[in,out] file The file to write to. + * @return 0 on success, non-zero on failure. + */ int dmnsn_png_write_canvas(const dmnsn_canvas *canvas, FILE *file); + +/** + * Write a canvas to a PNG file in the background. + * @param[in] canvas The canvas to write. + * @param[in,out] file The file to write to. + * @return A \ref dmnsn_progress object, or NULL on failure. + */ dmnsn_progress *dmnsn_png_write_canvas_async(const dmnsn_canvas *canvas, FILE *file); -/* Read a canvas from a PNG file. Returns NULL on failure. */ +/** + * Read a canvas from a PNG file. + * @param[in,out] file The PNG file to read. + * @return The new canvas, or NULL on failure. + */ dmnsn_canvas *dmnsn_png_read_canvas(FILE *file); + +/** + * Read a canvas from a PNG file in the background. + * @param[out] canvas The address of a non-allocated canvas object. The + * canvas object will be allocated and filled with the + * contents of \p file. Do not read from this object + * until the background task has finished. + * @param[in,out] file The PNG file to read. + * @return A \ref dmnsn_progress object, or NULL on failure. + */ dmnsn_progress *dmnsn_png_read_canvas_async(dmnsn_canvas **canvas, FILE *file); #endif /* DIMENSION_PNG_H */ diff --git a/libdimension/dimension/polynomial.h b/libdimension/dimension/polynomial.h index 56e3ac0..b0a9357 100644 --- a/libdimension/dimension/polynomial.h +++ b/libdimension/dimension/polynomial.h @@ -18,7 +18,8 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* +/** + * @file * Utility functions for working with and numerically solving polynomials. * Polynomials are represented as simple arrays where the ith element is the * coefficient on x^i. In general, we are only interested in positive roots. @@ -30,6 +31,14 @@ #include <stddef.h> #include <stdio.h> +/** + * Evaluate a polynomial at \p x. + * @param[in] poly The coefficients of the polynomial to evaluate, in order + * from lowest degree to highest degree. The array should + * have dimension <tt>degree + 1</tt>. + * @param[in] degree The degree of the polynomial. + * @param[in] x The value of the variable at which to evaluate. + */ DMNSN_INLINE double dmnsn_evaluate_polynomial(const double poly[], size_t degree, double x) { @@ -41,6 +50,12 @@ dmnsn_evaluate_polynomial(const double poly[], size_t degree, double x) return ret; } +/** + * Evaluate the derivative of a polynomial at \p x. + * @param[in] poly The coefficients of the polynomial to evaluate. + * @param[in] degree The degree of the polynomial. + * @param[in] x The value of the variable at which to evaluate. + */ DMNSN_INLINE double dmnsn_evaluate_polynomial_derivative(const double poly[], size_t degree, double x) @@ -53,11 +68,23 @@ dmnsn_evaluate_polynomial_derivative(const double poly[], size_t degree, return ret; } -/* Stores the positive roots of poly[] in x[], and returns the number of such - roots that were stored */ +/** + * Find the positive roots of a polynomial. + * @param[in] poly The coefficients of the polynomial to solve. + * @param[in] degree The degree of the polynomial. + * @param[out] x An array in which to store the roots. It should have + * dimension \p degree. + * @return The number of positive roots stored in \c x[]. + */ size_t dmnsn_solve_polynomial(const double poly[], size_t degree, double x[]); -/* Helper function to print a polynomial */ +/** + * Output a polynomial. The polynomial is printed as a function of x suitable + * for input into a CAS, and without a trailing newline. + * @param[in,out] file The file to write to. + * @param[in] poly The coefficients of the polynomial to print. + * @param[in] degree The degree of the polynomial. + */ void dmnsn_print_polynomial(FILE *file, const double poly[], size_t degree); #endif /* DIMENSION_POLYNOMIAL_H */ diff --git a/libdimension/dimension/progress.h b/libdimension/dimension/progress.h index 043f014..89d0d25 100644 --- a/libdimension/dimension/progress.h +++ b/libdimension/dimension/progress.h @@ -18,7 +18,8 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* +/** + * @file * An interface for asynchronous tasks. *_async() versions of functions * return a dmnsn_progress* object which can indicate the progress of the * background task, and wait for task completion. The task's return value @@ -28,15 +29,30 @@ #ifndef DIMENSION_PROGRESS_H #define DIMENSION_PROGRESS_H +/** A progress object */ typedef struct dmnsn_progress dmnsn_progress; -/* Join the worker thread and return it's integer return value in addition to - deleting `progress' */ +/** + * Join the worker thread and return it's integer return value in addition to + * deleting \p progress. + * @param[in,out] progress The background task to finish. + * @return The return value of the background task. + */ int dmnsn_finish_progress(dmnsn_progress *progress); -/* Get the progress of the background task, out of 1.0 */ +/** + * Get the progress of the background task. + * @param[in] progress The background task to examine. + * @return The progress of the background task, out of 1.0. + */ double dmnsn_get_progress(const dmnsn_progress *progress); -/* Wait for the progress to be >= prog, in a better way than spinlocking */ + +/** + * Wait for a certain amount of progress. Always use this rather than + * spinlocking. + * @param[in] progress The background task to monitor. + * @param[in] prog The progress value to wait for. + */ void dmnsn_wait_progress(const dmnsn_progress *progress, double prog); #endif /* DIMENSION_PROGRESS_H */ diff --git a/libdimension/dimension/raytrace.h b/libdimension/dimension/raytrace.h index f145d5f..2fee879 100644 --- a/libdimension/dimension/raytrace.h +++ b/libdimension/dimension/raytrace.h @@ -18,15 +18,25 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Render a scene by raytracing +/** + * @file + * Ray-trace a scene. */ #ifndef DIMENSION_RAYTRACE_H #define DIMENSION_RAYTRACE_H -/* Render a scene by raytracing */ +/** + * Render a scene by raytracing. + * @param[in,out] scene The scene to render. + */ void dmnsn_raytrace_scene(dmnsn_scene *scene); + +/** + * Render a scene in the background. + * @param[in,out] scene The scene to render. + * @return A \p dmnsn_progress object. + */ dmnsn_progress *dmnsn_raytrace_scene_async(dmnsn_scene *scene); #endif /* DIMENSION_RAYTRACE_H */ diff --git a/libdimension/dimension/scene.h b/libdimension/dimension/scene.h index 7e52859..36fe74e 100644 --- a/libdimension/dimension/scene.h +++ b/libdimension/dimension/scene.h @@ -18,60 +18,70 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * A scene. +/** + * @file + * Entire scenes. */ #ifndef DIMENSION_SCENE_H #define DIMENSION_SCENE_H -#include <stdbool.h> - +/** Render quality flags. */ enum { - DMNSN_RENDER_NONE = 0, - DMNSN_RENDER_PIGMENT = 1 << 0, - DMNSN_RENDER_LIGHTS = 1 << 1, - DMNSN_RENDER_FINISH = 1 << 2, - DMNSN_RENDER_TRANSLUCENCY = 1 << 3, - DMNSN_RENDER_REFLECTION = 1 << 4, - DMNSN_RENDER_FULL = ~DMNSN_RENDER_NONE + DMNSN_RENDER_NONE = 0, /**< Render nothing. */ + DMNSN_RENDER_PIGMENT = 1 << 0, /**< Render pigments. */ + DMNSN_RENDER_LIGHTS = 1 << 1, /**< Render lights and shadows. */ + DMNSN_RENDER_FINISH = 1 << 2, /**< Render object finishes. */ + DMNSN_RENDER_TRANSLUCENCY = 1 << 3, /**< Render translucency/refraction. */ + DMNSN_RENDER_REFLECTION = 1 << 4, /**< Render specular reflection. */ + DMNSN_RENDER_FULL = ~DMNSN_RENDER_NONE /**< Render everything. */ }; +/** Render quality. */ typedef unsigned int dmnsn_quality; -typedef struct { +/** An entire scene. */ +typedef struct dmnsn_scene { /* World attributes */ - dmnsn_color background; - dmnsn_texture *default_texture; + dmnsn_color background; /**< Background color. */ + dmnsn_texture *default_texture; /**< Default object texture. */ - /* Camera */ + /** Camera. */ dmnsn_camera *camera; - /* Canvas */ + /** Canvas. */ dmnsn_canvas *canvas; - /* Objects */ + /** Objects. */ dmnsn_array *objects; - /* Lights */ + /** Lights. */ dmnsn_array *lights; - /* Rendering quality */ + /** Render quality. */ dmnsn_quality quality; - /* Recursion limit */ + /** Recursion limit. */ unsigned int reclimit; - /* Number of parallel threads */ + /** Number of parallel threads. */ unsigned int nthreads; - /* Timers */ + /** Timers */ dmnsn_timer *bounding_timer; dmnsn_timer *render_timer; } dmnsn_scene; -/* Create a scene */ +/** + * Create a scene. + * @return A new empty scene. + */ dmnsn_scene *dmnsn_new_scene(void); + +/** + * Delete a scene. + * @param[in,out] scene The scene to delete. + */ void dmnsn_delete_scene(dmnsn_scene *scene); #endif /* DIMENSION_SCENE_H */ diff --git a/libdimension/dimension/texture.h b/libdimension/dimension/texture.h index 5586e24..f582351 100644 --- a/libdimension/dimension/texture.h +++ b/libdimension/dimension/texture.h @@ -18,7 +18,8 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* +/** + * @file * Object textures. */ @@ -32,31 +33,55 @@ /* Forward-declare dmnsn_pigment */ typedef struct dmnsn_pigment dmnsn_pigment; -/* Pigment callbacks */ +/** + * Pigment callback. + * @param[in] pigment The pigment itself. + * @param[in] v The point to color. + * @return The color of the pigment at \p v. + */ typedef dmnsn_color dmnsn_pigment_fn(const dmnsn_pigment *pigment, dmnsn_vector v); + +/** + * Pigment initializer callback. + * @param[in,out] pigment The pigment to initialize. + */ typedef void dmnsn_pigment_init_fn(dmnsn_pigment *pigment); -/* dmnsn_pigment definition */ +/** A pigment */ struct dmnsn_pigment { - /* Callbacks */ - dmnsn_pigment_fn *pigment_fn; - dmnsn_pigment_init_fn *init_fn; - dmnsn_free_fn *free_fn; + dmnsn_pigment_fn *pigment_fn; /**< The pigment callback. */ + dmnsn_pigment_init_fn *init_fn; /**< The initializer callback. */ + dmnsn_free_fn *free_fn; /**< The destructor callback. */ - /* Transformation matrix */ - dmnsn_matrix trans, trans_inv; + dmnsn_matrix trans; /**< Transformation matrix. */ + dmnsn_matrix trans_inv; /**< The inverse of the transformation matrix. */ - /* Quick color */ + /** Quick color -- used for low-quality renders. */ dmnsn_color quick_color; - /* Generic pointer */ + /** Generic pointer */ void *ptr; }; +/** + * Allocate a new dummy pigment. + * @return The allocated pigment. + */ dmnsn_pigment *dmnsn_new_pigment(void); + +/** + * Delete a pigment. + * @param[in,out] pigment The pigment to delete. + */ void dmnsn_delete_pigment(dmnsn_pigment *pigment); +/** + * Initialize a pigment. Pigments should not be used before being initialized, + * but should not be modified after being initialized. Pigments are generally + * initialized for you. + * @param[in,out] pigment The pigment to initialize. + */ void dmnsn_pigment_init(dmnsn_pigment *pigment); /* @@ -66,56 +91,111 @@ void dmnsn_pigment_init(dmnsn_pigment *pigment); /* Forward-declare dmnsn_finish */ typedef struct dmnsn_finish dmnsn_finish; -/* Finish callbacks */ +/** + * Diffuse reflection callback. + * @param[in] finish The finish itself. + * @param[in] light The color of the light illuminating the object. + * @param[in] color The pigment of the object. + * @param[in] ray The direction of the light source. + * @param[in] normal The normal vector of the surface. + * @return The diffuse reflection component of the object's color. + */ typedef dmnsn_color dmnsn_diffuse_fn(const dmnsn_finish *finish, dmnsn_color light, dmnsn_color color, dmnsn_vector ray, dmnsn_vector normal); +/** + * Specular highlight callback. + * @param[in] finish The finish itself. + * @param[in] light The color of the light illuminating the object. + * @param[in] color The pigment of the object. + * @param[in] ray The direction of the light source. + * @param[in] normal The normal vector of the surface. + * @param[in] viewer The direction of the viewer. + * @return The specular reflection component of the object's color. + */ typedef dmnsn_color dmnsn_specular_fn(const dmnsn_finish *finish, dmnsn_color light, dmnsn_color color, dmnsn_vector ray, dmnsn_vector normal, dmnsn_vector viewer); +/** + * Ambient light callback. + * @param[in] finish The finish itself. + * @param[in] pigment The pigment of the object. + * @return The ambient contribution to the object's color. + */ typedef dmnsn_color dmnsn_ambient_fn(const dmnsn_finish *finish, dmnsn_color pigment); +/** + * Reflected light callback. + * @param[in] finish The finish itself. + * @param[in] reflect The color of the reflected ray. + * @param[in] color The pigment of the object. + * @param[in] ray The direction of the reflected ray. + * @param[in] normal The normal vector of the surface. + * @return The contribution of the reflected ray to the object's color. + */ typedef dmnsn_color dmnsn_reflection_fn(const dmnsn_finish *finish, dmnsn_color reflect, dmnsn_color color, dmnsn_vector ray, dmnsn_vector normal); -/* dmnsn_finish definition */ +/** A finish. */ struct dmnsn_finish { - /* Callbacks */ - dmnsn_diffuse_fn *diffuse_fn; - dmnsn_specular_fn *specular_fn; - dmnsn_ambient_fn *ambient_fn; - dmnsn_reflection_fn *reflection_fn; - dmnsn_free_fn *free_fn; - - /* Generic pointer */ + dmnsn_diffuse_fn *diffuse_fn; /**< The diffuse callback. */ + dmnsn_specular_fn *specular_fn; /**< The specular callback. */ + dmnsn_ambient_fn *ambient_fn; /**< The ambient callback. */ + dmnsn_reflection_fn *reflection_fn; /**< The reflection callback. */ + dmnsn_free_fn *free_fn; /**< The destruction callback. */ + + /** Generic pointer */ void *ptr; }; +/** + * Allocate a new dummy finish. + * @return The allocated finish. + */ dmnsn_finish *dmnsn_new_finish(void); + +/** + * Delete a finish. + * @param[in,out] finish The finish to delete. + */ void dmnsn_delete_finish(dmnsn_finish *finish); /* - * A complete texture + * Textures */ +/** A complete texture. */ typedef struct { - /* Texture components */ - dmnsn_pigment *pigment; - dmnsn_finish *finish; + dmnsn_pigment *pigment; /**< Pigment. */ + dmnsn_finish *finish; /**< Finish. */ - /* Transformation matrix */ - dmnsn_matrix trans, trans_inv; + dmnsn_matrix trans; /**< Transformation matrix. */ + dmnsn_matrix trans_inv; /**< The inverse of the transformation matrix. */ - /* Reference count */ - unsigned int *refcount; - bool should_init; + unsigned int *refcount; /**< @internal Reference count. */ + bool should_init; /**< @internal Whether to init the texture. */ } dmnsn_texture; +/** + * Create a blank texture. + * @return The new texture. + */ dmnsn_texture *dmnsn_new_texture(void); + +/** + * Delete a texture. + * @param[in,out] texture The texture to delete. + */ void dmnsn_delete_texture(dmnsn_texture *texture); +/** + * Initialize a texture. Textures should not be used before being initialized, + * but should not be modified after being initialized. Textures are generally + * initialized for you. + * @param[in,out] texture The texture to initialize. + */ void dmnsn_texture_init(dmnsn_texture *texture); #endif /* DIMENSION_TEXTURE_H */ diff --git a/libdimension/dimension/timer.h b/libdimension/dimension/timer.h index 0f3c61f..9e935c2 100644 --- a/libdimension/dimension/timer.h +++ b/libdimension/dimension/timer.h @@ -18,17 +18,43 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * A platform-agnostic timer abstraction +/** + * @file + * A platform-agnostic timer abstraction. */ +/** A platform-agnotic timer. */ typedef struct dmnsn_timer { - double real, user, system; + double real; /**< Wall-clock time. */ + double user; /**< Time spent executing. */ + double system; /**< Time spent waiting for the system. */ } dmnsn_timer; +/** A standard format string for timers. */ #define DMNSN_TIMER_FORMAT "%.2fs (user: %.2fs; system: %.2fs)" +/** + * The appropriate arguments to printf() a timer. For example: + * @code + * printf(DMNSN_TIMER_FORMAT "\n", DMNSN_TIMER_PRINTF(timer)); + * @endcode + * will print something like "1.00s (user: 0.99s; system: 0.01s)". + */ #define DMNSN_TIMER_PRINTF(t) (t)->real, (t)->user, (t)->system +/** + * Create a new timer. Timing starts right before this function returns. + * @return A new timer object. + */ dmnsn_timer *dmnsn_new_timer(void); + +/** + * Finish timing. The members of the timer struct will now contain timing data. + * @param[in,out] timer The timer to stop. + */ void dmnsn_complete_timer(dmnsn_timer *timer); + +/** + * Delete a timer. + * @param[in,out] timer The timer to delete. + */ void dmnsn_delete_timer(dmnsn_timer *timer); diff --git a/libdimension/error.c b/libdimension/error.c index 31d1606..f87c655 100644 --- a/libdimension/error.c +++ b/libdimension/error.c @@ -18,17 +18,28 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Error handling. + */ + #include "dimension-impl.h" #include <pthread.h> #include <stdio.h> /* For fprintf() */ #include <stdlib.h> /* For exit() */ +/** The default fatal error handler. */ static void dmnsn_default_fatal_error_fn(void); + +/** The current fatal error handler. */ static dmnsn_fatal_error_fn *dmnsn_fatal = &dmnsn_default_fatal_error_fn; +/** Mutex which protects \c dmnsn_fatal. */ +static pthread_mutex_t dmnsn_fatal_mutex = PTHREAD_MUTEX_INITIALIZER; +/** The current resilience. */ static dmnsn_severity dmnsn_resilience = DMNSN_SEVERITY_MEDIUM; +/** Mutex which protexts \c dmnsn_resilience. */ static pthread_mutex_t dmnsn_resilience_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t dmnsn_fatal_mutex = PTHREAD_MUTEX_INITIALIZER; /* Called by dmnsn_error macro (don't call directly). */ void diff --git a/libdimension/finish_combination.c b/libdimension/finish_combination.c index 1a54d22..49908bd 100644 --- a/libdimension/finish_combination.c +++ b/libdimension/finish_combination.c @@ -18,14 +18,16 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Finish combinations. + */ + #include "dimension.h" #include <math.h> #include <stdlib.h> -/* - * Finish combinations - */ - +/** Diffuse combination callback. */ static dmnsn_color dmnsn_finish_combination_diffuse_fn(const dmnsn_finish *finish, dmnsn_color light, dmnsn_color color, @@ -46,6 +48,7 @@ dmnsn_finish_combination_diffuse_fn(const dmnsn_finish *finish, } } +/** Specular combination callback. */ static dmnsn_color dmnsn_finish_combination_specular_fn(const dmnsn_finish *finish, dmnsn_color light, dmnsn_color color, @@ -69,6 +72,7 @@ dmnsn_finish_combination_specular_fn(const dmnsn_finish *finish, } } +/** Ambient combination callback. */ static dmnsn_color dmnsn_finish_combination_ambient_fn(const dmnsn_finish *finish, dmnsn_color pigment) @@ -86,6 +90,7 @@ dmnsn_finish_combination_ambient_fn(const dmnsn_finish *finish, } } +/** Reflection combination callback. */ static dmnsn_color dmnsn_finish_combination_reflection_fn(const dmnsn_finish *finish, dmnsn_color reflect, dmnsn_color color, @@ -106,6 +111,7 @@ dmnsn_finish_combination_reflection_fn(const dmnsn_finish *finish, } } +/** Finish combination destructor callback. */ static void dmnsn_finish_combination_free_fn(void *ptr) { diff --git a/libdimension/geometry.c b/libdimension/geometry.c index 6d3652f..9f198b8 100644 --- a/libdimension/geometry.c +++ b/libdimension/geometry.c @@ -18,6 +18,11 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Geometrical function implementations. + */ + #include "dimension.h" #include <math.h> @@ -58,7 +63,7 @@ dmnsn_rotation_matrix(dmnsn_vector theta) /* Two trig calls, 25 multiplications, 13 additions */ double angle = dmnsn_vector_norm(theta); - if (angle == 0.0) { + if (fabs(angle) < dmnsn_epsilon) { return dmnsn_identity_matrix(); } dmnsn_vector axis = dmnsn_vector_div(theta, angle); @@ -88,14 +93,14 @@ dmnsn_vector_axis_angle(dmnsn_vector v1, dmnsn_vector v2, dmnsn_vector axis) dmnsn_vector proj = dmnsn_vector_add(dmnsn_vector_proj(d, axis), v2); double projn = dmnsn_vector_norm(proj); - if (!projn) + if (fabs(projn) < dmnsn_epsilon) return 0.0; double c = dmnsn_vector_dot(dmnsn_vector_normalize(v1), dmnsn_vector_div(proj, projn)); double angle = acos(c); - if (dmnsn_vector_dot(dmnsn_vector_cross(v1, proj), axis) > 0) { + if (dmnsn_vector_dot(dmnsn_vector_cross(v1, proj), axis) > 0.0) { return angle; } else { return -angle; @@ -104,16 +109,25 @@ dmnsn_vector_axis_angle(dmnsn_vector v1, dmnsn_vector v2, dmnsn_vector axis) /* Matrix inversion helper functions */ +/** A 2x2 matrix for inversion by partitioning. */ typedef struct { double n[2][2]; } dmnsn_matrix2; +/** Construct a 2x2 matrix. */ static dmnsn_matrix2 dmnsn_new_matrix2(double a1, double a2, double b1, double b2); +/** Invert a 2x2 matrix. */ static dmnsn_matrix2 dmnsn_matrix2_inverse(dmnsn_matrix2 A); +/** Negate a 2x2 matrix. */ static dmnsn_matrix2 dmnsn_matrix2_negate(dmnsn_matrix2 A); +/** Subtract two 2x2 matricies. */ static dmnsn_matrix2 dmnsn_matrix2_sub(dmnsn_matrix2 lhs, dmnsn_matrix2 rhs); +/** Add two 2x2 matricies. */ static dmnsn_matrix2 dmnsn_matrix2_mul(dmnsn_matrix2 lhs, dmnsn_matrix2 rhs); +/** Invert a matrix with the slower cofactor algorithm, if partitioning + failed. */ static dmnsn_matrix dmnsn_matrix_inverse_generic(dmnsn_matrix A); +/** Get the [\p row, \p col] cofactor of A */ static double dmnsn_matrix_cofactor(dmnsn_matrix A, unsigned int row, unsigned int col); @@ -395,29 +409,3 @@ dmnsn_transform_bounding_box(dmnsn_matrix trans, dmnsn_bounding_box box) return ret; } - -/* Solve for the t value such that x0 + t*n = x */ -double -dmnsn_line_index(dmnsn_line l, dmnsn_vector x) -{ - /* nz + 1 divisions, nz additions */ - double d = 0.0; - unsigned int nz = 0; - - if (l.n.x != 0.0) { - d += (x.x - l.x0.x)/l.n.x; - ++nz; - } - - if (l.n.y != 0.0) { - d += (x.y - l.x0.y)/l.n.y; - ++nz; - } - - if (l.n.z != 0.0) { - d += (x.z - l.x0.z)/l.n.z; - ++nz; - } - - return d/nz; -} diff --git a/libdimension/gl-stubs.c b/libdimension/gl-stubs.c index 1d6946d..656b6a8 100644 --- a/libdimension/gl-stubs.c +++ b/libdimension/gl-stubs.c @@ -18,11 +18,14 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Stubs for GL functions when compiled with --disable-gl. + */ + #include "dimension.h" #include <errno.h> -/* Stubs for GL functions when compiled with --disable-gl */ - int dmnsn_gl_optimize_canvas(dmnsn_canvas *canvas) { diff --git a/libdimension/gl.c b/libdimension/gl.c index b09509e..2b26938 100644 --- a/libdimension/gl.c +++ b/libdimension/gl.c @@ -18,13 +18,18 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * OpenGL import/export. + */ + #include "dimension.h" #include <GL/gl.h> #include <stdlib.h> #include <stdint.h> -/* GL optimizer callback */ -static void dmnsn_gl_optimizer_fn(dmnsn_canvas *canvas, +/** GL optimizer callback. */ +static void dmnsn_gl_optimizer_fn(const dmnsn_canvas *canvas, dmnsn_canvas_optimizer optimizer, size_t x, size_t y); @@ -44,7 +49,7 @@ dmnsn_gl_optimize_canvas(dmnsn_canvas *canvas) optimizer.free_fn = &dmnsn_free; /* Allocate a buffer to hold RGB values */ - optimizer.ptr = dmnsn_malloc(4*canvas->x*canvas->y*sizeof(GLushort)); + optimizer.ptr = dmnsn_malloc(4*canvas->width*canvas->height*sizeof(GLushort)); /* Set a new optimizer */ dmnsn_optimize_canvas(canvas, optimizer); @@ -60,8 +65,8 @@ dmnsn_gl_write_canvas(const dmnsn_canvas *canvas) dmnsn_sRGB sRGB; dmnsn_color color; - size_t width = canvas->x; - size_t height = canvas->y; + size_t width = canvas->width; + size_t height = canvas->height; /* Check if we can optimize this */ DMNSN_ARRAY_FOREACH (dmnsn_canvas_optimizer *, i, canvas->optimizers) { @@ -160,12 +165,12 @@ dmnsn_gl_read_canvas(size_t x0, size_t y0, /* GL optimizer callback */ static void -dmnsn_gl_optimizer_fn(dmnsn_canvas *canvas, dmnsn_canvas_optimizer optimizer, - size_t x, size_t y) +dmnsn_gl_optimizer_fn(const dmnsn_canvas *canvas, + dmnsn_canvas_optimizer optimizer, size_t x, size_t y) { dmnsn_color color; dmnsn_sRGB sRGB; - GLushort *pixel = (GLushort *)optimizer.ptr + 4*(y*canvas->x + x); + GLushort *pixel = (GLushort *)optimizer.ptr + 4*(y*canvas->width + x); color = dmnsn_get_pixel(canvas, x, y); sRGB = dmnsn_sRGB_from_color(color); diff --git a/libdimension/gradient.c b/libdimension/gradient.c index 6bcb3b8..47e6c6b 100644 --- a/libdimension/gradient.c +++ b/libdimension/gradient.c @@ -18,12 +18,14 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -#include "dimension.h" - -/* - * Gradient pattern +/** + * @file + * Gradient pattern. */ +#include "dimension.h" + +/** Gradient pattern callback. */ static double dmnsn_gradient_pattern_fn(const dmnsn_pattern *gradient, dmnsn_vector v) { diff --git a/libdimension/inline.c b/libdimension/inline.c index adffd6c..a1b4694 100644 --- a/libdimension/inline.c +++ b/libdimension/inline.c @@ -18,6 +18,11 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Emit definitions of inline functions, if necessary. + */ + /* Set DMNSN_INLINE to produce definitions of inline functions, emitted here, if needed */ #ifdef __cplusplus diff --git a/libdimension/interior.c b/libdimension/interior.c index 6bf76e4..035a7f6 100644 --- a/libdimension/interior.c +++ b/libdimension/interior.c @@ -18,6 +18,11 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Interiors. + */ + #include "dimension.h" #include <stdlib.h> diff --git a/libdimension/light.c b/libdimension/light.c index 4e0f850..445a9d3 100644 --- a/libdimension/light.c +++ b/libdimension/light.c @@ -18,6 +18,11 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Lights. + */ + #include "dimension.h" #include <stdlib.h> diff --git a/libdimension/list.c b/libdimension/list.c index 15051d6..3ccc6b8 100644 --- a/libdimension/list.c +++ b/libdimension/list.c @@ -18,6 +18,11 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Doubly-linked lists. + */ + #include "dimension.h" dmnsn_list * diff --git a/libdimension/malloc.c b/libdimension/malloc.c index 605de8b..f5666a0 100644 --- a/libdimension/malloc.c +++ b/libdimension/malloc.c @@ -18,6 +18,11 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Dynamic memory. + */ + #include "dimension.h" #include <stdlib.h> #include <string.h> diff --git a/libdimension/object.c b/libdimension/object.c index d710304..bb4eeb1 100644 --- a/libdimension/object.c +++ b/libdimension/object.c @@ -18,6 +18,11 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Objects. + */ + #include "dimension.h" #include <stdlib.h> diff --git a/libdimension/pattern.c b/libdimension/pattern.c index 0be017f..9e8dacb 100644 --- a/libdimension/pattern.c +++ b/libdimension/pattern.c @@ -18,6 +18,11 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Patterns. + */ + #include "dimension.h" /* Allocate a dummy pattern */ diff --git a/libdimension/perspective.c b/libdimension/perspective.c index cc602eb..0fa5567 100644 --- a/libdimension/perspective.c +++ b/libdimension/perspective.c @@ -18,60 +18,30 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Perspective cameras. + */ + #include "dimension.h" #include <stdlib.h> -/* - * Perspective camera - */ - -/* Perspective camera ray callback */ -static dmnsn_line dmnsn_perspective_camera_ray_fn(const dmnsn_camera *camera, - double x, double y); +/** Perspective camera ray callback. */ +static dmnsn_line +dmnsn_perspective_camera_ray_fn(const dmnsn_camera *camera, double x, double y) +{ + dmnsn_line l = dmnsn_new_line( + dmnsn_zero, + dmnsn_new_vector(x - 0.5, y - 0.5, 1.0) + ); + return l; +} -/* Create a new perspective camera. Rays are aimed from the origin to a screen - located on the z = 1 plane, from (-0.5, -0.5) to (0.5, 0.5). Rays are then - transformed by the camera's transformation matrix. */ +/* Create a new perspective camera. */ dmnsn_camera * dmnsn_new_perspective_camera() { dmnsn_camera *camera = dmnsn_new_camera(); - - dmnsn_matrix *ptr = dmnsn_malloc(sizeof(dmnsn_matrix)); - *ptr = dmnsn_identity_matrix(); - camera->ray_fn = &dmnsn_perspective_camera_ray_fn; - camera->free_fn = &dmnsn_free; - camera->ptr = ptr; - return camera; } - -/* Get the transformation matrix */ -dmnsn_matrix -dmnsn_get_perspective_camera_trans(const dmnsn_camera *camera) -{ - dmnsn_matrix *trans = camera->ptr; - return *trans; -} - -/* Set the transformation matrix */ -void -dmnsn_set_perspective_camera_trans(dmnsn_camera *camera, dmnsn_matrix T) -{ - dmnsn_matrix *trans = camera->ptr; - *trans = T; -} - -/* Perspective camera ray callback */ -static dmnsn_line -dmnsn_perspective_camera_ray_fn(const dmnsn_camera *camera, - double x, double y) -{ - dmnsn_matrix *trans = camera->ptr; - dmnsn_line l = dmnsn_new_line( - dmnsn_zero, - dmnsn_new_vector(x - 0.5, y - 0.5, 1.0) - ); - return dmnsn_transform_line(*trans, l); -} diff --git a/libdimension/phong.c b/libdimension/phong.c index f0fb3bb..e2afd15 100644 --- a/libdimension/phong.c +++ b/libdimension/phong.c @@ -18,13 +18,15 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Phong highlights. + */ + #include "dimension.h" #include <stdlib.h> -/* - * Phong finish - */ - +/** Phong specular highlight callback. */ static dmnsn_color dmnsn_phong_specular_fn(const dmnsn_finish *finish, dmnsn_color light, dmnsn_color color, diff --git a/libdimension/plane.c b/libdimension/plane.c index be3d91a..c941cd1 100644 --- a/libdimension/plane.c +++ b/libdimension/plane.c @@ -18,14 +18,15 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Planes. + */ + #include "dimension.h" #include <math.h> #include <stdlib.h> -/* - * Plane - */ - /* Plane object callbacks */ static bool dmnsn_plane_intersection_fn(const dmnsn_object *plane, diff --git a/libdimension/platform.c b/libdimension/platform.c index 0317bd5..9ae579a 100644 --- a/libdimension/platform.c +++ b/libdimension/platform.c @@ -18,6 +18,11 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Platform abstractions. + */ + #include "dimension-impl.h" #if HAVE_UNISTD_H #include <unistd.h> @@ -40,7 +45,10 @@ dmnsn_backtrace(FILE *file) void *buffer[size]; int nptrs = backtrace(buffer, size); - backtrace_symbols_fd(buffer, nptrs, fileno(file)); + int fd = fileno(file); + if (fd != -1) { + backtrace_symbols_fd(buffer, nptrs, fd); + } #endif } diff --git a/libdimension/platform.h b/libdimension/platform.h index a5d4dc6..a339ced 100644 --- a/libdimension/platform.h +++ b/libdimension/platform.h @@ -18,8 +18,13 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -#ifndef DIMENSION_IMPL_UTILITIES_H -#define DIMENSION_IMPL_UTILITIES_H +/** + * @file + * Platform abstractions. + */ + +#ifndef DIMENSION_IMPL_PLATFORM_H +#define DIMENSION_IMPL_PLATFORM_H #include <stdbool.h> #include <stddef.h> @@ -37,4 +42,4 @@ bool dmnsn_is_little_endian(void); /* Return the number of CPUs available to dimension */ size_t dmnsn_ncpus(void); -#endif /* DIMENSION_IMPL_UTILITIES_H */ +#endif /* DIMENSION_IMPL_PLATFORM_H */ diff --git a/libdimension/png-stubs.c b/libdimension/png-stubs.c index db4a19d..04fe608 100644 --- a/libdimension/png-stubs.c +++ b/libdimension/png-stubs.c @@ -18,11 +18,14 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Stubs for PNG functions when compiled with --disable-png. + */ + #include "dimension.h" #include <errno.h> -/* Stubs for PNG functions when compiled with --disable-png */ - int dmnsn_png_optimize_canvas(dmnsn_canvas *canvas) { diff --git a/libdimension/png.c b/libdimension/png.c index ec2b980..63cb71e 100644 --- a/libdimension/png.c +++ b/libdimension/png.c @@ -18,6 +18,11 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * PNG import/export. + */ + #include "dimension-impl.h" #include <pthread.h> #include <png.h> @@ -26,8 +31,8 @@ #include <stdlib.h> #include <stdint.h> -/* PNG optimizer callback */ -static void dmnsn_png_optimizer_fn(dmnsn_canvas *canvas, +/** PNG optimizer callback. */ +static void dmnsn_png_optimizer_fn(const dmnsn_canvas *canvas, dmnsn_canvas_optimizer optimizer, size_t x, size_t y); @@ -46,7 +51,7 @@ dmnsn_png_optimize_canvas(dmnsn_canvas *canvas) optimizer.optimizer_fn = &dmnsn_png_optimizer_fn; optimizer.free_fn = &dmnsn_free; - optimizer.ptr = dmnsn_malloc(4*canvas->x*canvas->y*sizeof(uint16_t)); + optimizer.ptr = dmnsn_malloc(4*canvas->width*canvas->height*sizeof(uint16_t)); dmnsn_optimize_canvas(canvas, optimizer); return 0; @@ -54,12 +59,12 @@ dmnsn_png_optimize_canvas(dmnsn_canvas *canvas) /* PNG optimizer callback */ static void -dmnsn_png_optimizer_fn(dmnsn_canvas *canvas, dmnsn_canvas_optimizer optimizer, - size_t x, size_t y) +dmnsn_png_optimizer_fn(const dmnsn_canvas *canvas, + dmnsn_canvas_optimizer optimizer, size_t x, size_t y) { dmnsn_color color; dmnsn_sRGB sRGB; - uint16_t *pixel = (uint16_t *)optimizer.ptr + 4*(y*canvas->x + x); + uint16_t *pixel = (uint16_t *)optimizer.ptr + 4*(y*canvas->width + x); color = dmnsn_get_pixel(canvas, x, y); sRGB = dmnsn_sRGB_from_color(color); @@ -100,22 +105,23 @@ dmnsn_png_optimizer_fn(dmnsn_canvas *canvas, dmnsn_canvas_optimizer optimizer, } } -/* Payload to store function arguments for thread callbacks */ - +/** Payload type for PNG write thread callback. */ typedef struct { dmnsn_progress *progress; const dmnsn_canvas *canvas; FILE *file; } dmnsn_png_write_payload; +/** Payload type for PNG read thread callback. */ typedef struct { dmnsn_progress *progress; dmnsn_canvas **canvas; FILE *file; } dmnsn_png_read_payload; -/* Thread callbacks */ +/** PNG write thread callback. */ static int dmnsn_png_write_canvas_thread(void *ptr); +/** PNG read thread callback. */ static int dmnsn_png_read_canvas_thread(void *ptr); /* Write a canvas to a png file, using libpng. Return 0 on success, nonzero on @@ -140,7 +146,7 @@ dmnsn_png_write_canvas_async(const dmnsn_canvas *canvas, FILE *file) payload->file = file; /* Create the worker thread */ - dmnsn_new_thread(progress, NULL, &dmnsn_png_write_canvas_thread, payload); + dmnsn_new_thread(progress, &dmnsn_png_write_canvas_thread, payload); return progress; } @@ -168,7 +174,7 @@ dmnsn_png_read_canvas_async(dmnsn_canvas **canvas, FILE *file) payload->file = file; /* Create the worker thread */ - dmnsn_new_thread(progress, NULL, &dmnsn_png_read_canvas_thread, payload); + dmnsn_new_thread(progress, &dmnsn_png_read_canvas_thread, payload); return progress; } @@ -190,8 +196,8 @@ dmnsn_png_write_canvas_thread(void *ptr) return -1; } - png_uint_32 width = payload->canvas->x; - png_uint_32 height = payload->canvas->y; + png_uint_32 width = payload->canvas->width; + png_uint_32 height = payload->canvas->height; dmnsn_new_progress_element(payload->progress, height); @@ -321,11 +327,11 @@ dmnsn_png_write_canvas_thread(void *ptr) return 0; } -/* Thread-specific pointer to the appropriate dmnsn_progress* for - dmnsn_png_read_row_callback */ +/** Thread-specific pointer to the appropriate dmnsn_progress* for + dmnsn_png_read_row_callback. */ static __thread dmnsn_progress *dmnsn_tl_png_read_progress; -/* Callback to increment the progress after a row has been read */ +/** Callback to increment the progress after a row has been read. */ static void dmnsn_png_read_row_callback(png_structp png_ptr, png_uint_32 row, int pass) { diff --git a/libdimension/point_light.c b/libdimension/point_light.c index f12df62..ba15f57 100644 --- a/libdimension/point_light.c +++ b/libdimension/point_light.c @@ -18,13 +18,15 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Point lights. + */ + #include "dimension.h" #include <stdlib.h> -/* - * Point light source - */ - +/** Point light callback. */ static dmnsn_color dmnsn_point_light_fn(const dmnsn_light *light, dmnsn_vector v) { diff --git a/libdimension/polynomial.c b/libdimension/polynomial.c index 20c3423..0ca31ab 100644 --- a/libdimension/polynomial.c +++ b/libdimension/polynomial.c @@ -18,10 +18,15 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Polynomials. + */ + #include "dimension.h" #include <math.h> -/* Get the real degree of a polynomial, ignoring leading zeros */ +/** Get the real degree of a polynomial, ignoring leading zeros. */ static inline size_t dmnsn_real_degree(const double poly[], size_t degree) { @@ -34,7 +39,7 @@ dmnsn_real_degree(const double poly[], size_t degree) return 0; } -/* Divide each coefficient by the leading coefficient */ +/** Divide each coefficient by the leading coefficient. */ static inline void dmnsn_normalize_polynomial(double poly[], size_t degree) { @@ -44,7 +49,7 @@ dmnsn_normalize_polynomial(double poly[], size_t degree) poly[degree] = 1.0; } -/* Eliminate trivial zero roots from poly[] */ +/** Eliminate trivial zero roots from \p poly[]. */ static inline void dmnsn_eliminate_zero_roots(double poly[], size_t *degree) { @@ -60,7 +65,7 @@ dmnsn_eliminate_zero_roots(double poly[], size_t *degree) *degree -= i; } -/* Returns the number of sign changes between coefficients of `poly' */ +/** Returns the number of sign changes between coefficients of \p poly[]. */ static inline size_t dmnsn_descartes_rule(const double poly[], size_t degree) { @@ -85,7 +90,10 @@ dmnsn_descartes_rule(const double poly[], size_t degree) return changes; } +/** How many levels of Pascal's triangle to precompute. */ #define DMNSN_NBINOM 11 + +/** Pre-computed values of Pascal's triangle. */ static const double dmnsn_pascals_triangle[DMNSN_NBINOM][DMNSN_NBINOM] = { { 1.0 }, { 1.0, 1.0 }, @@ -100,7 +108,7 @@ static const double dmnsn_pascals_triangle[DMNSN_NBINOM][DMNSN_NBINOM] = { { 1.0, 10.0, 45.0, 120.0, 210.0, 252.0, 210.0, 120.0, 45.0, 10.0, 1.0 } }; -/* Get the (n k) binomial coefficient */ +/** Compute the (n k) binomial coefficient. */ static inline double dmnsn_binom(size_t n, size_t k) { @@ -117,7 +125,7 @@ dmnsn_binom(size_t n, size_t k) return ret; } -/* Find all ranges that contain a single root, with Uspensky's algorithm */ +/** Find ranges that contain a single root, with Uspensky's algorithm. */ static size_t dmnsn_uspensky_bounds(const double poly[], size_t degree, double bounds[][2], size_t max_roots) @@ -201,7 +209,7 @@ dmnsn_uspensky_bounds(const double poly[], size_t degree, double bounds[][2], } } -/* Calculate a finite upper bound for the roots of poly[] */ +/** Calculate a finite upper bound for the roots of \p poly[]. */ static inline double dmnsn_root_bound(double poly[], size_t degree) { @@ -214,7 +222,7 @@ dmnsn_root_bound(double poly[], size_t degree) return bound; } -/* Improve a root with Newton's method */ +/** Improve a root with Newton's method. */ static inline double dmnsn_improve_root(const double poly[], size_t degree, double x) { @@ -234,8 +242,8 @@ dmnsn_improve_root(const double poly[], size_t degree, double x) return x; } -/* Use the false position method to find a root in a range that contains exactly - one root */ +/** Use the false position method to find a root in a range that contains + exactly one root. */ static inline double dmnsn_bisect_root(const double poly[], size_t degree, double min, double max) { @@ -293,7 +301,7 @@ dmnsn_bisect_root(const double poly[], size_t degree, double min, double max) return mid; } -/* Use synthetic division to eliminate the root `r' from poly[] */ +/** Use synthetic division to eliminate the root \p r from \p poly[]. */ static inline void dmnsn_eliminate_root(double poly[], size_t *degree, double r) { @@ -307,8 +315,7 @@ dmnsn_eliminate_root(double poly[], size_t *degree, double r) --*degree; } -/* Basic solving methods -- assuming normalized polynomial */ - +/** Solve a normalized linear polynomial algebraically. */ static inline size_t dmnsn_solve_linear(const double poly[2], double x[1]) { @@ -316,6 +323,7 @@ dmnsn_solve_linear(const double poly[2], double x[1]) return (x[0] >= dmnsn_epsilon) ? 1 : 0; } +/** Solve a normalized quadratic polynomial algebraically. */ static inline size_t dmnsn_solve_quadratic(const double poly[3], double x[2]) { @@ -386,6 +394,7 @@ dmnsn_solve_polynomial(const double poly[], size_t degree, double x[]) return i; } +/* Print a polynomial */ void dmnsn_print_polynomial(FILE *file, const double poly[], size_t degree) { diff --git a/libdimension/progress-impl.h b/libdimension/progress-impl.h index ef5ad42..bfb74f6 100644 --- a/libdimension/progress-impl.h +++ b/libdimension/progress-impl.h @@ -18,17 +18,23 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Progress object implementation. + */ + #ifndef DIMENSION_IMPL_PROGRESS_H #define DIMENSION_IMPL_PROGRESS_H -/* Allocate a new progress object */ +/** Allocate a new progress object. */ dmnsn_progress *dmnsn_new_progress(void); -/* Create a new level of loop nesting */ +/** Create a new level of loop nesting. */ void dmnsn_new_progress_element(dmnsn_progress *progress, unsigned int total); -/* Increment the progress counter; should only be called from innermost loop */ +/** Increment the progress counter; should only be called from the innermost + loop. */ void dmnsn_increment_progress(dmnsn_progress *progress); -/* Instantly complete the progress */ +/** Instantly complete the progress. */ void dmnsn_done_progress(dmnsn_progress *progress); struct dmnsn_progress { diff --git a/libdimension/progress.c b/libdimension/progress.c index 51e7992..243b7e6 100644 --- a/libdimension/progress.c +++ b/libdimension/progress.c @@ -18,31 +18,39 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Progress objects. + */ + #include "dimension-impl.h" #include <pthread.h> -/* A single element in an array for dmnsn_progress. Progress of this item is - progress/total. */ +/** A single element in an array for dmnsn_progress. Progress of this item is + \p progress/\p total. */ typedef struct { unsigned int progress, total; } dmnsn_progress_element; -/* For thread synchronization */ - +/** Read-lock a progress object. */ static void dmnsn_progress_rdlock_impl(const dmnsn_progress *progress); +/** Write-lock a progress object. */ static void dmnsn_progress_wrlock_impl(dmnsn_progress *progress); +/** Unlock a progress object. */ static void dmnsn_progress_unlock_impl(void *arg); +/** Read-lock a progress object and ensure that it will unlock upon error. */ #define dmnsn_progress_rdlock(progress) \ dmnsn_progress_rdlock_impl(progress); \ pthread_cleanup_push(&dmnsn_progress_unlock_impl, (void *)progress); +/** Write-lock a progress object and ensure that it will unlock upon error. */ #define dmnsn_progress_wrlock(progress) \ dmnsn_progress_wrlock_impl(progress); \ pthread_cleanup_push(&dmnsn_progress_unlock_impl, (void *)progress); +/** Unlock a progress object. */ #define dmnsn_progress_unlock(progress) \ pthread_cleanup_pop(1); - /* Allocate a new dmnsn_progress* */ dmnsn_progress * dmnsn_new_progress() diff --git a/libdimension/prtree.c b/libdimension/prtree.c index 73c2484..88aba73 100644 --- a/libdimension/prtree.c +++ b/libdimension/prtree.c @@ -18,13 +18,21 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Priority R-tree implementation. These are the hottest code paths in + * libdimension. + */ + #include "dimension-impl.h" #include <stdlib.h> -/* Number of children per node */ +/** Number of children per PR-node. */ #define DMNSN_PRTREE_B 6 +/** Number of children per pseudo-PR-node (must be 2*ndimensions) */ #define DMNSN_PSEUDO_PRTREE_B 6 +/** Pseudo PR-tree node. */ struct dmnsn_prtree_node { dmnsn_bounding_box bounding_box; @@ -34,6 +42,7 @@ struct dmnsn_prtree_node { dmnsn_bounding_box bounding_boxes[DMNSN_PRTREE_B]; }; +/** Pseudo PR-tree leaf node. */ typedef struct dmnsn_pseudo_prleaf { void *children[DMNSN_PRTREE_B]; bool is_leaf; @@ -42,11 +51,13 @@ typedef struct dmnsn_pseudo_prleaf { typedef struct dmnsn_pseudo_prtree dmnsn_pseudo_prtree; +/** Pseudo PR-tree internal node. */ typedef struct dmnsn_pseudo_prnode { dmnsn_pseudo_prtree *left, *right; dmnsn_pseudo_prleaf children[DMNSN_PSEUDO_PRTREE_B]; } dmnsn_pseudo_prnode; +/** Pseudo PR-tree. */ struct dmnsn_pseudo_prtree { bool is_leaf; union { @@ -55,7 +66,7 @@ struct dmnsn_pseudo_prtree { } pseudo; }; -/* Expand node to contain the bounding box from min to max */ +/** Expand a node to contain the bounding box \p box. */ static void dmnsn_pseudo_prleaf_swallow(dmnsn_pseudo_prleaf *leaf, dmnsn_bounding_box box) { @@ -63,7 +74,7 @@ dmnsn_pseudo_prleaf_swallow(dmnsn_pseudo_prleaf *leaf, dmnsn_bounding_box box) leaf->bounding_box.max = dmnsn_vector_max(leaf->bounding_box.max, box.max); } -/* Comparator types */ +/** Comparator types. */ enum { DMNSN_XMIN, DMNSN_YMIN, @@ -73,6 +84,7 @@ enum { DMNSN_ZMAX }; +/** Get a coordinate of the bounding box of a node. */ static inline double dmnsn_priority_get(dmnsn_list_iterator *i, bool is_object, int comparator) { @@ -205,6 +217,7 @@ dmnsn_zmax_prnode_comp(dmnsn_list_iterator *l, dmnsn_list_iterator *r) return lval < rval; } +/** Leaf node comparators. */ static dmnsn_list_comparator_fn *dmnsn_object_comparators[6] = { [DMNSN_XMIN] = &dmnsn_xmin_object_comp, [DMNSN_YMIN] = &dmnsn_ymin_object_comp, @@ -214,6 +227,7 @@ static dmnsn_list_comparator_fn *dmnsn_object_comparators[6] = { [DMNSN_ZMAX] = &dmnsn_zmax_object_comp }; +/** Internal node comparators. */ static dmnsn_list_comparator_fn *dmnsn_prnode_comparators[6] = { [DMNSN_XMIN] = &dmnsn_xmin_prnode_comp, [DMNSN_YMIN] = &dmnsn_ymin_prnode_comp, @@ -223,6 +237,7 @@ static dmnsn_list_comparator_fn *dmnsn_prnode_comparators[6] = { [DMNSN_ZMAX] = &dmnsn_zmax_prnode_comp }; +/** Select an extreme node based on a comparator. */ static dmnsn_list_iterator * dmnsn_priority_search(dmnsn_list *leaves, bool are_objects, int comparator) { @@ -245,7 +260,7 @@ dmnsn_priority_search(dmnsn_list *leaves, bool are_objects, int comparator) return i; } -/* Build a pseudo PR-tree */ +/** Build a pseudo PR-tree. */ static dmnsn_pseudo_prtree * dmnsn_new_pseudo_prtree(dmnsn_list *leaves, bool are_objects, int comparator) { @@ -349,6 +364,7 @@ dmnsn_new_pseudo_prtree(dmnsn_list *leaves, bool are_objects, int comparator) return pseudo; } +/** Delete a pseudo-PR-tree. */ static void dmnsn_delete_pseudo_prtree(dmnsn_pseudo_prtree *pseudo) { @@ -361,7 +377,7 @@ dmnsn_delete_pseudo_prtree(dmnsn_pseudo_prtree *pseudo) } } -/* Construct a node from a pseudo leaf */ +/** Construct a node from a pseudo leaf. */ static dmnsn_prtree_node * dmnsn_new_prtree_node(const dmnsn_pseudo_prleaf *leaf) { @@ -386,6 +402,7 @@ dmnsn_new_prtree_node(const dmnsn_pseudo_prleaf *leaf) return node; } +/** Add a pseudo leaf to a list of leaves. */ static void dmnsn_pseudo_prtree_add_leaf(const dmnsn_pseudo_prleaf *leaf, dmnsn_list *leaves) @@ -397,6 +414,7 @@ dmnsn_pseudo_prtree_add_leaf(const dmnsn_pseudo_prleaf *leaf, } } +/** Recursively extract the leaves of a pseudo-PR-tree. */ static void dmnsn_pseudo_prtree_leaves_recursive(const dmnsn_pseudo_prtree *node, dmnsn_list *leaves) @@ -412,7 +430,7 @@ dmnsn_pseudo_prtree_leaves_recursive(const dmnsn_pseudo_prtree *node, } } -/* Extract the leaves of a pseudo PR-tree */ +/** Extract the leaves of a pseudo PR-tree. */ static dmnsn_list * dmnsn_pseudo_prtree_leaves(const dmnsn_pseudo_prtree *pseudo) { @@ -427,8 +445,7 @@ dmnsn_pseudo_prtree_leaves(const dmnsn_pseudo_prtree *pseudo) return leaves; } -/* Add objects from an array to a list, splitting unions etc. */ - +/** Add an object or its children, if any, to a list. */ static void dmnsn_list_add_object(dmnsn_list *objects, const dmnsn_object *object) { @@ -441,6 +458,7 @@ dmnsn_list_add_object(dmnsn_list *objects, const dmnsn_object *object) } } +/** Add objects from an array to a list, splitting unions etc. */ static dmnsn_list * dmnsn_object_list(const dmnsn_array *objects) { @@ -451,7 +469,7 @@ dmnsn_object_list(const dmnsn_array *objects) return list; } -/* Split the unbounded objects into a new list */ +/** Split unbounded objects into a new list. */ static dmnsn_list * dmnsn_split_unbounded(dmnsn_list *objects) { @@ -516,7 +534,7 @@ dmnsn_new_prtree(const dmnsn_array *objects) return prtree; } -/* Free a PR-tree node */ +/** Free a PR-tree node. */ static void dmnsn_delete_prtree_node(dmnsn_prtree_node *node) { @@ -541,12 +559,13 @@ dmnsn_delete_prtree(dmnsn_prtree *tree) } } +/** A line with pre-calculated reciprocals to avoid divisions. */ typedef struct dmnsn_optimized_line { dmnsn_line line; dmnsn_vector n_inv; } dmnsn_optimized_line; -/* Precompute inverses for faster ray-box intersection tests */ +/** Precompute inverses for faster ray-box intersection tests. */ static inline dmnsn_optimized_line dmnsn_optimize_line(dmnsn_line line) { @@ -557,7 +576,7 @@ dmnsn_optimize_line(dmnsn_line line) return optline; } -/* Ray-AABB intersection test, by the slab method */ +/** Ray-AABB intersection test, by the slab method. Highly optimized. */ static inline bool dmnsn_ray_box_intersection(dmnsn_optimized_line optline, dmnsn_bounding_box box, double t) @@ -592,6 +611,7 @@ dmnsn_ray_box_intersection(dmnsn_optimized_line optline, return tmax >= dmnsn_max(0.0, tmin) && tmin < t; } +/** Recursive component of PR-tree intersection traversal. */ static void dmnsn_prtree_intersection_recursive(const dmnsn_prtree_node *node, dmnsn_optimized_line ray, @@ -657,6 +677,7 @@ dmnsn_prtree_intersection(const dmnsn_prtree *tree, dmnsn_line ray, return !isinf(t); } +/** Recursive component of PR-tree containment traversal. */ static bool dmnsn_prtree_inside_recursive(const dmnsn_prtree_node *node, dmnsn_vector point) { diff --git a/libdimension/prtree.h b/libdimension/prtree.h index 7ab616d..a0f7651 100644 --- a/libdimension/prtree.h +++ b/libdimension/prtree.h @@ -18,11 +18,12 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -/* - * Priority R-Trees for storing bounding box hierarchies. PR-trees are a data - * structure introduced by Arge, de Berg, Haverkort, and Yi, which provides - * asymptotically optimal worst-case lookup, while remaining efficient with - * real-world data. Their structure is derived from B-trees. +/** + * @file. + * Priority R-trees. PR-trees are a data structure introduced by Arge, de Berg, + * Haverkort, and Yi, which provides asymptotically optimal worst-case lookup, + * while remaining efficient with real-world data. Their structure is derived + * from B-trees. */ #ifndef DIMENSION_IMPL_PRTREE_H @@ -30,19 +31,25 @@ #include <stdbool.h> +/** A PR-tree node. */ typedef struct dmnsn_prtree_node dmnsn_prtree_node; +/** A priority R-tree. */ typedef struct dmnsn_prtree { dmnsn_bounding_box bounding_box; dmnsn_prtree_node *root; dmnsn_array *unbounded; } dmnsn_prtree; +/** Create a PR-tree. */ dmnsn_prtree *dmnsn_new_prtree(const dmnsn_array *objects); +/** Delete a PR-tree. */ void dmnsn_delete_prtree(dmnsn_prtree *tree); +/** Find the closest ray-object intersection in the tree. */ bool dmnsn_prtree_intersection(const dmnsn_prtree *tree, dmnsn_line ray, dmnsn_intersection *intersection); +/** Determine whether a point is inside any object in the tree. */ bool dmnsn_prtree_inside(const dmnsn_prtree *tree, dmnsn_vector point); #endif /* DIMENSION_IMPL_PRTREE_H */ diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c index 2d93c86..ca489ef 100644 --- a/libdimension/raytrace.c +++ b/libdimension/raytrace.c @@ -18,15 +18,20 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * The ray-tracing algorithm. + */ + #include "dimension-impl.h" #include <stdlib.h> +#include <pthread.h> /* * Boilerplate for multithreading */ -/* Payload type for passing arguments to worker thread */ - +/** Payload type for passing arguments to worker threads. */ typedef struct { dmnsn_progress *progress; dmnsn_scene *scene; @@ -36,7 +41,7 @@ typedef struct { unsigned int index, threads; } dmnsn_raytrace_payload; -/* Thread callback */ +/** Background thread callback. */ static int dmnsn_raytrace_scene_thread(void *ptr); /* Raytrace a scene */ @@ -58,12 +63,12 @@ dmnsn_raytrace_scene_async(dmnsn_scene *scene) payload->progress = progress; payload->scene = scene; - dmnsn_new_thread(progress, NULL, &dmnsn_raytrace_scene_thread, payload); + dmnsn_new_thread(progress, &dmnsn_raytrace_scene_thread, payload); return progress; } -/* Thread callback */ +/** Worker thread callback. */ static void *dmnsn_raytrace_scene_multithread_thread(void *ptr); /* Thread callback -- set up the multithreaded engine */ @@ -95,7 +100,7 @@ dmnsn_raytrace_scene_thread(void *ptr) /* Set up the progress object */ dmnsn_new_progress_element(payload->progress, - payload->scene->canvas->y); + payload->scene->canvas->height); /* Create the payloads */ for (int i = 0; i < nthreads; ++i) { @@ -136,7 +141,7 @@ dmnsn_raytrace_scene_thread(void *ptr) return 0; } -/* Actual raytracing implementation */ +/** Actual raytracing implementation. */ static void dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene, dmnsn_prtree *prtree, @@ -156,6 +161,7 @@ dmnsn_raytrace_scene_multithread_thread(void *ptr) * Raytracing algorithm */ +/** The current state of the ray-tracing engine. */ typedef struct dmnsn_raytrace_state { const struct dmnsn_raytrace_state *parent; @@ -175,7 +181,7 @@ typedef struct dmnsn_raytrace_state { double ior; } dmnsn_raytrace_state; -/* Main helper for dmnsn_raytrace_scene_impl - shoot a ray */ +/** Main helper for dmnsn_raytrace_scene_impl - shoot a ray. */ static dmnsn_color dmnsn_raytrace_shoot(dmnsn_raytrace_state *state, dmnsn_line ray); @@ -192,21 +198,18 @@ dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene, .ior = 1.0 }; - size_t width = scene->canvas->x; - size_t height = scene->canvas->y; - /* Iterate through each pixel */ - for (size_t y = index; y < height; y += threads) { - for (size_t x = 0; x < width; ++x) { + for (size_t y = index; y < scene->canvas->height; y += threads) { + for (size_t x = 0; x < scene->canvas->width; ++x) { /* Set the pixel to the background color */ dmnsn_color color = scene->background; if (scene->quality) { /* Get the ray corresponding to the (x,y)'th pixel */ - dmnsn_line ray = (*scene->camera->ray_fn)( + dmnsn_line ray = dmnsn_camera_ray( scene->camera, - ((double)x)/(scene->canvas->x - 1), - ((double)y)/(scene->canvas->y - 1) + ((double)x)/(scene->canvas->width - 1), + ((double)y)/(scene->canvas->height - 1) ); /* Shoot a ray */ @@ -221,20 +224,24 @@ dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene, } } +/** Get the intersection texture. */ #define ITEXTURE(state) (state->intersection->texture) +/** Get the default texture. */ #define DTEXTURE(state) (state->scene->default_texture) +/** Can a texture element be accessed? */ #define CAN_ACCESS(texture, telem) \ ((texture) && (texture)->telem) +/** Can a texture element callback be called? */ #define CAN_CALL(texture, telem, fn) \ (CAN_ACCESS(texture, telem) && (texture)->telem->fn) -/* Determine whether a callback may be called */ +/** Determine whether a callback may be called. */ #define TEXTURE_HAS_CALLBACK(state, telem, fn) \ (CAN_CALL(ITEXTURE(state), telem, fn) \ || CAN_CALL(DTEXTURE(state), telem, fn)) -/* Call the appropriate overloaded texture callback */ +/** Call the appropriate overloaded texture callback. */ #define TEXTURE_CALLBACK(state, telem, fn, def, ...) \ (CAN_CALL(ITEXTURE(state), telem, fn) \ ? (*ITEXTURE(state)->telem->fn)(ITEXTURE(state)->telem, __VA_ARGS__) \ @@ -242,7 +249,7 @@ dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene, ? (*DTEXTURE(state)->telem->fn)(DTEXTURE(state)->telem, __VA_ARGS__) \ : def)); -/* Get a property from a texture element */ +/** Get a property from a texture element. */ #define TEXTURE_PROPERTY(state, telem, prop, def) \ (CAN_ACCESS(ITEXTURE(state), telem) \ ? ITEXTURE(state)->telem->prop \ @@ -250,11 +257,13 @@ dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene, ? DTEXTURE(state)->telem->prop \ : def)) +/** Get the current index of refraction. */ #define IOR(state) \ ((state)->intersection->interior \ ? (state)->intersection->interior->ior \ : 1.0) +/** Calculate the base pigment at the intersection. */ static void dmnsn_raytrace_pigment(dmnsn_raytrace_state *state) { @@ -267,7 +276,7 @@ dmnsn_raytrace_pigment(dmnsn_raytrace_state *state) state->diffuse = state->pigment; } -/* Get the color of a light ray at an intersection point */ +/** Get the color of a light ray at an intersection point. */ static dmnsn_color dmnsn_raytrace_light_ray(const dmnsn_raytrace_state *state, const dmnsn_light *light) @@ -315,6 +324,7 @@ dmnsn_raytrace_light_ray(const dmnsn_raytrace_state *state, return color; } +/** Handle light, shadow, and shading. */ static void dmnsn_raytrace_lighting(dmnsn_raytrace_state *state) { @@ -357,6 +367,7 @@ dmnsn_raytrace_lighting(dmnsn_raytrace_state *state) } } +/** Trace a reflected ray. */ static dmnsn_color dmnsn_raytrace_reflection(const dmnsn_raytrace_state *state) { @@ -379,7 +390,7 @@ dmnsn_raytrace_reflection(const dmnsn_raytrace_state *state) return reflected; } -/* Handle translucency - must be called last to work correctly */ +/** Handle translucency - must be called last to work correctly. */ static void dmnsn_raytrace_translucency(dmnsn_raytrace_state *state) { @@ -435,7 +446,7 @@ dmnsn_raytrace_translucency(dmnsn_raytrace_state *state) } } -/* Shoot a ray, and calculate the color, using `color' as the background */ +/* Shoot a ray, and calculate the color */ static dmnsn_color dmnsn_raytrace_shoot(dmnsn_raytrace_state *state, dmnsn_line ray) { diff --git a/libdimension/reflective.c b/libdimension/reflective.c index 6800ac7..cc89534 100644 --- a/libdimension/reflective.c +++ b/libdimension/reflective.c @@ -18,19 +18,22 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Reflective finish. + */ + #include "dimension.h" #include <math.h> #include <stdlib.h> -/* - * Reflective finish - */ - +/** Reflective finish payload. */ typedef struct dmnsn_reflection_params { dmnsn_color min, max; double falloff; } dmnsn_reflection_params; +/** Reflective finish callback. */ static dmnsn_color dmnsn_reflective_finish_fn(const dmnsn_finish *finish, dmnsn_color reflect, dmnsn_color color, diff --git a/libdimension/scene.c b/libdimension/scene.c index f56236f..fc5bb92 100644 --- a/libdimension/scene.c +++ b/libdimension/scene.c @@ -18,6 +18,11 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Scenes. + */ + #include "dimension-impl.h" #include <stdlib.h> diff --git a/libdimension/solid_pigment.c b/libdimension/solid_pigment.c index 2b878c7..14bdffe 100644 --- a/libdimension/solid_pigment.c +++ b/libdimension/solid_pigment.c @@ -18,12 +18,21 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Solid color pigments. + */ + #include "dimension.h" #include <stdlib.h> -/* Solid color pigment callback */ -static dmnsn_color dmnsn_solid_pigment_fn(const dmnsn_pigment *pigment, - dmnsn_vector v); +/** Solid color pigment callback. */ +static dmnsn_color +dmnsn_solid_pigment_fn(const dmnsn_pigment *pigment, dmnsn_vector v) +{ + dmnsn_color *color = pigment->ptr; + return *color; +} /* Create a solid color */ dmnsn_pigment * @@ -41,11 +50,3 @@ dmnsn_new_solid_pigment(dmnsn_color color) return pigment; } - -/* Solid color callback */ -static dmnsn_color -dmnsn_solid_pigment_fn(const dmnsn_pigment *pigment, dmnsn_vector v) -{ - dmnsn_color *color = pigment->ptr; - return *color; -} diff --git a/libdimension/sphere.c b/libdimension/sphere.c index 7ff2292..53ceef9 100644 --- a/libdimension/sphere.c +++ b/libdimension/sphere.c @@ -18,34 +18,14 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -#include "dimension.h" -#include <math.h> /* For sqrt */ - -/* - * Sphere +/** + * @file + * Spheres. */ -/* Sphere object callbacks */ - -static bool dmnsn_sphere_intersection_fn(const dmnsn_object *sphere, - dmnsn_line line, - dmnsn_intersection *intersection); -static bool dmnsn_sphere_inside_fn(const dmnsn_object *sphere, - dmnsn_vector point); - -/* Allocate a new sphere */ -dmnsn_object * -dmnsn_new_sphere() -{ - dmnsn_object *sphere = dmnsn_new_object(); - sphere->intersection_fn = &dmnsn_sphere_intersection_fn; - sphere->inside_fn = &dmnsn_sphere_inside_fn; - sphere->bounding_box.min = dmnsn_new_vector(-1.0, -1.0, -1.0); - sphere->bounding_box.max = dmnsn_new_vector(1.0, 1.0, 1.0); - return sphere; -} +#include "dimension.h" -/* Returns the closest intersection of `line' with `sphere' */ +/** Sphere intersection callback. */ static bool dmnsn_sphere_intersection_fn(const dmnsn_object *sphere, dmnsn_line l, dmnsn_intersection *intersection) @@ -73,9 +53,21 @@ dmnsn_sphere_intersection_fn(const dmnsn_object *sphere, dmnsn_line l, } } -/* Return whether a point is inside a sphere (x**2 + y**2 + z**2 < 1.0) */ +/** Sphere inside callback. */ static bool dmnsn_sphere_inside_fn(const dmnsn_object *sphere, dmnsn_vector point) { return point.x*point.x + point.y*point.y + point.z*point.z < 1.0; } + +/* Allocate a new sphere */ +dmnsn_object * +dmnsn_new_sphere() +{ + dmnsn_object *sphere = dmnsn_new_object(); + sphere->intersection_fn = &dmnsn_sphere_intersection_fn; + sphere->inside_fn = &dmnsn_sphere_inside_fn; + sphere->bounding_box.min = dmnsn_new_vector(-1.0, -1.0, -1.0); + sphere->bounding_box.max = dmnsn_new_vector(1.0, 1.0, 1.0); + return sphere; +} diff --git a/libdimension/texture.c b/libdimension/texture.c index 00b8682..f69f748 100644 --- a/libdimension/texture.c +++ b/libdimension/texture.c @@ -18,6 +18,11 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Textures, pigments, and finishes. + */ + #include "dimension.h" #include <stdlib.h> diff --git a/libdimension/threads.c b/libdimension/threads.c index 2c00cc8..5e39fdc 100644 --- a/libdimension/threads.c +++ b/libdimension/threads.c @@ -18,15 +18,22 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Background threading. + */ + #include "dimension-impl.h" #include <pthread.h> +/** The payload to pass to the pthread callback. */ typedef struct dmnsn_thread_payload { dmnsn_thread_fn *thread_fn; void *arg; dmnsn_progress *progress; } dmnsn_thread_payload; +/** Clean up after a thread. */ static void dmnsn_thread_cleanup(void *arg) { @@ -37,6 +44,7 @@ dmnsn_thread_cleanup(void *arg) dmnsn_done_progress(progress); } +/** pthread callback -- call the real thread callback. */ static void * dmnsn_thread(void *arg) { @@ -51,15 +59,15 @@ dmnsn_thread(void *arg) } void -dmnsn_new_thread(dmnsn_progress *progress, const pthread_attr_t *attr, - dmnsn_thread_fn *thread_fn, void *arg) +dmnsn_new_thread(dmnsn_progress *progress, dmnsn_thread_fn *thread_fn, + void *arg) { dmnsn_thread_payload *payload = dmnsn_malloc(sizeof(dmnsn_thread_payload)); payload->thread_fn = thread_fn; payload->arg = arg; payload->progress = progress; - if (pthread_create(&progress->thread, attr, &dmnsn_thread, payload) != 0) { + if (pthread_create(&progress->thread, NULL, &dmnsn_thread, payload) != 0) { dmnsn_error(DMNSN_SEVERITY_HIGH, "Couldn't start thread."); } } diff --git a/libdimension/threads.h b/libdimension/threads.h index 00be0a9..7ae6288 100644 --- a/libdimension/threads.h +++ b/libdimension/threads.h @@ -18,15 +18,28 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Background threading interface. + */ + #ifndef DIMENSION_IMPL_THREADS_H #define DIMENSION_IMPL_THREADS_H -#include <pthread.h> - +/** + * Thread callback type. + * @param[in,out] ptr An arbitrary pointer. + * @return 0 on success, non-zero on failure. + */ typedef int dmnsn_thread_fn(void *ptr); -/* Creates a thread that cleans up after itself on errors */ -void dmnsn_new_thread(dmnsn_progress *progress, const pthread_attr_t *attr, - dmnsn_thread_fn *thread_fn, void *arg); +/** + * Create a thread that cleans up after itself on errors. + * @param[in,out] progress The progress object to associate with the thread. + * @param[in] thread_fn The thread callback. + * @param[in,out] arg The pointer to pass to the thread callback. + */ +void dmnsn_new_thread(dmnsn_progress *progress, dmnsn_thread_fn *thread_fn, + void *arg); #endif /* DIMENSION_IMPL_THREADS_H */ diff --git a/libdimension/timer.c b/libdimension/timer.c index eb15357..daf0c00 100644 --- a/libdimension/timer.c +++ b/libdimension/timer.c @@ -18,10 +18,16 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ +/** + * @file + * Performance counter. + */ + #include "dimension.h" #include <sys/times.h> #include <unistd.h> +/** Clock ticks per second. */ static long clk_tck = 0; dmnsn_timer * diff --git a/libdimension/torus.c b/libdimension/torus.c index 702404b..244f174 100644 --- a/libdimension/torus.c +++ b/libdimension/torus.c @@ -18,47 +18,19 @@ * <http://www.gnu.org/licenses/>. * *************************************************************************/ -#include "dimension.h" - -/* - * Torus - special case of a quartic +/** + * @file + * Torii. A special case of a quartic. */ -/* Torus object callbacks */ -static bool dmnsn_torus_intersection_fn(const dmnsn_object *torus, - dmnsn_line line, - dmnsn_intersection *intersection); -static bool dmnsn_torus_inside_fn(const dmnsn_object *torus, - dmnsn_vector point); +#include "dimension.h" -/* Payload type */ +/** Torus payload type. */ typedef struct dmnsn_torus_payload { double major, minor; } dmnsn_torus_payload; -/* Allocate a new torus */ -dmnsn_object * -dmnsn_new_torus(double major, double minor) -{ - dmnsn_object *torus = dmnsn_new_object(); - torus->intersection_fn = &dmnsn_torus_intersection_fn; - torus->inside_fn = &dmnsn_torus_inside_fn; - torus->bounding_box.min = dmnsn_new_vector(-(major + minor), - -minor, - -(major + minor)); - torus->bounding_box.max = dmnsn_new_vector(major + minor, - minor, - major + minor); - - dmnsn_torus_payload *payload = dmnsn_malloc(sizeof(dmnsn_torus_payload)); - payload->major = major; - payload->minor = minor; - torus->ptr = payload; - torus->free_fn = &dmnsn_free; - return torus; -} - -/* Bound the torus in a cylindrical shell */ +/** Bound the torus in a cylindrical shell. */ static inline bool dmnsn_torus_bound_intersection(const dmnsn_torus_payload *payload, dmnsn_line l) { @@ -103,7 +75,7 @@ dmnsn_torus_bound_intersection(const dmnsn_torus_payload *payload, dmnsn_line l) return true; } -/* Returns the closest intersection of `line' with `torus' */ +/** Torus intersection callback. */ static bool dmnsn_torus_intersection_fn(const dmnsn_object *torus, dmnsn_line l, dmnsn_intersection *intersection) @@ -159,7 +131,7 @@ dmnsn_torus_intersection_fn(const dmnsn_object *torus, dmnsn_line l, return true; } -/* Return whether a point is inside a torus */ +/** Torus inside callback. */ static bool dmnsn_torus_inside_fn(const dmnsn_object *torus, dmnsn_vector point) { @@ -167,3 +139,25 @@ dmnsn_torus_inside_fn(const dmnsn_object *torus, dmnsn_vector point) double dmajor = payload->major - sqrt(point.x*point.x + point.z*point.z); return dmajor*dmajor + point.y*point.y < payload->minor*payload->minor; } + +/* Allocate a new torus */ +dmnsn_object * +dmnsn_new_torus(double major, double minor) +{ + dmnsn_object *torus = dmnsn_new_object(); + torus->intersection_fn = &dmnsn_torus_intersection_fn; + torus->inside_fn = &dmnsn_torus_inside_fn; + torus->bounding_box.min = dmnsn_new_vector(-(major + minor), + -minor, + -(major + minor)); + torus->bounding_box.max = dmnsn_new_vector(major + minor, + minor, + major + minor); + + dmnsn_torus_payload *payload = dmnsn_malloc(sizeof(dmnsn_torus_payload)); + payload->major = major; + payload->minor = minor; + torus->ptr = payload; + torus->free_fn = &dmnsn_free; + return torus; +} diff --git a/tests/libdimension/render.c b/tests/libdimension/render.c index 1de9fba..440333c 100644 --- a/tests/libdimension/render.c +++ b/tests/libdimension/render.c @@ -45,7 +45,7 @@ dmnsn_new_test_scene(void) /* Set up the transformation matrix for the perspective camera */ dmnsn_matrix trans = dmnsn_scale_matrix( dmnsn_new_vector( - ((double)scene->canvas->x)/scene->canvas->y, 1.0, 1.0 + ((double)scene->canvas->width)/scene->canvas->height, 1.0, 1.0 ) ); trans = dmnsn_matrix_mul( @@ -63,7 +63,7 @@ dmnsn_new_test_scene(void) /* Create a perspective camera */ scene->camera = dmnsn_new_perspective_camera(); - dmnsn_set_perspective_camera_trans(scene->camera, trans); + scene->camera->trans = trans; /* Background color */ scene->background = dmnsn_color_from_sRGB((dmnsn_sRGB){ 0.0, 0.1, 0.2 }); @@ -106,11 +106,11 @@ dmnsn_new_test_scene(void) dmnsn_array *arrow_array = dmnsn_new_array(sizeof(dmnsn_object *)); - dmnsn_object *cylinder = dmnsn_new_cylinder(0.1, 0.1, false); + dmnsn_object *cylinder = dmnsn_new_cone(0.1, 0.1, false); cylinder->trans = dmnsn_scale_matrix(dmnsn_new_vector(1.0, 1.25, 1.0)); dmnsn_array_push(arrow_array, &cylinder); - dmnsn_object *cone = dmnsn_new_cylinder(0.1, 0.0, true); + dmnsn_object *cone = dmnsn_new_cone(0.1, 0.0, true); cone->trans = dmnsn_matrix_mul( dmnsn_translation_matrix(dmnsn_new_vector(0.0, 1.375, 0.0)), diff --git a/tests/libdimension/tests.c b/tests/libdimension/tests.c index 9d1d38c..e2e0d18 100644 --- a/tests/libdimension/tests.c +++ b/tests/libdimension/tests.c @@ -86,7 +86,7 @@ dmnsn_new_display(const dmnsn_canvas *canvas) swa.event_mask = StructureNotifyMask; display->win = XCreateWindow(display->dpy, RootWindow(display->dpy, display->vi->screen), - 0, 0, canvas->x, canvas->y, + 0, 0, canvas->width, canvas->height, 0, display->vi->depth, InputOutput, display->vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa); |