summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/blender/blender.c39
-rw-r--r--src/blender/canvas.c23
-rw-r--r--src/blender/color.c8
-rw-r--r--src/common/geom.c27
-rw-r--r--src/morpher/trianglemap.c2
-rw-r--r--src/painter/canvas.c27
-rw-r--r--src/painter/color.c20
-rw-r--r--src/painter/rasterizer.c86
8 files changed, 160 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
5static 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
10static 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
17void 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
3void canvas_init(Canvas *canvas, IntVector width, IntVector height) {
4 canvas->mlv = MLV_create_image(width, height);
5}
6
7void canvas_free(Canvas *canvas) {
8 MLV_free_image(canvas->mlv);
9}
10
11void 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
15Color 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
21CartesianVector 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
3bool 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
6static inline IntVector int_round(RealVector x) {
7 return (IntVector) round(x);
8}
9
4CartesianMapping m(int x, int y) { 10CartesianMapping 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
19BarycentricVector b(double a, double b) {
20 return (BarycentricVector) {a, b};
21}
22
13bool mappings_equals(CartesianMapping m1, CartesianMapping m2) { 23bool 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
21IntVector triangle_area(CartesianVector v1, CartesianVector v2, CartesianVector v3) { 31bool barycentric_vector_equals(BarycentricVector b1, BarycentricVector b2) {
32 return b1.a == b2.a && b1.b == b2.b;
33}
34
35IntVector 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
40BarycentricVector 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
46CartesianVector 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..53deeb9
--- /dev/null
+++ b/src/painter/canvas.c
@@ -0,0 +1,27 @@
1#include "painter/canvas.h"
2#include "common/mem.h"
3
4Canvas *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
10void canvas_destroy(Canvas *c) {
11 MLV_free_image(c->mlv);
12 free(c);
13}
14
15void canvas_set_pixel(Canvas *c, CartesianVector pos, Color color) {
16 MLV_set_pixel_on_image(pos.x, pos.y, color.mlv, c->mlv);
17}
18
19Color canvas_get_pixel(Canvas *c, CartesianVector pos) {
20 int r, g, b, a;
21 MLV_get_pixel_on_image(c->mlv, pos.x, pos.y, &r, &g, &b, &a);
22 return (Color) {{a, b, g, r}};
23}
24
25CartesianVector canvas_get_dim(Canvas *c) {
26 return (CartesianVector) {MLV_get_image_width(c->mlv), MLV_get_image_height(c->mlv)};
27}
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
4static 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
8bool 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
15Color 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
5static inline IntVector i(double (*f)(double, double), RealVector a, RealVector b) {
6 return (IntVector) floor(f(a, b));
7}
8
9static 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
14static inline RealVector slope(CartesianVector a, CartesianVector b) {
15 return (((RealVector) b.x) - ((RealVector) a.x)) / (((RealVector) b.y) - ((RealVector) a.y));
16}
17
18static inline int positive_y_vertex_comparator(const void *l, const void *r) {
19 return ((CartesianVector *) l)->y - ((CartesianVector *) r)->y;
20}
21
22static 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
27static 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}
39
40static inline void draw_pixel(CartesianVector pos, TriangleContext *tctx, RasterizationContext *rctx) {
41 BarycentricVector b = cartesian_to_barycentric(tctx->current, pos);
42 Color c = color_blend(color_at(rctx->source, tctx->source, b), color_at(rctx->target, tctx->target, b), rctx->frame);
43 canvas_set_pixel(rctx->result, pos, c);