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; }
/** * Determine type and flags from scratch. * * \param mat matrix. * * This is expensive enough to only want to do it once. */ static void analyse_from_scratch( GLmatrix *mat ) { const GLfloat *m = mat->m; GLuint mask = 0; GLuint i; for (i = 0 ; i < 16 ; i++) { if (m[i] == 0.0) mask |= (1<<i); } if (m[0] == 1.0F) mask |= (1<<16); if (m[5] == 1.0F) mask |= (1<<21); if (m[10] == 1.0F) mask |= (1<<26); if (m[15] == 1.0F) mask |= (1<<31); mat->flags &= ~MAT_FLAGS_GEOMETRY; /* Check for translation - no-one really cares */ if ((mask & MASK_NO_TRX) != MASK_NO_TRX) mat->flags |= MAT_FLAG_TRANSLATION; /* Do the real work */ if (mask == (GLuint) MASK_IDENTITY) { mat->type = MATRIX_IDENTITY; } else if ((mask & MASK_2D_NO_ROT) == (GLuint) MASK_2D_NO_ROT) { mat->type = MATRIX_2D_NO_ROT; if ((mask & MASK_NO_2D_SCALE) != MASK_NO_2D_SCALE) mat->flags |= MAT_FLAG_GENERAL_SCALE; } else if ((mask & MASK_2D) == (GLuint) MASK_2D) { GLfloat mm = DOT2(m, m); GLfloat m4m4 = DOT2(m+4,m+4); GLfloat mm4 = DOT2(m,m+4); mat->type = MATRIX_2D; /* Check for scale */ if (SQ(mm-1) > SQ(1e-6) || SQ(m4m4-1) > SQ(1e-6)) mat->flags |= MAT_FLAG_GENERAL_SCALE; /* Check for rotation */ if (SQ(mm4) > SQ(1e-6)) mat->flags |= MAT_FLAG_GENERAL_3D; else mat->flags |= MAT_FLAG_ROTATION; } else if ((mask & MASK_3D_NO_ROT) == (GLuint) MASK_3D_NO_ROT) { mat->type = MATRIX_3D_NO_ROT; /* Check for scale */ if (SQ(m[0]-m[5]) < SQ(1e-6) && SQ(m[0]-m[10]) < SQ(1e-6)) { if (SQ(m[0]-1.0) > SQ(1e-6)) { mat->flags |= MAT_FLAG_UNIFORM_SCALE; } } else { mat->flags |= MAT_FLAG_GENERAL_SCALE; } } else if ((mask & MASK_3D) == (GLuint) MASK_3D) { GLfloat c1 = DOT3(m,m); GLfloat c2 = DOT3(m+4,m+4); GLfloat c3 = DOT3(m+8,m+8); GLfloat d1 = DOT3(m, m+4); GLfloat cp[3]; mat->type = MATRIX_3D; /* Check for scale */ if (SQ(c1-c2) < SQ(1e-6) && SQ(c1-c3) < SQ(1e-6)) { if (SQ(c1-1.0) > SQ(1e-6)) mat->flags |= MAT_FLAG_UNIFORM_SCALE; /* else no scale at all */ } else { mat->flags |= MAT_FLAG_GENERAL_SCALE; } /* Check for rotation */ if (SQ(d1) < SQ(1e-6)) { CROSS3( cp, m, m+4 ); SUB_3V( cp, cp, (m+8) ); if (LEN_SQUARED_3FV(cp) < SQ(1e-6)) mat->flags |= MAT_FLAG_ROTATION; else mat->flags |= MAT_FLAG_GENERAL_3D; } else { mat->flags |= MAT_FLAG_GENERAL_3D; /* shear, etc */ } } else if ((mask & MASK_PERSPECTIVE) == MASK_PERSPECTIVE && m[11]==-1.0F) { mat->type = MATRIX_PERSPECTIVE; mat->flags |= MAT_FLAG_GENERAL; } else { mat->type = MATRIX_GENERAL; mat->flags |= MAT_FLAG_GENERAL; } }