Torque3D Documentation / _generateds / distanceField.cpp

distanceField.cpp

Engine/source/gfx/util/distanceField.cpp

More...

Classes:

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