1710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik/* 2710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik * Copyright (C) 2012 The Android Open Source Project 3710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik * 4710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik * Licensed under the Apache License, Version 2.0 (the "License"); 5710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik * you may not use this file except in compliance with the License. 6710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik * You may obtain a copy of the License at 7710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik * 8710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik * http://www.apache.org/licenses/LICENSE-2.0 9710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik * 10710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik * Unless required by applicable law or agreed to in writing, software 11710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik * distributed under the License is distributed on an "AS IS" BASIS, 12710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik * See the License for the specific language governing permissions and 14710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik * limitations under the License. 15710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik */ 16710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 17710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#define LOG_TAG "PathRenderer" 18710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#define LOG_NDEBUG 1 19710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#define ATRACE_TAG ATRACE_TAG_GRAPHICS 20710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 21710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#define VERTEX_DEBUG 0 22710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 23710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#include <SkPath.h> 24cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik#include <SkPaint.h> 25710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 26710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#include <stdlib.h> 27710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#include <stdint.h> 28710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#include <sys/types.h> 29710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 30710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#include <utils/Log.h> 31710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#include <utils/Trace.h> 32710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 33710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#include "PathRenderer.h" 34710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#include "Matrix.h" 35710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#include "Vector.h" 36710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#include "Vertex.h" 37710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 38710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craiknamespace android { 39710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craiknamespace uirenderer { 40710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 41710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#define THRESHOLD 0.5f 42710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 43cb4d6009576cf08195dc23f341a3f4939c0878bbChris CraikSkRect PathRenderer::computePathBounds(const SkPath& path, const SkPaint* paint) { 44cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik SkRect bounds = path.getBounds(); 45cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik if (paint->getStyle() != SkPaint::kFill_Style) { 46cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik float outset = paint->getStrokeWidth() * 0.5f; 47cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik bounds.outset(outset, outset); 48cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik } 49cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik return bounds; 50cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik} 51cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 52cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craikvoid computeInverseScales(const mat4 *transform, float &inverseScaleX, float& inverseScaleY) { 53710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik if (CC_UNLIKELY(!transform->isPureTranslate())) { 54710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float m00 = transform->data[Matrix4::kScaleX]; 55710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float m01 = transform->data[Matrix4::kSkewY]; 56710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float m10 = transform->data[Matrix4::kSkewX]; 57710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float m11 = transform->data[Matrix4::kScaleY]; 58710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float scaleX = sqrt(m00 * m00 + m01 * m01); 59710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float scaleY = sqrt(m10 * m10 + m11 * m11); 6016b897c488a740e004bfce7d50b0d7602277fc0bChris Craik inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 1.0f; 6116b897c488a740e004bfce7d50b0d7602277fc0bChris Craik inverseScaleY = (scaleY != 0) ? (1.0f / scaleY) : 1.0f; 62cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik } else { 63cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik inverseScaleX = 1.0f; 64cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik inverseScaleY = 1.0f; 65710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik } 66710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik} 67710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 6816b897c488a740e004bfce7d50b0d7602277fc0bChris Craikinline void copyVertex(Vertex* destPtr, const Vertex* srcPtr) { 69cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik Vertex::set(destPtr, srcPtr->position[0], srcPtr->position[1]); 70cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik} 71710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 7216b897c488a740e004bfce7d50b0d7602277fc0bChris Craikinline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) { 73cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik AlphaVertex::set(destPtr, srcPtr->position[0], srcPtr->position[1], srcPtr->alpha); 74cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik} 75710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 7616b897c488a740e004bfce7d50b0d7602277fc0bChris Craik/** 7716b897c488a740e004bfce7d50b0d7602277fc0bChris Craik * Produces a pseudo-normal for a vertex, given the normals of the two incoming lines. If the offset 7816b897c488a740e004bfce7d50b0d7602277fc0bChris Craik * from each vertex in a perimeter is calculated, the resultant lines connecting the offset vertices 7916b897c488a740e004bfce7d50b0d7602277fc0bChris Craik * will be offset by 1.0 8016b897c488a740e004bfce7d50b0d7602277fc0bChris Craik * 8116b897c488a740e004bfce7d50b0d7602277fc0bChris Craik * Note that we can't add and normalize the two vectors, that would result in a rectangle having an 8216b897c488a740e004bfce7d50b0d7602277fc0bChris Craik * offset of (sqrt(2)/2, sqrt(2)/2) at each corner, instead of (1, 1) 83780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik * 84780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik * NOTE: assumes angles between normals 90 degrees or less 8516b897c488a740e004bfce7d50b0d7602277fc0bChris Craik */ 8616b897c488a740e004bfce7d50b0d7602277fc0bChris Craikinline vec2 totalOffsetFromNormals(const vec2& normalA, const vec2& normalB) { 8716b897c488a740e004bfce7d50b0d7602277fc0bChris Craik return (normalA + normalB) / (1 + fabs(normalA.dot(normalB))); 8816b897c488a740e004bfce7d50b0d7602277fc0bChris Craik} 8916b897c488a740e004bfce7d50b0d7602277fc0bChris Craik 90780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craikinline void scaleOffsetForStrokeWidth(vec2& offset, float halfStrokeWidth, 91780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik float inverseScaleX, float inverseScaleY) { 92780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik if (halfStrokeWidth == 0.0f) { 93780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik // hairline - compensate for scale 94780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik offset.x *= 0.5f * inverseScaleX; 95780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik offset.y *= 0.5f * inverseScaleY; 96780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } else { 97780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik offset *= halfStrokeWidth; 98780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } 99780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik} 100780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 101cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craikvoid getFillVerticesFromPerimeter(const Vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) { 102cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size()); 103cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 104cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik int currentIndex = 0; 105cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik // zig zag between all previous points on the inside of the hull to create a 106cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik // triangle strip that fills the hull 107cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik int srcAindex = 0; 108cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik int srcBindex = perimeter.size() - 1; 109cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik while (srcAindex <= srcBindex) { 110cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyVertex(&buffer[currentIndex++], &perimeter[srcAindex]); 111cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik if (srcAindex == srcBindex) break; 112cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyVertex(&buffer[currentIndex++], &perimeter[srcBindex]); 113cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik srcAindex++; 114cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik srcBindex--; 115710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik } 116cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik} 117cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 118cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craikvoid getStrokeVerticesFromPerimeter(const Vector<Vertex>& perimeter, float halfStrokeWidth, 119cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) { 120cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size() * 2 + 2); 121cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 122710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik int currentIndex = 0; 123cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik const Vertex* last = &(perimeter[perimeter.size() - 1]); 124cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik const Vertex* current = &(perimeter[0]); 125cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik vec2 lastNormal(current->position[1] - last->position[1], 126cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik last->position[0] - current->position[0]); 127cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik lastNormal.normalize(); 128cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik for (unsigned int i = 0; i < perimeter.size(); i++) { 129cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik const Vertex* next = &(perimeter[i + 1 >= perimeter.size() ? 0 : i + 1]); 130cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik vec2 nextNormal(next->position[1] - current->position[1], 131cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[0] - next->position[0]); 132cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik nextNormal.normalize(); 133cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 13416b897c488a740e004bfce7d50b0d7602277fc0bChris Craik vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); 135780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inverseScaleY); 136cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 137cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik Vertex::set(&buffer[currentIndex++], 138cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[0] + totalOffset.x, 139cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[1] + totalOffset.y); 140cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 141cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik Vertex::set(&buffer[currentIndex++], 142cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[0] - totalOffset.x, 143cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[1] - totalOffset.y); 144cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 145cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik last = current; 146cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current = next; 147cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik lastNormal = nextNormal; 148710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik } 149710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 150cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik // wrap around to beginning 151cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyVertex(&buffer[currentIndex++], &buffer[0]); 152cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyVertex(&buffer[currentIndex++], &buffer[1]); 153cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik} 154710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 155780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craikvoid getStrokeVerticesFromUnclosedVertices(const Vector<Vertex>& vertices, float halfStrokeWidth, 156780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) { 157780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik Vertex* buffer = vertexBuffer.alloc<Vertex>(vertices.size() * 2); 158780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 159780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik int currentIndex = 0; 160780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik const Vertex* current = &(vertices[0]); 161780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 lastNormal; 162780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik for (unsigned int i = 0; i < vertices.size() - 1; i++) { 163780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik const Vertex* next = &(vertices[i + 1]); 164780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 nextNormal(next->position[1] - current->position[1], 165780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] - next->position[0]); 166780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik nextNormal.normalize(); 167780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 168780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 totalOffset; 169780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik if (i == 0) { 170780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik totalOffset = nextNormal; 171780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } else { 172780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); 173780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } 174780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inverseScaleY); 175780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 176780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik Vertex::set(&buffer[currentIndex++], 177780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] + totalOffset.x, 178780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[1] + totalOffset.y); 179780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 180780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik Vertex::set(&buffer[currentIndex++], 181780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] - totalOffset.x, 182780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[1] - totalOffset.y); 183780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 184780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current = next; 185780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik lastNormal = nextNormal; 186780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } 187780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 188780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 totalOffset = lastNormal; 189780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inverseScaleY); 190780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 191780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik Vertex::set(&buffer[currentIndex++], 192780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] + totalOffset.x, 193780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[1] + totalOffset.y); 194780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik Vertex::set(&buffer[currentIndex++], 195780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] - totalOffset.x, 196780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[1] - totalOffset.y); 197780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik#if VERTEX_DEBUG 198780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { 199780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik ALOGD("point at %f %f", buffer[i].position[0], buffer[i].position[1]); 200780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } 201780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik#endif 202780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik} 203780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 204cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craikvoid getFillVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, VertexBuffer& vertexBuffer, 205cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik float inverseScaleX, float inverseScaleY) { 206cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(perimeter.size() * 3 + 2); 207710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 208cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik // generate alpha points - fill Alpha vertex gaps in between each point with 209cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik // alpha 0 vertex, offset by a scaled normal. 210cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik int currentIndex = 0; 211cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik const Vertex* last = &(perimeter[perimeter.size() - 1]); 212cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik const Vertex* current = &(perimeter[0]); 213cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik vec2 lastNormal(current->position[1] - last->position[1], 214cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik last->position[0] - current->position[0]); 215cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik lastNormal.normalize(); 216cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik for (unsigned int i = 0; i < perimeter.size(); i++) { 217cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik const Vertex* next = &(perimeter[i + 1 >= perimeter.size() ? 0 : i + 1]); 218710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik vec2 nextNormal(next->position[1] - current->position[1], 219cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[0] - next->position[0]); 220710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik nextNormal.normalize(); 221710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 22216b897c488a740e004bfce7d50b0d7602277fc0bChris Craik // AA point offset from original point is that point's normal, such that each side is offset 22316b897c488a740e004bfce7d50b0d7602277fc0bChris Craik // by .5 pixels 22416b897c488a740e004bfce7d50b0d7602277fc0bChris Craik vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); 22516b897c488a740e004bfce7d50b0d7602277fc0bChris Craik totalOffset.x *= 0.5f * inverseScaleX; 22616b897c488a740e004bfce7d50b0d7602277fc0bChris Craik totalOffset.y *= 0.5f * inverseScaleY; 227710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 228710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik AlphaVertex::set(&buffer[currentIndex++], 229cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[0] + totalOffset.x, 230cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[1] + totalOffset.y, 231cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 0.0f); 232710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik AlphaVertex::set(&buffer[currentIndex++], 233cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[0] - totalOffset.x, 234cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[1] - totalOffset.y, 235cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 1.0f); 236cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 237710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik last = current; 238cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current = next; 239cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik lastNormal = nextNormal; 240710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik } 241710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 242710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik // wrap around to beginning 243cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyAlphaVertex(&buffer[currentIndex++], &buffer[0]); 244cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyAlphaVertex(&buffer[currentIndex++], &buffer[1]); 245710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 246710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik // zig zag between all previous points on the inside of the hull to create a 247710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik // triangle strip that fills the hull, repeating the first inner point to 248710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik // create degenerate tris to start inside path 249710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik int srcAindex = 0; 250cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik int srcBindex = perimeter.size() - 1; 251710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik while (srcAindex <= srcBindex) { 252cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyAlphaVertex(&buffer[currentIndex++], &buffer[srcAindex * 2 + 1]); 253710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik if (srcAindex == srcBindex) break; 254cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyAlphaVertex(&buffer[currentIndex++], &buffer[srcBindex * 2 + 1]); 255710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik srcAindex++; 256710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik srcBindex--; 257710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik } 258710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 259710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#if VERTEX_DEBUG 260cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { 261780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik ALOGD("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].position[1], buffer[i].alpha); 262780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } 263780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik#endif 264780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik} 265780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 266780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 267780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craikvoid getStrokeVerticesFromUnclosedVerticesAA(const Vector<Vertex>& vertices, float halfStrokeWidth, 268780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) { 269780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * vertices.size() + 2); 270780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 271780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik // avoid lines smaller than hairline since they break triangle based sampling. instead reducing 272780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik // alpha value (TODO: support different X/Y scale) 273780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik float maxAlpha = 1.0f; 274780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik if (halfStrokeWidth != 0 && inverseScaleX == inverseScaleY && 275780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik halfStrokeWidth * inverseScaleX < 0.5f) { 276780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX; 277780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik halfStrokeWidth = 0.0f; 278780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } 279780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 280780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik // there is no outer/inner here, using them for consistency with below approach 281780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik int offset = 2 * (vertices.size() - 2); 282780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik int currentAAOuterIndex = 2; 283780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik int currentAAInnerIndex = 2 * offset + 5; // reversed 284780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik int currentStrokeIndex = currentAAInnerIndex + 7; 285780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 286780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik const Vertex* last = &(vertices[0]); 287780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik const Vertex* current = &(vertices[1]); 288780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 lastNormal(current->position[1] - last->position[1], 289780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik last->position[0] - current->position[0]); 290780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik lastNormal.normalize(); 291780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 292780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik { 293780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik // start cap 294780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 totalOffset = lastNormal; 295780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 AAOffset = totalOffset; 296780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AAOffset.x *= 0.5f * inverseScaleX; 297780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AAOffset.y *= 0.5f * inverseScaleY; 298780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 299780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 innerOffset = totalOffset; 300780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY); 301780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 outerOffset = innerOffset + AAOffset; 302780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik innerOffset -= AAOffset; 303780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 304780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik // TODO: support square cap by changing this offset to incorporate halfStrokeWidth 305780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 capAAOffset(AAOffset.y, -AAOffset.x); 306780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AlphaVertex::set(&buffer[0], 307780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik last->position[0] + outerOffset.x + capAAOffset.x, 308780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik last->position[1] + outerOffset.y + capAAOffset.y, 309780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 0.0f); 310780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AlphaVertex::set(&buffer[1], 311780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik last->position[0] + innerOffset.x - capAAOffset.x, 312780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik last->position[1] + innerOffset.y - capAAOffset.y, 313780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik maxAlpha); 314780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 315780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AlphaVertex::set(&buffer[2 * offset + 6], 316780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik last->position[0] - outerOffset.x + capAAOffset.x, 317780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik last->position[1] - outerOffset.y + capAAOffset.y, 318780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 0.0f); 319780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AlphaVertex::set(&buffer[2 * offset + 7], 320780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik last->position[0] - innerOffset.x - capAAOffset.x, 321780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik last->position[1] - innerOffset.y - capAAOffset.y, 322780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik maxAlpha); 323780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik copyAlphaVertex(&buffer[2 * offset + 8], &buffer[0]); 324780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik copyAlphaVertex(&buffer[2 * offset + 9], &buffer[1]); 325780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik copyAlphaVertex(&buffer[2 * offset + 10], &buffer[1]); // degenerate tris (the only two!) 326780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik copyAlphaVertex(&buffer[2 * offset + 11], &buffer[2 * offset + 7]); 327780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } 328780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 329780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik for (unsigned int i = 1; i < vertices.size() - 1; i++) { 330780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik const Vertex* next = &(vertices[i + 1]); 331780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 nextNormal(next->position[1] - current->position[1], 332780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] - next->position[0]); 333780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik nextNormal.normalize(); 334780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 335780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); 336780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 AAOffset = totalOffset; 337780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AAOffset.x *= 0.5f * inverseScaleX; 338780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AAOffset.y *= 0.5f * inverseScaleY; 339780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 340780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 innerOffset = totalOffset; 341780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY); 342780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 outerOffset = innerOffset + AAOffset; 343780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik innerOffset -= AAOffset; 344780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 345780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AlphaVertex::set(&buffer[currentAAOuterIndex++], 346780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] + outerOffset.x, 347780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[1] + outerOffset.y, 348780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 0.0f); 349780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AlphaVertex::set(&buffer[currentAAOuterIndex++], 350780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] + innerOffset.x, 351780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[1] + innerOffset.y, 352780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik maxAlpha); 353780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 354780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AlphaVertex::set(&buffer[currentStrokeIndex++], 355780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] + innerOffset.x, 356780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[1] + innerOffset.y, 357780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik maxAlpha); 358780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AlphaVertex::set(&buffer[currentStrokeIndex++], 359780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] - innerOffset.x, 360780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[1] - innerOffset.y, 361780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik maxAlpha); 362780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 363780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AlphaVertex::set(&buffer[currentAAInnerIndex--], 364780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] - innerOffset.x, 365780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[1] - innerOffset.y, 366780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik maxAlpha); 367780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AlphaVertex::set(&buffer[currentAAInnerIndex--], 368780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] - outerOffset.x, 369780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[1] - outerOffset.y, 370780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 0.0f); 371780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 372780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik last = current; 373780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current = next; 374780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik lastNormal = nextNormal; 375780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } 376780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 377780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik { 378780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik // end cap 379780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 totalOffset = lastNormal; 380780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 AAOffset = totalOffset; 381780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AAOffset.x *= 0.5f * inverseScaleX; 382780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AAOffset.y *= 0.5f * inverseScaleY; 383780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 384780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 innerOffset = totalOffset; 385780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY); 386780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 outerOffset = innerOffset + AAOffset; 387780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik innerOffset -= AAOffset; 388780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 389780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik // TODO: support square cap by changing this offset to incorporate halfStrokeWidth 390780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vec2 capAAOffset(-AAOffset.y, AAOffset.x); 391780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 392780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AlphaVertex::set(&buffer[offset + 2], 393780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] + outerOffset.x + capAAOffset.x, 394780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[1] + outerOffset.y + capAAOffset.y, 395780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 0.0f); 396780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AlphaVertex::set(&buffer[offset + 3], 397780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] + innerOffset.x - capAAOffset.x, 398780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[1] + innerOffset.y - capAAOffset.y, 399780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik maxAlpha); 400780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 401780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AlphaVertex::set(&buffer[offset + 4], 402780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] - outerOffset.x + capAAOffset.x, 403780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[1] - outerOffset.y + capAAOffset.y, 404780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 0.0f); 405780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik AlphaVertex::set(&buffer[offset + 5], 406780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[0] - innerOffset.x - capAAOffset.x, 407780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik current->position[1] - innerOffset.y - capAAOffset.y, 408780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik maxAlpha); 409780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 410780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik copyAlphaVertex(&buffer[vertexBuffer.getSize() - 2], &buffer[offset + 3]); 411780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik copyAlphaVertex(&buffer[vertexBuffer.getSize() - 1], &buffer[offset + 5]); 412780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } 413780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 414780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik#if VERTEX_DEBUG 415780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { 416780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik ALOGD("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].position[1], buffer[i].alpha); 417710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik } 418710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#endif 419710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik} 420710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 421780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 422cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craikvoid getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float halfStrokeWidth, 423cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) { 424cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * perimeter.size() + 8); 425cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 42616b897c488a740e004bfce7d50b0d7602277fc0bChris Craik // avoid lines smaller than hairline since they break triangle based sampling. instead reducing 42716b897c488a740e004bfce7d50b0d7602277fc0bChris Craik // alpha value (TODO: support different X/Y scale) 42816b897c488a740e004bfce7d50b0d7602277fc0bChris Craik float maxAlpha = 1.0f; 42916b897c488a740e004bfce7d50b0d7602277fc0bChris Craik if (halfStrokeWidth != 0 && inverseScaleX == inverseScaleY && 4302154af209f6d269e29c6e991ce6c1349dfc85b93Chris Craik halfStrokeWidth * inverseScaleX < 0.5f) { 43116b897c488a740e004bfce7d50b0d7602277fc0bChris Craik maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX; 43216b897c488a740e004bfce7d50b0d7602277fc0bChris Craik halfStrokeWidth = 0.0f; 43316b897c488a740e004bfce7d50b0d7602277fc0bChris Craik } 43416b897c488a740e004bfce7d50b0d7602277fc0bChris Craik 435cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik int offset = 2 * perimeter.size() + 3; 436cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik int currentAAOuterIndex = 0; 437cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik int currentStrokeIndex = offset; 438cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik int currentAAInnerIndex = offset * 2; 439cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 440cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik const Vertex* last = &(perimeter[perimeter.size() - 1]); 441cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik const Vertex* current = &(perimeter[0]); 442cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik vec2 lastNormal(current->position[1] - last->position[1], 443cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik last->position[0] - current->position[0]); 444cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik lastNormal.normalize(); 445cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik for (unsigned int i = 0; i < perimeter.size(); i++) { 446cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik const Vertex* next = &(perimeter[i + 1 >= perimeter.size() ? 0 : i + 1]); 447cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik vec2 nextNormal(next->position[1] - current->position[1], 448cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[0] - next->position[0]); 449cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik nextNormal.normalize(); 450cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 45116b897c488a740e004bfce7d50b0d7602277fc0bChris Craik vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); 45216b897c488a740e004bfce7d50b0d7602277fc0bChris Craik vec2 AAOffset = totalOffset; 45316b897c488a740e004bfce7d50b0d7602277fc0bChris Craik AAOffset.x *= 0.5f * inverseScaleX; 45416b897c488a740e004bfce7d50b0d7602277fc0bChris Craik AAOffset.y *= 0.5f * inverseScaleY; 455cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 45616b897c488a740e004bfce7d50b0d7602277fc0bChris Craik vec2 innerOffset = totalOffset; 457780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY); 458cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik vec2 outerOffset = innerOffset + AAOffset; 459cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik innerOffset -= AAOffset; 460cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 461cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik AlphaVertex::set(&buffer[currentAAOuterIndex++], 462cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[0] + outerOffset.x, 463cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[1] + outerOffset.y, 464cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 0.0f); 465cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik AlphaVertex::set(&buffer[currentAAOuterIndex++], 466cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[0] + innerOffset.x, 467cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[1] + innerOffset.y, 46816b897c488a740e004bfce7d50b0d7602277fc0bChris Craik maxAlpha); 469cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 470cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik AlphaVertex::set(&buffer[currentStrokeIndex++], 471cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[0] + innerOffset.x, 472cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[1] + innerOffset.y, 47316b897c488a740e004bfce7d50b0d7602277fc0bChris Craik maxAlpha); 474cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik AlphaVertex::set(&buffer[currentStrokeIndex++], 475cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[0] - innerOffset.x, 476cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[1] - innerOffset.y, 47716b897c488a740e004bfce7d50b0d7602277fc0bChris Craik maxAlpha); 478cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 479cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik AlphaVertex::set(&buffer[currentAAInnerIndex++], 480cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[0] - innerOffset.x, 481cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[1] - innerOffset.y, 48216b897c488a740e004bfce7d50b0d7602277fc0bChris Craik maxAlpha); 483cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik AlphaVertex::set(&buffer[currentAAInnerIndex++], 484cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[0] - outerOffset.x, 485cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current->position[1] - outerOffset.y, 486cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 0.0f); 487cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 488cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik last = current; 489cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik current = next; 490cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik lastNormal = nextNormal; 491cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik } 492cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 493cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik // wrap each strip around to beginning, creating degenerate tris to bridge strips 494cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyAlphaVertex(&buffer[currentAAOuterIndex++], &buffer[0]); 495cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyAlphaVertex(&buffer[currentAAOuterIndex++], &buffer[1]); 496cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyAlphaVertex(&buffer[currentAAOuterIndex++], &buffer[1]); 497710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 498cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyAlphaVertex(&buffer[currentStrokeIndex++], &buffer[offset]); 499cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyAlphaVertex(&buffer[currentStrokeIndex++], &buffer[offset + 1]); 500cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyAlphaVertex(&buffer[currentStrokeIndex++], &buffer[offset + 1]); 501cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 502cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyAlphaVertex(&buffer[currentAAInnerIndex++], &buffer[2 * offset]); 503cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik copyAlphaVertex(&buffer[currentAAInnerIndex++], &buffer[2 * offset + 1]); 504cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik // don't need to create last degenerate tri 505780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 506780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik#if VERTEX_DEBUG 507780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { 508780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik ALOGD("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].position[1], buffer[i].alpha); 509780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } 510780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik#endif 511cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik} 512cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 513cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craikvoid PathRenderer::convexPathVertices(const SkPath &path, const SkPaint* paint, 514cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik const mat4 *transform, VertexBuffer& vertexBuffer) { 515cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik ATRACE_CALL(); 516cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 517cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik SkPaint::Style style = paint->getStyle(); 518cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik bool isAA = paint->isAntiAlias(); 519cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 520cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik float inverseScaleX, inverseScaleY; 521cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik computeInverseScales(transform, inverseScaleX, inverseScaleY); 522cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 523cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik Vector<Vertex> tempVertices; 52416b897c488a740e004bfce7d50b0d7602277fc0bChris Craik float threshInvScaleX = inverseScaleX; 52516b897c488a740e004bfce7d50b0d7602277fc0bChris Craik float threshInvScaleY = inverseScaleY; 52616b897c488a740e004bfce7d50b0d7602277fc0bChris Craik if (style == SkPaint::kStroke_Style) { 52716b897c488a740e004bfce7d50b0d7602277fc0bChris Craik // alter the bezier recursion threshold values we calculate in order to compensate for 52816b897c488a740e004bfce7d50b0d7602277fc0bChris Craik // expansion done after the path vertices are found 52916b897c488a740e004bfce7d50b0d7602277fc0bChris Craik SkRect bounds = path.getBounds(); 53016b897c488a740e004bfce7d50b0d7602277fc0bChris Craik if (!bounds.isEmpty()) { 53116b897c488a740e004bfce7d50b0d7602277fc0bChris Craik threshInvScaleX *= bounds.width() / (bounds.width() + paint->getStrokeWidth()); 53216b897c488a740e004bfce7d50b0d7602277fc0bChris Craik threshInvScaleY *= bounds.height() / (bounds.height() + paint->getStrokeWidth()); 53316b897c488a740e004bfce7d50b0d7602277fc0bChris Craik } 53416b897c488a740e004bfce7d50b0d7602277fc0bChris Craik } 535780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 536780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik // force close if we're filling the path, since fill path expects closed perimeter. 537780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik bool forceClose = style != SkPaint::kStroke_Style; 538780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik bool wasClosed = convexPathPerimeterVertices(path, forceClose, threshInvScaleX * threshInvScaleX, 53916b897c488a740e004bfce7d50b0d7602277fc0bChris Craik threshInvScaleY * threshInvScaleY, tempVertices); 540cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 541bf09ffb4e0dc820aeae56a3e576aed33cab218daChris Craik if (!tempVertices.size()) { 542bf09ffb4e0dc820aeae56a3e576aed33cab218daChris Craik // path was empty, return without allocating vertex buffer 543bf09ffb4e0dc820aeae56a3e576aed33cab218daChris Craik return; 544bf09ffb4e0dc820aeae56a3e576aed33cab218daChris Craik } 545bf09ffb4e0dc820aeae56a3e576aed33cab218daChris Craik 546cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik#if VERTEX_DEBUG 547cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik for (unsigned int i = 0; i < tempVertices.size(); i++) { 548cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik ALOGD("orig path: point at %f %f", tempVertices[i].position[0], tempVertices[i].position[1]); 549cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik } 550cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik#endif 551cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 552cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik if (style == SkPaint::kStroke_Style) { 553cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik float halfStrokeWidth = paint->getStrokeWidth() * 0.5f; 554cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik if (!isAA) { 555780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik if (wasClosed) { 556780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik getStrokeVerticesFromPerimeter(tempVertices, halfStrokeWidth, vertexBuffer, 557780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik inverseScaleX, inverseScaleY); 558780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } else { 559780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik getStrokeVerticesFromUnclosedVertices(tempVertices, halfStrokeWidth, vertexBuffer, 560780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik inverseScaleX, inverseScaleY); 561780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } 562780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 563cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik } else { 564780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik if (wasClosed) { 565780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik getStrokeVerticesFromPerimeterAA(tempVertices, halfStrokeWidth, vertexBuffer, 566780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik inverseScaleX, inverseScaleY); 567780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } else { 568780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik getStrokeVerticesFromUnclosedVerticesAA(tempVertices, halfStrokeWidth, vertexBuffer, 569780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik inverseScaleX, inverseScaleY); 570780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } 571cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik } 572cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik } else { 573cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik // For kStrokeAndFill style, the path should be adjusted externally, as it will be treated as a fill here. 574cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik if (!isAA) { 575cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik getFillVerticesFromPerimeter(tempVertices, vertexBuffer); 576cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik } else { 577cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik getFillVerticesFromPerimeterAA(tempVertices, vertexBuffer, inverseScaleX, inverseScaleY); 578cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik } 579cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik } 580cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik} 581cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 582cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 583780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craikvoid pushToVector(Vector<Vertex>& vertices, float x, float y) { 584780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik // TODO: make this not yuck 585780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik vertices.push(); 586780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik Vertex* newVertex = &(vertices.editArray()[vertices.size() - 1]); 587780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik Vertex::set(newVertex, x, y); 588780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik} 589780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 590780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craikbool PathRenderer::convexPathPerimeterVertices(const SkPath& path, bool forceClose, 591cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik float sqrInvScaleX, float sqrInvScaleY, Vector<Vertex>& outputVertices) { 592710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik ATRACE_CALL(); 593710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 594780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik // TODO: to support joins other than sharp miter, join vertices should be labelled in the 595780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik // perimeter, or resolved into more vertices. Reconsider forceClose-ing in that case. 596780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik SkPath::Iter iter(path, forceClose); 597710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik SkPoint pts[4]; 598710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik SkPath::Verb v; 599710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik Vertex* newVertex = 0; 600710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik while (SkPath::kDone_Verb != (v = iter.next(pts))) { 601710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik switch (v) { 602710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik case SkPath::kMove_Verb: 603780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik pushToVector(outputVertices, pts[0].x(), pts[0].y()); 604710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik ALOGV("Move to pos %f %f", pts[0].x(), pts[0].y()); 605710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik break; 606710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik case SkPath::kClose_Verb: 607710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik ALOGV("Close at pos %f %f", pts[0].x(), pts[0].y()); 608710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik break; 609710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik case SkPath::kLine_Verb: 610710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik ALOGV("kLine_Verb %f %f -> %f %f", 611cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik pts[0].x(), pts[0].y(), 612cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik pts[1].x(), pts[1].y()); 613710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 614780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik pushToVector(outputVertices, pts[1].x(), pts[1].y()); 615710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik break; 616710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik case SkPath::kQuad_Verb: 617710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik ALOGV("kQuad_Verb"); 618710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik recursiveQuadraticBezierVertices( 619cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik pts[0].x(), pts[0].y(), 620cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik pts[2].x(), pts[2].y(), 621cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik pts[1].x(), pts[1].y(), 622cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik sqrInvScaleX, sqrInvScaleY, outputVertices); 623710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik break; 624710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik case SkPath::kCubic_Verb: 625710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik ALOGV("kCubic_Verb"); 626710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik recursiveCubicBezierVertices( 627cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik pts[0].x(), pts[0].y(), 628cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik pts[1].x(), pts[1].y(), 629cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik pts[3].x(), pts[3].y(), 630cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik pts[2].x(), pts[2].y(), 631cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik sqrInvScaleX, sqrInvScaleY, outputVertices); 632710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik break; 633710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik default: 634710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik break; 635710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik } 636710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik } 637780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik 638780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik int size = outputVertices.size(); 639780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik if (size >= 2 && outputVertices[0].position[0] == outputVertices[size - 1].position[0] && 640780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik outputVertices[0].position[1] == outputVertices[size - 1].position[1]) { 641780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik outputVertices.pop(); 642780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik return true; 643780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik } 644780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik return false; 645710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik} 646710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 647710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craikvoid PathRenderer::recursiveCubicBezierVertices( 648710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float p1x, float p1y, float c1x, float c1y, 649710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float p2x, float p2y, float c2x, float c2y, 650cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik float sqrInvScaleX, float sqrInvScaleY, Vector<Vertex>& outputVertices) { 651710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float dx = p2x - p1x; 652710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float dy = p2y - p1y; 653710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float d1 = fabs((c1x - p2x) * dy - (c1y - p2y) * dx); 654710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float d2 = fabs((c2x - p2x) * dy - (c2y - p2y) * dx); 655710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float d = d1 + d2; 656710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 657cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors 658cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik 659cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) { 660710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik // below thresh, draw line by adding endpoint 661780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik pushToVector(outputVertices, p2x, p2y); 662710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik } else { 663710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float p1c1x = (p1x + c1x) * 0.5f; 664710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float p1c1y = (p1y + c1y) * 0.5f; 665710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float p2c2x = (p2x + c2x) * 0.5f; 666710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float p2c2y = (p2y + c2y) * 0.5f; 667710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 668710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float c1c2x = (c1x + c2x) * 0.5f; 669710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float c1c2y = (c1y + c2y) * 0.5f; 670710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 671710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float p1c1c2x = (p1c1x + c1c2x) * 0.5f; 672710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float p1c1c2y = (p1c1y + c1c2y) * 0.5f; 673710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 674710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float p2c1c2x = (p2c2x + c1c2x) * 0.5f; 675710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float p2c1c2y = (p2c2y + c1c2y) * 0.5f; 676710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 677710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float mx = (p1c1c2x + p2c1c2x) * 0.5f; 678710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float my = (p1c1c2y + p2c1c2y) * 0.5f; 679710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 680710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik recursiveCubicBezierVertices( 681710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik p1x, p1y, p1c1x, p1c1y, 682710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik mx, my, p1c1c2x, p1c1c2y, 683cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik sqrInvScaleX, sqrInvScaleY, outputVertices); 684710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik recursiveCubicBezierVertices( 685710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik mx, my, p2c1c2x, p2c1c2y, 686710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik p2x, p2y, p2c2x, p2c2y, 687cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik sqrInvScaleX, sqrInvScaleY, outputVertices); 688710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik } 689710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik} 690710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 691710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craikvoid PathRenderer::recursiveQuadraticBezierVertices( 692710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float ax, float ay, 693710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float bx, float by, 694710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float cx, float cy, 695cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik float sqrInvScaleX, float sqrInvScaleY, Vector<Vertex>& outputVertices) { 696710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float dx = bx - ax; 697710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float dy = by - ay; 698710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float d = (cx - bx) * dy - (cy - by) * dx; 699710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 700cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) { 701710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik // below thresh, draw line by adding endpoint 702780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik pushToVector(outputVertices, bx, by); 703710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik } else { 704710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float acx = (ax + cx) * 0.5f; 705710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float bcx = (bx + cx) * 0.5f; 706710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float acy = (ay + cy) * 0.5f; 707710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float bcy = (by + cy) * 0.5f; 708710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 709710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik // midpoint 710710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float mx = (acx + bcx) * 0.5f; 711710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik float my = (acy + bcy) * 0.5f; 712710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 713710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy, 714cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik sqrInvScaleX, sqrInvScaleY, outputVertices); 715710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy, 716cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik sqrInvScaleX, sqrInvScaleY, outputVertices); 717710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik } 718710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik} 719710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik 720710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik}; // namespace uirenderer 721710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik}; // namespace android 722