- 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); | |||