123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #pragma hdrstop
- #include "../idlib/precompiled.h"
- #include "float.h"
- #pragma warning( disable: 4189 ) // local variable is initialized but not referenced
- /*
- ========================
- idSWFShapeParser::ParseShape
- ========================
- */
- void idSWFShapeParser::Parse( idSWFBitStream & bitstream, idSWFShape & shape, int recordType ) {
- extendedCount = ( recordType > 1 );
- lineStyle2 = ( recordType == 4 );
- rgba = ( recordType >= 3 );
- morph = false;
- bitstream.ReadRect( shape.startBounds );
- shape.endBounds = shape.startBounds;
- if ( recordType == 4 ) {
- swfRect_t edgeBounds;
- bitstream.ReadRect( edgeBounds );
- bitstream.ReadU8(); // flags (that we ignore)
- }
- ReadFillStyle( bitstream );
- ParseShapes( bitstream, NULL, false );
- TriangulateSoup( shape );
- shape.lineDraws.SetNum( lineDraws.Num() );
- for ( int i = 0; i < lineDraws.Num(); i++ ) {
- idSWFShapeDrawLine & ld = shape.lineDraws[i];
- swfSPDrawLine_t & spld = lineDraws[i];
- ld.style = spld.style;
- ld.indices.SetNum( spld.edges.Num() * 3 );
- ld.indices.SetNum( 0 );
- for ( int e = 0; e < spld.edges.Num(); e++ ) {
- int v0 = ld.startVerts.AddUnique( verts[ spld.edges[e].start.v0 ] );
- ld.indices.Append( v0 );
- ld.indices.Append( v0 );
- // Rather then tesselating curves at run time, we do them once here by inserting a vert every 10 units
- // It may not wind up being 10 actual pixels when rendered because the shape may have scaling applied to it
- if ( spld.edges[e].start.cp != 0xFFFF ) {
- assert( spld.edges[e].end.cp != 0xFFFF );
- float length1 = ( verts[ spld.edges[e].start.v0 ] - verts[ spld.edges[e].start.v1 ] ).Length();
- float length2 = ( verts[ spld.edges[e].end.v0 ] - verts[ spld.edges[e].end.v1 ] ).Length();
- int numPoints = 1 + idMath::Ftoi( Max( length1, length2 ) / 10.0f );
- for ( int ti = 0; ti < numPoints; ti++ ) {
- float t0 = ( ti + 1 ) / ( (float) numPoints + 1.0f );
- float t1 = ( 1.0f - t0 );
- float c1 = t1 * t1;
- float c2 = t0 * t1 * 2.0f;
- float c3 = t0 * t0;
- idVec2 p1 = c1 * verts[ spld.edges[e].start.v0 ];
- p1 += c2 * verts[ spld.edges[e].start.cp ];
- p1 += c3 * verts[ spld.edges[e].start.v1 ];
- int v1 = ld.startVerts.AddUnique( p1 );
- ld.indices.Append( v1 );
- ld.indices.Append( v1 );
- ld.indices.Append( v1 );
- }
- }
- ld.indices.Append( ld.startVerts.AddUnique( verts[ spld.edges[e].start.v1 ] ) );
- }
- }
- }
- /*
- ========================
- idSWFShapeParser::ParseMorph
- ========================
- */
- void idSWFShapeParser::ParseMorph( idSWFBitStream & bitstream, idSWFShape & shape ) {
- extendedCount = true;
- lineStyle2 = false;
- rgba = true;
- morph = true;
- bitstream.ReadRect( shape.startBounds );
- bitstream.ReadRect( shape.endBounds );
- uint32 offset = bitstream.ReadU32();
- // offset is the byte offset from the current read position to the 'endShape' record
- // we read the entire block into 'bitstream1' which moves the read pointer of 'bitstream'
- // to the start of the 'endShape' record
- idSWFBitStream bitstream1;
- bitstream1.Load( (byte *)bitstream.ReadData( offset ), offset, false );
- ReadFillStyle( bitstream1 );
- ParseShapes( bitstream1, &bitstream, true );
- TriangulateSoup( shape );
- }
- /*
- ========================
- idSWFShapeParser::ParseFont
- ========================
- */
- void idSWFShapeParser::ParseFont( idSWFBitStream & bitstream, idSWFFontGlyph & shape ) {
- extendedCount = false;
- lineStyle2 = false;
- rgba = false;
- morph = false;
- fillDraws.SetNum( 1 );
- ParseShapes( bitstream, NULL, true );
- TriangulateSoup( shape );
- }
- /*
- ========================
- idSWFShapeParser::ParseShapes
- ========================
- */
- void idSWFShapeParser::ParseShapes( idSWFBitStream & bitstream1, idSWFBitStream * bitstream2, bool swap ) {
- int32 pen1X = 0;
- int32 pen1Y = 0;
- int32 pen2X = 0;
- int32 pen2Y = 0;
- uint8 fillStyle0 = 0;
- uint8 fillStyle1 = 0;
- uint8 lineStyle = 0;
- uint16 baseFillStyle = 0;
- uint16 baseLineStyle = 0;
- uint8 numBits = bitstream1.ReadU8();
- uint8 numFillBits1 = numBits >> 4;
- uint8 numLineBits1 = numBits & 0xF;
- uint8 numFillBits2 = 0;
- uint8 numLineBits2 = 0;
- if ( bitstream2 ) {
- numBits = bitstream2->ReadU8();
- numFillBits2 = numBits >> 4;
- numLineBits2 = numBits & 0xF;
- }
- while ( true ) {
- if ( !bitstream1.ReadBool() ) {
- bool stateNewStyles = bitstream1.ReadBool();
- bool stateLineStyle = bitstream1.ReadBool();
- bool stateFillStyle1 = bitstream1.ReadBool();
- bool stateFillStyle0 = bitstream1.ReadBool();
- bool stateMoveTo = bitstream1.ReadBool();
- if ( ( stateNewStyles || stateLineStyle || stateFillStyle1 || stateFillStyle0 || stateMoveTo ) == false ) {
- // end record
- if ( bitstream2 ) {
- uint8 flags = bitstream2->ReadU( 6 );
- if ( flags != 0 ) {
- idLib::Warning( "idSWFShapeParser: morph stream 1 ends before 2" );
- break;
- }
- }
- break;
- }
- if ( stateMoveTo ) {
- uint8 moveBits = bitstream1.ReadU( 5 );
- pen1X = bitstream1.ReadS( moveBits );
- pen1Y = bitstream1.ReadS( moveBits );
- }
- if ( stateFillStyle0 ) {
- fillStyle0 = bitstream1.ReadU( numFillBits1 );
- }
- if ( stateFillStyle1 ) {
- fillStyle1 = bitstream1.ReadU( numFillBits1 );
- }
- if ( stateLineStyle ) {
- lineStyle = bitstream1.ReadU( numLineBits1 );
- }
- if ( stateNewStyles ) {
- baseFillStyle = fillDraws.Num();
- baseLineStyle = lineDraws.Num();
- ReadFillStyle( bitstream1 );
- numBits = bitstream1.ReadU8();
- numFillBits1 = numBits >> 4;
- numLineBits1 = numBits & 0xF;
- }
- if ( bitstream2 ) {
- bool isEdge = bitstream2->ReadBool();
- if ( isEdge ) {
- idLib::Warning( "idSWFShapeParser: morph stream 1 defines style change, but stream 2 does not" );
- break;
- }
- bool stateNewStyles = bitstream2->ReadBool();
- bool stateLineStyle = bitstream2->ReadBool();
- bool stateFillStyle1 = bitstream2->ReadBool();
- bool stateFillStyle0 = bitstream2->ReadBool();
- bool stateMoveTo = bitstream2->ReadBool();
- if ( stateMoveTo ) {
- uint8 moveBits = bitstream2->ReadU( 5 );
- pen2X = bitstream2->ReadS( moveBits );
- pen2Y = bitstream2->ReadS( moveBits );
- }
- if ( stateFillStyle0 ) {
- if ( bitstream2->ReadU( numFillBits2 ) != fillStyle0 ) {
- idLib::Warning( "idSWFShapeParser: morph stream 2 defined a different fillStyle0 from stream 1" );
- break;
- }
- }
- if ( stateFillStyle1 ) {
- if ( bitstream2->ReadU( numFillBits2 ) != fillStyle1 ) {
- idLib::Warning( "idSWFShapeParser: morph stream 2 defined a different fillStyle1 from stream 1" );
- break;
- }
- }
- if ( stateLineStyle ) {
- if ( bitstream2->ReadU( numLineBits2 ) != lineStyle ) {
- idLib::Warning( "idSWFShapeParser: morph stream 2 defined a different lineStyle from stream 1" );
- break;
- }
- }
- if ( stateNewStyles ) {
- idLib::Warning( "idSWFShapeParser: morph stream 2 defines new styles" );
- break;
- }
- }
- } else {
- swfSPMorphEdge_t morphEdge;
- ParseEdge( bitstream1, pen1X, pen1Y, morphEdge.start );
- if ( bitstream2 ) {
- bool isEdge = bitstream2->ReadBool();
- if ( !isEdge ) {
- idLib::Warning( "idSWFShapeParser: morph stream 1 defines an edge, but stream 2 does not" );
- break;
- }
- ParseEdge( *bitstream2, pen2X, pen2Y, morphEdge.end );
- } else {
- morphEdge.end = morphEdge.start;
- }
- // one edge may be a straight edge, and the other may be a curve
- // in this case, we turn the straight edge into a curve by adding
- // a control point in the middle of the line
- if ( morphEdge.start.cp != 0xFFFF ) {
- if ( morphEdge.end.cp == 0xFFFF ) {
- const idVec2 & v0 = verts[ morphEdge.end.v0 ];
- const idVec2 & v1 = verts[ morphEdge.end.v1 ];
- morphEdge.end.cp = verts.AddUnique( ( v0 + v1 ) * 0.5f );
- }
- } else {
- if ( morphEdge.end.cp != 0xFFFF ) {
- const idVec2 & v0 = verts[ morphEdge.start.v0 ];
- const idVec2 & v1 = verts[ morphEdge.start.v1 ];
- morphEdge.start.cp = verts.AddUnique( ( v0 + v1 ) * 0.5f );
- }
- }
- if ( lineStyle != 0 ) {
- lineDraws[ baseLineStyle + lineStyle - 1 ].edges.Append( morphEdge );
- }
- if ( swap ) {
- SwapValues( morphEdge.start.v0, morphEdge.start.v1 );
- SwapValues( morphEdge.end.v0, morphEdge.end.v1 );
- }
- if ( fillStyle1 != 0 ) {
- fillDraws[ baseFillStyle + fillStyle1 - 1 ].edges.Append( morphEdge );
- }
- if ( fillStyle0 != 0 ) {
- // for fill style 0, we need to reverse the winding
- swfSPMorphEdge_t swapped = morphEdge;
- SwapValues( swapped.start.v0, swapped.start.v1 );
- SwapValues( swapped.end.v0, swapped.end.v1 );
- fillDraws[ baseFillStyle + fillStyle0 - 1 ].edges.Append( swapped );
- }
- }
- }
- }
- /*
- ========================
- idSWFShapeParser::ParseEdge
- ========================
- */
- void idSWFShapeParser::ParseEdge( idSWFBitStream & bitstream, int32 & penX, int32 & penY, swfSPEdge_t & edge ) {
- bool straight = bitstream.ReadBool();
- uint8 numBits = bitstream.ReadU( 4 ) + 2;
- edge.v0 = verts.AddUnique( idVec2( SWFTWIP( penX ), SWFTWIP( penY ) ) );
- if ( straight ) {
- edge.cp = 0xFFFF;
- if ( bitstream.ReadBool() ) {
- penX += bitstream.ReadS( numBits );
- penY += bitstream.ReadS( numBits );
- } else {
- if ( bitstream.ReadBool() ) {
- penY += bitstream.ReadS( numBits );
- } else {
- penX += bitstream.ReadS( numBits );
- }
- }
- } else {
- penX += bitstream.ReadS( numBits );
- penY += bitstream.ReadS( numBits );
- edge.cp = verts.AddUnique( idVec2( SWFTWIP( penX ), SWFTWIP( penY ) ) );
- penX += bitstream.ReadS( numBits );
- penY += bitstream.ReadS( numBits );
- }
- edge.v1 = verts.AddUnique( idVec2( SWFTWIP( penX ), SWFTWIP( penY ) ) );
- }
- /*
- ========================
- idSWFShapeParser::MakeLoops
- ========================
- */
- void idSWFShapeParser::MakeLoops() {
- // At this point, each fill style has an edge soup associated with it
- // We want to turn this soup into loops of connected verts
- for ( int i = 0; i < fillDraws.Num(); i++ ) {
- swfSPDrawFill_t & fill = fillDraws[i];
- // first remove degenerate edges
- for ( int e = 0; e < fill.edges.Num(); e++ ) {
- if ( ( fill.edges[e].start.v0 == fill.edges[e].start.v1 ) || ( fill.edges[e].end.v0 == fill.edges[e].end.v1 ) ) {
- fill.edges.RemoveIndexFast( e );
- e--;
- }
- }
- idList< int > unusedEdges;
- unusedEdges.SetNum( fill.edges.Num() );
- for ( int e = 0; e < fill.edges.Num(); e++ ) {
- unusedEdges[e] = e;
- }
- while ( unusedEdges.Num() > 0 ) {
- swfSPLineLoop_t & loop = fill.loops.Alloc();
- loop.hole = false;
- int e1 = unusedEdges[ unusedEdges.Num() - 1 ];
- unusedEdges.SetNum( unusedEdges.Num() - 1 );
- while ( true ) {
- loop.vindex1.Append( fill.edges[e1].start.v0 );
- loop.vindex2.Append( fill.edges[e1].end.v0 );
- // Rather then tesselating curves at run time, we do them once here by inserting a vert every 10 units
- // It may not wind up being 10 actual pixels when rendered because the shape may have scaling applied to it
- if ( fill.edges[e1].start.cp != 0xFFFF ) {
- assert( fill.edges[e1].end.cp != 0xFFFF );
- float length1 = ( verts[ fill.edges[e1].start.v0 ] - verts[ fill.edges[e1].start.v1 ] ).Length();
- float length2 = ( verts[ fill.edges[e1].end.v0 ] - verts[ fill.edges[e1].end.v1 ] ).Length();
- int numPoints = 1 + idMath::Ftoi( Max( length1, length2 ) / 10.0f );
- for ( int ti = 0; ti < numPoints; ti++ ) {
- float t0 = ( ti + 1 ) / ( (float) numPoints + 1.0f );
- float t1 = ( 1.0f - t0 );
- float c1 = t1 * t1;
- float c2 = t0 * t1 * 2.0f;
- float c3 = t0 * t0;
- idVec2 p1 = c1 * verts[ fill.edges[e1].start.v0 ];
- p1 += c2 * verts[ fill.edges[e1].start.cp ];
- p1 += c3 * verts[ fill.edges[e1].start.v1 ];
- idVec2 p2 = c1 * verts[ fill.edges[e1].end.v0 ];
- p2 += c2 * verts[ fill.edges[e1].end.cp ];
- p2 += c3 * verts[ fill.edges[e1].end.v1 ];
- loop.vindex1.Append( verts.AddUnique( p1 ) );
- loop.vindex2.Append( verts.AddUnique( p2 ) );
- }
- }
- const swfSPEdge_t & edge1 = fill.edges[e1].start;
- float bestNormal = FLT_MAX;
- int beste = -1;
- for ( int e = 0; e < unusedEdges.Num(); e++ ) {
- int e2 = unusedEdges[e];
- const swfSPEdge_t & edge2 = fill.edges[e2].start;
- if ( edge1.v1 != edge2.v0 ) {
- continue;
- }
- assert( edge1.v0 != edge2.v0 );
- assert( edge1.v1 != edge2.v1 );
- const idVec2 & v1 = verts[ edge1.v0 ];
- const idVec2 & v2 = verts[ edge1.v1 ]; // == edge2.v0
- const idVec2 & v3 = verts[ edge2.v1 ];
- idVec2 a = v1 - v2;
- idVec2 b = v3 - v2;
- float normal = ( a.x * b.y - a.y * b.x );
- if ( normal < bestNormal ) {
- bestNormal = normal;
- beste = e;
- } else {
- assert( beste != -1 );
- }
- }
- if ( beste < 0 ) {
- // no more edges connect to this one
- break;
- }
- e1 = unusedEdges[beste];
- unusedEdges.RemoveIndexFast( beste );
- }
- if ( loop.vindex1.Num() < 3 ) {
- idLib::Warning( "idSWFShapeParser: loop with < 3 verts" );
- fill.loops.SetNum( fill.loops.Num() - 1 );
- continue;
- }
- // Use the left most vert to determine if it's a hole or not
- float leftMostX = FLT_MAX;
- int leftMostIndex = 0;
- for ( int j = 0; j < loop.vindex1.Num(); j++ ) {
- idVec2 & v = verts[ loop.vindex1[j] ];
- if ( v.x < leftMostX ) {
- leftMostIndex = j;
- leftMostX = v.x;
- }
- }
- const idVec2 & v1 = verts[ loop.vindex1[(loop.vindex1.Num() + leftMostIndex - 1) % loop.vindex1.Num()] ];
- const idVec2 & v2 = verts[ loop.vindex1[leftMostIndex] ];
- const idVec2 & v3 = verts[ loop.vindex1[(leftMostIndex+1) % loop.vindex1.Num()] ];
- idVec2 a = v1 - v2;
- idVec2 b = v3 - v2;
- float normal = ( a.x * b.y - a.y * b.x );
- loop.hole = ( normal > 0.0f );
- }
- // now we have a series of loops, which define either shapes or holes
- // we want to merge the holes into the shapes by inserting edges
- // this assumes shapes are either completely contained or not
- // we start merging holes starting on the right so nested holes work
- while ( true ) {
- int hole = -1;
- int holeVert = -1;
- float rightMostX = -1e10f;
- for ( int j = 0; j < fill.loops.Num(); j++ ) {
- swfSPLineLoop_t & loop = fill.loops[j];
- if ( !loop.hole ) {
- continue;
- }
- for ( int v = 0; v < loop.vindex1.Num(); v++ ) {
- if ( verts[ loop.vindex1[v] ].x > rightMostX ) {
- hole = j;
- holeVert = v;
- rightMostX = verts[ loop.vindex1[v] ].x;
- }
- }
- }
- if ( hole == -1 ) {
- break;
- }
- swfSPLineLoop_t & loopHole = fill.loops[ hole ];
- const idVec2 & holePoint = verts[ loopHole.vindex1[ holeVert ] ];
- int shape = -1;
- for ( int j = 0; j < fill.loops.Num(); j++ ) {
- swfSPLineLoop_t & loop = fill.loops[j];
- if ( loop.hole ) {
- continue;
- }
- bool inside = false;
- for ( int k = 0; k < loop.vindex1.Num(); k++ ) {
- const idVec2 & v1 = verts[ loop.vindex1[k] ];
- const idVec2 & v2 = verts[ loop.vindex1[(k + 1) % loop.vindex1.Num()] ];
- if ( v1.x < holePoint.x && v2.x < holePoint.x ) {
- continue; // both on the left of the holePoint
- }
- if ( ( v1.y < holePoint.y ) == ( v2.y < holePoint.y ) ) {
- continue; // both on the same side of the horizon
- }
- assert( v1 != holePoint );
- assert( v2 != holePoint );
- inside = !inside;
- }
- if ( inside ) {
- shape = j;
- break;
- }
- }
- if ( shape == -1 ) {
- idLib::Warning( "idSWFShapeParser: Hole not in a shape" );
- fill.loops.RemoveIndexFast( hole );
- continue;
- }
- swfSPLineLoop_t & loopShape = fill.loops[ shape ];
- // now that we have a hole and the shape it's inside, merge the two together
- // find the nearest vert that's on the right side of holePoint
- float bestDist = 1e10f;
- int shapeVert = -1;
- for ( int j = 0; j < loopShape.vindex1.Num(); j++ ) {
- const idVec2 & v1 = verts[ loopShape.vindex1[j] ];
- if ( v1.x < holePoint.x ) {
- continue; // on the left of the holePoint
- }
- float dist = ( v1 - holePoint ).Length();
- if ( dist < bestDist ) {
- shapeVert = j;
- bestDist = dist;
- }
- }
- // connect holeVert to shapeVert
- idList< uint16 > vindex;
- vindex.SetNum( loopShape.vindex1.Num() + loopHole.vindex1.Num() + 1 );
- vindex.SetNum( 0 );
- for ( int j = 0; j <= shapeVert; j++ ) {
- vindex.Append( loopShape.vindex1[j] );
- }
- for ( int j = holeVert; j < loopHole.vindex1.Num(); j++ ) {
- vindex.Append( loopHole.vindex1[j] );
- }
- for ( int j = 0; j <= holeVert; j++ ) {
- vindex.Append( loopHole.vindex1[j] );
- }
- for ( int j = shapeVert; j < loopShape.vindex1.Num(); j++ ) {
- vindex.Append( loopShape.vindex1[j] );
- }
- loopShape.vindex1 = vindex;
- vindex.Clear();
- for ( int j = 0; j <= shapeVert; j++ ) {
- vindex.Append( loopShape.vindex2[j] );
- }
- for ( int j = holeVert; j < loopHole.vindex2.Num(); j++ ) {
- vindex.Append( loopHole.vindex2[j] );
- }
- for ( int j = 0; j <= holeVert; j++ ) {
- vindex.Append( loopHole.vindex2[j] );
- }
- for ( int j = shapeVert; j < loopShape.vindex2.Num(); j++ ) {
- vindex.Append( loopShape.vindex2[j] );
- }
- loopShape.vindex2 = vindex;
- fill.loops.RemoveIndexFast( hole );
- }
- }
- }
- /*
- ========================
- idSWFShapeParser::TriangulateSoup
- ========================
- */
- void idSWFShapeParser::TriangulateSoup( idSWFShape & shape ) {
- MakeLoops();
- // Now turn the (potentially) concave line loops into triangles by using ear clipping
- shape.fillDraws.SetNum( fillDraws.Num() );
- for ( int i = 0; i < fillDraws.Num(); i++ ) {
- swfSPDrawFill_t & spDrawFill = fillDraws[i];
- idSWFShapeDrawFill & drawFill = shape.fillDraws[i];
- swfFillStyle_t & style = spDrawFill.style;
- drawFill.style = spDrawFill.style;
- for ( int j = 0; j < spDrawFill.loops.Num(); j++ ) {
- swfSPLineLoop_t & loop = spDrawFill.loops[j];
- int numVerts = loop.vindex1.Num();
- for ( int k = 0; k < numVerts - 2; k++ ) {
- int v1 = FindEarVert( loop );
- if ( v1 == -1 ) {
- idLib::Warning( "idSWFShapeParser: could not find an ear vert" );
- break;
- }
- int num = loop.vindex1.Num();
- int v2 = ( v1 + 1 ) % num;
- int v3 = ( v1 + 2 ) % num;
- AddUniqueVert( drawFill, verts[ loop.vindex1[ v1 ] ], verts[ loop.vindex2[ v1 ] ] );
- AddUniqueVert( drawFill, verts[ loop.vindex1[ v2 ] ], verts[ loop.vindex2[ v2 ] ] );
- AddUniqueVert( drawFill, verts[ loop.vindex1[ v3 ] ], verts[ loop.vindex2[ v3 ] ] );
- loop.vindex1.RemoveIndex( v2 );
- loop.vindex2.RemoveIndex( v2 );
- }
- }
- }
- }
- /*
- ========================
- idSWFShapeParser::TriangulateSoup
- ========================
- */
- void idSWFShapeParser::TriangulateSoup( idSWFFontGlyph & shape ) {
- MakeLoops();
- // Now turn the (potentially) concave line loops into triangles by using ear clipping
- assert( fillDraws.Num() == 1 );
- swfSPDrawFill_t & spDrawFill = fillDraws[0];
- for ( int j = 0; j < spDrawFill.loops.Num(); j++ ) {
- swfSPLineLoop_t & loop = spDrawFill.loops[j];
- int numVerts = loop.vindex1.Num();
- for ( int k = 0; k < numVerts - 2; k++ ) {
- int v1 = FindEarVert( loop );
- if ( v1 == -1 ) {
- idLib::Warning( "idSWFShapeParser: could not find an ear vert" );
- break;
- }
- int num = loop.vindex1.Num();
- int v2 = ( v1 + 1 ) % num;
- int v3 = ( v1 + 2 ) % num;
- shape.indices.Append( shape.verts.AddUnique( verts[ loop.vindex1[ v1 ] ] ) );
- shape.indices.Append( shape.verts.AddUnique( verts[ loop.vindex1[ v2 ] ] ) );
- shape.indices.Append( shape.verts.AddUnique( verts[ loop.vindex1[ v3 ] ] ) );
- loop.vindex1.RemoveIndex( v2 );
- loop.vindex2.RemoveIndex( v2 );
- }
- }
- }
- struct earVert_t {
- int i1;
- int i2;
- int i3;
- float cross;
- };
- class idSort_Ears : public idSort_Quick< earVert_t, idSort_Ears > {
- public:
- int Compare( const earVert_t & a, const earVert_t & b ) const {
- if ( a.cross < b.cross ) {
- return -1;
- } else if ( a.cross > b.cross ) {
- return 1;
- }
- return 0;
- }
- };
- /*
- ========================
- idSWFShapeParser::FindEarVert
- ========================
- */
- int idSWFShapeParser::FindEarVert( const swfSPLineLoop_t & loop ) {
- assert( loop.vindex1.Num() == loop.vindex2.Num() );
- int num = loop.vindex1.Num();
- idList<earVert_t> ears;
- ears.SetNum( num );
- for ( int i1 = 0; i1 < num; i1++ ) {
- int i2 = ( i1 + 1 ) % num;
- int i3 = ( i1 + 2 ) % num;
- const idVec2 & v1s = verts[ loop.vindex1[ i1 ] ];
- const idVec2 & v2s = verts[ loop.vindex1[ i2 ] ];
- const idVec2 & v3s = verts[ loop.vindex1[ i3 ] ];
- idVec2 a = v1s - v2s;
- idVec2 b = v2s - v3s;
- ears[i1].cross = a.x * b.y - a.y * b.x;
- ears[i1].i1 = i1;
- ears[i1].i2 = i2;
- ears[i1].i3 = i3;
- }
- ears.SortWithTemplate( idSort_Ears() );
- for ( int i = 0; i < ears.Num(); i++ ) {
- if ( ears[i].cross < 0.0f ) {
- continue;
- }
- int i1 = ears[i].i1;
- int i2 = ears[i].i2;
- int i3 = ears[i].i3;
- const idVec2 & v1s = verts[ loop.vindex1[ i1 ] ];
- const idVec2 & v2s = verts[ loop.vindex1[ i2 ] ];
- const idVec2 & v3s = verts[ loop.vindex1[ i3 ] ];
- const idVec2 & v1e = verts[ loop.vindex2[ i1 ] ];
- const idVec2 & v2e = verts[ loop.vindex2[ i2 ] ];
- const idVec2 & v3e = verts[ loop.vindex2[ i3 ] ];
- idMat3 edgeEquations1;
- edgeEquations1[0].Set( v1s.x, v1s.y, 1.0f );
- edgeEquations1[1].Set( v2s.x, v2s.y, 1.0f );
- edgeEquations1[2].Set( v3s.x, v3s.y, 1.0f );
- idMat3 edgeEquations2;
- edgeEquations2[0].Set( v1e.x, v1e.y, 1.0f );
- edgeEquations2[1].Set( v2e.x, v2e.y, 1.0f );
- edgeEquations2[2].Set( v3e.x, v3e.y, 1.0f );
- edgeEquations1.InverseSelf();
- edgeEquations2.InverseSelf();
- bool isEar = true;
- for ( int j = 0; j < num; j++ ) {
- if ( j == i1 || j == i2 || j == i3 ) {
- continue;
- }
- idVec3 p1;
- p1.ToVec2() = verts[ loop.vindex1[j] ];
- p1.z = 1.0f;
- idVec3 signs1 = p1 * edgeEquations1;
- bool b1x = signs1.x > 0;
- bool b1y = signs1.y > 0;
- bool b1z = signs1.z > 0;
- if ( b1x == b1y && b1x == b1z ) {
- // point inside
- isEar = false;
- break;
- }
- idVec3 p2;
- p2.ToVec2() = verts[ loop.vindex2[j] ];
- p2.z = 1.0f;
- idVec3 signs2 = p2 * edgeEquations2;
- bool b2x = signs2.x > 0;
- bool b2y = signs2.y > 0;
- bool b2z = signs2.z > 0;
- if ( b2x == b2y && b2x == b2z ) {
- // point inside
- isEar = false;
- break;
- }
- }
- if ( isEar ) {
- return i1;
- }
- }
- return -1;
- }
- /*
- ========================
- idSWFShapeParser::AddUniqueVert
- ========================
- */
- void idSWFShapeParser::AddUniqueVert( idSWFShapeDrawFill & drawFill, const idVec2 & start, const idVec2 & end ) {
- if ( morph ) {
- for ( int i = 0; i < drawFill.startVerts.Num(); i++ ) {
- if ( drawFill.startVerts[i] == start && drawFill.endVerts[i] == end ) {
- drawFill.indices.Append( i );
- return;
- }
- }
- int index1 = drawFill.startVerts.Append( start );
- int index2 = drawFill.endVerts.Append( end );
- assert( index1 == index2 );
- drawFill.indices.Append( index1 );
- } else {
- drawFill.indices.Append( drawFill.startVerts.AddUnique( start ) );
- }
- }
- /*
- ========================
- idSWFShapeParser::ReadFillStyle
- ========================
- */
- void idSWFShapeParser::ReadFillStyle( idSWFBitStream & bitstream ) {
- uint16 fillStyleCount = bitstream.ReadU8();
- if ( extendedCount && fillStyleCount == 0xFF ) {
- fillStyleCount = bitstream.ReadU16();
- }
- for ( int i = 0; i < fillStyleCount; i++ ) {
- uint8 fillStyleType = bitstream.ReadU8();
- swfFillStyle_t & fillStyle = fillDraws.Alloc().style;
- fillStyle.type = fillStyleType >> 4;
- fillStyle.subType = fillStyleType & 0xF;
- if ( fillStyle.type == 0 ) {
- if ( morph ) {
- bitstream.ReadColorRGBA( fillStyle.startColor );
- bitstream.ReadColorRGBA( fillStyle.endColor );
- } else {
- if ( rgba ) {
- bitstream.ReadColorRGBA( fillStyle.startColor );
- } else {
- bitstream.ReadColorRGB( fillStyle.startColor );
- }
- fillStyle.endColor = fillStyle.startColor;
- }
- } else if ( fillStyle.type == 1 ) {
- bitstream.ReadMatrix( fillStyle.startMatrix );
- if ( morph ) {
- bitstream.ReadMatrix( fillStyle.endMatrix );
- bitstream.ReadMorphGradient( fillStyle.gradient );
- } else {
- fillStyle.endMatrix = fillStyle.startMatrix;
- bitstream.ReadGradient( fillStyle.gradient, rgba );
- }
- if ( fillStyle.subType == 3 ) {
- assert( morph == false ); // focal gradients aren't allowed in morph shapes
- fillStyle.focalPoint = bitstream.ReadFixed8();
- }
- } else if ( fillStyle.type == 4 ) {
- fillStyle.bitmapID = bitstream.ReadU16();
- bitstream.ReadMatrix( fillStyle.startMatrix );
- if ( morph ) {
- bitstream.ReadMatrix( fillStyle.endMatrix );
- } else {
- fillStyle.endMatrix = fillStyle.startMatrix;
- }
- }
- }
- uint16 lineStyleCount = bitstream.ReadU8();
- if ( extendedCount && lineStyleCount == 0xFF ) {
- lineStyleCount = bitstream.ReadU16();
- }
- lineDraws.SetNum( lineDraws.Num() + lineStyleCount );
- lineDraws.SetNum( 0 );
- for ( int i = 0; i < lineStyleCount; i++ ) {
- swfLineStyle_t & lineStyle = lineDraws.Alloc().style;
- lineStyle.startWidth = bitstream.ReadU16();
- if ( lineStyle2 ) {
- lineStyle.endWidth = lineStyle.startWidth;
- uint8 startCapStyle = bitstream.ReadU( 2 );
- uint8 joinStyle = bitstream.ReadU( 2 );
- bool hasFillFlag = bitstream.ReadBool();
- bool noHScaleFlag = bitstream.ReadBool();
- bool noVScaleFlag = bitstream.ReadBool();
- bool pixelHintingFlag = bitstream.ReadBool();
- uint8 reserved = bitstream.ReadU( 5 );
- bool noClose = bitstream.ReadBool();
- uint8 endCapStyle = bitstream.ReadU( 2 );
- if ( joinStyle == 2 ) {
- uint16 miterLimitFactor = bitstream.ReadU16();
- }
- if ( hasFillFlag ) {
- // FIXME: read fill style
- idLib::Warning( "idSWFShapeParser: Ignoring hasFillFlag" );
- } else {
- bitstream.ReadColorRGBA( lineStyle.startColor );
- lineStyle.endColor = lineStyle.startColor;
- }
- } else {
- if ( morph ) {
- lineStyle.endWidth = bitstream.ReadU16();
- } else {
- lineStyle.endWidth = lineStyle.startWidth;
- }
- if ( rgba ) {
- bitstream.ReadColorRGBA( lineStyle.startColor );
- } else {
- bitstream.ReadColorRGB( lineStyle.startColor );
- }
- if ( morph ) {
- bitstream.ReadColorRGBA( lineStyle.endColor );
- } else {
- lineStyle.endColor = lineStyle.startColor;
- }
- }
- }
- }
|