OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2010 Google Inc. | 2 * Copyright 2010 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 "GrAtlas.h" | 8 #include "GrAtlas.h" |
9 #include "GrGpu.h" | 9 #include "GrGpu.h" |
10 #include "GrRectanizer.h" | 10 #include "GrRectanizer.h" |
11 #include "GrTextStrike.h" | 11 #include "GrTextStrike.h" |
12 #include "GrTextStrike_impl.h" | 12 #include "GrTextStrike_impl.h" |
13 #include "SkString.h" | 13 #include "SkString.h" |
14 | 14 |
15 SK_DEFINE_INST_COUNT(GrFontScaler) | 15 SK_DEFINE_INST_COUNT(GrFontScaler) |
16 SK_DEFINE_INST_COUNT(GrKey) | 16 SK_DEFINE_INST_COUNT(GrKey) |
17 | 17 |
18 /////////////////////////////////////////////////////////////////////////////// | 18 /////////////////////////////////////////////////////////////////////////////// |
19 | 19 |
20 #define FONT_CACHE_STATS 0 | 20 #define FONT_CACHE_STATS 0 |
21 #if FONT_CACHE_STATS | 21 #if FONT_CACHE_STATS |
22 static int g_PurgeCount = 0; | 22 static int g_PurgeCount = 0; |
23 #endif | 23 #endif |
24 | 24 |
| 25 void edtaa2(unsigned char *img, int w, int h, short *distx, short *disty, float
*dist); |
| 26 |
25 GrFontCache::GrFontCache(GrGpu* gpu) : fGpu(gpu) { | 27 GrFontCache::GrFontCache(GrGpu* gpu) : fGpu(gpu) { |
26 gpu->ref(); | 28 gpu->ref(); |
27 for (int i = 0; i < kMaskFormatCount; ++i) { | 29 for (int i = 0; i < kMaskFormatCount; ++i) { |
28 fAtlasMgr[i] = NULL; | 30 fAtlasMgr[i] = NULL; |
29 } | 31 } |
30 | 32 |
31 fHead = fTail = NULL; | 33 fHead = fTail = NULL; |
32 } | 34 } |
33 | 35 |
34 GrFontCache::~GrFontCache() { | 36 GrFontCache::~GrFontCache() { |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 ++gDumpCount; | 189 ++gDumpCount; |
188 } | 190 } |
189 #endif | 191 #endif |
190 | 192 |
191 /////////////////////////////////////////////////////////////////////////////// | 193 /////////////////////////////////////////////////////////////////////////////// |
192 | 194 |
193 #ifdef SK_DEBUG | 195 #ifdef SK_DEBUG |
194 static int gCounter; | 196 static int gCounter; |
195 #endif | 197 #endif |
196 | 198 |
| 199 #define DISTANCE_FIELD_PAD 4 |
| 200 #define DISTANCE_FIELD_RANGE (4.f) |
| 201 |
197 /* | 202 /* |
198 The text strike is specific to a given font/style/matrix setup, which is | 203 The text strike is specific to a given font/style/matrix setup, which is |
199 represented by the GrHostFontScaler object we are given in getGlyph(). | 204 represented by the GrHostFontScaler object we are given in getGlyph(). |
200 | 205 |
201 We map a 32bit glyphID to a GrGlyph record, which in turn points to a | 206 We map a 32bit glyphID to a GrGlyph record, which in turn points to a |
202 atlas and a position within that texture. | 207 atlas and a position within that texture. |
203 */ | 208 */ |
204 | 209 |
205 GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key, | 210 GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key, |
206 GrMaskFormat format, | 211 GrMaskFormat format, |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
240 } | 245 } |
241 | 246 |
242 GrGlyph* GrTextStrike::generateGlyph(GrGlyph::PackedID packed, | 247 GrGlyph* GrTextStrike::generateGlyph(GrGlyph::PackedID packed, |
243 GrFontScaler* scaler) { | 248 GrFontScaler* scaler) { |
244 SkIRect bounds; | 249 SkIRect bounds; |
245 if (!scaler->getPackedGlyphBounds(packed, &bounds)) { | 250 if (!scaler->getPackedGlyphBounds(packed, &bounds)) { |
246 return NULL; | 251 return NULL; |
247 } | 252 } |
248 | 253 |
249 GrGlyph* glyph = fPool.alloc(); | 254 GrGlyph* glyph = fPool.alloc(); |
| 255 // expand bounds to hold full distance field data |
| 256 if (fUseDistanceField) { |
| 257 bounds.fLeft -= DISTANCE_FIELD_PAD; |
| 258 bounds.fRight += DISTANCE_FIELD_PAD; |
| 259 bounds.fTop -= DISTANCE_FIELD_PAD; |
| 260 bounds.fBottom += DISTANCE_FIELD_PAD; |
| 261 } |
250 glyph->init(packed, bounds); | 262 glyph->init(packed, bounds); |
251 fCache.insert(packed, glyph); | 263 fCache.insert(packed, glyph); |
252 return glyph; | 264 return glyph; |
253 } | 265 } |
254 | 266 |
255 bool GrTextStrike::removeUnusedPlots() { | 267 bool GrTextStrike::removeUnusedPlots() { |
256 fCache.getArray().visitAll(invalidate_glyph); | 268 fCache.getArray().visitAll(invalidate_glyph); |
257 return fAtlasMgr->removeUnusedPlots(&fAtlas); | 269 return fAtlasMgr->removeUnusedPlots(&fAtlas); |
258 } | 270 } |
259 | 271 |
| 272 |
260 bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) { | 273 bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) { |
261 #if 0 // testing hack to force us to flush our cache often | 274 #if 0 // testing hack to force us to flush our cache often |
262 static int gCounter; | 275 static int gCounter; |
263 if ((++gCounter % 10) == 0) return false; | 276 if ((++gCounter % 10) == 0) return false; |
264 #endif | 277 #endif |
265 | 278 |
266 SkASSERT(glyph); | 279 SkASSERT(glyph); |
267 SkASSERT(scaler); | 280 SkASSERT(scaler); |
268 SkASSERT(fCache.contains(glyph)); | 281 SkASSERT(fCache.contains(glyph)); |
269 SkASSERT(NULL == glyph->fPlot); | 282 SkASSERT(NULL == glyph->fPlot); |
270 | 283 |
271 SkAutoRef ar(scaler); | 284 SkAutoRef ar(scaler); |
272 | 285 |
273 int bytesPerPixel = GrMaskFormatBytesPerPixel(fMaskFormat); | 286 int bytesPerPixel = GrMaskFormatBytesPerPixel(fMaskFormat); |
274 size_t size = glyph->fBounds.area() * bytesPerPixel; | 287 |
275 SkAutoSMalloc<1024> storage(size); | 288 GrPlot* plot; |
276 if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(), | 289 if (fUseDistanceField) { |
277 glyph->height(), | 290 SkASSERT(1 == bytesPerPixel); |
278 glyph->width() * bytesPerPixel, | 291 |
279 storage.get())) { | 292 // we've already expanded the glyph dimensions to match the final size |
280 return false; | 293 // but must shrink back down to get the packed glyph data |
| 294 int dfwidth = glyph->width(); |
| 295 int dfheight = glyph->height(); |
| 296 int width = dfwidth - 2*DISTANCE_FIELD_PAD; |
| 297 int height = dfheight - 2*DISTANCE_FIELD_PAD; |
| 298 size_t stride = width*bytesPerPixel; |
| 299 |
| 300 size_t size = width * height * bytesPerPixel; |
| 301 SkAutoSMalloc<1024> storage(size); |
| 302 if (!scaler->getPackedGlyphImage(glyph->fPackedID, width, height, stride
, storage.get())) { |
| 303 return false; |
| 304 } |
| 305 |
| 306 // alloc storage for distance field glyph |
| 307 size_t dfsize = dfwidth * dfheight * bytesPerPixel; |
| 308 SkAutoSMalloc<1024> dfstorage(dfsize); |
| 309 |
| 310 // copy glyph into distance field storage |
| 311 memset(dfstorage.get(), 0, dfsize); |
| 312 |
| 313 unsigned char* ptr = (unsigned char*) storage.get(); |
| 314 unsigned char* dfptr = (unsigned char*) dfstorage.get(); |
| 315 size_t dfstride = dfwidth*bytesPerPixel; |
| 316 dfptr += DISTANCE_FIELD_PAD*dfstride; |
| 317 dfptr += DISTANCE_FIELD_PAD*bytesPerPixel; |
| 318 |
| 319 for (int i = 0; i < height; ++i) { |
| 320 memcpy(dfptr, ptr, stride); |
| 321 |
| 322 dfptr += dfstride; |
| 323 ptr += stride; |
| 324 } |
| 325 |
| 326 // generate distance field data |
| 327 short* distx = new short[dfwidth*dfheight]; |
| 328 short* disty = new short[dfwidth*dfheight]; |
| 329 float* outerdist = new float[dfwidth*dfheight]; |
| 330 dfptr = (unsigned char*) dfstorage.get(); |
| 331 edtaa2(dfptr, dfwidth, dfheight, distx, disty, outerdist); |
| 332 |
| 333 for (int i = 0; i < dfwidth*dfheight; ++i) { |
| 334 *dfptr++ = 255 - *dfptr; |
| 335 } |
| 336 float* innerdist = new float[dfwidth*dfheight]; |
| 337 dfptr = (unsigned char*) dfstorage.get(); |
| 338 edtaa2(dfptr, dfwidth, dfheight, distx, disty, innerdist); |
| 339 |
| 340 for (int i = 0; i < dfwidth*dfheight; ++i) { |
| 341 unsigned char val; |
| 342 float outerval = outerdist[i]; |
| 343 if (outerval < 0.0f) { outerval = 0.0f; } |
| 344 float innerval = innerdist[i]; |
| 345 if (innerval < 0.0f) { innerval = 0.0f; } |
| 346 float dist = outerval - innerval; |
| 347 if (dist <= -DISTANCE_FIELD_RANGE) { |
| 348 val = 255; |
| 349 } else if (dist > DISTANCE_FIELD_RANGE) { |
| 350 val = 0; |
| 351 } else { |
| 352 val = (unsigned char)((DISTANCE_FIELD_RANGE-dist)*128.f/DISTANCE
_FIELD_RANGE); |
| 353 } |
| 354 *dfptr++ = val; |
| 355 } |
| 356 |
| 357 delete [] distx; |
| 358 delete [] disty; |
| 359 delete [] innerdist; |
| 360 delete [] outerdist; |
| 361 |
| 362 // copy to atlas |
| 363 plot = fAtlasMgr->addToAtlas(&fAtlas, dfwidth, dfheight, dfstorage.get()
, |
| 364 &glyph->fAtlasLocation); |
| 365 |
| 366 } else { |
| 367 size_t size = glyph->fBounds.area() * bytesPerPixel; |
| 368 SkAutoSMalloc<1024> storage(size); |
| 369 if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(), |
| 370 glyph->height(), |
| 371 glyph->width() * bytesPerPixel, |
| 372 storage.get())) { |
| 373 return false; |
| 374 } |
| 375 |
| 376 plot = fAtlasMgr->addToAtlas(&fAtlas, glyph->width(), glyph->height(), s
torage.get(), |
| 377 &glyph->fAtlasLocation); |
281 } | 378 } |
282 | 379 |
283 GrPlot* plot = fAtlasMgr->addToAtlas(&fAtlas, glyph->width(), | |
284 glyph->height(), storage.get(), | |
285 &glyph->fAtlasLocation); | |
286 if (NULL == plot) { | 380 if (NULL == plot) { |
287 return false; | 381 return false; |
288 } | 382 } |
289 | 383 |
290 glyph->fPlot = plot; | 384 glyph->fPlot = plot; |
291 return true; | 385 return true; |
292 } | 386 } |
| 387 |
| 388 |
| 389 ////////////////////////////////////////////////////////////////////////////////
////// |
| 390 |
| 391 /* |
| 392 * A hairy function to approximate the distance to an edge in a certain pixel, |
| 393 * with consideration to both the direction to the pixel, the local gradient |
| 394 * at that pixel and its greyscale value. |
| 395 * This function is complicated enough to warrant a function call for each |
| 396 * evaluation. Inlining it with a macro would only obfuscate the code. |
| 397 */ |
| 398 static float distaa2(unsigned char *img, int w, int c, int xc, int yc, int xi, i
nt yi) |
| 399 { |
| 400 float di, df, gx, gy, a, a1, temp; |
| 401 |
| 402 a = (float)(img[c-xc-yc*w])/255.f; // Grayscale value at the edge pixel pointe
d to |
| 403 if(a < 0.0f) a = 0.0f; // Clip grayscale values outside the range [0,1] |
| 404 if(a == 0.0f) return 1000000.0f; // Not an object pixel, return "very far" ("d
on't know yet") |
| 405 if(a > 1.0) a = 1.0f; |
| 406 df = 0.5f-a; // Linear function is correct if gx==0 or gy==0 |
| 407 |
| 408 gx = (float)abs(xi); // Move to first quadrant gx>=0, gy>=0 (sign symmetry) |
| 409 gy = (float)abs(yi); |
| 410 di = sqrtf(gx*gx+gy*gy); // Length of integer vector, like a traditional EDT |
| 411 if ((gx > 0) && (gy > 0)) { // Neither gx nor gy are zero |
| 412 gx = gx / di; |
| 413 gy = gy / di; |
| 414 if(gx<gy) { // Move to first octant gx >= gy (transposition symmetry) |
| 415 temp = gx; |
| 416 gx = gy; |
| 417 gy = temp; |
| 418 } |
| 419 a1 = 0.5f*gy/gx; // area of corner triangle |
| 420 if (a < a1) // 0 <= a < a1, square root characteristic |
| 421 df = 0.5f*(gx + gy) - sqrtf(2.0f*a*gx*gy); |
| 422 else if (a <= (1.0f-a1)) // a1 <= a <= 1-a1, linear characteristic |
| 423 df = (0.5f-a)*gx; |
| 424 else // a1 < a <= 1, square root characteristic |
| 425 df = -0.5f*(gx + gy) + sqrtf(2.0f*(1.0f-a)*gx*gy); |
| 426 } |
| 427 return di + df; // Negative at edge pixels (di=0) with a>0.5 (df<0) |
| 428 } |
| 429 |
| 430 // Shorthand macro: add ubiquitous parameters dist, img and w and call distaa2() |
| 431 #define DISTAA2(c,xc,yc,xi,yi) (distaa2(img, w, c, xc, yc, xi, yi)) |
| 432 |
| 433 static void edtaa2(unsigned char *img, int w, int h, short *distx, short *disty,
float *dist) |
| 434 { |
| 435 int x, y, i, c; |
| 436 int offset_u, offset_ur, offset_r, offset_rd, |
| 437 offset_d, offset_dl, offset_l, offset_lu; |
| 438 float olddist, newdist; |
| 439 int cdistx, cdisty, newdistx, newdisty; |
| 440 int changed; |
| 441 |
| 442 /* Initialize index offsets for the current image width */ |
| 443 offset_u = -w; |
| 444 offset_ur = -w+1; |
| 445 offset_r = 1; |
| 446 offset_rd = w+1; |
| 447 offset_d = w; |
| 448 offset_dl = w-1; |
| 449 offset_l = -1; |
| 450 offset_lu = -w-1; |
| 451 |
| 452 /* Initialize the distance images */ |
| 453 for(i=0; i<w*h; i++) { |
| 454 float val = (float)(img[i])/255.f; |
| 455 distx[i] = 0; // At first, all pixels point to |
| 456 disty[i] = 0; // themselves as the closest known. |
| 457 if(val == 0) |
| 458 { |
| 459 dist[i]= 1000000.0f; // Big value, means "not set yet" |
| 460 } |
| 461 else if (val < 1.0f) { |
| 462 dist[i] = 0.5f-val; // Reasonable local guess |
| 463 } |
| 464 else { |
| 465 dist[i]= 0.0f; // Inside the object |
| 466 } |
| 467 } |
| 468 |
| 469 /* Perform the transformation */ |
| 470 do |
| 471 { |
| 472 changed = 0; |
| 473 |
| 474 /* Scan rows, except first row */ |
| 475 for(y=1; y<h; y++) |
| 476 { |
| 477 |
| 478 /* move index to leftmost pixel of current row */ |
| 479 i = y*w; |
| 480 |
| 481 /* scan right, propagate distances from above & left */ |
| 482 |
| 483 /* Leftmost pixel is special, has no left neighbors */ |
| 484 olddist = dist[i]; |
| 485 if(olddist > 0) // If non-zero distance or not set yet |
| 486 { |
| 487 c = i + offset_u; // Index of candidate for testing |
| 488 cdistx = distx[c]; |
| 489 cdisty = disty[c]; |
| 490 newdistx = cdistx; |
| 491 newdisty = cdisty+1; |
| 492 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 493 if(newdist < olddist) |
| 494 { |
| 495 distx[i]=newdistx; |
| 496 disty[i]=newdisty; |
| 497 dist[i]=newdist; |
| 498 olddist=newdist; |
| 499 changed = 1; |
| 500 } |
| 501 |
| 502 c = i+offset_ur; |
| 503 cdistx = distx[c]; |
| 504 cdisty = disty[c]; |
| 505 newdistx = cdistx-1; |
| 506 newdisty = cdisty+1; |
| 507 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 508 if(newdist < olddist) |
| 509 { |
| 510 distx[i]=newdistx; |
| 511 disty[i]=newdisty; |
| 512 dist[i]=newdist; |
| 513 changed = 1; |
| 514 } |
| 515 } |
| 516 i++; |
| 517 |
| 518 /* Middle pixels have all neighbors */ |
| 519 for(x=1; x<w-1; x++, i++) |
| 520 { |
| 521 olddist = dist[i]; |
| 522 if(olddist <= 0) continue; // No need to update further |
| 523 |
| 524 c = i+offset_l; |
| 525 cdistx = distx[c]; |
| 526 cdisty = disty[c]; |
| 527 newdistx = cdistx+1; |
| 528 newdisty = cdisty; |
| 529 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 530 if(newdist < olddist) |
| 531 { |
| 532 distx[i]=newdistx; |
| 533 disty[i]=newdisty; |
| 534 dist[i]=newdist; |
| 535 olddist=newdist; |
| 536 changed = 1; |
| 537 } |
| 538 |
| 539 c = i+offset_lu; |
| 540 cdistx = distx[c]; |
| 541 cdisty = disty[c]; |
| 542 newdistx = cdistx+1; |
| 543 newdisty = cdisty+1; |
| 544 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 545 if(newdist < olddist) |
| 546 { |
| 547 distx[i]=newdistx; |
| 548 disty[i]=newdisty; |
| 549 dist[i]=newdist; |
| 550 olddist=newdist; |
| 551 changed = 1; |
| 552 } |
| 553 |
| 554 c = i+offset_u; |
| 555 cdistx = distx[c]; |
| 556 cdisty = disty[c]; |
| 557 newdistx = cdistx; |
| 558 newdisty = cdisty+1; |
| 559 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 560 if(newdist < olddist) |
| 561 { |
| 562 distx[i]=newdistx; |
| 563 disty[i]=newdisty; |
| 564 dist[i]=newdist; |
| 565 olddist=newdist; |
| 566 changed = 1; |
| 567 } |
| 568 |
| 569 c = i+offset_ur; |
| 570 cdistx = distx[c]; |
| 571 cdisty = disty[c]; |
| 572 newdistx = cdistx-1; |
| 573 newdisty = cdisty+1; |
| 574 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 575 if(newdist < olddist) |
| 576 { |
| 577 distx[i]=newdistx; |
| 578 disty[i]=newdisty; |
| 579 dist[i]=newdist; |
| 580 changed = 1; |
| 581 } |
| 582 } |
| 583 |
| 584 /* Rightmost pixel of row is special, has no right neighbors */ |
| 585 olddist = dist[i]; |
| 586 if(olddist > 0) // If not already zero distance |
| 587 { |
| 588 c = i+offset_l; |
| 589 cdistx = distx[c]; |
| 590 cdisty = disty[c]; |
| 591 newdistx = cdistx+1; |
| 592 newdisty = cdisty; |
| 593 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 594 if(newdist < olddist) |
| 595 { |
| 596 distx[i]=newdistx; |
| 597 disty[i]=newdisty; |
| 598 dist[i]=newdist; |
| 599 olddist=newdist; |
| 600 changed = 1; |
| 601 } |
| 602 |
| 603 c = i+offset_lu; |
| 604 cdistx = distx[c]; |
| 605 cdisty = disty[c]; |
| 606 newdistx = cdistx+1; |
| 607 newdisty = cdisty+1; |
| 608 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 609 if(newdist < olddist) |
| 610 { |
| 611 distx[i]=newdistx; |
| 612 disty[i]=newdisty; |
| 613 dist[i]=newdist; |
| 614 olddist=newdist; |
| 615 changed = 1; |
| 616 } |
| 617 |
| 618 c = i+offset_u; |
| 619 cdistx = distx[c]; |
| 620 cdisty = disty[c]; |
| 621 newdistx = cdistx; |
| 622 newdisty = cdisty+1; |
| 623 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 624 if(newdist < olddist) |
| 625 { |
| 626 distx[i]=newdistx; |
| 627 disty[i]=newdisty; |
| 628 dist[i]=newdist; |
| 629 changed = 1; |
| 630 } |
| 631 } |
| 632 |
| 633 /* Move index to second rightmost pixel of current row. */ |
| 634 /* Rightmost pixel is skipped, it has no right neighbor. */ |
| 635 i = y*w + w-2; |
| 636 |
| 637 /* scan left, propagate distance from right */ |
| 638 for(x=w-2; x>=0; x--, i--) |
| 639 { |
| 640 olddist = dist[i]; |
| 641 if(olddist <= 0) continue; // Already zero distance |
| 642 |
| 643 c = i+offset_r; |
| 644 cdistx = distx[c]; |
| 645 cdisty = disty[c]; |
| 646 newdistx = cdistx-1; |
| 647 newdisty = cdisty; |
| 648 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 649 if(newdist < olddist) |
| 650 { |
| 651 distx[i]=newdistx; |
| 652 disty[i]=newdisty; |
| 653 dist[i]=newdist; |
| 654 changed = 1; |
| 655 } |
| 656 } |
| 657 } |
| 658 |
| 659 /* Scan rows in reverse order, except last row */ |
| 660 for(y=h-2; y>=0; y--) |
| 661 { |
| 662 /* move index to rightmost pixel of current row */ |
| 663 i = y*w + w-1; |
| 664 |
| 665 /* Scan left, propagate distances from below & right */ |
| 666 |
| 667 /* Rightmost pixel is special, has no right neighbors */ |
| 668 olddist = dist[i]; |
| 669 if(olddist > 0) // If not already zero distance |
| 670 { |
| 671 c = i+offset_d; |
| 672 cdistx = distx[c]; |
| 673 cdisty = disty[c]; |
| 674 newdistx = cdistx; |
| 675 newdisty = cdisty-1; |
| 676 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 677 if(newdist < olddist) |
| 678 { |
| 679 distx[i]=newdistx; |
| 680 disty[i]=newdisty; |
| 681 dist[i]=newdist; |
| 682 olddist=newdist; |
| 683 changed = 1; |
| 684 } |
| 685 |
| 686 c = i+offset_dl; |
| 687 cdistx = distx[c]; |
| 688 cdisty = disty[c]; |
| 689 newdistx = cdistx+1; |
| 690 newdisty = cdisty-1; |
| 691 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 692 if(newdist < olddist) |
| 693 { |
| 694 distx[i]=newdistx; |
| 695 disty[i]=newdisty; |
| 696 dist[i]=newdist; |
| 697 changed = 1; |
| 698 } |
| 699 } |
| 700 i--; |
| 701 |
| 702 /* Middle pixels have all neighbors */ |
| 703 for(x=w-2; x>0; x--, i--) |
| 704 { |
| 705 olddist = dist[i]; |
| 706 if(olddist <= 0) continue; // Already zero distance |
| 707 |
| 708 c = i+offset_r; |
| 709 cdistx = distx[c]; |
| 710 cdisty = disty[c]; |
| 711 newdistx = cdistx-1; |
| 712 newdisty = cdisty; |
| 713 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 714 if(newdist < olddist) |
| 715 { |
| 716 distx[i]=newdistx; |
| 717 disty[i]=newdisty; |
| 718 dist[i]=newdist; |
| 719 olddist=newdist; |
| 720 changed = 1; |
| 721 } |
| 722 |
| 723 c = i+offset_rd; |
| 724 cdistx = distx[c]; |
| 725 cdisty = disty[c]; |
| 726 newdistx = cdistx-1; |
| 727 newdisty = cdisty-1; |
| 728 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 729 if(newdist < olddist) |
| 730 { |
| 731 distx[i]=newdistx; |
| 732 disty[i]=newdisty; |
| 733 dist[i]=newdist; |
| 734 olddist=newdist; |
| 735 changed = 1; |
| 736 } |
| 737 |
| 738 c = i+offset_d; |
| 739 cdistx = distx[c]; |
| 740 cdisty = disty[c]; |
| 741 newdistx = cdistx; |
| 742 newdisty = cdisty-1; |
| 743 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 744 if(newdist < olddist) |
| 745 { |
| 746 distx[i]=newdistx; |
| 747 disty[i]=newdisty; |
| 748 dist[i]=newdist; |
| 749 olddist=newdist; |
| 750 changed = 1; |
| 751 } |
| 752 |
| 753 c = i+offset_dl; |
| 754 cdistx = distx[c]; |
| 755 cdisty = disty[c]; |
| 756 newdistx = cdistx+1; |
| 757 newdisty = cdisty-1; |
| 758 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 759 if(newdist < olddist) |
| 760 { |
| 761 distx[i]=newdistx; |
| 762 disty[i]=newdisty; |
| 763 dist[i]=newdist; |
| 764 changed = 1; |
| 765 } |
| 766 } |
| 767 /* Leftmost pixel is special, has no left neighbors */ |
| 768 olddist = dist[i]; |
| 769 if(olddist > 0) // If not already zero distance |
| 770 { |
| 771 c = i+offset_r; |
| 772 cdistx = distx[c]; |
| 773 cdisty = disty[c]; |
| 774 newdistx = cdistx-1; |
| 775 newdisty = cdisty; |
| 776 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 777 if(newdist < olddist) |
| 778 { |
| 779 distx[i]=newdistx; |
| 780 disty[i]=newdisty; |
| 781 dist[i]=newdist; |
| 782 olddist=newdist; |
| 783 changed = 1; |
| 784 } |
| 785 |
| 786 c = i+offset_rd; |
| 787 cdistx = distx[c]; |
| 788 cdisty = disty[c]; |
| 789 newdistx = cdistx-1; |
| 790 newdisty = cdisty-1; |
| 791 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 792 if(newdist < olddist) |
| 793 { |
| 794 distx[i]=newdistx; |
| 795 disty[i]=newdisty; |
| 796 dist[i]=newdist; |
| 797 olddist=newdist; |
| 798 changed = 1; |
| 799 } |
| 800 |
| 801 c = i+offset_d; |
| 802 cdistx = distx[c]; |
| 803 cdisty = disty[c]; |
| 804 newdistx = cdistx; |
| 805 newdisty = cdisty-1; |
| 806 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 807 if(newdist < olddist) |
| 808 { |
| 809 distx[i]=newdistx; |
| 810 disty[i]=newdisty; |
| 811 dist[i]=newdist; |
| 812 changed = 1; |
| 813 } |
| 814 } |
| 815 |
| 816 /* Move index to second leftmost pixel of current row. */ |
| 817 /* Leftmost pixel is skipped, it has no left neighbor. */ |
| 818 i = y*w + 1; |
| 819 for(x=1; x<w; x++, i++) |
| 820 { |
| 821 /* scan right, propagate distance from left */ |
| 822 olddist = dist[i]; |
| 823 if(olddist <= 0) continue; // Already zero distance |
| 824 |
| 825 c = i+offset_l; |
| 826 cdistx = distx[c]; |
| 827 cdisty = disty[c]; |
| 828 newdistx = cdistx+1; |
| 829 newdisty = cdisty; |
| 830 newdist = DISTAA2(c, cdistx, cdisty, newdistx, newdisty); |
| 831 if(newdist < olddist) |
| 832 { |
| 833 distx[i]=newdistx; |
| 834 disty[i]=newdisty; |
| 835 dist[i]=newdist; |
| 836 changed = 1; |
| 837 } |
| 838 } |
| 839 } |
| 840 } |
| 841 while(changed); // Sweep until no more updates are made |
| 842 |
| 843 /* The transformation is completed. */ |
| 844 |
| 845 } |
| 846 |
OLD | NEW |