From c29e4ecb7de4cb10f48b2526bc1abae847c718e2 Mon Sep 17 00:00:00 2001 From: pacien Date: Thu, 28 Dec 2017 01:19:45 +0100 Subject: Add new geometry common types and functions Signed-off-by: pacien --- include/common/geom.h | 93 +++++++++++++++++++++++++++++++++++++++++++---- include/common/time.h | 4 +- src/common/geom.c | 27 +++++++++++++- src/morpher/trianglemap.c | 2 +- test/common/geom.c | 21 +++++++++++ 5 files changed, 137 insertions(+), 10 deletions(-) create mode 100644 test/common/geom.c diff --git a/include/common/geom.h b/include/common/geom.h index b3564a5..334e95c 100644 --- a/include/common/geom.h +++ b/include/common/geom.h @@ -14,6 +14,12 @@ */ typedef int32_t IntVector; +/** + * Type: RealVector + * An abstract 1-D real vector. + */ +typedef double RealVector; + /** * Struct: CartesianVector * An abstract 2-D vector in cartesian coordinates. @@ -26,6 +32,19 @@ typedef struct { IntVector x, y; } CartesianVector; +/** + * Struct: BarycentricVector + * An abstract barycentric coordinate tuple relative to a triangle. + * The third barycentric coordinate is deduced from the first two ones. + * + * Fields: + * a - the first barycentric coordinate + * b - the second barycentric coordinate + */ +typedef struct { + RealVector a, b; +} BarycentricVector; + /** * Struct: CartesianMapping * A tuple of cartesian vectors representing a mapping. @@ -38,6 +57,16 @@ typedef struct { CartesianVector origin, target; } CartesianMapping; +/** + * Struct: Triangle + * Represents a simple triangle with three vertices. + * + * Fields: + * v[] - array of vertices + */ +typedef struct { + CartesianVector v[3]; +} Triangle; /** * Function: m @@ -65,6 +94,19 @@ CartesianMapping m(int x, int y); */ CartesianVector v(int x, int y); +/** + * Function: b + * Shorthand for a barycentric vector. + * + * Parameters: + * a - the a-coordinate + * b - the b-coordinate + * + * Returns: + * A barycentric vector + */ +BarycentricVector b(double a, double b); + /** * Function: mappings_equals * Compares two cartesian mappings. @@ -92,17 +134,54 @@ bool mappings_equals(CartesianMapping m1, CartesianMapping m2); bool vector_equals(CartesianVector v1, CartesianVector v2); /** - * Function: triangle_area - * Computes the area of a triangle. + * Function: barycentric_vector_equals + * Compares two barycentric vectors. + * + * Parameters: + * v1 - the first vector + * v2 - the second vector + * + * Returns: + * T(v1 is equal to v2) + */ +bool barycentric_vector_equals(BarycentricVector b1, BarycentricVector b2); + +/** + * Function: square_area + * Computes the area of a square spawned by three positively oriented vertices. + * + * Parameters: + * vi - vertices + * + * Returns: + * The area of the square + */ +IntVector square_area(CartesianVector v1, CartesianVector v2, CartesianVector v3); + +/** + * Function: cartesian_to_barycentric + * Computes and returns the barycentric coordinates of a given point in the given reference triangle. + * + * Parameters: + * t - reference triangle + * p - the vector to convert + * + * Returns: + * The barycentric coordinates vector + */ +BarycentricVector cartesian_to_barycentric(Triangle t, CartesianVector p); + +/** + * Function: barycentric_to_cartesian + * Computes and returns the cartesian coordinates of a given point in the given reference triangle. * * Parameters: - * v1 - first vertex - * v2 - second vertex - * v3 - third vertex + * t - reference triangle + * p - the vector to convert * * Returns: - * The area of the triangle spawned by the three supplied vertices + * The cartesian coordinate vector */ -IntVector triangle_area(CartesianVector v1, CartesianVector v2, CartesianVector v3); +CartesianVector barycentric_to_cartesian(Triangle t, BarycentricVector p); #endif diff --git a/include/common/time.h b/include/common/time.h index 54a7bb2..e207ad7 100644 --- a/include/common/time.h +++ b/include/common/time.h @@ -5,6 +5,8 @@ * File: time.h */ +#include "geom.h" + /** * Constants: Time vectors * @@ -18,6 +20,6 @@ * Type: TimeVector * An abstract time vector. */ -typedef float TimeVector; +typedef RealVector TimeVector; #endif 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 @@ #include "common/geom.h" +#include +#include #include "morpher/matrix.h" +static inline IntVector int_round(RealVector x) { + return (IntVector) round(x); +} + CartesianMapping m(int x, int y) { return (CartesianMapping) {{x, y}, {x, y}}; @@ -10,6 +16,10 @@ CartesianVector v(int x, int y) { return (CartesianVector) {x, y}; } +BarycentricVector b(double a, double b) { + return (BarycentricVector) {a, b}; +} + bool mappings_equals(CartesianMapping m1, CartesianMapping m2) { return vector_equals(m1.origin, m2.origin) && vector_equals(m1.target, m2.target); } @@ -18,7 +28,22 @@ bool vector_equals(CartesianVector v1, CartesianVector v2) { return v1.x == v2.x && v1.y == v2.y; } -IntVector triangle_area(CartesianVector v1, CartesianVector v2, CartesianVector v3) { +bool barycentric_vector_equals(BarycentricVector b1, BarycentricVector b2) { + return b1.a == b2.a && b1.b == b2.b; +} + +IntVector square_area(CartesianVector v1, CartesianVector v2, CartesianVector v3) { return matrix_int_det2(v1.x - v3.x, v2.x - v3.x, v1.y - v3.y, v2.y - v3.y); } + +BarycentricVector cartesian_to_barycentric(Triangle t, CartesianVector p) { + RealVector total_area = square_area(t.v[0], t.v[1], t.v[2]); + return (BarycentricVector) {square_area(t.v[1], t.v[2], p) / total_area, + square_area(t.v[2], t.v[0], p) / total_area}; +} + +CartesianVector barycentric_to_cartesian(Triangle t, BarycentricVector p) { + 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), + 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)}; +} 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) { int edge; for (edge = 0; edge < 3; ++edge) - if (triangle_area(t->vertices[edge].origin, t->vertices[(edge + 1) % 3].origin, v) > 0) + if (square_area(t->vertices[edge].origin, t->vertices[(edge + 1) % 3].origin, v) > 0) return t->neighbors[edge]; return t; diff --git a/test/common/geom.c b/test/common/geom.c new file mode 100644 index 0000000..f05e0a1 --- /dev/null +++ b/test/common/geom.c @@ -0,0 +1,21 @@ +#include "common/geom.h" +#include + +static void test_square_area() { + assert(square_area(v(0, 0), v(10, 0), v(10, 10)) == 100); + assert(square_area(v(0, 0), v(0, 10), v(10, 10)) == -100); +} + +static void test_cartesian_barycentric_vectors() { + Triangle t = {{v(0, 0), v(10, 0), v(10, 10)}}; + CartesianVector c = v(3, 2); + BarycentricVector bv = cartesian_to_barycentric(t, c); + assert(barycentric_vector_equals(bv, b(0.7, 0.1))); + assert(vector_equals(barycentric_to_cartesian(t, bv), c)); +} + +int main(int argc, char **argv) { + test_square_area(); + test_cartesian_barycentric_vectors(); + return 0; +} -- cgit v1.2.3 From c970da3f5830fae5b4d98dcdcc8d34d678ec0434 Mon Sep 17 00:00:00 2001 From: pacien Date: Thu, 28 Dec 2017 01:22:03 +0100 Subject: Refactor canvas Signed-off-by: pacien --- include/painter/canvas.h | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ src/blender/canvas.c | 23 --------------- src/painter/canvas.c | 27 +++++++++++++++++ 3 files changed, 103 insertions(+), 23 deletions(-) create mode 100644 include/painter/canvas.h delete mode 100644 src/blender/canvas.c create mode 100644 src/painter/canvas.c diff --git a/include/painter/canvas.h b/include/painter/canvas.h new file mode 100644 index 0000000..e354938 --- /dev/null +++ b/include/painter/canvas.h @@ -0,0 +1,76 @@ +#ifndef UPEM_MORPHING_CANVAS +#define UPEM_MORPHING_CANVAS + +/** + * File: canvas.h + * "Everyday is a good day when you paint" – Bob Ross + */ + +#include +#include "common/geom.h" +#include "painter/color.h" + +/** + * Type: Canvas + * Represents a fixed size RGBa pixel matrix. + */ +typedef struct { + MLV_Image *mlv; +} Canvas; + +/** + * Function: canvas_create + * Initialises a canvas of the given size + * + * Parameters: + * width - the width in pixels + * height - the height in pixels + */ +Canvas *canvas_create(IntVector width, IntVector height); + +/** + * Function: canvas_destroy + * Frees all memory allocated to a canvas. + * + * Parameters: + * *c - the canvas to destroy + */ +void canvas_destroy(Canvas *c); + +/** + * Function: canvas_set_pixel + * Sets the pixel colour at the given coordinates. + * + * Parameters: + * *c - the canvas to alter + * pos - the coordinate of the pixel to set + * color - the new colour to set + */ +void canvas_set_pixel(Canvas *c, CartesianVector pos, Color color); + +/** + * Function: canvas_get_pixel + * Returns the colour of the pixel at the given position. + * + * Parameters: + * *c - the base canvas + * pos - the coordinate of the pixel to get + * + * Returns: + * The colour of the requested pixel + */ +Color canvas_get_pixel(Canvas *c, CartesianVector pos); + +/** + * Function: canvas_get_dim + * Returns the size (in pixels) of the given canvas. + * + * Parameters: + * *c - the canvas + * + * Returns: + * The size of the canvas + */ +CartesianVector canvas_get_dim(Canvas *c); + +#endif 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 @@ -#include "blender/canvas.h" - -void canvas_init(Canvas *canvas, IntVector width, IntVector height) { - canvas->mlv = MLV_create_image(width, height); -} - -void canvas_free(Canvas *canvas) { - MLV_free_image(canvas->mlv); -} - -void canvas_set_pixel(Canvas *canvas, CartesianVector position, Color color) { - MLV_set_pixel_on_image(position.x, position.y, color.mlv, canvas->mlv); -} - -Color canvas_get_pixel(Canvas *canvas, CartesianVector position) { - int r, g, b, a; - MLV_get_pixel_on_image(canvas->mlv, position.x, position.y, &r, &g, &b, &a); - return (Color) {{r, g, b, a}}; -} - -CartesianVector canvas_get_dim(Canvas *canvas) { - return (CartesianVector) {MLV_get_image_width(canvas->mlv), MLV_get_image_height(canvas->mlv)}; -} 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 @@ +#include "painter/canvas.h" +#include "common/mem.h" + +Canvas *canvas_create(IntVector width, IntVector height) { + Canvas *c = malloc_or_die(sizeof(Canvas)); + c->mlv = MLV_create_image(width, height); + return c; +} + +void canvas_destroy(Canvas *c) { + MLV_free_image(c->mlv); + free(c); +} + +void canvas_set_pixel(Canvas *c, CartesianVector pos, Color color) { + MLV_set_pixel_on_image(pos.x, pos.y, color.mlv, c->mlv); +} + +Color canvas_get_pixel(Canvas *c, CartesianVector pos) { + int r, g, b, a; + MLV_get_pixel_on_image(c->mlv, pos.x, pos.y, &r, &g, &b, &a); + return (Color) {{a, b, g, r}}; +} + +CartesianVector canvas_get_dim(Canvas *c) { + return (CartesianVector) {MLV_get_image_width(c->mlv), MLV_get_image_height(c->mlv)}; +} -- cgit v1.2.3 From 190449ee18bec69b2e385dccd9bd42ddc83dd418 Mon Sep 17 00:00:00 2001 From: pacien Date: Thu, 28 Dec 2017 01:22:41 +0100 Subject: Refactor and test color Signed-off-by: pacien --- include/painter/color.h | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ src/blender/color.c | 8 ------- src/painter/color.c | 20 ++++++++++++++++ test/painter/color.c | 14 ++++++++++++ 4 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 include/painter/color.h delete mode 100644 src/blender/color.c create mode 100644 src/painter/color.c create mode 100644 test/painter/color.c diff --git a/include/painter/color.h b/include/painter/color.h new file mode 100644 index 0000000..2aeee3e --- /dev/null +++ b/include/painter/color.h @@ -0,0 +1,61 @@ +#ifndef UPEM_MORPHING_COLOR +#define UPEM_MORPHING_COLOR + +/** + * File: color.h + * + * See also: + * A rainbow + */ + +#include +#include +#include "common/time.h" + +/** + * Type: ColorComponent + * Represents a single colour component of 32-bits RGBa tuple. + */ +typedef uint8_t ColorComponent; + +/** + * Type: ColorPixel + * Represents a single RGBa coloured pixel. + * Compatible with the libMLV representation. + */ +typedef union { + struct { + ColorComponent a, b, g, r; + } rgba; + + MLV_Color mlv; +} Color; + +/** + * Function: color_equals + * Compares the supplied colors. + * + * Parameters: + * c1 - the first color + * c2 - the second color + * + * Returns: + * T(c1 is the same color as c2) + */ +bool color_equals(Color c1, Color c2); + +/** + * Function: color_blend + * Blends two colors. + * + * Parameters: + * origin - the first color + * target - the second color + * distance - the distance from the first color + * + * Returns: + * The blended color + */ +Color color_blend(Color origin, Color target, TimeVector distance); + +#endif 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 @@ -#include "blender/color.h" - -bool color_equals(Color c1, Color c2) { - return c1.rgba.r == c2.rgba.r && - c1.rgba.g == c2.rgba.g && - c1.rgba.b == c2.rgba.b && - c1.rgba.a == c2.rgba.a; -} 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 @@ +#include "painter/color.h" +#include + +static inline ColorComponent blend_component(ColorComponent origin, ColorComponent target, TimeVector frame) { + return (ColorComponent) round(sqrt((TIME_UNIT - frame) * pow(origin, 2) + frame * pow(target, 2))); +} + +bool color_equals(Color c1, Color c2) { + return c1.rgba.r == c2.rgba.r && + c1.rgba.g == c2.rgba.g && + c1.rgba.b == c2.rgba.b && + c1.rgba.a == c2.rgba.a; +} + +Color color_blend(Color origin, Color target, TimeVector distance) { + return (Color) {{blend_component(origin.rgba.a, target.rgba.a, distance), + blend_component(origin.rgba.b, target.rgba.b, distance), + blend_component(origin.rgba.g, target.rgba.g, distance), + blend_component(origin.rgba.r, target.rgba.r, distance)}}; +} diff --git a/test/painter/color.c b/test/painter/color.c new file mode 100644 index 0000000..bdfe9b3 --- /dev/null +++ b/test/painter/color.c @@ -0,0 +1,14 @@ +#include "painter/color.h" +#include + +static void test_color_blend() { + Color a = {{1, 10, 100, 200}}, b = {{100, 1, 200, 10}}; + assert(color_equals(color_blend(a, b, TIME_ORIGIN), a)); + assert(color_equals(color_blend(a, b, TIME_UNIT), b)); + assert(color_equals(color_blend(a, b, 0.25), (Color) {{50, 9, 132, 173}})); +} + +int main(int argc, char **argv) { + test_color_blend(); + return 0; +} -- cgit v1.2.3 From 330fd85db8c89c178621d978929d911bbe93fec7 Mon Sep 17 00:00:00 2001 From: pacien Date: Thu, 28 Dec 2017 01:23:08 +0100 Subject: Refactor canvas blender into rasterizer Signed-off-by: pacien --- include/blender/blender.h | 26 -------------- include/painter/rasterizer.h | 41 +++++++++++++++++++++ src/blender/blender.c | 39 -------------------- src/painter/rasterizer.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ test/blender/blender.c | 29 --------------- test/painter/rasterizer.c | 27 ++++++++++++++ 6 files changed, 154 insertions(+), 94 deletions(-) delete mode 100644 include/blender/blender.h create mode 100644 include/painter/rasterizer.h delete mode 100644 src/blender/blender.c create mode 100644 src/painter/rasterizer.c delete mode 100644 test/blender/blender.c create mode 100644 test/painter/rasterizer.c diff --git a/include/blender/blender.h b/include/blender/blender.h deleted file mode 100644 index 26ff802..0000000 --- a/include/blender/blender.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef UPEM_MORPHING_BLENDER -#define UPEM_MORPHING_BLENDER - -/** - * File: blender.h - * Will it blend? That is the question. - */ - -#include "common/time.h" -#include "blender/canvas.h" -#include "morpher/morphing.h" - -/** - * Function: blender_blend_canvas - * Blends two canvas by applying the given morphing at the requested time frame. - * - * Parameters: - * *canvas - pointer to the canvas to paint - * *source - source image - * *target - target image - * *morphing - morphing transform to apply - * frame - the interpolation distance from the origin canvas [0;1] - */ -void blender_blend_canvas(Canvas *canvas, Canvas *source, Canvas *target, Morphing *morphing, TimeVector frame); - -#endif diff --git a/include/painter/rasterizer.h b/include/painter/rasterizer.h new file mode 100644 index 0000000..204d616 --- /dev/null +++ b/include/painter/rasterizer.h @@ -0,0 +1,41 @@ +#ifndef UPEM_MORPHING_RASTERIZER +#define UPEM_MORPHING_RASTERIZER + +/** + * File: rasterizer.h + */ + +#include "painter/canvas.h" +#include "morpher/morphing.h" + +/** + * Struct: RasterizationContext + */ +typedef struct { + Canvas *result, *source, *target; + TimeVector frame; +} RasterizationContext; + +/** + * Struct: TriangleContext + */ +typedef struct { + Triangle current, source, target; +} TriangleContext; + +/** + * Function: rasterize + * Rasterises a morphing from a source and a target image at the given time frame. + * + * Parameters: + * *source - source image canvas + * *target - target image canvas + * *m - reference morphing + * frame - time frame + * + * Returns: + * The drawn canvas, dynamically allocated + */ +Canvas *rasterize(Canvas *source, Canvas *target, Morphing *m, TimeVector frame); + +#endif 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 @@ -#include "blender/blender.h" -#include -#include - -static inline ColorComponent blend_components(ColorComponent origin, ColorComponent target, TimeVector frame) { - // https://www.youtube.com/watch?v=LKnqECcg6Gw - return (ColorComponent) sqrt((TIME_UNIT - frame) * pow(origin, 2) + frame * pow(target, 2)); -} - -static inline Color blend_colors(Color origin, Color target, TimeVector frame) { - return (Color) {{blend_components(origin.rgba.r, target.rgba.r, frame), - blend_components(origin.rgba.g, target.rgba.g, frame), - blend_components(origin.rgba.b, target.rgba.b, frame), - blend_components(origin.rgba.a, target.rgba.a, frame)}}; -} - -void blender_blend_canvas(Canvas *canvas, Canvas *source, Canvas *target, Morphing *morphing, TimeVector frame) { - IntVector flat_dim; - CartesianVector dim, point; - CartesianMapping mapping; - Color pixel; - - dim = morphing->dim; - - assert(dim.x > 0 && dim.y > 0); - assert(vector_equals(dim, canvas_get_dim(canvas))); - assert(vector_equals(dim, canvas_get_dim(source))); - assert(vector_equals(dim, canvas_get_dim(target))); - assert(frame >= TIME_ORIGIN && frame <= TIME_UNIT); - - for (flat_dim = (dim.x - 1) * (dim.y - 1); flat_dim >= 0; --flat_dim) { - point.x = flat_dim % dim.y; - point.y = flat_dim / dim.y; - - mapping = (CartesianMapping) {point, point}; - pixel = blend_colors(canvas_get_pixel(source, mapping.origin), canvas_get_pixel(target, mapping.target), frame); - canvas_set_pixel(canvas, point, pixel); - } -} 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 @@ +#include "painter/rasterizer.h" +#include +#include + +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.y, m->dim.x), source, target, frame}; + for (t = m->first; t != NULL; t = t->next) draw_triangle(t, &rctx); + + return rctx.result; +} diff --git a/test/blender/blender.c b/test/blender/blender.c deleted file mode 100644 index f42322f..0000000 --- a/test/blender/blender.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "blender/blender.h" -#include - -static void test_canvas_blending() { - Morphing *morphing; - Canvas origin, target, result; - CartesianVector sample_point = {13, 17}; - - morphing = morphing_create(64, 64); - canvas_init(&origin, 64, 64); - canvas_init(&target, 64, 64); - canvas_init(&result, 64, 64); - - canvas_set_pixel(&origin, sample_point, (Color) {{0xFF, 0xED, 0x00, 0x00}}); - canvas_set_pixel(&target, sample_point, (Color) {{0x00, 0x47, 0xAB, 0x00}}); - - blender_blend_canvas(&result, &origin, &target, morphing, 0.125); - assert(color_equals(canvas_get_pixel(&result, sample_point), (Color) {{0xEE, 0xDF, 0x3C, 0x00}})); - - canvas_free(&result); - canvas_free(&target); - canvas_free(&origin); - morphing_destroy(morphing); -} - -int main(int argc, char **argv) { - test_canvas_blending(); - return 0; -} diff --git a/test/painter/rasterizer.c b/test/painter/rasterizer.c new file mode 100644 index 0000000..99a70b4 --- /dev/null +++ b/test/painter/rasterizer.c @@ -0,0 +1,27 @@ +#include "painter/rasterizer.h" +#include + +static void test_rasterize() { + Morphing *morphing; + Canvas *origin, *target, *result; + CartesianVector sample_point = {13, 17}; + + morphing = morphing_create(100, 100); + origin = canvas_create(100, 100); + target = canvas_create(100, 100); + canvas_set_pixel(origin, sample_point, (Color) {{0xFF, 0x00, 0xED, 0xFF}}); + canvas_set_pixel(target, sample_point, (Color) {{0xFF, 0xAB, 0x47, 0x00}}); + + result = rasterize(origin, target, morphing, 0.125); + assert(color_equals(canvas_get_pixel(result, sample_point), (Color) {{0xFF, 0x3C, 0xDF, 0xEF}})); + + canvas_destroy(result); + canvas_destroy(target); + canvas_destroy(origin); + morphing_destroy(morphing); +} + +int main(int argc, char **argv) { + test_rasterize(); + return 0; +} -- cgit v1.2.3