static void shDrawPaintMesh(VGContext *c, SHVector2 *min, SHVector2 *max, VGPaintMode mode, GLenum texUnit) { SHPaint *p; SHVector2 pmin, pmax; SHfloat K = 1.0f; /* Pick the right paint */ if (mode == VG_FILL_PATH) { p = (c->fillPaint ? c->fillPaint : &c->defaultPaint); }else if (mode == VG_STROKE_PATH) { p = (c->strokePaint ? c->strokePaint : &c->defaultPaint); K = SH_CEIL(c->strokeMiterLimit * c->strokeLineWidth) + 1.0f; } /* We want to be sure to cover every pixel of this path so better take a pixel more than leave some out (multisampling is tricky). */ SET2V(pmin, (*min)); SUB2(pmin, K,K); SET2V(pmax, (*max)); ADD2(pmax, K,K); /* Construct appropriate OpenGL primitives so as to fill the stencil mask with select paint */ switch (p->type) { case VG_PAINT_TYPE_LINEAR_GRADIENT: shDrawLinearGradientMesh(p, min, max, mode, texUnit); break; case VG_PAINT_TYPE_RADIAL_GRADIENT: shDrawRadialGradientMesh(p, min, max, mode, texUnit); break; case VG_PAINT_TYPE_PATTERN: if (p->pattern != VG_INVALID_HANDLE) { shDrawPatternMesh(p, min, max, mode, texUnit); break; }/* else behave as a color paint */ case VG_PAINT_TYPE_COLOR: glColor4fv((GLfloat*)&p->color); glBegin(GL_QUADS); glVertex2f(pmin.x, pmin.y); glVertex2f(pmax.x, pmin.y); glVertex2f(pmax.x, pmax.y); glVertex2f(pmin.x, pmax.y); glEnd(); break; } }
int shDrawLinearGradientMesh(SHPaint *p, SHVector2 *min, SHVector2 *max, VGPaintMode mode, GLenum texUnit) { SHint i; SHfloat n; SHfloat x1 = p->linearGradient[0]; SHfloat y1 = p->linearGradient[1]; SHfloat x2 = p->linearGradient[2]; SHfloat y2 = p->linearGradient[3]; SHVector2 c, ux, uy; SHVector2 cc, uux, uuy; SHMatrix3x3 *m; SHMatrix3x3 mi; SHint invertible; SHVector2 corners[4]; SHfloat minOffset = 0.0f; SHfloat maxOffset = 0.0f; SHfloat left = 0.0f; SHfloat right = 0.0f; SHVector2 l1,r1,l2,r2; /* Pick paint transform matrix */ SH_GETCONTEXT(0); if (mode == VG_FILL_PATH) m = &context->fillTransform; else if (mode == VG_STROKE_PATH) m = &context->strokeTransform; /* Gradient center and unit vectors */ SET2(c, x1, y1); SET2(ux, x2-x1, y2-y1); SET2(uy, -ux.y, ux.x); n = NORM2(ux); DIV2(ux, n); NORMALIZE2(uy); /* Apply paint-to-user transformation */ ADD2V(ux, c); ADD2V(uy, c); TRANSFORM2TO(c, (*m), cc); TRANSFORM2TO(ux, (*m), uux); TRANSFORM2TO(uy, (*m), uuy); SUB2V(ux,c); SUB2V(uy,c); SUB2V(uux,cc); SUB2V(uuy,cc); /* Boundbox corners */ SET2(corners[0], min->x, min->y); SET2(corners[1], max->x, min->y); SET2(corners[2], max->x, max->y); SET2(corners[3], min->x, max->y); /* Find inverse transformation (back to paint space) */ invertible = shInvertMatrix(m, &mi); if (!invertible || n==0.0f) { /* Fill boundbox with color at offset 1 */ SHColor *c = &p->stops.items[p->stops.size-1].color; glColor4fv((GLfloat*)c); glBegin(GL_QUADS); for (i=0; i<4; ++i) glVertex2fv((GLfloat*)&corners[i]); glEnd(); return 1; } /*--------------------------------------------------------*/ for (i=0; i<4; ++i) { /* Find min/max offset and perpendicular span */ SHfloat o, s; TRANSFORM2(corners[i], mi); SUB2V(corners[i], c); o = DOT2(corners[i], ux) / n; s = DOT2(corners[i], uy); if (o < minOffset || i==0) minOffset = o; if (o > maxOffset || i==0) maxOffset = o; if (s < left || i==0) left = s; if (s > right || i==0) right = s; } /*---------------------------------------------------------*/ /* Corners of boundbox in gradient system */ SET2V(l1, cc); SET2V(r1, cc); SET2V(l2, cc); SET2V(r2, cc); OFFSET2V(l1, uuy, left); OFFSET2V(l1, uux, minOffset * n); OFFSET2V(r1, uuy, right); OFFSET2V(r1, uux, minOffset * n); OFFSET2V(l2, uuy, left); OFFSET2V(l2, uux, maxOffset * n); OFFSET2V(r2, uuy, right); OFFSET2V(r2, uux, maxOffset * n); /* Draw quad using color-ramp texture */ glActiveTexture(texUnit); shSetGradientTexGLState(p); glEnable(GL_TEXTURE_1D); glBegin(GL_QUAD_STRIP); glMultiTexCoord1f(texUnit, minOffset); glVertex2fv((GLfloat*)&r1); glVertex2fv((GLfloat*)&l1); glMultiTexCoord1f(texUnit, maxOffset); glVertex2fv((GLfloat*)&r2); glVertex2fv((GLfloat*)&l2); glEnd(); glDisable(GL_TEXTURE_1D); return 1; }
static void shDrawPaintMesh(VGContext *c, SHVector2 *min, SHVector2 *max, VGPaintMode mode, GLenum texUnit) { SHPaint *p; SHVector2 pmin, pmax; SHfloat K = 1.0f; #ifdef ANDROIDVG SHColor *color; GLfloat v[6][2]; #endif /* Pick the right paint */ if (mode == VG_FILL_PATH) { p = (c->fillPaint ? c->fillPaint : &c->defaultPaint); }else if (mode == VG_STROKE_PATH) { p = (c->strokePaint ? c->strokePaint : &c->defaultPaint); K = SH_CEIL(c->strokeMiterLimit * c->strokeLineWidth) + 1.0f; } /* We want to be sure to cover every pixel of this path so better take a pixel more than leave some out (multisampling is tricky). */ SET2V(pmin, (*min)); SUB2(pmin, K,K); SET2V(pmax, (*max)); ADD2(pmax, K,K); /* Construct appropriate OpenGL primitives so as to fill the stencil mask with select paint */ switch (p->type) { case VG_PAINT_TYPE_LINEAR_GRADIENT: shDrawLinearGradientMesh(p, min, max, mode, texUnit); break; case VG_PAINT_TYPE_RADIAL_GRADIENT: shDrawRadialGradientMesh(p, min, max, mode, texUnit); break; case VG_PAINT_TYPE_PATTERN: if (p->pattern != VG_INVALID_HANDLE) { shDrawPatternMesh(p, min, max, mode, texUnit); break; }/* else behave as a color paint */ case VG_PAINT_TYPE_COLOR: #ifdef ANDROIDVG v[0][0] = pmin.x; v[0][1] = pmin.y; v[1][0] = pmax.x; v[1][1] = pmin.y; v[2][0] = pmax.x; v[2][1] = pmax.y; v[3][0] = pmin.x; v[3][1] = pmin.y; v[4][0] = pmax.x; v[4][1] = pmax.y; v[5][0] = pmin.x; v[5][1] = pmax.y; color = &p->color; glColor4f(color->r, color->g, color->b, color->a); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, v); glDrawArrays(GL_TRIANGLES, 0, 6); glDisableClientState(GL_VERTEX_ARRAY); #else glColor4fv((GLfloat*)&p->color); glBegin(GL_QUADS); glVertex2f(pmin.x, pmin.y); glVertex2f(pmax.x, pmin.y); glVertex2f(pmax.x, pmax.y); glVertex2f(pmin.x, pmax.y); glEnd(); #endif break; } }