From 7c6517e9a082c1039a0e2410178ad4f47c4ecaf5 Mon Sep 17 00:00:00 2001 From: Hugh Sanderson Date: Tue, 23 Apr 2024 23:57:23 +0800 Subject: [PATCH] Update hardware polygon AA edge code --- include/nme/QuickVec.h | 4 +- project/include/Hardware.h | 2 +- project/src/common/Hardware.cpp | 1114 ++++++++++++++++++----------- project/src/common/Tessellate.cpp | 30 +- 4 files changed, 718 insertions(+), 432 deletions(-) diff --git a/include/nme/QuickVec.h b/include/nme/QuickVec.h index f290c9e92..9880c8405 100644 --- a/include/nme/QuickVec.h +++ b/include/nme/QuickVec.h @@ -351,7 +351,9 @@ class QuickVec void erase(size_t inFirst,size_t inLen) { if (inFirst>mSize || inFirst<0) - return; + { + throw std::runtime_error("bad erase"); + } if (inFirst+inLen>=mSize || inLen<0) resize(inFirst); else diff --git a/project/include/Hardware.h b/project/include/Hardware.h index a7fdeab72..a018b789a 100644 --- a/project/include/Hardware.h +++ b/project/include/Hardware.h @@ -99,7 +99,7 @@ class HardwareData void NmeClipOutline(Vertices &ioOutline,QuickVec &ioSubPolys, WindingRule inWinding); -void ConvertOutlineToTriangles(Vertices &ioOutline,const QuickVec &inSubPolys,WindingRule inWinding); +bool ConvertOutlineToTriangles(Vertices &ioOutline,const QuickVec &inSubPolys,WindingRule inWinding); class HardwareContext : public Object { diff --git a/project/src/common/Hardware.cpp b/project/src/common/Hardware.cpp index 6a77d3122..11e274a2d 100644 --- a/project/src/common/Hardware.cpp +++ b/project/src/common/Hardware.cpp @@ -17,8 +17,13 @@ namespace nme #endif #endif -enum { DEBUG_KEEP_LOOPS = 0 }; -enum { DEBUG_FAT_LINES = 0 }; +enum { DEBUG_KEEP_LOOPS = 0 }; +enum { DEBUG_FAT_LINES = 0 }; +enum { DEBUG_UNSCALED = 0 }; +enum { DEBUG_NO_INTERIOR = 0 }; +enum { DEBUG_NO_FAT_FALLBACK = 0 }; +enum { DEBUG_EXTRA_FAT = 0 }; +enum { DEBUG_PRINT_THRESH = 0 }; struct CurveEdge @@ -262,6 +267,18 @@ void balanceTris(PNTris &tris, const Vertices &p) } } +/* +void makePoly0ormals(PNTris &inTris, Vertices &inPoints, Vertices &outNormals) +{ + std::vector edgeDist(inPoints.size); + for(int i=0;i Normals; class HardwareBuilder @@ -284,7 +301,7 @@ class HardwareBuilder int align = 2*sizeof(float); mSolidMode = false; - mPolyAA = inJob.mPolyAA; + mPolyAA = false; mPerpLen = 0.5; mStateScale = data.scaleOf(inState); mScale = mStateScale; @@ -292,7 +309,6 @@ class HardwareBuilder if (mScale<=0.001) mScale = 0.001; mCurveThresh2 = 0.125/mScale/mScale; - mFatLineCullThresh = 5.0/mScale; mWinding = inPath.winding; if (inJob.mIsTileJob) @@ -316,13 +332,20 @@ class HardwareBuilder if (!SetFill(inJob.mFill,inHardware)) return; - if (mPolyAA) + if (inJob.mPolyAA && polyAaGeomOk(&inPath.commands[inJob.mCommand0], inJob.mCommandCount, &inPath.data[inJob.mData0]) ) { - //printf("Reserve solid AA..\n"); - mElement.mFlags |= DRAW_HAS_NORMAL; - mElement.mNormalOffset = mElement.mVertexOffset + mElement.mStride; - mElement.mStride += sizeof(float)*2; - mPolyAA = true; + mPolyAA = inJob.mPolyAA; + mElement.mPrimType = ptTriangles; + + mCaps = scRound; + mJoints = sjRound; + mMiterLimit = 0.5; + + mElement.mWidth = 1.0/mScale; + if (DEBUG_EXTRA_FAT) + mElement.mWidth = 5.0/mScale; + mPerpLen = mElement.mWidth*0.5; + } } else if (tessellate_lines && inJob.mStroke->scaleMode==ssmNormal) @@ -494,9 +517,17 @@ class HardwareBuilder AddTiles(mode, &inPath.data[inJob.mData0], tiles); } } - else if (tessellate_lines && !mSolidMode) + else if (tessellate_lines && (!mSolidMode || mPolyAA) ) { - AddLineTriangles(&inPath.commands[inJob.mCommand0], inJob.mCommandCount, &inPath.data[inJob.mData0] ); + if (!AddLineTriangles(&inPath.commands[inJob.mCommand0], inJob.mCommandCount, &inPath.data[inJob.mData0] )) + { + if (mPolyAA) + { + mPolyAA = false; + mSolidMode = true; + AddObject(&inPath.commands[inJob.mCommand0], inJob.mCommandCount, &inPath.data[inJob.mData0]); + } + } } else { @@ -1355,12 +1386,10 @@ class HardwareBuilder PushElement(); } - void PushTris(const PNTris &inTris, const Vertices &inPoints) + void PushTris(PNTris &inTris, Vertices &inPoints) { int n = (int)inTris.size(); ReserveArrays(n*3); - std::vector isOuter; - isOuter.reserve(n*3); //printf("PushVertices %d\n", inV.size()); @@ -1371,21 +1400,11 @@ class HardwareBuilder *v = inPoints[ tri.p[0] ]; Next(v); *v = inPoints[ tri.p[1] ]; Next(v); *v = inPoints[ tri.p[2] ]; Next(v); - - isOuter.push_back( tri.n[0]<0 ); - isOuter.push_back( tri.n[1]<0 ); - isOuter.push_back( tri.n[2]<0 ); } if (mElement.mSurface) CalcTexCoords(); - if (mPolyAA) - { - mElement.mFlags |= DRAW_EDGE_DIST; - CalcNormalCoords(isOuter); - } - PushElement(); } @@ -1571,15 +1590,16 @@ class HardwareBuilder #define FLAT 0.000001 - void AddPolygon(Vertices &ioOutline,const QuickVec &inSubPolys) + bool AddPolygon(Vertices &ioOutline,const QuickVec &inSubPolys, bool requireClean = false) { bool showTriangles = false; - if (mSolidMode && ioOutline.size()<3) - return; + bool solid = mSolidMode || mPolyAA; + if (solid && ioOutline.size()<3) + return true; bool isConvex = inSubPolys.size()==1; - if (mSolidMode) + if (solid) { if (isConvex) { @@ -1613,12 +1633,14 @@ class HardwareBuilder } if (!isConvex) { - ConvertOutlineToTriangles(ioOutline,inSubPolys,mWinding); + bool good = ConvertOutlineToTriangles(ioOutline,inSubPolys,mWinding); + if (requireClean && !good) + return false; //showTriangles = true; } } - if (mSolidMode && ioOutline.size()<3) - return; + if (solid && ioOutline.size()<3) + return true; mElement.mVertexOffset = data.mArray.size(); @@ -1631,29 +1653,13 @@ class HardwareBuilder PushTriangleWireframe(ioOutline, fan); //PushOutline(ioOutline); } - else if (mPolyAA) - { - PNTris tris; - - if (fan) - fanToTris(tris, ioOutline.size() ); - else - triListToTris(tris, ioOutline ); - - //balanceTris(tris,ioOutline); - mElement.mPrimType = ptTriangles; - #ifdef DBG_BALANCE - PushTrisWireframe(tris,ioOutline); - #else - PushTris(tris,ioOutline); - #endif - } else { if (!fan) mElement.mPrimType = ptTriangles; PushVertices(ioOutline); } + return true; } @@ -1818,6 +1824,8 @@ class HardwareBuilder int steps = 1 + mPerpLen*mScale*angle*3; if (steps>60) steps = 60; + else if (steps<3) + steps = 3; double d_theta = angle / (steps+1); double theta = d_theta; for(int i=1;i0) + { + curve[dest].t = (curve[i].t + curve[i+mergeCount].t) * 0.5; + i+=mergeCount; + } + dest++; + } + curve.resize(dest); + if (DEBUG_KEEP_LOOPS) { - if (inLoop) - curve.push_back( CurveEdge( curve[0].p, oT) ); + int n = (int)curve.size(); + if (isClosed && curve[0].p != curve[n-1].p) + curve.push_back(curve[0]); return; } - double perp2 = mPerpLen*mPerpLen*4.0; - int lastStart = inLoop ? 0 : -3; - for(int startPoint=0; startPoint0 && curve.size()>DEBUG_PRINT_THRESH; + if (dbgPrint) + printf("Clear Curve - %d\n", osize); + + int lastStart = isClosed ? 0 : -3; + for(int startPoint=0; startPoint2;startPoint++) { + // Get line segment ....... startPoint, startPoint+1: p0 - p1 const UserPoint &p0 = curve[startPoint].p; int startNext = (startPoint+1) % curve.size(); UserPoint &p1 = curve[startNext].p; - UserPoint dp = p1-p0; - // Merge.... - double dpLen = dp.x*dp.x + dp.y*dp.y; - if (dpLen < 0.0001) + + UserPoint dir0 = p1-p0; + // Should already be cleaned, but maybe very close insertions + double len = dir0.Norm(); + if ( len<0.000001 ) { + if (dbgPrint) + printf("remove dupe %d/%d : %d\n", startPoint,startNext, (int)curve.size() ); curve.erase(std::max(startPoint,startNext),1); - // will be incremented again startPoint--; continue; } - dpLen = inSide*sqrt(dpLen); - double dpX = dp.x/dpLen; - double dpY = dp.y/dpLen; - float minX = std::min(p0.x,p1.x); - float maxX = std::max(p0.x,p1.x); - float minY = std::min(p0.y,p1.y); - float maxY = std::max(p0.y,p1.y); + UserPoint onSideDist = dir0.Perp(-0.25*inSide/mPerpLen); + // Next segment can't intersect with first segment since it shared end + int prevSlot = (startPoint+2) % curve.size(); + UserPoint prevPoint = curve[prevSlot].p; + // Should already be cleaned, but maybe very close insertions + if ( (prevPoint-p1).Norm()<0.0001 ) + { + if (dbgPrint) + printf("remove dupe1 %d\n", startNext ); + curve.erase(std::max(startNext,prevSlot),1); + startPoint--; + continue; + } - int stopOffset = inLoop ? curve.size() : -1; - for(int t = startPoint+2; t1 ) { - int testPoint = t; - int testNext = t+1; - if (inLoop) + //if (dbgPrint) + // printf(" %d] stop early side %f\n", startPoint, side); + continue; + } + + // Check all the points downstream, possibly including the closing segment from end to beginning + int stopOffset = isClosed ? curve.size() : -1; + int advance = 0; + for(int t = startPoint+3; t mPerpLen*2) - if (perp*perp > perp2) + if (dbgPrint) + printf(" %d] loopback done %d\n", startPoint, advance); break; + } + + const UserPoint &p = curve[testPoint].p; + float side = onSideDist.Dot( p-p0 ); + bool currentOnOddSide = side<0; + advance++; + //if (advance<5) + // printf(" %d-%d i %d-%d, side0=%d, sid1=%f -> %d\n", startPoint, startNext, prevSlot,testPoint, prevOnOddSide, side, currentOnOddSide ); - const UserPoint &l1 = curve[testNext].p; - if ( (l0.xmaxX && l1.x>maxX) || - (l0.ymaxY && l1.y>maxY) ) - continue; - - UserPoint dl = l1-l0; - // Solve p0.x + a dp.x = l0.x + b dl.x - // p0.y + a dp.y = l0.y + b dl.y - - // Solve p0.x*dp.y + a dp.x*dp.y = l0.x*dp.y + b dl.x*dp.y - // p0.y*dp.x + a dp.y*dp.x = l0.y*dp.x + b dl.y*dp.x - // p0 x dp - l0 x dp = b dl x dp - // (p0-l0) x dp = b dl x dp - double denom = dl.Cross(dp); - if (denom!=0.0) + if (prevOnOddSide != currentOnOddSide) { - double b = (p0-l0).Cross(dp)/denom; - if (b>=0 && b<=1.0) + const UserPoint dir = p-prevPoint; + // prevPoint -> p crosses the p0->p1 line + + // Solve p0.x + a dir0.x = prevPoint.x + b dir.x + // p0.y + a dir0.y = prevPoint.y + b dir.y + + // Solve p0.x*dir0.y + a dir0.x*dir0.y = prevPoint.x*dir0.y + b dir.x*dir0.y + // p0.y*dir0.x + a dir0.y*dir0.x = prevPoint.y*dir0.x + b dir.y*dir0.x + // p0 x dir0 - prevPoint x dir0 = b dir x dir0 + // (p0-prevPoint) x dir0 = b dir x dir0 + double denom = dir.Cross(dir0); + if (denom!=0.0) { - double a = (fabs(dp.x) > fabs(dp.y)) ? (l0.x + b*dl.x - p0.x)/dp.x : - (l0.y + b*dl.y - p0.y)/dp.y; - //if (a>=0 && a<=1) equals case? - if ( (a!=1 && a!=0) || (b!=1 && b!=0) ) + double b = (p0-prevPoint).Cross(dir0)/denom; + if (b>=0 && b<=1.0) { - if (a>=0 && a<=1) + double a = (fabs(dir0.x) > fabs(dir0.y)) ? (prevPoint.x + b*dir.x - p0.x)/dir0.x : + (prevPoint.y + b*dir.y - p0.y)/dir0.y; + //if (a>=0 && a<=1) equals case? + if ( (a!=1 && a!=0) || (b!=1 && b!=0) ) { - UserPoint p = p0 + dp*a; - // Calculate loop-sense ... - double sense = 0.0; - int end = testPoint; - if (end0) // figure-8 intersection Ok.... - { - continue; - } - else - if (testNext=0 && a<=1) { - if (startNext == 0) + if (dbgPrint) + printf("Intersect %f %f %d-%d x %d-%d\n", a, b, startPoint, startNext, prevSlot, testPoint ); + UserPoint p = p0 + dir0*a; + + // Calculate loop-sense ... + double sense = 0.0; + int end = testPoint; + UserPoint prev = p1 - p; + // Loop p , startNext, startNext+1, startNext+1, ... prevSlot, p | testPoint + for(int i=startNext+1; i!=testPoint; i=(i+1)%curve.size() ) { - // Remove the loop - // c[startNext] - // ... - // c[testPoint] <- p - // c[testNext] - // ... - // c[startPoint] - // erase between 0 and testPoint - curve[testPoint].p = p; + UserPoint v = curve[i].p - p; + sense += prev.Cross(v); + prev = v; + } - //curve[testPoint].t = curve[testPoint>>1].t; - curve.EraseAt(0, testPoint); - // Done + // figure-8 - more than one island of correctly oriented edges + if (dbgPrint) + printf(" sense: %f\n", sense); + if (sense*inSide>0.00001) + { + if (dbgPrint) + printf(" keep sub loop\n"); + break; } - else if (testPoint>1].t; - //curve.EraseAt(startNext,curve.size()); - oT = curve[startNext].t; - curve.resize(startNext); - curve.EraseAt(0,testPoint); - startPoint-= testPoint; - startPoint--; + if (dbgPrint) + printf(" snip wrap around\n"); + if (startNext == 0) + { + if (dbgPrint) + printf(" snip start\n"); + // Remove the loop up to testPoint, and replace testPoint with intersection + // c[startNext] + // ... + // c[prevSlot] + // c[testPoint] <- p + // ... + // c[startPoint] + // erase between 0 and testPoint + curve[testPoint].p = p; + curve[testPoint].t = curve[0].t; + curve.EraseAt(0, testPoint); + // Done + } + else if (testPoint==0) + { + if (dbgPrint) + printf(" snip end %d -> %d\n", (int)curve.size(), startNext+1); + // Remove the loop + // c[testPoint] + // ... + // c[startPoint] + // c[startNext] <- p + // ... + // ... + curve[startNext].p = p; + //curve[startNext].t = curve[0].t; + curve.resize(startNext+1); + + } + else if (testPoint wrap around to p + // c[startNext] + // ... + // + curve[prevSlot].p = p; + curve[prevSlot].t = curve[0].t; + // Delete startNext onwards + //oT = curve[startNext].t; + curve.resize(startNext); + // Remove up to prevSlot + if (prevSlot) + curve.EraseAt(0,prevSlot); + startPoint-= prevSlot; + startPoint--; + } + else + { + if (dbgPrint) + printf(" snip in middle\n"); + // Remove the loop - set first point to intersection, delete startNext onwards + // c[testPoint] <- p + // ... + // c[startPoint] + // c[startNext] + // ... + // c[prevSlot] + curve[testPoint].p = p; + //oT = curve[startNext].t; + curve.EraseAt(startNext,curve.size()); + startPoint--; + } } else { + if (dbgPrint) + printf(" snip normal at %d\n", advance); // Remove the loop - // c[testNext] <- p - // ... // c[startPoint] // c[startNext] - // ... - // c[testPoint] - curve[testNext].p = p; - oT = curve[startNext].t; - curve.EraseAt(startNext,curve.size()); - startPoint--; + // ... + // c[prevSlot] <- p + // c[testPoint] + // ... + curve[prevSlot].p = p; + if (dbgPrint) + printf(" replace %d -> %f,%f\n", prevSlot, p.x, p.y ); + curve[prevSlot].t = curve[ (startNext+prevSlot) >> 1].t; + if (dbgPrint) + printf(" erase %d...%d\n", startNext, testPoint ); + curve.EraseAt(startNext,prevSlot); + // will get incremented + startPoint -=1; + if (startPoint<-1) startPoint = -1; } + // Go back to start point + prevSlot = -1; + break; } - else - { - // Remove the loop - // c[startPoint] - // c[startNext] - // ... - // c[testPoint] <- p - // c[testNext] - // ... - curve[testPoint].p = p; - curve[testPoint].t = curve[ (startNext+testPoint) >> 1].t; - curve.EraseAt(startNext,testPoint); - startPoint -=1; - if (startPoint<-1) startPoint = -1; - } - // Try again... - break; } } } } + // Point is outside the onSideDist - stop + // Don't care about overlap so much in non-mPolyAA case + //if (fabs(side)>1 ) + if (side>1 || (!mPolyAA && side<-1) ) + { + //if (dbgPrint) + // printf(" %d] side @ %d %f\n", startPoint, advance, side); + break; + } + + prevOnOddSide = currentOnOddSide; + prevSlot = testPoint; + prevPoint = p; } } + if (isClosed && curve.size()>1 && curve[ curve.size()-1].p != curve[0].p) + curve.push_back( CurveEdge( curve[0].p, oT) ); - /* - double sense = 0; - if (inLoop) + if (dbgPrint) { - int n = inPath.size(); - for(int i=0;i1 && curve[ curve.size()-1].p != curve[0].p) - curve.push_back( CurveEdge( curve[0].p, oT) ); } - #if 0 - void removeLoops(QuickVec &curve,int startPoint,float turningPoint,int *inAdjustStart=0) - { - if (DEBUG_KEEP_LOOPS!=0) - return; - - for(int i=startPoint;ii) - (*inAdjustStart)--; - curve.erase(i,1); - i--; - continue; - } - float minX = std::min(p0.x,p1.x); - float maxX = std::max(p0.x,p1.x); - float minY = std::min(p0.y,p1.y); - float maxY = std::max(p0.y,p1.y); - float ct = curve[i].t; - int cti = (int)ct; - bool afterTurning = turningPoint!=0 && ct>turningPoint; - for(int j=i+2;jmaxX && l1.x>maxX) || - (l0.ymaxY && l1.y>maxY) ) - continue; - - // Only consider intersection with self or joint for second half of curve - if (turningPoint>0 && curve[j].t>turningPoint && cti<(int)curve[j].t-1) - break; - - UserPoint dl = l1-l0; - // Solve p0.x + a dp.x = l0.x + b dl.x - // p0.y + a dp.y = l0.y + b dl.y - - // Solve p0.x*dp.y + a dp.x*dp.y = l0.x*dp.y + b dl.x*dp.y - // p0.y*dp.x + a dp.y*dp.x = l0.y*dp.x + b dl.y*dp.x - // p0 x dp - l0 x dp = b dl x dp - // (p0-l0) x dp = b dl x dp - double denom = dl.Cross(dp); - if (denom!=0.0) - { - double b = (p0-l0).Cross(dp)/denom; - if (b>=0 && b<=1.0) - { - double a = (fabs(dp.x) > fabs(dp.y)) ? (l0.x + b*dl.x - p0.x)/dp.x : - (l0.y + b*dl.y - p0.y)/dp.y; - if (a>=0 && a<=1) - { - if (a>0 && a<1 && b>0 && b<1) - { - UserPoint p = p0 + dp*a; - // Remove the loop - // c[i] - // p <- new point between c[i] and c[i+1] - // c[i+1] - // c[i+2] - // ... - // c[j] - // p <- new point between c[j] and c[j+1] - // c[j+1] - { - // replace c[i+1] with p, and erase upto and including c[j] - p1 = p; - curve.EraseAt(i+2,j+1); - if (inAdjustStart) - { - int &a = *inAdjustStart; - if (a>i) - a = i; - } - break; - } - } - } - } - } - } - } - } - #endif - - void AddCurveSegment(Curves &leftCurve, Curves &rightCurve, UserPoint perp0, UserPoint perp1, UserPoint inP0,UserPoint inP1,UserPoint inP2, @@ -2297,7 +2306,7 @@ class HardwareBuilder } } - bool ComputeDistInfo(const UserPoint &otherSide, const UserPoint &prev, const UserPoint &p, + void ComputeDistInfo(const UserPoint &otherSide, const UserPoint &prev, const UserPoint &p, UserPoint &outSideInfo, UserPoint &outInfo, double inSign) { /* @@ -2318,44 +2327,136 @@ class HardwareBuilder */ + if (mPolyAA) + { + // inSign 1 -> 1, inSign -1 -> 0 + // Shader uses: x - abs(y) + outSideInfo = UserPoint(1, 0.5+inSign*0.5); + outInfo = UserPoint(1, 0.5-inSign*0.5); + } + else + { + // Use simplified version to ensure values on edges of triangles match + float h = mElement.mWidth*mScale*0.5f; + outSideInfo = UserPoint(h, inSign*h); + outInfo = UserPoint(h, -inSign*h); + } + //float lastLen = outSideInfo.x; + /* float h = fabs( (p-otherSide).Dot( (p-prev).Perp(1.0) ) ); + h *= mScale * 0.5; if (h 1.0; + bool AddStrip(const QuickVec &inPath, bool isClosed) + { + if (inPath.size()<2) + return true; + + Curves leftCurve; + Curves rightCurve; + + pathToCurves(inPath, isClosed, leftCurve, rightCurve); + + if (leftCurve.size()<1 || rightCurve.size()<1) + return true; + if (leftCurve.size()<3 && rightCurve.size()<3) + return true; + + if (mPolyAA) + { + float lx = leftCurve[0].p.x; + for(int i=1;i1 && !DEBUG_FAT_LINES && !DEBUG_NO_INTERIOR ) + { + Vertices outline(inner.size()); + for(int i=0; i subs(1); + subs[0] = (int)outline.size(); + + mElement.mPrimType = ptTriangleFan; + mElement.mScaleMode = ssmNormal; + bool isGood = AddPolygon(outline, subs, true); + if (!isGood) + { + // Nibbled off too much and the interior could not be triangulated + // (potentially an issue with cleanCurve too) + // Fallback to normal solid + // In debug mode, predend we rendered it + return DEBUG_NO_FAT_FALLBACK; + } + } + + // Exterior finge + int extra = data.mArray.size() - interiorVertexOffset; + mElement.mVertexOffset += extra; + if (mElement.mTexOffset) + mElement.mTexOffset += extra; + if (mElement.mColourOffset) + mElement.mColourOffset += extra; + + // Add normal flag + mElement.mFlags |= DRAW_HAS_NORMAL; + mElement.mNormalOffset = mElement.mVertexOffset + mElement.mStride; + mElement.mStride += sizeof(float)*2; + + // Right = outer + if (rx &inPath, bool inLoop) + + void pathToCurves(const QuickVec &inPath, bool isClosed, Curves &leftCurve, Curves &rightCurve) { if (inPath.size()<2) return; // Allow shrinking to half the size - float s = mStateScale * 0.5; - if (data.mMinScale==0 || s>data.mMinScale) - data.mMinScale = s; - - // And growing to 1.41 the size ... - s = mStateScale * 1.41; - if (data.mMaxScale==0 || sdata.mMinScale) + data.mMinScale = s; + + // And growing to 1.41 the size ... + s = mStateScale * 1.41; + if (data.mMaxScale==0 || s 1.0 && mJoints==sjRound ) || - ( mPerpLen*mScale >= 0.999 && mJoints==sjMiter); + ( mPerpLen*mScale >= 0.999 && mJoints==sjMiter) || mPolyAA; for(int i=1;i20 && leftCurve.size()<100; + const bool dbgPrt = false; + //printf("Curve %d %d\n", (int)leftCurve.size(), (int)rightCurve.size() ); + if (dbgPrt) + printf("Flags: %04x, vo=%d, no=%d, to=%d, co=%d surf=%p\n", mElement. mFlags, + mElement.mVertexOffset, mElement.mNormalOffset, mElement.mTexOffset, mElement.mColourOffset, + mElement.mSurface ); + + if (DEBUG_FAT_LINES) { if (mElement.mFlags & DRAW_HAS_NORMAL) { + if (dbgPrt) + printf("Remove normal stride\n"); mElement.mFlags &= ~DRAW_HAS_NORMAL; + if (mElement.mTexOffset>mElement.mNormalOffset) + mElement.mTexOffset -= sizeof(float)*2; + if (mElement.mColourOffset>mElement.mNormalOffset) + mElement.mColourOffset -= sizeof(float)*2; + mElement.mNormalOffset = 0; - mElement.mStride -= sizeof(float)*2.0; + mElement.mStride -= sizeof(float)*2; } mElement.mWidth = 1; + mElement.mScaleMode = ssmNone; + } + if (DEBUG_FAT_LINES==1) + { for(int side=0; side<2; side++) { - Curves &curve = side==0 ? leftCurve : rightCurve; + if (dbgPrt) + printf("DBG: %s, voff=%d, stride=%d\n", side==0 ? "leftCurve" : "rightCurve", mElement.mVertexOffset, mElement.mStride); + const Curves &curve = side==0 ? leftCurve : rightCurve; int n = curve.size(); @@ -2570,16 +2686,24 @@ class HardwareBuilder for(int i=0;i=leftCurve.size() || (right1) + if (added++>1) return false; + + stripSize = 1; + prev = *point; + first = *point++; + break; + + case pcWideLineTo: + point++; + case pcLineTo: + { + if (stripSize>0 && *point==prev) + { + point++; + continue; + } + + stripSize++; + + // Implicit loop closing... + if (stripSize>2 && *point==first ) + { + if (added++>1) return false; + stripSize = 0; + } + + prev = *point; + point++; + } + break; + + case pcCurveTo: + { + if (stripSize>0 && *point==prev && point[1]==prev) + { + point+=2; + continue; + } + + stripSize++; + + // Implicit loop closing... + if (stripSize>=2 && point[1]==first) + { + if (added++>1) return false; + stripSize = 0; + } + + prev = point[1]; + point +=2; + } + break; + + + case pcCubicTo: + { + if (stripSize>0 && *point==prev && point[1]==prev && point[2]==prev) + { + point+=3; + continue; + } + + stripSize++; + + // Implicit loop closing... + if (stripSize>=2 && point[2]==first) + { + if (added++>1) return false; + stripSize = 0; + } + + prev = point[2]; + point +=3; + } + break; + + + default: + point += gCommandDataSize[ inCommands[i] ]; + } + } + + if (stripSize>1 && added) + return false; + + return true; + } + + + bool AddLineTriangles(const uint8* inCommands, int inCount, const float *inData) { UserPoint *point = (UserPoint *)inData; @@ -2792,7 +3060,8 @@ class HardwareBuilder if (strip.size()>1) { - AddStrip(strip,false); + if (!AddStrip(strip,false)) + return false; } strip.resize(0); @@ -2816,7 +3085,8 @@ class HardwareBuilder // Implicit loop closing... if (strip.size()>2 && *point==first ) { - AddStrip(strip,true); + if (!AddStrip(strip,true)) + return false; strip.resize(0); } @@ -2838,7 +3108,8 @@ class HardwareBuilder // Implicit loop closing... if (strip.size()>=2 && point[1]==first) { - AddStrip(strip,true); + if (!AddStrip(strip,true)) + return false; strip.resize(0); } @@ -2861,7 +3132,8 @@ class HardwareBuilder // Implicit loop closing... if (strip.size()>=2 && point[2]==first) { - AddStrip(strip,true); + if (!AddStrip(strip,true)) + return false; strip.resize(0); } @@ -2878,8 +3150,15 @@ class HardwareBuilder if (strip.size()>1) { - AddStrip(strip,false); + if (mPolyAA) + { + strip.push_back(Segment(first)); + return AddStrip(strip,true); + } + else + return AddStrip(strip,false); } + return true; } @@ -2898,7 +3177,6 @@ class HardwareBuilder float mTileScaleX; float mTileScaleY; double mCurveThresh2; - double mFatLineCullThresh; Matrix mTextureMapper; StrokeCaps mCaps; StrokeJoints mJoints; diff --git a/project/src/common/Tessellate.cpp b/project/src/common/Tessellate.cpp index 08a416583..85ddff783 100644 --- a/project/src/common/Tessellate.cpp +++ b/project/src/common/Tessellate.cpp @@ -216,7 +216,7 @@ struct ConcaveSet }; -void OutlineToEars(EdgePoint *head, int size, Vertices &outTriangles) +bool OutlineToEars(EdgePoint *head, int size, Vertices &outTriangles) { outTriangles.reserve( outTriangles.size() + (size-2)*3); @@ -234,7 +234,7 @@ void OutlineToEars(EdgePoint *head, int size, Vertices &outTriangles) { p = head = p->next; if (p == p->next) - return; + return true; } else { @@ -331,6 +331,7 @@ void OutlineToEars(EdgePoint *head, int size, Vertices &outTriangles) } } } + return size<3; } @@ -822,7 +823,7 @@ static bool sortLeft(SubInfo *a, SubInfo *b) -void TriangulateSubPolys(SubInfo *outer, QuickVec &holes, Vertices &outTriangles) +bool TriangulateSubPolys(SubInfo *outer, QuickVec &holes, Vertices &outTriangles) { int holeCount = holes.size(); int size = outer->size; @@ -864,6 +865,7 @@ void TriangulateSubPolys(SubInfo *outer, QuickVec &holes, Vertices & } delete poly2Tri; + return true #else if (holeCount) @@ -885,7 +887,7 @@ void TriangulateSubPolys(SubInfo *outer, QuickVec &holes, Vertices & } } EdgePoint *p = outer->first; - OutlineToEars(outer->first, size, outTriangles); + return OutlineToEars(outer->first, size, outTriangles); #endif } @@ -913,14 +915,14 @@ static void dump(const SubInfo &sub) } // Clipper Version -void ConvertOutlineToTriangles(Vertices &ioOutline,const QuickVec &inSubPolys,WindingRule inWinding) +bool ConvertOutlineToTriangles(Vertices &ioOutline,const QuickVec &inSubPolys,WindingRule inWinding) { Vertices triangles; int subs = inSubPolys.size(); int n = ioOutline.size(); if (subs<1 || n<1) - return; + return true; float minX = ioOutline[0].x; float maxX = minX; @@ -935,7 +937,7 @@ void ConvertOutlineToTriangles(Vertices &ioOutline,const QuickVec &inSubPol } float diffX = maxX-minX; float diffY = maxY-minY; - if (diffX==0 || diffY==0) return; + if (diffX==0 || diffY==0) return true; float diff = diffX > diffY ? diffX : diffY; float scale = (float)(0x40000000)/diff; float unscale = 1.0/scale; @@ -965,7 +967,7 @@ void ConvertOutlineToTriangles(Vertices &ioOutline,const QuickVec &inSubPol catch(...) { // Hmmm - return; + return false; } // TODO - winding pftEvenOdd, pftNonZero @@ -1017,6 +1019,7 @@ void ConvertOutlineToTriangles(Vertices &ioOutline,const QuickVec &inSubPol } ioOutline.swap(triangles); + return true; } #else @@ -1030,11 +1033,11 @@ void ConvertOutlineToTriangles(Vertices &ioOutline,const QuickVec &inSubPol #define FUSE_TOL 1e-12 -void ConvertOutlineToTriangles(Vertices &ioOutline,const QuickVec &inSubPolys,WindingRule inWinding) +bool ConvertOutlineToTriangles(Vertices &ioOutline,const QuickVec &inSubPolys,WindingRule inWinding) { #ifdef NME_INTERNAL_CLIPPING if (inSubPolys.size()<1) - return; + return true; QuickVec subPolys(inSubPolys); NmeClipOutline(ioOutline,subPolys,inWinding); #else @@ -1043,7 +1046,7 @@ void ConvertOutlineToTriangles(Vertices &ioOutline,const QuickVec &inSubPol int subs = subPolys.size(); if (subs<1) - return; + return true; Vertices triangles; @@ -1132,6 +1135,7 @@ void ConvertOutlineToTriangles(Vertices &ioOutline,const QuickVec &inSubPol } + bool good = true; for(int group=0;group &inSubPol } if (first>=0) { - TriangulateSubPolys(&subInfo[first], holes, triangles); + if (!TriangulateSubPolys(&subInfo[first], holes, triangles)) + good = false; } } ioOutline.swap(triangles); + return good; } #endif