mirror of
https://github.com/godotengine/godot.git
synced 2024-12-27 11:24:59 +08:00
135 lines
5.1 KiB
C++
135 lines
5.1 KiB
C++
|
|
#include "contour-combiners.h"
|
|
|
|
#include <cfloat>
|
|
#include "arithmetics.hpp"
|
|
|
|
namespace msdfgen {
|
|
|
|
static void initDistance(double &distance) {
|
|
distance = -DBL_MAX;
|
|
}
|
|
|
|
static void initDistance(MultiDistance &distance) {
|
|
distance.r = -DBL_MAX;
|
|
distance.g = -DBL_MAX;
|
|
distance.b = -DBL_MAX;
|
|
}
|
|
|
|
static double resolveDistance(double distance) {
|
|
return distance;
|
|
}
|
|
|
|
static double resolveDistance(const MultiDistance &distance) {
|
|
return median(distance.r, distance.g, distance.b);
|
|
}
|
|
|
|
template <class EdgeSelector>
|
|
SimpleContourCombiner<EdgeSelector>::SimpleContourCombiner(const Shape &shape) { }
|
|
|
|
template <class EdgeSelector>
|
|
void SimpleContourCombiner<EdgeSelector>::reset(const Point2 &p) {
|
|
shapeEdgeSelector.reset(p);
|
|
}
|
|
|
|
template <class EdgeSelector>
|
|
EdgeSelector & SimpleContourCombiner<EdgeSelector>::edgeSelector(int) {
|
|
return shapeEdgeSelector;
|
|
}
|
|
|
|
template <class EdgeSelector>
|
|
typename SimpleContourCombiner<EdgeSelector>::DistanceType SimpleContourCombiner<EdgeSelector>::distance() const {
|
|
return shapeEdgeSelector.distance();
|
|
}
|
|
|
|
template class SimpleContourCombiner<TrueDistanceSelector>;
|
|
template class SimpleContourCombiner<PseudoDistanceSelector>;
|
|
template class SimpleContourCombiner<MultiDistanceSelector>;
|
|
template class SimpleContourCombiner<MultiAndTrueDistanceSelector>;
|
|
|
|
template <class EdgeSelector>
|
|
OverlappingContourCombiner<EdgeSelector>::OverlappingContourCombiner(const Shape &shape) {
|
|
windings.reserve(shape.contours.size());
|
|
for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
|
|
windings.push_back(contour->winding());
|
|
edgeSelectors.resize(shape.contours.size());
|
|
}
|
|
|
|
template <class EdgeSelector>
|
|
void OverlappingContourCombiner<EdgeSelector>::reset(const Point2 &p) {
|
|
this->p = p;
|
|
for (typename std::vector<EdgeSelector>::iterator contourEdgeSelector = edgeSelectors.begin(); contourEdgeSelector != edgeSelectors.end(); ++contourEdgeSelector)
|
|
contourEdgeSelector->reset(p);
|
|
}
|
|
|
|
template <class EdgeSelector>
|
|
EdgeSelector & OverlappingContourCombiner<EdgeSelector>::edgeSelector(int i) {
|
|
return edgeSelectors[i];
|
|
}
|
|
|
|
template <class EdgeSelector>
|
|
typename OverlappingContourCombiner<EdgeSelector>::DistanceType OverlappingContourCombiner<EdgeSelector>::distance() const {
|
|
int contourCount = (int) edgeSelectors.size();
|
|
EdgeSelector shapeEdgeSelector;
|
|
EdgeSelector innerEdgeSelector;
|
|
EdgeSelector outerEdgeSelector;
|
|
shapeEdgeSelector.reset(p);
|
|
innerEdgeSelector.reset(p);
|
|
outerEdgeSelector.reset(p);
|
|
for (int i = 0; i < contourCount; ++i) {
|
|
DistanceType edgeDistance = edgeSelectors[i].distance();
|
|
shapeEdgeSelector.merge(edgeSelectors[i]);
|
|
if (windings[i] > 0 && resolveDistance(edgeDistance) >= 0)
|
|
innerEdgeSelector.merge(edgeSelectors[i]);
|
|
if (windings[i] < 0 && resolveDistance(edgeDistance) <= 0)
|
|
outerEdgeSelector.merge(edgeSelectors[i]);
|
|
}
|
|
|
|
DistanceType shapeDistance = shapeEdgeSelector.distance();
|
|
DistanceType innerDistance = innerEdgeSelector.distance();
|
|
DistanceType outerDistance = outerEdgeSelector.distance();
|
|
double innerScalarDistance = resolveDistance(innerDistance);
|
|
double outerScalarDistance = resolveDistance(outerDistance);
|
|
DistanceType distance;
|
|
initDistance(distance);
|
|
|
|
int winding = 0;
|
|
if (innerScalarDistance >= 0 && fabs(innerScalarDistance) <= fabs(outerScalarDistance)) {
|
|
distance = innerDistance;
|
|
winding = 1;
|
|
for (int i = 0; i < contourCount; ++i)
|
|
if (windings[i] > 0) {
|
|
DistanceType contourDistance = edgeSelectors[i].distance();
|
|
if (fabs(resolveDistance(contourDistance)) < fabs(outerScalarDistance) && resolveDistance(contourDistance) > resolveDistance(distance))
|
|
distance = contourDistance;
|
|
}
|
|
} else if (outerScalarDistance <= 0 && fabs(outerScalarDistance) < fabs(innerScalarDistance)) {
|
|
distance = outerDistance;
|
|
winding = -1;
|
|
for (int i = 0; i < contourCount; ++i)
|
|
if (windings[i] < 0) {
|
|
DistanceType contourDistance = edgeSelectors[i].distance();
|
|
if (fabs(resolveDistance(contourDistance)) < fabs(innerScalarDistance) && resolveDistance(contourDistance) < resolveDistance(distance))
|
|
distance = contourDistance;
|
|
}
|
|
} else
|
|
return shapeDistance;
|
|
|
|
for (int i = 0; i < contourCount; ++i)
|
|
if (windings[i] != winding) {
|
|
DistanceType contourDistance = edgeSelectors[i].distance();
|
|
if (resolveDistance(contourDistance)*resolveDistance(distance) >= 0 && fabs(resolveDistance(contourDistance)) < fabs(resolveDistance(distance)))
|
|
distance = contourDistance;
|
|
}
|
|
if (resolveDistance(distance) == resolveDistance(shapeDistance))
|
|
distance = shapeDistance;
|
|
return distance;
|
|
}
|
|
|
|
template class OverlappingContourCombiner<TrueDistanceSelector>;
|
|
template class OverlappingContourCombiner<PseudoDistanceSelector>;
|
|
template class OverlappingContourCombiner<MultiDistanceSelector>;
|
|
template class OverlappingContourCombiner<MultiAndTrueDistanceSelector>;
|
|
|
|
}
|