319 lines
9.8 KiB
C++
319 lines
9.8 KiB
C++
/**********************************************************************
|
|
|
|
Filename : GCompoundShape.cpp
|
|
Content :
|
|
Created : 2005-2006
|
|
Authors : Maxim Shemanarev
|
|
|
|
Copyright : (c) 2001-2006 Scaleform Corp. All Rights Reserved.
|
|
|
|
Notes : Compound Shape container
|
|
|
|
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 "GCompoundShape.h"
|
|
|
|
|
|
GDECLARE_MEMORY_STAT_AUTOSUM_GROUP(GStatRG_Mem, "RenderGen", GStat_Mem)
|
|
GDECLARE_MEMORY_STAT(GStatRG_Vertices_Mem, "Vertices", GStatRG_Mem)
|
|
GDECLARE_MEMORY_STAT(GStatRG_MeshFill_Mem, "MeshFill", GStatRG_Mem)
|
|
GDECLARE_MEMORY_STAT(GStatRG_MeshStroke_Mem, "MeshStroke", GStatRG_Mem)
|
|
GDECLARE_MEMORY_STAT(GStatRG_Tessellator_Mem, "Tessellator", GStatRG_Mem)
|
|
GDECLARE_MEMORY_STAT(GStatRG_Rasterizer_Mem, "Rasterizer", GStatRG_Mem)
|
|
GDECLARE_MEMORY_STAT(GStatRG_Stroker_Mem, "Stroker", GStatRG_Mem)
|
|
GDECLARE_MEMORY_STAT(GStatRG_EdgeAA_Mem, "EdgeAA", GStatRG_Mem)
|
|
GDECLARE_MEMORY_STAT(GStatRG_StrokerAA_Mem, "StrokerAA", GStatRG_Mem)
|
|
GDECLARE_MEMORY_STAT(GStatRG_Other_Mem, "RG_Other", GStatRG_Mem)
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
void GCompoundShape::Clear()
|
|
{
|
|
Vertices.Clear();
|
|
Paths.Clear();
|
|
CurrPath = 0;
|
|
MinStyle = 0x7FFFFFFF;
|
|
MaxStyle = -0x7FFFFFFF;
|
|
MinX = 1;
|
|
MinY = 1;
|
|
MaxX = 0;
|
|
MaxY = 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void GCompoundShape::ClearAndRelease()
|
|
{
|
|
Clear();
|
|
Vertices.ClearAndRelease();
|
|
Paths.ClearAndRelease();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
UPInt GCompoundShape::GetNumBytes() const
|
|
{
|
|
return Vertices.GetNumBytes() + Paths.GetNumBytes();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void GCompoundShape::SetCurveTolerance(GCoordType t)
|
|
{
|
|
CurveTolerance = t;
|
|
t /= 4;
|
|
ToleranceSquare = t * t;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void GCompoundShape::BeginPath(int lStyle, int rStyle, int lineStyle)
|
|
{
|
|
Paths.PushBack(SPath(this, (unsigned)Vertices.GetSize(), lStyle, rStyle, lineStyle));
|
|
CurrPath = &Paths.Back();
|
|
if(lStyle >= 0)
|
|
{
|
|
if(lStyle < MinStyle) MinStyle = lStyle;
|
|
if(lStyle > MaxStyle) MaxStyle = lStyle;
|
|
}
|
|
if(rStyle >= 0)
|
|
{
|
|
if(rStyle < MinStyle) MinStyle = rStyle;
|
|
if(rStyle > MaxStyle) MaxStyle = rStyle;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void GCompoundShape::BeginPath(int lStyle, int rStyle, int lineStyle,
|
|
GCoordType x, GCoordType y)
|
|
{
|
|
BeginPath(lStyle, rStyle, lineStyle);
|
|
AddVertex(x, y);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void GCompoundShape::ClosePath()
|
|
{
|
|
if(CurrPath && CurrPath->GetNumVertices() > 1)
|
|
{
|
|
const GPointType& v = CurrPath->GetVertex(0);
|
|
AddVertex(v.x, v.y);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void GCompoundShape::AddCurve(GCoordType cx, GCoordType cy,
|
|
GCoordType ax, GCoordType ay)
|
|
{
|
|
const GPointType& p = Vertices.Back();
|
|
if(GMath2D::AbsCrossProduct(p,
|
|
GPointType(cx, cy),
|
|
GPointType(ax, ay)) < G_CollinearCurveEpsilon)
|
|
{
|
|
AddVertex(ax, ay);
|
|
}
|
|
else
|
|
{
|
|
flattenQuadraticCurve(p.x, p.y, cx, cy, ax, ay);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void GCompoundShape::flattenQuadraticCurve(GCoordType x1, GCoordType y1,
|
|
GCoordType x2, GCoordType y2,
|
|
GCoordType x3, GCoordType y3)
|
|
{
|
|
const GCoordType halfMultiplier = (GCoordType)0.5f;
|
|
|
|
// Calculate all the mid-points of the line segments
|
|
//----------------------
|
|
GCoordType x12 = (x1 + x2) * halfMultiplier;
|
|
GCoordType y12 = (y1 + y2) * halfMultiplier;
|
|
GCoordType x23 = (x2 + x3) * halfMultiplier;
|
|
GCoordType y23 = (y2 + y3) * halfMultiplier;
|
|
|
|
GCoordType dx = x3-x1;
|
|
GCoordType dy = y3-y1;
|
|
GCoordType d = (GCoordType)fabs(((x2 - x3) * dy - (y2 - y3) * dx));
|
|
|
|
if(d > G_CollinearCurveEpsilon)
|
|
{
|
|
// Regular case
|
|
//-----------------
|
|
if(d * d <= ToleranceSquare * (dx*dx + dy*dy))
|
|
{
|
|
// If the curvature doesn't exceed the distance_tolerance value
|
|
// we can finish subdivisions.
|
|
//----------------------
|
|
AddVertex(x3, y3);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AddVertex(x3, y3);
|
|
return;
|
|
}
|
|
|
|
GCoordType x123 = (x12 + x23) * halfMultiplier;
|
|
GCoordType y123 = (y12 + y23) * halfMultiplier;
|
|
|
|
// Continue subdivision
|
|
//----------------------
|
|
flattenQuadraticCurve(x1, y1, x12, y12, x123, y123);
|
|
flattenQuadraticCurve(x123, y123, x23, y23, x3, y3);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
bool GCompoundShape::PathsEqual(const SPath& a, const SPath& b)
|
|
{
|
|
unsigned ia, ib;
|
|
for(ia = ib = 0;
|
|
ia < a.GetNumVertices() && ib < a.GetNumVertices();
|
|
++ia, ++ib)
|
|
{
|
|
const GPointType& pa = a.GetVertex(ia);
|
|
const GPointType& pb = b.GetVertex(ib);
|
|
if(pa.x != pb.x || pa.y != pb.y)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return (ia < a.GetNumVertices()) == (ib < b.GetNumVertices());
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void GCompoundShape::PerceiveBounds(GCoordType* x1, GCoordType* y1,
|
|
GCoordType* x2, GCoordType* y2) const
|
|
{
|
|
*x1 = 1;
|
|
*y1 = 1;
|
|
*x2 = 0;
|
|
*y2 = 0;
|
|
if(Vertices.GetSize())
|
|
{
|
|
*x1 = *x2 = Vertices[0].x;
|
|
*y1 = *y2 = Vertices[0].y;
|
|
for(unsigned i = 1; i < Vertices.GetSize(); i++)
|
|
{
|
|
const GPointType& p = Vertices[i];
|
|
if(p.x < *x1) *x1 = p.x;
|
|
if(p.y < *y1) *y1 = p.y;
|
|
if(p.x > *x2) *x2 = p.x;
|
|
if(p.y > *y2) *y2 = p.y;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void GCompoundShape::ExpandPathBounds(const SPath& path,
|
|
GCoordType* x1, GCoordType* y1,
|
|
GCoordType* x2, GCoordType* y2)
|
|
{
|
|
for (unsigned i = 0; i < path.GetNumVertices(); ++i)
|
|
{
|
|
const GPointType& p = path.GetVertex(i);
|
|
if(p.x < *x1) *x1 = p.x;
|
|
if(p.y < *y1) *y1 = p.y;
|
|
if(p.x > *x2) *x2 = p.x;
|
|
if(p.y > *y2) *y2 = p.y;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
void GCompoundShape::PerceiveBounds()
|
|
{
|
|
PerceiveBounds(&MinX, &MinY, &MaxX, &MaxY);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
bool GCompoundShape::PointInShape(GCoordType x, GCoordType y, bool nonZero) const
|
|
{
|
|
int styleCount = 0;
|
|
unsigned i, j;
|
|
for(i = 0; i < GetNumPaths(); i++)
|
|
{
|
|
const SPath& path = GetPath(i);
|
|
int ls = path.GetLeftStyle();
|
|
int rs = path.GetRightStyle();
|
|
if(ls != rs)
|
|
{
|
|
for(j = 1; j < path.GetNumVertices(); j++)
|
|
{
|
|
GPointType p1 = path.GetVertex(j-1);
|
|
GPointType p2 = path.GetVertex(j);
|
|
if(p1.y != p2.y)
|
|
{
|
|
int dir = 1;
|
|
if(p1.y > p2.y)
|
|
{
|
|
G_Swap(p1, p2);
|
|
dir = -1;
|
|
}
|
|
if(y >= p1.y && y < p2.y &&
|
|
GMath2D::CrossProduct(p1, p2, GPointType(x, y)) > 0)
|
|
{
|
|
if(nonZero)
|
|
{
|
|
if(ls >= 0) styleCount += (ls + 1) * dir;
|
|
if(rs >= 0) styleCount -= (rs + 1) * dir;
|
|
}
|
|
else
|
|
{
|
|
if(ls >= 0) styleCount ^= 1;
|
|
if(rs >= 0) styleCount ^= 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return styleCount != 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void GCompoundShape::ScaleAndTranslate(GCoordType kx, GCoordType ky,
|
|
GCoordType dx, GCoordType dy)
|
|
{
|
|
for(unsigned i = 0; i < Vertices.GetSize(); i++)
|
|
{
|
|
GPointType& p = Vertices[i];
|
|
p.x *= kx;
|
|
p.y *= ky;
|
|
p.x += dx;
|
|
p.y += dy;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void GCompoundShape::RemoveShortSegments(GCoordType maxLen)
|
|
{
|
|
unsigned i, j;
|
|
for(i = 0; i < GetNumPaths(); ++i)
|
|
{
|
|
SPath& path = GetPath(i);
|
|
if (path.NumVertices > 2)
|
|
{
|
|
unsigned start = path.StartVertex;
|
|
unsigned num = path.NumVertices - 1;
|
|
GPointType v1 = Vertices[start];
|
|
for(j = 1; j < num; ++j)
|
|
{
|
|
GPointType& v2 = Vertices[start + j];
|
|
if (fabsf(v2.x-v1.x) + fabsf(v2.y-v1.y) >= maxLen)
|
|
v1 = v2;
|
|
else
|
|
v2 = v1;
|
|
}
|
|
v1 = Vertices[start + num];
|
|
GPointType& v2 = Vertices[start + num - 1];
|
|
if (fabsf(v2.x-v1.x) + fabsf(v2.y-v1.y) < maxLen)
|
|
v2 = v1;
|
|
}
|
|
}
|
|
}
|
|
|