distanceField.cpp
Engine/source/gfx/util/distanceField.cpp
Classes:
Public Functions
cmpSortDistanceFieldSearchSpaceStruct(const void * p1, const void * p2)
Detailed Description
Public Functions
cmpSortDistanceFieldSearchSpaceStruct(const void * p1, const void * p2)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23#include "math/mPoint2.h" 24#include "gfx/bitmap/gBitmap.h" 25 26#include "gfx/util/distanceField.h" 27 28//----------------------------------------------------------------------------- 29struct DistanceFieldSearchSpaceStruct 30{ 31 S32 xOffset; 32 S32 yOffset; 33 F32 distance; 34}; 35 36S32 QSORT_CALLBACK cmpSortDistanceFieldSearchSpaceStruct(const void* p1, const void* p2) 37{ 38 const DistanceFieldSearchSpaceStruct* sp1 = (const DistanceFieldSearchSpaceStruct*)p1; 39 const DistanceFieldSearchSpaceStruct* sp2 = (const DistanceFieldSearchSpaceStruct*)p2; 40 41 if (sp2->distance > sp1->distance) 42 return -1; 43 else if (sp2->distance == sp1->distance) 44 return 0; 45 else 46 return 1; 47} 48 49//GBitmap * GFXUtil::DistanceField::makeDistanceField(GBitmap * sourceBmp, S32 targetSizeX, S32 targetSizeY, F32 rangePct) 50//{ 51// AssertFatal(sourceBmp->getFormat() == GFXFormatA8,"Use an alpha-only texture to create distance fields"); 52// 53// static Vector<DistanceFieldSearchSpaceStruct> searchSpace; 54// 55// S32 sourceSizeX = sourceBmp->getWidth(); 56// S32 sourceSizeY = sourceBmp->getHeight(); 57// 58// S32 targetToSourceScalarX = sourceSizeX / targetSizeX; 59// S32 targetToSourceScalarY = sourceSizeY / targetSizeY; 60// S32 targetToSourcePixOffsetX = targetToSourceScalarX / 2; 61// S32 targetToSourcePixOffsetY = targetToSourceScalarY / 2; 62// 63// F32 range = getMin(sourceSizeX,sourceSizeY) * rangePct; 64// F32 range2 = range * 2.f; 65// 66// { 67// S32 intRange = mCeil(range); 68// for(S32 spaceY = -intRange; spaceY < intRange; spaceY++) 69// { 70// for(S32 spaceX = -intRange; spaceX < intRange; spaceX++) 71// { 72// if(spaceX == 0 && spaceY == 0) 73// continue; 74// 75// F32 distance = Point2F(spaceX,spaceY).len(); 76// if(distance <= range) 77// { 78// searchSpace.increment(); 79// searchSpace.last().distance = distance; 80// searchSpace.last().xOffset = spaceX; 81// searchSpace.last().yOffset = spaceY; 82// } 83// } 84// } 85// } 86// dQsort(searchSpace.address(), searchSpace.size(), sizeof(DistanceFieldSearchSpaceStruct), cmpSortDistanceFieldSearchSpaceStruct); 87// 88// GBitmap * targetBmp = new GBitmap(targetSizeX,targetSizeY,false,GFXFormatA8); 89// 90// U8 * targetPixel = targetBmp->getWritableBits(); 91// for(S32 y = 0; y < targetSizeY; y++) 92// { 93// for(S32 x = 0; x < targetSizeX; x++) 94// { 95// S32 sourceX = x * targetToSourceScalarX + targetToSourcePixOffsetX; 96// S32 sourceY = y * targetToSourceScalarY + targetToSourcePixOffsetY; 97// 98// const U8 * thisPixel = sourceBmp->getAddress(sourceX,sourceY); 99// 100// bool thisPixelEmpty = *thisPixel == 0; 101// 102// F32 closestDist = F32_MAX; 103// 104// for(DistanceFieldSearchSpaceStruct * seachSpaceStructPtr = searchSpace.begin(); seachSpaceStructPtr <= searchSpace.end(); seachSpaceStructPtr++) 105// { 106// DistanceFieldSearchSpaceStruct & searchSpaceStruct = *seachSpaceStructPtr; 107// S32 cx = sourceX + searchSpaceStruct.xOffset; 108// if(cx < 0 || cx >= sourceSizeX) 109// continue; 110// 111// S32 cy = sourceY + searchSpaceStruct.yOffset; 112// if(cy < 0 || cy >= sourceSizeY) 113// continue; 114// 115// const U8 * checkPixel = sourceBmp->getAddress(cx,cy); 116// if((*checkPixel == 0) != thisPixelEmpty) 117// { 118// closestDist = searchSpaceStruct.distance; 119// break; 120// } 121// } 122// 123// F32 diff = thisPixelEmpty ? getMax(-0.5f,-(closestDist / range2)) : getMin(0.5f,closestDist / range2); 124// F32 targetValue = 0.5f + diff; 125// 126// *targetPixel = targetValue * 255; 127// targetPixel++; 128// } 129// } 130// 131// searchSpace.clear(); 132// 133// return targetBmp; 134//} 135 136void GFXUtil::DistanceField::makeDistanceField( const U8 * sourceData, S32 sourceSizeX, S32 sourceSizeY, U8 * targetData, S32 targetSizeX, S32 targetSizeY, F32 radius ) 137{ 138 static Vector<DistanceFieldSearchSpaceStruct> searchSpace; 139 140 S32 targetToSourceScalarX = sourceSizeX / targetSizeX; 141 S32 targetToSourceScalarY = sourceSizeY / targetSizeY; 142 S32 targetToSourcePixOffsetX = targetToSourceScalarX / 2; 143 S32 targetToSourcePixOffsetY = targetToSourceScalarY / 2; 144 145 F32 radius2 = radius * 2.f; 146 147 { 148 S32 intRange = mCeil(radius); 149 for(S32 spaceY = -intRange; spaceY < intRange; spaceY++) 150 { 151 for(S32 spaceX = -intRange; spaceX < intRange; spaceX++) 152 { 153 if(spaceX == 0 && spaceY == 0) 154 continue; 155 156 F32 distance = Point2F(spaceX,spaceY).len(); 157 if(distance <= radius) 158 { 159 searchSpace.increment(); 160 searchSpace.last().distance = distance; 161 searchSpace.last().xOffset = spaceX; 162 searchSpace.last().yOffset = spaceY; 163 } 164 } 165 } 166 } 167 dQsort(searchSpace.address(), searchSpace.size(), sizeof(DistanceFieldSearchSpaceStruct), cmpSortDistanceFieldSearchSpaceStruct); 168 169 for(S32 y = 0; y < targetSizeY; y++) 170 { 171 for(S32 x = 0; x < targetSizeX; x++) 172 { 173 S32 sourceX = x * targetToSourceScalarX + targetToSourcePixOffsetX; 174 S32 sourceY = y * targetToSourceScalarY + targetToSourcePixOffsetY; 175 176 bool thisPixelEmpty = sourceData[sourceY * sourceSizeX + sourceX] < 127; 177 178 F32 closestDist = F32_MAX; 179 180 for(DistanceFieldSearchSpaceStruct * seachSpaceStructPtr = searchSpace.begin(); seachSpaceStructPtr <= searchSpace.end(); seachSpaceStructPtr++) 181 { 182 DistanceFieldSearchSpaceStruct & searchSpaceStruct = *seachSpaceStructPtr; 183 S32 cx = sourceX + searchSpaceStruct.xOffset; 184 if(cx < 0 || cx >= sourceSizeX) 185 continue; 186 187 S32 cy = sourceY + searchSpaceStruct.yOffset; 188 if(cy < 0 || cy >= sourceSizeY) 189 continue; 190 191 if((sourceData[cy * sourceSizeX + cx] < 127) != thisPixelEmpty) 192 { 193 closestDist = searchSpaceStruct.distance; 194 break; 195 } 196 } 197 198 F32 diff = thisPixelEmpty ? getMax(-0.5f,-(closestDist / radius2)) : getMin(0.5f,closestDist / radius2); 199 F32 targetValue = 0.5f + diff; 200 201 *targetData = targetValue * 255; 202 targetData++; 203 } 204 } 205 206 searchSpace.clear(); 207} 208