diff options
-rw-r--r-- | include/blender/blender.h | 2 | ||||
-rw-r--r-- | include/morpher/morphing.h | 58 | ||||
-rw-r--r-- | src/blender/blender.c | 5 | ||||
-rw-r--r-- | src/morpher/morphing.c | 44 | ||||
-rw-r--r-- | test/blender/blender.c | 8 |
5 files changed, 109 insertions, 8 deletions
diff --git a/include/blender/blender.h b/include/blender/blender.h index 8e89208..26ff802 100644 --- a/include/blender/blender.h +++ b/include/blender/blender.h | |||
@@ -8,7 +8,7 @@ | |||
8 | 8 | ||
9 | #include "common/time.h" | 9 | #include "common/time.h" |
10 | #include "blender/canvas.h" | 10 | #include "blender/canvas.h" |
11 | #include "morpher/morpher.h" | 11 | #include "morpher/morphing.h" |
12 | 12 | ||
13 | /** | 13 | /** |
14 | * Function: blender_blend_canvas | 14 | * Function: blender_blend_canvas |
diff --git a/include/morpher/morphing.h b/include/morpher/morphing.h new file mode 100644 index 0000000..028cd87 --- /dev/null +++ b/include/morpher/morphing.h | |||
@@ -0,0 +1,58 @@ | |||
1 | #ifndef UPEM_MORPHING_MORPHING | ||
2 | #define UPEM_MORPHING_MORPHING | ||
3 | |||
4 | /** | ||
5 | * File: morphing.h | ||
6 | * Coordinate mapping for morphing transforms. | ||
7 | */ | ||
8 | |||
9 | #include "common/geom.h" | ||
10 | #include "common/time.h" | ||
11 | #include "morpher/trianglemap.h" | ||
12 | |||
13 | /** | ||
14 | * Struct: Morphing | ||
15 | * Represents an abstract coordinate transform from a source to a destination coordinate matrix, | ||
16 | * constrained by a given set of points. | ||
17 | * | ||
18 | * Fields: | ||
19 | * dim - dimension in pixels | ||
20 | * *first - the first triangle in the linked list | ||
21 | * *center - the center triangle | ||
22 | */ | ||
23 | typedef struct { | ||
24 | CartesianVector dim; | ||
25 | TriangleMap *first, *center; | ||
26 | } Morphing; | ||
27 | |||
28 | /** | ||
29 | * Function: morphing_init | ||
30 | * Initialises a morphing. | ||
31 | * | ||
32 | * Parameters: | ||
33 | * width - coordinate matrix width in pixels | ||
34 | * height - coordinate matrix height in pixels | ||
35 | */ | ||
36 | Morphing *morphing_create(IntVector width, IntVector height); | ||
37 | |||
38 | /** | ||
39 | * Function: morphing_free | ||
40 | * Frees any resources allocated to a morphing. | ||
41 | * | ||
42 | * Parameters: | ||
43 | * *m - pointer to the morphing to destroy | ||
44 | */ | ||
45 | void morphing_destroy(Morphing *m); | ||
46 | |||
47 | /** | ||
48 | * Function: morphing_add_constraint | ||
49 | * Adds a constraint point to a morphing. | ||
50 | * | ||
51 | * Parameters: | ||
52 | * *m - pointer to the morphing to alter | ||
53 | * origin - constraint point coordinates on the origin matrix | ||
54 | * destination - constraint point coordinates on the target matrix | ||
55 | */ | ||
56 | void morphing_add_constraint(Morphing *m, CartesianVector origin, CartesianVector destination); | ||
57 | |||
58 | #endif | ||
diff --git a/src/blender/blender.c b/src/blender/blender.c index 99abedd..08cafa4 100644 --- a/src/blender/blender.c +++ b/src/blender/blender.c | |||
@@ -1,7 +1,6 @@ | |||
1 | #include "blender/blender.h" | 1 | #include "blender/blender.h" |
2 | #include <assert.h> | 2 | #include <assert.h> |
3 | #include <math.h> | 3 | #include <math.h> |
4 | #include "morpher/morpher.h" | ||
5 | 4 | ||
6 | static inline ColorComponent blend_components(ColorComponent origin, ColorComponent target, TimeVector frame) { | 5 | static inline ColorComponent blend_components(ColorComponent origin, ColorComponent target, TimeVector frame) { |
7 | // https://www.youtube.com/watch?v=LKnqECcg6Gw | 6 | // https://www.youtube.com/watch?v=LKnqECcg6Gw |
@@ -21,7 +20,7 @@ void blender_blend_canvas(Canvas *canvas, Canvas *source, Canvas *target, Morphi | |||
21 | CartesianMapping mapping; | 20 | CartesianMapping mapping; |
22 | Color pixel; | 21 | Color pixel; |
23 | 22 | ||
24 | dim = morpher_get_dim(morphing); | 23 | dim = morphing->dim; |
25 | 24 | ||
26 | assert(dim.x > 0 && dim.y > 0); | 25 | assert(dim.x > 0 && dim.y > 0); |
27 | assert(vector_equals(dim, canvas_get_dim(canvas))); | 26 | assert(vector_equals(dim, canvas_get_dim(canvas))); |
@@ -33,7 +32,7 @@ void blender_blend_canvas(Canvas *canvas, Canvas *source, Canvas *target, Morphi | |||
33 | point.x = flat_dim % dim.y; | 32 | point.x = flat_dim % dim.y; |
34 | point.y = flat_dim / dim.y; | 33 | point.y = flat_dim / dim.y; |
35 | 34 | ||
36 | mapping = morpher_get_point_mapping(morphing, point, frame); | 35 | mapping = (CartesianMapping) {point, point}; |
37 | pixel = blend_colors(canvas_get_pixel(source, mapping.origin), canvas_get_pixel(target, mapping.target), frame); | 36 | pixel = blend_colors(canvas_get_pixel(source, mapping.origin), canvas_get_pixel(target, mapping.target), frame); |
38 | canvas_set_pixel(canvas, point, pixel); | 37 | canvas_set_pixel(canvas, point, pixel); |
39 | } | 38 | } |
diff --git a/src/morpher/morphing.c b/src/morpher/morphing.c new file mode 100644 index 0000000..2ab22d0 --- /dev/null +++ b/src/morpher/morphing.c | |||
@@ -0,0 +1,44 @@ | |||
1 | #include "morpher/morphing.h" | ||
2 | #include "common/mem.h" | ||
3 | |||
4 | static inline TriangleMap *init_trianglemap(IntVector width, IntVector height) { | ||
5 | TriangleMap *bottom_left = trianglemap_create(m(0, 0), m(0, height), m(width, height)); | ||
6 | TriangleMap *top_right = trianglemap_create(m(0, 0), m(width, height), m(width, 0)); | ||
7 | trianglemap_set_neighbors(bottom_left, NULL, NULL, top_right, top_right); | ||
8 | trianglemap_set_neighbors(top_right, bottom_left, NULL, NULL, NULL); | ||
9 | return bottom_left; | ||
10 | } | ||
11 | |||
12 | static inline TriangleMap *find_triangle(TriangleMap *start, CartesianVector target) { | ||
13 | TriangleMap *t = trianglemap_to(start, target); | ||
14 | return t == start ? t : find_triangle(t, target); | ||
15 | } | ||
16 | |||
17 | static inline void update_center(Morphing *m) { | ||
18 | m->center = find_triangle(m->center, v(m->dim.x / 2, m->dim.y / 2)); | ||
19 | } | ||
20 | |||
21 | static inline void ensure_delaunay_neighborhood(TriangleMap *t) { | ||
22 | trianglemap_propagate_delaunay(t); | ||
23 | trianglemap_propagate_delaunay(t->next); | ||
24 | trianglemap_propagate_delaunay(t->next->next); | ||
25 | } | ||
26 | |||
27 | Morphing *morphing_create(IntVector width, IntVector height) { | ||
28 | Morphing *m = malloc_or_die(sizeof(Morphing)); | ||
29 | m->dim = (CartesianVector) {width, height}; | ||
30 | m->first = init_trianglemap(width, height); | ||
31 | m->center = m->first; | ||
32 | return m; | ||
33 | } | ||
34 | |||
35 | void morphing_destroy(Morphing *m) { | ||
36 | while (m->first != NULL) m->first = trianglemap_destroy(m->first); | ||
37 | } | ||
38 | |||
39 | void morphing_add_constraint(Morphing *m, CartesianVector origin, CartesianVector destination) { | ||
40 | TriangleMap *target = find_triangle(m->center, origin); | ||
41 | TriangleMap *split = trianglemap_split(target, (CartesianMapping) {origin, destination}); | ||
42 | ensure_delaunay_neighborhood(split); | ||
43 | update_center(m); | ||
44 | } | ||
diff --git a/test/blender/blender.c b/test/blender/blender.c index bf16dc6..f42322f 100644 --- a/test/blender/blender.c +++ b/test/blender/blender.c | |||
@@ -2,11 +2,11 @@ | |||
2 | #include <assert.h> | 2 | #include <assert.h> |
3 | 3 | ||
4 | static void test_canvas_blending() { | 4 | static void test_canvas_blending() { |
5 | Morphing morphing; | 5 | Morphing *morphing; |
6 | Canvas origin, target, result; | 6 | Canvas origin, target, result; |
7 | CartesianVector sample_point = {13, 17}; | 7 | CartesianVector sample_point = {13, 17}; |
8 | 8 | ||
9 | morpher_init(&morphing, 64, 64); | 9 | morphing = morphing_create(64, 64); |
10 | canvas_init(&origin, 64, 64); | 10 | canvas_init(&origin, 64, 64); |
11 | canvas_init(&target, 64, 64); | 11 | canvas_init(&target, 64, 64); |
12 | canvas_init(&result, 64, 64); | 12 | canvas_init(&result, 64, 64); |
@@ -14,13 +14,13 @@ static void test_canvas_blending() { | |||
14 | canvas_set_pixel(&origin, sample_point, (Color) {{0xFF, 0xED, 0x00, 0x00}}); | 14 | canvas_set_pixel(&origin, sample_point, (Color) {{0xFF, 0xED, 0x00, 0x00}}); |
15 | canvas_set_pixel(&target, sample_point, (Color) {{0x00, 0x47, 0xAB, 0x00}}); | 15 | canvas_set_pixel(&target, sample_point, (Color) {{0x00, 0x47, 0xAB, 0x00}}); |
16 | 16 | ||
17 | blender_blend_canvas(&result, &origin, &target, &morphing, 0.125); | 17 | blender_blend_canvas(&result, &origin, &target, morphing, 0.125); |
18 | assert(color_equals(canvas_get_pixel(&result, sample_point), (Color) {{0xEE, 0xDF, 0x3C, 0x00}})); | 18 | assert(color_equals(canvas_get_pixel(&result, sample_point), (Color) {{0xEE, 0xDF, 0x3C, 0x00}})); |
19 | 19 | ||
20 | canvas_free(&result); | 20 | canvas_free(&result); |
21 | canvas_free(&target); | 21 | canvas_free(&target); |
22 | canvas_free(&origin); | 22 | canvas_free(&origin); |
23 | morpher_free(&morphing); | 23 | morphing_destroy(morphing); |
24 | } | 24 | } |
25 | 25 | ||
26 | int main(int argc, char **argv) { | 26 | int main(int argc, char **argv) { |