1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
#include "painter/rasterizer.h"
#include <math.h>
#include <assert.h>
static inline IntVector i(double (*f)(double, double), RealVector a, RealVector b) {
return (IntVector) floor(f(a, b));
}
static inline CartesianVector vertex_at_frame(CartesianMapping m, TimeVector t) {
return (CartesianVector) {(IntVector) round((TIME_UNIT - t) * m.origin.x + t * m.target.x),
(IntVector) round((TIME_UNIT - t) * m.origin.y + t * m.target.y)};
}
static inline RealVector slope(CartesianVector a, CartesianVector b) {
return (((RealVector) b.x) - ((RealVector) a.x)) / (((RealVector) b.y) - ((RealVector) a.y));
}
static inline int positive_y_vertex_comparator(const void *l, const void *r) {
return ((CartesianVector *) l)->y - ((CartesianVector *) r)->y;
}
static inline Color color_at(Canvas *c, Triangle ref, BarycentricVector b) {
CartesianVector v = barycentric_to_cartesian(ref, b);
return canvas_get_pixel(c, v);
}
static inline TriangleContext build_triangle_context(Triangle current, TriangleMap *map) {
TriangleContext c;
int cursor;
for (cursor = 0; cursor < 3; ++cursor) {
c.current.v[cursor] = current.v[cursor];
c.source.v[cursor] = map->vertices[cursor].origin;
c.target.v[cursor] = map->vertices[cursor].target;
}
return c;
}
static inline void draw_pixel(CartesianVector pos, TriangleContext *tctx, RasterizationContext *rctx) {
BarycentricVector b = cartesian_to_barycentric(tctx->current, pos);
Color c = color_blend(color_at(rctx->source, tctx->source, b), color_at(rctx->target, tctx->target, b), rctx->frame);
canvas_set_pixel(rctx->result, pos, c);
}
static inline void draw_flat_triangle(IntVector top, IntVector bottom,
RealVector dx1, RealVector dx2, RealVector *x1, RealVector *x2,
TriangleContext *tctx, RasterizationContext *rctx) {
IntVector y, l, r;
for (y = top; y <= bottom; ++y, *x1 += dx1, *x2 += dx2)
for (l = i(fmin, *x1, *x2), r = i(fmax, *x1, *x2); l <= r; ++l)
draw_pixel(v(l, y), tctx, rctx);
}
static inline void draw_triangle(TriangleMap *t, RasterizationContext *rctx) {
Triangle triangle = {{vertex_at_frame(t->vertices[0], rctx->frame),
vertex_at_frame(t->vertices[1], rctx->frame),
vertex_at_frame(t->vertices[2], rctx->frame)}};
TriangleContext tctx = build_triangle_context(triangle, t);
CartesianVector *v = triangle.v;
qsort(v, 3, sizeof(CartesianVector), positive_y_vertex_comparator);
{
RealVector dx1 = slope(v[0], v[1]), dx2 = slope(v[0], v[2]), dx3 = slope(v[1], v[2]);
RealVector x1 = v[0].x, x2 = v[0].x, x3 = v[1].x;
draw_flat_triangle(v[0].y, v[1].y - 1, dx1, dx2, &x1, &x2, &tctx, rctx);
draw_flat_triangle(v[1].y, v[2].y, dx2, dx3, &x2, &x3, &tctx, rctx);
}
}
Canvas *rasterize(Canvas *source, Canvas *target, Morphing *m, TimeVector frame) {
RasterizationContext rctx;
TriangleMap *t;
assert(source != NULL && target != NULL && m != NULL);
assert(vector_equals(canvas_get_dim(source), m->dim) && vector_equals(canvas_get_dim(target), m->dim));
assert(frame >= TIME_ORIGIN && frame <= TIME_UNIT);
rctx = (RasterizationContext) {canvas_create(m->dim.x, m->dim.y), source, target, frame};
for (t = m->first; t != NULL; t = t->next) draw_triangle(t, &rctx);
return rctx.result;
}
|