diff --git a/src/nanovg.c b/src/nanovg.c index 5744b4a..bcd5bca 100644 --- a/src/nanovg.c +++ b/src/nanovg.c @@ -375,34 +375,33 @@ struct NVGcolor nvgHSLA(float h, float s, float l, unsigned char a) } - static struct NVGstate* nvg__getState(struct NVGcontext* ctx) { return &ctx->states[ctx->nstates-1]; } -static void nvg__xformIdentity(float* t) +void nvgTransformIdentity(float* t) { t[0] = 1.0f; t[1] = 0.0f; t[2] = 0.0f; t[3] = 1.0f; t[4] = 0.0f; t[5] = 0.0f; } -static void nvg__xformTranslate(float* t, float tx, float ty) +void nvgTransformTranslate(float* t, float tx, float ty) { t[0] = 1.0f; t[1] = 0.0f; t[2] = 0.0f; t[3] = 1.0f; t[4] = tx; t[5] = ty; } -static void nvg__xformScale(float* t, float sx, float sy) +void nvgTransformScale(float* t, float sx, float sy) { t[0] = sx; t[1] = 0.0f; t[2] = 0.0f; t[3] = sy; t[4] = 0.0f; t[5] = 0.0f; } -static void nvg__xformRotate(float* t, float a) +void nvgTransformRotate(float* t, float a) { float cs = nvg__cosf(a), sn = nvg__sinf(a); t[0] = cs; t[1] = sn; @@ -410,7 +409,21 @@ static void nvg__xformRotate(float* t, float a) t[4] = 0.0f; t[5] = 0.0f; } -static void nvg__xformMultiply(float* t, float* s) +void nvgTransformSkewX(float* t, float a) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = nvg__tanf(a); t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +void nvgTransformSkewY(float* t, float a) +{ + t[0] = 1.0f; t[1] = nvg__tanf(a); + t[2] = 0.0f; t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +void nvgTransformMultiply(float* t, const float* s) { float t0 = t[0] * s[0] + t[1] * s[2]; float t2 = t[2] * s[0] + t[3] * s[2]; @@ -423,18 +436,51 @@ static void nvg__xformMultiply(float* t, float* s) t[4] = t4; } -static void nvg__xformPremultiply(float* t, float* s) +void nvgTransformPremultiply(float* t, const float* s) { float s2[6]; memcpy(s2, s, sizeof(float)*6); - nvg__xformMultiply(s2, t); + nvgTransformMultiply(s2, t); memcpy(t, s2, sizeof(float)*6); } +int nvgTransformInverse(float* inv, const float* t) +{ + double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; + if (det > -1e-6 && det < 1e-6) { + nvgTransformIdentity(inv); + return 0; + } + invdet = 1.0 / det; + inv[0] = (float)(t[3] * invdet); + inv[2] = (float)(-t[2] * invdet); + inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); + inv[1] = (float)(-t[1] * invdet); + inv[3] = (float)(t[0] * invdet); + inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); + return 1; +} + +void nvgTransformPoint(float* dx, float* dy, const float* t, float sx, float sy) +{ + *dx = sx*t[0] + sy*t[2] + t[4]; + *dy = sx*t[1] + sy*t[3] + t[5]; +} + +float nvgDegToRad(float deg) +{ + return deg / 180.0f * NVG_PI; +} + +float nvgRadToDeg(float rad) +{ + return rad / NVG_PI * 180.0f; +} + static void nvg__setPaintColor(struct NVGpaint* p, struct NVGcolor color) { memset(p, 0, sizeof(*p)); - nvg__xformIdentity(p->xform); + nvgTransformIdentity(p->xform); p->radius = 0.0f; p->feather = 1.0f; p->innerColor = color; @@ -470,7 +516,7 @@ void nvgReset(struct NVGcontext* ctx) state->miterLimit = 10.0f; state->lineCap = NVG_BUTT; state->lineJoin = NVG_MITER; - nvg__xformIdentity(state->xform); + nvgTransformIdentity(state->xform); state->scissor.extent[0] = 0.0f; state->scissor.extent[1] = 0.0f; @@ -513,39 +559,61 @@ void nvgTransform(struct NVGcontext* ctx, float a, float b, float c, float d, fl { struct NVGstate* state = nvg__getState(ctx); float t[6] = { a, b, c, d, e, f }; - nvg__xformPremultiply(state->xform, t); + nvgTransformPremultiply(state->xform, t); } void nvgResetTransform(struct NVGcontext* ctx) { struct NVGstate* state = nvg__getState(ctx); - nvg__xformIdentity(state->xform); + nvgTransformIdentity(state->xform); } void nvgTranslate(struct NVGcontext* ctx, float x, float y) { struct NVGstate* state = nvg__getState(ctx); float t[6]; - nvg__xformTranslate(t, x,y); - nvg__xformPremultiply(state->xform, t); + nvgTransformTranslate(t, x,y); + nvgTransformPremultiply(state->xform, t); } void nvgRotate(struct NVGcontext* ctx, float angle) { struct NVGstate* state = nvg__getState(ctx); float t[6]; - nvg__xformRotate(t, angle); - nvg__xformPremultiply(state->xform, t); + nvgTransformRotate(t, angle); + nvgTransformPremultiply(state->xform, t); +} + +void nvgSkewX(struct NVGcontext* ctx, float angle) +{ + struct NVGstate* state = nvg__getState(ctx); + float t[6]; + nvgTransformSkewX(t, angle); + nvgTransformPremultiply(state->xform, t); +} + +void nvgSkewY(struct NVGcontext* ctx, float angle) +{ + struct NVGstate* state = nvg__getState(ctx); + float t[6]; + nvgTransformSkewY(t, angle); + nvgTransformPremultiply(state->xform, t); } void nvgScale(struct NVGcontext* ctx, float x, float y) { struct NVGstate* state = nvg__getState(ctx); float t[6]; - nvg__xformScale(t, x,y); - nvg__xformPremultiply(state->xform, t); + nvgTransformScale(t, x,y); + nvgTransformPremultiply(state->xform, t); } +void nvgCurrentTransform(struct NVGcontext* ctx, float* xform) +{ + struct NVGstate* state = nvg__getState(ctx); + if (xform == NULL) return; + memcpy(xform, state->xform, sizeof(float)*6); +} void nvgStrokeColor(struct NVGcontext* ctx, struct NVGcolor color) { @@ -557,7 +625,7 @@ void nvgStrokePaint(struct NVGcontext* ctx, struct NVGpaint paint) { struct NVGstate* state = nvg__getState(ctx); state->stroke = paint; - nvg__xformMultiply(state->stroke.xform, state->xform); + nvgTransformMultiply(state->stroke.xform, state->xform); } void nvgFillColor(struct NVGcontext* ctx, struct NVGcolor color) @@ -570,7 +638,7 @@ void nvgFillPaint(struct NVGcontext* ctx, struct NVGpaint paint) { struct NVGstate* state = nvg__getState(ctx); state->fill = paint; - nvg__xformMultiply(state->fill.xform, state->xform); + nvgTransformMultiply(state->fill.xform, state->xform); } int nvgCreateImage(struct NVGcontext* ctx, const char* filename) @@ -670,7 +738,7 @@ struct NVGpaint nvgRadialGradient(struct NVGcontext* ctx, NVG_NOTUSED(ctx); memset(&p, 0, sizeof(p)); - nvg__xformIdentity(p.xform); + nvgTransformIdentity(p.xform); p.xform[4] = cx; p.xform[5] = cy; @@ -695,7 +763,7 @@ struct NVGpaint nvgBoxGradient(struct NVGcontext* ctx, NVG_NOTUSED(ctx); memset(&p, 0, sizeof(p)); - nvg__xformIdentity(p.xform); + nvgTransformIdentity(p.xform); p.xform[4] = x+w*0.5f; p.xform[5] = y+h*0.5f; @@ -721,7 +789,7 @@ struct NVGpaint nvgImagePattern(struct NVGcontext* ctx, NVG_NOTUSED(ctx); memset(&p, 0, sizeof(p)); - nvg__xformRotate(p.xform, angle); + nvgTransformRotate(p.xform, angle); p.xform[4] = cx; p.xform[5] = cy; @@ -739,10 +807,10 @@ void nvgScissor(struct NVGcontext* ctx, float x, float y, float w, float h) { struct NVGstate* state = nvg__getState(ctx); - nvg__xformIdentity(state->scissor.xform); + nvgTransformIdentity(state->scissor.xform); state->scissor.xform[4] = x+w*0.5f; state->scissor.xform[5] = y+h*0.5f; - nvg__xformMultiply(state->scissor.xform, state->xform); + nvgTransformMultiply(state->scissor.xform, state->xform); state->scissor.extent[0] = w*0.5f; state->scissor.extent[1] = h*0.5f; @@ -756,12 +824,6 @@ void nvgResetScissor(struct NVGcontext* ctx) state->scissor.extent[1] = 0; } -static void nvg__xformPt(float* dx, float* dy, float sx, float sy, const float* t) -{ - *dx = sx*t[0] + sy*t[2] + t[4]; - *dy = sx*t[1] + sy*t[3] + t[5]; -} - static int nvg__ptEquals(float x1, float y1, float x2, float y2, float tol) { float dx = x2 - x1; @@ -805,17 +867,17 @@ static void nvg__appendCommands(struct NVGcontext* ctx, float* vals, int nvals) int cmd = (int)vals[i]; switch (cmd) { case NVG_MOVETO: - nvg__xformPt(&vals[i+1],&vals[i+2], vals[i+1],vals[i+2], state->xform); + nvgTransformPoint(&vals[i+1],&vals[i+2], state->xform, vals[i+1],vals[i+2]); i += 3; break; case NVG_LINETO: - nvg__xformPt(&vals[i+1],&vals[i+2], vals[i+1],vals[i+2], state->xform); + nvgTransformPoint(&vals[i+1],&vals[i+2], state->xform, vals[i+1],vals[i+2]); i += 3; break; case NVG_BEZIERTO: - nvg__xformPt(&vals[i+1],&vals[i+2], vals[i+1],vals[i+2], state->xform); - nvg__xformPt(&vals[i+3],&vals[i+4], vals[i+3],vals[i+4], state->xform); - nvg__xformPt(&vals[i+5],&vals[i+6], vals[i+5],vals[i+6], state->xform); + nvgTransformPoint(&vals[i+1],&vals[i+2], state->xform, vals[i+1],vals[i+2]); + nvgTransformPoint(&vals[i+3],&vals[i+4], state->xform, vals[i+3],vals[i+4]); + nvgTransformPoint(&vals[i+5],&vals[i+6], state->xform, vals[i+5],vals[i+6]); i += 7; break; case NVG_CLOSE: @@ -1973,10 +2035,10 @@ float nvgText(struct NVGcontext* ctx, float x, float y, const char* string, cons while (fonsTextIterNext(ctx->fs, &iter, &q)) { // Trasnform corners. float c[4*2]; - nvg__xformPt(&c[0],&c[1], q.x0*invscale, q.y0*invscale, state->xform); - nvg__xformPt(&c[2],&c[3], q.x1*invscale, q.y0*invscale, state->xform); - nvg__xformPt(&c[4],&c[5], q.x1*invscale, q.y1*invscale, state->xform); - nvg__xformPt(&c[6],&c[7], q.x0*invscale, q.y1*invscale, state->xform); + nvgTransformPoint(&c[0],&c[1], state->xform, q.x0*invscale, q.y0*invscale); + nvgTransformPoint(&c[2],&c[3], state->xform, q.x1*invscale, q.y0*invscale); + nvgTransformPoint(&c[4],&c[5], state->xform, q.x1*invscale, q.y1*invscale); + nvgTransformPoint(&c[6],&c[7], state->xform, q.x0*invscale, q.y1*invscale); // Create triangles if (nverts+6 <= cverts) { nvg__vset(&verts[nverts], c[0], c[1], q.s0, q.t0); nverts++; diff --git a/src/nanovg.h b/src/nanovg.h index 2879d2f..7dd0b15 100644 --- a/src/nanovg.h +++ b/src/nanovg.h @@ -237,12 +237,64 @@ void nvgTransform(struct NVGcontext* ctx, float a, float b, float c, float d, fl // Translates current coordinate system. void nvgTranslate(struct NVGcontext* ctx, float x, float y); -// Rotates current coordinate system. +// Rotates current coordinate system. Angle is specifid in radians. void nvgRotate(struct NVGcontext* ctx, float angle); +// Skews the current coordinate system along X axis. Angle is specifid in radians. +void nvgSkewX(struct NVGcontext* ctx, float angle); + +// Skews the current coordinate system along Y axis. Angle is specifid in radians. +void nvgSkewY(struct NVGcontext* ctx, float angle); + // Scales the current coordinat system. void nvgScale(struct NVGcontext* ctx, float x, float y); +// Stores the top part (a-f) of the current transformation matrix in to the specified buffer. +// [a c e] +// [b d f] +// [0 0 1] +// There should be space for 6 floats in the return buffer for the values a-f. +void nvgCurrentTransform(struct NVGcontext* ctx, float* xform); + + +// The following functions can be used to make calculations on 2x3 transformation matrices. +// A 2x3 matrix is representated as float[6]. + +// Sets the transform to identity matrix. +void nvgTransformIdentity(float* dst); + +// Sets the transform to translation matrix matrix. +void nvgTransformTranslate(float* dst, float tx, float ty); + +// Sets the transform to scale matrix. +void nvgTransformScale(float* dst, float sx, float sy); + +// Sets the transform to rotate matrix. Angle is specifid in radians. +void nvgTransformRotate(float* dst, float a); + +// Sets the transform to skew-x matrix. Angle is specifid in radians. +void nvgTransformSkewX(float* dst, float a); + +// Sets the transform to skew-y matrix. Angle is specifid in radians. +void nvgTransformSkewY(float* dst, float a); + +// Sets the transform to the result of multiplication of two transforms, of A = A*B. +void nvgTransformMultiply(float* dst, const float* src); + +// Sets the transform to the result of multiplication of two transforms, of A = B*A. +void nvgTransformPremultiply(float* dst, const float* src); + +// Sets the destination to inverse of specified transform. +// Returns 1 if the inverse could be calculated, else 0. +int nvgTransformInverse(float* dst, const float* src); + +// Transform a point by given transform. +void nvgTransformPoint(float* dstx, float* dsty, const float* xform, float srcx, float srcy); + +// Converts degress to radians and vice versa. +float nvgDegToRad(float deg); +float nvgRadToDeg(float rad); + // // Images // diff --git a/src/nanovg_gl.h b/src/nanovg_gl.h index 9206129..26c227c 100644 --- a/src/nanovg_gl.h +++ b/src/nanovg_gl.h @@ -671,29 +671,6 @@ static int glnvg__renderGetTextureSize(void* uptr, int image, int* w, int* h) return 1; } -static void glnvg__xformIdentity(float* t) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = 0.0f; t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void glnvg__xformInverse(float* inv, float* t) -{ - double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; - if (det > -1e-6 && det < 1e-6) { - glnvg__xformIdentity(t); - return; - } - invdet = 1.0 / det; - inv[0] = (float)(t[3] * invdet); - inv[2] = (float)(-t[2] * invdet); - inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); - inv[1] = (float)(-t[1] * invdet); - inv[3] = (float)(t[0] * invdet); - inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); -} - static void glnvg__xformToMat3x4(float* m3, float* t) { m3[0] = t[0]; @@ -721,7 +698,7 @@ static int glnvg__convertPaint(struct GLNVGcontext* gl, struct GLNVGfragUniforms frag->innerCol = paint->innerColor; frag->outerCol = paint->outerColor; - glnvg__xformInverse(invxform, paint->xform); + nvgTransformInverse(invxform, paint->xform); glnvg__xformToMat3x4(frag->paintMat, invxform); if (scissor->extent[0] < 0.5f || scissor->extent[1] < 0.5f) { @@ -731,7 +708,7 @@ static int glnvg__convertPaint(struct GLNVGcontext* gl, struct GLNVGfragUniforms frag->scissorScale[0] = 1.0f; frag->scissorScale[1] = 1.0f; } else { - glnvg__xformInverse(invxform, scissor->xform); + nvgTransformInverse(invxform, scissor->xform); glnvg__xformToMat3x4(frag->scissorMat, invxform); frag->scissorExt[0] = scissor->extent[0]; frag->scissorExt[1] = scissor->extent[1];