diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/blender/blender.c | 39 | ||||
-rw-r--r-- | src/blender/canvas.c | 23 | ||||
-rw-r--r-- | src/blender/color.c | 8 | ||||
-rw-r--r-- | src/common/geom.c | 27 | ||||
-rw-r--r-- | src/morpher/trianglemap.c | 2 | ||||
-rw-r--r-- | src/painter/canvas.c | 33 | ||||
-rw-r--r-- | src/painter/color.c | 20 | ||||
-rw-r--r-- | src/painter/rasterizer.c | 86 |
8 files changed, 166 insertions, 72 deletions
diff --git a/src/blender/blender.c b/src/blender/blender.c deleted file mode 100644 index 08cafa4..0000000 --- a/src/blender/blender.c +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | #include "blender/blender.h" | ||
2 | #include <assert.h> | ||
3 | #include <math.h> | ||
4 | |||
5 | static inline ColorComponent blend_components(ColorComponent origin, ColorComponent target, TimeVector frame) { | ||
6 | // https://www.youtube.com/watch?v=LKnqECcg6Gw | ||
7 | return (ColorComponent) sqrt((TIME_UNIT - frame) * pow(origin, 2) + frame * pow(target, 2)); | ||
8 | } | ||
9 | |||
10 | static inline Color blend_colors(Color origin, Color target, TimeVector frame) { | ||
11 | return (Color) {{blend_components(origin.rgba.r, target.rgba.r, frame), | ||
12 | blend_components(origin.rgba.g, target.rgba.g, frame), | ||
13 | blend_components(origin.rgba.b, target.rgba.b, frame), | ||
14 | blend_components(origin.rgba.a, target.rgba.a, frame)}}; | ||
15 | } | ||
16 | |||
17 | void blender_blend_canvas(Canvas *canvas, Canvas *source, Canvas *target, Morphing *morphing, TimeVector frame) { | ||
18 | IntVector flat_dim; | ||
19 | CartesianVector dim, point; | ||
20 | CartesianMapping mapping; | ||
21 | Color pixel; | ||
22 | |||
23 | dim = morphing->dim; | ||
24 | |||
25 | assert(dim.x > 0 && dim.y > 0); | ||
26 | assert(vector_equals(dim, canvas_get_dim(canvas))); | ||
27 | assert(vector_equals(dim, canvas_get_dim(source))); | ||
28 | assert(vector_equals(dim, canvas_get_dim(target))); | ||
29 | assert(frame >= TIME_ORIGIN && frame <= TIME_UNIT); | ||
30 | |||
31 | for (flat_dim = (dim.x - 1) * (dim.y - 1); flat_dim >= 0; --flat_dim) { | ||
32 | point.x = flat_dim % dim.y; | ||
33 | point.y = flat_dim / dim.y; | ||
34 | |||
35 | mapping = (CartesianMapping) {point, point}; | ||
36 | pixel = blend_colors(canvas_get_pixel(source, mapping.origin), canvas_get_pixel(target, mapping.target), frame); | ||
37 | canvas_set_pixel(canvas, point, pixel); | ||
38 | } | ||
39 | } | ||
diff --git a/src/blender/canvas.c b/src/blender/canvas.c deleted file mode 100644 index b7cd9dc..0000000 --- a/src/blender/canvas.c +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | #include "blender/canvas.h" | ||
2 | |||
3 | void canvas_init(Canvas *canvas, IntVector width, IntVector height) { | ||
4 | canvas->mlv = MLV_create_image(width, height); | ||
5 | } | ||
6 | |||
7 | void canvas_free(Canvas *canvas) { | ||
8 | MLV_free_image(canvas->mlv); | ||
9 | } | ||
10 | |||
11 | void canvas_set_pixel(Canvas *canvas, CartesianVector position, Color color) { | ||
12 | MLV_set_pixel_on_image(position.x, position.y, color.mlv, canvas->mlv); | ||
13 | } | ||
14 | |||
15 | Color canvas_get_pixel(Canvas *canvas, CartesianVector position) { | ||
16 | int r, g, b, a; | ||
17 | MLV_get_pixel_on_image(canvas->mlv, position.x, position.y, &r, &g, &b, &a); | ||
18 | return (Color) {{r, g, b, a}}; | ||
19 | } | ||
20 | |||
21 | CartesianVector canvas_get_dim(Canvas *canvas) { | ||
22 | return (CartesianVector) {MLV_get_image_width(canvas->mlv), MLV_get_image_height(canvas->mlv)}; | ||
23 | } | ||
diff --git a/src/blender/color.c b/src/blender/color.c deleted file mode 100644 index f92fba9..0000000 --- a/src/blender/color.c +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | #include "blender/color.h" | ||
2 | |||
3 | bool color_equals(Color c1, Color c2) { | ||
4 | return c1.rgba.r == c2.rgba.r && | ||
5 | c1.rgba.g == c2.rgba.g && | ||
6 | c1.rgba.b == c2.rgba.b && | ||
7 | c1.rgba.a == c2.rgba.a; | ||
8 | } | ||
diff --git a/src/common/geom.c b/src/common/geom.c index 219270f..eb35727 100644 --- a/src/common/geom.c +++ b/src/common/geom.c | |||
@@ -1,6 +1,12 @@ | |||
1 | #include "common/geom.h" | 1 | #include "common/geom.h" |
2 | #include <math.h> | ||
3 | #include <common/geom.h> | ||
2 | #include "morpher/matrix.h" | 4 | #include "morpher/matrix.h" |
3 | 5 | ||
6 | static inline IntVector int_round(RealVector x) { | ||
7 | return (IntVector) round(x); | ||
8 | } | ||
9 | |||
4 | CartesianMapping m(int x, int y) { | 10 | CartesianMapping m(int x, int y) { |
5 | return (CartesianMapping) {{x, y}, | 11 | return (CartesianMapping) {{x, y}, |
6 | {x, y}}; | 12 | {x, y}}; |
@@ -10,6 +16,10 @@ CartesianVector v(int x, int y) { | |||
10 | return (CartesianVector) {x, y}; | 16 | return (CartesianVector) {x, y}; |
11 | } | 17 | } |
12 | 18 | ||
19 | BarycentricVector b(double a, double b) { | ||
20 | return (BarycentricVector) {a, b}; | ||
21 | } | ||
22 | |||
13 | bool mappings_equals(CartesianMapping m1, CartesianMapping m2) { | 23 | bool mappings_equals(CartesianMapping m1, CartesianMapping m2) { |
14 | return vector_equals(m1.origin, m2.origin) && vector_equals(m1.target, m2.target); | 24 | return vector_equals(m1.origin, m2.origin) && vector_equals(m1.target, m2.target); |
15 | } | 25 | } |
@@ -18,7 +28,22 @@ bool vector_equals(CartesianVector v1, CartesianVector v2) { | |||
18 | return v1.x == v2.x && v1.y == v2.y; | 28 | return v1.x == v2.x && v1.y == v2.y; |
19 | } | 29 | } |
20 | 30 | ||
21 | IntVector triangle_area(CartesianVector v1, CartesianVector v2, CartesianVector v3) { | 31 | bool barycentric_vector_equals(BarycentricVector b1, BarycentricVector b2) { |
32 | return b1.a == b2.a && b1.b == b2.b; | ||
33 | } | ||
34 | |||
35 | IntVector square_area(CartesianVector v1, CartesianVector v2, CartesianVector v3) { | ||
22 | return matrix_int_det2(v1.x - v3.x, v2.x - v3.x, | 36 | return matrix_int_det2(v1.x - v3.x, v2.x - v3.x, |
23 | v1.y - v3.y, v2.y - v3.y); | 37 | v1.y - v3.y, v2.y - v3.y); |
24 | } | 38 | } |
39 | |||
40 | BarycentricVector cartesian_to_barycentric(Triangle t, CartesianVector p) { | ||
41 | RealVector total_area = square_area(t.v[0], t.v[1], t.v[2]); | ||
42 | return (BarycentricVector) {square_area(t.v[1], t.v[2], p) / total_area, | ||
43 | square_area(t.v[2], t.v[0], p) / total_area}; | ||
44 | } | ||
45 | |||
46 | CartesianVector barycentric_to_cartesian(Triangle t, BarycentricVector p) { | ||
47 | return (CartesianVector) {int_round(p.a * (t.v[0].x - t.v[2].x) + p.b * (t.v[1].x - t.v[2].x) + t.v[2].x), | ||
48 | int_round(p.a * (t.v[0].y - t.v[2].y) + p.b * (t.v[1].y - t.v[2].y) + t.v[2].y)}; | ||
49 | } | ||
diff --git a/src/morpher/trianglemap.c b/src/morpher/trianglemap.c index e2f3eb9..ad526bc 100644 --- a/src/morpher/trianglemap.c +++ b/src/morpher/trianglemap.c | |||
@@ -30,7 +30,7 @@ TriangleMap *trianglemap_to(TriangleMap *t, CartesianVector v) { | |||
30 | int edge; | 30 | int edge; |
31 | 31 | ||
32 | for (edge = 0; edge < 3; ++edge) | 32 | for (edge = 0; edge < 3; ++edge) |
33 | if (triangle_area(t->vertices[edge].origin, t->vertices[(edge + 1) % 3].origin, v) > 0) | 33 | if (square_area(t->vertices[edge].origin, t->vertices[(edge + 1) % 3].origin, v) > 0) |
34 | return t->neighbors[edge]; | 34 | return t->neighbors[edge]; |
35 | 35 | ||
36 | return t; | 36 | return t; |
diff --git a/src/painter/canvas.c b/src/painter/canvas.c new file mode 100644 index 0000000..306dc9c --- /dev/null +++ b/src/painter/canvas.c | |||
@@ -0,0 +1,33 @@ | |||
1 | #include "painter/canvas.h" | ||
2 | #include "common/mem.h" | ||
3 | |||
4 | Canvas *canvas_create(IntVector width, IntVector height) { | ||
5 | Canvas *c = malloc_or_die(sizeof(Canvas)); | ||
6 | c->mlv = MLV_create_image(width, height); | ||
7 | return c; | ||
8 | } | ||
9 | |||
10 | Canvas *canvas_create_from_image(const char *fpath) { | ||
11 | Canvas *c = malloc_or_die(sizeof(Canvas)); | ||
12 | c->mlv = MLV_load_image(fpath); | ||
13 | return c; | ||
14 | } | ||
15 | |||
16 | void canvas_destroy(Canvas *c) { | ||
17 | MLV_free_image(c->mlv); | ||
18 | free(c); | ||
19 | } | ||
20 | |||
21 | void canvas_set_pixel(Canvas *c, CartesianVector pos, Color color) { | ||
22 | MLV_set_pixel_on_image(pos.x, pos.y, color.mlv, c->mlv); | ||
23 | } | ||
24 | |||
25 | Color canvas_get_pixel(Canvas *c, CartesianVector pos) { | ||
26 | int r, g, b, a; | ||
27 | MLV_get_pixel_on_image(c->mlv, pos.x, pos.y, &r, &g, &b, &a); | ||
28 | return (Color) {{a, b, g, r}}; | ||
29 | } | ||
30 | |||
31 | CartesianVector canvas_get_dim(Canvas *c) { | ||
32 | return (CartesianVector) {MLV_get_image_width(c->mlv), MLV_get_image_height(c->mlv)}; | ||
33 | } | ||
diff --git a/src/painter/color.c b/src/painter/color.c new file mode 100644 index 0000000..65c4f20 --- /dev/null +++ b/src/painter/color.c | |||
@@ -0,0 +1,20 @@ | |||
1 | #include "painter/color.h" | ||
2 | #include <math.h> | ||
3 | |||
4 | static inline ColorComponent blend_component(ColorComponent origin, ColorComponent target, TimeVector frame) { | ||
5 | return (ColorComponent) round(sqrt((TIME_UNIT - frame) * pow(origin, 2) + frame * pow(target, 2))); | ||
6 | } | ||
7 | |||
8 | bool color_equals(Color c1, Color c2) { | ||
9 | return c1.rgba.r == c2.rgba.r && | ||
10 | c1.rgba.g == c2.rgba.g && | ||
11 | c1.rgba.b == c2.rgba.b && | ||
12 | c1.rgba.a == c2.rgba.a; | ||
13 | } | ||
14 | |||
15 | Color color_blend(Color origin, Color target, TimeVector distance) { | ||
16 | return (Color) {{blend_component(origin.rgba.a, target.rgba.a, distance), | ||
17 | blend_component(origin.rgba.b, target.rgba.b, distance), | ||
18 | blend_component(origin.rgba.g, target.rgba.g, distance), | ||
19 | blend_component(origin.rgba.r, target.rgba.r, distance)}}; | ||
20 | } | ||
diff --git a/src/painter/rasterizer.c b/src/painter/rasterizer.c new file mode 100644 index 0000000..881920a --- /dev/null +++ b/src/painter/rasterizer.c | |||
@@ -0,0 +1,86 @@ | |||
1 | #include "painter/rasterizer.h" | ||
2 | #include <math.h> | ||
3 | #include <assert.h> | ||
4 | |||
5 | static inline IntVector i(double (*f)(double, double), RealVector a, RealVector b) { | ||
6 | return (IntVector) floor(f(a, b)); | ||
7 | } | ||
8 | |||
9 | static inline CartesianVector vertex_at_frame(CartesianMapping m, TimeVector t) { | ||
10 | return (CartesianVector) {(IntVector) round((TIME_UNIT - t) * m.origin.x + t * m.target.x), | ||
11 | (IntVector) round((TIME_UNIT - t) * m.origin.y + t * m.target.y)}; | ||
12 | } | ||
13 | |||
14 | static inline RealVector slope(CartesianVector a, CartesianVector b) { | ||
15 | return (((RealVector) b.x) - ((RealVector) a.x)) / (((RealVector) b.y) - ((RealVector) a.y)); | ||
16 | } | ||
17 | |||
18 | static inline int positive_y_vertex_comparator(const void *l, const void *r) { | ||
19 | return ((CartesianVector *) l)->y - ((CartesianVector *) r)->y; | ||
20 | } | ||
21 | |||
22 | static inline Color color_at(Canvas *c, Triangle ref, BarycentricVector b) { | ||
23 | CartesianVector v = barycentric_to_cartesian(ref, b); | ||
24 | return canvas_get_pixel(c, v); | ||
25 | } | ||
26 | |||
27 | static inline TriangleContext build_triangle_context(Triangle current, TriangleMap *map) { | ||
28 | TriangleContext c; | ||
29 | int cursor; | ||
30 | |||
31 | for (cursor = 0; cursor < 3; ++cursor) { | ||
32 | c.current.v[cursor] = current.v[cursor]; | ||
33 | c.source.v[cursor] = map->vertices[cursor].origin; | ||
34 | c.target.v[cursor] = map->vertices[cursor].target; | ||
35 | } | ||
36 | |||
37 | return c; | ||
38 | } | ||