| OLD | NEW |
| (Empty) |
| 1 #include "SkGL.h" | |
| 2 #include "SkColorPriv.h" | |
| 3 #include "SkGeometry.h" | |
| 4 #include "SkPaint.h" | |
| 5 #include "SkPath.h" | |
| 6 #include "SkTemplates.h" | |
| 7 #include "SkXfermode.h" | |
| 8 | |
| 9 //#define TRACE_TEXTURE_CREATION | |
| 10 | |
| 11 /////////////////////////////////////////////////////////////////////////////// | |
| 12 | |
| 13 #ifdef SK_GL_HAS_COLOR4UB | |
| 14 static inline void gl_pmcolor(U8CPU r, U8CPU g, U8CPU b, U8CPU a) { | |
| 15 glColor4ub(r, g, b, a); | |
| 16 } | |
| 17 | |
| 18 void SkGL::SetAlpha(U8CPU alpha) { | |
| 19 glColor4ub(alpha, alpha, alpha, alpha); | |
| 20 } | |
| 21 #else | |
| 22 static inline SkFixed byte2fixed(U8CPU value) { | |
| 23 return (value + (value >> 7)) << 8; | |
| 24 } | |
| 25 | |
| 26 static inline void gl_pmcolor(U8CPU r, U8CPU g, U8CPU b, U8CPU a) { | |
| 27 glColor4x(byte2fixed(r), byte2fixed(g), byte2fixed(b), byte2fixed(a)); | |
| 28 } | |
| 29 | |
| 30 void SkGL::SetAlpha(U8CPU alpha) { | |
| 31 SkFixed fa = byte2fixed(alpha); | |
| 32 glColor4x(fa, fa, fa, fa); | |
| 33 } | |
| 34 #endif | |
| 35 | |
| 36 void SkGL::SetColor(SkColor c) { | |
| 37 SkPMColor pm = SkPreMultiplyColor(c); | |
| 38 gl_pmcolor(SkGetPackedR32(pm), | |
| 39 SkGetPackedG32(pm), | |
| 40 SkGetPackedB32(pm), | |
| 41 SkGetPackedA32(pm)); | |
| 42 } | |
| 43 | |
| 44 static const GLenum gXfermodeCoeff2Blend[] = { | |
| 45 GL_ZERO, | |
| 46 GL_ONE, | |
| 47 GL_SRC_COLOR, | |
| 48 GL_ONE_MINUS_SRC_COLOR, | |
| 49 GL_DST_COLOR, | |
| 50 GL_ONE_MINUS_DST_COLOR, | |
| 51 GL_SRC_ALPHA, | |
| 52 GL_ONE_MINUS_SRC_ALPHA, | |
| 53 GL_DST_ALPHA, | |
| 54 GL_ONE_MINUS_DST_ALPHA, | |
| 55 }; | |
| 56 | |
| 57 void SkGL::SetPaint(const SkPaint& paint, bool isPremul, bool justAlpha) { | |
| 58 if (justAlpha) { | |
| 59 SkGL::SetAlpha(paint.getAlpha()); | |
| 60 } else { | |
| 61 SkGL::SetColor(paint.getColor()); | |
| 62 } | |
| 63 | |
| 64 GLenum sm = GL_ONE; | |
| 65 GLenum dm = GL_ONE_MINUS_SRC_ALPHA; | |
| 66 | |
| 67 SkXfermode* mode = paint.getXfermode(); | |
| 68 SkXfermode::Coeff sc, dc; | |
| 69 if (mode && mode->asCoeff(&sc, &dc)) { | |
| 70 sm = gXfermodeCoeff2Blend[sc]; | |
| 71 dm = gXfermodeCoeff2Blend[dc]; | |
| 72 } | |
| 73 | |
| 74 // hack for text, which is not-premul (afaik) | |
| 75 if (!isPremul) { | |
| 76 if (GL_ONE == sm) { | |
| 77 sm = GL_SRC_ALPHA; | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 glEnable(GL_BLEND); | |
| 82 glBlendFunc(sm, dm); | |
| 83 | |
| 84 if (paint.isDither()) { | |
| 85 glEnable(GL_DITHER); | |
| 86 } else { | |
| 87 glDisable(GL_DITHER); | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 /////////////////////////////////////////////////////////////////////////////// | |
| 92 | |
| 93 void SkGL::DumpError(const char caller[]) { | |
| 94 GLenum err = glGetError(); | |
| 95 if (err) { | |
| 96 SkDebugf("---- glGetError(%s) %d\n", caller, err); | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 void SkGL::SetRGBA(uint8_t rgba[], const SkColor src[], int count) { | |
| 101 for (int i = 0; i < count; i++) { | |
| 102 SkPMColor c = SkPreMultiplyColor(*src++); | |
| 103 *rgba++ = SkGetPackedR32(c); | |
| 104 *rgba++ = SkGetPackedG32(c); | |
| 105 *rgba++ = SkGetPackedB32(c); | |
| 106 *rgba++ = SkGetPackedA32(c); | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 /////////////////////////////////////////////////////////////////////////////// | |
| 111 | |
| 112 void SkGL::Scissor(const SkIRect& r, int viewportHeight) { | |
| 113 glScissor(r.fLeft, viewportHeight - r.fBottom, r.width(), r.height()); | |
| 114 } | |
| 115 | |
| 116 /////////////////////////////////////////////////////////////////////////////// | |
| 117 | |
| 118 void SkGL::Ortho(float left, float right, float bottom, float top, | |
| 119 float near, float far) { | |
| 120 | |
| 121 float mat[16]; | |
| 122 | |
| 123 bzero(mat, sizeof(mat)); | |
| 124 | |
| 125 mat[0] = 2 / (right - left); | |
| 126 mat[5] = 2 / (top - bottom); | |
| 127 mat[10] = 2 / (near - far); | |
| 128 mat[15] = 1; | |
| 129 | |
| 130 mat[12] = (right + left) / (left - right); | |
| 131 mat[13] = (top + bottom) / (bottom - top); | |
| 132 mat[14] = (far + near) / (near - far); | |
| 133 | |
| 134 glMultMatrixf(mat); | |
| 135 } | |
| 136 | |
| 137 /////////////////////////////////////////////////////////////////////////////// | |
| 138 | |
| 139 static bool canBeTexture(const SkBitmap& bm, GLenum* format, GLenum* type) { | |
| 140 switch (bm.config()) { | |
| 141 case SkBitmap::kARGB_8888_Config: | |
| 142 *format = GL_RGBA; | |
| 143 *type = GL_UNSIGNED_BYTE; | |
| 144 break; | |
| 145 case SkBitmap::kRGB_565_Config: | |
| 146 *format = GL_RGB; | |
| 147 *type = GL_UNSIGNED_SHORT_5_6_5; | |
| 148 break; | |
| 149 case SkBitmap::kARGB_4444_Config: | |
| 150 *format = GL_RGBA; | |
| 151 *type = GL_UNSIGNED_SHORT_4_4_4_4; | |
| 152 break; | |
| 153 case SkBitmap::kIndex8_Config: | |
| 154 #ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D | |
| 155 *format = GL_PALETTE8_RGBA8_OES; | |
| 156 *type = GL_UNSIGNED_BYTE; // unused I think | |
| 157 #else | |
| 158 // we promote index to argb32 | |
| 159 *format = GL_RGBA; | |
| 160 *type = GL_UNSIGNED_BYTE; | |
| 161 #endif | |
| 162 break; | |
| 163 case SkBitmap::kA8_Config: | |
| 164 *format = GL_ALPHA; | |
| 165 *type = GL_UNSIGNED_BYTE; | |
| 166 break; | |
| 167 default: | |
| 168 return false; | |
| 169 } | |
| 170 return true; | |
| 171 } | |
| 172 | |
| 173 #define SK_GL_SIZE_OF_PALETTE (256 * sizeof(SkPMColor)) | |
| 174 | |
| 175 size_t SkGL::ComputeTextureMemorySize(const SkBitmap& bitmap) { | |
| 176 int shift = 0; | |
| 177 size_t adder = 0; | |
| 178 switch (bitmap.config()) { | |
| 179 case SkBitmap::kARGB_8888_Config: | |
| 180 case SkBitmap::kRGB_565_Config: | |
| 181 case SkBitmap::kARGB_4444_Config: | |
| 182 case SkBitmap::kA8_Config: | |
| 183 // we're good as is | |
| 184 break; | |
| 185 case SkBitmap::kIndex8_Config: | |
| 186 #ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D | |
| 187 // account for the colortable | |
| 188 adder = SK_GL_SIZE_OF_PALETTE; | |
| 189 #else | |
| 190 // we promote index to argb32 | |
| 191 shift = 2; | |
| 192 #endif | |
| 193 break; | |
| 194 default: | |
| 195 return 0; | |
| 196 } | |
| 197 return (bitmap.getSize() << shift) + adder; | |
| 198 } | |
| 199 | |
| 200 #ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D | |
| 201 /* Fill out buffer with the compressed format GL expects from a colortable | |
| 202 based bitmap. [palette (colortable) + indices]. | |
| 203 | |
| 204 At the moment I always take the 8bit version, since that's what my data | |
| 205 is. I could detect that the colortable.count is <= 16, and then repack the | |
| 206 indices as nibbles to save RAM, but it would take more time (i.e. a lot | |
| 207 slower than memcpy), so I'm skipping that for now. | |
| 208 | |
| 209 GL wants a full 256 palette entry, even though my ctable is only as big | |
| 210 as the colortable.count says it is. I presume it is OK to leave any | |
| 211 trailing entries uninitialized, since none of my indices should exceed | |
| 212 ctable->count(). | |
| 213 */ | |
| 214 static void build_compressed_data(void* buffer, const SkBitmap& bitmap) { | |
| 215 SkASSERT(SkBitmap::kIndex8_Config == bitmap.config()); | |
| 216 | |
| 217 SkColorTable* ctable = bitmap.getColorTable(); | |
| 218 uint8_t* dst = (uint8_t*)buffer; | |
| 219 | |
| 220 memcpy(dst, ctable->lockColors(), ctable->count() * sizeof(SkPMColor)); | |
| 221 ctable->unlockColors(false); | |
| 222 | |
| 223 // always skip a full 256 number of entries, even if we memcpy'd fewer | |
| 224 dst += SK_GL_SIZE_OF_PALETTE; | |
| 225 memcpy(dst, bitmap.getPixels(), bitmap.getSize()); | |
| 226 } | |
| 227 #endif | |
| 228 | |
| 229 /* Return true if the bitmap cannot be supported in its current config as a | |
| 230 texture, and it needs to be promoted to ARGB32. | |
| 231 */ | |
| 232 static bool needToPromoteTo32bit(const SkBitmap& bitmap) { | |
| 233 if (bitmap.config() == SkBitmap::kIndex8_Config) { | |
| 234 #ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D | |
| 235 const int w = bitmap.width(); | |
| 236 const int h = bitmap.height(); | |
| 237 if (SkNextPow2(w) == w && SkNextPow2(h) == h) { | |
| 238 // we can handle Indx8 if we're a POW2 | |
| 239 return false; | |
| 240 } | |
| 241 #endif | |
| 242 return true; // must promote to ARGB32 | |
| 243 } | |
| 244 return false; | |
| 245 } | |
| 246 | |
| 247 GLuint SkGL::BindNewTexture(const SkBitmap& origBitmap, SkPoint* max) { | |
| 248 SkBitmap tmpBitmap; | |
| 249 const SkBitmap* bitmap = &origBitmap; | |
| 250 | |
| 251 if (needToPromoteTo32bit(origBitmap)) { | |
| 252 origBitmap.copyTo(&tmpBitmap, SkBitmap::kARGB_8888_Config); | |
| 253 // now bitmap points to our temp, which has been promoted to 32bits | |
| 254 bitmap = &tmpBitmap; | |
| 255 } | |
| 256 | |
| 257 GLenum format, type; | |
| 258 if (!canBeTexture(*bitmap, &format, &type)) { | |
| 259 return 0; | |
| 260 } | |
| 261 | |
| 262 SkAutoLockPixels alp(*bitmap); | |
| 263 if (!bitmap->readyToDraw()) { | |
| 264 return 0; | |
| 265 } | |
| 266 | |
| 267 GLuint textureName; | |
| 268 glGenTextures(1, &textureName); | |
| 269 | |
| 270 glBindTexture(GL_TEXTURE_2D, textureName); | |
| 271 | |
| 272 // express rowbytes as a number of pixels for ow | |
| 273 int ow = bitmap->rowBytesAsPixels(); | |
| 274 int oh = bitmap->height(); | |
| 275 int nw = SkNextPow2(ow); | |
| 276 int nh = SkNextPow2(oh); | |
| 277 | |
| 278 glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel()); | |
| 279 | |
| 280 // check if we need to scale to create power-of-2 dimensions | |
| 281 #ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D | |
| 282 if (SkBitmap::kIndex8_Config == bitmap->config()) { | |
| 283 size_t imagesize = bitmap->getSize() + SK_GL_SIZE_OF_PALETTE; | |
| 284 SkAutoMalloc storage(imagesize); | |
| 285 | |
| 286 build_compressed_data(storage.get(), *bitmap); | |
| 287 // we only support POW2 here (GLES 1.0 restriction) | |
| 288 SkASSERT(ow == nw); | |
| 289 SkASSERT(oh == nh); | |
| 290 glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, ow, oh, 0, | |
| 291 imagesize, storage.get()); | |
| 292 } else // fall through to non-compressed logic | |
| 293 #endif | |
| 294 { | |
| 295 if (ow != nw || oh != nh) { | |
| 296 glTexImage2D(GL_TEXTURE_2D, 0, format, nw, nh, 0, | |
| 297 format, type, NULL); | |
| 298 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ow, oh, | |
| 299 format, type, bitmap->getPixels()); | |
| 300 } else { | |
| 301 // easy case, the bitmap is already pow2 | |
| 302 glTexImage2D(GL_TEXTURE_2D, 0, format, ow, oh, 0, | |
| 303 format, type, bitmap->getPixels()); | |
| 304 } | |
| 305 } | |
| 306 | |
| 307 #ifdef TRACE_TEXTURE_CREATION | |
| 308 SkDebugf("--- new texture [%d] size=(%d %d) bpp=%d\n", textureName, ow, oh, | |
| 309 bitmap->bytesPerPixel()); | |
| 310 #endif | |
| 311 | |
| 312 if (max) { | |
| 313 max->fX = SkFixedToScalar(bitmap->width() << (16 - SkNextLog2(nw))); | |
| 314 max->fY = SkFixedToScalar(oh << (16 - SkNextLog2(nh))); | |
| 315 } | |
| 316 return textureName; | |
| 317 } | |
| 318 | |
| 319 static const GLenum gTileMode2GLWrap[] = { | |
| 320 GL_CLAMP_TO_EDGE, | |
| 321 GL_REPEAT, | |
| 322 #if GL_VERSION_ES_CM_1_0 | |
| 323 GL_REPEAT // GLES doesn't support MIRROR | |
| 324 #else | |
| 325 GL_MIRRORED_REPEAT | |
| 326 #endif | |
| 327 }; | |
| 328 | |
| 329 void SkGL::SetTexParams(bool doFilter, | |
| 330 SkShader::TileMode tx, SkShader::TileMode ty) { | |
| 331 SkASSERT((unsigned)tx < SK_ARRAY_COUNT(gTileMode2GLWrap)); | |
| 332 SkASSERT((unsigned)ty < SK_ARRAY_COUNT(gTileMode2GLWrap)); | |
| 333 | |
| 334 GLenum filter = doFilter ? GL_LINEAR : GL_NEAREST; | |
| 335 | |
| 336 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); | |
| 337 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); | |
| 338 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gTileMode2GLWrap[tx]); | |
| 339 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gTileMode2GLWrap[ty]); | |
| 340 } | |
| 341 | |
| 342 void SkGL::SetTexParamsClamp(bool doFilter) { | |
| 343 GLenum filter = doFilter ? GL_LINEAR : GL_NEAREST; | |
| 344 | |
| 345 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); | |
| 346 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); | |
| 347 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| 348 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 349 } | |
| 350 | |
| 351 /////////////////////////////////////////////////////////////////////////////// | |
| 352 | |
| 353 void SkGL::DrawVertices(int count, GLenum mode, | |
| 354 const SkGLVertex* SK_RESTRICT vertex, | |
| 355 const SkGLVertex* SK_RESTRICT texCoords, | |
| 356 const uint8_t* SK_RESTRICT colorArray, | |
| 357 const uint16_t* SK_RESTRICT indexArray, | |
| 358 SkGLClipIter* iter) { | |
| 359 SkASSERT(NULL != vertex); | |
| 360 | |
| 361 if (NULL != texCoords) { | |
| 362 glEnable(GL_TEXTURE_2D); | |
| 363 glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |
| 364 glTexCoordPointer(2, SK_GLType, 0, texCoords); | |
| 365 } else { | |
| 366 glDisable(GL_TEXTURE_2D); | |
| 367 glDisableClientState(GL_TEXTURE_COORD_ARRAY); | |
| 368 } | |
| 369 | |
| 370 if (NULL != colorArray) { | |
| 371 glEnableClientState(GL_COLOR_ARRAY); | |
| 372 glColorPointer(4, GL_UNSIGNED_BYTE, 0, colorArray); | |
| 373 glShadeModel(GL_SMOOTH); | |
| 374 } else { | |
| 375 glDisableClientState(GL_COLOR_ARRAY); | |
| 376 glShadeModel(GL_FLAT); | |
| 377 } | |
| 378 | |
| 379 glVertexPointer(2, SK_GLType, 0, vertex); | |
| 380 | |
| 381 if (NULL != indexArray) { | |
| 382 if (iter) { | |
| 383 while (!iter->done()) { | |
| 384 iter->scissor(); | |
| 385 glDrawElements(mode, count, GL_UNSIGNED_SHORT, indexArray); | |
| 386 iter->next(); | |
| 387 } | |
| 388 } else { | |
| 389 glDrawElements(mode, count, GL_UNSIGNED_SHORT, indexArray); | |
| 390 } | |
| 391 } else { | |
| 392 if (iter) { | |
| 393 while (!iter->done()) { | |
| 394 iter->scissor(); | |
| 395 glDrawArrays(mode, 0, count); | |
| 396 iter->next(); | |
| 397 } | |
| 398 } else { | |
| 399 glDrawArrays(mode, 0, count); | |
| 400 } | |
| 401 } | |
| 402 } | |
| 403 | |
| 404 void SkGL::PrepareForFillPath(SkPaint* paint) { | |
| 405 if (paint->getStrokeWidth() <= 0) { | |
| 406 paint->setStrokeWidth(SK_Scalar1); | |
| 407 } | |
| 408 } | |
| 409 | |
| 410 void SkGL::FillPath(const SkPath& path, const SkPaint& paint, bool useTex, | |
| 411 SkGLClipIter* iter) { | |
| 412 SkPaint p(paint); | |
| 413 SkPath fillPath; | |
| 414 | |
| 415 SkGL::PrepareForFillPath(&p); | |
| 416 p.getFillPath(path, &fillPath); | |
| 417 SkGL::DrawPath(fillPath, useTex, iter); | |
| 418 } | |
| 419 | |
| 420 // should return max of all contours, rather than the sum (to save temp RAM) | |
| 421 static int worst_case_edge_count(const SkPath& path) { | |
| 422 int edgeCount = 0; | |
| 423 | |
| 424 SkPath::Iter iter(path, true); | |
| 425 SkPath::Verb verb; | |
| 426 | |
| 427 while ((verb = iter.next(NULL)) != SkPath::kDone_Verb) { | |
| 428 switch (verb) { | |
| 429 case SkPath::kLine_Verb: | |
| 430 edgeCount += 1; | |
| 431 break; | |
| 432 case SkPath::kQuad_Verb: | |
| 433 edgeCount += 8; | |
| 434 break; | |
| 435 case SkPath::kCubic_Verb: | |
| 436 edgeCount += 16; | |
| 437 break; | |
| 438 default: | |
| 439 break; | |
| 440 } | |
| 441 } | |
| 442 return edgeCount; | |
| 443 } | |
| 444 | |
| 445 void SkGL::DrawPath(const SkPath& path, bool useTex, SkGLClipIter* clipIter) { | |
| 446 SkRect bounds; | |
| 447 | |
| 448 path.computeBounds(&bounds, SkPath::kFast_BoundsType); | |
| 449 if (bounds.isEmpty()) { | |
| 450 return; | |
| 451 } | |
| 452 | |
| 453 int maxPts = worst_case_edge_count(path); | |
| 454 // add 1 for center of fan, and 1 for closing edge | |
| 455 SkAutoSTMalloc<32, SkGLVertex> storage(maxPts + 2); | |
| 456 SkGLVertex* base = storage.get(); | |
| 457 SkGLVertex* vert = base; | |
| 458 SkGLVertex* texs = useTex ? base : NULL; | |
| 459 | |
| 460 SkPath::Iter pathIter(path, true); | |
| 461 SkPoint pts[4]; | |
| 462 | |
| 463 bool needEnd = false; | |
| 464 | |
| 465 for (;;) { | |
| 466 switch (pathIter.next(pts)) { | |
| 467 case SkPath::kMove_Verb: | |
| 468 if (needEnd) { | |
| 469 SkGL::DrawVertices(vert - base, GL_TRIANGLE_FAN, | |
| 470 base, texs, NULL, NULL, clipIter); | |
| 471 clipIter->safeRewind(); | |
| 472 vert = base; | |
| 473 } | |
| 474 needEnd = true; | |
| 475 // center of the FAN | |
| 476 vert->setScalars(bounds.centerX(), bounds.centerY()); | |
| 477 vert++; | |
| 478 // add first edge point | |
| 479 vert->setPoint(pts[0]); | |
| 480 vert++; | |
| 481 break; | |
| 482 case SkPath::kLine_Verb: | |
| 483 vert->setPoint(pts[1]); | |
| 484 vert++; | |
| 485 break; | |
| 486 case SkPath::kQuad_Verb: { | |
| 487 const int n = 8; | |
| 488 const SkScalar dt = SK_Scalar1 / n; | |
| 489 SkScalar t = dt; | |
| 490 for (int i = 1; i < n; i++) { | |
| 491 SkPoint loc; | |
| 492 SkEvalQuadAt(pts, t, &loc, NULL); | |
| 493 t += dt; | |
| 494 vert->setPoint(loc); | |
| 495 vert++; | |
| 496 } | |
| 497 vert->setPoint(pts[2]); | |
| 498 vert++; | |
| 499 break; | |
| 500 } | |
| 501 case SkPath::kCubic_Verb: { | |
| 502 const int n = 16; | |
| 503 const SkScalar dt = SK_Scalar1 / n; | |
| 504 SkScalar t = dt; | |
| 505 for (int i = 1; i < n; i++) { | |
| 506 SkPoint loc; | |
| 507 SkEvalCubicAt(pts, t, &loc, NULL, NULL); | |
| 508 t += dt; | |
| 509 vert->setPoint(loc); | |
| 510 vert++; | |
| 511 } | |
| 512 vert->setPoint(pts[3]); | |
| 513 vert++; | |
| 514 break; | |
| 515 } | |
| 516 case SkPath::kClose_Verb: | |
| 517 break; | |
| 518 case SkPath::kDone_Verb: | |
| 519 goto FINISHED; | |
| 520 } | |
| 521 } | |
| 522 FINISHED: | |
| 523 if (needEnd) { | |
| 524 SkGL::DrawVertices(vert - base, GL_TRIANGLE_FAN, base, texs, | |
| 525 NULL, NULL, clipIter); | |
| 526 } | |
| 527 } | |
| 528 | |
| OLD | NEW |