SWF_ShapeParser.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. 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.
  17. 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.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. #include "float.h"
  23. #pragma warning( disable: 4189 ) // local variable is initialized but not referenced
  24. /*
  25. ========================
  26. idSWFShapeParser::ParseShape
  27. ========================
  28. */
  29. void idSWFShapeParser::Parse( idSWFBitStream & bitstream, idSWFShape & shape, int recordType ) {
  30. extendedCount = ( recordType > 1 );
  31. lineStyle2 = ( recordType == 4 );
  32. rgba = ( recordType >= 3 );
  33. morph = false;
  34. bitstream.ReadRect( shape.startBounds );
  35. shape.endBounds = shape.startBounds;
  36. if ( recordType == 4 ) {
  37. swfRect_t edgeBounds;
  38. bitstream.ReadRect( edgeBounds );
  39. bitstream.ReadU8(); // flags (that we ignore)
  40. }
  41. ReadFillStyle( bitstream );
  42. ParseShapes( bitstream, NULL, false );
  43. TriangulateSoup( shape );
  44. shape.lineDraws.SetNum( lineDraws.Num() );
  45. for ( int i = 0; i < lineDraws.Num(); i++ ) {
  46. idSWFShapeDrawLine & ld = shape.lineDraws[i];
  47. swfSPDrawLine_t & spld = lineDraws[i];
  48. ld.style = spld.style;
  49. ld.indices.SetNum( spld.edges.Num() * 3 );
  50. ld.indices.SetNum( 0 );
  51. for ( int e = 0; e < spld.edges.Num(); e++ ) {
  52. int v0 = ld.startVerts.AddUnique( verts[ spld.edges[e].start.v0 ] );
  53. ld.indices.Append( v0 );
  54. ld.indices.Append( v0 );
  55. // Rather then tesselating curves at run time, we do them once here by inserting a vert every 10 units
  56. // It may not wind up being 10 actual pixels when rendered because the shape may have scaling applied to it
  57. if ( spld.edges[e].start.cp != 0xFFFF ) {
  58. assert( spld.edges[e].end.cp != 0xFFFF );
  59. float length1 = ( verts[ spld.edges[e].start.v0 ] - verts[ spld.edges[e].start.v1 ] ).Length();
  60. float length2 = ( verts[ spld.edges[e].end.v0 ] - verts[ spld.edges[e].end.v1 ] ).Length();
  61. int numPoints = 1 + idMath::Ftoi( Max( length1, length2 ) / 10.0f );
  62. for ( int ti = 0; ti < numPoints; ti++ ) {
  63. float t0 = ( ti + 1 ) / ( (float) numPoints + 1.0f );
  64. float t1 = ( 1.0f - t0 );
  65. float c1 = t1 * t1;
  66. float c2 = t0 * t1 * 2.0f;
  67. float c3 = t0 * t0;
  68. idVec2 p1 = c1 * verts[ spld.edges[e].start.v0 ];
  69. p1 += c2 * verts[ spld.edges[e].start.cp ];
  70. p1 += c3 * verts[ spld.edges[e].start.v1 ];
  71. int v1 = ld.startVerts.AddUnique( p1 );
  72. ld.indices.Append( v1 );
  73. ld.indices.Append( v1 );
  74. ld.indices.Append( v1 );
  75. }
  76. }
  77. ld.indices.Append( ld.startVerts.AddUnique( verts[ spld.edges[e].start.v1 ] ) );
  78. }
  79. }
  80. }
  81. /*
  82. ========================
  83. idSWFShapeParser::ParseMorph
  84. ========================
  85. */
  86. void idSWFShapeParser::ParseMorph( idSWFBitStream & bitstream, idSWFShape & shape ) {
  87. extendedCount = true;
  88. lineStyle2 = false;
  89. rgba = true;
  90. morph = true;
  91. bitstream.ReadRect( shape.startBounds );
  92. bitstream.ReadRect( shape.endBounds );
  93. uint32 offset = bitstream.ReadU32();
  94. // offset is the byte offset from the current read position to the 'endShape' record
  95. // we read the entire block into 'bitstream1' which moves the read pointer of 'bitstream'
  96. // to the start of the 'endShape' record
  97. idSWFBitStream bitstream1;
  98. bitstream1.Load( (byte *)bitstream.ReadData( offset ), offset, false );
  99. ReadFillStyle( bitstream1 );
  100. ParseShapes( bitstream1, &bitstream, true );
  101. TriangulateSoup( shape );
  102. }
  103. /*
  104. ========================
  105. idSWFShapeParser::ParseFont
  106. ========================
  107. */
  108. void idSWFShapeParser::ParseFont( idSWFBitStream & bitstream, idSWFFontGlyph & shape ) {
  109. extendedCount = false;
  110. lineStyle2 = false;
  111. rgba = false;
  112. morph = false;
  113. fillDraws.SetNum( 1 );
  114. ParseShapes( bitstream, NULL, true );
  115. TriangulateSoup( shape );
  116. }
  117. /*
  118. ========================
  119. idSWFShapeParser::ParseShapes
  120. ========================
  121. */
  122. void idSWFShapeParser::ParseShapes( idSWFBitStream & bitstream1, idSWFBitStream * bitstream2, bool swap ) {
  123. int32 pen1X = 0;
  124. int32 pen1Y = 0;
  125. int32 pen2X = 0;
  126. int32 pen2Y = 0;
  127. uint8 fillStyle0 = 0;
  128. uint8 fillStyle1 = 0;
  129. uint8 lineStyle = 0;
  130. uint16 baseFillStyle = 0;
  131. uint16 baseLineStyle = 0;
  132. uint8 numBits = bitstream1.ReadU8();
  133. uint8 numFillBits1 = numBits >> 4;
  134. uint8 numLineBits1 = numBits & 0xF;
  135. uint8 numFillBits2 = 0;
  136. uint8 numLineBits2 = 0;
  137. if ( bitstream2 ) {
  138. numBits = bitstream2->ReadU8();
  139. numFillBits2 = numBits >> 4;
  140. numLineBits2 = numBits & 0xF;
  141. }
  142. while ( true ) {
  143. if ( !bitstream1.ReadBool() ) {
  144. bool stateNewStyles = bitstream1.ReadBool();
  145. bool stateLineStyle = bitstream1.ReadBool();
  146. bool stateFillStyle1 = bitstream1.ReadBool();
  147. bool stateFillStyle0 = bitstream1.ReadBool();
  148. bool stateMoveTo = bitstream1.ReadBool();
  149. if ( ( stateNewStyles || stateLineStyle || stateFillStyle1 || stateFillStyle0 || stateMoveTo ) == false ) {
  150. // end record
  151. if ( bitstream2 ) {
  152. uint8 flags = bitstream2->ReadU( 6 );
  153. if ( flags != 0 ) {
  154. idLib::Warning( "idSWFShapeParser: morph stream 1 ends before 2" );
  155. break;
  156. }
  157. }
  158. break;
  159. }
  160. if ( stateMoveTo ) {
  161. uint8 moveBits = bitstream1.ReadU( 5 );
  162. pen1X = bitstream1.ReadS( moveBits );
  163. pen1Y = bitstream1.ReadS( moveBits );
  164. }
  165. if ( stateFillStyle0 ) {
  166. fillStyle0 = bitstream1.ReadU( numFillBits1 );
  167. }
  168. if ( stateFillStyle1 ) {
  169. fillStyle1 = bitstream1.ReadU( numFillBits1 );
  170. }
  171. if ( stateLineStyle ) {
  172. lineStyle = bitstream1.ReadU( numLineBits1 );
  173. }
  174. if ( stateNewStyles ) {
  175. baseFillStyle = fillDraws.Num();
  176. baseLineStyle = lineDraws.Num();
  177. ReadFillStyle( bitstream1 );
  178. numBits = bitstream1.ReadU8();
  179. numFillBits1 = numBits >> 4;
  180. numLineBits1 = numBits & 0xF;
  181. }
  182. if ( bitstream2 ) {
  183. bool isEdge = bitstream2->ReadBool();
  184. if ( isEdge ) {
  185. idLib::Warning( "idSWFShapeParser: morph stream 1 defines style change, but stream 2 does not" );
  186. break;
  187. }
  188. bool stateNewStyles = bitstream2->ReadBool();
  189. bool stateLineStyle = bitstream2->ReadBool();
  190. bool stateFillStyle1 = bitstream2->ReadBool();
  191. bool stateFillStyle0 = bitstream2->ReadBool();
  192. bool stateMoveTo = bitstream2->ReadBool();
  193. if ( stateMoveTo ) {
  194. uint8 moveBits = bitstream2->ReadU( 5 );
  195. pen2X = bitstream2->ReadS( moveBits );
  196. pen2Y = bitstream2->ReadS( moveBits );
  197. }
  198. if ( stateFillStyle0 ) {
  199. if ( bitstream2->ReadU( numFillBits2 ) != fillStyle0 ) {
  200. idLib::Warning( "idSWFShapeParser: morph stream 2 defined a different fillStyle0 from stream 1" );
  201. break;
  202. }
  203. }
  204. if ( stateFillStyle1 ) {
  205. if ( bitstream2->ReadU( numFillBits2 ) != fillStyle1 ) {
  206. idLib::Warning( "idSWFShapeParser: morph stream 2 defined a different fillStyle1 from stream 1" );
  207. break;
  208. }
  209. }
  210. if ( stateLineStyle ) {
  211. if ( bitstream2->ReadU( numLineBits2 ) != lineStyle ) {
  212. idLib::Warning( "idSWFShapeParser: morph stream 2 defined a different lineStyle from stream 1" );
  213. break;
  214. }
  215. }
  216. if ( stateNewStyles ) {
  217. idLib::Warning( "idSWFShapeParser: morph stream 2 defines new styles" );
  218. break;
  219. }
  220. }
  221. } else {
  222. swfSPMorphEdge_t morphEdge;
  223. ParseEdge( bitstream1, pen1X, pen1Y, morphEdge.start );
  224. if ( bitstream2 ) {
  225. bool isEdge = bitstream2->ReadBool();
  226. if ( !isEdge ) {
  227. idLib::Warning( "idSWFShapeParser: morph stream 1 defines an edge, but stream 2 does not" );
  228. break;
  229. }
  230. ParseEdge( *bitstream2, pen2X, pen2Y, morphEdge.end );
  231. } else {
  232. morphEdge.end = morphEdge.start;
  233. }
  234. // one edge may be a straight edge, and the other may be a curve
  235. // in this case, we turn the straight edge into a curve by adding
  236. // a control point in the middle of the line
  237. if ( morphEdge.start.cp != 0xFFFF ) {
  238. if ( morphEdge.end.cp == 0xFFFF ) {
  239. const idVec2 & v0 = verts[ morphEdge.end.v0 ];
  240. const idVec2 & v1 = verts[ morphEdge.end.v1 ];
  241. morphEdge.end.cp = verts.AddUnique( ( v0 + v1 ) * 0.5f );
  242. }
  243. } else {
  244. if ( morphEdge.end.cp != 0xFFFF ) {
  245. const idVec2 & v0 = verts[ morphEdge.start.v0 ];
  246. const idVec2 & v1 = verts[ morphEdge.start.v1 ];
  247. morphEdge.start.cp = verts.AddUnique( ( v0 + v1 ) * 0.5f );
  248. }
  249. }
  250. if ( lineStyle != 0 ) {
  251. lineDraws[ baseLineStyle + lineStyle - 1 ].edges.Append( morphEdge );
  252. }
  253. if ( swap ) {
  254. SwapValues( morphEdge.start.v0, morphEdge.start.v1 );
  255. SwapValues( morphEdge.end.v0, morphEdge.end.v1 );
  256. }
  257. if ( fillStyle1 != 0 ) {
  258. fillDraws[ baseFillStyle + fillStyle1 - 1 ].edges.Append( morphEdge );
  259. }
  260. if ( fillStyle0 != 0 ) {
  261. // for fill style 0, we need to reverse the winding
  262. swfSPMorphEdge_t swapped = morphEdge;
  263. SwapValues( swapped.start.v0, swapped.start.v1 );
  264. SwapValues( swapped.end.v0, swapped.end.v1 );
  265. fillDraws[ baseFillStyle + fillStyle0 - 1 ].edges.Append( swapped );
  266. }
  267. }
  268. }
  269. }
  270. /*
  271. ========================
  272. idSWFShapeParser::ParseEdge
  273. ========================
  274. */
  275. void idSWFShapeParser::ParseEdge( idSWFBitStream & bitstream, int32 & penX, int32 & penY, swfSPEdge_t & edge ) {
  276. bool straight = bitstream.ReadBool();
  277. uint8 numBits = bitstream.ReadU( 4 ) + 2;
  278. edge.v0 = verts.AddUnique( idVec2( SWFTWIP( penX ), SWFTWIP( penY ) ) );
  279. if ( straight ) {
  280. edge.cp = 0xFFFF;
  281. if ( bitstream.ReadBool() ) {
  282. penX += bitstream.ReadS( numBits );
  283. penY += bitstream.ReadS( numBits );
  284. } else {
  285. if ( bitstream.ReadBool() ) {
  286. penY += bitstream.ReadS( numBits );
  287. } else {
  288. penX += bitstream.ReadS( numBits );
  289. }
  290. }
  291. } else {
  292. penX += bitstream.ReadS( numBits );
  293. penY += bitstream.ReadS( numBits );
  294. edge.cp = verts.AddUnique( idVec2( SWFTWIP( penX ), SWFTWIP( penY ) ) );
  295. penX += bitstream.ReadS( numBits );
  296. penY += bitstream.ReadS( numBits );
  297. }
  298. edge.v1 = verts.AddUnique( idVec2( SWFTWIP( penX ), SWFTWIP( penY ) ) );
  299. }
  300. /*
  301. ========================
  302. idSWFShapeParser::MakeLoops
  303. ========================
  304. */
  305. void idSWFShapeParser::MakeLoops() {
  306. // At this point, each fill style has an edge soup associated with it
  307. // We want to turn this soup into loops of connected verts
  308. for ( int i = 0; i < fillDraws.Num(); i++ ) {
  309. swfSPDrawFill_t & fill = fillDraws[i];
  310. // first remove degenerate edges
  311. for ( int e = 0; e < fill.edges.Num(); e++ ) {
  312. if ( ( fill.edges[e].start.v0 == fill.edges[e].start.v1 ) || ( fill.edges[e].end.v0 == fill.edges[e].end.v1 ) ) {
  313. fill.edges.RemoveIndexFast( e );
  314. e--;
  315. }
  316. }
  317. idList< int > unusedEdges;
  318. unusedEdges.SetNum( fill.edges.Num() );
  319. for ( int e = 0; e < fill.edges.Num(); e++ ) {
  320. unusedEdges[e] = e;
  321. }
  322. while ( unusedEdges.Num() > 0 ) {
  323. swfSPLineLoop_t & loop = fill.loops.Alloc();
  324. loop.hole = false;
  325. int e1 = unusedEdges[ unusedEdges.Num() - 1 ];
  326. unusedEdges.SetNum( unusedEdges.Num() - 1 );
  327. while ( true ) {
  328. loop.vindex1.Append( fill.edges[e1].start.v0 );
  329. loop.vindex2.Append( fill.edges[e1].end.v0 );
  330. // Rather then tesselating curves at run time, we do them once here by inserting a vert every 10 units
  331. // It may not wind up being 10 actual pixels when rendered because the shape may have scaling applied to it
  332. if ( fill.edges[e1].start.cp != 0xFFFF ) {
  333. assert( fill.edges[e1].end.cp != 0xFFFF );
  334. float length1 = ( verts[ fill.edges[e1].start.v0 ] - verts[ fill.edges[e1].start.v1 ] ).Length();
  335. float length2 = ( verts[ fill.edges[e1].end.v0 ] - verts[ fill.edges[e1].end.v1 ] ).Length();
  336. int numPoints = 1 + idMath::Ftoi( Max( length1, length2 ) / 10.0f );
  337. for ( int ti = 0; ti < numPoints; ti++ ) {
  338. float t0 = ( ti + 1 ) / ( (float) numPoints + 1.0f );
  339. float t1 = ( 1.0f - t0 );
  340. float c1 = t1 * t1;
  341. float c2 = t0 * t1 * 2.0f;
  342. float c3 = t0 * t0;
  343. idVec2 p1 = c1 * verts[ fill.edges[e1].start.v0 ];
  344. p1 += c2 * verts[ fill.edges[e1].start.cp ];
  345. p1 += c3 * verts[ fill.edges[e1].start.v1 ];
  346. idVec2 p2 = c1 * verts[ fill.edges[e1].end.v0 ];
  347. p2 += c2 * verts[ fill.edges[e1].end.cp ];
  348. p2 += c3 * verts[ fill.edges[e1].end.v1 ];
  349. loop.vindex1.Append( verts.AddUnique( p1 ) );
  350. loop.vindex2.Append( verts.AddUnique( p2 ) );
  351. }
  352. }
  353. const swfSPEdge_t & edge1 = fill.edges[e1].start;
  354. float bestNormal = FLT_MAX;
  355. int beste = -1;
  356. for ( int e = 0; e < unusedEdges.Num(); e++ ) {
  357. int e2 = unusedEdges[e];
  358. const swfSPEdge_t & edge2 = fill.edges[e2].start;
  359. if ( edge1.v1 != edge2.v0 ) {
  360. continue;
  361. }
  362. assert( edge1.v0 != edge2.v0 );
  363. assert( edge1.v1 != edge2.v1 );
  364. const idVec2 & v1 = verts[ edge1.v0 ];
  365. const idVec2 & v2 = verts[ edge1.v1 ]; // == edge2.v0
  366. const idVec2 & v3 = verts[ edge2.v1 ];
  367. idVec2 a = v1 - v2;
  368. idVec2 b = v3 - v2;
  369. float normal = ( a.x * b.y - a.y * b.x );
  370. if ( normal < bestNormal ) {
  371. bestNormal = normal;
  372. beste = e;
  373. } else {
  374. assert( beste != -1 );
  375. }
  376. }
  377. if ( beste < 0 ) {
  378. // no more edges connect to this one
  379. break;
  380. }
  381. e1 = unusedEdges[beste];
  382. unusedEdges.RemoveIndexFast( beste );
  383. }
  384. if ( loop.vindex1.Num() < 3 ) {
  385. idLib::Warning( "idSWFShapeParser: loop with < 3 verts" );
  386. fill.loops.SetNum( fill.loops.Num() - 1 );
  387. continue;
  388. }
  389. // Use the left most vert to determine if it's a hole or not
  390. float leftMostX = FLT_MAX;
  391. int leftMostIndex = 0;
  392. for ( int j = 0; j < loop.vindex1.Num(); j++ ) {
  393. idVec2 & v = verts[ loop.vindex1[j] ];
  394. if ( v.x < leftMostX ) {
  395. leftMostIndex = j;
  396. leftMostX = v.x;
  397. }
  398. }
  399. const idVec2 & v1 = verts[ loop.vindex1[(loop.vindex1.Num() + leftMostIndex - 1) % loop.vindex1.Num()] ];
  400. const idVec2 & v2 = verts[ loop.vindex1[leftMostIndex] ];
  401. const idVec2 & v3 = verts[ loop.vindex1[(leftMostIndex+1) % loop.vindex1.Num()] ];
  402. idVec2 a = v1 - v2;
  403. idVec2 b = v3 - v2;
  404. float normal = ( a.x * b.y - a.y * b.x );
  405. loop.hole = ( normal > 0.0f );
  406. }
  407. // now we have a series of loops, which define either shapes or holes
  408. // we want to merge the holes into the shapes by inserting edges
  409. // this assumes shapes are either completely contained or not
  410. // we start merging holes starting on the right so nested holes work
  411. while ( true ) {
  412. int hole = -1;
  413. int holeVert = -1;
  414. float rightMostX = -1e10f;
  415. for ( int j = 0; j < fill.loops.Num(); j++ ) {
  416. swfSPLineLoop_t & loop = fill.loops[j];
  417. if ( !loop.hole ) {
  418. continue;
  419. }
  420. for ( int v = 0; v < loop.vindex1.Num(); v++ ) {
  421. if ( verts[ loop.vindex1[v] ].x > rightMostX ) {
  422. hole = j;
  423. holeVert = v;
  424. rightMostX = verts[ loop.vindex1[v] ].x;
  425. }
  426. }
  427. }
  428. if ( hole == -1 ) {
  429. break;
  430. }
  431. swfSPLineLoop_t & loopHole = fill.loops[ hole ];
  432. const idVec2 & holePoint = verts[ loopHole.vindex1[ holeVert ] ];
  433. int shape = -1;
  434. for ( int j = 0; j < fill.loops.Num(); j++ ) {
  435. swfSPLineLoop_t & loop = fill.loops[j];
  436. if ( loop.hole ) {
  437. continue;
  438. }
  439. bool inside = false;
  440. for ( int k = 0; k < loop.vindex1.Num(); k++ ) {
  441. const idVec2 & v1 = verts[ loop.vindex1[k] ];
  442. const idVec2 & v2 = verts[ loop.vindex1[(k + 1) % loop.vindex1.Num()] ];
  443. if ( v1.x < holePoint.x && v2.x < holePoint.x ) {
  444. continue; // both on the left of the holePoint
  445. }
  446. if ( ( v1.y < holePoint.y ) == ( v2.y < holePoint.y ) ) {
  447. continue; // both on the same side of the horizon
  448. }
  449. assert( v1 != holePoint );
  450. assert( v2 != holePoint );
  451. inside = !inside;
  452. }
  453. if ( inside ) {
  454. shape = j;
  455. break;
  456. }
  457. }
  458. if ( shape == -1 ) {
  459. idLib::Warning( "idSWFShapeParser: Hole not in a shape" );
  460. fill.loops.RemoveIndexFast( hole );
  461. continue;
  462. }
  463. swfSPLineLoop_t & loopShape = fill.loops[ shape ];
  464. // now that we have a hole and the shape it's inside, merge the two together
  465. // find the nearest vert that's on the right side of holePoint
  466. float bestDist = 1e10f;
  467. int shapeVert = -1;
  468. for ( int j = 0; j < loopShape.vindex1.Num(); j++ ) {
  469. const idVec2 & v1 = verts[ loopShape.vindex1[j] ];
  470. if ( v1.x < holePoint.x ) {
  471. continue; // on the left of the holePoint
  472. }
  473. float dist = ( v1 - holePoint ).Length();
  474. if ( dist < bestDist ) {
  475. shapeVert = j;
  476. bestDist = dist;
  477. }
  478. }
  479. // connect holeVert to shapeVert
  480. idList< uint16 > vindex;
  481. vindex.SetNum( loopShape.vindex1.Num() + loopHole.vindex1.Num() + 1 );
  482. vindex.SetNum( 0 );
  483. for ( int j = 0; j <= shapeVert; j++ ) {
  484. vindex.Append( loopShape.vindex1[j] );
  485. }
  486. for ( int j = holeVert; j < loopHole.vindex1.Num(); j++ ) {
  487. vindex.Append( loopHole.vindex1[j] );
  488. }
  489. for ( int j = 0; j <= holeVert; j++ ) {
  490. vindex.Append( loopHole.vindex1[j] );
  491. }
  492. for ( int j = shapeVert; j < loopShape.vindex1.Num(); j++ ) {
  493. vindex.Append( loopShape.vindex1[j] );
  494. }
  495. loopShape.vindex1 = vindex;
  496. vindex.Clear();
  497. for ( int j = 0; j <= shapeVert; j++ ) {
  498. vindex.Append( loopShape.vindex2[j] );
  499. }
  500. for ( int j = holeVert; j < loopHole.vindex2.Num(); j++ ) {
  501. vindex.Append( loopHole.vindex2[j] );
  502. }
  503. for ( int j = 0; j <= holeVert; j++ ) {
  504. vindex.Append( loopHole.vindex2[j] );
  505. }
  506. for ( int j = shapeVert; j < loopShape.vindex2.Num(); j++ ) {
  507. vindex.Append( loopShape.vindex2[j] );
  508. }
  509. loopShape.vindex2 = vindex;
  510. fill.loops.RemoveIndexFast( hole );
  511. }
  512. }
  513. }
  514. /*
  515. ========================
  516. idSWFShapeParser::TriangulateSoup
  517. ========================
  518. */
  519. void idSWFShapeParser::TriangulateSoup( idSWFShape & shape ) {
  520. MakeLoops();
  521. // Now turn the (potentially) concave line loops into triangles by using ear clipping
  522. shape.fillDraws.SetNum( fillDraws.Num() );
  523. for ( int i = 0; i < fillDraws.Num(); i++ ) {
  524. swfSPDrawFill_t & spDrawFill = fillDraws[i];
  525. idSWFShapeDrawFill & drawFill = shape.fillDraws[i];
  526. swfFillStyle_t & style = spDrawFill.style;
  527. drawFill.style = spDrawFill.style;
  528. for ( int j = 0; j < spDrawFill.loops.Num(); j++ ) {
  529. swfSPLineLoop_t & loop = spDrawFill.loops[j];
  530. int numVerts = loop.vindex1.Num();
  531. for ( int k = 0; k < numVerts - 2; k++ ) {
  532. int v1 = FindEarVert( loop );
  533. if ( v1 == -1 ) {
  534. idLib::Warning( "idSWFShapeParser: could not find an ear vert" );
  535. break;
  536. }
  537. int num = loop.vindex1.Num();
  538. int v2 = ( v1 + 1 ) % num;
  539. int v3 = ( v1 + 2 ) % num;
  540. AddUniqueVert( drawFill, verts[ loop.vindex1[ v1 ] ], verts[ loop.vindex2[ v1 ] ] );
  541. AddUniqueVert( drawFill, verts[ loop.vindex1[ v2 ] ], verts[ loop.vindex2[ v2 ] ] );
  542. AddUniqueVert( drawFill, verts[ loop.vindex1[ v3 ] ], verts[ loop.vindex2[ v3 ] ] );
  543. loop.vindex1.RemoveIndex( v2 );
  544. loop.vindex2.RemoveIndex( v2 );
  545. }
  546. }
  547. }
  548. }
  549. /*
  550. ========================
  551. idSWFShapeParser::TriangulateSoup
  552. ========================
  553. */
  554. void idSWFShapeParser::TriangulateSoup( idSWFFontGlyph & shape ) {
  555. MakeLoops();
  556. // Now turn the (potentially) concave line loops into triangles by using ear clipping
  557. assert( fillDraws.Num() == 1 );
  558. swfSPDrawFill_t & spDrawFill = fillDraws[0];
  559. for ( int j = 0; j < spDrawFill.loops.Num(); j++ ) {
  560. swfSPLineLoop_t & loop = spDrawFill.loops[j];
  561. int numVerts = loop.vindex1.Num();
  562. for ( int k = 0; k < numVerts - 2; k++ ) {
  563. int v1 = FindEarVert( loop );
  564. if ( v1 == -1 ) {
  565. idLib::Warning( "idSWFShapeParser: could not find an ear vert" );
  566. break;
  567. }
  568. int num = loop.vindex1.Num();
  569. int v2 = ( v1 + 1 ) % num;
  570. int v3 = ( v1 + 2 ) % num;
  571. shape.indices.Append( shape.verts.AddUnique( verts[ loop.vindex1[ v1 ] ] ) );
  572. shape.indices.Append( shape.verts.AddUnique( verts[ loop.vindex1[ v2 ] ] ) );
  573. shape.indices.Append( shape.verts.AddUnique( verts[ loop.vindex1[ v3 ] ] ) );
  574. loop.vindex1.RemoveIndex( v2 );
  575. loop.vindex2.RemoveIndex( v2 );
  576. }
  577. }
  578. }
  579. struct earVert_t {
  580. int i1;
  581. int i2;
  582. int i3;
  583. float cross;
  584. };
  585. class idSort_Ears : public idSort_Quick< earVert_t, idSort_Ears > {
  586. public:
  587. int Compare( const earVert_t & a, const earVert_t & b ) const {
  588. if ( a.cross < b.cross ) {
  589. return -1;
  590. } else if ( a.cross > b.cross ) {
  591. return 1;
  592. }
  593. return 0;
  594. }
  595. };
  596. /*
  597. ========================
  598. idSWFShapeParser::FindEarVert
  599. ========================
  600. */
  601. int idSWFShapeParser::FindEarVert( const swfSPLineLoop_t & loop ) {
  602. assert( loop.vindex1.Num() == loop.vindex2.Num() );
  603. int num = loop.vindex1.Num();
  604. idList<earVert_t> ears;
  605. ears.SetNum( num );
  606. for ( int i1 = 0; i1 < num; i1++ ) {
  607. int i2 = ( i1 + 1 ) % num;
  608. int i3 = ( i1 + 2 ) % num;
  609. const idVec2 & v1s = verts[ loop.vindex1[ i1 ] ];
  610. const idVec2 & v2s = verts[ loop.vindex1[ i2 ] ];
  611. const idVec2 & v3s = verts[ loop.vindex1[ i3 ] ];
  612. idVec2 a = v1s - v2s;
  613. idVec2 b = v2s - v3s;
  614. ears[i1].cross = a.x * b.y - a.y * b.x;
  615. ears[i1].i1 = i1;
  616. ears[i1].i2 = i2;
  617. ears[i1].i3 = i3;
  618. }
  619. ears.SortWithTemplate( idSort_Ears() );
  620. for ( int i = 0; i < ears.Num(); i++ ) {
  621. if ( ears[i].cross < 0.0f ) {
  622. continue;
  623. }
  624. int i1 = ears[i].i1;
  625. int i2 = ears[i].i2;
  626. int i3 = ears[i].i3;
  627. const idVec2 & v1s = verts[ loop.vindex1[ i1 ] ];
  628. const idVec2 & v2s = verts[ loop.vindex1[ i2 ] ];
  629. const idVec2 & v3s = verts[ loop.vindex1[ i3 ] ];
  630. const idVec2 & v1e = verts[ loop.vindex2[ i1 ] ];
  631. const idVec2 & v2e = verts[ loop.vindex2[ i2 ] ];
  632. const idVec2 & v3e = verts[ loop.vindex2[ i3 ] ];
  633. idMat3 edgeEquations1;
  634. edgeEquations1[0].Set( v1s.x, v1s.y, 1.0f );
  635. edgeEquations1[1].Set( v2s.x, v2s.y, 1.0f );
  636. edgeEquations1[2].Set( v3s.x, v3s.y, 1.0f );
  637. idMat3 edgeEquations2;
  638. edgeEquations2[0].Set( v1e.x, v1e.y, 1.0f );
  639. edgeEquations2[1].Set( v2e.x, v2e.y, 1.0f );
  640. edgeEquations2[2].Set( v3e.x, v3e.y, 1.0f );
  641. edgeEquations1.InverseSelf();
  642. edgeEquations2.InverseSelf();
  643. bool isEar = true;
  644. for ( int j = 0; j < num; j++ ) {
  645. if ( j == i1 || j == i2 || j == i3 ) {
  646. continue;
  647. }
  648. idVec3 p1;
  649. p1.ToVec2() = verts[ loop.vindex1[j] ];
  650. p1.z = 1.0f;
  651. idVec3 signs1 = p1 * edgeEquations1;
  652. bool b1x = signs1.x > 0;
  653. bool b1y = signs1.y > 0;
  654. bool b1z = signs1.z > 0;
  655. if ( b1x == b1y && b1x == b1z ) {
  656. // point inside
  657. isEar = false;
  658. break;
  659. }
  660. idVec3 p2;
  661. p2.ToVec2() = verts[ loop.vindex2[j] ];
  662. p2.z = 1.0f;
  663. idVec3 signs2 = p2 * edgeEquations2;
  664. bool b2x = signs2.x > 0;
  665. bool b2y = signs2.y > 0;
  666. bool b2z = signs2.z > 0;
  667. if ( b2x == b2y && b2x == b2z ) {
  668. // point inside
  669. isEar = false;
  670. break;
  671. }
  672. }
  673. if ( isEar ) {
  674. return i1;
  675. }
  676. }
  677. return -1;
  678. }
  679. /*
  680. ========================
  681. idSWFShapeParser::AddUniqueVert
  682. ========================
  683. */
  684. void idSWFShapeParser::AddUniqueVert( idSWFShapeDrawFill & drawFill, const idVec2 & start, const idVec2 & end ) {
  685. if ( morph ) {
  686. for ( int i = 0; i < drawFill.startVerts.Num(); i++ ) {
  687. if ( drawFill.startVerts[i] == start && drawFill.endVerts[i] == end ) {
  688. drawFill.indices.Append( i );
  689. return;
  690. }
  691. }
  692. int index1 = drawFill.startVerts.Append( start );
  693. int index2 = drawFill.endVerts.Append( end );
  694. assert( index1 == index2 );
  695. drawFill.indices.Append( index1 );
  696. } else {
  697. drawFill.indices.Append( drawFill.startVerts.AddUnique( start ) );
  698. }
  699. }
  700. /*
  701. ========================
  702. idSWFShapeParser::ReadFillStyle
  703. ========================
  704. */
  705. void idSWFShapeParser::ReadFillStyle( idSWFBitStream & bitstream ) {
  706. uint16 fillStyleCount = bitstream.ReadU8();
  707. if ( extendedCount && fillStyleCount == 0xFF ) {
  708. fillStyleCount = bitstream.ReadU16();
  709. }
  710. for ( int i = 0; i < fillStyleCount; i++ ) {
  711. uint8 fillStyleType = bitstream.ReadU8();
  712. swfFillStyle_t & fillStyle = fillDraws.Alloc().style;
  713. fillStyle.type = fillStyleType >> 4;
  714. fillStyle.subType = fillStyleType & 0xF;
  715. if ( fillStyle.type == 0 ) {
  716. if ( morph ) {
  717. bitstream.ReadColorRGBA( fillStyle.startColor );
  718. bitstream.ReadColorRGBA( fillStyle.endColor );
  719. } else {
  720. if ( rgba ) {
  721. bitstream.ReadColorRGBA( fillStyle.startColor );
  722. } else {
  723. bitstream.ReadColorRGB( fillStyle.startColor );
  724. }
  725. fillStyle.endColor = fillStyle.startColor;
  726. }
  727. } else if ( fillStyle.type == 1 ) {
  728. bitstream.ReadMatrix( fillStyle.startMatrix );
  729. if ( morph ) {
  730. bitstream.ReadMatrix( fillStyle.endMatrix );
  731. bitstream.ReadMorphGradient( fillStyle.gradient );
  732. } else {
  733. fillStyle.endMatrix = fillStyle.startMatrix;
  734. bitstream.ReadGradient( fillStyle.gradient, rgba );
  735. }
  736. if ( fillStyle.subType == 3 ) {
  737. assert( morph == false ); // focal gradients aren't allowed in morph shapes
  738. fillStyle.focalPoint = bitstream.ReadFixed8();
  739. }
  740. } else if ( fillStyle.type == 4 ) {
  741. fillStyle.bitmapID = bitstream.ReadU16();
  742. bitstream.ReadMatrix( fillStyle.startMatrix );
  743. if ( morph ) {
  744. bitstream.ReadMatrix( fillStyle.endMatrix );
  745. } else {
  746. fillStyle.endMatrix = fillStyle.startMatrix;
  747. }
  748. }
  749. }
  750. uint16 lineStyleCount = bitstream.ReadU8();
  751. if ( extendedCount && lineStyleCount == 0xFF ) {
  752. lineStyleCount = bitstream.ReadU16();
  753. }
  754. lineDraws.SetNum( lineDraws.Num() + lineStyleCount );
  755. lineDraws.SetNum( 0 );
  756. for ( int i = 0; i < lineStyleCount; i++ ) {
  757. swfLineStyle_t & lineStyle = lineDraws.Alloc().style;
  758. lineStyle.startWidth = bitstream.ReadU16();
  759. if ( lineStyle2 ) {
  760. lineStyle.endWidth = lineStyle.startWidth;
  761. uint8 startCapStyle = bitstream.ReadU( 2 );
  762. uint8 joinStyle = bitstream.ReadU( 2 );
  763. bool hasFillFlag = bitstream.ReadBool();
  764. bool noHScaleFlag = bitstream.ReadBool();
  765. bool noVScaleFlag = bitstream.ReadBool();
  766. bool pixelHintingFlag = bitstream.ReadBool();
  767. uint8 reserved = bitstream.ReadU( 5 );
  768. bool noClose = bitstream.ReadBool();
  769. uint8 endCapStyle = bitstream.ReadU( 2 );
  770. if ( joinStyle == 2 ) {
  771. uint16 miterLimitFactor = bitstream.ReadU16();
  772. }
  773. if ( hasFillFlag ) {
  774. // FIXME: read fill style
  775. idLib::Warning( "idSWFShapeParser: Ignoring hasFillFlag" );
  776. } else {
  777. bitstream.ReadColorRGBA( lineStyle.startColor );
  778. lineStyle.endColor = lineStyle.startColor;
  779. }
  780. } else {
  781. if ( morph ) {
  782. lineStyle.endWidth = bitstream.ReadU16();
  783. } else {
  784. lineStyle.endWidth = lineStyle.startWidth;
  785. }
  786. if ( rgba ) {
  787. bitstream.ReadColorRGBA( lineStyle.startColor );
  788. } else {
  789. bitstream.ReadColorRGB( lineStyle.startColor );
  790. }
  791. if ( morph ) {
  792. bitstream.ReadColorRGBA( lineStyle.endColor );
  793. } else {
  794. lineStyle.endColor = lineStyle.startColor;
  795. }
  796. }
  797. }
  798. }