2020-03-31 22:16:17 +02:00
|
|
|
#include "hvif-light.h"
|
|
|
|
|
2020-04-01 23:23:59 +02:00
|
|
|
#include <assert.h>
|
2020-03-31 22:16:17 +02:00
|
|
|
#include <cairo.h>
|
2020-04-23 22:08:06 +02:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdlib.h>
|
2020-03-31 22:16:17 +02:00
|
|
|
|
|
|
|
#define INTERNAL_DATASTRUCTURES
|
|
|
|
#include "hvif-light.c"
|
|
|
|
#undef INTERNAL_DATASTRUCTURES
|
|
|
|
|
2020-04-01 23:23:59 +02:00
|
|
|
/* TODO:
|
|
|
|
* 1. Draw the path in each shape as outline
|
|
|
|
* 2. Then do the same for the styles
|
|
|
|
* 3. Put everything together
|
|
|
|
*/
|
|
|
|
|
2020-04-23 00:43:10 +02:00
|
|
|
/* TODO: Gradients
|
|
|
|
* - Check the various forms
|
|
|
|
* - How is the gradient oriented in the picture
|
|
|
|
* - Apply transformation matrix
|
|
|
|
* - Color space
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
2020-04-23 22:08:06 +02:00
|
|
|
cairo_matrix_init_from_matrix(
|
|
|
|
cairo_matrix_t* matrix, const hvif_matrix* hvif_matrix)
|
2020-04-23 00:43:10 +02:00
|
|
|
{
|
2020-04-23 22:08:06 +02:00
|
|
|
cairo_matrix_init(
|
|
|
|
matrix, hvif_matrix->xx, hvif_matrix->yx, hvif_matrix->xy, hvif_matrix->yy,
|
|
|
|
hvif_matrix->x0, hvif_matrix->y0);
|
2020-04-23 00:43:10 +02:00
|
|
|
}
|
|
|
|
|
2020-04-01 23:23:59 +02:00
|
|
|
void
|
|
|
|
create_path(cairo_t* cr, hvif_path* path)
|
|
|
|
{
|
|
|
|
assert(path->num_points > 0);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < path->num_points; ++i) {
|
|
|
|
hvif_point p = path->points[3 * i];
|
|
|
|
hvif_point cp1 = path->points[3 * i + 1];
|
|
|
|
hvif_point cp2 = path->points[3 * i + 2];
|
2020-04-23 00:43:10 +02:00
|
|
|
uint8_t command = path_command_at(path, i);
|
|
|
|
if (command == PATH_COMMAND_CURVE)
|
|
|
|
cairo_curve_to(cr, cp1.x, cp1.y, cp2.x, cp2.y, p.x, p.y);
|
|
|
|
else
|
|
|
|
cairo_line_to(cr, p.x, p.y);
|
2020-04-01 23:23:59 +02:00
|
|
|
}
|
|
|
|
|
2020-04-23 22:08:06 +02:00
|
|
|
if (path->closed) cairo_close_path(cr);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define R(c) (COLOR_GET_RED(c) / 255.0)
|
|
|
|
#define G(c) (COLOR_GET_GREEN(c) / 255.0)
|
|
|
|
#define B(c) (COLOR_GET_BLUE(c) / 255.0)
|
|
|
|
#define A(c) (COLOR_GET_ALPHA(c) / 255.0)
|
|
|
|
|
|
|
|
void
|
|
|
|
create_diamond_patch(
|
|
|
|
cairo_pattern_t* pat, double s, double d, hvif_color c1, hvif_color c2)
|
|
|
|
{
|
|
|
|
cairo_mesh_pattern_begin_patch(pat);
|
|
|
|
cairo_mesh_pattern_move_to(pat, s, s);
|
|
|
|
cairo_mesh_pattern_line_to(pat, s + d, s + d);
|
|
|
|
cairo_mesh_pattern_line_to(pat, s + d, -(s + d));
|
|
|
|
cairo_mesh_pattern_line_to(pat, s, -s);
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 0, R(c1), G(c1), B(c1), A(c1));
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 1, R(c2), G(c2), B(c2), A(c2));
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 2, R(c2), G(c2), B(c2), A(c2));
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 3, R(c1), G(c1), B(c1), A(c1));
|
|
|
|
cairo_mesh_pattern_end_patch(pat);
|
|
|
|
cairo_mesh_pattern_begin_patch(pat);
|
|
|
|
cairo_mesh_pattern_move_to(pat, s, -s);
|
|
|
|
cairo_mesh_pattern_line_to(pat, s + d, -(s + d));
|
|
|
|
cairo_mesh_pattern_line_to(pat, -(s + d), -(s + d));
|
|
|
|
cairo_mesh_pattern_line_to(pat, -s, -s);
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 0, R(c1), G(c1), B(c1), A(c1));
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 1, R(c2), G(c2), B(c2), A(c2));
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 2, R(c2), G(c2), B(c2), A(c2));
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 3, R(c1), G(c1), B(c1), A(c1));
|
|
|
|
cairo_mesh_pattern_end_patch(pat);
|
|
|
|
cairo_mesh_pattern_begin_patch(pat);
|
|
|
|
cairo_mesh_pattern_move_to(pat, -s, -s);
|
|
|
|
cairo_mesh_pattern_line_to(pat, -(s + d), -(s + d));
|
|
|
|
cairo_mesh_pattern_line_to(pat, -(s + d), s + d);
|
|
|
|
cairo_mesh_pattern_line_to(pat, -s, s);
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 0, R(c1), G(c1), B(c1), A(c1));
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 1, R(c2), G(c2), B(c2), A(c2));
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 2, R(c2), G(c2), B(c2), A(c2));
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 3, R(c1), G(c1), B(c1), A(c1));
|
|
|
|
cairo_mesh_pattern_end_patch(pat);
|
|
|
|
cairo_mesh_pattern_begin_patch(pat);
|
|
|
|
cairo_mesh_pattern_move_to(pat, -s, s);
|
|
|
|
cairo_mesh_pattern_line_to(pat, -(s + d), s + d);
|
|
|
|
cairo_mesh_pattern_line_to(pat, s + d, s + d);
|
|
|
|
cairo_mesh_pattern_line_to(pat, s, s);
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 0, R(c1), G(c1), B(c1), A(c1));
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 1, R(c2), G(c2), B(c2), A(c2));
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 2, R(c2), G(c2), B(c2), A(c2));
|
|
|
|
cairo_mesh_pattern_set_corner_color_rgba(pat, 3, R(c1), G(c1), B(c1), A(c1));
|
|
|
|
cairo_mesh_pattern_end_patch(pat);
|
2020-04-01 23:23:59 +02:00
|
|
|
}
|
|
|
|
|
2020-04-23 00:43:10 +02:00
|
|
|
void
|
|
|
|
create_style(cairo_t* cr, hvif_style* style)
|
|
|
|
{
|
|
|
|
assert(style->num_stops > 0);
|
2020-04-23 22:08:06 +02:00
|
|
|
cairo_pattern_t* pat;
|
|
|
|
|
|
|
|
double width = 64.0;
|
|
|
|
double height = 64.0;
|
|
|
|
cairo_matrix_t transformation;
|
|
|
|
cairo_matrix_init_from_matrix(&transformation, &style->transformation);
|
|
|
|
cairo_matrix_transform_point(&transformation, &width, &height);
|
|
|
|
double extremum = width > height ? width : height;
|
2020-04-23 00:43:10 +02:00
|
|
|
|
|
|
|
switch (style->gradient_type) {
|
|
|
|
case GRADIENT_LINEAR:
|
|
|
|
printf("GRADIENT_LINEAR\n");
|
|
|
|
pat = cairo_pattern_create_linear(-64, 32, 64, 32);
|
2020-04-23 22:08:06 +02:00
|
|
|
for (unsigned i = 0; i < style->num_stops; ++i) {
|
|
|
|
hvif_color c = style->colors[i];
|
|
|
|
cairo_pattern_add_color_stop_rgba(
|
|
|
|
pat, style->offsets[i], R(c), G(c), B(c), A(c));
|
|
|
|
}
|
2020-04-23 00:43:10 +02:00
|
|
|
break;
|
|
|
|
case GRADIENT_CIRCULAR:
|
|
|
|
printf("GRADIENT_CIRCULAR\n");
|
|
|
|
pat = cairo_pattern_create_radial(0, 0, 0, 0, 0, 64);
|
2020-04-23 22:08:06 +02:00
|
|
|
for (unsigned i = 0; i < style->num_stops; ++i) {
|
|
|
|
hvif_color c = style->colors[i];
|
|
|
|
cairo_pattern_add_color_stop_rgba(
|
|
|
|
pat, style->offsets[i], R(c), G(c), B(c), A(c));
|
|
|
|
}
|
2020-04-23 00:43:10 +02:00
|
|
|
break;
|
|
|
|
case GRADIENT_DIAMOND:
|
2020-04-23 22:08:06 +02:00
|
|
|
pat = cairo_pattern_create_mesh();
|
|
|
|
double d = 64.0 / (style->num_stops - 1);
|
|
|
|
for (unsigned i = 0; i < style->num_stops - 1; ++i) {
|
|
|
|
hvif_color c1 = style->colors[i];
|
|
|
|
hvif_color c2 = style->colors[i + 1];
|
|
|
|
double s = d * i;
|
|
|
|
create_diamond_patch(pat, s, d, c1, c2);
|
|
|
|
}
|
|
|
|
if (extremum > 64.0) {
|
|
|
|
hvif_color c = style->colors[style->num_stops - 1];
|
|
|
|
create_diamond_patch(pat, 64.0, extremum - 64.0, c, c);
|
|
|
|
}
|
2020-04-23 00:43:10 +02:00
|
|
|
printf("GRADIENT_DIAMOND\n");
|
|
|
|
break;
|
|
|
|
case GRADIENT_CONIC:
|
|
|
|
printf("GRADIENT_CONIC\n");
|
|
|
|
assert(false);
|
|
|
|
break;
|
|
|
|
case GRADIENT_XY:
|
|
|
|
printf("GRADIENT_XY\n");
|
|
|
|
assert(false);
|
|
|
|
break;
|
|
|
|
case GRADIENT_SQRT_XY:
|
|
|
|
printf("GRADIENT_SQRT_XY\n");
|
|
|
|
assert(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cairo_matrix_invert(&transformation) != CAIRO_STATUS_SUCCESS) {
|
|
|
|
printf("could not invert style transformation\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
cairo_pattern_set_matrix(pat, &transformation);
|
|
|
|
|
|
|
|
cairo_rectangle(cr, 0, 0, 64, 64);
|
|
|
|
cairo_set_source(cr, pat);
|
|
|
|
cairo_fill(cr);
|
|
|
|
cairo_pattern_destroy(pat);
|
|
|
|
}
|
|
|
|
|
2020-03-31 22:16:17 +02:00
|
|
|
bool
|
|
|
|
hvif_render_image(const char* filename, hvif_image* image)
|
|
|
|
{
|
|
|
|
cairo_surface_t* surface =
|
2020-04-23 00:43:10 +02:00
|
|
|
/* cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 254, 254); */
|
2020-04-23 22:08:06 +02:00
|
|
|
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 64, 64);
|
2020-03-31 22:16:17 +02:00
|
|
|
cairo_t* cr = cairo_create(surface);
|
2020-04-23 00:43:10 +02:00
|
|
|
/* cairo_scale(cr, 4.0, 4.0); */
|
|
|
|
cairo_scale(cr, 1.0, 1.0);
|
2020-04-01 23:23:59 +02:00
|
|
|
|
|
|
|
cairo_set_line_width(cr, 0.2);
|
|
|
|
|
|
|
|
double r = 0;
|
|
|
|
double delta = 1.0 / image->num_shapes;
|
|
|
|
|
2020-04-23 00:43:10 +02:00
|
|
|
printf("styles %u\n", image->num_styles);
|
|
|
|
create_style(cr, &image->styles[0]);
|
|
|
|
|
2020-04-23 22:08:06 +02:00
|
|
|
/*
|
2020-04-01 23:23:59 +02:00
|
|
|
for (unsigned i = 0; i < image->num_shapes; ++i) {
|
|
|
|
cairo_set_source_rgb(cr, r, 0, 0);
|
|
|
|
r = r + delta;
|
|
|
|
hvif_shape s = image->shapes[i];
|
|
|
|
if (s.hinting)
|
|
|
|
printf("shape %u has hinting\n", i);
|
|
|
|
else
|
|
|
|
printf("shape %u has no hinting\n", i);
|
|
|
|
for (unsigned j = 0; j < s.num_paths; ++j) {
|
|
|
|
hvif_path* p = &image->paths[s.path_idxs[j]];
|
|
|
|
create_path(cr, p);
|
|
|
|
cairo_stroke(cr);
|
|
|
|
}
|
|
|
|
}
|
2020-04-23 00:43:10 +02:00
|
|
|
*/
|
2020-03-31 22:16:17 +02:00
|
|
|
|
|
|
|
cairo_destroy(cr);
|
|
|
|
|
|
|
|
bool result = true;
|
|
|
|
if (cairo_surface_write_to_png(surface, filename) != CAIRO_STATUS_SUCCESS)
|
|
|
|
result = false;
|
|
|
|
cairo_surface_destroy(surface);
|
|
|
|
return result;
|
|
|
|
}
|