summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2010-11-22 12:01:14 -0500
committerTavian Barnes <tavianator@gmail.com>2010-11-22 12:01:14 -0500
commitf77a53bf817920bfa94c2a6d83d5e7066b157134 (patch)
treef18c17148198a16a30606a61e52a465cbaca7285
parent8054e510b83702b931f3b81bb1e1385f9a7ecb80 (diff)
downloaddimension-f77a53bf817920bfa94c2a6d83d5e7066b157134.tar.xz
Generisise map implementation.
-rw-r--r--dimension/realize.c26
-rw-r--r--libdimension/Makefile.am2
-rw-r--r--libdimension/color_map.c74
-rw-r--r--libdimension/dimension.h1
-rw-r--r--libdimension/dimension/map.h76
-rw-r--r--libdimension/dimension/pigments.h34
-rw-r--r--libdimension/map.c126
-rw-r--r--tests/libdimension/render.c28
8 files changed, 247 insertions, 120 deletions
diff --git a/dimension/realize.c b/dimension/realize.c
index 2f74ce0..ddccf89 100644
--- a/dimension/realize.c
+++ b/dimension/realize.c
@@ -480,29 +480,29 @@ dmnsn_realize_pattern(dmnsn_astnode astnode)
return pattern;
}
-static dmnsn_color_map *
+static dmnsn_map *
dmnsn_realize_color_list(dmnsn_astnode astnode)
{
dmnsn_assert(astnode.type == DMNSN_AST_COLOR_LIST, "Expected a color list.");
- dmnsn_color_map *color_map = dmnsn_new_color_map();
+ dmnsn_map *color_map = dmnsn_new_color_map();
double n = 0.0, i = 1.0/(dmnsn_array_size(astnode.children) - 1);
DMNSN_ARRAY_FOREACH (dmnsn_astnode *, entry, astnode.children) {
dmnsn_color color = dmnsn_realize_color(*entry);
- dmnsn_add_color_map_entry(color_map, n, color);
+ dmnsn_add_map_entry(color_map, n, &color);
n += i;
}
return color_map;
}
-static dmnsn_color_map *
+static dmnsn_map *
dmnsn_realize_color_map(dmnsn_astnode astnode)
{
dmnsn_assert(astnode.type == DMNSN_AST_COLOR_MAP, "Expected a color_map.");
- dmnsn_color_map *color_map = dmnsn_new_color_map();
+ dmnsn_map *color_map = dmnsn_new_color_map();
DMNSN_ARRAY_FOREACH (dmnsn_astnode *, entry, astnode.children) {
dmnsn_assert(entry->type == DMNSN_AST_COLOR_MAP_ENTRY,
@@ -515,7 +515,7 @@ dmnsn_realize_color_map(dmnsn_astnode astnode)
double n = dmnsn_realize_float(n_node);
dmnsn_color color = dmnsn_realize_color(color_node);
- dmnsn_add_color_map_entry(color_map, n, color);
+ dmnsn_add_map_entry(color_map, n, &color);
}
return color_map;
@@ -528,7 +528,7 @@ dmnsn_realize_pattern_pigment(dmnsn_astnode type, dmnsn_astnode modifiers)
"Expected pigment modifiers");
dmnsn_pattern *pattern = dmnsn_realize_pattern(type);
- dmnsn_color_map *color_map = NULL;
+ dmnsn_map *color_map = NULL;
/* Set up the color_map */
DMNSN_ARRAY_FOREACH_REVERSE (dmnsn_astnode *, modifier, modifiers.children) {
@@ -558,18 +558,18 @@ dmnsn_realize_pattern_pigment(dmnsn_astnode type, dmnsn_astnode modifiers)
/* Default checker pattern is blue and green */
if (!color_map)
color_map = dmnsn_new_color_map();
- if (dmnsn_array_size(color_map) < 1)
- dmnsn_add_color_map_entry(color_map, 0.0, dmnsn_blue);
- if (dmnsn_array_size(color_map) < 2)
- dmnsn_add_color_map_entry(color_map, 1.0, dmnsn_green);
+ if (dmnsn_map_size(color_map) < 1)
+ dmnsn_add_map_entry(color_map, 0.0, &dmnsn_blue);
+ if (dmnsn_map_size(color_map) < 2)
+ dmnsn_add_map_entry(color_map, 1.0, &dmnsn_green);
break;
default:
/* Default map is grayscale */
if (!color_map) {
color_map = dmnsn_new_color_map();
- dmnsn_add_color_map_entry(color_map, 0.0, dmnsn_black);
- dmnsn_add_color_map_entry(color_map, 1.0, dmnsn_white);
+ dmnsn_add_map_entry(color_map, 0.0, &dmnsn_black);
+ dmnsn_add_map_entry(color_map, 1.0, &dmnsn_white);
}
break;
}
diff --git a/libdimension/Makefile.am b/libdimension/Makefile.am
index 86caa57..e56a22b 100644
--- a/libdimension/Makefile.am
+++ b/libdimension/Makefile.am
@@ -37,6 +37,7 @@ nobase_include_HEADERS = dimension.h \
dimension/lights.h \
dimension/list.h \
dimension/malloc.h \
+ dimension/map.h \
dimension/object.h \
dimension/objects.h \
dimension/pattern.h \
@@ -75,6 +76,7 @@ libdimension_la_SOURCES = $(nobase_include_HEADERS) \
light.c \
list.c \
malloc.c \
+ map.c \
object.c \
pattern.c \
perspective.c \
diff --git a/libdimension/color_map.c b/libdimension/color_map.c
index c794374..f7d800e 100644
--- a/libdimension/color_map.c
+++ b/libdimension/color_map.c
@@ -25,71 +25,16 @@
#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(void)
-{
- return dmnsn_new_array(sizeof(dmnsn_color_map_entry));
-}
-
-void
-dmnsn_delete_color_map(dmnsn_color_map *map)
-{
- dmnsn_delete_array(map);
-}
-
-void
-dmnsn_add_color_map_entry(dmnsn_color_map *map, double n, dmnsn_color c)
-{
- dmnsn_color_map_entry entry = { .n = n, .color = c };
-
- /* Sorted insertion */
- size_t i;
- dmnsn_color_map_entry *other = dmnsn_array_last(map);
- for (i = dmnsn_array_size(map); i-- > 0;) {
- if (other->n <= n)
- break;
- }
-
- dmnsn_array_insert(map, i + 1, &entry);
-}
-
-dmnsn_color
-dmnsn_color_map_value(const dmnsn_color_map *map, double n)
+dmnsn_map *
+dmnsn_new_color_map()
{
- dmnsn_color_map_entry *entry = dmnsn_array_first(map);
-
- double n1, n2 = 0.0;
- dmnsn_color c1, c2 = entry->color;
-
- if (n < n2) {
- return c2;
- }
-
- for (; entry <= (dmnsn_color_map_entry *)dmnsn_array_last(map); ++entry) {
- n1 = n2;
- c1 = c2;
-
- n2 = entry->n;
- c2 = entry->color;
-
- if (n < n2) {
- return dmnsn_color_gradient(c1, c2, (n - n1)/(n2 - n1));
- }
- }
-
- return c2;
+ return dmnsn_new_map(sizeof(dmnsn_color));
}
/** Payload for a color_map pigment. */
typedef struct dmnsn_color_map_payload {
dmnsn_pattern *pattern;
- dmnsn_color_map *map;
+ dmnsn_map *map;
} dmnsn_color_map_payload;
/** Free a color_map payload. */
@@ -97,7 +42,7 @@ static void
dmnsn_delete_color_map_payload(void *ptr)
{
dmnsn_color_map_payload *payload = ptr;
- dmnsn_delete_color_map(payload->map);
+ dmnsn_delete_map(payload->map);
dmnsn_delete_pattern(payload->pattern);
dmnsn_free(payload);
}
@@ -107,8 +52,11 @@ static dmnsn_color
dmnsn_color_map_pigment_fn(const dmnsn_pigment *pigment, dmnsn_vector v)
{
const dmnsn_color_map_payload *payload = pigment->ptr;
- return dmnsn_color_map_value(payload->map,
- dmnsn_pattern_value(payload->pattern, v));
+ double n;
+ dmnsn_color color1, color2;
+ dmnsn_evaluate_map(payload->map, dmnsn_pattern_value(payload->pattern, v),
+ &n, &color1, &color2);
+ return dmnsn_color_gradient(color1, color2, n);
}
/** color_map initialization callback. */
@@ -122,7 +70,7 @@ dmnsn_color_map_initialize_fn(dmnsn_pigment *pigment)
}
dmnsn_pigment *
-dmnsn_new_color_map_pigment(dmnsn_pattern *pattern, dmnsn_color_map *map)
+dmnsn_new_color_map_pigment(dmnsn_pattern *pattern, dmnsn_map *map)
{
dmnsn_pigment *pigment = dmnsn_new_pigment();
diff --git a/libdimension/dimension.h b/libdimension/dimension.h
index d4ce61e..fb8efb5 100644
--- a/libdimension/dimension.h
+++ b/libdimension/dimension.h
@@ -68,6 +68,7 @@ typedef void dmnsn_free_fn(void *ptr);
#include <dimension/png.h>
#include <dimension/pattern.h>
#include <dimension/patterns.h>
+#include <dimension/map.h>
#include <dimension/texture.h>
#include <dimension/pigments.h>
#include <dimension/finishes.h>
diff --git a/libdimension/dimension/map.h b/libdimension/dimension/map.h
new file mode 100644
index 0000000..1cd0f55
--- /dev/null
+++ b/libdimension/dimension/map.h
@@ -0,0 +1,76 @@
+/*************************************************************************
+ * Copyright (C) 2009-2010 Tavian Barnes <tavianator@gmail.com> *
+ * *
+ * This file is part of The Dimension Library. *
+ * *
+ * The Dimension Library is free software; you can redistribute it and/ *
+ * or modify it under the terms of the GNU Lesser General Public License *
+ * as published by the Free Software Foundation; either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * The Dimension Library is distributed in the hope that it will be *
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty *
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this program. If not, see *
+ * <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+
+/**
+ * @file
+ * Generic maps (backend for color_maps, pigment_maps, etc.).
+ */
+
+#ifndef DIMENSION_MAP_H
+#define DIMENSION_MAP_H
+
+/** A map. */
+typedef struct dmnsn_map {
+ dmnsn_free_fn *free_fn; /**< Destructor callback. */
+ size_t obj_size; /**< @internal The size of the mapped objects. */
+ dmnsn_array *array; /**< @internal The map entries. */
+} dmnsn_map;
+
+/**
+ * Create an empty map.
+ * @param[in] size The size of the objects to store in the map.
+ * @return A map with no entries.
+ */
+dmnsn_map *dmnsn_new_map(size_t size);
+
+/**
+ * Delete a map.
+ * @param[in,out] map The map to delete.
+ */
+void dmnsn_delete_map(dmnsn_map *map);
+
+/**
+ * Add an entry (a scalar-object 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] object The value of the entry.
+ */
+void dmnsn_add_map_entry(dmnsn_map *map, double n, const void *obj);
+
+/**
+ * Return the number of entries in a map.
+ * @param[in] map The map to measure.
+ * @return The size of \p map.
+ */
+size_t dmnsn_map_size(const dmnsn_map *map);
+
+/**
+ * Evaluate a map.
+ * @param[in] map The map to evaluate.
+ * @param[in] n The index to evaluate.
+ * @param[out] val The normalized distance of \p n from \p obj1.
+ * @param[out] obj1 The first object.
+ * @param[out] obj2 The second object.
+ */
+void dmnsn_evaluate_map(const dmnsn_map *map, double n,
+ double *val, void *obj1, void *obj2);
+
+#endif /* DIMENSION_MAP_H */
diff --git a/libdimension/dimension/pigments.h b/libdimension/dimension/pigments.h
index 68a9c66..687080f 100644
--- a/libdimension/dimension/pigments.h
+++ b/libdimension/dimension/pigments.h
@@ -41,37 +41,11 @@ dmnsn_pigment *dmnsn_new_solid_pigment(dmnsn_color color);
*/
dmnsn_pigment *dmnsn_new_canvas_pigment(dmnsn_canvas *canvas);
-/** Color map. */
-typedef dmnsn_array dmnsn_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.
+ * Construct a color map.
+ * @return An empty color map.
*/
-dmnsn_color dmnsn_color_map_value(const dmnsn_color_map *map, double n);
+dmnsn_map *dmnsn_new_color_map();
/**
* A color-mapped pigment.
@@ -80,6 +54,6 @@ dmnsn_color dmnsn_color_map_value(const dmnsn_color_map *map, double n);
* @return A pigment mapping the pattern to color values.
*/
dmnsn_pigment *dmnsn_new_color_map_pigment(dmnsn_pattern *pattern,
- dmnsn_color_map *map);
+ dmnsn_map *map);
#endif /* DIMENSION_PIGMENTS_H */
diff --git a/libdimension/map.c b/libdimension/map.c
new file mode 100644
index 0000000..3ea4b0c
--- /dev/null
+++ b/libdimension/map.c
@@ -0,0 +1,126 @@
+/*************************************************************************
+ * Copyright (C) 2010 Tavian Barnes <tavianator@gmail.com> *
+ * *
+ * This file is part of The Dimension Library. *
+ * *
+ * The Dimension Library is free software; you can redistribute it and/ *
+ * or modify it under the terms of the GNU Lesser General Public License *
+ * as published by the Free Software Foundation; either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * The Dimension Library is distributed in the hope that it will be *
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty *
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this program. If not, see *
+ * <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+/**
+ * @file
+ * Generic maps.
+ */
+
+#include "dimension.h"
+#include <alloca.h>
+
+/** An [index, object] pair. */
+typedef struct dmnsn_map_entry {
+ double n;
+ char object[];
+} dmnsn_map_entry;
+
+dmnsn_map *
+dmnsn_new_map(size_t size)
+{
+ dmnsn_map *map = dmnsn_malloc(sizeof(dmnsn_map));
+ map->free_fn = NULL;
+ map->obj_size = size;
+ map->array = dmnsn_new_array(sizeof(dmnsn_map_entry) + size);
+ return map;
+}
+
+void
+dmnsn_delete_map(dmnsn_map *map)
+{
+ if (map) {
+ if (map->free_fn) {
+ for (size_t i = 0; i < dmnsn_array_size(map->array); ++i) {
+ dmnsn_map_entry *entry = dmnsn_array_at(map->array, i);
+ (*map->free_fn)(entry->object);
+ }
+ }
+
+ dmnsn_delete_array(map->array);
+ dmnsn_free(map);
+ }
+}
+
+void
+dmnsn_add_map_entry(dmnsn_map *map, double n, const void *obj)
+{
+ dmnsn_map_entry *entry = alloca(sizeof(dmnsn_map_entry) + map->obj_size);
+ entry->n = n;
+ memcpy(entry->object, obj, map->obj_size);
+
+ /* Sorted insertion */
+ size_t i;
+ for (i = dmnsn_array_size(map->array); i-- > 0;) {
+ dmnsn_map_entry *other = dmnsn_array_at(map->array, i);
+ if (other->n <= n)
+ break;
+ }
+
+ dmnsn_array_insert(map->array, i + 1, entry);
+}
+
+size_t
+dmnsn_map_size(const dmnsn_map *map)
+{
+ return dmnsn_array_size(map->array);
+}
+
+void
+dmnsn_evaluate_map(const dmnsn_map *map, double n,
+ double *val, void *obj1, void *obj2)
+{
+ dmnsn_assert(dmnsn_array_size(map->array) > 0,
+ "Attempt to evaluate empty map.");
+
+ const dmnsn_map_entry *entry = dmnsn_array_first(map->array);
+
+ double n1, n2 = 0.0;
+ const void *o1, *o2 = entry->object;
+
+ if (n < n2) {
+ *val = 0.0;
+ memcpy(obj1, o2, map->obj_size);
+ memcpy(obj2, o2, map->obj_size);
+ return;
+ }
+
+ const dmnsn_map_entry *last = dmnsn_array_last(map->array);
+ ptrdiff_t skip = sizeof(dmnsn_map_entry) + map->obj_size;
+ for (; entry <= last;
+ entry = (const dmnsn_map_entry *)((const char *)entry + skip))
+ {
+ n1 = n2;
+ o1 = o2;
+
+ n2 = entry->n;
+ o2 = entry->object;
+
+ if (n < n2) {
+ *val = (n - n1)/(n2 - n1);
+ memcpy(obj1, o1, map->obj_size);
+ memcpy(obj2, o2, map->obj_size);
+ return;
+ }
+ }
+
+ *val = 1.0;
+ memcpy(obj1, o2, map->obj_size);
+ memcpy(obj2, o2, map->obj_size);
+}
diff --git a/tests/libdimension/render.c b/tests/libdimension/render.c
index 31518bf..5ba075d 100644
--- a/tests/libdimension/render.c
+++ b/tests/libdimension/render.c
@@ -71,11 +71,11 @@ dmnsn_new_test_scene(void)
/* Sky sphere */
scene->sky_sphere = dmnsn_new_sky_sphere();
dmnsn_pattern *sky_gradient = dmnsn_new_gradient_pattern(dmnsn_y);
- dmnsn_color_map *sky_gradient_color_map = dmnsn_new_color_map();
- dmnsn_add_color_map_entry(sky_gradient_color_map, 0.0, dmnsn_orange);
+ dmnsn_map *sky_gradient_color_map = dmnsn_new_color_map();
+ dmnsn_add_map_entry(sky_gradient_color_map, 0.0, &dmnsn_orange);
dmnsn_color background = dmnsn_color_from_sRGB((dmnsn_sRGB){ 0.0, 0.1, 0.2 });
background.filter = 0.1;
- dmnsn_add_color_map_entry(sky_gradient_color_map, 0.35, background);
+ dmnsn_add_map_entry(sky_gradient_color_map, 0.35, &background);
dmnsn_pigment *sky_pigment
= dmnsn_new_color_map_pigment(sky_gradient, sky_gradient_color_map);
dmnsn_array_push(scene->sky_sphere->pigments, &sky_pigment);
@@ -134,14 +134,14 @@ dmnsn_new_test_scene(void)
dmnsn_new_vector(dmnsn_radians(-45.0), 0.0, 0.0)
);
dmnsn_pattern *gradient = dmnsn_new_gradient_pattern(dmnsn_y);
- dmnsn_color_map *gradient_color_map = dmnsn_new_color_map();
- dmnsn_add_color_map_entry(gradient_color_map, 0.0, dmnsn_red);
- dmnsn_add_color_map_entry(gradient_color_map, 1.0/6.0, dmnsn_orange);
- dmnsn_add_color_map_entry(gradient_color_map, 2.0/6.0, dmnsn_yellow);
- dmnsn_add_color_map_entry(gradient_color_map, 3.0/6.0, dmnsn_green);
- dmnsn_add_color_map_entry(gradient_color_map, 4.0/6.0, dmnsn_blue);
- dmnsn_add_color_map_entry(gradient_color_map, 5.0/6.0, dmnsn_magenta);
- dmnsn_add_color_map_entry(gradient_color_map, 1.0, dmnsn_red);
+ dmnsn_map *gradient_color_map = dmnsn_new_color_map();
+ dmnsn_add_map_entry(gradient_color_map, 0.0, &dmnsn_red);
+ dmnsn_add_map_entry(gradient_color_map, 1.0/6.0, &dmnsn_orange);
+ dmnsn_add_map_entry(gradient_color_map, 2.0/6.0, &dmnsn_yellow);
+ dmnsn_add_map_entry(gradient_color_map, 3.0/6.0, &dmnsn_green);
+ dmnsn_add_map_entry(gradient_color_map, 4.0/6.0, &dmnsn_blue);
+ dmnsn_add_map_entry(gradient_color_map, 5.0/6.0, &dmnsn_magenta);
+ dmnsn_add_map_entry(gradient_color_map, 1.0, &dmnsn_red);
arrow->texture = dmnsn_new_texture();
arrow->texture->pigment
= dmnsn_new_color_map_pigment(gradient, gradient_color_map);
@@ -180,9 +180,9 @@ dmnsn_new_test_scene(void)
plane->trans = dmnsn_translation_matrix(dmnsn_new_vector(0.0, -2.0, 0.0));
plane->texture = dmnsn_new_texture();
dmnsn_pattern *checker = dmnsn_new_checker_pattern();
- dmnsn_color_map *checker_color_map = dmnsn_new_color_map();
- dmnsn_add_color_map_entry(checker_color_map, 0.0, dmnsn_black);
- dmnsn_add_color_map_entry(checker_color_map, 1.0, dmnsn_white);
+ dmnsn_map *checker_color_map = dmnsn_new_color_map();
+ dmnsn_add_map_entry(checker_color_map, 0.0, &dmnsn_black);
+ dmnsn_add_map_entry(checker_color_map, 1.0, &dmnsn_white);
plane->texture->pigment
= dmnsn_new_color_map_pigment(checker, checker_color_map);
plane->texture->pigment->quick_color