636 lines
20 KiB
C++
636 lines
20 KiB
C++
![]() |
/**********************************************************************
|
||
|
|
||
|
Filename : GEdgeAA.cpp
|
||
|
Content :
|
||
|
Created : 2005-2006
|
||
|
Authors : Maxim Shemanarev
|
||
|
|
||
|
Copyright : (c) 2005-2006 Scaleform Corp. All Rights Reserved.
|
||
|
Patent Pending. Contact Scaleform for more information.
|
||
|
|
||
|
Notes :
|
||
|
|
||
|
Licensees may use this file in accordance with the valid Scaleform
|
||
|
Commercial License Agreement provided with the software.
|
||
|
|
||
|
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
|
||
|
THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE.
|
||
|
|
||
|
**********************************************************************/
|
||
|
|
||
|
#include "GEdgeAA.h"
|
||
|
|
||
|
#include <stdio.h> // remove!
|
||
|
|
||
|
#ifndef GFC_NO_FXPLAYER_EDGEAA
|
||
|
|
||
|
|
||
|
const unsigned GEdgeAA::VertexIdx[6] = {0, 1, 2, 0, 1, 2 };
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
UPInt GEdgeAA::GetNumBytes() const
|
||
|
{
|
||
|
return MeshTriangles.GetNumBytes() +
|
||
|
EdgeIdx.GetNumBytes() +
|
||
|
FanEdges.GetNumBytes() +
|
||
|
TmpStarVer.GetNumBytes() +
|
||
|
Triangles.GetNumBytes() +
|
||
|
VertexMap.GetNumBytes();
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
void GEdgeAA::Clear()
|
||
|
{
|
||
|
Vertices.Clear();
|
||
|
Edges.Clear();
|
||
|
MeshTriangles.Clear();
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
void GEdgeAA::ClearAndRelease()
|
||
|
{
|
||
|
Vertices.ClearAndRelease();
|
||
|
Edges.ClearAndRelease();
|
||
|
MeshTriangles.ClearAndRelease();
|
||
|
EdgeIdx.ClearAndRelease();
|
||
|
FanEdges.ClearAndRelease();
|
||
|
TmpStarVer.ClearAndRelease();
|
||
|
Triangles.ClearAndRelease();
|
||
|
VertexMap.ClearAndRelease();
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
void GEdgeAA::AddVertex(const GPointType& v)
|
||
|
{
|
||
|
VertexType tv;
|
||
|
tv.x = v.x;
|
||
|
tv.y = v.y;
|
||
|
tv.id = TransparencyBit | StyleMask;
|
||
|
Vertices.PushBack(tv);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
void GEdgeAA::AddTriangle(unsigned v1, unsigned v2, unsigned v3, unsigned style)
|
||
|
{
|
||
|
EdgeType e;
|
||
|
MeshTriType tri;
|
||
|
|
||
|
tri.iniVer[0] = v1;
|
||
|
tri.iniVer[1] = v2;
|
||
|
tri.iniVer[2] = v3;
|
||
|
tri.newVer[0] = v1;
|
||
|
tri.newVer[1] = v2;
|
||
|
tri.newVer[2] = v3;
|
||
|
|
||
|
tri.startEdge = (unsigned)Edges.GetSize();
|
||
|
tri.adjTri[0] =
|
||
|
tri.adjTri[1] =
|
||
|
tri.adjTri[2] = -1;
|
||
|
tri.extVer[0] =
|
||
|
tri.extVer[1] =
|
||
|
tri.extVer[2] = -1;
|
||
|
tri.edgeStat[0] =
|
||
|
tri.edgeStat[1] =
|
||
|
tri.edgeStat[2] = 0;
|
||
|
tri.style = style;
|
||
|
|
||
|
e.tri = (unsigned)MeshTriangles.GetSize() << 2;
|
||
|
e.v1 = v1;
|
||
|
e.v2 = v2;
|
||
|
Edges.PushBack(e);
|
||
|
e.tri++;
|
||
|
e.v1 = v2;
|
||
|
e.v2 = v3;
|
||
|
Edges.PushBack(e);
|
||
|
e.tri++;
|
||
|
e.v1 = v3;
|
||
|
e.v2 = v1;
|
||
|
Edges.PushBack(e);
|
||
|
|
||
|
MeshTriangles.PushBack(tri);
|
||
|
DefaultStyle = style;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
void GEdgeAA::buildAdjacencyTable()
|
||
|
{
|
||
|
EdgeIdx.Resize(Edges.GetSize());
|
||
|
UPInt i;
|
||
|
for(i = 0; i < Edges.GetSize(); i++)
|
||
|
{
|
||
|
EdgeIdx[i] = (unsigned)i;
|
||
|
}
|
||
|
EdgeIdxLess edgeLess(Vertices, Edges);
|
||
|
G_QuickSort(EdgeIdx, edgeLess);
|
||
|
|
||
|
for(i = 0; i < MeshTriangles.GetSize(); i++)
|
||
|
{
|
||
|
MeshTriType& tri = MeshTriangles[i];
|
||
|
tri.adjTri[0] = findAdjacentTriangle(tri.startEdge);
|
||
|
tri.adjTri[1] = findAdjacentTriangle(tri.startEdge + 1);
|
||
|
tri.adjTri[2] = findAdjacentTriangle(tri.startEdge + 2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
bool GEdgeAA::buildEdgesFan(unsigned triIdx)
|
||
|
{
|
||
|
int adjStart = triIdx;
|
||
|
int adj = adjStart;
|
||
|
int adj1, adj2;
|
||
|
bool cyclic = false;
|
||
|
int lastEdge = 0x7FFFFFFF;
|
||
|
unsigned lastIdx = 0;
|
||
|
|
||
|
FanEdges.Clear();
|
||
|
for(;;)
|
||
|
{
|
||
|
FanEdges.PushBack(adj1 = adj);
|
||
|
FanEdges.PushBack(adj2 = adj = triangleNextIdx(adj, 2));
|
||
|
if(adj1 == lastEdge || adj2 == lastEdge)
|
||
|
{
|
||
|
// Protection from infinite loops in degenerate cases
|
||
|
FanEdges.Clear();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
adj = adjacentTriangle(adj);
|
||
|
if(adj == adjStart)
|
||
|
{
|
||
|
cyclic = true;
|
||
|
break;
|
||
|
}
|
||
|
if(adj < 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
lastEdge = FanEdges[lastIdx++];
|
||
|
}
|
||
|
|
||
|
G_ReverseArray(FanEdges);
|
||
|
if(cyclic)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
adj = adjStart;
|
||
|
for(;;)
|
||
|
{
|
||
|
adj = adjacentTriangle(adj);
|
||
|
if(adj < 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
FanEdges.PushBack(adj1 = adj);
|
||
|
FanEdges.PushBack(adj2 = adj = triangleNextIdx(adj, 1));
|
||
|
if(adj1 == lastEdge || adj2 == lastEdge)
|
||
|
{
|
||
|
// Protection from infinite loops in degenerate cases
|
||
|
FanEdges.Clear();
|
||
|
return true;
|
||
|
}
|
||
|
lastEdge = FanEdges[lastIdx++];
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
void GEdgeAA::calcIntersectionPoint(GCoordType width, GCoordType lim,
|
||
|
unsigned start, unsigned end,
|
||
|
GCoordType* x, GCoordType* y) const
|
||
|
{
|
||
|
VertexType v1 = triangleVertex(FanEdges[start], 0);
|
||
|
VertexType v2 = triangleVertex(FanEdges[start], 1);
|
||
|
VertexType v3 = triangleVertex(FanEdges[end], 0);
|
||
|
VertexType v4 = triangleVertex(FanEdges[end], 1);
|
||
|
GCoordType vx = v2.x;
|
||
|
GCoordType vy = v2.y;
|
||
|
GCoordType len1 = GMath2D::CalcDistance(v1, v2);
|
||
|
GCoordType len2 = GMath2D::CalcDistance(v3, v4);
|
||
|
GCoordType epsilon = (len1 + len2) * G_IntersectionEpsilonAA;
|
||
|
GCoordType dx1 = width * (v2.y - v1.y) / len1;
|
||
|
GCoordType dy1 = width * (v1.x - v2.x) / len1;
|
||
|
GCoordType dx2 = width * (v4.y - v3.y) / len2;
|
||
|
GCoordType dy2 = width * (v3.x - v4.x) / len2;
|
||
|
|
||
|
if(GMath2D::CalcIntersection(v1.x + dx1, v1.y + dy1,
|
||
|
v2.x + dx1, v2.y + dy1,
|
||
|
v3.x + dx2, v3.y + dy2,
|
||
|
v4.x + dx2, v4.y + dy2, x, y, epsilon))
|
||
|
{
|
||
|
GCoordType dist = GMath2D::CalcDistance(*x, *y, vx, vy);
|
||
|
if (len1 < len2)
|
||
|
len1 = len2;
|
||
|
if (lim > len1)
|
||
|
lim = len1;
|
||
|
if(dist > lim)
|
||
|
{
|
||
|
GCoordType k = lim / dist;
|
||
|
*x = vx + (*x - vx) * k;
|
||
|
*y = vy + (*y - vy) * k;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (len1 > len2)
|
||
|
{
|
||
|
*x = v2.x + dx1;
|
||
|
*y = v2.y + dy1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*x = v3.x + dx2;
|
||
|
*y = v3.y + dy2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
void GEdgeAA::correctCrossIntersection(const VertexType& iniVer,
|
||
|
const MeshTriType& tri,
|
||
|
unsigned triVerIdx,
|
||
|
VertexType* newVer,
|
||
|
GCoordType width) const
|
||
|
{
|
||
|
GUNUSED(width);
|
||
|
|
||
|
const VertexType& v1 = Vertices[tri.newVer[VertexIdx[triVerIdx + 1]]];
|
||
|
const VertexType& v2 = Vertices[tri.newVer[VertexIdx[triVerIdx + 2]]];
|
||
|
|
||
|
if(GMath2D::CrossProduct(*newVer, v1, v2) < -0.1)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// A simple variant, works fairly well
|
||
|
GCoordType x, y;
|
||
|
GCoordType epsilon = (fabsf(iniVer.x - newVer->x) +
|
||
|
fabsf(iniVer.y - newVer->y) +
|
||
|
fabsf(v1.x - v2.x) +
|
||
|
fabsf(v1.y - v2.y)) * G_IntersectionEpsilonAA;
|
||
|
if(GMath2D::CalcIntersection(iniVer, *newVer,
|
||
|
v1, v2,
|
||
|
&x, &y,
|
||
|
epsilon))
|
||
|
{
|
||
|
x += (iniVer.x - x) * (GCoordType)0.25; // Correction to reduce possible overlaps
|
||
|
y += (iniVer.y - y) * (GCoordType)0.25;
|
||
|
newVer->x = x;
|
||
|
newVer->y = y;
|
||
|
}
|
||
|
|
||
|
//// An attempt to improve it. Doesn't help much
|
||
|
//GCoordType cp1 = GMath2D::CrossProduct(iniVer, *newVer, v1);
|
||
|
//GCoordType cp2 = GMath2D::CrossProduct(iniVer, *newVer, v2);
|
||
|
//GCoordType x, y;
|
||
|
//
|
||
|
//if(cp1 > 0 && cp2 < 0)
|
||
|
//{
|
||
|
// // The new vector spits the triangle
|
||
|
// if(GMath2D::CalcIntersection(iniVer, *newVer,
|
||
|
// v1, v2,
|
||
|
// &x, &y,
|
||
|
// G_IntersectionEpsilonAA))
|
||
|
// {
|
||
|
// newVer->x = x;
|
||
|
// newVer->y = y;
|
||
|
// }
|
||
|
//}
|
||
|
//else
|
||
|
//{
|
||
|
// // The vector is outside of the triangle
|
||
|
// GCoordType d;
|
||
|
// GCoordType k = 1;
|
||
|
//
|
||
|
// if(cp1 <= 0)
|
||
|
// {
|
||
|
// d = GMath2D::CalcDistance(iniVer, v1);
|
||
|
// if(width < d)
|
||
|
// {
|
||
|
// k = width / d;
|
||
|
// }
|
||
|
// newVer->x = iniVer.x + (v1.x - iniVer.x) * k;
|
||
|
// newVer->y = iniVer.y + (v1.y - iniVer.y) * k;
|
||
|
// }
|
||
|
// else
|
||
|
// if(cp2 >= 0)
|
||
|
// {
|
||
|
// d = GMath2D::CalcDistance(iniVer, v2);
|
||
|
// if(width < d)
|
||
|
// {
|
||
|
// k = width / d;
|
||
|
// }
|
||
|
// newVer->x = iniVer.x + (v2.x - iniVer.x) * k;
|
||
|
// newVer->y = iniVer.y + (v2.y - iniVer.y) * k;
|
||
|
// }
|
||
|
//}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
int GEdgeAA::findAdjacentTriangle(unsigned ei) const
|
||
|
{
|
||
|
EdgeType e;
|
||
|
e.v1 = Edges[ei].v2;
|
||
|
e.v2 = Edges[ei].v1;
|
||
|
EdgeLess edgeLess(Vertices, Edges);
|
||
|
UPInt pos = G_LowerBound(EdgeIdx, e, edgeLess);
|
||
|
if(pos < EdgeIdx.GetSize())
|
||
|
{
|
||
|
const EdgeType& e2 = Edges[EdgeIdx[pos]];
|
||
|
if(e2.v1 == e.v1 && e2.v2 == e.v2)
|
||
|
{
|
||
|
return e2.tri;
|
||
|
}
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
int GEdgeAA::findSameVertex(int id, GCoordType x, GCoordType y) const
|
||
|
{
|
||
|
unsigned i;
|
||
|
for (i = (unsigned)Vertices.GetSize(); i > StartDuplicates; --i)
|
||
|
{
|
||
|
const VertexType& v2 = Vertices[i - 1];
|
||
|
if (unsigned(v2.id & StyleMask) == unsigned(id) && v2.x == x && v2.y == y)
|
||
|
return int(i - 1);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
unsigned GEdgeAA::assignStyle(unsigned v1, unsigned v2, unsigned v3)
|
||
|
{
|
||
|
int id = Vertices[v1].id;
|
||
|
if (id & TransparencyBit)
|
||
|
{
|
||
|
int id2 = Vertices[v2].id;
|
||
|
int id3 = Vertices[v3].id;
|
||
|
int srcId;
|
||
|
if (id2 & TransparencyBit)
|
||
|
srcId = id3 & StyleMask;
|
||
|
else
|
||
|
srcId = id2 & StyleMask;
|
||
|
if (unsigned(id & StyleMask) != unsigned(srcId))
|
||
|
{
|
||
|
if(id & NeedsDuplicate)
|
||
|
{
|
||
|
VertexType newVer = Vertices[v1];
|
||
|
int newIdx = findSameVertex(srcId, newVer.x, newVer.y);
|
||
|
if (newIdx >= 0)
|
||
|
{
|
||
|
v1 = newIdx;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
newVer.id = (id & FlagsMask) | srcId | VertexUsed;
|
||
|
v1 = (unsigned)Vertices.GetSize();
|
||
|
Vertices.PushBack(newVer);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Vertices[v1].id = (id & FlagsMask) | srcId | NeedsDuplicate | VertexUsed;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return v1;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
void GEdgeAA::ProcessEdges(GCoordType width, AA_Method aaMethod)
|
||
|
{
|
||
|
unsigned i, j, k;
|
||
|
|
||
|
Triangles.Clear();
|
||
|
buildAdjacencyTable();
|
||
|
|
||
|
if(width >= 0)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int defaultStyle = TransparencyBit | VertexUsed | StyleMask;
|
||
|
if(aaMethod == AA_OuterEdges)
|
||
|
{
|
||
|
width *= 2;
|
||
|
defaultStyle = TransparencyBit | VertexUsed | DefaultStyle;
|
||
|
}
|
||
|
|
||
|
GCoordType lim = fabsf(width) * GetIntersectionMiterLimit();
|
||
|
|
||
|
for(i = 0; i < MeshTriangles.GetSize(); i++)
|
||
|
{
|
||
|
const MeshTriType& tri = MeshTriangles[i];
|
||
|
for(j = 0; j < 3; j++)
|
||
|
{
|
||
|
if((tri.edgeStat[j] & EdgeModified) == 0 &&
|
||
|
(Vertices[tri.iniVer[j]].id & VertexProcessed) == 0)
|
||
|
{
|
||
|
bool cyclic = buildEdgesFan((i << 2) + j);
|
||
|
|
||
|
if(FanEdges.GetSize() == 0)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if(cyclic &&
|
||
|
MeshTriangles[FanEdges[0] >> 2].style ==
|
||
|
MeshTriangles[FanEdges.Back() >> 2].style)
|
||
|
{
|
||
|
// Process only those cases that have different
|
||
|
// styles at start and the end.
|
||
|
// It protects us from using improper starting edges,
|
||
|
// as well as from processing of cyclic fans with
|
||
|
// all the same styles.
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
GCoordType x, y;
|
||
|
unsigned newVerIdx;
|
||
|
unsigned adjVal;
|
||
|
TmpStarVer.Clear();
|
||
|
const VertexType& center = Vertices[tri.iniVer[j]];
|
||
|
|
||
|
if(!cyclic)
|
||
|
{
|
||
|
// Non-circular fan means that we have external edges
|
||
|
calcIntersectionPoint(-width, lim, 0, (unsigned)FanEdges.GetSize() - 1, &x, &y);
|
||
|
|
||
|
newVerIdx = (unsigned)Vertices.GetSize();
|
||
|
Vertices.PushBack(VertexType(x, y, defaultStyle));
|
||
|
TmpStarVer.PushBack(newVerIdx);
|
||
|
|
||
|
adjVal = FanEdges[0];
|
||
|
MeshTriangles[adjVal >> 2].extVer[VertexIdx[(adjVal & 3) + 1]] = newVerIdx;
|
||
|
|
||
|
adjVal = FanEdges.Back();
|
||
|
MeshTriangles[adjVal >> 2].extVer[adjVal & 3] = newVerIdx;
|
||
|
}
|
||
|
|
||
|
if(aaMethod == AA_AllEdges)
|
||
|
{
|
||
|
unsigned start, end;
|
||
|
for(start = 0; start < FanEdges.GetSize(); )
|
||
|
{
|
||
|
const MeshTriType& t1 = MeshTriangles[FanEdges[start] >> 2];
|
||
|
for(end = start + 1; end < FanEdges.GetSize(); end++)
|
||
|
{
|
||
|
if(t1.style != MeshTriangles[FanEdges[end] >> 2].style)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
calcIntersectionPoint(width, lim, start, end - 1, &x, &y);
|
||
|
newVerIdx = (unsigned)Vertices.GetSize();
|
||
|
Vertices.PushBack(VertexType(x, y, defaultStyle));
|
||
|
TmpStarVer.PushBack(newVerIdx);
|
||
|
VertexType& newVer = Vertices.Back();
|
||
|
for(k = start; k < end; k += 2)
|
||
|
{
|
||
|
unsigned triVerIdx = triangleNextIdx(FanEdges[k], 1);
|
||
|
MeshTriType& t2 = MeshTriangles[triVerIdx >> 2];
|
||
|
correctCrossIntersection(Vertices[tri.iniVer[j]],
|
||
|
t2,
|
||
|
triVerIdx & 3,
|
||
|
&newVer,
|
||
|
-width);
|
||
|
t2.newVer[triVerIdx & 3] = newVerIdx;
|
||
|
t2.edgeStat[triVerIdx & 3] |= EdgeModified;
|
||
|
}
|
||
|
start = end;
|
||
|
}
|
||
|
|
||
|
while(TmpStarVer.GetSize() > 2)
|
||
|
{
|
||
|
GCoordType maxDist = 0;
|
||
|
unsigned maxIdx = 0;
|
||
|
unsigned s = (unsigned)TmpStarVer.GetSize();
|
||
|
for(k = 0; k < s; k++)
|
||
|
{
|
||
|
GCoordType d = GMath2D::CalcDistance(Vertices[TmpStarVer[k]],
|
||
|
center);
|
||
|
if(d > maxDist)
|
||
|
{
|
||
|
maxDist = d;
|
||
|
maxIdx = k;
|
||
|
}
|
||
|
}
|
||
|
addTriangle(TmpStarVer[(maxIdx + s - 1) % s],
|
||
|
TmpStarVer[ maxIdx ],
|
||
|
TmpStarVer[(maxIdx + 1) % s ]);
|
||
|
TmpStarVer.RemoveAt(maxIdx);
|
||
|
}
|
||
|
}
|
||
|
Vertices[tri.iniVer[j]].id |= VertexProcessed;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for(i = 0; i < MeshTriangles.GetSize(); i++)
|
||
|
{
|
||
|
MeshTriType& t1 = MeshTriangles[i];
|
||
|
if(t1.newVer[0] != t1.newVer[1] &&
|
||
|
t1.newVer[1] != t1.newVer[2] &&
|
||
|
t1.newVer[2] != t1.newVer[0])
|
||
|
{
|
||
|
addTriangle(t1.newVer[0], t1.newVer[1], t1.newVer[2]);
|
||
|
}
|
||
|
|
||
|
for(j = 0; j < 3; j++)
|
||
|
{
|
||
|
unsigned idx = t1.newVer[j];
|
||
|
Vertices[idx].id = t1.style | VertexUsed;
|
||
|
|
||
|
if((t1.edgeStat[j] & TrapezoidEmitted) == 0)
|
||
|
{
|
||
|
int adj = t1.adjTri[j];
|
||
|
int v1, v2, v3, v4;
|
||
|
|
||
|
if(adj < 0)
|
||
|
{
|
||
|
// External edge
|
||
|
v3 = t1.extVer[VertexIdx[j + 1]];
|
||
|
v4 = t1.extVer[j];
|
||
|
if(v3 >= 0 && v4 >= 0)
|
||
|
{
|
||
|
v1 = triangleNewVerIdx((i << 2) | j);
|
||
|
v2 = triangleNewVerIdx((i << 2) | j, 1);
|
||
|
addTriangle(v1, v2, v4);
|
||
|
addTriangle(v4, v2, v3);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Internal edge;
|
||
|
MeshTriType& t2 = MeshTriangles[adj >> 2];
|
||
|
if(t2.style != t1.style)
|
||
|
{
|
||
|
v1 = triangleNewVerIdx((i << 2) | j);
|
||
|
v2 = triangleNewVerIdx((i << 2) | j, 1);
|
||
|
v3 = triangleNewVerIdx(adj);
|
||
|
v4 = triangleNewVerIdx(adj, 1);
|
||
|
addTriangle(v1, v2, v4);
|
||
|
addTriangle(v4, v2, v3);
|
||
|
t2.edgeStat[adj & 3] |= TrapezoidEmitted;
|
||
|
}
|
||
|
}
|
||
|
t1.edgeStat[j] |= TrapezoidEmitted;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(aaMethod == AA_AllEdges)
|
||
|
{
|
||
|
VertexMap.Resize(Vertices.GetSize());
|
||
|
for(i = j = 0; i < (unsigned)Vertices.GetSize(); ++i)
|
||
|
{
|
||
|
VertexMap[i] = j;
|
||
|
if (Vertices[i].id & VertexUsed)
|
||
|
{
|
||
|
Vertices[j++] = Vertices[i];
|
||
|
}
|
||
|
}
|
||
|
Vertices.CutAt(StartDuplicates = j);
|
||
|
for(i = 0; i < (unsigned)Triangles.GetSize(); ++i)
|
||
|
{
|
||
|
TriangleType t1 = Triangles[i];
|
||
|
TriangleType t2;
|
||
|
t1.v1 = VertexMap[t1.v1];
|
||
|
t1.v2 = VertexMap[t1.v2];
|
||
|
t1.v3 = VertexMap[t1.v3];
|
||
|
t2.v1 = assignStyle(t1.v1, t1.v2, t1.v3);
|
||
|
t2.v2 = assignStyle(t1.v2, t1.v3, t1.v1);
|
||
|
t2.v3 = assignStyle(t1.v3, t1.v1, t1.v2);
|
||
|
Triangles[i] = t2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
void GEdgeAA::SortTrianglesByStyle()
|
||
|
{
|
||
|
unsigned i;
|
||
|
|
||
|
// Arrange styles in triangles
|
||
|
for(i = 0; i < Triangles.GetSize(); i++)
|
||
|
{
|
||
|
TriangleType& tri = Triangles[i];
|
||
|
if(Vertices[tri.v2].id < Vertices[tri.v1].id) G_Swap(tri.v2, tri.v1);
|
||
|
if(Vertices[tri.v3].id < Vertices[tri.v2].id) G_Swap(tri.v3, tri.v2);
|
||
|
if(Vertices[tri.v2].id < Vertices[tri.v1].id) G_Swap(tri.v2, tri.v1);
|
||
|
}
|
||
|
|
||
|
// Arrange triangles by styles in lexicographical order
|
||
|
TriangleLess triangleLess(Vertices);
|
||
|
G_QuickSort(Triangles, triangleLess);
|
||
|
}
|
||
|
|
||
|
#endif // #ifndef GFC_NO_FXPLAYER_EDGEAA
|