149 lines
3.4 KiB
Objective-C
149 lines
3.4 KiB
Objective-C
// 6 september 2015
|
|
#include "area.h"
|
|
|
|
// TODO some pixel thick lines aren't actually pixel thick
|
|
|
|
struct uiDrawContext {
|
|
CGContextRef c;
|
|
|
|
BOOL useRGBA;
|
|
CGFloat r;
|
|
CGFloat g;
|
|
CGFloat b;
|
|
CGFloat a;
|
|
};
|
|
|
|
uiDrawContext *newContext(CGContextRef ctxt)
|
|
{
|
|
uiDrawContext *c;
|
|
|
|
// TODO use uiNew
|
|
c = (uiDrawContext *) malloc(sizeof (uiDrawContext));
|
|
c->c = ctxt;
|
|
return c;
|
|
}
|
|
|
|
void uiDrawBeginPathRGB(uiDrawContext *c, uint8_t r, uint8_t g, uint8_t b)
|
|
{
|
|
c->useRGBA = YES;
|
|
c->r = ((CGFloat) r) / 255;
|
|
c->g = ((CGFloat) g) / 255;
|
|
c->b = ((CGFloat) b) / 255;
|
|
c->a = 1.0;
|
|
CGContextBeginPath(c->c);
|
|
}
|
|
|
|
void uiDrawBeginPathRGBA(uiDrawContext *c, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
|
{
|
|
c->useRGBA = YES;
|
|
c->r = ((CGFloat) r) / 255;
|
|
c->g = ((CGFloat) g) / 255;
|
|
c->b = ((CGFloat) b) / 255;
|
|
c->a = ((CGFloat) a) / 255;
|
|
CGContextBeginPath(c->c);
|
|
}
|
|
|
|
// TODO 0.25 for retina? some say yes, some say no
|
|
// TODO same adjustment for cairo
|
|
#define topoint(x) (((CGFloat) x) + 0.5)
|
|
|
|
void uiDrawMoveTo(uiDrawContext *c, intmax_t x, intmax_t y)
|
|
{
|
|
CGContextMoveToPoint(c->c, topoint(x), topoint(y));
|
|
}
|
|
|
|
void uiDrawLineTo(uiDrawContext *c, intmax_t x, intmax_t y)
|
|
{
|
|
CGContextAddLineToPoint(c->c, topoint(x), topoint(y));
|
|
}
|
|
|
|
// TODO width-1/height-1? (also for cairo)
|
|
void uiDrawRectangle(uiDrawContext *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height)
|
|
{
|
|
CGContextAddRect(c->c, CGRectMake(topoint(x), topoint(y), width, height));
|
|
}
|
|
|
|
void uiDrawArcTo(uiDrawContext *c, intmax_t xCenter, intmax_t yCenter, intmax_t radius, double startAngle, double endAngle, int lineFromCurrentPointToStart)
|
|
{
|
|
if (!lineFromCurrentPointToStart) {
|
|
// see http://stackoverflow.com/questions/31489157/extra-line-when-drawing-an-arc-in-swift
|
|
// TODO verify correctness
|
|
CGFloat x, y;
|
|
|
|
x = topoint(xCenter);
|
|
y = topoint(yCenter);
|
|
x += radius * cos(startAngle);
|
|
y -= radius * sin(startAngle);
|
|
CGContextMoveToPoint(c->c, x, y);
|
|
}
|
|
CGContextAddArc(c->c,
|
|
topoint(xCenter), topoint(yCenter),
|
|
radius,
|
|
startAngle, endAngle,
|
|
0);
|
|
}
|
|
|
|
void uiDrawBezierTo(uiDrawContext *c, intmax_t c1x, intmax_t c1y, intmax_t c2x, intmax_t c2y, intmax_t endX, intmax_t endY)
|
|
{
|
|
CGContextAddCurveToPoint(c->c,
|
|
topoint(c1x), topoint(c1y),
|
|
topoint(c2x), topoint(c2y),
|
|
topoint(endX), topoint(endY));
|
|
}
|
|
|
|
void uiDrawCloseFigure(uiDrawContext *c)
|
|
{
|
|
CGContextClosePath(c->c);
|
|
}
|
|
|
|
void uiDrawStroke(uiDrawContext *c, uiDrawStrokeParams *p)
|
|
{
|
|
switch (p->Cap) {
|
|
case uiDrawLineCapFlat:
|
|
CGContextSetLineCap(c->c, kCGLineCapButt);
|
|
break;
|
|
case uiDrawLineCapRound:
|
|
CGContextSetLineCap(c->c, kCGLineCapRound);
|
|
break;
|
|
case uiDrawLineCapSquare:
|
|
CGContextSetLineCap(c->c, kCGLineCapSquare);
|
|
break;
|
|
}
|
|
switch (p->Join) {
|
|
case uiDrawLineJoinMiter:
|
|
CGContextSetLineJoin(c->c, kCGLineJoinMiter);
|
|
CGContextSetMiterLimit(c->c, p->MiterLimit);
|
|
break;
|
|
case uiDrawLineJoinRound:
|
|
CGContextSetLineJoin(c->c, kCGLineJoinRound);
|
|
break;
|
|
case uiDrawLineJoinBevel:
|
|
CGContextSetLineJoin(c->c, kCGLineJoinBevel);
|
|
break;
|
|
}
|
|
CGContextSetLineWidth(c->c, p->Thickness);
|
|
if (c->useRGBA)
|
|
CGContextSetRGBStrokeColor(c->c, c->r, c->g, c->b, c->a);
|
|
else {
|
|
// TODO
|
|
}
|
|
CGContextStrokePath(c->c);
|
|
}
|
|
|
|
void uiDrawFill(uiDrawContext *c, uiDrawFillMode mode)
|
|
{
|
|
if (c->useRGBA)
|
|
CGContextSetRGBFillColor(c->c, c->r, c->g, c->b, c->a);
|
|
else {
|
|
// TODO
|
|
}
|
|
switch (mode) {
|
|
case uiDrawFillModeWinding:
|
|
CGContextFillPath(c->c);
|
|
break;
|
|
case uiDrawFillModeAlternate:
|
|
CGContextEOFillPath(c->c);
|
|
break;
|
|
}
|
|
}
|