GrAAHairLinePathRenderer.cpp revision 3f2a2d5fdc833dd20900ee90249b03474d0e00b3
1f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com/* 2f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * Copyright 2011 Google Inc. 3f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * 4f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * Use of this source code is governed by a BSD-style license that can be 5f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * found in the LICENSE file. 6f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com */ 7f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com 8aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrAAHairLinePathRenderer.h" 9aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 10aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrContext.h" 119381363050ec9d3e724076a8e9152bfa9a8de1d1tomhudson@google.com#include "GrDrawState.h" 12c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrDrawTargetCaps.h" 1390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org#include "GrEffect.h" 14aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrGpu.h" 15aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrIndexBuffer.h" 16dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com#include "GrPathUtils.h" 1790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org#include "GrTBackendEffectFactory.h" 18aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "SkGeometry.h" 1912b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com#include "SkStroke.h" 20aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "SkTemplates.h" 21aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 2290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org#include "gl/GrGLEffect.h" 2390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org#include "gl/GrGLSL.h" 244647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com 25aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comnamespace { 26aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// quadratics are rendered as 5-sided polys in order to bound the 27aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// AA stroke around the center-curve. See comments in push_quad_index_buffer and 285383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// bloat_quad. Quadratics and conics share an index buffer 29aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comstatic const int kVertsPerQuad = 5; 30aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comstatic const int kIdxsPerQuad = 9; 31aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 32aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comstatic const int kVertsPerLineSeg = 4; 33aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comstatic const int kIdxsPerLineSeg = 6; 34aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 35aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comstatic const int kNumQuadsInIdxBuffer = 256; 36aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comstatic const size_t kQuadIdxSBufize = kIdxsPerQuad * 37aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com sizeof(uint16_t) * 38aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com kNumQuadsInIdxBuffer; 39aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 40aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.combool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { 41aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com uint16_t* data = (uint16_t*) qIdxBuffer->lock(); 42aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bool tempData = NULL == data; 43aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (tempData) { 44c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad); 45aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 46aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) { 47aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 48aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // Each quadratic is rendered as a five sided polygon. This poly bounds 49aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // the quadratic's bounding triangle but has been expanded so that the 50aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // 1-pixel wide area around the curve is inside the poly. 51aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // If a,b,c are the original control points then the poly a0,b0,c0,c1,a1 52aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // that is rendered would look like this: 53aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // b0 54aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // b 55aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // 56aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // a0 c0 57aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // a c 58aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // a1 c1 590e5104c1570de4709e04720e62d80a0ca8970260bsalomon@google.com // Each is drawn as three triangles specified by these 9 indices: 60aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com int baseIdx = i * kIdxsPerQuad; 61aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com uint16_t baseVert = (uint16_t)(i * kVertsPerQuad); 62aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com data[0 + baseIdx] = baseVert + 0; // a0 63aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com data[1 + baseIdx] = baseVert + 1; // a1 64aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com data[2 + baseIdx] = baseVert + 2; // b0 65aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com data[3 + baseIdx] = baseVert + 2; // b0 66aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com data[4 + baseIdx] = baseVert + 4; // c1 67aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com data[5 + baseIdx] = baseVert + 3; // c0 68aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com data[6 + baseIdx] = baseVert + 1; // a1 69aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com data[7 + baseIdx] = baseVert + 4; // c1 70aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com data[8 + baseIdx] = baseVert + 2; // b0 71aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 72aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (tempData) { 73aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bool ret = qIdxBuffer->updateData(data, kQuadIdxSBufize); 74aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com delete[] data; 75aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return ret; 76aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } else { 77aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com qIdxBuffer->unlock(); 78aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return true; 79aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 80aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 81aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 82aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 83aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comGrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) { 84a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com const GrIndexBuffer* lIdxBuffer = context->getQuadIndexBuffer(); 85a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com if (NULL == lIdxBuffer) { 86aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return NULL; 87aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 88a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com GrGpu* gpu = context->getGpu(); 89a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false); 90a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); 91a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com if (NULL == qIdxBuf || 92a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com !push_quad_index_data(qIdxBuf)) { 93a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com return NULL; 94a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com } 95c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com return SkNEW_ARGS(GrAAHairLinePathRenderer, 96c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com (context, lIdxBuffer, qIdxBuf)); 97aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 98aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 99aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comGrAAHairLinePathRenderer::GrAAHairLinePathRenderer( 100aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com const GrContext* context, 101aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com const GrIndexBuffer* linesIndexBuffer, 102aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com const GrIndexBuffer* quadsIndexBuffer) { 103aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com fLinesIndexBuffer = linesIndexBuffer; 104aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com linesIndexBuffer->ref(); 105aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com fQuadsIndexBuffer = quadsIndexBuffer; 106aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com quadsIndexBuffer->ref(); 107aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 108aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 109aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comGrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { 110aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com fLinesIndexBuffer->unref(); 111aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com fQuadsIndexBuffer->unref(); 112aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 113aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 114aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comnamespace { 115aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 11649313f6b4391d0f74ab1964c295634e8830680f6bsalomon@google.comtypedef SkTArray<SkPoint, true> PtArray; 11792669014aa7ab821cdc09cc9ad610316eb16b490bsalomon@google.com#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> 11849313f6b4391d0f74ab1964c295634e8830680f6bsalomon@google.comtypedef SkTArray<int, true> IntArray; 1195383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.comtypedef SkTArray<float, true> FloatArray; 120aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 121aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// Takes 178th time of logf on Z600 / VC2010 122aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comint get_float_exp(float x) { 123aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); 124aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#if GR_DEBUG 125aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com static bool tested; 126aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (!tested) { 127aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com tested = true; 128aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrAssert(get_float_exp(0.25f) == -2); 129aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrAssert(get_float_exp(0.3f) == -2); 130aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrAssert(get_float_exp(0.5f) == -1); 131aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrAssert(get_float_exp(1.f) == 0); 132aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrAssert(get_float_exp(2.f) == 1); 133aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrAssert(get_float_exp(2.5f) == 1); 134aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrAssert(get_float_exp(8.f) == 3); 135aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrAssert(get_float_exp(100.f) == 6); 136aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrAssert(get_float_exp(1000.f) == 9); 137aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrAssert(get_float_exp(1024.f) == 10); 138aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrAssert(get_float_exp(3000000.f) == 21); 139aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 140aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#endif 1412ec7280a178ad3dcfd2e645bc330eeb04a84bfcfbsalomon@google.com const int* iptr = (const int*)&x; 1422ec7280a178ad3dcfd2e645bc330eeb04a84bfcfbsalomon@google.com return (((*iptr) & 0x7f800000) >> 23) - 127; 143aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 144aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 1455383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// Uses the max curvature function for quads to estimate 1465383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// where to chop the conic. If the max curvature is not 1475383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// found along the curve segment it will return 1 and 1483f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// dst[0] is the original conic. If it returns 2 the dst[0] 1495383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// and dst[1] are the two new conics. 1503f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.comint split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { 1515383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkScalar t = SkFindQuadMaxCurvature(src); 1525383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (t == 0) { 1535383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (dst) { 1545383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com dst[0].set(src, weight); 1555383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1565383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 1; 1575383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } else { 1585383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (dst) { 1595383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkConic conic; 1605383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com conic.set(src, weight); 1615383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com conic.chopAt(t, dst); 1625383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1635383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 2; 1645383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1655383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com} 1665383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 1673f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Calls split_conic on the entire conic and then once more on each subsection. 1683f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Most cases will result in either 1 conic (chop point is not within t range) 1693f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// or 3 points (split once and then one subsection is split again). 1703f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.comint chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) { 1713f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkConic dstTemp[2]; 1723f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com int conicCnt = split_conic(src, dstTemp, weight); 1733f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com if (2 == conicCnt) { 1743f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW); 1753f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW); 1763f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com } else { 1773f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com dst[0] = dstTemp[0]; 1783f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com } 1793f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com return conicCnt; 1803f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com} 1813f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com 1825383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// returns 0 if quad/conic is degen or close to it 1835383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// in this case approx the path with lines 1845383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// otherwise returns 1 1855383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.comint is_degen_quad_or_conic(const SkPoint p[3]) { 1865383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com static const SkScalar gDegenerateToLineTol = SK_Scalar1; 1875383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com static const SkScalar gDegenerateToLineTolSqd = 1885383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); 1895383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 1905383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || 1915383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { 1925383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 1; 1935383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1945383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 1955383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkScalar dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]); 1965383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (dsqd < gDegenerateToLineTolSqd) { 1975383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 1; 1985383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1995383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 2005383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) { 2015383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 1; 2025383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 2035383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 0; 2045383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com} 2055383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 206aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// we subdivide the quads to avoid huge overfill 207aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// if it returns -1 then should be drawn as lines 208aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comint num_quad_subdivs(const SkPoint p[3]) { 209aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com static const SkScalar gDegenerateToLineTol = SK_Scalar1; 210fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com static const SkScalar gDegenerateToLineTolSqd = 21146a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); 21246a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com 21346a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || 21446a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { 21546a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com return -1; 21646a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com } 217aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 21881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com SkScalar dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]); 21946a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com if (dsqd < gDegenerateToLineTolSqd) { 220aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return -1; 221aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 22246a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com 22346a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) { 224aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return -1; 225aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 226aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 227aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // tolerance of triangle height in pixels 228aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // tuned on windows Quadro FX 380 / Z600 229aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // trade off of fill vs cpu time on verts 230aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // maybe different when do this using gpu (geo or tess shaders) 231aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com static const SkScalar gSubdivTol = 175 * SK_Scalar1; 232aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 2337460b378d68217167013ca889a4cdcae742908e7robertphillips@google.com if (dsqd <= SkScalarMul(gSubdivTol, gSubdivTol)) { 234aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return 0; 235aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } else { 23687379e17c5e95c6fe0d88b3b9ae134355cfafc66robertphillips@google.com static const int kMaxSub = 4; 237aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // subdividing the quad reduces d by 4. so we want x = log4(d/tol) 238aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // = log4(d*d/tol*tol)/2 239aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // = log2(d*d/tol*tol) 240aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 241aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#ifdef SK_SCALAR_IS_FLOAT 242aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // +1 since we're ignoring the mantissa contribution. 243aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com int log = get_float_exp(dsqd/(gSubdivTol*gSubdivTol)) + 1; 244aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com log = GrMin(GrMax(0, log), kMaxSub); 245aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return log; 246aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#else 2477460b378d68217167013ca889a4cdcae742908e7robertphillips@google.com SkScalar log = SkScalarLog( 248fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com SkScalarDiv(dsqd, 2497460b378d68217167013ca889a4cdcae742908e7robertphillips@google.com SkScalarMul(gSubdivTol, gSubdivTol))); 250aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com static const SkScalar conv = SkScalarInvert(SkScalarLog(2)); 251aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com log = SkScalarMul(log, conv); 252aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return GrMin(GrMax(0, SkScalarCeilToInt(log)),kMaxSub); 253aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#endif 254aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 255aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 256aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 257dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com/** 258dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * Generates the lines and quads to be rendered. Lines are always recorded in 259dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * device space. We will do a device space bloat to account for the 1pixel 260dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * thickness. 261dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * Quads are recorded in device space unless m contains 262dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * perspective, then in they are in src space. We do this because we will 263dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * subdivide large quads to reduce over-fill. This subdivision has to be 264dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * performed before applying the perspective matrix. 265dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com */ 266dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.comint generate_lines_and_quads(const SkPath& path, 267dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com const SkMatrix& m, 268fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org const SkIRect& devClipBounds, 269dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com PtArray* lines, 270dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com PtArray* quads, 2715383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com PtArray* conics, 2725383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com IntArray* quadSubdivCnts, 2735383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com FloatArray* conicWeights) { 274aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkPath::Iter iter(path, false); 275aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 276aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com int totalQuadCount = 0; 277fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org SkRect bounds; 278fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org SkIRect ibounds; 279dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com 280dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com bool persp = m.hasPerspective(); 281dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com 282aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com for (;;) { 283912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org GrPoint pathPts[4]; 284dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com GrPoint devPts[4]; 285912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPath::Verb verb = iter.next(pathPts); 28694b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com switch (verb) { 2875383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com case SkPath::kConic_Verb: { 2883f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkConic dst[4]; 2893f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com // We chop the conics to create tighter clipping to hide error 2903f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com // that appears near max curvature of very thin conics. Thin 2913f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com // hyperbolas with high weight still show error. 2925383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com int conicCnt = chop_conic(pathPts, dst, iter.conicWeight()); 2935383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com for (int i = 0; i < conicCnt; ++i) { 2945383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkPoint* chopPnts = dst[i].fPts; 2955383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com m.mapPoints(devPts, chopPnts, 3); 2965383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com bounds.setBounds(devPts, 3); 2975383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com bounds.outset(SK_Scalar1, SK_Scalar1); 2985383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com bounds.roundOut(&ibounds); 2995383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (SkIRect::Intersects(devClipBounds, ibounds)) { 3005383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (is_degen_quad_or_conic(devPts)) { 3015383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkPoint* pts = lines->push_back_n(4); 3025383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[0] = devPts[0]; 3035383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[1] = devPts[1]; 3045383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[2] = devPts[1]; 3055383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[3] = devPts[2]; 3065383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } else { 3075383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com // when in perspective keep conics in src space 3085383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkPoint* cPts = persp ? chopPnts : devPts; 3095383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkPoint* pts = conics->push_back_n(3); 3105383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[0] = cPts[0]; 3115383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[1] = cPts[1]; 3125383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[2] = cPts[2]; 3135383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com conicWeights->push_back() = dst[i].fW; 3145383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 3155383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 3165383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 317277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com break; 3185383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 3195383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com case SkPath::kMove_Verb: 320aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com break; 32194b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kLine_Verb: 322912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org m.mapPoints(devPts, pathPts, 2); 323dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com bounds.setBounds(devPts, 2); 324aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.outset(SK_Scalar1, SK_Scalar1); 325aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.roundOut(&ibounds); 3267b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com if (SkIRect::Intersects(devClipBounds, ibounds)) { 327a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com SkPoint* pts = lines->push_back_n(2); 328a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[0] = devPts[0]; 329a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[1] = devPts[1]; 330aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 331aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com break; 332912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org case SkPath::kQuad_Verb: { 333912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPoint choppedPts[5]; 334912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // Chopping the quad helps when the quad is either degenerate or nearly degenerate. 335912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // When it is degenerate it allows the approximation with lines to work since the 336912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // chop point (if there is one) will be at the parabola's vertex. In the nearly 337912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // degenerate the QuadUVMatrix computed for the points is almost singular which 338912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // can cause rendering artifacts. 339912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org int n = SkChopQuadAtMaxCurvature(pathPts, choppedPts); 340912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org for (int i = 0; i < n; ++i) { 341912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPoint* quadPts = choppedPts + i * 2; 342912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org m.mapPoints(devPts, quadPts, 3); 343912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org bounds.setBounds(devPts, 3); 344912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org bounds.outset(SK_Scalar1, SK_Scalar1); 345912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org bounds.roundOut(&ibounds); 346912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org 347912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org if (SkIRect::Intersects(devClipBounds, ibounds)) { 348912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org int subdiv = num_quad_subdivs(devPts); 349912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org GrAssert(subdiv >= -1); 350912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org if (-1 == subdiv) { 351912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPoint* pts = lines->push_back_n(4); 352912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[0] = devPts[0]; 353912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[1] = devPts[1]; 354912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[2] = devPts[1]; 355912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[3] = devPts[2]; 356912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org } else { 357912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // when in perspective keep quads in src space 358912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPoint* qPts = persp ? quadPts : devPts; 359912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPoint* pts = quads->push_back_n(3); 360912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[0] = qPts[0]; 361912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[1] = qPts[1]; 362912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[2] = qPts[2]; 363912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org quadSubdivCnts->push_back() = subdiv; 364912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org totalQuadCount += 1 << subdiv; 365912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org } 366aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 367aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 368a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com break; 369912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org } 37094b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kCubic_Verb: 371912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org m.mapPoints(devPts, pathPts, 4); 372dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com bounds.setBounds(devPts, 4); 373aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.outset(SK_Scalar1, SK_Scalar1); 374aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.roundOut(&ibounds); 3757b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com if (SkIRect::Intersects(devClipBounds, ibounds)) { 37692669014aa7ab821cdc09cc9ad610316eb16b490bsalomon@google.com PREALLOC_PTARRAY(32) q; 377a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com // we don't need a direction if we aren't constraining the subdivision 378a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com static const SkPath::Direction kDummyDir = SkPath::kCCW_Direction; 37969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com // We convert cubics to quadratics (for now). 38069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com // In perspective have to do conversion in src space. 381dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com if (persp) { 382fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com SkScalar tolScale = 383dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com GrPathUtils::scaleToleranceToSrc(SK_Scalar1, m, 384dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com path.getBounds()); 385912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org GrPathUtils::convertCubicToQuads(pathPts, tolScale, false, kDummyDir, &q); 386dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } else { 387a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com GrPathUtils::convertCubicToQuads(devPts, SK_Scalar1, false, kDummyDir, &q); 388dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 389aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com for (int i = 0; i < q.count(); i += 3) { 390dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com SkPoint* qInDevSpace; 391dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // bounds has to be calculated in device space, but q is 392dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // in src space when there is perspective. 393dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com if (persp) { 394dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com m.mapPoints(devPts, &q[i], 3); 395dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com bounds.setBounds(devPts, 3); 396dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com qInDevSpace = devPts; 397dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } else { 398dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com bounds.setBounds(&q[i], 3); 399dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com qInDevSpace = &q[i]; 400dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 401aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.outset(SK_Scalar1, SK_Scalar1); 402aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.roundOut(&ibounds); 4037b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com if (SkIRect::Intersects(devClipBounds, ibounds)) { 404dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com int subdiv = num_quad_subdivs(qInDevSpace); 405aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrAssert(subdiv >= -1); 406aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (-1 == subdiv) { 407a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com SkPoint* pts = lines->push_back_n(4); 408dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // lines should always be in device coords 409a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[0] = qInDevSpace[0]; 410a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[1] = qInDevSpace[1]; 411a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[2] = qInDevSpace[1]; 412a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[3] = qInDevSpace[2]; 413aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } else { 414a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com SkPoint* pts = quads->push_back_n(3); 415dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // q is already in src space when there is no 416dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // perspective and dev coords otherwise. 417a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[0] = q[0 + i]; 418a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[1] = q[1 + i]; 419a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[2] = q[2 + i]; 420aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com quadSubdivCnts->push_back() = subdiv; 421aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com totalQuadCount += 1 << subdiv; 422aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 423aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 424aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 425aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 426a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com break; 42794b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kClose_Verb: 428aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com break; 42994b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kDone_Verb: 430aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return totalQuadCount; 431aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 432aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 433aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 434aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 435aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comstruct Vertex { 436aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrPoint fPos; 437aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com union { 438aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com struct { 43981712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com SkScalar fA; 44081712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com SkScalar fB; 44181712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com SkScalar fC; 442aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } fLine; 4435383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com struct { 4443f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar fK; 4453f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar fL; 4463f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar fM; 4475383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } fConic; 448aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrVec fQuadCoord; 449aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com struct { 4503f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar fBogus[4]; 451aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com }; 452aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com }; 453aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}; 4545383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 4553f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.comGR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint)); 456aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 457aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comvoid intersect_lines(const SkPoint& ptA, const SkVector& normA, 458aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com const SkPoint& ptB, const SkVector& normB, 459aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkPoint* result) { 460aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 461aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkScalar lineAW = -normA.dot(ptA); 462aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkScalar lineBW = -normB.dot(ptB); 463aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 464aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - 4655383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkScalarMul(normA.fY, normB.fX); 466aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com wInv = SkScalarInvert(wInv); 467aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 468aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); 469aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com result->fX = SkScalarMul(result->fX, wInv); 470fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 471aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); 472aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com result->fY = SkScalarMul(result->fY, wInv); 473aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 474aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 475b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.comvoid bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, 4761dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com const SkMatrix* toSrc, Vertex verts[kVertsPerQuad], 4771dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkRect* devBounds) { 478dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com GrAssert(!toDevice == !toSrc); 479aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // original quad is specified by tri a,b,c 480dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com SkPoint a = qpts[0]; 481dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com SkPoint b = qpts[1]; 482dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com SkPoint c = qpts[2]; 483aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 484dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // this should be in the src space, not dev coords, when we have perspective 4851971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com GrPathUtils::QuadUVMatrix DevToUV(qpts); 486aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 487dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com if (toDevice) { 488dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com toDevice->mapPoints(&a, 1); 489dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com toDevice->mapPoints(&b, 1); 490dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com toDevice->mapPoints(&c, 1); 491dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 492dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // make a new poly where we replace a and c by a 1-pixel wide edges orthog 493dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // to edges ab and bc: 494dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // 495dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // before | after 496dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // | b0 497dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // b | 498dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // | 499dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // | a0 c0 500dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // a c | a1 c1 501dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // 502dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // edges a0->b0 and b0->c0 are parallel to original edges a->b and b->c, 503dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // respectively. 504dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com Vertex& a0 = verts[0]; 505dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com Vertex& a1 = verts[1]; 506dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com Vertex& b0 = verts[2]; 507dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com Vertex& c0 = verts[3]; 508dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com Vertex& c1 = verts[4]; 509dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com 510aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector ab = b; 511aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com ab -= a; 512aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector ac = c; 513aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com ac -= a; 514aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector cb = b; 515aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com cb -= c; 516aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 517aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // We should have already handled degenerates 518aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrAssert(ab.length() > 0 && cb.length() > 0); 519aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 520aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com ab.normalize(); 521aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector abN; 522aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com abN.setOrthog(ab, SkVector::kLeft_Side); 523aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (abN.dot(ac) > 0) { 524aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com abN.negate(); 525aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 526aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 527aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com cb.normalize(); 528aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector cbN; 529aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com cbN.setOrthog(cb, SkVector::kLeft_Side); 530aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (cbN.dot(ac) < 0) { 531aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com cbN.negate(); 532aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 533aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 534aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com a0.fPos = a; 535aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com a0.fPos += abN; 536aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com a1.fPos = a; 537aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com a1.fPos -= abN; 538aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 539aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com c0.fPos = c; 540aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com c0.fPos += cbN; 541aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com c1.fPos = c; 542aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com c1.fPos -= cbN; 543aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 5441dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com // This point may not be within 1 pixel of a control point. We update the bounding box to 5451dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com // include it. 546aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); 5471dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); 548aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 549dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com if (toSrc) { 550dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad); 551dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 5521971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); 553aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 554aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 5553f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Input: 5563f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Three control points: p[0], p[1], p[2] and weight: w 5573f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Output: 5583f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Let: 5593f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// l = (2*w * (y1 - y0), 2*w * (x0 - x1), 2*w * (x1*y0 - x0*y1)) 5603f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// m = (2*w * (y2 - y1), 2*w * (x1 - x2), 2*w * (x2*y1 - x1*y2)) 5613f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// k = (y2 - y0, x0 - x2, (x2 - x0)*y0 - (y2 - y0)*x0 ) 5623f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.comvoid calc_conic_klm(const SkPoint p[3], const SkScalar weight, 5633f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar k[3], SkScalar l[3], SkScalar m[3]) { 5643f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com const SkScalar w2 = 2 * weight; 5653f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com l[0] = w2 * (p[1].fY - p[0].fY); 5663f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com l[1] = w2 * (p[0].fX - p[1].fX); 5673f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com l[2] = w2 * (p[1].fX * p[0].fY - p[0].fX * p[1].fY); 5683f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com 5693f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com m[0] = w2 * (p[2].fY - p[1].fY); 5703f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com m[1] = w2 * (p[1].fX - p[2].fX); 5713f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com m[2] = w2 * (p[2].fX * p[1].fY - p[1].fX * p[2].fY); 5723f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com 5733f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com k[0] = p[2].fY - p[0].fY; 5743f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com k[1] = p[0].fX - p[2].fX; 5753f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com k[2] = (p[2].fX - p[0].fX) * p[0].fY - (p[2].fY - p[0].fY) * p[0].fX; 5763f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com 5773f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com // scale the max absolute value of coeffs to 10 5783f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar scale = 0.0f; 5793f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com for (int i = 0; i < 3; ++i) { 5803f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com scale = SkMaxScalar(scale, SkScalarAbs(k[i])); 5813f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com scale = SkMaxScalar(scale, SkScalarAbs(l[i])); 5823f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com scale = SkMaxScalar(scale, SkScalarAbs(m[i])); 5833f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com } 5843f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com GrAssert(scale > 0); 5853f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com scale /= 10.0f; 5863f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com k[0] /= scale; 5873f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com k[1] /= scale; 5883f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com k[2] /= scale; 5893f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com l[0] /= scale; 5903f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com l[1] /= scale; 5913f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com l[2] /= scale; 5923f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com m[0] /= scale; 5933f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com m[1] /= scale; 5943f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com m[2] /= scale; 5953f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com} 5965383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 5973f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Equations based off of Loop-Blinn Quadratic GPU Rendering 5985383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// Input Parametric: 5995383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// P(t) = (P0*(1-t)^2 + 2*w*P1*t*(1-t) + P2*t^2) / (1-t)^2 + 2*w*t*(1-t) + t^2) 6005383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// Output Implicit: 6013f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// f(x, y, w) = f(P) = K^2 - LM 6023f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// K = dot(k, P), L = dot(l, P), M = dot(m, P) 6033f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// k, l, m are calculated in function calc_conic_klm 6045383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.comvoid set_conic_coeffs(const SkPoint p[3], Vertex verts[kVertsPerQuad], const float weight) { 6053f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar k[3]; 6063f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar l[3]; 6073f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar m[3]; 6083f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com 6093f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com calc_conic_klm(p, weight, k, l, m); 6105383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 6115383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com for (int i = 0; i < kVertsPerQuad; ++i) { 6123f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com const SkPoint pnt = verts[i].fPos; 6133f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com verts[i].fConic.fK = pnt.fX * k[0] + pnt.fY * k[1] + k[2]; 6143f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com verts[i].fConic.fL = pnt.fX * l[0] + pnt.fY * l[1] + l[2]; 6153f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com verts[i].fConic.fM = pnt.fX * m[0] + pnt.fY * m[1] + m[2]; 6165383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 6175383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com} 6185383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 6195383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.comvoid add_conics(const SkPoint p[3], 6205383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com float weight, 6215383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com const SkMatrix* toDevice, 6225383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com const SkMatrix* toSrc, 6235383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com Vertex** vert, 6245383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkRect* devBounds) { 6255383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com bloat_quad(p, toDevice, toSrc, *vert, devBounds); 6265383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com set_conic_coeffs(p, *vert, weight); 6275383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com *vert += kVertsPerQuad; 6285383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com} 6295383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 630aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comvoid add_quads(const SkPoint p[3], 631aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com int subdiv, 632b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com const SkMatrix* toDevice, 633b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com const SkMatrix* toSrc, 6341dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com Vertex** vert, 6351dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkRect* devBounds) { 636aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrAssert(subdiv >= 0); 637aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (subdiv) { 638aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkPoint newP[5]; 639aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkChopQuadAtHalf(p, newP); 6401dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert, devBounds); 6411dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert, devBounds); 642aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } else { 6431dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com bloat_quad(p, toDevice, toSrc, *vert, devBounds); 644aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com *vert += kVertsPerQuad; 645aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 646aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 647aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 648aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comvoid add_line(const SkPoint p[2], 649aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com int rtHeight, 650dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com const SkMatrix* toSrc, 651aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com Vertex** vert) { 652aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com const SkPoint& a = p[0]; 653aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com const SkPoint& b = p[1]; 654aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 655aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector orthVec = b; 656aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com orthVec -= a; 657aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 658aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (orthVec.setLength(SK_Scalar1)) { 659aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com orthVec.setOrthog(orthVec); 660aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 661706f66831a575bdc2b1ab1331b48b793cd487356bsalomon@google.com SkScalar lineC = -(a.dot(orthVec)); 662aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com for (int i = 0; i < kVertsPerLineSeg; ++i) { 663aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com (*vert)[i].fPos = (i < 2) ? a : b; 664aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (0 == i || 3 == i) { 665aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com (*vert)[i].fPos -= orthVec; 666aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } else { 667aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com (*vert)[i].fPos += orthVec; 668aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 669706f66831a575bdc2b1ab1331b48b793cd487356bsalomon@google.com (*vert)[i].fLine.fA = orthVec.fX; 670706f66831a575bdc2b1ab1331b48b793cd487356bsalomon@google.com (*vert)[i].fLine.fB = orthVec.fY; 671aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com (*vert)[i].fLine.fC = lineC; 672aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 673dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com if (NULL != toSrc) { 674dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com toSrc->mapPointsWithStride(&(*vert)->fPos, 675dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com sizeof(Vertex), 676dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com kVertsPerLineSeg); 677dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 678aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } else { 679aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // just make it degenerate and likely offscreen 680aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com (*vert)[0].fPos.set(SK_ScalarMax, SK_ScalarMax); 681aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); 682aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); 683aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); 684aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 685aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 686aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com *vert += kVertsPerLineSeg; 687aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 688aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 689aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 690aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 6915383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com/** 6923f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * Shader is based off of Loop-Blinn Quadratic GPU Rendering 6935383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com * The output of this effect is a hairline edge for conics. 6943f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * Conics specified by implicit equation K^2 - LM. 6953f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * K, L, and M, are the first three values of the vertex attribute, 6963f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * the fourth value is not used. Distance is calculated using a 6973f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * first order approximation from the taylor series. 6985383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com * Coverage is max(0, 1-distance). 6995383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com */ 7003f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com 7013f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com/** 7023f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * Test were also run using a second order distance approximation. 7033f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * There were two versions of the second order approx. The first version 7043f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * is of roughly the form: 7053f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * f(q) = |f(p)| - ||f'(p)||*||q-p|| - ||f''(p)||*||q-p||^2. 7063f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * The second is similar: 7073f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * f(q) = |f(p)| + ||f'(p)||*||q-p|| + ||f''(p)||*||q-p||^2. 7083f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * The exact version of the equations can be found in the paper 7093f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * "Distance Approximations for Rasterizing Implicit Curves" by Gabriel Taubin 7103f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * 7113f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * In both versions we solve the quadratic for ||q-p||. 7123f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * Version 1: 7133f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * gFM is magnitude of first partials and gFM2 is magnitude of 2nd partials (as derived from paper) 7143f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * builder->fsCodeAppend("\t\tedgeAlpha = (sqrt(gFM*gFM+4.0*func*gF2M) - gFM)/(2.0*gF2M);\n"); 7153f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * Version 2: 7163f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * builder->fsCodeAppend("\t\tedgeAlpha = (gFM - sqrt(gFM*gFM-4.0*func*gF2M))/(2.0*gF2M);\n"); 7173f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * 7183f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * Also note that 2nd partials of k,l,m are zero 7193f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * 7203f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * When comparing the two second order approximations to the first order approximations, 7213f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * the following results were found. Version 1 tends to underestimate the distances, thus it 7223f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * basically increases all the error that we were already seeing in the first order 7233f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * approx. So this version is not the one to use. Version 2 has the opposite effect 7243f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * and tends to overestimate the distances. This is much closer to what we are 7253f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * looking for. It is able to render ellipses (even thin ones) without the need to chop. 7263f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * However, it can not handle thin hyperbolas well and thus would still rely on 7273f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * chopping to tighten the clipping. Another side effect of the overestimating is 7283f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * that the curves become much thinner and "ropey". If all that was ever rendered 7293f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * were "not too thin" curves and ellipses then 2nd order may have an advantage since 7303f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * only one geometry would need to be rendered. However no benches were run comparing 7313f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com * chopped first order and non chopped 2nd order. 7323f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com */ 7335383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.comclass HairConicEdgeEffect : public GrEffect { 7345383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.compublic: 7355383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com static GrEffectRef* Create() { 7365383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com GR_CREATE_STATIC_EFFECT(gHairConicEdgeEffect, HairConicEdgeEffect, ()); 7375383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com gHairConicEdgeEffect->ref(); 7385383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return gHairConicEdgeEffect; 7395383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 7405383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 7415383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com virtual ~HairConicEdgeEffect() {} 7425383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 7435383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com static const char* Name() { return "HairConicEdge"; } 7445383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 7455383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com virtual void getConstantColorComponents(GrColor* color, 7465383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com uint32_t* validFlags) const SK_OVERRIDE { 7475383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com *validFlags = 0; 7485383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 7495383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 7505383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 7515383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return GrTBackendEffectFactory<HairConicEdgeEffect>::getInstance(); 7525383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 7535383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 7545383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com class GLEffect : public GrGLEffect { 7555383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com public: 7565383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) 7575383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com : INHERITED (factory) {} 7585383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 7595383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com virtual void emitCode(GrGLShaderBuilder* builder, 7605383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com const GrDrawEffect& drawEffect, 7615383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com EffectKey key, 7625383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com const char* outputColor, 7635383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com const char* inputColor, 7645383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com const TextureSamplerArray& samplers) SK_OVERRIDE { 7653f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com const char *vsName, *fsName; 7665383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 7675383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkAssertResult(builder->enableFeature( 7685383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); 7693f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com builder->addVarying(kVec4f_GrSLType, "ConicCoeffs", 7703f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com &vsName, &fsName); 7715383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com const SkString* attr0Name = 7725383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]); 7733f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com builder->vsCodeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str()); 7743f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com 7753f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com builder->fsCodeAppend("\t\tfloat edgeAlpha;\n"); 7763f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com 7773f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com builder->fsCodeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName); 7783f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com builder->fsCodeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName); 7793f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com builder->fsCodeAppendf("\t\tfloat dfdx =\n" 7803f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com "\t\t\t2.0*%s.x*dklmdx.x - %s.y*dklmdx.z - %s.z*dklmdx.y;\n", 7813f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com fsName, fsName, fsName); 7823f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com builder->fsCodeAppendf("\t\tfloat dfdy =\n" 7833f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com "\t\t\t2.0*%s.x*dklmdy.x - %s.y*dklmdy.z - %s.z*dklmdy.y;\n", 7843f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com fsName, fsName, fsName); 7853f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com builder->fsCodeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n"); 7863f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com builder->fsCodeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n"); 7873f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com builder->fsCodeAppendf("\t\tfloat func = abs(%s.x*%s.x - %s.y*%s.z);\n", fsName, fsName, 7883f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com fsName, fsName); 7893f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com builder->fsCodeAppend("\t\tedgeAlpha = func / gFM;\n"); 7903f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com builder->fsCodeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n"); 7915383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com // Add line below for smooth cubic ramp 7925383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n"); 7935383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 7945383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkString modulate; 7955383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); 7965383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()); 7975383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 7985383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 7995383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { 8005383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 0x0; 8015383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 8025383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 8035383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {} 8045383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 8055383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com private: 8065383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com typedef GrGLEffect INHERITED; 8075383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com }; 8085383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 8095383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.comprivate: 8105383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com HairConicEdgeEffect() { 8115383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com this->addVertexAttrib(kVec4f_GrSLType); 8125383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 8135383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 8145383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { 8155383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return true; 8165383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 8175383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 8185383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com GR_DECLARE_EFFECT_TEST; 8195383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 8205383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com typedef GrEffect INHERITED; 8215383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com}; 8225383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 8235383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.comGR_DEFINE_EFFECT_TEST(HairConicEdgeEffect); 8245383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 8255383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.comGrEffectRef* HairConicEdgeEffect::TestCreate(SkMWCRandom* random, 8265383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com GrContext*, 8275383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com const GrDrawTargetCaps& caps, 8285383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com GrTexture*[]) { 8293f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com return caps.shaderDerivativeSupport() ? HairConicEdgeEffect::Create() : NULL; 8305383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com} 83190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 83290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/** 83390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * The output of this effect is a hairline edge for quadratics. 83490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * Quadratic specified by 0=u^2-v canonical coords. u and v are the first 83590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * two components of the vertex attribute. Uses unsigned distance. 836041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com * Coverage is min(0, 1-distance). 3rd & 4th component unused. 837041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com * Requires shader derivative instruction support. 83890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org */ 83990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgclass HairQuadEdgeEffect : public GrEffect { 84090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgpublic: 84190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 84290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org static GrEffectRef* Create() { 843d42aca31b9ddc1cb9a81522b4c73a9fe550450bcbsalomon@google.com GR_CREATE_STATIC_EFFECT(gHairQuadEdgeEffect, HairQuadEdgeEffect, ()); 844d42aca31b9ddc1cb9a81522b4c73a9fe550450bcbsalomon@google.com gHairQuadEdgeEffect->ref(); 845d42aca31b9ddc1cb9a81522b4c73a9fe550450bcbsalomon@google.com return gHairQuadEdgeEffect; 84690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 84790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 84890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org virtual ~HairQuadEdgeEffect() {} 84990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 85090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org static const char* Name() { return "HairQuadEdge"; } 85190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 852041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com virtual void getConstantColorComponents(GrColor* color, 85390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org uint32_t* validFlags) const SK_OVERRIDE { 85490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org *validFlags = 0; 85590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 85690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 85790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 85890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org return GrTBackendEffectFactory<HairQuadEdgeEffect>::getInstance(); 85990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 86090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 86190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org class GLEffect : public GrGLEffect { 86290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org public: 86390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) 86490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org : INHERITED (factory) {} 86590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 86690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org virtual void emitCode(GrGLShaderBuilder* builder, 86790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org const GrDrawEffect& drawEffect, 86890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org EffectKey key, 86990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org const char* outputColor, 87090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org const char* inputColor, 87190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org const TextureSamplerArray& samplers) SK_OVERRIDE { 87290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org const char *vsName, *fsName; 87390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org const SkString* attrName = 87490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]); 87590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); 87690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 87790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org SkAssertResult(builder->enableFeature( 8785383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); 87990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsName); 88090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 88190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName); 88290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName); 88390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n" 88490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org "\t\t 2.0*%s.x*duvdy.x - duvdy.y);\n", 88590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org fsName, fsName); 88690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, 88790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org fsName); 88890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n"); 88990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->fsCodeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n"); 89090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 89190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org SkString modulate; 892018f179efb2413431bdb1a9e6701eb44ef36b792bsalomon@google.com GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); 89390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()); 89490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 89590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str()); 89690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 89790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 89890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { 89990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org return 0x0; 90090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 90190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 90290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {} 90390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 90490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org private: 90590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org typedef GrGLEffect INHERITED; 90690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org }; 90790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 90890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgprivate: 909041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com HairQuadEdgeEffect() { 910041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com this->addVertexAttrib(kVec4f_GrSLType); 91190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 91290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 91390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { 91490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org return true; 91590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 91690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 91790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org GR_DECLARE_EFFECT_TEST; 91890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 91990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org typedef GrEffect INHERITED; 92090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org}; 92190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 92290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgGR_DEFINE_EFFECT_TEST(HairQuadEdgeEffect); 92390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 92490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgGrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random, 92590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org GrContext*, 92690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org const GrDrawTargetCaps& caps, 92790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org GrTexture*[]) { 92890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org // Doesn't work without derivative instructions. 9295383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; 9305383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com} 93190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 93290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/////////////////////////////////////////////////////////////////////////////// 93390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 93490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/** 935041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com * The output of this effect is a 1-pixel wide line. 936041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com * Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component unused. 93790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org */ 93890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgclass HairLineEdgeEffect : public GrEffect { 93990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgpublic: 94090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 94190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org static GrEffectRef* Create() { 942d42aca31b9ddc1cb9a81522b4c73a9fe550450bcbsalomon@google.com GR_CREATE_STATIC_EFFECT(gHairLineEdge, HairLineEdgeEffect, ()); 943d42aca31b9ddc1cb9a81522b4c73a9fe550450bcbsalomon@google.com gHairLineEdge->ref(); 944d42aca31b9ddc1cb9a81522b4c73a9fe550450bcbsalomon@google.com return gHairLineEdge; 94590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 94690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 94790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org virtual ~HairLineEdgeEffect() {} 94890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 94990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org static const char* Name() { return "HairLineEdge"; } 95090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 951041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com virtual void getConstantColorComponents(GrColor* color, 95290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org uint32_t* validFlags) const SK_OVERRIDE { 95390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org *validFlags = 0; 95490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 95590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 95690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 95790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org return GrTBackendEffectFactory<HairLineEdgeEffect>::getInstance(); 95890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 95990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 96090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org class GLEffect : public GrGLEffect { 96190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org public: 96290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) 96390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org : INHERITED (factory) {} 96490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 96590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org virtual void emitCode(GrGLShaderBuilder* builder, 96690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org const GrDrawEffect& drawEffect, 96790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org EffectKey key, 96890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org const char* outputColor, 96990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org const char* inputColor, 97090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org const TextureSamplerArray& samplers) SK_OVERRIDE { 97190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org const char *vsName, *fsName; 97290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org const SkString* attrName = 97390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]); 97490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); 97590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 97690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->addVarying(kVec4f_GrSLType, "HairLineEdge", &vsName, &fsName); 97790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 97890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->fsCodeAppendf("\t\tedgeAlpha = abs(dot(vec3(%s.xy,1), %s.xyz));\n", 97990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->fragmentPosition(), fsName); 98090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->fsCodeAppendf("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n"); 98190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 98290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org SkString modulate; 983018f179efb2413431bdb1a9e6701eb44ef36b792bsalomon@google.com GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); 98490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()); 98590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 98690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str()); 98790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 98890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 98990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { 99090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org return 0x0; 99190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 99290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 99390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {} 99490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 99590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org private: 99690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org typedef GrGLEffect INHERITED; 99790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org }; 99890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 99990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgprivate: 1000041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com HairLineEdgeEffect() { 1001041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com this->addVertexAttrib(kVec4f_GrSLType); 10028d47ddc19a40d1984bf1f384d711d36ab59fd1c0commit-bot@chromium.org this->setWillReadFragmentPosition(); 100390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 100490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 100590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { 100690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org return true; 100790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 100890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 100990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org GR_DECLARE_EFFECT_TEST; 101090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 101190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org typedef GrEffect INHERITED; 101290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org}; 101390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 101490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgGR_DEFINE_EFFECT_TEST(HairLineEdgeEffect); 101590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 101690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgGrEffectRef* HairLineEdgeEffect::TestCreate(SkMWCRandom* random, 101790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org GrContext*, 101890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org const GrDrawTargetCaps& caps, 101990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org GrTexture*[]) { 102090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org return HairLineEdgeEffect::Create(); 102190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org} 102290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 102390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/////////////////////////////////////////////////////////////////////////////// 102490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 1025429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.comnamespace { 1026429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com 1027429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com// position + edge 1028429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.comextern const GrVertexAttrib gHairlineAttribs[] = { 1029429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, 1030429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding} 1031429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com}; 1032429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com}; 1033429033038271147ed66b4bc2675ac98a5ccfa75crobertphillips@google.com 1034b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.combool GrAAHairLinePathRenderer::createGeom( 1035b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com const SkPath& path, 1036b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com GrDrawTarget* target, 1037b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com int* lineCnt, 1038b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com int* quadCnt, 10395383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com int* conicCnt, 10401dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com GrDrawTarget::AutoReleaseGeometry* arg, 10411dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkRect* devBounds) { 10429b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com GrDrawState* drawState = target->drawState(); 10439b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com int rtHeight = drawState->getRenderTarget()->height(); 1044aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 1045fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org SkIRect devClipBounds; 1046912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devClipBounds); 1047aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 10489b855c7c95ce9fff7a447e4a6bdf8a469c1f3097jvanverth@google.com SkMatrix viewM = drawState->getViewMatrix(); 1049aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 10501dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com // All the vertices that we compute are within 1 of path control points with the exception of 10511dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com // one of the bounding vertices for each quad. The add_quads() function will update the bounds 10521dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com // for each quad added. 10531dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com *devBounds = path.getBounds(); 10541dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com viewM.mapRect(devBounds); 10551dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com devBounds->outset(SK_Scalar1, SK_Scalar1); 10561dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com 105792669014aa7ab821cdc09cc9ad610316eb16b490bsalomon@google.com PREALLOC_PTARRAY(128) lines; 105892669014aa7ab821cdc09cc9ad610316eb16b490bsalomon@google.com PREALLOC_PTARRAY(128) quads; 10595383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com PREALLOC_PTARRAY(128) conics; 1060aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com IntArray qSubdivs; 10615383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com FloatArray cWeights; 10620f11e1ab5b6e53f6176dde2dbb25a8e3ae34858fbsalomon@google.com *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, 10635383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com &lines, &quads, &conics, &qSubdivs, &cWeights); 1064aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 1065c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com *lineCnt = lines.count() / 2; 10665383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com *conicCnt = conics.count() / 3; 10675383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt + 10685383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com kVertsPerQuad * *conicCnt; 1069aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 10703f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHairlineAttribs)); 1071b75b0a0b8492e14c7728e0a0881f87dc64ce60f9jvanverth@google.com GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); 1072aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 1073b75b0a0b8492e14c7728e0a0881f87dc64ce60f9jvanverth@google.com if (!arg->set(target, vertCnt, 0)) { 1074aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return false; 1075aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 1076dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com 1077b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); 1078b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com 1079b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com const SkMatrix* toDevice = NULL; 1080b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com const SkMatrix* toSrc = NULL; 1081b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com SkMatrix ivm; 1082dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com 1083dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com if (viewM.hasPerspective()) { 1084dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com if (viewM.invert(&ivm)) { 1085dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com toDevice = &viewM; 1086dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com toSrc = &ivm; 1087dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 1088dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 1089aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 1090c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com for (int i = 0; i < *lineCnt; ++i) { 1091dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com add_line(&lines[2*i], rtHeight, toSrc, &verts); 1092aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 1093dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com 1094aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com int unsubdivQuadCnt = quads.count() / 3; 1095aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com for (int i = 0; i < unsubdivQuadCnt; ++i) { 1096aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GrAssert(qSubdivs[i] >= 0); 10971dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); 1098aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 1099aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 11005383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com // Start Conics 11015383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com for (int i = 0; i < *conicCnt; ++i) { 11025383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds); 11035383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1104aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return true; 1105aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 1106aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 11078a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.combool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, 11085f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com const SkStrokeRec& stroke, 11098a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com const GrDrawTarget* target, 11108a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com bool antiAlias) const { 11115f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com if (!stroke.isHairlineStyle() || !antiAlias) { 1112c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com return false; 1113c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com } 1114c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com 11153f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com if (SkPath::kLine_SegmentMask == path.getSegmentMasks() || 11163f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com target->caps()->shaderDerivativeSupport()) { 11173f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com return true; 1118c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com } 11193f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com return false; 1120c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com} 1121aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 1122c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.combool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, 11235f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com const SkStrokeRec&, 1124c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com GrDrawTarget* target, 1125c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com bool antiAlias) { 1126c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com 1127c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com int lineCnt; 1128c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com int quadCnt; 11295383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com int conicCnt; 1130b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com GrDrawTarget::AutoReleaseGeometry arg; 11311dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkRect devBounds; 11321dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com 1133c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com if (!this->createGeom(path, 1134c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com target, 1135c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com &lineCnt, 1136b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com &quadCnt, 11375383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com &conicCnt, 11381dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com &arg, 11391dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com &devBounds)) { 1140c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com return false; 1141aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 1142aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 1143137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com GrDrawTarget::AutoStateRestore asr; 11444647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com 1145a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com // createGeom transforms the geometry to device space when the matrix does not have 1146a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com // perspective. 1147137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com if (target->getDrawState().getViewMatrix().hasPerspective()) { 1148137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com asr.set(target, GrDrawTarget::kPreserve_ASRInit); 1149137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { 1150137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com return false; 1151aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 1152137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com GrDrawState* drawState = target->drawState(); 1153fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 1154aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // TODO: See whether rendering lines as degenerate quads improves perf 1155aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // when we have a mix 1156a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com 11574647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com static const int kEdgeAttrIndex = 1; 1158a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com 115990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); 116090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); 11615383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create(); 116237cbc7fd014e3b35833523dbdbe3bc3ac52ecacdskia.committer@gmail.com 11631dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com // Check devBounds 11641dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com#if GR_DEBUG 11651dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkRect tolDevBounds = devBounds; 11661dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); 11671dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkRect actualBounds; 11681dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); 11695383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt + kVertsPerQuad * conicCnt; 11701dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com bool first = true; 11711dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com for (int i = 0; i < vCount; ++i) { 11721dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkPoint pos = verts[i].fPos; 11731dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com // This is a hack to workaround the fact that we move some degenerate segments offscreen. 11741dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com if (SK_ScalarMax == pos.fX) { 11751dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com continue; 11761dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } 11771dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com drawState->getViewMatrix().mapPoints(&pos, 1); 11781dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com if (first) { 11791dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); 11801dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com first = false; 11811dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } else { 11821dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com actualBounds.growToInclude(pos.fX, pos.fY); 11831dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } 11841dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } 11851dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com if (!first) { 11861dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com GrAssert(tolDevBounds.contains(actualBounds)); 11871dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } 11881dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com#endif 11891dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com 1190eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com { 1191eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com GrDrawState::AutoRestoreEffects are(drawState); 1192eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com target->setIndexSourceToBuffer(fLinesIndexBuffer); 1193eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com int lines = 0; 1194eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com int nBufLines = fLinesIndexBuffer->maxQuads(); 1195eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com drawState->addCoverageEffect(hairLineEffect, kEdgeAttrIndex)->unref(); 1196eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com while (lines < lineCnt) { 1197eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com int n = GrMin(lineCnt - lines, nBufLines); 1198eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com target->drawIndexed(kTriangles_GrPrimitiveType, 1199eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com kVertsPerLineSeg*lines, // startV 1200eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com 0, // startI 1201eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com kVertsPerLineSeg*n, // vCount 1202eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com kIdxsPerLineSeg*n, 1203eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com &devBounds); // iCount 1204eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com lines += n; 1205eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com } 1206aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 1207aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 12085383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com { 12095383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com GrDrawState::AutoRestoreEffects are(drawState); 12105383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com target->setIndexSourceToBuffer(fQuadsIndexBuffer); 12115383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com int quads = 0; 12125383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); 12135383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com while (quads < quadCnt) { 12145383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); 12155383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com target->drawIndexed(kTriangles_GrPrimitiveType, 12165383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com kVertsPerLineSeg * lineCnt + kVertsPerQuad*quads, // startV 12175383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 0, // startI 12185383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com kVertsPerQuad*n, // vCount 12195383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com kIdxsPerQuad*n, // iCount 12205383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com &devBounds); 12215383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com quads += n; 12225383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 12235383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 12245383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 12255383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com { 12265383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com GrDrawState::AutoRestoreEffects are(drawState); 12275383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com int conics = 0; 12285383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref(); 12295383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com while (conics < conicCnt) { 12305383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer); 12315383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com target->drawIndexed(kTriangles_GrPrimitiveType, 12325383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com kVertsPerLineSeg*lineCnt + 12335383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com kVertsPerQuad*(quadCnt + conics), // startV 12345383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 0, // startI 12355383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com kVertsPerQuad*n, // vCount 12365383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com kIdxsPerQuad*n, // iCount 12375383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com &devBounds); 12385383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com conics += n; 12395383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1240aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 12410406b9e1faee06c6ecb2732a1bcf3b0e53104e07bsalomon@google.com target->resetIndexSource(); 12424647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com 1243c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com return true; 1244aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 1245