|
|
07b70f |
|
|
|
07b70f |
#include <cairo.h></cairo.h>
|
|
|
07b70f |
|
|
|
07b70f |
#include "private.h"
|
|
|
07b70f |
#include "drawing.h"
|
|
|
07b70f |
|
|
|
07b70f |
static double colorBack[4] = {1, 1, 1, 1};
|
|
|
07b70f |
static double colorFill[4] = {0.5, 0.5, 0.5, 1};
|
|
|
07b70f |
static double colorStroke[4] = {0, 0, 0, 1};
|
|
|
07b70f |
static double lineWidth = 1;
|
|
|
07b70f |
static double *path;
|
|
|
07b70f |
static size_t pathSize;
|
|
|
07b70f |
static size_t pathAllocated;
|
|
|
07b70f |
|
|
|
07b70f |
static HAlign horAlign = HALIGN_LEFT;
|
|
|
07b70f |
static VAlign vertAlign = VALIGN_TOP;
|
|
|
07b70f |
static char *font;
|
|
|
07b70f |
static double fontSize = 24;
|
|
|
07b70f |
|
|
|
07b70f |
|
|
|
07b70f |
void background(const char *color)
|
|
|
07b70f |
{ heliParseColor(color, colorBack); }
|
|
|
07b70f |
void fill(const char *color)
|
|
|
07b70f |
{ heliParseColor(color, colorFill); }
|
|
|
07b70f |
void noFill()
|
|
|
07b70f |
{ fill("transparent"); }
|
|
|
07b70f |
void stroke(const char *color)
|
|
|
07b70f |
{ heliParseColor(color, colorStroke); }
|
|
|
07b70f |
void noStroke()
|
|
|
07b70f |
{ stroke("transparent"); }
|
|
|
07b70f |
|
|
|
07b70f |
void strokeWeight(double weight)
|
|
|
07b70f |
{ lineWidth = weight; }
|
|
|
07b70f |
|
|
|
07b70f |
char* rgba(double r, double g, double b, double a) {
|
|
|
07b70f |
static char buf[1024];
|
|
|
07b70f |
snprintf(buf, sizeof(buf) - 1, "%f %f %f %f", r, g, b, a);
|
|
|
07b70f |
return buf;
|
|
|
07b70f |
}
|
|
|
07b70f |
|
|
|
07b70f |
char* rgb(double r, double g, double b)
|
|
|
07b70f |
{ return rgba(r, g, b, 1); }
|
|
|
07b70f |
|
|
|
07b70f |
void rect(double x, double y, double width, double height) {
|
|
|
07b70f |
resetPath();
|
|
|
07b70f |
moveTo(x, y);
|
|
|
07b70f |
lineTo(x + width, y);
|
|
|
07b70f |
lineTo(x + width, y + height);
|
|
|
07b70f |
lineTo(x, y + height);
|
|
|
07b70f |
closePath();
|
|
|
07b70f |
}
|
|
|
07b70f |
|
|
|
07b70f |
void line(double x1, double y1, double x2, double y2) {
|
|
|
07b70f |
resetPath();
|
|
|
07b70f |
moveTo(x1, y1);
|
|
|
07b70f |
lineTo(x2, y2);
|
|
|
07b70f |
strokePath();
|
|
|
07b70f |
}
|
|
|
07b70f |
|
|
|
07b70f |
void ellipse(double x, double y, double width, double height) {
|
|
|
07b70f |
resetPath();
|
|
|
07b70f |
arcPath(x, y, width, height, 0, 360);
|
|
|
07b70f |
closePath();
|
|
|
07b70f |
}
|
|
|
07b70f |
|
|
|
07b70f |
void point(double x, double y)
|
|
|
07b70f |
{ ellipse(x - lineWidth*0.25, y - lineWidth*0.25, lineWidth*0.5, lineWidth*0.5); }
|
|
|
07b70f |
|
|
|
07b70f |
void arcPath(double x, double y, double w, double h, double start, double stop) {
|
|
|
07b70f |
double step = PI/180;
|
|
|
07b70f |
start *= PI/180;
|
|
|
07b70f |
stop *= PI/180;
|
|
|
07b70f |
if (start < stop) { double s = start; stop = start; start = s; }
|
|
|
07b70f |
for(double a = start; a < stop; a += step) {
|
|
|
07b70f |
double lx = x + cos(a)*w;
|
|
|
07b70f |
double ly = y + sin(a)*h;
|
|
|
07b70f |
lineTo(lx, ly);
|
|
|
07b70f |
}
|
|
|
07b70f |
}
|
|
|
07b70f |
|
|
|
07b70f |
void arc(double x, double y, double w, double h, double start, double stop) {
|
|
|
07b70f |
resetPath();
|
|
|
07b70f |
arcPath(x, y, w, h, start, stop);
|
|
|
07b70f |
strokePath();
|
|
|
07b70f |
}
|
|
|
07b70f |
|
|
|
07b70f |
void regularPolygon(double x, double y, int sides, double size) {
|
|
|
07b70f |
resetPath();
|
|
|
07b70f |
size *= 0.5;
|
|
|
07b70f |
moveTo(x + size, y);
|
|
|
07b70f |
for(int i = 1; i < sides; ++i) {
|
|
|
07b70f |
double a = i*PI/sides;
|
|
|
07b70f |
lineTo(x + size*cos(a), y + size*sin(a));
|
|
|
07b70f |
}
|
|
|
07b70f |
closePath();
|
|
|
07b70f |
}
|
|
|
07b70f |
|
|
|
07b70f |
|
|
|
07b70f |
void resetPath()
|
|
|
07b70f |
{ pathSize = 0; }
|
|
|
07b70f |
|
|
|
07b70f |
static void endPath(int close, int stroke, int fill) {
|
|
|
07b70f |
cairo_t *cr = heliCairo;
|
|
|
07b70f |
if (cr && pathSize >= 8) {
|
|
|
07b70f |
cairo_save(cr);
|
|
|
07b70f |
cairo_move_to(cr, path[0], path[1]);
|
|
|
07b70f |
for(int i = 2; i < pathSize; i += 2)
|
|
|
07b70f |
cairo_line_to(cr, path[i], path[i+1]);
|
|
|
07b70f |
if (close)
|
|
|
07b70f |
cairo_close_path(cr);
|
|
|
07b70f |
if (fill) {
|
|
|
07b70f |
cairo_set_source_rgba(cr, colorFill[0], colorFill[1], colorFill[2], colorFill[3]);
|
|
|
07b70f |
if (stroke) cairo_fill_preserve(cr); else cairo_fill(cr);
|
|
|
07b70f |
}
|
|
|
07b70f |
if (stroke) {
|
|
|
07b70f |
cairo_set_line_width(cr, lineWidth);
|
|
|
07b70f |
cairo_set_source_rgba(cr, colorStroke[0], colorStroke[1], colorStroke[2], colorStroke[3]);
|
|
|
07b70f |
cairo_stroke(cr);
|
|
|
07b70f |
}
|
|
|
07b70f |
cairo_restore(cr);
|
|
|
07b70f |
}
|
|
|
07b70f |
resetPath();
|
|
|
07b70f |
}
|
|
|
07b70f |
|
|
|
07b70f |
static void pushPathPoint(double x, double y) {
|
|
|
07b70f |
if (pathAllocated < pathSize + 2) {
|
|
|
07b70f |
pathAllocated += pathAllocated/4 + 32;
|
|
|
07b70f |
path = realloc(path, pathAllocated);
|
|
|
07b70f |
memset(&path[pathSize], 0, (pathAllocated - pathSize)*sizeof(*path));
|
|
|
07b70f |
}
|
|
|
07b70f |
path[pathSize++] = x;
|
|
|
07b70f |
path[pathSize++] = y;
|
|
|
07b70f |
}
|
|
|
07b70f |
|
|
|
07b70f |
void closePath()
|
|
|
07b70f |
{ endPath(TRUE, TRUE, TRUE); }
|
|
|
07b70f |
void strokePath()
|
|
|
07b70f |
{ endPath(FALSE, TRUE, FALSE); }
|
|
|
07b70f |
void lineTo(double x, double y)
|
|
|
07b70f |
{ pushPathPoint(x, y); }
|
|
|
07b70f |
void moveTo(double x, double y)
|
|
|
07b70f |
{ resetPath(); lineTo(x, y); }
|
|
|
07b70f |
|
|
|
07b70f |
|
|
|
07b70f |
void textAlign(HAlign hor, VAlign vert)
|
|
|
07b70f |
{ horAlign = hor; vertAlign = vert; }
|
|
|
07b70f |
void textFont(const char *f)
|
|
|
07b70f |
{ free(font); font = heliStringCopy(f); }
|
|
|
07b70f |
void textSize(double size)
|
|
|
07b70f |
{ fontSize = size; }
|
|
|
07b70f |
|
|
|
07b70f |
void text(const char *text, double x, double y) {
|
|
|
07b70f |
resetPath();
|
|
|
07b70f |
|
|
|
07b70f |
cairo_t *cr = heliCairo;
|
|
|
07b70f |
if (!cr) return;
|
|
|
07b70f |
cairo_save(cr);
|
|
|
07b70f |
|
|
|
07b70f |
if (font) cairo_select_font_face(cr, font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
|
|
07b70f |
cairo_set_font_size(cr, fontSize);
|
|
|
07b70f |
|
|
|
07b70f |
cairo_text_extents_t extents;
|
|
|
07b70f |
cairo_text_extents(cr, text, &extents);
|
|
|
07b70f |
double w = extents.x_bearing + extents.width;
|
|
|
07b70f |
double h = extents.y_bearing + extents.height;
|
|
|
07b70f |
if (horAlign == HALIGN_CENTER) x -= w*0.5;
|
|
|
07b70f |
if (horAlign == HALIGN_RIGHT ) x -= w;
|
|
|
07b70f |
if (vertAlign == VALIGN_CENTER) y -= h*0.5;
|
|
|
07b70f |
if (vertAlign == VALIGN_BOTTOM) y -= h;
|
|
|
07b70f |
|
|
|
07b70f |
cairo_set_source_rgba(cr, colorStroke[0], colorStroke[1], colorStroke[2], colorStroke[3]);
|
|
|
07b70f |
cairo_move_to(cr, x, y);
|
|
|
07b70f |
cairo_show_text(cr, text);
|
|
|
07b70f |
|
|
|
07b70f |
cairo_restore(cr);
|
|
|
07b70f |
}
|
|
|
07b70f |
|
|
|
650f35 |
void heliDrawingClearFrame(cairo_t *cr) {
|
|
|
07b70f |
cairo_save(cr);
|
|
|
07b70f |
cairo_set_source_rgba(cr, colorBack[0], colorBack[1], colorBack[2], 1);
|
|
|
07b70f |
cairo_paint(cr);
|
|
|
07b70f |
cairo_restore(cr);
|
|
|
07b70f |
}
|
|
|
07b70f |
|
|
|
650f35 |
void heliDrawingPrepareFrame() {
|
|
|
650f35 |
resetPath();
|
|
|
650f35 |
if (heliCairo) heliDrawingClearFrame(heliCairo);
|
|
|
650f35 |
}
|
|
|
650f35 |
|
|
|
07b70f |
void heliDrawingFinish() {
|
|
|
07b70f |
resetPath();
|
|
|
07b70f |
free(path);
|
|
|
07b70f |
path = NULL;
|
|
|
07b70f |
pathAllocated = 0;
|
|
|
07b70f |
free(font);
|
|
|
07b70f |
font = NULL;
|
|
|
07b70f |
}
|