//const float defaultViewportScale = 800f; public static SVGMatrix GetFillTransform(SVGFill svgFill, Rect bounds, SVGLength[] gradientStart, SVGLength[] gradientEnd, SVGMatrix fillTransform, SVGMatrix gradientTransform) { SVGMatrix transform = SVGMatrix.identity; SVGLength gradientStartX = gradientStart[0]; SVGLength gradientStartY = gradientStart[1]; SVGLength gradientEndX = gradientEnd[0]; SVGLength gradientEndY = gradientEnd[1]; Rect viewport = svgFill.viewport; //Debug.Log(viewport); if (svgFill.fillType == FILL_TYPE.GRADIENT) { switch (svgFill.gradientType) { case GRADIENT_TYPE.LINEAR: { Vector2 startPoint = GetGradientVector(gradientStartX, gradientStartY, bounds); Vector2 endPoint = GetGradientVector(gradientEndX, gradientEndY, bounds); Vector2 gradientVector = endPoint - startPoint; Vector2 normalizedVector = Vector2.zero; float angle = Mathf.Atan2(gradientVector.y, gradientVector.x) * Mathf.Rad2Deg; Vector2 posDiff = Vector2.Lerp(startPoint, endPoint, 0.5f); float magnitude = gradientVector.magnitude; if (magnitude != 0f) { normalizedVector.x = viewport.width / magnitude; normalizedVector.y = viewport.height / magnitude; } transform = transform.Translate(viewport.center); transform = transform.Scale(normalizedVector.x, normalizedVector.y); transform = transform.Rotate(-angle); transform = transform.Translate(-posDiff); transform = transform.Multiply(gradientTransform.Inverse()); transform = transform.Multiply(fillTransform.Inverse()); break; } case GRADIENT_TYPE.RADIAL: { Vector2 point = GetGradientVector(gradientStartX, gradientStartY, bounds); float radius = GetGradientVector(gradientEndX, gradientEndY, bounds).x; if (gradientEndX.unitType == SVGLengthType.Percentage) { radius *= 0.5f; } float radiusTimesTwo = radius * 2f; Vector2 normalizedVector = Vector2.zero; if (radiusTimesTwo != 0f) { normalizedVector.x = viewport.width / radiusTimesTwo; normalizedVector.y = viewport.height / radiusTimesTwo; } transform = transform.Translate(viewport.center); transform = transform.Scale(normalizedVector.x, normalizedVector.y); transform = transform.Translate(-point); transform = transform.Multiply(gradientTransform.Inverse()); transform = transform.Multiply(fillTransform.Inverse()); break; } case GRADIENT_TYPE.CONICAL: { Vector2 point = GetGradientVector(gradientStartX, gradientStartY, bounds); float radius = GetGradientVector(gradientEndX, gradientEndY, bounds).x; if (gradientEndX.unitType == SVGLengthType.Percentage) { radius *= 0.5f; } float radiusTimesTwo = radius * 2f; Vector2 normalizedVector = Vector2.zero; if (radiusTimesTwo != 0f) { normalizedVector.x = viewport.width / radiusTimesTwo; normalizedVector.y = viewport.height / radiusTimesTwo; } transform = transform.Translate(viewport.center); transform = transform.Scale(normalizedVector.x, normalizedVector.y); transform = transform.Translate(-point); transform = transform.Multiply(gradientTransform.Inverse()); transform = transform.Multiply(fillTransform.Inverse()); break; } } } return(transform); }
//const float defaultViewportScale = 800f; private static SVGMatrix GetFillTransform(SVGPaintable svgPaintable, Rect bounds) { SVGFill svgFill = svgPaintable.svgFill; SVGMatrix transform = new SVGMatrix(); SVGMatrix gradientMatrix = svgFill.gradientTransform; Rect viewport = svgPaintable.viewport; if (svgFill.fillType == FILL_TYPE.GRADIENT) { switch (svgFill.gradientType) { case GRADIENT_TYPE.LINEAR: { Vector2 startPoint = GetGradientVector(svgFill.gradientStartX, svgFill.gradientStartY, bounds); Vector2 endPoint = GetGradientVector(svgFill.gradientEndX, svgFill.gradientEndY, bounds); Vector2 gradientVector = endPoint - startPoint; Vector2 normalizedVector = Vector2.zero; float angle = Mathf.Atan2(gradientVector.y, gradientVector.x) * Mathf.Rad2Deg; Vector2 posDiff = Vector2.Lerp(startPoint, endPoint, 0.5f); float magnitude = gradientVector.magnitude; if (magnitude != 0f) { normalizedVector.x = viewport.width / magnitude; normalizedVector.y = viewport.height / magnitude; } transform = transform.Translate(viewport.center); transform = transform.ScaleNonUniform(normalizedVector.x, normalizedVector.y); transform = transform.Rotate(-angle); transform = transform.Translate(-posDiff); transform = transform.Multiply(gradientMatrix.Inverse()); transform = transform.Multiply(svgFill.transform.Inverse()); break; } case GRADIENT_TYPE.RADIAL: { Vector2 point = GetGradientVector(svgFill.gradientStartX, svgFill.gradientStartY, bounds); float radius = GetGradientVector(svgFill.gradientEndX, svgFill.gradientEndY, bounds).x; if (svgFill.gradientEndX.unitType == SVGLengthType.Percentage) { radius *= 0.5f; } float radiusTimesTwo = radius * 2f; Vector2 normalizedVector = Vector2.zero; if (radiusTimesTwo != 0f) { normalizedVector.x = viewport.width / radiusTimesTwo; normalizedVector.y = viewport.height / radiusTimesTwo; } transform = transform.Translate(viewport.center); transform = transform.ScaleNonUniform(normalizedVector.x, normalizedVector.y); transform = transform.Translate(-point); transform = transform.Multiply(gradientMatrix.Inverse()); transform = transform.Multiply(svgFill.transform.Inverse()); break; } case GRADIENT_TYPE.CONICAL: { Vector2 point = GetGradientVector(svgFill.gradientStartX, svgFill.gradientStartY, bounds); float radius = GetGradientVector(svgFill.gradientEndX, svgFill.gradientEndY, bounds).x; if (svgFill.gradientEndX.unitType == SVGLengthType.Percentage) { radius *= 0.5f; } float radiusTimesTwo = radius * 2f; Vector2 normalizedVector = Vector2.zero; if (radiusTimesTwo != 0f) { normalizedVector.x = viewport.width / radiusTimesTwo; normalizedVector.y = viewport.height / radiusTimesTwo; } transform = transform.Translate(viewport.center); transform = transform.ScaleNonUniform(normalizedVector.x, normalizedVector.y); transform = transform.Translate(-point); transform = transform.Multiply(gradientMatrix.Inverse()); transform = transform.Multiply(svgFill.transform.Inverse()); break; } } } return(transform); }
public static bool CreatePolygon(List <List <Vector2> > inputShapes, SVGPaintable paintable, SVGMatrix matrix, out SVGShape layer, out SVGShape antialiasingLayer, bool isStroke = false, bool antialiasing = false) { layer = new SVGShape(); antialiasingLayer = new SVGShape(); if (inputShapes == null || inputShapes.Count == 0) { return(false); } List <List <Vector2> > simplifiedShapes = new List <List <Vector2> >(); PolyFillType fillType = PolyFillType.pftNonZero; if (paintable.fillRule == SVGFillRule.EvenOdd) { fillType = PolyFillType.pftEvenOdd; } simplifiedShapes = SVGGeom.SimplifyPolygons(inputShapes, fillType); if (simplifiedShapes == null || simplifiedShapes.Count == 0) { return(false); } AddInputShape(simplifiedShapes); Rect bounds = GetRect(simplifiedShapes); Rect viewport = paintable.viewport; if (!isStroke) { switch (paintable.GetPaintType()) { case SVGPaintMethod.SolidFill: { layer.type = SVGShapeType.FILL; Color color = Color.black; SVGColorType colorType = paintable.fillColor.Value.colorType; if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None) { color.a *= paintable.fillOpacity; paintable.svgFill = new SVGFill(color); } else { color = paintable.fillColor.Value.color; color.a *= paintable.fillOpacity; paintable.svgFill = new SVGFill(color); } paintable.svgFill.fillType = FILL_TYPE.SOLID; if (color.a == 1) { paintable.svgFill.blend = FILL_BLEND.OPAQUE; } else { paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED; } } break; case SVGPaintMethod.LinearGradientFill: { layer.type = SVGShapeType.FILL; SVGLinearGradientBrush linearGradBrush = paintable.GetLinearGradientBrush(bounds, matrix, viewport); paintable.svgFill = linearGradBrush.fill; } break; case SVGPaintMethod.RadialGradientFill: { layer.type = SVGShapeType.FILL; SVGRadialGradientBrush radialGradBrush = paintable.GetRadialGradientBrush(bounds, matrix, viewport); paintable.svgFill = radialGradBrush.fill; } break; case SVGPaintMethod.ConicalGradientFill: { layer.type = SVGShapeType.FILL; SVGConicalGradientBrush conicalGradBrush = paintable.GetConicalGradientBrush(bounds, matrix, viewport); paintable.svgFill = conicalGradBrush.fill; } break; case SVGPaintMethod.PathDraw: { layer.type = SVGShapeType.STROKE; Color color = Color.black; SVGColorType colorType = paintable.fillColor.Value.colorType; if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None) { color.a *= paintable.strokeOpacity; paintable.svgFill = new SVGFill(color); } else { color = paintable.fillColor.Value.color; color.a *= paintable.strokeOpacity; paintable.svgFill = new SVGFill(color); } paintable.svgFill.fillType = FILL_TYPE.SOLID; if (color.a == 1) { paintable.svgFill.blend = FILL_BLEND.OPAQUE; } else { paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED; } } break; default: break; } } else { layer.type = SVGShapeType.STROKE; Color color = paintable.strokeColor.Value.color; color.a *= paintable.strokeOpacity; paintable.svgFill = new SVGFill(color, FILL_BLEND.OPAQUE, FILL_TYPE.SOLID); if (color.a != 1f) { paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED; } paintable.svgFill.color = color; } // Use LibTessDotNet if (true) { LibTessDotNet.Tess tesselation = new LibTessDotNet.Tess(); LibTessDotNet.ContourVertex[] path; int pathLength; for (int i = 0; i < simplifiedShapes.Count; i++) { if (simplifiedShapes[i] == null) { continue; } pathLength = simplifiedShapes[i].Count; path = new LibTessDotNet.ContourVertex[pathLength]; Vector2 position; for (int j = 0; j < pathLength; j++) { position = simplifiedShapes[i][j]; path[j].Position = new LibTessDotNet.Vec3 { X = position.x, Y = position.y, Z = 0f }; } tesselation.AddContour(path, SVGImporter.LibTessDotNet.ContourOrientation.Clockwise); } tesselation.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3); int meshVertexCount = tesselation.Vertices.Length; if (meshVertexCount == 0) { return(false); } int numTriangles = tesselation.ElementCount; layer.triangles = new int[numTriangles * 3]; layer.vertices = new Vector2[meshVertexCount]; for (int i = 0; i < numTriangles; i++) { layer.triangles[i * 3] = tesselation.Elements[i * 3]; layer.triangles[i * 3 + 1] = tesselation.Elements[i * 3 + 1]; layer.triangles[i * 3 + 2] = tesselation.Elements[i * 3 + 2]; } for (int i = 0; i < meshVertexCount; i++) { layer.vertices[i] = new Vector2(tesselation.Vertices[i].Position.X, tesselation.Vertices[i].Position.Y) * SVGAssetImport.meshScale; } } /* * else { * // Use Triangle.net library * SVGImporter.TriangleNet.Mesh triangleMesh = new SVGImporter.TriangleNet.Mesh(); * SVGImporter.TriangleNet.Geometry.InputGeometry triangleInput = new SVGImporter.TriangleNet.Geometry.InputGeometry(); * * int pathLength, m = 0; * for(int i = 0; i < simplifiedShapes.Count; i++) * { * if(simplifiedShapes[i] == null) * continue; * * pathLength = simplifiedShapes[i].Count; * Vector2 position; * for(int j = 0; j < pathLength; j++) * { * triangleInput.AddPoint(simplifiedShapes[i][j].x, simplifiedShapes[i][j].y); * } * } * * triangleMesh.Triangulate(triangleInput); * * int totalVertices = triangleMesh.vertices.Count; * layer.vertices = new Vector2[totalVertices]; * for(int i = 0; i < totalVertices; i++) * { * layer.vertices[i].x = (float)triangleMesh.vertices[i].x * SVGAssetImport.meshScale; * layer.vertices[i].y = (float)triangleMesh.vertices[i].y * SVGAssetImport.meshScale; * } * * int totalTriangles = triangleMesh.triangles.Count; * layer.triangles = new int[totalTriangles * 3]; * int ti = 0; * for(int i = 0; i < totalTriangles; i++) * { * ti = i * 3; * layer.triangles[ti] = triangleMesh.triangles[i].P0; * layer.triangles[ti + 1] = triangleMesh.triangles[i].P1; * layer.triangles[ti + 2] = triangleMesh.triangles[i].P2; * } * } */ layer.fill = paintable.svgFill; layer.fill.opacity = paintable.opacity; if (layer.fill.opacity < 1f && layer.fill.blend == FILL_BLEND.OPAQUE) { layer.fill.blend = FILL_BLEND.ALPHA_BLENDED; } if (layer.fill.fillType == FILL_TYPE.GRADIENT && layer.fill.gradientColors != null) { layer.fill.color = Color.white; } else if (layer.fill.fillType == FILL_TYPE.TEXTURE) { layer.fill.color = Color.white; } viewport.x *= SVGAssetImport.meshScale; viewport.y *= SVGAssetImport.meshScale; viewport.size *= SVGAssetImport.meshScale; layer.fill.viewport = viewport; SVGMatrix scaleMatrix = SVGMatrix.identity.Scale(SVGAssetImport.meshScale); layer.fill.transform = scaleMatrix.Multiply(layer.fill.transform); layer.fill.transform = layer.fill.transform.Multiply(scaleMatrix.Inverse()); Vector2 boundsMin = bounds.min * SVGAssetImport.meshScale; Vector2 boundsMax = bounds.max * SVGAssetImport.meshScale; layer.bounds = new Rect(boundsMin.x, boundsMin.y, boundsMax.x - boundsMin.x, boundsMax.y - boundsMin.y); if (antialiasing) { if (CreateAntialiasing(simplifiedShapes, out antialiasingLayer, Color.white, -1f, ClosePathRule.ALWAYS)) { int verticesLength = antialiasingLayer.vertices.Length; for (int i = 0; i < verticesLength; i++) { antialiasingLayer.vertices[i] *= SVGAssetImport.meshScale; } antialiasingLayer.type = SVGShapeType.ANTIALIASING; antialiasingLayer.RecalculateBounds(); antialiasingLayer.fill = layer.fill.Clone(); antialiasingLayer.fill.blend = FILL_BLEND.ALPHA_BLENDED; } } return(true); }
public static bool CreatePolygon(List <List <Vector2> > inputShapes, SVGPaintable paintable, SVGMatrix matrix, out SVGLayer layer, bool isStroke = false) { layer = new SVGLayer(); if (inputShapes == null || inputShapes.Count == 0) { return(false); } List <List <Vector2> > simplifiedShapes = new List <List <Vector2> >(); PolyFillType fillType = PolyFillType.pftNonZero; if (paintable.fillRule == SVGFillRule.EvenOdd) { fillType = PolyFillType.pftEvenOdd; } simplifiedShapes = SVGGeom.SimplifyPolygons(inputShapes, fillType); if (simplifiedShapes == null || simplifiedShapes.Count == 0) { return(false); } AddInputShape(simplifiedShapes); Rect bounds = GetRect(simplifiedShapes); Rect viewport = paintable.viewport; if (!isStroke) { switch (paintable.GetPaintType()) { case SVGPaintMethod.SolidFill: { Color color = Color.black; SVGColorType colorType = paintable.fillColor.Value.colorType; if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None) { color.a *= paintable.fillOpacity; paintable.svgFill = new SVGFill(color); } else { color = paintable.fillColor.Value.color; color.a *= paintable.fillOpacity; paintable.svgFill = new SVGFill(color); } paintable.svgFill.fillType = FILL_TYPE.SOLID; if (color.a == 1) { paintable.svgFill.blend = FILL_BLEND.OPAQUE; } else { paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED; } } break; case SVGPaintMethod.LinearGradientFill: { SVGLinearGradientBrush linearGradBrush = paintable.GetLinearGradientBrush(bounds, matrix, viewport); paintable.svgFill = linearGradBrush.fill; } break; case SVGPaintMethod.RadialGradientFill: { SVGRadialGradientBrush radialGradBrush = paintable.GetRadialGradientBrush(bounds, matrix, viewport); paintable.svgFill = radialGradBrush.fill; } break; case SVGPaintMethod.ConicalGradientFill: { SVGConicalGradientBrush conicalGradBrush = paintable.GetConicalGradientBrush(bounds, matrix, viewport); paintable.svgFill = conicalGradBrush.fill; } break; case SVGPaintMethod.PathDraw: { Color color = Color.black; SVGColorType colorType = paintable.fillColor.Value.colorType; if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None) { color.a *= paintable.strokeOpacity; paintable.svgFill = new SVGFill(color); } else { color = paintable.fillColor.Value.color; color.a *= paintable.strokeOpacity; paintable.svgFill = new SVGFill(color); } paintable.svgFill.fillType = FILL_TYPE.SOLID; if (color.a == 1) { paintable.svgFill.blend = FILL_BLEND.OPAQUE; } else { paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED; } } break; default: break; } } else { Color color = paintable.strokeColor.Value.color; color.a *= paintable.strokeOpacity; paintable.svgFill = new SVGFill(color, FILL_BLEND.OPAQUE, FILL_TYPE.SOLID); if (color.a != 1f) { paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED; } paintable.svgFill.color = color; } LibTessDotNet.Tess tesselation = new LibTessDotNet.Tess(); LibTessDotNet.ContourVertex[] path; int pathLength; for (int i = 0; i < simplifiedShapes.Count; i++) { if (simplifiedShapes[i] == null) { continue; } pathLength = simplifiedShapes[i].Count; path = new LibTessDotNet.ContourVertex[pathLength]; Vector2 position; for (int j = 0; j < pathLength; j++) { position = simplifiedShapes[i][j]; path[j].Position = new LibTessDotNet.Vec3 { X = position.x, Y = position.y, Z = 0f }; } tesselation.AddContour(path, SVGImporter.LibTessDotNet.ContourOrientation.Clockwise); } tesselation.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3); int meshVertexCount = tesselation.Vertices.Length; layer.vertices = new Vector2[meshVertexCount]; for (int i = 0; i < meshVertexCount; i++) { layer.vertices[i] = new Vector2(tesselation.Vertices[i].Position.X, tesselation.Vertices[i].Position.Y) * SVGAssetImport.meshScale; } int numTriangles = tesselation.ElementCount; layer.triangles = new int[numTriangles * 3]; for (int i = 0; i < numTriangles; i++) { layer.triangles[i * 3] = tesselation.Elements[i * 3]; layer.triangles[i * 3 + 1] = tesselation.Elements[i * 3 + 1]; layer.triangles[i * 3 + 2] = tesselation.Elements[i * 3 + 2]; } layer.fill = paintable.svgFill; layer.fill.opacity = paintable.opacity; if (layer.fill.opacity < 1f && layer.fill.blend == FILL_BLEND.OPAQUE) { layer.fill.blend = FILL_BLEND.ALPHA_BLENDED; } if (layer.fill.fillType == FILL_TYPE.GRADIENT && layer.fill.gradientColors != null) { layer.fill.color = Color.white; } else if (layer.fill.fillType == FILL_TYPE.TEXTURE) { layer.fill.color = Color.white; } viewport.x *= SVGAssetImport.meshScale; viewport.y *= SVGAssetImport.meshScale; viewport.size *= SVGAssetImport.meshScale; layer.fill.viewport = viewport; if (layer.fill.transform != null) { SVGMatrix scaleMatrix = SVGMatrix.Identity().Scale(SVGAssetImport.meshScale); layer.fill.transform = scaleMatrix.Multiply(layer.fill.transform); layer.fill.transform = layer.fill.transform.Multiply(scaleMatrix.Inverse()); } Vector2 boundsMin = bounds.min * SVGAssetImport.meshScale; Vector2 boundsMax = bounds.max * SVGAssetImport.meshScale; layer.bounds = new Rect(boundsMin.x, boundsMin.y, boundsMax.x - boundsMin.x, boundsMax.y - boundsMin.y); return(true); }