Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkDistanceFieldGen.h" | 8 #include "SkDistanceFieldGen.h" |
| 9 #include "SkPoint.h" | 9 #include "SkPoint.h" |
| 10 | 10 |
| 11 struct DFData { | 11 struct DFData { |
| 12 float fAlpha; // alpha value of source texel | 12 float fAlpha; // alpha value of source texel |
| 13 float fDistSq; // distance squared to nearest (so far) edge texel | 13 float fDistSq; // distance squared to nearest (so far) edge texel |
| 14 SkPoint fDistVector; // distance vector to nearest (so far) edge texel | 14 SkPoint fDistVector; // distance vector to nearest (so far) edge texel |
| 15 }; | 15 }; |
| 16 | 16 |
|
robertphillips
2014/03/12 16:40:07
Name this guy EdgeFlags? NeighborFlags might be cl
| |
| 17 enum { | |
| 18 kEdgeFlag_Left = 0x01, | |
| 19 kEdgeFlag_Right = 0x02, | |
| 20 kEdgeFlag_TopLeft = 0x04, | |
| 21 kEdgeFlag_Top = 0x08, | |
| 22 kEdgeFlag_TopRight = 0x10, | |
| 23 kEdgeFlag_BottomLeft = 0x20, | |
| 24 kEdgeFlag_Bottom = 0x40, | |
| 25 kEdgeFlag_BottomRight = 0x80, | |
| 26 kEdgeFlag_All = 0xff | |
| 27 }; | |
| 28 | |
| 17 // We treat an "edge" as a place where we cross from a texel >= 128 to a texel < 128, | 29 // We treat an "edge" as a place where we cross from a texel >= 128 to a texel < 128, |
| 18 // or vice versa. This means we just need to check if the MSBs are different. | 30 // or vice versa. This means we just need to check if the MSBs are different. |
|
robertphillips
2014/03/12 16:40:07
// 'edgeFlags' is used to limit the directions in
| |
| 19 static bool found_edge(const unsigned char* imagePtr, int width) { | 31 static bool found_edge(const unsigned char* imagePtr, int width, int edgeFlags) { |
| 32 // the order of these should match the edge flags above | |
|
robertphillips
2014/03/12 16:40:07
swap 8 out for kEdgeFlagCount? Add kNum8ConnectedN
| |
| 20 const int offsets[8] = {-1, 1, -width-1, -width, -width+1, width-1, width, w idth+1 }; | 33 const int offsets[8] = {-1, 1, -width-1, -width, -width+1, width-1, width, w idth+1 }; |
| 21 | 34 |
| 22 // search for an edge | 35 // search for an edge |
| 23 int checkVal = *imagePtr >> 7; | 36 unsigned char currVal = *imagePtr >> 7; |
| 24 for (int i = 0; i < 8; ++i) { | 37 for (int i = 0; i < 8; ++i) { |
| 25 const unsigned char* checkPtr = imagePtr + offsets[i]; | 38 unsigned char checkVal; |
| 26 if (checkVal ^ (*checkPtr >> 7)) { | 39 if ((1 << i) & edgeFlags) { |
| 40 const unsigned char* checkPtr = imagePtr + offsets[i]; | |
| 41 checkVal = *checkPtr >> 7; | |
| 42 } else { | |
| 43 checkVal = 0; | |
| 44 } | |
| 45 SkASSERT(checkVal == 0 || checkVal == 1); | |
| 46 SkASSERT(currVal == 0 || currVal == 1); | |
| 47 if (checkVal != currVal) { | |
| 27 return true; | 48 return true; |
| 28 } | 49 } |
| 29 } | 50 } |
| 30 | 51 |
| 31 return false; | 52 return false; |
| 32 } | 53 } |
| 33 | 54 |
| 34 static void init_glyph_data(DFData* data, unsigned char* edges, const unsigned c har* image, | 55 static void init_glyph_data(DFData* data, unsigned char* edges, const unsigned c har* image, |
| 35 int dataWidth, int dataHeight, | 56 int dataWidth, int dataHeight, |
| 36 int imageWidth, int imageHeight, | 57 int imageWidth, int imageHeight, |
| 37 int pad) { | 58 int pad) { |
| 38 data += pad*dataWidth; | 59 data += pad*dataWidth; |
| 39 data += pad; | 60 data += pad; |
| 40 edges += (pad*dataWidth + pad); | 61 edges += (pad*dataWidth + pad); |
| 41 | 62 |
| 42 for (int j = 0; j < imageHeight; ++j) { | 63 for (int j = 0; j < imageHeight; ++j) { |
| 43 for (int i = 0; i < imageWidth; ++i) { | 64 for (int i = 0; i < imageWidth; ++i) { |
| 44 if (255 == *image) { | 65 if (255 == *image) { |
| 45 data->fAlpha = 1.0f; | 66 data->fAlpha = 1.0f; |
| 46 } else { | 67 } else { |
| 47 data->fAlpha = (*image)*0.00392156862f; // 1/255 | 68 data->fAlpha = (*image)*0.00392156862f; // 1/255 |
| 48 } | 69 } |
| 49 if (i > 0 && i < imageWidth-1 && j > 0 && j < imageHeight-1 && | 70 int checkMask = kEdgeFlag_All; |
|
robertphillips
2014/03/12 16:40:07
Would it be helpful to add helper values like "kAl
| |
| 50 found_edge(image, imageWidth)) { | 71 if (i == 0) { |
| 72 checkMask &= ~(kEdgeFlag_Left|kEdgeFlag_TopLeft|kEdgeFlag_Bottom Left); | |
| 73 } | |
| 74 if (i == imageWidth-1) { | |
| 75 checkMask &= ~(kEdgeFlag_Right|kEdgeFlag_TopRight|kEdgeFlag_Bott omRight); | |
| 76 } | |
| 77 if (j == 0) { | |
| 78 checkMask &= ~(kEdgeFlag_TopLeft|kEdgeFlag_Top|kEdgeFlag_TopRigh t); | |
| 79 } | |
| 80 if (j == imageHeight-1) { | |
| 81 checkMask &= ~(kEdgeFlag_BottomLeft|kEdgeFlag_Bottom|kEdgeFlag_B ottomRight); | |
| 82 } | |
| 83 if (found_edge(image, imageWidth, checkMask)) { | |
| 51 *edges = 255; // using 255 makes for convenient debug rendering | 84 *edges = 255; // using 255 makes for convenient debug rendering |
| 52 } | 85 } |
| 53 ++data; | 86 ++data; |
| 54 ++image; | 87 ++image; |
| 55 ++edges; | 88 ++edges; |
| 56 } | 89 } |
| 57 data += 2*pad; | 90 data += 2*pad; |
| 58 edges += 2*pad; | 91 edges += 2*pad; |
| 59 } | 92 } |
| 60 } | 93 } |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 260 check = curr + width+1; | 293 check = curr + width+1; |
| 261 distVec = check->fDistVector; | 294 distVec = check->fDistVector; |
| 262 distSq = check->fDistSq + 2.0f*(distVec.fX + distVec.fY + 1.0f); | 295 distSq = check->fDistSq + 2.0f*(distVec.fX + distVec.fY + 1.0f); |
| 263 if (distSq < curr->fDistSq) { | 296 if (distSq < curr->fDistSq) { |
| 264 distVec.fX += 1.0f; | 297 distVec.fX += 1.0f; |
| 265 distVec.fY += 1.0f; | 298 distVec.fY += 1.0f; |
| 266 curr->fDistSq = distSq; | 299 curr->fDistSq = distSq; |
| 267 curr->fDistVector = distVec; | 300 curr->fDistVector = distVec; |
| 268 } | 301 } |
| 269 } | 302 } |
| 270 | 303 |
|
robertphillips
2014/03/12 16:40:07
// Enable this to ...?
| |
| 304 #define DUMP_EDGE 0 | |
| 305 | |
| 306 #if !DUMP_EDGE | |
| 271 static unsigned char pack_distance_field_val(float dist, float distanceMagnitude ) { | 307 static unsigned char pack_distance_field_val(float dist, float distanceMagnitude ) { |
| 272 if (dist <= -distanceMagnitude) { | 308 if (dist <= -distanceMagnitude) { |
| 273 return 255; | 309 return 255; |
| 274 } else if (dist > distanceMagnitude) { | 310 } else if (dist > distanceMagnitude) { |
| 275 return 0; | 311 return 0; |
| 276 } else { | 312 } else { |
| 277 return (unsigned char)((distanceMagnitude-dist)*128.0f/distanceMagnitude ); | 313 return (unsigned char)((distanceMagnitude-dist)*128.0f/distanceMagnitude ); |
| 278 } | 314 } |
| 279 } | 315 } |
| 316 #endif | |
| 280 | 317 |
| 281 // assumes an 8-bit image and distance field | 318 // assumes an 8-bit image and distance field |
| 282 bool SkGenerateDistanceFieldFromImage(unsigned char* distanceField, | 319 bool SkGenerateDistanceFieldFromImage(unsigned char* distanceField, |
| 283 const unsigned char* image, | 320 const unsigned char* image, |
| 284 int width, int height, | 321 int width, int height, |
| 285 int distanceMagnitude) { | 322 int distanceMagnitude) { |
| 286 SkASSERT(NULL != distanceField); | 323 SkASSERT(NULL != distanceField); |
| 287 SkASSERT(NULL != image); | 324 SkASSERT(NULL != image); |
| 288 | 325 |
| 289 // the final distance field will have additional texels on each side to hand le | 326 // the final distance field will have additional texels on each side to hand le |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 375 currData -= dataWidth-1; | 412 currData -= dataWidth-1; |
| 376 currEdge -= dataWidth-1; | 413 currEdge -= dataWidth-1; |
| 377 } | 414 } |
| 378 | 415 |
| 379 // copy results to final distance field data | 416 // copy results to final distance field data |
| 380 currData = dataPtr + dataWidth+1; | 417 currData = dataPtr + dataWidth+1; |
| 381 currEdge = edgePtr + dataWidth+1; | 418 currEdge = edgePtr + dataWidth+1; |
| 382 unsigned char *dfPtr = distanceField; | 419 unsigned char *dfPtr = distanceField; |
| 383 for (int j = 1; j < dataHeight-1; ++j) { | 420 for (int j = 1; j < dataHeight-1; ++j) { |
| 384 for (int i = 1; i < dataWidth-1; ++i) { | 421 for (int i = 1; i < dataWidth-1; ++i) { |
| 422 #if DUMP_EDGE | |
| 423 unsigned char val = (currData->fAlpha >= 0.5f) ? 255 : 0; | |
|
robertphillips
2014/03/12 16:40:07
newline after { and before } ?
| |
| 424 if (*currEdge) { val = 128; } | |
| 425 *dfPtr++ = val; | |
| 426 #else | |
| 385 float dist; | 427 float dist; |
| 386 if (currData->fAlpha > 0.5f) { | 428 if (currData->fAlpha > 0.5f) { |
| 387 dist = -SkScalarSqrt(currData->fDistSq); | 429 dist = -SkScalarSqrt(currData->fDistSq); |
| 388 } else { | 430 } else { |
| 389 dist = SkScalarSqrt(currData->fDistSq); | 431 dist = SkScalarSqrt(currData->fDistSq); |
| 390 } | 432 } |
| 391 | |
| 392 *dfPtr++ = pack_distance_field_val(dist, (float)distanceMagnitude); | 433 *dfPtr++ = pack_distance_field_val(dist, (float)distanceMagnitude); |
| 434 #endif | |
| 393 ++currData; | 435 ++currData; |
| 394 ++currEdge; | 436 ++currEdge; |
| 395 } | 437 } |
| 396 currData += 2; | 438 currData += 2; |
| 397 currEdge += 2; | 439 currEdge += 2; |
| 398 } | 440 } |
| 399 | 441 |
| 400 return true; | 442 return true; |
| 401 } | 443 } |
| OLD | NEW |