Ingen beskrivning
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SpriteShapeGenerator.cs 107KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603
  1. using System;
  2. using System.Linq;
  3. using Unity.Jobs;
  4. using Unity.Collections;
  5. using Unity.Mathematics;
  6. using Unity.Collections.LowLevel.Unsafe;
  7. using Unity.Profiling;
  8. using Unity.SpriteShape.External.LibTessDotNet;
  9. // We will enable this once Burst gets a verified final version as this attribute keeps changing.
  10. #if ENABLE_SPRITESHAPE_BURST
  11. using Unity.Burst;
  12. #endif
  13. namespace UnityEngine.U2D
  14. {
  15. #if ENABLE_SPRITESHAPE_BURST
  16. [BurstCompile]
  17. #endif
  18. public struct SpriteShapeGenerator : IJob
  19. {
  20. public ProfilerMarker generateGeometry;
  21. public ProfilerMarker generateCollider;
  22. struct JobParameters
  23. {
  24. public int4 shapeData; // x : ClosedShape (bool) y : AdaptiveUV (bool) z : SpriteBorders (bool) w : Enable Fill Texture.
  25. public int4 splineData; // x : StrtechUV. y : splineDetail z : _unused_ w: Collider On/Off
  26. public float4 curveData; // x : ColliderPivot y : BorderPivot z : AngleThreshold w : _unused_.
  27. public float4 fillData; // x : fillScale y : fillScale.x W z : fillScale.y H w: 0.
  28. }
  29. struct JobSpriteInfo
  30. {
  31. public float4 texRect; // TextureRect.
  32. public float4 texData; // x : GPUWidth y : GPUHeight z : TexelWidth w : TexelHeight
  33. public float4 uvInfo; // x : x, y : y, z : width, w : height
  34. public float4 metaInfo; // x : PPU, y : Pivot Y z : Original Rect Width w : Original Rect Height.
  35. public float4 border; // Sprite Border.
  36. }
  37. struct JobAngleRange
  38. {
  39. public float4 spriteAngles; // x, y | First Angle & z,w | Second Angle.
  40. public int4 spriteData; // Additional Data. x : sorting Order. y : variant Count. z : render Order Max.
  41. };
  42. struct JobControlPoint
  43. {
  44. public int4 cpData; // x : Sprite Index y : Corner Type z : Mode w : Internal Sprite Index.
  45. public int4 exData; // x : Corner Type y: Corner Sprite z : Corner 0(disabled), 1 (stretch), (2, 3)(corner start/end)
  46. public float2 cpInfo; // x : Height y : Render Order.
  47. public float2 position;
  48. public float2 tangentLt;
  49. public float2 tangentRt;
  50. };
  51. struct JobContourPoint
  52. {
  53. public float2 position; // x, y Position.
  54. public float2 ptData; // x : height. y :source cp.
  55. }
  56. struct JobIntersectPoint
  57. {
  58. public float2 top;
  59. public float2 bottom;
  60. }
  61. // Tessellation Structures.
  62. struct JobSegmentInfo
  63. {
  64. public int4 sgInfo; // x : Begin y : End. z : Sprite w : First Sprite for that Angle Range.
  65. public float4 spriteInfo; // x : width y : height z : Render Order. w : 0 (no) 1 (left stretchy) 2(right)
  66. };
  67. struct JobCornerInfo
  68. {
  69. public float2 bottom;
  70. public float2 top;
  71. public float2 left;
  72. public float2 right;
  73. public int2 cornerData;
  74. }
  75. struct JobShapeVertex
  76. {
  77. public float2 pos;
  78. public float2 uv;
  79. public float4 tan;
  80. public float2 meta; // x : height y : -
  81. public int4 sprite; // x : sprite y : is main Point z : is edgeCaps.
  82. }
  83. /// <summary>
  84. /// Native Arrays : Scope : Initialized before and ReadOnly During Job
  85. /// </summary>
  86. [ReadOnly]
  87. private JobParameters m_ShapeParams;
  88. [ReadOnly]
  89. [DeallocateOnJobCompletion]
  90. private NativeArray<JobSpriteInfo> m_SpriteInfos;
  91. [ReadOnly]
  92. [DeallocateOnJobCompletion]
  93. private NativeArray<JobSpriteInfo> m_CornerSpriteInfos;
  94. [ReadOnly]
  95. [DeallocateOnJobCompletion]
  96. private NativeArray<JobAngleRange> m_AngleRanges;
  97. /// <summary>
  98. /// Native Arrays : Scope : Job
  99. /// </summary>
  100. [DeallocateOnJobCompletion]
  101. private NativeArray<JobSegmentInfo> m_Segments;
  102. private int m_SegmentCount;
  103. [DeallocateOnJobCompletion]
  104. private NativeArray<JobContourPoint> m_ContourPoints;
  105. private int m_ContourPointCount;
  106. [DeallocateOnJobCompletion]
  107. private NativeArray<JobCornerInfo> m_Corners;
  108. private int m_CornerCount;
  109. [DeallocateOnJobCompletion]
  110. private NativeArray<float2> m_TessPoints;
  111. private int m_TessPointCount;
  112. [DeallocateOnJobCompletion]
  113. NativeArray<JobShapeVertex> m_VertexData;
  114. [DeallocateOnJobCompletion]
  115. NativeArray<JobShapeVertex> m_OutputVertexData;
  116. [DeallocateOnJobCompletion]
  117. private NativeArray<JobControlPoint> m_ControlPoints;
  118. private int m_ControlPointCount;
  119. [DeallocateOnJobCompletion]
  120. private NativeArray<float2> m_CornerCoordinates;
  121. [DeallocateOnJobCompletion]
  122. private NativeArray<float2> m_TempPoints;
  123. [DeallocateOnJobCompletion]
  124. private NativeArray<JobControlPoint> m_GeneratedControlPoints;
  125. [DeallocateOnJobCompletion]
  126. private NativeArray<int2> m_SpriteIndices;
  127. [DeallocateOnJobCompletion]
  128. private NativeArray<JobIntersectPoint> m_Intersectors;
  129. /// <summary>
  130. /// Output Native Arrays : Scope : SpriteShapeRenderer / SpriteShapeController.
  131. /// </summary>
  132. private int m_IndexArrayCount;
  133. public NativeArray<ushort> m_IndexArray;
  134. private int m_VertexArrayCount;
  135. public NativeSlice<Vector3> m_PosArray;
  136. public NativeSlice<Vector2> m_Uv0Array;
  137. public NativeSlice<Vector4> m_TanArray;
  138. private int m_GeomArrayCount;
  139. public NativeArray<SpriteShapeSegment> m_GeomArray;
  140. private int m_ColliderPointCount;
  141. public NativeArray<float2> m_ColliderPoints;
  142. public NativeArray<Bounds> m_Bounds;
  143. int m_IndexDataCount;
  144. int m_VertexDataCount;
  145. int m_ColliderDataCount;
  146. int m_ActiveIndexCount;
  147. int m_ActiveVertexCount;
  148. float2 m_FirstLT;
  149. float2 m_FirstLB;
  150. float4x4 m_Transform;
  151. int kModeLinear;
  152. int kModeContinous;
  153. int kModeBroken;
  154. int kModeUTess;
  155. int kCornerTypeOuterTopLeft;
  156. int kCornerTypeOuterTopRight;
  157. int kCornerTypeOuterBottomLeft;
  158. int kCornerTypeOuterBottomRight;
  159. int kCornerTypeInnerTopLeft;
  160. int kCornerTypeInnerTopRight;
  161. int kCornerTypeInnerBottomLeft;
  162. int kCornerTypeInnerBottomRight;
  163. int kControlPointCount;
  164. float kEpsilon;
  165. float kEpsilonOrder;
  166. float kEpsilonRelaxed;
  167. float kExtendSegment;
  168. float kRenderQuality;
  169. float kOptimizeRender;
  170. float kColliderQuality;
  171. float kOptimizeCollider;
  172. float kLowestQualityTolerance;
  173. float kHighestQualityTolerance;
  174. #region Getters.
  175. // Return Vertex Data Count
  176. private int vertexDataCount
  177. {
  178. get { return m_VertexDataCount; }
  179. }
  180. // Return final Vertex Array Count
  181. private int vertexArrayCount
  182. {
  183. get { return m_VertexArrayCount; }
  184. }
  185. // Return Index Data Count
  186. private int indexDataCount
  187. {
  188. get { return m_IndexDataCount; }
  189. }
  190. // Return Sprite Count
  191. private int spriteCount
  192. {
  193. get { return m_SpriteInfos.Length; }
  194. }
  195. private int cornerSpriteCount
  196. {
  197. get { return m_CornerSpriteInfos.Length; }
  198. }
  199. // Return Angle Range Count
  200. private int angleRangeCount
  201. {
  202. get { return m_AngleRanges.Length; }
  203. }
  204. // Return the Input Control Point Count.
  205. private int controlPointCount
  206. {
  207. get { return m_ControlPointCount; }
  208. }
  209. // Return the Contour Point Count.
  210. private int contourPointCount
  211. {
  212. get { return m_ContourPointCount; }
  213. }
  214. // Return Segment Count
  215. private int segmentCount
  216. {
  217. get { return m_SegmentCount; }
  218. }
  219. // Needs Collider Generaie.
  220. private bool hasCollider
  221. {
  222. get { return m_ShapeParams.splineData.w == 1; }
  223. }
  224. // Collider Pivot
  225. private float colliderPivot
  226. {
  227. get { return m_ShapeParams.curveData.x; }
  228. }
  229. // Border Pivot
  230. private float borderPivot
  231. {
  232. get { return m_ShapeParams.curveData.y; }
  233. }
  234. // Spline Detail
  235. private int splineDetail
  236. {
  237. get { return m_ShapeParams.splineData.y; }
  238. }
  239. // Is this Closed-Loop.
  240. private bool isCarpet
  241. {
  242. get { return m_ShapeParams.shapeData.x == 1; }
  243. }
  244. // Is Adaptive UV
  245. private bool isAdaptive
  246. {
  247. get { return m_ShapeParams.shapeData.y == 1; }
  248. }
  249. // Has Sprite Border.
  250. private bool hasSpriteBorder
  251. {
  252. get { return m_ShapeParams.shapeData.z == 1; }
  253. }
  254. #endregion
  255. #region Safe Getters.
  256. JobSpriteInfo GetSpriteInfo(int index)
  257. {
  258. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  259. if (index >= m_SpriteInfos.Length)
  260. throw new ArgumentException($"GetSpriteInfo accessed with invalid Index {index} / {m_SpriteInfos.Length}");
  261. #endif
  262. return m_SpriteInfos[index];
  263. }
  264. JobSpriteInfo GetCornerSpriteInfo(int index)
  265. {
  266. int ai = index - 1;
  267. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  268. if (ai >= m_CornerSpriteInfos.Length || index == 0)
  269. throw new ArgumentException($"GetCornerSpriteInfo accessed with invalid Index {index} / {m_CornerSpriteInfos.Length}");
  270. #endif
  271. return m_CornerSpriteInfos[ai];
  272. }
  273. JobAngleRange GetAngleRange(int index)
  274. {
  275. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  276. if (index >= m_AngleRanges.Length)
  277. throw new ArgumentException($"GetAngleRange accessed with invalid Index {index} / {m_AngleRanges.Length}");
  278. #endif
  279. return m_AngleRanges[index];
  280. }
  281. JobControlPoint GetControlPoint(int index)
  282. {
  283. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  284. if (index >= m_ControlPoints.Length)
  285. throw new ArgumentException($"GetControlPoint accessed with invalid Index {index} / {m_ControlPoints.Length}");
  286. #endif
  287. return m_ControlPoints[index];
  288. }
  289. JobContourPoint GetContourPoint(int index)
  290. {
  291. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  292. if (index >= m_ContourPointCount)
  293. throw new ArgumentException($"GetContourPoint accessed with invalid Index {index} / {m_ContourPointCount}");
  294. #endif
  295. return m_ContourPoints[index];
  296. }
  297. JobSegmentInfo GetSegmentInfo(int index)
  298. {
  299. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  300. if (index >= m_SegmentCount)
  301. throw new ArgumentException($"GetSegmentInfo accessed with invalid Index {index} / {m_SegmentCount}");
  302. #endif
  303. return m_Segments[index];
  304. }
  305. int GetContourIndex(int index)
  306. {
  307. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  308. if (index >= m_ControlPoints.Length)
  309. throw new ArgumentException($"GetContourIndex accessed with invalid Index {index} / {m_ControlPoints.Length}");
  310. #endif
  311. return index * m_ShapeParams.splineData.y;
  312. }
  313. int GetEndContourIndexOfSegment(JobSegmentInfo isi)
  314. {
  315. int contourIndex = GetContourIndex(isi.sgInfo.y) - 1;
  316. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  317. if (isi.sgInfo.y >= m_ControlPoints.Length || isi.sgInfo.y == 0)
  318. throw new ArgumentException($"GetEndContourIndexOfSegment accessed with invalid Index");
  319. #endif
  320. return contourIndex;
  321. }
  322. #endregion
  323. #region Utility
  324. static void CopyToNativeArray<T>(NativeArray<T> from, int length, ref NativeArray<T> to) where T : struct
  325. {
  326. to = new NativeArray<T>(length, Allocator.TempJob);
  327. for (int i = 0; i < length; ++i)
  328. to[i] = from[i];
  329. }
  330. static void SafeDispose<T>(NativeArray<T> na) where T : struct
  331. {
  332. if (na.Length > 0)
  333. na.Dispose();
  334. }
  335. static bool IsPointOnLine(float epsilon, float2 a, float2 b, float2 c)
  336. {
  337. float cp = (c.y - a.y) * (b.x - a.x) - (c.x - a.x) * (b.y - a.y);
  338. if (math.abs(cp) > epsilon)
  339. return false;
  340. float dp = (c.x - a.x) * (b.x - a.x) + (c.y - a.y) * (b.y - a.y);
  341. if (dp < 0)
  342. return false;
  343. float ba = (b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y);
  344. if (dp > ba)
  345. return false;
  346. return true;
  347. }
  348. static bool IsPointOnLines(float epsilon, float2 p1, float2 p2, float2 p3, float2 p4, float2 r)
  349. {
  350. return IsPointOnLine(epsilon, p1, p2, r) && IsPointOnLine(epsilon, p3, p4, r);
  351. }
  352. static bool Colinear(float2 p, float2 q, float2 r)
  353. {
  354. return (q.x <= math.max(p.x, r.x) && q.x >= math.min(p.x, r.x) && q.y <= math.max(p.y, r.y) && q.y >= math.min(p.y, r.y));
  355. }
  356. static int Det(float epsilon, float2 p, float2 q, float2 r)
  357. {
  358. float val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
  359. if (val > -epsilon && val < epsilon) return 0;
  360. return (val > 0)? 1: 2;
  361. }
  362. static bool LineIntersectionTest(float epsilon, float2 p1, float2 q1, float2 p2, float2 q2)
  363. {
  364. int o1 = Det(epsilon, p1, q1, p2);
  365. int o2 = Det(epsilon, p1, q1, q2);
  366. int o3 = Det(epsilon, p2, q2, p1);
  367. int o4 = Det(epsilon, p2, q2, q1);
  368. if (o1 != o2 && o3 != o4)
  369. return true;
  370. // Special Cases
  371. if (o1 == 0 && Colinear(p1, p2, q1)) return true;
  372. if (o2 == 0 && Colinear(p1, q2, q1)) return true;
  373. if (o3 == 0 && Colinear(p2, p1, q2)) return true;
  374. if (o4 == 0 && Colinear(p2, q1, q2)) return true;
  375. return false;
  376. }
  377. static bool LineIntersection(float epsilon, float2 p1, float2 p2, float2 p3, float2 p4, ref float2 result)
  378. {
  379. if (!LineIntersectionTest(epsilon, p1, p2, p3, p4))
  380. {
  381. return false;
  382. }
  383. float bx = p2.x - p1.x;
  384. float by = p2.y - p1.y;
  385. float dx = p4.x - p3.x;
  386. float dy = p4.y - p3.y;
  387. float bDotDPerp = bx * dy - by * dx;
  388. if (math.abs(bDotDPerp) < epsilon)
  389. {
  390. return false;
  391. }
  392. float cx = p3.x - p1.x;
  393. float cy = p3.y - p1.y;
  394. float t = (cx * dy - cy * dx) / bDotDPerp;
  395. if ((t >= -epsilon) && (t <= 1.0f + epsilon))
  396. {
  397. result.x = p1.x + t * bx;
  398. result.y = p1.y + t * by;
  399. return true;
  400. }
  401. return false;
  402. }
  403. static float AngleBetweenVector(float2 a, float2 b)
  404. {
  405. float dot = math.dot(a, b);
  406. float det = (a.x * b.y) - (b.x * a.y);
  407. return math.atan2(det, dot) * Mathf.Rad2Deg;
  408. }
  409. static bool GenerateColumnsBi(float2 a, float2 b, float2 whsize, bool flip, ref float2 rt, ref float2 rb, float cph, float pivot)
  410. {
  411. float2 v1 = flip ? (a - b) : (b - a);
  412. if (math.length(v1) < 1e-30f)
  413. return false;
  414. float2 rvxy = new float2(-1f, 1f);
  415. float2 v2 = v1.yx * rvxy;
  416. float2 whsizey = new float2(whsize.y * cph);
  417. v2 = math.normalize(v2);
  418. float2 v3 = v2 * whsizey;
  419. rt = a - v3;
  420. rb = a + v3;
  421. float2 pivotSet = (rb - rt) * pivot;
  422. rt = rt + pivotSet;
  423. rb = rb + pivotSet;
  424. return true;
  425. }
  426. static bool GenerateColumnsTri(float2 a, float2 b, float2 c, float2 whsize, bool flip, ref float2 rt, ref float2 rb, float cph, float pivot)
  427. {
  428. float2 rvxy = new float2(-1f, 1f);
  429. float2 v0 = b - a;
  430. float2 v1 = c - b;
  431. v0 = v0.yx * rvxy;
  432. v1 = v1.yx * rvxy;
  433. float2 v2 = math.normalize(v0) + math.normalize(v1);
  434. if (math.length(v2) < 1e-30f)
  435. return false;
  436. v2 = math.normalize(v2);
  437. float2 whsizey = new float2(whsize.y * cph);
  438. float2 v3 = v2 * whsizey;
  439. rt = b - v3;
  440. rb = b + v3;
  441. float2 pivotSet = (rb - rt) * pivot;
  442. rt = rt + pivotSet;
  443. rb = rb + pivotSet;
  444. return true;
  445. }
  446. #endregion
  447. #region Input Preparation.
  448. void AppendCornerCoordinates(ref NativeArray<float2> corners, ref int cornerCount, float2 a, float2 b, float2 c, float2 d)
  449. {
  450. corners[cornerCount++] = a;
  451. corners[cornerCount++] = b;
  452. corners[cornerCount++] = c;
  453. corners[cornerCount++] = d;
  454. }
  455. unsafe void PrepareInput(SpriteShapeParameters shapeParams, int maxArrayCount, NativeArray<ShapeControlPoint> shapePoints, bool optimizeGeometry, bool updateCollider, bool optimizeCollider, float colliderOffset, float colliderDetail)
  456. {
  457. kModeLinear = 0;
  458. kModeContinous = 1;
  459. kModeBroken = 2;
  460. kCornerTypeOuterTopLeft = 1;
  461. kCornerTypeOuterTopRight = 2;
  462. kCornerTypeOuterBottomLeft = 3;
  463. kCornerTypeOuterBottomRight = 4;
  464. kCornerTypeInnerTopLeft = 5;
  465. kCornerTypeInnerTopRight = 6;
  466. kCornerTypeInnerBottomLeft = 7;
  467. kCornerTypeInnerBottomRight = 8;
  468. m_IndexDataCount = 0;
  469. m_VertexDataCount = 0;
  470. m_ColliderDataCount = 0;
  471. m_ActiveIndexCount = 0;
  472. m_ActiveVertexCount = 0;
  473. kEpsilon = 0.00001f;
  474. kEpsilonOrder = -0.0001f;
  475. kEpsilonRelaxed = 0.001f;
  476. kExtendSegment = 10000.0f;
  477. kLowestQualityTolerance = 4.0f;
  478. kHighestQualityTolerance = 16.0f;
  479. kColliderQuality = math.clamp(colliderDetail, kLowestQualityTolerance, kHighestQualityTolerance);
  480. kOptimizeCollider = optimizeCollider ? 1 : 0;
  481. kColliderQuality = (kHighestQualityTolerance - kColliderQuality + 2.0f) * 0.002f;
  482. colliderOffset = (colliderOffset == 0) ? kEpsilonRelaxed : -colliderOffset;
  483. kOptimizeRender = optimizeGeometry ? 1 : 0;
  484. kRenderQuality = math.clamp(shapeParams.splineDetail, kLowestQualityTolerance, kHighestQualityTolerance);
  485. kRenderQuality = (kHighestQualityTolerance - kRenderQuality + 2.0f) * 0.0002f;
  486. m_ShapeParams.shapeData = new int4(shapeParams.carpet ? 1 : 0, shapeParams.adaptiveUV ? 1 : 0, shapeParams.spriteBorders ? 1 : 0, shapeParams.fillTexture != null ? 1 : 0);
  487. m_ShapeParams.splineData = new int4(shapeParams.stretchUV ? 1 : 0, (shapeParams.splineDetail > 4) ? (int)shapeParams.splineDetail : 4, 0, updateCollider ? 1 : 0);
  488. m_ShapeParams.curveData = new float4(colliderOffset, shapeParams.borderPivot, shapeParams.angleThreshold, 0);
  489. float fx = 0, fy = 0;
  490. if (shapeParams.fillTexture != null)
  491. {
  492. fx = (float)shapeParams.fillTexture.width * (1.0f / (float)shapeParams.fillScale);
  493. fy = (float)shapeParams.fillTexture.height * (1.0f / (float)shapeParams.fillScale);
  494. }
  495. m_ShapeParams.fillData = new float4(shapeParams.fillScale, fx, fy, 0);
  496. UnsafeUtility.MemClear(m_GeomArray.GetUnsafePtr(), m_GeomArray.Length * UnsafeUtility.SizeOf<SpriteShapeSegment>());
  497. m_Transform = new float4x4(shapeParams.transform.m00, shapeParams.transform.m01, shapeParams.transform.m02, shapeParams.transform.m03,
  498. shapeParams.transform.m10, shapeParams.transform.m11, shapeParams.transform.m12, shapeParams.transform.m13,
  499. shapeParams.transform.m20, shapeParams.transform.m21, shapeParams.transform.m22, shapeParams.transform.m23,
  500. shapeParams.transform.m30, shapeParams.transform.m31, shapeParams.transform.m32, shapeParams.transform.m33);
  501. kControlPointCount = shapePoints.Length * (int)shapeParams.splineDetail * 32;
  502. m_Segments = new NativeArray<JobSegmentInfo>(shapePoints.Length * 2, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
  503. m_ContourPoints = new NativeArray<JobContourPoint>(kControlPointCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
  504. m_TessPoints = new NativeArray<float2>(shapePoints.Length * (int)shapeParams.splineDetail * 128, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
  505. m_VertexData = new NativeArray<JobShapeVertex>(maxArrayCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
  506. m_OutputVertexData = new NativeArray<JobShapeVertex>(maxArrayCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
  507. m_CornerCoordinates = new NativeArray<float2>(32, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
  508. m_Intersectors = new NativeArray<JobIntersectPoint>(kControlPointCount, Allocator.TempJob, NativeArrayOptions.ClearMemory);
  509. m_TempPoints = new NativeArray<float2>(maxArrayCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
  510. m_GeneratedControlPoints = new NativeArray<JobControlPoint>(kControlPointCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
  511. m_SpriteIndices = new NativeArray<int2>(kControlPointCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
  512. int cornerCount = 0;
  513. AppendCornerCoordinates(ref m_CornerCoordinates, ref cornerCount, new float2(1f, 1f), new float2(0, 1f), new float2(1f, 0), new float2(0, 0));
  514. AppendCornerCoordinates(ref m_CornerCoordinates, ref cornerCount, new float2(1f, 0), new float2(1f, 1f), new float2(0, 0), new float2(0, 1f));
  515. AppendCornerCoordinates(ref m_CornerCoordinates, ref cornerCount, new float2(0, 1f), new float2(0, 0), new float2(1f, 1f), new float2(1f, 0));
  516. AppendCornerCoordinates(ref m_CornerCoordinates, ref cornerCount, new float2(0, 0), new float2(1f, 0), new float2(0, 1f), new float2(1f, 1f));
  517. AppendCornerCoordinates(ref m_CornerCoordinates, ref cornerCount, new float2(0, 0), new float2(0, 1f), new float2(1f, 0), new float2(1f, 1f));
  518. AppendCornerCoordinates(ref m_CornerCoordinates, ref cornerCount, new float2(0, 1f), new float2(1f, 1f), new float2(0, 0), new float2(1f, 0));
  519. AppendCornerCoordinates(ref m_CornerCoordinates, ref cornerCount, new float2(1f, 0), new float2(0, 0), new float2(1f, 1f), new float2(0, 1f));
  520. AppendCornerCoordinates(ref m_CornerCoordinates, ref cornerCount, new float2(1f, 1f), new float2(1f, 0), new float2(0, 1f), new float2(0, 0));
  521. }
  522. void TransferSprites(ref NativeArray<JobSpriteInfo> spriteInfos, Sprite[] sprites, int maxCount)
  523. {
  524. for (int i = 0; i < sprites.Length && i < maxCount; ++i)
  525. {
  526. JobSpriteInfo spriteInfo = spriteInfos[i];
  527. Sprite spr = sprites[i];
  528. if (spr != null)
  529. {
  530. Texture2D tex = spr.texture;
  531. spriteInfo.texRect = new float4(spr.textureRect.x, spr.textureRect.y, spr.textureRect.width, spr.textureRect.height);
  532. spriteInfo.texData = new float4(tex.width, tex.height, tex.texelSize.x, tex.texelSize.y);
  533. spriteInfo.border = new float4(spr.border.x, spr.border.y, spr.border.z, spr.border.w);
  534. spriteInfo.uvInfo = new float4(spriteInfo.texRect.x / spriteInfo.texData.x, spriteInfo.texRect.y / spriteInfo.texData.y, spriteInfo.texRect.z / spriteInfo.texData.x, spriteInfo.texRect.w / spriteInfo.texData.y);
  535. spriteInfo.metaInfo = new float4(spr.pixelsPerUnit, spr.pivot.y / spr.textureRect.height, spr.rect.width, spr.rect.height);
  536. if (!math.any(spriteInfo.texRect))
  537. {
  538. Cleanup();
  539. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  540. throw new ArgumentException($"{spr.name} is packed with Tight packing or mesh type set to Tight. Please check input sprites");
  541. #endif
  542. }
  543. }
  544. spriteInfos[i] = spriteInfo;
  545. }
  546. }
  547. void PrepareSprites(Sprite[] edgeSprites, Sprite[] cornerSprites)
  548. {
  549. m_SpriteInfos = new NativeArray<JobSpriteInfo>(edgeSprites.Length, Allocator.TempJob);
  550. TransferSprites(ref m_SpriteInfos, edgeSprites, edgeSprites.Length);
  551. m_CornerSpriteInfos = new NativeArray<JobSpriteInfo>(kCornerTypeInnerBottomRight, Allocator.TempJob);
  552. TransferSprites(ref m_CornerSpriteInfos, cornerSprites, cornerSprites.Length);
  553. }
  554. void PrepareAngleRanges(AngleRangeInfo[] angleRanges)
  555. {
  556. m_AngleRanges = new NativeArray<JobAngleRange>(angleRanges.Length, Allocator.TempJob);
  557. for (int i = 0; i < angleRanges.Length; ++i)
  558. {
  559. JobAngleRange angleRange = m_AngleRanges[i];
  560. AngleRangeInfo ari = angleRanges[i];
  561. int[] spr = ari.sprites;
  562. if (ari.start > ari.end)
  563. {
  564. var sw = ari.start;
  565. ari.start = ari.end;
  566. ari.end = sw;
  567. }
  568. angleRange.spriteAngles = new float4(ari.start + 90f, ari.end + 90f, 0, 0);
  569. angleRange.spriteData = new int4((int)ari.order, spr.Length, 32, 0);
  570. m_AngleRanges[i] = angleRange;
  571. }
  572. }
  573. void PrepareControlPoints(NativeArray<ShapeControlPoint> shapePoints, NativeArray<SplinePointMetaData> metaData)
  574. {
  575. float2 zero = new float2(0, 0);
  576. m_ControlPoints = new NativeArray<JobControlPoint>(kControlPointCount, Allocator.TempJob);
  577. for (int i = 0; i < shapePoints.Length; ++i)
  578. {
  579. JobControlPoint shapePoint = m_ControlPoints[i];
  580. ShapeControlPoint sp = shapePoints[i];
  581. SplinePointMetaData md = metaData[i];
  582. shapePoint.position = new float2(sp.position.x, sp.position.y);
  583. shapePoint.tangentLt = (sp.mode == kModeLinear) ? zero : new float2(sp.leftTangent.x, sp.leftTangent.y);
  584. shapePoint.tangentRt = (sp.mode == kModeLinear) ? zero : new float2(sp.rightTangent.x, sp.rightTangent.y);
  585. shapePoint.cpInfo = new float2(md.height, 0);
  586. shapePoint.cpData = new int4((int)md.spriteIndex, md.cornerMode, sp.mode, 0);
  587. shapePoint.exData = new int4(-1, 0, 0, sp.mode);
  588. m_ControlPoints[i] = shapePoint;
  589. }
  590. m_ControlPointCount = shapePoints.Length;
  591. m_Corners = new NativeArray<JobCornerInfo>(shapePoints.Length, Allocator.TempJob);
  592. GenerateControlPoints();
  593. }
  594. #endregion
  595. #region Resolve Angles for Points.
  596. bool WithinRange(JobAngleRange angleRange, float inputAngle)
  597. {
  598. float range = angleRange.spriteAngles.y - angleRange.spriteAngles.x;
  599. float angle = Mathf.Repeat(inputAngle - angleRange.spriteAngles.x, 360f);
  600. return (angle >= 0f && angle <= range);
  601. }
  602. bool AngleWithinRange(float t, float a, float b)
  603. {
  604. return (a != 0 && b != 0) && (t >= a && t <= b);
  605. }
  606. static float2 BezierPoint(float2 st, float2 sp, float2 ep, float2 et, float t)
  607. {
  608. float2 xt = new float2(t);
  609. float2 nt = new float2(1.0f - t);
  610. float2 x3 = new float2(3.0f);
  611. return (sp * nt * nt * nt) + (st * nt * nt * xt * x3) + (et * nt * xt * xt * x3) + (ep * xt * xt * xt);
  612. }
  613. static float SlopeAngle(float2 dirNormalized)
  614. {
  615. float2 dvup = new float2(0, 1f);
  616. float2 dvrt = new float2(1f, 0);
  617. float dr = math.dot(dirNormalized, dvrt);
  618. float du = math.dot(dirNormalized, dvup);
  619. float cu = math.acos(du);
  620. float sn = dr >= 0 ? 1.0f : -1.0f;
  621. float an = cu * Mathf.Rad2Deg * sn;
  622. // Adjust angles when direction is parallel to Up Axis.
  623. an = (du != 1f) ? an : 0;
  624. an = (du != -1f) ? an : -180f;
  625. return an;
  626. }
  627. static float SlopeAngle(float2 start, float2 end)
  628. {
  629. float2 dir = math.normalize(start - end);
  630. return SlopeAngle(dir);
  631. }
  632. bool ResolveAngle(float angle, int activeIndex, ref float renderOrder, ref int spriteIndex, ref int firstSpriteIndex)
  633. {
  634. int localRenderOrder = 0;
  635. int localSpriteIndex = 0;
  636. for (int i = 0; i < m_AngleRanges.Length; ++i)
  637. {
  638. bool withinRange = WithinRange(m_AngleRanges[i], angle);
  639. if (withinRange)
  640. {
  641. int validIndex = (activeIndex < m_AngleRanges[i].spriteData.y) ? activeIndex : 0;
  642. renderOrder = localRenderOrder + validIndex;
  643. spriteIndex = localSpriteIndex + validIndex;
  644. firstSpriteIndex = localSpriteIndex;
  645. return true;
  646. }
  647. localRenderOrder += m_AngleRanges[i].spriteData.z;
  648. localSpriteIndex += m_AngleRanges[i].spriteData.y;
  649. }
  650. return false;
  651. }
  652. int GetSpriteIndex(int index, int previousIndex, ref int resolved)
  653. {
  654. int next = (index + 1) % controlPointCount, spriteIndex = -1, firstSpriteIndex = -1;
  655. float order = 0;
  656. var cp = GetControlPoint(index);
  657. float angle = SlopeAngle(GetControlPoint(next).position, cp.position);
  658. bool resolve = ResolveAngle(angle, cp.cpData.x, ref order, ref spriteIndex, ref firstSpriteIndex);
  659. resolved = resolve ? 1 : 0;
  660. return resolve ? spriteIndex : previousIndex;
  661. }
  662. #endregion
  663. #region Segments.
  664. void GenerateSegments()
  665. {
  666. int activeSpriteIndex = 0, activeSegmentIndex = 0, firstSpriteIndex = -1;
  667. JobSegmentInfo activeSegment = m_Segments[0];
  668. activeSegment.sgInfo = int4.zero;
  669. activeSegment.spriteInfo = int4.zero;
  670. float angle = 0;
  671. // Generate Segments.
  672. for (int i = 0; i < controlPointCount; ++i)
  673. {
  674. int next = (i + 1) % controlPointCount;
  675. // Check for Last Point and see if we need loop-back.
  676. bool skipSegmenting = false;
  677. if (next == 0)
  678. {
  679. if (!isCarpet)
  680. continue;
  681. next = 1;
  682. skipSegmenting = true;
  683. }
  684. JobControlPoint iscp = GetControlPoint(i);
  685. JobControlPoint iscpNext = GetControlPoint(next);
  686. // If this segment is corner, continue.
  687. if (iscp.exData.x > 0 && iscp.exData.x == iscpNext.exData.x && iscp.exData.z == 2)
  688. continue;
  689. // Resolve Angle and Order.
  690. int4 pointData = iscp.cpData;
  691. float2 pointInfo = iscp.cpInfo;
  692. // Get Min Max Segment.
  693. int mn = (i < next) ? i : next;
  694. int mx = (i > next) ? i : next;
  695. bool continueStrip = (iscp.cpData.z == kModeContinous), edgeUpdated = false;
  696. if (false == continueStrip || 0 == activeSegmentIndex)
  697. angle = SlopeAngle(iscpNext.position, iscp.position);
  698. bool resolved = ResolveAngle(angle, pointData.x, ref pointInfo.y, ref pointData.w, ref firstSpriteIndex);
  699. if (!resolved && !skipSegmenting)
  700. {
  701. // If we do not resolve SpriteIndex (AngleRange) just continue existing segment.
  702. pointData.w = activeSpriteIndex;
  703. iscp.cpData = pointData;
  704. m_ControlPoints[i] = iscp;
  705. // Insert Dummy Segment.
  706. activeSegment = m_Segments[activeSegmentIndex];
  707. activeSegment.sgInfo.x = mn;
  708. activeSegment.sgInfo.y = mx;
  709. activeSegment.sgInfo.z = -1;
  710. m_Segments[activeSegmentIndex] = activeSegment;
  711. activeSegmentIndex++;
  712. continue;
  713. }
  714. // Update current Point.
  715. activeSpriteIndex = pointData.w;
  716. iscp.cpData = pointData;
  717. iscp.cpInfo = pointInfo;
  718. m_ControlPoints[i] = iscp;
  719. if (skipSegmenting)
  720. continue;
  721. // Check for Segments. Also check if the Segment Start has been resolved. Otherwise simply start with the next one.
  722. if (activeSegmentIndex != 0)
  723. continueStrip = continueStrip && (m_SpriteIndices[activeSegment.sgInfo.x].y != 0 && activeSpriteIndex == activeSegment.sgInfo.z);
  724. if (continueStrip && i != (controlPointCount - 1))
  725. {
  726. for (int s = 0; s < activeSegmentIndex; ++s)
  727. {
  728. activeSegment = m_Segments[s];
  729. if (activeSegment.sgInfo.x - mn == 1)
  730. {
  731. edgeUpdated = true;
  732. activeSegment.sgInfo.x = mn;
  733. m_Segments[s] = activeSegment;
  734. break;
  735. }
  736. if (mx - activeSegment.sgInfo.y == 1)
  737. {
  738. edgeUpdated = true;
  739. activeSegment.sgInfo.y = mx;
  740. m_Segments[s] = activeSegment;
  741. break;
  742. }
  743. }
  744. }
  745. if (!edgeUpdated)
  746. {
  747. activeSegment = m_Segments[activeSegmentIndex];
  748. JobSpriteInfo sprLt = GetSpriteInfo(iscp.cpData.w);
  749. activeSegment.sgInfo.x = mn;
  750. activeSegment.sgInfo.y = mx;
  751. activeSegment.sgInfo.z = activeSpriteIndex;
  752. activeSegment.sgInfo.w = firstSpriteIndex;
  753. activeSegment.spriteInfo.x = sprLt.texRect.z;
  754. activeSegment.spriteInfo.y = sprLt.texRect.w;
  755. activeSegment.spriteInfo.z = pointInfo.y;
  756. m_Segments[activeSegmentIndex] = activeSegment;
  757. activeSegmentIndex++;
  758. }
  759. }
  760. m_SegmentCount = activeSegmentIndex;
  761. }
  762. void UpdateSegments()
  763. {
  764. // Determine Distance of Segment.
  765. for (int i = 0; i < segmentCount; ++i)
  766. {
  767. // Calculate Segment Distances.
  768. JobSegmentInfo isi = GetSegmentInfo(i);
  769. if (isi.spriteInfo.z >= 0)
  770. {
  771. isi.spriteInfo.w = SegmentDistance(isi);
  772. m_Segments[i] = isi;
  773. }
  774. }
  775. }
  776. bool GetSegmentBoundaryColumn(JobSegmentInfo segment, JobSpriteInfo sprInfo, float2 whsize, float2 startPos, float2 endPos, bool end, ref float2 top, ref float2 bottom)
  777. {
  778. bool res = false;
  779. float pivot = 0.5f - sprInfo.metaInfo.y;
  780. if (!end)
  781. {
  782. JobControlPoint icp = GetControlPoint(segment.sgInfo.x);
  783. if (math.any(icp.tangentRt))
  784. endPos = icp.tangentRt + startPos;
  785. res = GenerateColumnsBi(startPos, endPos, whsize, end, ref top, ref bottom, icp.cpInfo.x * 0.5f, pivot);
  786. }
  787. else
  788. {
  789. JobControlPoint jcp = GetControlPoint(segment.sgInfo.y);
  790. if (math.any(jcp.tangentLt))
  791. endPos = jcp.tangentLt + startPos;
  792. res = GenerateColumnsBi(startPos, endPos, whsize, end, ref top, ref bottom, jcp.cpInfo.x * 0.5f, pivot);
  793. }
  794. return res;
  795. }
  796. void GenerateControlPoints()
  797. {
  798. // Globals.
  799. int activePoint = 0, activeIndex = 0;
  800. int startPoint = 0, endPoint = controlPointCount, lastPoint = (controlPointCount - 1);
  801. int2 sprData = new int2(0, 0);
  802. // Calc and calculate Indices.
  803. for (int i = 0; i < controlPointCount; ++i)
  804. {
  805. var resolved = 0;
  806. int spriteIndex = GetSpriteIndex(i, activeIndex, ref resolved);
  807. sprData.x = activeIndex = spriteIndex;
  808. sprData.y = resolved;
  809. m_SpriteIndices[i] = sprData;
  810. }
  811. // Open-Ended. We simply dont allow Continous mode in End-points.
  812. if (!isCarpet)
  813. {
  814. JobControlPoint cp = GetControlPoint(0);
  815. cp.cpData.z = (cp.cpData.z == kModeContinous) ? kModeBroken : cp.cpData.z;
  816. m_GeneratedControlPoints[activePoint++] = cp;
  817. // If its not carpet, we already pre-insert start and endpoint.
  818. startPoint = 1;
  819. endPoint = controlPointCount - 1;
  820. }
  821. // Generate Intermediates.
  822. for (int i = startPoint; i < endPoint; ++i)
  823. {
  824. // Check if the Neighbor Points are all in Linear Mode.
  825. bool cornerCriteriaMet = false;
  826. bool vc = InsertCorner(i, ref m_SpriteIndices, ref m_GeneratedControlPoints, ref activePoint, ref cornerCriteriaMet);
  827. if (vc)
  828. continue;
  829. // NO Corners.
  830. var cp = GetControlPoint(i);
  831. cp.exData.z = (cornerCriteriaMet && cp.cpData.y == 2) ? 1 : 0; // Set this to stretched of Corner criteria met but no corner sprites but stretched corner.
  832. m_GeneratedControlPoints[activePoint++] = cp;
  833. }
  834. // Open-Ended.
  835. if (!isCarpet)
  836. {
  837. // Fixup for End-Points and Point-Mode.
  838. JobControlPoint sp = m_GeneratedControlPoints[0];
  839. sp.exData.z = 1;
  840. m_GeneratedControlPoints[0] = sp;
  841. JobControlPoint cp = GetControlPoint(endPoint);
  842. cp.cpData.z = (cp.cpData.z == kModeContinous) ? kModeBroken : cp.cpData.z;
  843. cp.exData.z = 1;
  844. m_GeneratedControlPoints[activePoint++] = cp;
  845. }
  846. // If Closed Shape
  847. else
  848. {
  849. JobControlPoint cp = m_GeneratedControlPoints[0];
  850. m_GeneratedControlPoints[activePoint++] = cp;
  851. }
  852. // Copy from these intermediate Points to main Control Points.
  853. for (int i = 0; i < activePoint; ++i)
  854. m_ControlPoints[i] = m_GeneratedControlPoints[i];
  855. m_ControlPointCount = activePoint;
  856. // Calc and calculate Indices.
  857. for (int i = 0; i < controlPointCount; ++i)
  858. {
  859. var resolved = 0;
  860. int spriteIndex = GetSpriteIndex(i, activeIndex, ref resolved);
  861. sprData.x = activeIndex = spriteIndex;
  862. sprData.y = resolved;
  863. m_SpriteIndices[i] = sprData;
  864. }
  865. }
  866. float SegmentDistance(JobSegmentInfo isi)
  867. {
  868. float distance = 0;
  869. int stIx = GetContourIndex(isi.sgInfo.x);
  870. int enIx = GetEndContourIndexOfSegment(isi);
  871. for (int i = stIx; i < enIx; ++i)
  872. {
  873. int j = i + 1;
  874. JobContourPoint lt = GetContourPoint(i);
  875. JobContourPoint rt = GetContourPoint(j);
  876. distance = distance + math.distance(lt.position, rt.position);
  877. }
  878. return distance;
  879. }
  880. void GenerateContour()
  881. {
  882. int controlPointContour = controlPointCount - 1;
  883. // Expand the Bezier.
  884. int ap = 0;
  885. float fmax = (float)(splineDetail - 1);
  886. for (int i = 0; i < controlPointContour; ++i)
  887. {
  888. int j = i + 1;
  889. JobControlPoint cp = GetControlPoint(i);
  890. JobControlPoint pp = GetControlPoint(j);
  891. var smoothInterp = cp.exData.w == kModeContinous || pp.exData.w == kModeContinous;
  892. float2 p0 = cp.position;
  893. float2 p1 = pp.position;
  894. float2 sp = p0;
  895. float2 rt = p0 + cp.tangentRt;
  896. float2 lt = p1 + pp.tangentLt;
  897. int cap = ap;
  898. float spd = 0, cpd = 0;
  899. for (int n = 0; n < splineDetail; ++n)
  900. {
  901. JobContourPoint xp = m_ContourPoints[ap];
  902. float t = (float) n / fmax;
  903. float2 bp = BezierPoint(rt, p0, p1, lt, t);
  904. xp.position = bp;
  905. spd += math.distance(bp, sp);
  906. m_ContourPoints[ap++] = xp;
  907. sp = bp;
  908. }
  909. sp = p0;
  910. for (int n = 0; n < splineDetail; ++n)
  911. {
  912. JobContourPoint xp = m_ContourPoints[cap];
  913. cpd += math.distance(xp.position, sp);
  914. xp.ptData.x = smoothInterp ? InterpolateSmooth(cp.cpInfo.x, pp.cpInfo.x, cpd / spd) : InterpolateLinear(cp.cpInfo.x, pp.cpInfo.x, cpd / spd);
  915. m_ContourPoints[cap++] = xp;
  916. sp = xp.position;
  917. }
  918. }
  919. // End
  920. m_ContourPointCount = ap;
  921. int tessPoints = 0;
  922. // Create Tessallator if required.
  923. for (int i = 0; i < contourPointCount; ++i)
  924. {
  925. if ((i + 1) % splineDetail == 0)
  926. continue;
  927. int h = (i == 0) ? (contourPointCount - 1) : (i - 1);
  928. int j = (i + 1) % contourPointCount;
  929. h = (i % splineDetail == 0) ? (h - 1) : h;
  930. JobContourPoint pp = GetContourPoint(h);
  931. JobContourPoint cp = GetContourPoint(i);
  932. JobContourPoint np = GetContourPoint(j);
  933. float2 cpd = cp.position - pp.position;
  934. float2 npd = np.position - cp.position;
  935. if (math.length(cpd) < kEpsilon || math.length(npd) < kEpsilon)
  936. continue;
  937. float2 vl = math.normalize(cpd);
  938. float2 vr = math.normalize(npd);
  939. vl = new float2(-vl.y, vl.x);
  940. vr = new float2(-vr.y, vr.x);
  941. float2 va = math.normalize(vl) + math.normalize(vr);
  942. float2 vn = math.normalize(va);
  943. if (math.any(va) && math.any(vn))
  944. m_TessPoints[tessPoints++] = cp.position + (vn * borderPivot);
  945. }
  946. m_TessPointCount = tessPoints;
  947. }
  948. // Burstable UTess2D Version.
  949. void TessellateContour()
  950. {
  951. // Generate Contour
  952. GenerateContour();
  953. // Fill Geom. Generate in Native code until we have a reasonably fast enough Tessellation in NativeArray based Jobs.
  954. SpriteShapeSegment geom = m_GeomArray[0];
  955. geom.vertexCount = 0;
  956. geom.geomIndex = 0;
  957. geom.indexCount = 0;
  958. geom.spriteIndex = -1;
  959. // Fill Geometry. Check if Fill Texture and Fill Scale is Valid.
  960. if (math.all(m_ShapeParams.shapeData.xw))
  961. {
  962. // Fill Geometry. Check if Fill Texture and Fill Scale is Valid.
  963. if (m_TessPointCount > 0)
  964. {
  965. if (kOptimizeRender > 0)
  966. OptimizePoints(kRenderQuality, ref m_TessPoints, ref m_TessPointCount);
  967. int dataLength = m_TessPointCount;
  968. NativeArray<int2> edges = new NativeArray<int2>(dataLength - 1, Allocator.Temp);
  969. NativeArray<float2> points = new NativeArray<float2>(dataLength - 1, Allocator.Temp);
  970. for (int i = 0; i < points.Length; ++i)
  971. points[i] = m_TessPoints[i];
  972. for (int i = 0; i < dataLength - 2; ++i)
  973. {
  974. int2 te = edges[i];
  975. te.x = i;
  976. te.y = i + 1;
  977. edges[i] = te;
  978. }
  979. int2 tee = edges[dataLength - 2];
  980. tee.x = dataLength - 2;
  981. tee.y = 0;
  982. edges[dataLength - 2] = tee;
  983. int ovc = 0, oic = 0, oec = 0;
  984. NativeArray<float2> ov = new NativeArray<float2>(m_TessPointCount * m_TessPointCount, Allocator.Temp);
  985. NativeArray<int> oi = new NativeArray<int>(m_TessPointCount * m_TessPointCount, Allocator.Temp);
  986. NativeArray<int2> oe = new NativeArray<int2>(m_TessPointCount * m_TessPointCount, Allocator.Temp);
  987. UnityEngine.U2D.Common.UTess.ModuleHandle.Tessellate(Allocator.Temp, points, edges, ref ov, out ovc, ref oi, out oic, ref oe, out oec);
  988. if (oic > 0)
  989. {
  990. for (m_ActiveIndexCount = 0; m_ActiveIndexCount < oic; ++m_ActiveIndexCount)
  991. m_IndexArray[m_ActiveIndexCount] = (ushort) oi[m_ActiveIndexCount];
  992. for (m_ActiveVertexCount = 0; m_ActiveVertexCount < ovc; ++m_ActiveVertexCount)
  993. m_PosArray[m_ActiveVertexCount] = new Vector3(ov[m_ActiveVertexCount].x, ov[m_ActiveVertexCount].y, 0);
  994. m_IndexDataCount = geom.indexCount = m_ActiveIndexCount;
  995. m_VertexDataCount = geom.vertexCount = m_ActiveVertexCount;
  996. }
  997. ov.Dispose();
  998. oi.Dispose();
  999. oe.Dispose();
  1000. edges.Dispose();
  1001. points.Dispose();
  1002. }
  1003. }
  1004. if (m_TanArray.Length > 1)
  1005. {
  1006. for (int i = 0; i < m_ActiveVertexCount; ++i)
  1007. m_TanArray[i] = new Vector4(1.0f, 0, 0, -1.0f);
  1008. }
  1009. m_GeomArray[0] = geom;
  1010. }
  1011. void TessellateContourMainThread()
  1012. {
  1013. // Generate Contour
  1014. GenerateContour();
  1015. // Fill Geom. Generate in Native code until we have a reasonably fast enough Tessellation in NativeArray based Jobs.
  1016. SpriteShapeSegment geom = m_GeomArray[0];
  1017. geom.vertexCount = 0;
  1018. geom.geomIndex = 0;
  1019. geom.indexCount = 0;
  1020. geom.spriteIndex = -1;
  1021. // Fill Geometry. Check if Fill Texture and Fill Scale is Valid.
  1022. if (math.all(m_ShapeParams.shapeData.xw))
  1023. {
  1024. // Fill Geometry. Check if Fill Texture and Fill Scale is Valid.
  1025. if (m_TessPointCount > 0)
  1026. {
  1027. if (kOptimizeRender > 0)
  1028. OptimizePoints(kRenderQuality, ref m_TessPoints, ref m_TessPointCount);
  1029. var inputs = new ContourVertex[m_TessPointCount];
  1030. for (int i = 0; i < m_TessPointCount; ++i)
  1031. inputs[i] = new ContourVertex() { Position = new Vec3() { X = m_TessPoints[i].x, Y = m_TessPoints[i].y } };
  1032. Tess tess = new Tess();
  1033. tess.AddContour(inputs, ContourOrientation.Original);
  1034. tess.Tessellate(WindingRule.NonZero, ElementType.Polygons, 3);
  1035. var indices = tess.Elements.Select(i => (UInt16)i).ToArray();
  1036. var vertices = tess.Vertices.Select(v => new Vector2(v.Position.X, v.Position.Y)).ToArray();
  1037. m_IndexDataCount = indices.Length;
  1038. m_VertexDataCount = vertices.Length;
  1039. if (vertices.Length > 0)
  1040. {
  1041. for (m_ActiveIndexCount = 0; m_ActiveIndexCount < m_IndexDataCount; ++m_ActiveIndexCount)
  1042. {
  1043. m_IndexArray[m_ActiveIndexCount] = indices[m_ActiveIndexCount];
  1044. }
  1045. for (m_ActiveVertexCount = 0; m_ActiveVertexCount < m_VertexDataCount; ++m_ActiveVertexCount)
  1046. {
  1047. var pos = new Vector3(vertices[m_ActiveVertexCount].x, vertices[m_ActiveVertexCount].y, 0);
  1048. m_PosArray[m_ActiveVertexCount] = pos;
  1049. }
  1050. geom.indexCount = m_ActiveIndexCount;
  1051. geom.vertexCount = m_ActiveVertexCount;
  1052. }
  1053. }
  1054. }
  1055. if (m_TanArray.Length > 1)
  1056. {
  1057. for (int i = 0; i < m_ActiveVertexCount; ++i)
  1058. m_TanArray[i] = new Vector4(1.0f, 0, 0, -1.0f);
  1059. }
  1060. m_GeomArray[0] = geom;
  1061. }
  1062. void CalculateBoundingBox()
  1063. {
  1064. if (vertexArrayCount == 0 && contourPointCount == 0)
  1065. return;
  1066. var bounds = new Bounds();
  1067. var min = vertexArrayCount != 0 ? new float2(m_PosArray[0].x, m_PosArray[0].y) : new float2(m_ContourPoints[0].position.x, m_ContourPoints[0].position.y);
  1068. var max = min;
  1069. {
  1070. for (int i = 0; i < vertexArrayCount; ++i)
  1071. {
  1072. float3 pos = m_PosArray[i];
  1073. min = math.min(min, pos.xy);
  1074. max = math.max(max, pos.xy);
  1075. }
  1076. }
  1077. {
  1078. for (int i = 0; i < contourPointCount; ++i)
  1079. {
  1080. float2 pos = new float2(m_ContourPoints[i].position.x, m_ContourPoints[i].position.y);
  1081. min = math.min(min, pos);
  1082. max = math.max(max, pos);
  1083. }
  1084. }
  1085. bounds.SetMinMax(new Vector3(min.x, min.y, 0), new Vector3(max.x, max.y, 0));
  1086. m_Bounds[0] = bounds;
  1087. }
  1088. void CalculateTexCoords()
  1089. {
  1090. SpriteShapeSegment geom = m_GeomArray[0];
  1091. if (m_ShapeParams.splineData.x > 0)
  1092. {
  1093. float3 ext = m_Bounds[0].extents * 2;
  1094. float3 min = m_Bounds[0].center - m_Bounds[0].extents;
  1095. for (int i = 0; i < geom.vertexCount; ++i)
  1096. {
  1097. Vector3 pos = m_PosArray[i];
  1098. Vector2 uv0 = m_Uv0Array[i];
  1099. float3 uv = ((new float3(pos.x, pos.y, pos.z) - min) / ext) * m_ShapeParams.fillData.x;
  1100. uv0.x = uv.x;
  1101. uv0.y = uv.y;
  1102. m_Uv0Array[i] = uv0;
  1103. }
  1104. }
  1105. else
  1106. {
  1107. for (int i = 0; i < geom.vertexCount; ++i)
  1108. {
  1109. Vector3 pos = m_PosArray[i];
  1110. Vector2 uv0 = m_Uv0Array[i];
  1111. float3 uv = math.transform(m_Transform, new float3(pos.x, pos.y, pos.z));
  1112. uv0.x = uv.x / m_ShapeParams.fillData.y;
  1113. uv0.y = uv.y / m_ShapeParams.fillData.z;
  1114. m_Uv0Array[i] = uv0;
  1115. }
  1116. }
  1117. }
  1118. void CopyVertexData(ref NativeSlice<Vector3> outPos, ref NativeSlice<Vector2> outUV0, ref NativeSlice<Vector4> outTan, int outIndex, NativeArray<JobShapeVertex> inVertices, int inIndex, float sOrder)
  1119. {
  1120. Vector3 iscp = outPos[outIndex];
  1121. Vector2 iscu = outUV0[outIndex];
  1122. float3 v0 = new float3(inVertices[inIndex].pos.x, inVertices[inIndex].pos.y, sOrder);
  1123. float3 v1 = new float3(inVertices[inIndex + 1].pos.x, inVertices[inIndex + 1].pos.y, sOrder);
  1124. float3 v2 = new float3(inVertices[inIndex + 2].pos.x, inVertices[inIndex + 2].pos.y, sOrder);
  1125. float3 v3 = new float3(inVertices[inIndex + 3].pos.x, inVertices[inIndex + 3].pos.y, sOrder);
  1126. outPos[outIndex] = v0;
  1127. outUV0[outIndex] = inVertices[inIndex].uv;
  1128. outPos[outIndex + 1] = v1;
  1129. outUV0[outIndex + 1] = inVertices[inIndex + 1].uv;
  1130. outPos[outIndex + 2] = v2;
  1131. outUV0[outIndex + 2] = inVertices[inIndex + 2].uv;
  1132. outPos[outIndex + 3] = v3;
  1133. outUV0[outIndex + 3] = inVertices[inIndex + 3].uv;
  1134. if (outTan.Length > 1)
  1135. {
  1136. outTan[outIndex] = inVertices[inIndex].tan;
  1137. outTan[outIndex + 1] = inVertices[inIndex + 1].tan;
  1138. outTan[outIndex + 2] = inVertices[inIndex + 2].tan;
  1139. outTan[outIndex + 3] = inVertices[inIndex + 3].tan;
  1140. }
  1141. }
  1142. int CopySegmentRenderData(JobSpriteInfo ispr, ref NativeSlice<Vector3> outPos, ref NativeSlice<Vector2> outUV0, ref NativeSlice<Vector4> outTan, ref int outCount, ref NativeArray<ushort> indexData, ref int indexCount, NativeArray<JobShapeVertex> inVertices, int inCount, float sOrder)
  1143. {
  1144. if (inCount < 4)
  1145. return -1;
  1146. int localVertex = 0;
  1147. int finalCount = indexCount + inCount + (inCount / 2);
  1148. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  1149. if (finalCount >= indexData.Length)
  1150. throw new InvalidOperationException(
  1151. $"Mesh data has reached Limits. Please try dividing shape into smaller blocks.");
  1152. #endif
  1153. for (int i = 0; i < inCount; i = i + 4, outCount = outCount + 4, localVertex = localVertex + 4)
  1154. {
  1155. CopyVertexData(ref outPos, ref outUV0, ref outTan, outCount, inVertices, i, sOrder);
  1156. indexData[indexCount++] = (ushort) (localVertex);
  1157. indexData[indexCount++] = (ushort) (3 + localVertex);
  1158. indexData[indexCount++] = (ushort) (1 + localVertex);
  1159. indexData[indexCount++] = (ushort) (localVertex);
  1160. indexData[indexCount++] = (ushort) (2 + localVertex);
  1161. indexData[indexCount++] = (ushort) (3 + localVertex);
  1162. }
  1163. return outCount;
  1164. }
  1165. void GetLineSegments(JobSpriteInfo sprInfo, JobSegmentInfo segment, float2 whsize, ref float2 vlt,
  1166. ref float2 vlb, ref float2 vrt, ref float2 vrb)
  1167. {
  1168. JobControlPoint scp = GetControlPoint(segment.sgInfo.x);
  1169. JobControlPoint ecp = GetControlPoint(segment.sgInfo.y);
  1170. GetSegmentBoundaryColumn(segment, sprInfo, whsize, scp.position, ecp.position, false, ref vlt, ref vlb);
  1171. GetSegmentBoundaryColumn(segment, sprInfo, whsize, ecp.position, scp.position, true, ref vrt, ref vrb);
  1172. }
  1173. void TessellateSegment(int segmentIndex, JobSpriteInfo sprInfo, JobSegmentInfo segment, float2 whsize, float4 border,
  1174. float pxlWidth, NativeArray<JobShapeVertex> vertices, int vertexCount, bool useClosure, bool validHead, bool validTail,
  1175. bool firstSegment, bool finalSegment, ref NativeArray<JobShapeVertex> outputVertices, ref int outputCount)
  1176. {
  1177. int outputVertexCount = 0;
  1178. float2 zero = float2.zero;
  1179. float2 lt = zero, lb = zero, rt = zero, rb = zero;
  1180. float4 stretcher = new float4(1.0f, 1.0f, 0, 0);
  1181. var column0 = new JobShapeVertex();
  1182. var column1 = new JobShapeVertex();
  1183. var column2 = new JobShapeVertex();
  1184. var column3 = new JobShapeVertex();
  1185. int cms = vertexCount - 1;
  1186. int lcm = cms - 1;
  1187. int expectedCount = outputCount + (cms * 4);
  1188. var sprite = vertices[0].sprite;
  1189. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  1190. if (expectedCount >= outputVertices.Length)
  1191. throw new InvalidOperationException($"Mesh data has reached Limits. Please try dividing shape into smaller blocks.");
  1192. #endif
  1193. float uvDist = 0;
  1194. float uvStart = border.x;
  1195. float uvEnd = whsize.x - border.z;
  1196. float uvTotal = whsize.x;
  1197. float uvInter = uvEnd - uvStart;
  1198. float uvNow = uvStart / uvTotal;
  1199. float dt = uvInter / pxlWidth;
  1200. float pivot = 0.5f - sprInfo.metaInfo.y;
  1201. //// //// //// //// Stretch
  1202. bool stretchCorners = false;
  1203. bool stretchSegment = math.abs(segment.sgInfo.x - segment.sgInfo.y) == 1;
  1204. if (stretchSegment && segmentCount > 1)
  1205. stretchCorners = FetchStretcher(segmentIndex, sprInfo, segment, whsize, validHead, validTail, ref stretcher);
  1206. //// //// //// //// Stretch
  1207. // Generate Render Inputs.
  1208. for (int i = 0; i < cms; ++i)
  1209. {
  1210. bool lc = (cms > 1) && (i == lcm);
  1211. bool im = (i != 0 && !lc);
  1212. JobShapeVertex cs = vertices[i];
  1213. JobShapeVertex ns = vertices[i + 1];
  1214. float2 es = lc ? cs.pos : vertices[i + 2].pos;
  1215. lt = column1.pos;
  1216. lb = column3.pos;
  1217. if (im)
  1218. {
  1219. // Left from Previous.
  1220. GenerateColumnsTri(cs.pos, ns.pos, es, whsize, lc, ref rt, ref rb, ns.meta.x * 0.5f, pivot);
  1221. }
  1222. else
  1223. {
  1224. if (!lc)
  1225. {
  1226. GetSegmentBoundaryColumn(segment, sprInfo, whsize, cs.pos, ns.pos, false, ref lt, ref lb);
  1227. }
  1228. if (lc && useClosure)
  1229. {
  1230. rb = m_FirstLB;
  1231. rt = m_FirstLT;
  1232. }
  1233. else
  1234. {
  1235. GetSegmentBoundaryColumn(segment, sprInfo, whsize, ns.pos, es, lc, ref rt, ref rb);
  1236. }
  1237. }
  1238. if (i == 0 && segment.sgInfo.x == 0)
  1239. {
  1240. m_FirstLB = lb;
  1241. m_FirstLT = lt;
  1242. }
  1243. if (!((math.any(lt) || math.any(lb)) && (math.any(rt) || math.any(rb))))
  1244. continue;
  1245. // default tan (1, 0, 0, -1) which is along uv. same here.
  1246. float2 nlt = math.normalize(rt - lt);
  1247. float4 tan = new float4(nlt.x, nlt.y, 0, -1.0f);
  1248. column0.pos = lt;
  1249. column0.meta = cs.meta;
  1250. column0.sprite = sprite;
  1251. column0.tan = tan;
  1252. column1.pos = rt;
  1253. column1.meta = ns.meta;
  1254. column1.sprite = sprite;
  1255. column1.tan = tan;
  1256. column2.pos = lb;
  1257. column2.meta = cs.meta;
  1258. column2.sprite = sprite;
  1259. column2.tan = tan;
  1260. column3.pos = rb;
  1261. column3.meta = ns.meta;
  1262. column3.sprite = sprite;
  1263. column3.tan = tan;
  1264. // Calculate UV.
  1265. if (validHead && i == 0)
  1266. {
  1267. column0.uv.x = column0.uv.y = column1.uv.y = column2.uv.x = 0;
  1268. column1.uv.x = column3.uv.x = border.x / whsize.x;
  1269. column2.uv.y = column3.uv.y = 1.0f;
  1270. column0.sprite.z = column2.sprite.z = firstSegment ? 0 : 1;
  1271. }
  1272. else if (validTail && i == lcm)
  1273. {
  1274. column0.uv.y = column1.uv.y = 0;
  1275. column0.uv.x = column2.uv.x = (whsize.x - border.z) / whsize.x;
  1276. column1.uv.x = column2.uv.y = column3.uv.x = column3.uv.y = 1.0f;
  1277. column1.sprite.z = column3.sprite.z = finalSegment ? 0 : 1;
  1278. }
  1279. else
  1280. {
  1281. if ((uvInter - uvDist) < kEpsilonRelaxed)
  1282. {
  1283. uvNow = uvStart / uvTotal;
  1284. uvDist = 0;
  1285. }
  1286. uvDist = uvDist + (math.distance(ns.pos, cs.pos) * dt);
  1287. float uvNext = (uvDist + uvStart) / uvTotal;
  1288. if ((uvDist - uvInter) > kEpsilonRelaxed)
  1289. {
  1290. uvNext = uvEnd / uvTotal;
  1291. uvDist = uvEnd;
  1292. }
  1293. column0.uv.y = column1.uv.y = 0;
  1294. column0.uv.x = column2.uv.x = uvNow;
  1295. column1.uv.x = column3.uv.x = uvNext;
  1296. column2.uv.y = column3.uv.y = 1.0f;
  1297. uvNow = uvNext;
  1298. }
  1299. {
  1300. // Fix UV and Copy.
  1301. column0.uv.x = (column0.uv.x * sprInfo.uvInfo.z) + sprInfo.uvInfo.x;
  1302. column0.uv.y = (column0.uv.y * sprInfo.uvInfo.w) + sprInfo.uvInfo.y;
  1303. outputVertices[outputVertexCount++] = column0;
  1304. column1.uv.x = (column1.uv.x * sprInfo.uvInfo.z) + sprInfo.uvInfo.x;
  1305. column1.uv.y = (column1.uv.y * sprInfo.uvInfo.w) + sprInfo.uvInfo.y;
  1306. outputVertices[outputVertexCount++] = column1;
  1307. column2.uv.x = (column2.uv.x * sprInfo.uvInfo.z) + sprInfo.uvInfo.x;
  1308. column2.uv.y = (column2.uv.y * sprInfo.uvInfo.w) + sprInfo.uvInfo.y;
  1309. outputVertices[outputVertexCount++] = column2;
  1310. column3.uv.x = (column3.uv.x * sprInfo.uvInfo.z) + sprInfo.uvInfo.x;
  1311. column3.uv.y = (column3.uv.y * sprInfo.uvInfo.w) + sprInfo.uvInfo.y;
  1312. outputVertices[outputVertexCount++] = column3;
  1313. }
  1314. }
  1315. //// //// //// //// Stretch
  1316. if (stretchCorners)
  1317. StretchCorners(segment, outputVertices, outputVertexCount, validHead, validTail, stretcher);
  1318. //// //// //// //// Stretch
  1319. outputCount = outputVertexCount;
  1320. }
  1321. bool SkipSegment(JobSegmentInfo isi)
  1322. {
  1323. // Start the Generation.
  1324. bool skip = (isi.sgInfo.z < 0);
  1325. if (!skip)
  1326. {
  1327. JobSpriteInfo ispr = GetSpriteInfo(isi.sgInfo.z);
  1328. skip = (math.any(ispr.uvInfo) == false);
  1329. }
  1330. if (skip)
  1331. {
  1332. int cis = GetContourIndex(isi.sgInfo.x);
  1333. int cie = GetEndContourIndexOfSegment(isi);
  1334. while (cis < cie)
  1335. {
  1336. JobContourPoint icp = GetContourPoint(cis);
  1337. m_ColliderPoints[m_ColliderDataCount++] = icp.position;
  1338. cis++;
  1339. }
  1340. }
  1341. return skip;
  1342. }
  1343. float InterpolateLinear(float a, float b, float t)
  1344. {
  1345. return math.lerp(a, b, t);
  1346. }
  1347. float InterpolateSmooth(float a, float b, float t)
  1348. {
  1349. float mu2 = (1.0f - math.cos(t * math.PI)) / 2.0f;
  1350. return (a * (1 - mu2) + b * mu2);
  1351. }
  1352. void TessellateSegments()
  1353. {
  1354. JobControlPoint iscp = GetControlPoint(0);
  1355. bool disableHead = (iscp.cpData.z == kModeContinous && isCarpet);
  1356. float2 zero = new float2(0, 0);
  1357. float2 ec = zero;
  1358. for (int i = 0; i < segmentCount; ++i)
  1359. {
  1360. // Tessellate the Segment.
  1361. JobSegmentInfo isi = GetSegmentInfo(i);
  1362. bool skip = SkipSegment(isi);
  1363. if (skip)
  1364. continue;
  1365. // Internal Data : x, y : pos z : height w : renderIndex
  1366. JobShapeVertex isv = new JobShapeVertex();
  1367. JobSpriteInfo ispr = GetSpriteInfo(isi.sgInfo.z);
  1368. int vertexCount = 0;
  1369. int sprIx = isi.sgInfo.z;
  1370. float rpunits = 1.0f / ispr.metaInfo.x;
  1371. float2 whsize = new float2(ispr.metaInfo.z, ispr.metaInfo.w) * rpunits;
  1372. float4 border = ispr.border * rpunits;
  1373. JobControlPoint _scp = GetControlPoint(isi.sgInfo.x);
  1374. JobControlPoint _ecp = GetControlPoint(isi.sgInfo.y);
  1375. bool useClosure = (m_ControlPoints[0].cpData.z == kModeContinous) && (isi.sgInfo.y == controlPointCount - 1);
  1376. bool firstSegment = (i == 0) && !isCarpet && !useClosure;
  1377. bool validHead = hasSpriteBorder && (border.x > 0) && ((_scp.exData.z == 0) || firstSegment);
  1378. validHead = (m_ControlPoints[0].cpData.z == kModeContinous) ? (validHead && !isCarpet) : validHead;
  1379. bool finalSegment = (i == segmentCount - 1) && !isCarpet && !useClosure;
  1380. bool validTail = hasSpriteBorder && (border.z > 0) && ((_ecp.exData.z == 0) || finalSegment);
  1381. validTail = (m_ControlPoints[0].cpData.z == kModeContinous) ? (validTail && !isCarpet) : validTail;
  1382. // Generate the UV Increments.
  1383. float extendUV = 0;
  1384. float stPixelU = border.x;
  1385. float enPixelU = whsize.x - border.z;
  1386. float pxlWidth = enPixelU - stPixelU;
  1387. float segmentD = isi.spriteInfo.w;
  1388. float uIncStep = math.floor(segmentD / pxlWidth);
  1389. uIncStep = uIncStep == 0 ? 1f : uIncStep;
  1390. pxlWidth = isAdaptive ? (segmentD / uIncStep) : pxlWidth;
  1391. // Check for any invalid Sizes.
  1392. if (pxlWidth < kEpsilon)
  1393. {
  1394. Cleanup();
  1395. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  1396. throw new ArgumentException($"One of the sprites seem to have Invalid Borders. Please check Input Sprites.");
  1397. #endif
  1398. }
  1399. // Start the Generation.
  1400. int stIx = GetContourIndex(isi.sgInfo.x);
  1401. int enIx = GetEndContourIndexOfSegment(isi);
  1402. // Single Segment Loop.
  1403. if (stIx == 0)
  1404. validHead = (validHead && !disableHead);
  1405. // Do we have a Sprite Head Slice
  1406. if (validHead)
  1407. {
  1408. JobContourPoint icp = GetContourPoint(stIx);
  1409. float2 v1 = icp.position;
  1410. float2 v2 = GetContourPoint(stIx + 1).position;
  1411. isv.pos = v1 + (math.normalize(v1 - v2) * border.x);
  1412. isv.meta.x = icp.ptData.x;
  1413. isv.sprite.x = sprIx;
  1414. m_VertexData[vertexCount++] = isv;
  1415. }
  1416. // Generate the Strip.
  1417. float sl = 0;
  1418. int it = stIx, nt = 0;
  1419. isv.sprite.z = 0;
  1420. while (it < enIx)
  1421. {
  1422. nt = it + 1;
  1423. JobContourPoint icp = GetContourPoint(it);
  1424. JobContourPoint ncp = GetContourPoint(nt);
  1425. float2 sp = icp.position;
  1426. float2 ip = sp;
  1427. float2 ep = ncp.position;
  1428. float2 df = ep - sp;
  1429. float al = math.length(df);
  1430. if (al > kEpsilon)
  1431. {
  1432. float sh = icp.ptData.x, eh = ncp.ptData.x, hl = 0;
  1433. sl = sl + al;
  1434. // Connect previously left out space when sl < pxlWidth
  1435. var addtail = (0 == vertexCount);
  1436. float2 step = math.normalize(df);
  1437. isv.pos = icp.position;
  1438. isv.meta.x = icp.ptData.x;
  1439. isv.sprite.x = sprIx;
  1440. if (vertexCount > 0)
  1441. {
  1442. var dt = math.length(m_VertexData[vertexCount - 1].pos - isv.pos);
  1443. addtail = dt > kEpsilonRelaxed;
  1444. }
  1445. if (addtail)
  1446. m_VertexData[vertexCount++] = isv;
  1447. while (sl > pxlWidth)
  1448. {
  1449. float _uv = pxlWidth - extendUV;
  1450. float2 uv = new float2(_uv);
  1451. ip = sp + (step * uv);
  1452. hl = hl + math.length(ip - sp);
  1453. isv.pos = ip;
  1454. isv.meta.x = InterpolateLinear(sh, eh, hl / al);
  1455. isv.sprite.x = sprIx;
  1456. if (math.any(m_VertexData[vertexCount - 1].pos - isv.pos))
  1457. m_VertexData[vertexCount++] = isv;
  1458. sl = sl - pxlWidth;
  1459. sp = ip;
  1460. extendUV = 0;
  1461. }
  1462. extendUV = sl;
  1463. }
  1464. it++;
  1465. }
  1466. // The Remains from the above Loop. Finish the Curve.
  1467. if (sl > kEpsilon)
  1468. {
  1469. JobContourPoint ecp = GetContourPoint(enIx);
  1470. isv.pos = ecp.position;
  1471. isv.meta.x = ecp.ptData.x;
  1472. isv.sprite.x = sprIx;
  1473. m_VertexData[vertexCount++] = isv;
  1474. }
  1475. // Generate Tail
  1476. if (validTail)
  1477. {
  1478. JobContourPoint icp = GetContourPoint(enIx);
  1479. float2 v1 = icp.position;
  1480. float2 v2 = GetContourPoint(enIx - 1).position;
  1481. isv.pos = v1 + (math.normalize(v1 - v2) * border.z);
  1482. isv.meta.x = icp.ptData.x;
  1483. isv.sprite.x = sprIx;
  1484. m_VertexData[vertexCount++] = isv;
  1485. }
  1486. // Generate the Renderer Data.
  1487. int outputCount = 0;
  1488. TessellateSegment(i, ispr, isi, whsize, border, pxlWidth, m_VertexData, vertexCount, useClosure, validHead, validTail, firstSegment, finalSegment, ref m_OutputVertexData, ref outputCount);
  1489. if (outputCount == 0)
  1490. continue;
  1491. var z = ((float)(i + 1) * kEpsilonOrder) + ((float)isi.sgInfo.z * kEpsilonOrder * 0.001f);
  1492. CopySegmentRenderData(ispr, ref m_PosArray, ref m_Uv0Array, ref m_TanArray, ref m_VertexDataCount, ref m_IndexArray, ref m_IndexDataCount, m_OutputVertexData, outputCount, z);
  1493. if (hasCollider)
  1494. {
  1495. JobSpriteInfo isprc = (ispr.metaInfo.x == 0) ? GetSpriteInfo(isi.sgInfo.w) : ispr;
  1496. outputCount = 0;
  1497. rpunits = 1.0f / isprc.metaInfo.x;
  1498. whsize = new float2(isprc.metaInfo.z, isprc.metaInfo.w) * rpunits;
  1499. border = isprc.border * rpunits;
  1500. stPixelU = border.x;
  1501. enPixelU = whsize.x - border.z;
  1502. pxlWidth = enPixelU - stPixelU;
  1503. TessellateSegment(i, isprc, isi, whsize, border, pxlWidth, m_VertexData, vertexCount, useClosure, validHead, validTail, firstSegment, finalSegment, ref m_OutputVertexData, ref outputCount);
  1504. ec = UpdateCollider(isi, isprc, m_OutputVertexData, outputCount, ref m_ColliderPoints, ref m_ColliderDataCount);
  1505. }
  1506. // Geom Data
  1507. var geom = m_GeomArray[i + 1];
  1508. geom.geomIndex = i + 1;
  1509. geom.indexCount = m_IndexDataCount - m_ActiveIndexCount;
  1510. geom.vertexCount = m_VertexDataCount - m_ActiveVertexCount;
  1511. geom.spriteIndex = isi.sgInfo.z;
  1512. m_GeomArray[i + 1] = geom;
  1513. // Exit
  1514. m_ActiveIndexCount = m_IndexDataCount;
  1515. m_ActiveVertexCount = m_VertexDataCount;
  1516. }
  1517. // Copy Collider, Copy Render Data.
  1518. m_GeomArrayCount = segmentCount + 1;
  1519. m_IndexArrayCount = m_IndexDataCount;
  1520. m_VertexArrayCount = m_VertexDataCount;
  1521. m_ColliderPointCount = m_ColliderDataCount;
  1522. }
  1523. #endregion
  1524. #region Stretch.
  1525. bool FetchStretcher(int segmentIndex, JobSpriteInfo sprInfo, JobSegmentInfo segment, float2 whsize, bool validHead, bool validTail, ref float4 stretcher)
  1526. {
  1527. bool needsStretchL = false, needsStretchR = false;
  1528. int lastSegmentIndex = segmentCount - 1;
  1529. int prevSegmentIndex = segmentIndex == 0 ? lastSegmentIndex : segmentIndex - 1;
  1530. int nextSegmentIndex = segmentIndex == lastSegmentIndex ? 0 : segmentIndex + 1;
  1531. JobSegmentInfo prevSegment = GetSegmentInfo(prevSegmentIndex);
  1532. JobSegmentInfo nextSegment = GetSegmentInfo(nextSegmentIndex);
  1533. JobControlPoint scp = GetControlPoint(segment.sgInfo.x);
  1534. JobControlPoint ecp = GetControlPoint(segment.sgInfo.y);
  1535. var stretchLeft = (scp.cpData.y == 2) && math.abs(prevSegment.sgInfo.x - prevSegment.sgInfo.y) == 1;
  1536. var stretchRight = (ecp.cpData.y == 2) && math.abs(nextSegment.sgInfo.x - nextSegment.sgInfo.y) == 1;
  1537. var lastControlPoint = (controlPointCount - 1);
  1538. if (!isCarpet)
  1539. {
  1540. stretchLeft = stretchLeft && segment.sgInfo.x != 0;
  1541. stretchRight = stretchRight && segment.sgInfo.y != lastControlPoint;
  1542. }
  1543. if (stretchLeft || stretchRight)
  1544. {
  1545. // Get End points for current segment.
  1546. float2 avlt = float2.zero, avlb = float2.zero, avrt = float2.zero, avrb = float2.zero;
  1547. GetLineSegments(sprInfo, segment, whsize, ref avlt, ref avlb, ref avrt, ref avrb);
  1548. float2 _avlt = avlt, _avlb = avlb, _avrt = avrt, _avrb = avrb;
  1549. float2 ltp = avlt, lbt = avlb, rtp = avrt, rbt = avrb;
  1550. ExtendSegment(ref avlt, ref avrt);
  1551. ExtendSegment(ref avlb, ref avrb);
  1552. // Check Neighbor Next
  1553. if (stretchLeft)
  1554. {
  1555. if (math.any(m_Intersectors[segment.sgInfo.x].top) && math.any(m_Intersectors[segment.sgInfo.x].bottom))
  1556. {
  1557. ltp = m_Intersectors[segment.sgInfo.x].top;
  1558. lbt = m_Intersectors[segment.sgInfo.x].bottom;
  1559. needsStretchL = true;
  1560. }
  1561. else
  1562. {
  1563. // Check end-points match for start and prev.
  1564. if (1 == scp.exData.z)
  1565. {
  1566. // Intersection Test
  1567. float2 pvlt = float2.zero, pvlb = float2.zero, pvrt = float2.zero, pvrb = float2.zero;
  1568. GetLineSegments(sprInfo, prevSegment, whsize, ref pvlt, ref pvlb, ref pvrt, ref pvrb);
  1569. ExtendSegment(ref pvlt, ref pvrt);
  1570. ExtendSegment(ref pvlb, ref pvrb);
  1571. bool _lt = LineIntersection(kEpsilon, pvlt, pvrt, avlt, avrt, ref ltp);
  1572. bool _lb = LineIntersection(kEpsilon, pvlb, pvrb, avlb, avrb, ref lbt);
  1573. needsStretchL = _lt && _lb;
  1574. }
  1575. if (needsStretchL)
  1576. {
  1577. JobIntersectPoint ip = m_Intersectors[segment.sgInfo.x];
  1578. ip.top = ltp;
  1579. ip.bottom = lbt;
  1580. m_Intersectors[segment.sgInfo.x] = ip;
  1581. }
  1582. }
  1583. }
  1584. // Check Neighbor Next
  1585. if (stretchRight)
  1586. {
  1587. if (math.any(m_Intersectors[segment.sgInfo.y].top) && math.any(m_Intersectors[segment.sgInfo.y].bottom))
  1588. {
  1589. rtp = m_Intersectors[segment.sgInfo.y].top;
  1590. rbt = m_Intersectors[segment.sgInfo.y].bottom;
  1591. needsStretchR = true;
  1592. }
  1593. else
  1594. {
  1595. // Check end-points match for end and next.
  1596. if (1 == ecp.exData.z)
  1597. {
  1598. // Intersection Test
  1599. float2 nvlt = float2.zero, nvlb = float2.zero, nvrt = float2.zero, nvrb = float2.zero;
  1600. GetLineSegments(sprInfo, nextSegment, whsize, ref nvlt, ref nvlb, ref nvrt, ref nvrb);
  1601. ExtendSegment(ref nvlt, ref nvrt);
  1602. ExtendSegment(ref nvlb, ref nvrb);
  1603. bool _rt = LineIntersection(kEpsilon, avlt, avrt, nvlt, nvrt, ref rtp);
  1604. bool _rb = LineIntersection(kEpsilon, avlb, avrb, nvlb, nvrb, ref rbt);
  1605. needsStretchR = _rt && _rb;
  1606. }
  1607. if (needsStretchR)
  1608. {
  1609. JobIntersectPoint ip = m_Intersectors[segment.sgInfo.y];
  1610. ip.top = rtp;
  1611. ip.bottom = rbt;
  1612. m_Intersectors[segment.sgInfo.y] = ip;
  1613. }
  1614. }
  1615. }
  1616. if (needsStretchL || needsStretchR)
  1617. {
  1618. float2 _lm = (_avlt + _avlb) * 0.5f;
  1619. float2 _rm = (_avrt + _avrb) * 0.5f;
  1620. float _m = math.length(_lm - _rm);
  1621. float _t = math.length(ltp - rtp);
  1622. float _b = math.length(lbt - rbt);
  1623. stretcher.x = _t / _m;
  1624. stretcher.y = _b / _m;
  1625. stretcher.z = needsStretchL ? 1.0f : 0;
  1626. stretcher.w = needsStretchR ? 1.0f : 0;
  1627. }
  1628. }
  1629. return (needsStretchL || needsStretchR);
  1630. }
  1631. void StretchCorners(JobSegmentInfo segment, NativeArray<JobShapeVertex> vertices, int vertexCount, bool validHead, bool validTail, float4 stretcher)
  1632. {
  1633. if (vertexCount > 0)
  1634. {
  1635. int lts = validHead ? 4 : 0;
  1636. float2 lt = vertices[lts].pos, _lt = vertices[lts].pos;
  1637. float2 rt = vertices[vertexCount - 3].pos, _rt = vertices[vertexCount - 3].pos;
  1638. float2 lb = vertices[lts + 2].pos, _lb = vertices[lts + 2].pos;
  1639. float2 rb = vertices[vertexCount - 1].pos, _rb = vertices[vertexCount - 1].pos;
  1640. if (math.any(m_Intersectors[segment.sgInfo.x].top) && math.any(m_Intersectors[segment.sgInfo.x].bottom))
  1641. {
  1642. lt = m_Intersectors[segment.sgInfo.x].top;
  1643. lb = m_Intersectors[segment.sgInfo.x].bottom;
  1644. }
  1645. if (math.any(m_Intersectors[segment.sgInfo.y].top) && math.any(m_Intersectors[segment.sgInfo.y].bottom))
  1646. {
  1647. rt = m_Intersectors[segment.sgInfo.y].top;
  1648. rb = m_Intersectors[segment.sgInfo.y].bottom;
  1649. }
  1650. for (int i = lts; i < vertexCount; i = i + 4)
  1651. {
  1652. JobShapeVertex v0 = vertices[i + 0];
  1653. JobShapeVertex v1 = vertices[i + 1];
  1654. JobShapeVertex v2 = vertices[i + 2];
  1655. JobShapeVertex v3 = vertices[i + 3];
  1656. v0.pos = lt + ((vertices[i + 0].pos - _lt) * stretcher.x);
  1657. v1.pos = lt + ((vertices[i + 1].pos - _lt) * stretcher.x);
  1658. v2.pos = lb + ((vertices[i + 2].pos - _lb) * stretcher.y);
  1659. v3.pos = lb + ((vertices[i + 3].pos - _lb) * stretcher.y);
  1660. vertices[i + 0] = v0;
  1661. vertices[i + 1] = v1;
  1662. vertices[i + 2] = v2;
  1663. vertices[i + 3] = v3;
  1664. }
  1665. JobShapeVertex vx = vertices[lts];
  1666. JobShapeVertex vy = vertices[lts + 2];
  1667. vx.pos = lt;
  1668. vy.pos = lb;
  1669. vertices[lts] = vx;
  1670. vertices[lts + 2] = vy;
  1671. JobShapeVertex vz = vertices[vertexCount - 3];
  1672. JobShapeVertex vw = vertices[vertexCount - 1];
  1673. vz.pos = rt;
  1674. vw.pos = rb;
  1675. vertices[vertexCount - 3] = vz;
  1676. vertices[vertexCount - 1] = vw;
  1677. }
  1678. }
  1679. #endregion
  1680. #region Corners
  1681. // Extend Segment.
  1682. void ExtendSegment(ref float2 l0, ref float2 r0)
  1683. {
  1684. float2 _l0 = l0, _r0 = r0;
  1685. float2 _x = math.normalize(_r0 - _l0);
  1686. r0 = _r0 + (_x * kExtendSegment);
  1687. l0 = _l0 + (-_x * kExtendSegment);
  1688. }
  1689. bool GetIntersection(int cp, int ct, JobSpriteInfo ispr, ref float2 lt0, ref float2 lb0, ref float2 rt0, ref float2 rb0, ref float2 lt1, ref float2 lb1, ref float2 rt1, ref float2 rb1, ref float2 tp, ref float2 bt)
  1690. {
  1691. // Correct Left.
  1692. float2 zero = new float2(0, 0);
  1693. int pp = (cp == 0) ? (controlPointCount - 1) : (cp - 1);
  1694. int np = (cp + 1) % controlPointCount;
  1695. float pivot = 0.5f - ispr.metaInfo.y;
  1696. JobControlPoint lcp = GetControlPoint(pp);
  1697. JobControlPoint ccp = GetControlPoint(cp);
  1698. JobControlPoint rcp = GetControlPoint(np);
  1699. float rpunits = 1.0f / ispr.metaInfo.x;
  1700. float2 whsize = new float2(ispr.texRect.z, ispr.texRect.w) * rpunits;
  1701. float4 border = ispr.border * rpunits;
  1702. // Generate the UV Increments.
  1703. float stPixelV = border.y;
  1704. float enPixelV = whsize.y - border.y;
  1705. float pxlWidth = enPixelV - stPixelV; // pxlWidth is the square size of the corner sprite.
  1706. // Generate the LeftTop, LeftBottom, RightTop & RightBottom for both sides.
  1707. GenerateColumnsBi(lcp.position, ccp.position, whsize, false, ref lb0, ref lt0, ccp.cpInfo.x * 0.5f, pivot);
  1708. GenerateColumnsBi(ccp.position, lcp.position, whsize, false, ref rt0, ref rb0, ccp.cpInfo.x * 0.5f, pivot);
  1709. GenerateColumnsBi(ccp.position, rcp.position, whsize, false, ref lb1, ref lt1, ccp.cpInfo.x * 0.5f, pivot);
  1710. GenerateColumnsBi(rcp.position, ccp.position, whsize, false, ref rt1, ref rb1, ccp.cpInfo.x * 0.5f, pivot);
  1711. rt0 = rt0 + (math.normalize(rt0 - lt0) * kExtendSegment);
  1712. rb0 = rb0 + (math.normalize(rb0 - lb0) * kExtendSegment);
  1713. lt1 = lt1 + (math.normalize(lt1 - rt1) * kExtendSegment);
  1714. lb1 = lb1 + (math.normalize(lb1 - rb1) * kExtendSegment);
  1715. // Generate Intersection of the Bottom Line Segments.
  1716. bool t = LineIntersection(kEpsilon, lt0, rt0, lt1, rt1, ref tp);
  1717. bool b = LineIntersection(kEpsilon, lb0, rb0, lb1, rb1, ref bt);
  1718. if (!b && !t)
  1719. return false;
  1720. return true;
  1721. }
  1722. bool AttachCorner(int cp, int ct, JobSpriteInfo ispr, ref NativeArray<JobControlPoint> newPoints, ref int activePoint)
  1723. {
  1724. // Correct Left.
  1725. float2 zero = new float2(0, 0);
  1726. float2 tp = zero, bt = zero;
  1727. float2 lt0 = zero, lb0 = zero, rt0 = zero, rb0 = zero, lt1 = zero, lb1 = zero, rt1 = zero, rb1 = zero;
  1728. float pivot = 0.5f - ispr.metaInfo.y;
  1729. int pp = (cp == 0) ? (controlPointCount - 1) : (cp - 1);
  1730. int np = (cp + 1) % controlPointCount;
  1731. JobControlPoint lcp = GetControlPoint(pp);
  1732. JobControlPoint ccp = GetControlPoint(cp);
  1733. JobControlPoint rcp = GetControlPoint(np);
  1734. float rpunits = 1.0f / ispr.metaInfo.x;
  1735. float2 whsize = new float2(ispr.texRect.z, ispr.texRect.w) * rpunits;
  1736. float4 border = ispr.border * rpunits;
  1737. // Generate the UV Increments.
  1738. float stPixelV = border.y;
  1739. float enPixelV = whsize.y - border.y;
  1740. float pxlWidth = enPixelV - stPixelV; // pxlWidth is the square size of the corner sprite.
  1741. bool intersects = GetIntersection(cp, ct, ispr, ref lt0, ref lb0, ref rt0, ref rb0, ref lt1, ref lb1, ref rt1, ref rb1, ref tp, ref bt);
  1742. if (!intersects)
  1743. return false;
  1744. float2 pt = ccp.position;
  1745. float2 lt = lcp.position - pt;
  1746. float2 rt = rcp.position - pt;
  1747. float ld = math.length(lt);
  1748. float rd = math.length(rt);
  1749. if (ld < pxlWidth || rd < pxlWidth)
  1750. return false;
  1751. float lrd = 0, rrd = 0;
  1752. float a = AngleBetweenVector(math.normalize(lcp.position - ccp.position), math.normalize(rcp.position - ccp.position));
  1753. if (a > 0)
  1754. {
  1755. lrd = ld - math.distance(lb0, bt);
  1756. rrd = rd - math.distance(bt, rb1);
  1757. }
  1758. else
  1759. {
  1760. lrd = ld - math.distance(lt0, tp);
  1761. rrd = rd - math.distance(tp, rt1);
  1762. }
  1763. float2 la = pt + (math.normalize(lt) * lrd);
  1764. float2 ra = pt + (math.normalize(rt) * rrd);
  1765. ccp.exData.x = ct;
  1766. ccp.exData.z = 2; // Start
  1767. ccp.position = la;
  1768. newPoints[activePoint++] = ccp;
  1769. ccp.exData.x = ct;
  1770. ccp.exData.z = 3; // End
  1771. ccp.position = ra;
  1772. newPoints[activePoint++] = ccp;
  1773. JobCornerInfo iscp = m_Corners[m_CornerCount];
  1774. if (a > 0)
  1775. {
  1776. iscp.bottom = bt;
  1777. iscp.top = tp;
  1778. GenerateColumnsBi(la, lcp.position, whsize, false, ref lt0, ref lb0, ccp.cpInfo.x * ispr.metaInfo.y, pivot);
  1779. GenerateColumnsBi(ra, rcp.position, whsize, false, ref lt1, ref lb1, ccp.cpInfo.x * ispr.metaInfo.y, pivot);
  1780. iscp.left = lt0;
  1781. iscp.right = lb1;
  1782. }
  1783. else
  1784. {
  1785. iscp.bottom = tp;
  1786. iscp.top = bt;
  1787. GenerateColumnsBi(la, lcp.position, whsize, false, ref lt0, ref lb0, ccp.cpInfo.x * ispr.metaInfo.y, pivot);
  1788. GenerateColumnsBi(ra, rcp.position, whsize, false, ref lt1, ref lb1, ccp.cpInfo.x * ispr.metaInfo.y, pivot);
  1789. iscp.left = lb0;
  1790. iscp.right = lt1;
  1791. }
  1792. iscp.cornerData.x = ct;
  1793. iscp.cornerData.y = activePoint;
  1794. m_Corners[m_CornerCount] = iscp;
  1795. m_CornerCount++;
  1796. return true;
  1797. }
  1798. float2 CornerTextureCoordinate(int cornerType, int index)
  1799. {
  1800. int cornerArrayIndex = (cornerType - 1) * 4;
  1801. return m_CornerCoordinates[cornerArrayIndex + index];
  1802. }
  1803. int CalculateCorner(int index, float angle, float2 lt, float2 rt)
  1804. {
  1805. var ct = 0;
  1806. float slope = SlopeAngle(lt);
  1807. var slopePairs = new float2[]
  1808. {
  1809. new float2(-135.0f, -35.0f),
  1810. new float2(35.0f, 135.0f),
  1811. new float2(-35.0f, 35.0f),
  1812. new float2(-135.0f, 135.0f)
  1813. };
  1814. var cornerPairs = new int2[]
  1815. {
  1816. new int2(kCornerTypeInnerTopLeft, kCornerTypeOuterBottomLeft),
  1817. new int2(kCornerTypeInnerBottomRight, kCornerTypeOuterTopRight),
  1818. new int2(kCornerTypeInnerTopRight, kCornerTypeOuterTopLeft),
  1819. new int2(kCornerTypeInnerBottomLeft, kCornerTypeOuterBottomRight)
  1820. };
  1821. for (int i = 0; i < 3; ++i)
  1822. {
  1823. if ( slope > slopePairs[i].x && slope < slopePairs[i].y )
  1824. {
  1825. ct = (angle > 0) ? cornerPairs[i].x : cornerPairs[i].y;
  1826. break;
  1827. }
  1828. }
  1829. if (ct == 0)
  1830. {
  1831. ct = (angle > 0) ? kCornerTypeInnerBottomLeft : kCornerTypeOuterBottomRight;
  1832. }
  1833. return ct;
  1834. }
  1835. bool InsertCorner(int index, ref NativeArray<int2> cpSpriteIndices, ref NativeArray<JobControlPoint> newPoints, ref int activePoint, ref bool cornerConsidered)
  1836. {
  1837. int i = (index == 0) ? (controlPointCount - 1) : (index - 1);
  1838. int k = (index + 1) % controlPointCount;
  1839. // Check if we have valid Sprites.
  1840. if (cpSpriteIndices[i].x >= spriteCount || cpSpriteIndices[index].x >= spriteCount)
  1841. return false;
  1842. // Check if they have been resolved.
  1843. if (cpSpriteIndices[i].y == 0 || cpSpriteIndices[index].y == 0)
  1844. return false;
  1845. JobControlPoint pcp = GetControlPoint(i);
  1846. JobControlPoint icp = GetControlPoint(index);
  1847. JobControlPoint ncp = GetControlPoint(k);
  1848. // Check if the Mode of control Point and previous neighbor is same. Also check if Corner Toggle is enabled.
  1849. if (icp.cpData.y == 0 || pcp.cpData.z != kModeLinear || icp.cpData.z != kModeLinear || ncp.cpData.z != kModeLinear)
  1850. return false;
  1851. // Check if the Height of the Control Points match
  1852. if (pcp.cpInfo.x != icp.cpInfo.x || icp.cpInfo.x != ncp.cpInfo.x)
  1853. return false;
  1854. JobSpriteInfo psi = GetSpriteInfo(cpSpriteIndices[i].x);
  1855. JobSpriteInfo isi = GetSpriteInfo(cpSpriteIndices[index].x);
  1856. // Check if the Sprites Pivot matches. Otherwise not allowed. // psi.uvInfo.w != isi.uvInfo.w && psi.metaInfo.y != 0.5f (no more height and pivot checks)
  1857. if (psi.metaInfo.y != isi.metaInfo.y)
  1858. return false;
  1859. // Now perform expensive stuff like angles etc..
  1860. float2 idir = math.normalize(ncp.position - icp.position);
  1861. float2 ndir = math.normalize(pcp.position - icp.position);
  1862. float angle = AngleBetweenVector(idir, ndir);
  1863. float angleAbs = math.abs(angle);
  1864. cornerConsidered = AngleWithinRange(angleAbs, (90f - m_ShapeParams.curveData.z), (90f + m_ShapeParams.curveData.z)) || (m_ShapeParams.curveData.z == 90.0f);
  1865. if (cornerConsidered && icp.cpData.y == 1)
  1866. {
  1867. float2 rdir = math.normalize(icp.position - pcp.position);
  1868. int ct = CalculateCorner(index, angle, rdir, idir);
  1869. // Check if we have a valid Sprite.
  1870. if (ct > 0)
  1871. {
  1872. JobSpriteInfo cspr = GetCornerSpriteInfo(ct);
  1873. return AttachCorner(index, ct, cspr, ref newPoints, ref activePoint);
  1874. }
  1875. }
  1876. return false;
  1877. }
  1878. void TessellateCorners()
  1879. {
  1880. for (int corner = 1; corner <= kCornerTypeInnerBottomRight; ++corner)
  1881. {
  1882. JobSpriteInfo isi = GetCornerSpriteInfo(corner);
  1883. if (isi.metaInfo.x == 0)
  1884. continue;
  1885. int ic = 0;
  1886. int vc = 0;
  1887. Vector3 pos = m_PosArray[ic];
  1888. Vector2 uv0 = m_Uv0Array[ic];
  1889. bool ccw = (corner <= kCornerTypeOuterBottomRight);
  1890. int vArrayCount = m_VertexArrayCount;
  1891. for (int i = 0; i < m_CornerCount; ++i)
  1892. {
  1893. JobCornerInfo isc = m_Corners[i];
  1894. if (isc.cornerData.x == corner)
  1895. {
  1896. // Vertices.
  1897. pos.x = isc.top.x;
  1898. pos.y = isc.top.y;
  1899. uv0.x = (CornerTextureCoordinate(corner, 1).x * isi.uvInfo.z) + isi.uvInfo.x;
  1900. uv0.y = (CornerTextureCoordinate(corner, 1).y * isi.uvInfo.w) + isi.uvInfo.y;
  1901. m_PosArray[m_VertexArrayCount] = pos;
  1902. m_Uv0Array[m_VertexArrayCount++] = uv0;
  1903. pos.x = isc.right.x;
  1904. pos.y = isc.right.y;
  1905. uv0.x = (CornerTextureCoordinate(corner, 0).x * isi.uvInfo.z) + isi.uvInfo.x;
  1906. uv0.y = (CornerTextureCoordinate(corner, 0).y * isi.uvInfo.w) + isi.uvInfo.y;
  1907. m_PosArray[m_VertexArrayCount] = pos;
  1908. m_Uv0Array[m_VertexArrayCount++] = uv0;
  1909. pos.x = isc.left.x;
  1910. pos.y = isc.left.y;
  1911. uv0.x = (CornerTextureCoordinate(corner, 3).x * isi.uvInfo.z) + isi.uvInfo.x;
  1912. uv0.y = (CornerTextureCoordinate(corner, 3).y * isi.uvInfo.w) + isi.uvInfo.y;
  1913. m_PosArray[m_VertexArrayCount] = pos;
  1914. m_Uv0Array[m_VertexArrayCount++] = uv0;
  1915. pos.x = isc.bottom.x;
  1916. pos.y = isc.bottom.y;
  1917. uv0.x = (CornerTextureCoordinate(corner, 2).x * isi.uvInfo.z) + isi.uvInfo.x;
  1918. uv0.y = (CornerTextureCoordinate(corner, 2).y * isi.uvInfo.w) + isi.uvInfo.y;
  1919. m_PosArray[m_VertexArrayCount] = pos;
  1920. m_Uv0Array[m_VertexArrayCount++] = uv0;
  1921. // Indices.
  1922. m_IndexArray[m_IndexArrayCount++] = (ushort)(vc + 0);
  1923. m_IndexArray[m_IndexArrayCount++] = (ushort)(vc + (ccw ? 1 : 3));
  1924. m_IndexArray[m_IndexArrayCount++] = (ushort)(vc + (ccw ? 3 : 1));
  1925. m_IndexArray[m_IndexArrayCount++] = (ushort)(vc + 0);
  1926. m_IndexArray[m_IndexArrayCount++] = (ushort)(vc + (ccw ? 3 : 2));
  1927. m_IndexArray[m_IndexArrayCount++] = (ushort)(vc + (ccw ? 2 : 3));
  1928. vc = vc + 4;
  1929. ic = ic + 6;
  1930. }
  1931. }
  1932. if (m_TanArray.Length > 1)
  1933. {
  1934. for (int i = vArrayCount; i < m_VertexArrayCount; ++i)
  1935. m_TanArray[i] = new Vector4(1.0f, 0, 0, -1.0f);
  1936. }
  1937. // Geom Data
  1938. if (ic > 0 && vc > 0)
  1939. {
  1940. var geom = m_GeomArray[m_GeomArrayCount];
  1941. geom.geomIndex = m_GeomArrayCount;
  1942. geom.indexCount = ic;
  1943. geom.vertexCount = vc;
  1944. geom.spriteIndex = m_SpriteInfos.Length + (corner - 1);
  1945. m_GeomArray[m_GeomArrayCount++] = geom;
  1946. }
  1947. }
  1948. }
  1949. #endregion
  1950. #region Fast Optimizations
  1951. bool AreCollinear(float2 a, float2 b, float2 c, float t)
  1952. {
  1953. float ax = (a.y - b.y) * (a.x - c.x);
  1954. float bx = (a.y - c.y) * (a.x - b.x);
  1955. float aa = math.abs(ax - bx);
  1956. return aa < t;
  1957. }
  1958. // Check if points are co linear and reduce.
  1959. void OptimizePoints(float tolerance, ref NativeArray<float2> pointSet, ref int pointCount)
  1960. {
  1961. int kMinimumPointsRequired = 8;
  1962. if (pointCount < kMinimumPointsRequired)
  1963. return;
  1964. int optimizedColliderPointCount = 0;
  1965. int endColliderPointCount = pointCount - 2;
  1966. bool val = true;
  1967. m_TempPoints[0] = pointSet[0];
  1968. for (int i = 0; i < endColliderPointCount; ++i)
  1969. {
  1970. int j = i;
  1971. float2 v0 = pointSet[i];
  1972. float2 v1 = pointSet[i + 1];
  1973. float2 v2 = pointSet[i + 2];
  1974. val = true;
  1975. while (val && j < endColliderPointCount)
  1976. {
  1977. val = AreCollinear(v0, v1, v2, tolerance);
  1978. if (false == val)
  1979. {
  1980. m_TempPoints[++optimizedColliderPointCount] = v1;
  1981. i = j;
  1982. break;
  1983. }
  1984. j++;
  1985. v1 = pointSet[j + 1];
  1986. v2 = pointSet[j + 2];
  1987. }
  1988. }
  1989. m_TempPoints[++optimizedColliderPointCount] = pointSet[endColliderPointCount];
  1990. m_TempPoints[++optimizedColliderPointCount] = pointSet[endColliderPointCount + 1];
  1991. if (isCarpet)
  1992. m_TempPoints[++optimizedColliderPointCount] = pointSet[0];
  1993. var localPointCount = optimizedColliderPointCount + 1;
  1994. if (localPointCount > 0)
  1995. {
  1996. pointCount = 0;
  1997. pointSet[pointCount++] = m_TempPoints[0];
  1998. for (int i = 1; i < localPointCount; ++i)
  1999. {
  2000. if (math.distance(pointSet[pointCount - 1], m_TempPoints[i]) > 0.0001f)
  2001. pointSet[pointCount++] = m_TempPoints[i];
  2002. }
  2003. }
  2004. }
  2005. #endregion
  2006. #region Collider Specific.
  2007. void AttachCornerToCollider(JobSegmentInfo isi, float pivot, ref NativeArray<float2> colliderPoints, ref int colliderPointCount)
  2008. {
  2009. float2 zero = new float2(0, 0);
  2010. int cornerIndex = isi.sgInfo.x + 1;
  2011. for (int i = 0; i < m_CornerCount; ++i)
  2012. {
  2013. JobCornerInfo isc = m_Corners[i];
  2014. if (cornerIndex == isc.cornerData.y)
  2015. {
  2016. float2 cp = zero;
  2017. float2 v0 = zero;
  2018. if (isc.cornerData.x > kCornerTypeOuterBottomRight)
  2019. v0 = isc.top;
  2020. else
  2021. v0 = isc.bottom;
  2022. float2 v2 = zero;
  2023. if (isc.cornerData.x > kCornerTypeOuterBottomRight)
  2024. v2 = isc.bottom;
  2025. else
  2026. v2 = isc.top;
  2027. cp = (v0 - v2) * pivot;
  2028. cp = (v2 + cp + v0 + cp) * 0.5f;
  2029. colliderPoints[colliderPointCount++] = cp;
  2030. break;
  2031. }
  2032. }
  2033. }
  2034. float2 UpdateCollider(JobSegmentInfo isi, JobSpriteInfo ispr, NativeArray<JobShapeVertex> vertices, int count, ref NativeArray<float2> colliderPoints, ref int colliderPointCount)
  2035. {
  2036. float2 zero = new float2(0, 0);
  2037. float pivot = 0; // 0.5f - ispr.metaInfo.y; // Follow processed geometry and only use ColliderPivot.
  2038. pivot = pivot + colliderPivot;
  2039. AttachCornerToCollider(isi, pivot, ref colliderPoints, ref colliderPointCount);
  2040. float2 cp = zero;
  2041. float2 v0 = zero;
  2042. float2 v2 = zero;
  2043. for (int k = 0; k < count; k = k + 4)
  2044. {
  2045. v0 = vertices[k].pos;
  2046. v2 = vertices[k + 2].pos;
  2047. cp = (v0 - v2) * pivot;
  2048. if (vertices[k].sprite.z == 0)
  2049. colliderPoints[colliderPointCount++] = (v2 + cp + v0 + cp) * 0.5f;
  2050. }
  2051. float2 v1 = vertices[count - 1].pos;
  2052. float2 v3 = vertices[count - 3].pos;
  2053. cp = (v3 - v1) * pivot;
  2054. if (vertices[count - 1].sprite.z == 0)
  2055. colliderPoints[colliderPointCount++] = (v1 + cp + v3 + cp) * 0.5f;
  2056. return cp;
  2057. }
  2058. void TrimOverlaps(int cpCount)
  2059. {
  2060. int kMinimumPointTolerance = 4;
  2061. if (m_ColliderPointCount < kMinimumPointTolerance)
  2062. return;
  2063. int trimmedPointCount = 0;
  2064. int i = 0;
  2065. int kColliderPointCountClamped = m_ColliderPointCount / 2;
  2066. int kSplineDetailClamped = math.clamp(splineDetail * 3, 0, 8);
  2067. int kNeighbors = kSplineDetailClamped > kColliderPointCountClamped ? kColliderPointCountClamped : kSplineDetailClamped;
  2068. kNeighbors = (kNeighbors > cpCount) ? cpCount : kNeighbors;
  2069. if (!isCarpet)
  2070. m_TempPoints[trimmedPointCount++] = m_ColliderPoints[0];
  2071. while (i < m_ColliderPointCount)
  2072. {
  2073. int h = (i > 0) ? (i - 1) : (m_ColliderPointCount - 1);
  2074. bool noIntersection = true;
  2075. float2 v0 = m_ColliderPoints[h];
  2076. float2 v1 = m_ColliderPoints[i];
  2077. for (int n = kNeighbors; n > 1; --n)
  2078. {
  2079. int j = (i + n - 1) % m_ColliderPointCount;
  2080. int k = (i + n) % m_ColliderPointCount;
  2081. if (k == 0 || i == 0)
  2082. continue;
  2083. float2 v2 = m_ColliderPoints[j];
  2084. float2 v3 = m_ColliderPoints[k];
  2085. float2 vx = v0 - v3;
  2086. if (math.abs(math.length(vx)) < kEpsilon)
  2087. break;
  2088. float2 vi = v0;
  2089. bool overLaps = LineIntersection(kEpsilonRelaxed, v0, v1, v2, v3, ref vi);
  2090. if (overLaps && IsPointOnLines(kEpsilonRelaxed, v0, v1, v2, v3, vi))
  2091. {
  2092. noIntersection = false;
  2093. m_TempPoints[trimmedPointCount++] = vi;
  2094. i = i + n;
  2095. break;
  2096. }
  2097. }
  2098. if (noIntersection)
  2099. {
  2100. m_TempPoints[trimmedPointCount++] = v1;
  2101. i = i + 1;
  2102. }
  2103. }
  2104. for (; i < m_ColliderPointCount; ++i)
  2105. m_TempPoints[trimmedPointCount++] = m_ColliderPoints[i];
  2106. i = 0;
  2107. m_ColliderPoints[i++] = m_TempPoints[0];
  2108. float2 prev = m_TempPoints[0];
  2109. for (int j = 1; j < trimmedPointCount; ++j)
  2110. {
  2111. float dist = math.length(m_TempPoints[j] - prev);
  2112. if (dist > kEpsilon)
  2113. m_ColliderPoints[i++] = m_TempPoints[j];
  2114. prev = m_TempPoints[j];
  2115. }
  2116. trimmedPointCount = i;
  2117. if (trimmedPointCount > 4)
  2118. {
  2119. // Check intersection of first line Segment and last.
  2120. float2 vin = m_ColliderPoints[0];
  2121. bool endOverLaps = LineIntersection(kEpsilonRelaxed, m_ColliderPoints[0], m_ColliderPoints[1],
  2122. m_ColliderPoints[trimmedPointCount - 1], m_ColliderPoints[trimmedPointCount - 2], ref vin);
  2123. if (endOverLaps)
  2124. m_ColliderPoints[0] = m_ColliderPoints[trimmedPointCount - 1] = vin;
  2125. }
  2126. m_ColliderPointCount = trimmedPointCount;
  2127. }
  2128. void OptimizeCollider()
  2129. {
  2130. if (hasCollider)
  2131. {
  2132. if (kColliderQuality > 0)
  2133. {
  2134. OptimizePoints(kColliderQuality, ref m_ColliderPoints, ref m_ColliderPointCount);
  2135. TrimOverlaps(m_ControlPointCount - 1);
  2136. m_ColliderPoints[m_ColliderPointCount++] = new float2(0, 0);
  2137. m_ColliderPoints[m_ColliderPointCount++] = new float2(0, 0);
  2138. }
  2139. // If the resulting Colliders don't have enough points including the last 2 'end-points', just use Contours as Colliders.
  2140. if (m_ColliderPointCount <= 4)
  2141. {
  2142. for (int i = 0; i < m_TessPointCount; ++i)
  2143. m_ColliderPoints[i] = m_TessPoints[i];
  2144. m_ColliderPoints[m_TessPointCount] = new float2(0, 0);
  2145. m_ColliderPoints[m_TessPointCount + 1] = new float2(0, 0);
  2146. m_ColliderPointCount = m_TessPointCount + 2;
  2147. }
  2148. }
  2149. }
  2150. #endregion
  2151. #region Entry, Exit Points.
  2152. [Obsolete]
  2153. public void Prepare(UnityEngine.U2D.SpriteShapeController controller, SpriteShapeParameters shapeParams, int maxArrayCount, NativeArray<ShapeControlPoint> shapePoints, NativeArray<SpriteShapeMetaData> metaData, AngleRangeInfo[] angleRanges, Sprite[] segmentSprites, Sprite[] cornerSprites)
  2154. {
  2155. // Prepare Inputs.
  2156. PrepareInput(shapeParams, maxArrayCount, shapePoints, controller.optimizeGeometry, controller.autoUpdateCollider, controller.optimizeCollider, controller.colliderOffset, controller.colliderDetail);
  2157. PrepareSprites(segmentSprites, cornerSprites);
  2158. PrepareAngleRanges(angleRanges);
  2159. NativeArray<SplinePointMetaData> newMetaData = new NativeArray<SplinePointMetaData>(metaData.Length, Allocator.Temp);
  2160. for (int i = 0; i < metaData.Length; ++i)
  2161. {
  2162. SplinePointMetaData newData = new SplinePointMetaData();
  2163. newData.height = metaData[i].height;
  2164. newData.spriteIndex = metaData[i].spriteIndex;
  2165. newData.cornerMode = metaData[i].corner ? (int)Corner.Automatic : (int)Corner.Disable;
  2166. newMetaData[i] = newData;
  2167. }
  2168. PrepareControlPoints(shapePoints, newMetaData);
  2169. newMetaData.Dispose();
  2170. // Generate Fill. Obsolete API and let's stick with main-thread fill.
  2171. kModeUTess = 0;
  2172. TessellateContourMainThread();
  2173. }
  2174. internal void Prepare(UnityEngine.U2D.SpriteShapeController controller, SpriteShapeParameters shapeParams, int maxArrayCount, NativeArray<ShapeControlPoint> shapePoints, NativeArray<SplinePointMetaData> metaData, AngleRangeInfo[] angleRanges, Sprite[] segmentSprites, Sprite[] cornerSprites, bool UseUTess)
  2175. {
  2176. // Prepare Inputs.
  2177. PrepareInput(shapeParams, maxArrayCount, shapePoints, controller.optimizeGeometry, controller.autoUpdateCollider, controller.optimizeCollider, controller.colliderOffset, controller.colliderDetail);
  2178. PrepareSprites(segmentSprites, cornerSprites);
  2179. PrepareAngleRanges(angleRanges);
  2180. PrepareControlPoints(shapePoints, metaData);
  2181. // Generate Fill.
  2182. kModeUTess = UseUTess ? 1 : 0;
  2183. if (0 == kModeUTess)
  2184. TessellateContourMainThread();
  2185. }
  2186. public void Execute()
  2187. {
  2188. // BURST
  2189. generateGeometry.Begin();
  2190. {
  2191. if (0 != kModeUTess)
  2192. TessellateContour();
  2193. GenerateSegments();
  2194. UpdateSegments();
  2195. TessellateSegments();
  2196. TessellateCorners();
  2197. CalculateTexCoords();
  2198. }
  2199. generateGeometry.End();
  2200. generateCollider.Begin();
  2201. {
  2202. CalculateBoundingBox();
  2203. OptimizeCollider();
  2204. }
  2205. generateCollider.End();
  2206. }
  2207. // Only needed if Burst is disabled.
  2208. // [BurstDiscard]
  2209. public void Cleanup()
  2210. {
  2211. SafeDispose(m_Corners);
  2212. SafeDispose(m_CornerSpriteInfos);
  2213. SafeDispose(m_SpriteInfos);
  2214. SafeDispose(m_AngleRanges);
  2215. SafeDispose(m_Segments);
  2216. SafeDispose(m_ControlPoints);
  2217. SafeDispose(m_ContourPoints);
  2218. SafeDispose(m_TempPoints);
  2219. SafeDispose(m_GeneratedControlPoints);
  2220. SafeDispose(m_SpriteIndices);
  2221. SafeDispose(m_Intersectors);
  2222. SafeDispose(m_TessPoints);
  2223. SafeDispose(m_VertexData);
  2224. SafeDispose(m_OutputVertexData);
  2225. SafeDispose(m_CornerCoordinates);
  2226. }
  2227. #endregion
  2228. }
  2229. };