- added function to allow to combine scissor rects using intersectionshared-context
@@ -1017,6 +1017,42 @@ void drawCaps(NVGcontext* vg, float x, float y, float width) | |||
nvgRestore(vg); | |||
} | |||
void drawScissor(NVGcontext* vg, float x, float y, float t) | |||
{ | |||
nvgSave(vg); | |||
// Draw first rect and set scissor to it's area. | |||
nvgTranslate(vg, x, y); | |||
nvgRotate(vg, nvgDegToRad(5)); | |||
nvgBeginPath(vg); | |||
nvgRect(vg, -20,-20,60,40); | |||
nvgFillColor(vg, nvgRGBA(255,0,0,255)); | |||
nvgFill(vg); | |||
nvgScissor(vg, -20,-20,60,40); | |||
// Draw second rectangle with offset and rotation. | |||
nvgTranslate(vg, 40,0); | |||
nvgRotate(vg, t); | |||
// Draw the intended second rectangle without any scissoring. | |||
nvgSave(vg); | |||
nvgResetScissor(vg); | |||
nvgBeginPath(vg); | |||
nvgRect(vg, -20,-10,60,30); | |||
nvgFillColor(vg, nvgRGBA(255,128,0,64)); | |||
nvgFill(vg); | |||
nvgRestore(vg); | |||
// Draw second rectangle with combined scissoring. | |||
nvgIntersectScissor(vg, -20,-10,60,30); | |||
nvgBeginPath(vg); | |||
nvgRect(vg, -20,-10,60,30); | |||
nvgFillColor(vg, nvgRGBA(255,128,0,255)); | |||
nvgFill(vg); | |||
nvgRestore(vg); | |||
} | |||
void renderDemo(NVGcontext* vg, float mx, float my, float width, float height, | |||
float t, int blowup, DemoData* data) | |||
{ | |||
@@ -1028,7 +1064,7 @@ void renderDemo(NVGcontext* vg, float mx, float my, float width, float height, | |||
drawColorwheel(vg, width - 300, height - 300, 250.0f, 250.0f, t); | |||
// Line joints | |||
drawLines(vg, 50, height-50, 600, 50, t); | |||
drawLines(vg, 120, height-50, 600, 50, t); | |||
// Line caps | |||
drawWidths(vg, 10, 50, 30); | |||
@@ -1036,6 +1072,8 @@ void renderDemo(NVGcontext* vg, float mx, float my, float width, float height, | |||
// Line caps | |||
drawCaps(vg, 10, 300, 30); | |||
drawScissor(vg, 50, height-80, t); | |||
nvgSave(vg); | |||
if (blowup) { | |||
nvgRotate(vg, sinf(t*0.3f)*5.0f/180.0f*NVG_PI); | |||
@@ -881,6 +881,49 @@ void nvgScissor(NVGcontext* ctx, float x, float y, float w, float h) | |||
state->scissor.extent[1] = h*0.5f; | |||
} | |||
static void nvg__isectRects(float* dst, | |||
float ax, float ay, float aw, float ah, | |||
float bx, float by, float bw, float bh) | |||
{ | |||
float minx = nvg__maxf(ax, bx); | |||
float miny = nvg__maxf(ay, by); | |||
float maxx = nvg__minf(ax+aw, bx+bw); | |||
float maxy = nvg__minf(ay+ah, by+bh); | |||
dst[0] = minx; | |||
dst[1] = miny; | |||
dst[2] = nvg__maxf(0.0f, maxx - minx); | |||
dst[3] = nvg__maxf(0.0f, maxy - miny); | |||
} | |||
void nvgIntersectScissor(NVGcontext* ctx, float x, float y, float w, float h) | |||
{ | |||
NVGstate* state = nvg__getState(ctx); | |||
float pxform[6], invxorm[6]; | |||
float rect[4]; | |||
float ex, ey, tex, tey; | |||
// If no previous scissor has been set, set the scissor as current scissor. | |||
if (state->scissor.extent[0] < 0) { | |||
nvgScissor(ctx, x, y, w, h); | |||
return; | |||
} | |||
// Transform the current scissor rect into current transform space. | |||
// If there is difference in rotation, this will be approximation. | |||
memcpy(pxform, state->scissor.xform, sizeof(float)*6); | |||
ex = state->scissor.extent[0]; | |||
ey = state->scissor.extent[1]; | |||
nvgTransformInverse(invxorm, state->xform); | |||
nvgTransformMultiply(pxform, invxorm); | |||
tex = ex*nvg__absf(pxform[0]) + ey*nvg__absf(pxform[2]); | |||
tey = ex*nvg__absf(pxform[1]) + ey*nvg__absf(pxform[3]); | |||
// Intersect rects. | |||
nvg__isectRects(rect, pxform[4]-tex,pxform[5]-tey,tex*2,tey*2, x,y,w,h); | |||
nvgScissor(ctx, rect[0], rect[1], rect[2], rect[3]); | |||
} | |||
void nvgResetScissor(NVGcontext* ctx) | |||
{ | |||
NVGstate* state = nvg__getState(ctx); | |||
@@ -370,10 +370,18 @@ NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey | |||
// Scissoring allows you to clip the rendering into a rectangle. This is useful for varius | |||
// user interface cases like rendering a text edit or a timeline. | |||
// Sets the current | |||
// Sets the current scissor rectangle. | |||
// The scissor rectangle is transformed by the current transform. | |||
void nvgScissor(NVGcontext* ctx, float x, float y, float w, float h); | |||
// Intersects current scissor rectangle with the specified rectangle. | |||
// The scissor rectangle is transformed by the current transform. | |||
// Note: in case the rotation of previous scissor rect differs from | |||
// the current one, the intersection will be done between the specified | |||
// rectangle and the previous scissor rectangle transformed in the current | |||
// transform space. The resulting shape is always rectangle. | |||
void nvgIntersectScissor(NVGcontext* ctx, float x, float y, float w, float h); | |||
// Reset and disables scissoring. | |||
void nvgResetScissor(NVGcontext* ctx); | |||