Няма описание
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 112KB

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