├── .gitattributes ├── .gitignore ├── AdvancedComponent.meta ├── AdvancedComponent ├── AdvancedImage.cs ├── AdvancedImage.cs.meta ├── AdvancedText.cs ├── AdvancedText.cs.meta ├── Editor.meta ├── Editor │ ├── AdvancedImageEditor.cs │ ├── AdvancedImageEditor.cs.meta │ ├── AdvancedTextEditor.cs │ └── AdvancedTextEditor.cs.meta ├── ShaderOutLine.cs ├── ShaderOutLine.cs.meta ├── UI-OutLine.mat ├── UI-OutLine.mat.meta ├── UI-OutLine.shader └── UI-OutLine.shader.meta ├── AutoCreateImage.meta ├── AutoCreateImage ├── Editor.meta └── Editor │ ├── AutoCreateImage.cs │ └── AutoCreateImage.cs.meta ├── LICENSE ├── LICENSE.meta ├── PrefabLoader.meta ├── PrefabLoader ├── PrefabLoader.cs └── PrefabLoader.cs.meta ├── README.md ├── README.md.meta ├── UI3DModifier.meta ├── UI3DModifier ├── UI-3DModifier.shader ├── UI-3DModifier.shader.meta ├── UI3DModifier.cs └── UI3DModifier.cs.meta ├── UIBake.meta ├── UIBake ├── Editor.meta ├── Editor │ ├── UIMeshBakeEditor.cs │ └── UIMeshBakeEditor.cs.meta ├── UIBakeMesh.cs ├── UIBakeMesh.cs.meta ├── UIBakeMeshAsset.cs ├── UIBakeMeshAsset.cs.meta ├── UIBakeMeshCreater.cs └── UIBakeMeshCreater.cs.meta ├── UIEffect.meta ├── UIEffect ├── Particle Add Clip.shader ├── Particle Add Clip.shader.meta ├── Particle Alpha Blend Clip.shader ├── Particle Alpha Blend Clip.shader.meta ├── Particles_Alpha Blended (Clip).mat ├── Particles_Alpha Blended (Clip).mat.meta ├── UIClipAble.cs └── UIClipAble.cs.meta ├── UILineFeedFixed └── LineFeedFixed.cs ├── UIPSDViewer.meta ├── UIPSDViewer ├── Plugins.meta ├── Plugins │ ├── PsdParser.dll │ └── PsdParser.dll.meta ├── TestFile.psd ├── TestFile.psd.meta ├── UIPSDViewer.cs └── UIPSDViewer.cs.meta ├── UIPackage.meta └── UIPackage ├── Editor.meta ├── Editor ├── UIPackageEditor.cs └── UIPackageEditor.cs.meta ├── UIPackage.cs └── UIPackage.cs.meta /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /[Ll]ibrary/ 2 | /[Tt]emp/ 3 | /[Oo]bj/ 4 | /[Bb]uild/ 5 | /[Bb]uilds/ 6 | /Assets/AssetStoreTools* 7 | 8 | # Visual Studio 2015 cache directory 9 | /.vs/ 10 | 11 | # Autogenerated VS/MD/Consulo solution and project files 12 | ExportedObj/ 13 | .consulo/ 14 | *.csproj 15 | *.unityproj 16 | *.sln 17 | *.suo 18 | *.tmp 19 | *.user 20 | *.userprefs 21 | *.pidb 22 | *.booproj 23 | *.svd 24 | *.pdb 25 | 26 | # Unity3D generated meta files 27 | *.pidb.meta 28 | 29 | # Unity3D Generated File On Crash Reports 30 | sysinfo.txt 31 | 32 | # Builds 33 | *.apk 34 | *.unitypackage 35 | -------------------------------------------------------------------------------- /AdvancedComponent.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e9ce451f4dcd61b429a47c49393866d1 3 | folderAsset: yes 4 | timeCreated: 1516557995 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /AdvancedComponent/AdvancedImage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.UI; 5 | 6 | namespace UGUIExtend 7 | { 8 | [RequireComponent(typeof(RectTransform))] 9 | [RequireComponent(typeof(CanvasRenderer))] 10 | [AddComponentMenu("UI/AdvancedImage", 12)] 11 | public class AdvancedImage : Image 12 | { 13 | /// 14 | /// 可见度 15 | /// 16 | [SerializeField] 17 | private bool m_Visible = true; 18 | public bool visible 19 | { 20 | get 21 | { 22 | return m_Visible; 23 | 24 | } 25 | 26 | set 27 | { 28 | if (m_Visible != value) 29 | { 30 | m_Visible = value; 31 | UpdateVisible(); 32 | if (m_Visible) 33 | CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); 34 | } 35 | } 36 | } 37 | 38 | /// 39 | /// 是否绘制 40 | /// 41 | [SerializeField] 42 | private bool m_EnabledPopulateMesh = true; 43 | public bool enabledPopulateMesh 44 | { 45 | get 46 | { 47 | return m_EnabledPopulateMesh; 48 | } 49 | 50 | set 51 | { 52 | if (m_EnabledPopulateMesh != value) 53 | { 54 | SetVerticesDirty(); 55 | } 56 | m_EnabledPopulateMesh = value; 57 | } 58 | } 59 | 60 | /// 61 | /// 是否使用Sprite的网格 62 | /// 63 | [SerializeField] 64 | private bool m_UseSpriteMesh; 65 | public bool useSpriteMesh 66 | { 67 | get 68 | { 69 | return m_UseSpriteMesh; 70 | } 71 | 72 | set 73 | { 74 | if (m_UseSpriteMesh != value) 75 | { 76 | SetVerticesDirty(); 77 | } 78 | m_UseSpriteMesh = value; 79 | } 80 | } 81 | 82 | /// 83 | /// 水平镜像 84 | /// 85 | [SerializeField] 86 | private bool m_HorizontalMirror; 87 | public bool horizontalMirror 88 | { 89 | get 90 | { 91 | return m_HorizontalMirror; 92 | } 93 | 94 | set 95 | { 96 | if (m_UseSpriteMesh != value) 97 | { 98 | SetVerticesDirty(); 99 | } 100 | m_HorizontalMirror = value; 101 | } 102 | } 103 | 104 | /// 105 | /// 垂直镜像 106 | /// 107 | [SerializeField] 108 | private bool m_VerticalMirror; 109 | public bool verticalMirror 110 | { 111 | get 112 | { 113 | return m_VerticalMirror; 114 | } 115 | 116 | set 117 | { 118 | if (m_VerticalMirror != value) 119 | { 120 | SetVerticesDirty(); 121 | } 122 | m_VerticalMirror = value; 123 | } 124 | } 125 | 126 | /// 127 | /// 设置中间挖空部分的边缘,FillCenter激活时无效 128 | /// 129 | [SerializeField] 130 | private Vector4 m_FillBorders = Vector4.zero; 131 | public Vector4 fillBorders 132 | { 133 | get 134 | { 135 | return m_FillBorders; 136 | } 137 | 138 | set 139 | { 140 | if (m_FillBorders != value) 141 | { 142 | SetVerticesDirty(); 143 | } 144 | m_FillBorders = value; 145 | } 146 | 147 | 148 | } 149 | 150 | 151 | /// 152 | /// 碰撞箱 153 | /// 154 | [SerializeField] 155 | public Collider2D hitArea; 156 | 157 | /// 158 | /// 使用Sprite网格作为碰撞箱 159 | /// 160 | [SerializeField] 161 | public bool useSpriteHitArea; 162 | 163 | /// 164 | /// 碰撞箱缩放 165 | /// 166 | [SerializeField] 167 | public Vector2 hitScale = Vector2.one; 168 | 169 | protected override void OnEnable() 170 | { 171 | base.OnEnable(); 172 | UpdateVisible(); 173 | } 174 | 175 | protected virtual void UpdateVisible() 176 | { 177 | this.canvasRenderer.cull = !m_Visible; 178 | } 179 | 180 | public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera) 181 | { 182 | if (!useSpriteHitArea && hitArea == null && hitScale == Vector2.one) 183 | { 184 | return base.IsRaycastLocationValid(screenPoint, eventCamera); 185 | } 186 | 187 | if (eventCamera != null) 188 | { 189 | screenPoint = eventCamera.ScreenToWorldPoint(screenPoint); 190 | } 191 | if (hitScale != Vector2.one) 192 | { 193 | Vector2 centerInScreen = transform.position; 194 | screenPoint = centerInScreen + Vector2.Scale(screenPoint - centerInScreen, new Vector2(1f / hitScale.x, 1f / hitScale.y)); 195 | } 196 | if (useSpriteHitArea && IsRaycastSprite(rectTransform.InverseTransformPoint(screenPoint)) || 197 | hitArea != null && hitArea.OverlapPoint(screenPoint) || 198 | !useSpriteHitArea && hitArea == null && rectTransform.rect.Contains(rectTransform.InverseTransformPoint(screenPoint))) 199 | { 200 | return true; 201 | } 202 | return false; 203 | } 204 | 205 | bool IsRaycastSprite(Vector2 point) 206 | { 207 | Rect r = GetPixelAdjustedRect(); 208 | var size = new Vector2(overrideSprite.rect.width, overrideSprite.rect.height); 209 | Bounds bounds = overrideSprite.bounds; 210 | 211 | if (preserveAspect) 212 | { 213 | PreserveAspect(ref r, size); 214 | } 215 | 216 | float w = r.width / bounds.size.x; 217 | float h = r.height / bounds.size.y; 218 | point.x = (point.x + w * bounds.center.x) / w; 219 | point.y = (point.y + h * bounds.center.y) / h; 220 | 221 | var vertices = overrideSprite.vertices; 222 | var triangles = overrideSprite.triangles; 223 | int count = triangles.Length; 224 | for (int i = 0;i < count;i+= 3) 225 | { 226 | Vector2 v1 = vertices[triangles[i]]; 227 | Vector2 v2 = vertices[triangles[i + 1]]; 228 | Vector2 v3 = vertices[triangles[i + 2]]; 229 | if (PointinTriangle(v1, v2, v3, point)) 230 | return true; 231 | } 232 | return false; 233 | } 234 | 235 | // 三角形碰撞检测 236 | static bool PointinTriangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P) 237 | { 238 | Vector2 v0 = C - A; 239 | Vector2 v1 = B - A; 240 | Vector2 v2 = P - A; 241 | 242 | float dot00 = Vector2.Dot(v0, v0); 243 | float dot01 = Vector2.Dot(v0, v1); 244 | float dot02 = Vector2.Dot(v0, v2); 245 | float dot11 = Vector2.Dot(v1, v1); 246 | float dot12 = Vector2.Dot(v1, v2); 247 | 248 | float inverDeno = 1 / (dot00 * dot11 - dot01 * dot01); 249 | 250 | float u = (dot11 * dot02 - dot01 * dot12) * inverDeno; 251 | if (u < 0 || u > 1) 252 | { 253 | return false; 254 | } 255 | 256 | float v = (dot00 * dot12 - dot01 * dot02) * inverDeno; 257 | if (v < 0 || v > 1) 258 | { 259 | return false; 260 | } 261 | 262 | return u + v <= 1; 263 | } 264 | 265 | protected override void OnPopulateMesh(VertexHelper toFill) 266 | { 267 | if (!m_EnabledPopulateMesh) 268 | { 269 | toFill.Clear(); 270 | return; 271 | } 272 | 273 | if (overrideSprite == null) 274 | { 275 | base.OnPopulateMesh(toFill); 276 | return; 277 | } 278 | 279 | switch (type) 280 | { 281 | case Type.Simple: 282 | if (m_UseSpriteMesh) 283 | GenerateSpriteSprite(toFill, preserveAspect); 284 | else 285 | GenerateSimpleSprite(toFill, preserveAspect); 286 | break; 287 | case Type.Sliced: 288 | GenerateSlicedSprite(toFill); 289 | break; 290 | default: 291 | base.OnPopulateMesh(toFill); 292 | break; 293 | } 294 | } 295 | 296 | public override void SetNativeSize() 297 | { 298 | if (overrideSprite != null && (type == Type.Simple || type == Type.Sliced) && (m_HorizontalMirror || m_VerticalMirror)) 299 | { 300 | float w = overrideSprite.rect.width / pixelsPerUnit; 301 | float h = overrideSprite.rect.height / pixelsPerUnit; 302 | rectTransform.anchorMax = rectTransform.anchorMin; 303 | 304 | if (m_HorizontalMirror && m_VerticalMirror) 305 | { 306 | rectTransform.sizeDelta = new Vector2(w * 2, h * 2); 307 | } 308 | else if (m_HorizontalMirror) 309 | { 310 | rectTransform.sizeDelta = new Vector2(w * 2, h); 311 | } 312 | else 313 | { 314 | rectTransform.sizeDelta = new Vector2(w, h * 2); 315 | } 316 | } 317 | else 318 | { 319 | base.SetNativeSize(); 320 | } 321 | } 322 | 323 | /// 324 | /// 用Sprite的网格数据直接创建顶点 325 | /// 326 | void GenerateSpriteSprite(VertexHelper vh, bool shouldPreserveAspect) 327 | { 328 | Rect r = GetPixelAdjustedRect(); 329 | var size = new Vector2(overrideSprite.rect.width, overrideSprite.rect.height); 330 | Bounds bounds = overrideSprite.bounds; 331 | 332 | if (shouldPreserveAspect) 333 | { 334 | PreserveAspect(ref r, size); 335 | } 336 | 337 | float w = r.width / bounds.size.x; 338 | float h = r.height / bounds.size.y; 339 | Vector4 v = new Vector4(-w * bounds.center.x, 340 | -h * bounds.center.y, 341 | w, 342 | h); 343 | 344 | Color32 color32 = color; 345 | vh.Clear(); 346 | var vertices = overrideSprite.vertices; 347 | var uv = overrideSprite.uv; 348 | int count = vertices.Length; 349 | for (int i = 0; i < count; i++) 350 | { 351 | Vector2 vert = vertices[i]; 352 | vh.AddVert(new Vector3(v.x + vert.x * v.z, v.y + vert.y * v.w, 0), color32, uv[i]); 353 | } 354 | var triangles = overrideSprite.triangles; 355 | count = triangles.Length; 356 | for (int i = 0; i < count; i += 3) 357 | { 358 | vh.AddTriangle(triangles[i], triangles[i + 1], triangles[i + 2]); 359 | } 360 | } 361 | 362 | 363 | 364 | /// 365 | /// Generate vertices for a simple Image. 366 | /// 367 | void GenerateSimpleSprite(VertexHelper vh, bool shouldPreserveAspect) 368 | { 369 | Vector4 v = GetDrawingDimensions(shouldPreserveAspect); 370 | var uv = (overrideSprite != null) ? UnityEngine.Sprites.DataUtility.GetOuterUV(overrideSprite) : Vector4.zero; 371 | 372 | var color32 = color; 373 | vh.Clear(); 374 | 375 | if (!fillCenter) 376 | { 377 | if (m_FillBorders != Vector4.zero) 378 | { 379 | AddBorders(vh, 380 | v, 381 | m_FillBorders, color, 382 | uv); 383 | } 384 | } 385 | else 386 | { 387 | if (!m_HorizontalMirror && !m_VerticalMirror) 388 | { 389 | vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(uv.x, uv.y)); 390 | vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(uv.x, uv.w)); 391 | vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(uv.z, uv.w)); 392 | vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(uv.z, uv.y)); 393 | 394 | vh.AddTriangle(0, 1, 2); 395 | vh.AddTriangle(2, 3, 0); 396 | } 397 | else 398 | { 399 | AddMirror(vh, v, color32, uv, m_HorizontalMirror, m_VerticalMirror); 400 | } 401 | } 402 | } 403 | 404 | /// 405 | /// Generate vertices for a 9-sliced Image. 406 | /// 407 | 408 | static readonly Vector2[] s_VertScratch = new Vector2[4]; 409 | static readonly Vector2[] s_UVScratch = new Vector2[4]; 410 | 411 | private void GenerateSlicedSprite(VertexHelper toFill) 412 | { 413 | if (!hasBorder) 414 | { 415 | GenerateSimpleSprite(toFill, false); 416 | return; 417 | } 418 | 419 | Vector4 outer, inner, padding, border; 420 | 421 | if (overrideSprite != null) 422 | { 423 | outer = UnityEngine.Sprites.DataUtility.GetOuterUV(overrideSprite); 424 | inner = UnityEngine.Sprites.DataUtility.GetInnerUV(overrideSprite); 425 | padding = UnityEngine.Sprites.DataUtility.GetPadding(overrideSprite); 426 | border = overrideSprite.border; 427 | } 428 | else 429 | { 430 | outer = Vector4.zero; 431 | inner = Vector4.zero; 432 | padding = Vector4.zero; 433 | border = Vector4.zero; 434 | } 435 | 436 | Rect rect = GetPixelAdjustedRect(); 437 | Vector4 adjustedBorders = GetAdjustedBorders(border / pixelsPerUnit, rect); 438 | padding = padding / pixelsPerUnit; 439 | if (m_HorizontalMirror) 440 | { 441 | adjustedBorders.z = adjustedBorders.x; 442 | } 443 | if (m_VerticalMirror) 444 | { 445 | adjustedBorders.y = adjustedBorders.w; 446 | } 447 | 448 | s_VertScratch[0] = new Vector2(padding.x, padding.y); 449 | s_VertScratch[3] = new Vector2(rect.width - padding.z, rect.height - padding.w); 450 | 451 | s_VertScratch[1].x = adjustedBorders.x; 452 | s_VertScratch[1].y = adjustedBorders.y; 453 | 454 | s_VertScratch[2].x = rect.width - adjustedBorders.z; 455 | s_VertScratch[2].y = rect.height - adjustedBorders.w; 456 | 457 | for (int i = 0; i < 4; ++i) 458 | { 459 | s_VertScratch[i].x += rect.x; 460 | s_VertScratch[i].y += rect.y; 461 | } 462 | 463 | s_UVScratch[0] = new Vector2(outer.x, outer.y); 464 | s_UVScratch[1] = new Vector2(inner.x, inner.y); 465 | s_UVScratch[2] = new Vector2(inner.z, inner.w); 466 | s_UVScratch[3] = new Vector2(outer.z, outer.w); 467 | 468 | toFill.Clear(); 469 | 470 | for (int x = 0; x < 3; ++x) 471 | { 472 | int x2 = x + 1; 473 | 474 | for (int y = 0; y < 3; ++y) 475 | { 476 | int y2 = y + 1; 477 | 478 | if (!fillCenter && x == 1 && y == 1) 479 | { 480 | if (m_FillBorders != Vector4.zero) 481 | { 482 | AddBorders(toFill, 483 | new Vector4(s_VertScratch[x].x, s_VertScratch[y].y, s_VertScratch[x2].x, s_VertScratch[y2].y), 484 | m_FillBorders, color, 485 | new Vector4(s_UVScratch[x].x, s_UVScratch[y].y, s_UVScratch[x2].x, s_UVScratch[y2].y)); 486 | } 487 | continue; 488 | } 489 | 490 | Vector4 uv; 491 | if (x == 2 && y == 0 && m_HorizontalMirror && m_VerticalMirror) 492 | { 493 | uv = new Vector4(s_UVScratch[1].x, s_UVScratch[3].y, s_UVScratch[0].x, s_UVScratch[2].y); 494 | } 495 | else if (x == 2 && m_HorizontalMirror) 496 | { 497 | uv = new Vector4(s_UVScratch[1].x, s_UVScratch[y].y, s_UVScratch[0].x, s_UVScratch[y2].y); 498 | } 499 | else if (y == 0 && m_VerticalMirror) 500 | { 501 | uv = new Vector4(s_UVScratch[x].x, s_UVScratch[3].y, s_UVScratch[x2].x, s_UVScratch[2].y); 502 | } 503 | else 504 | { 505 | uv = new Vector4(s_UVScratch[x].x, s_UVScratch[y].y, s_UVScratch[x2].x, s_UVScratch[y2].y); 506 | } 507 | 508 | AddMirror(toFill, 509 | new Vector4(s_VertScratch[x].x, s_VertScratch[y].y,s_VertScratch[x2].x, s_VertScratch[y2].y), 510 | color, 511 | uv, 512 | m_HorizontalMirror && x == 1, m_VerticalMirror && y == 1); 513 | } 514 | } 515 | } 516 | 517 | static void AddMirror(VertexHelper vh, Vector4 v, Color32 color32, Vector4 uv, bool hMirror, bool vMirror) 518 | { 519 | if (v.x >= v.z || v.y >= v.w) 520 | { 521 | return; 522 | } 523 | int si = vh.currentVertCount; 524 | 525 | if (hMirror && vMirror) 526 | { 527 | float d = (v.z - v.x) / 2f; 528 | v.z -= d; 529 | float d2 = (v.w - v.y) / 2f; 530 | v.y += d2; 531 | vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(uv.x, uv.y)); 532 | vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(uv.x, uv.w)); 533 | vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(uv.z, uv.w)); 534 | vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(uv.z, uv.y)); 535 | 536 | vh.AddVert(new Vector3(v.z + d, v.w), color32, new Vector2(uv.x, uv.w)); 537 | vh.AddVert(new Vector3(v.z + d, v.y), color32, new Vector2(uv.x, uv.y)); 538 | 539 | vh.AddVert(new Vector3(v.x, v.y - d2), color32, new Vector2(uv.x, uv.w)); 540 | vh.AddVert(new Vector3(v.z, v.y - d2), color32, new Vector2(uv.z, uv.w)); 541 | vh.AddVert(new Vector3(v.z + d, v.y - d2), color32, new Vector2(uv.x, uv.w)); 542 | 543 | vh.AddTriangle(si, si + 1, si + 2); 544 | vh.AddTriangle(si + 2, si + 3, si); 545 | vh.AddTriangle(si + 3, si + 2, si + 5); 546 | vh.AddTriangle(si + 5, si + 2, si + 4); 547 | vh.AddTriangle(si, si + 3, si + 7); 548 | vh.AddTriangle(si, si + 7, si + 6); 549 | vh.AddTriangle(si + 3, si + 5, si + 7); 550 | vh.AddTriangle(si + 5, si + 8, si + 7); 551 | } 552 | else if (hMirror) 553 | { 554 | float d = (v.z - v.x) / 2f; 555 | v.z -= d; 556 | vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(uv.x, uv.y)); 557 | vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(uv.x, uv.w)); 558 | vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(uv.z, uv.w)); 559 | vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(uv.z, uv.y)); 560 | 561 | vh.AddVert(new Vector3(v.z + d, v.w), color32, new Vector2(uv.x, uv.w)); 562 | vh.AddVert(new Vector3(v.z + d, v.y), color32, new Vector2(uv.x, uv.y)); 563 | 564 | vh.AddTriangle(si, si + 1, si + 2); 565 | vh.AddTriangle(si + 2, si + 3, si); 566 | vh.AddTriangle(si + 3, si + 2, si + 5); 567 | vh.AddTriangle(si + 5, si + 2, si + 4); 568 | } 569 | else if (vMirror) 570 | { 571 | float d = (v.w - v.y) / 2f; 572 | v.y += d; 573 | vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(uv.x, uv.y)); 574 | vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(uv.x, uv.w)); 575 | vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(uv.z, uv.w)); 576 | vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(uv.z, uv.y)); 577 | 578 | vh.AddVert(new Vector3(v.x, v.y - d), color32, new Vector2(uv.x, uv.w)); 579 | vh.AddVert(new Vector3(v.z, v.y - d), color32, new Vector2(uv.z, uv.w)); 580 | 581 | vh.AddTriangle(si, si + 1, si + 2); 582 | vh.AddTriangle(si + 2, si + 3, si); 583 | vh.AddTriangle(si, si + 3, si + 5); 584 | vh.AddTriangle(si, si + 5, si + 4); 585 | } 586 | else 587 | { 588 | vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(uv.x, uv.y)); 589 | vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(uv.x, uv.w)); 590 | vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(uv.z, uv.w)); 591 | vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(uv.z, uv.y)); 592 | 593 | vh.AddTriangle(si, si + 1, si + 2); 594 | vh.AddTriangle(si + 2, si + 3, si); 595 | } 596 | } 597 | 598 | static void AddBorders(VertexHelper vertexHelper, Vector4 pos, Vector4 border,Color32 color, Vector4 uv) 599 | { 600 | float w = pos.z - pos.x; 601 | float h = pos.w - pos.y; 602 | float uvW = uv.z - uv.x; 603 | float uvH = uv.w - uv.y; 604 | Vector4 inner = new Vector4(pos.x + w * border.x, 605 | pos.y + h * border.y, 606 | pos.z - w * border.z, 607 | pos.w - h * border.w); 608 | 609 | Vector4 innerUv = new Vector4(uv.x + uvW * border.x, 610 | uv.y + uvH * border.y, 611 | uv.z - uvW * border.z, 612 | uv.w - uvH * border.w); 613 | 614 | if (border.y > 0) 615 | AddQuad(vertexHelper, new Vector4(pos.x, pos.y, pos.z, inner.y), color, new Vector4(uv.x, uv.y, uv.z, innerUv.y)); 616 | if (border.w > 0) 617 | AddQuad(vertexHelper, new Vector4(pos.x, inner.w, pos.z, pos.w), color, new Vector4(uv.x, innerUv.w, uv.z, uv.w)); 618 | if (border.x > 0) 619 | AddQuad(vertexHelper, new Vector4(pos.x, inner.y, inner.x, inner.w), color, new Vector4(uv.x, innerUv.y, innerUv.x, innerUv.w)); 620 | if (border.z > 0) 621 | AddQuad(vertexHelper, new Vector4(inner.z, inner.y, pos.z, inner.w), color, new Vector4(innerUv.z, innerUv.y, uv.z, innerUv.w)); 622 | } 623 | 624 | static void AddQuad(VertexHelper vertexHelper, Vector4 pos, Color32 color, Vector4 uv) 625 | { 626 | int startIndex = vertexHelper.currentVertCount; 627 | 628 | vertexHelper.AddVert(new Vector3(pos.x, pos.y, 0), color, new Vector2(uv.x, uv.y)); 629 | vertexHelper.AddVert(new Vector3(pos.x, pos.w, 0), color, new Vector2(uv.x, uv.w)); 630 | vertexHelper.AddVert(new Vector3(pos.z, pos.w, 0), color, new Vector2(uv.z, uv.w)); 631 | vertexHelper.AddVert(new Vector3(pos.z, pos.y, 0), color, new Vector2(uv.z, uv.y)); 632 | 633 | vertexHelper.AddTriangle(startIndex, startIndex + 1, startIndex + 2); 634 | vertexHelper.AddTriangle(startIndex + 2, startIndex + 3, startIndex); 635 | } 636 | 637 | Vector4 GetAdjustedBorders(Vector4 border, Rect rect) 638 | { 639 | for (int axis = 0; axis <= 1; axis++) 640 | { 641 | // If the rect is smaller than the combined borders, then there's not room for the borders at their normal size. 642 | // In order to avoid artefacts with overlapping borders, we scale the borders down to fit. 643 | float combinedBorders = border[axis] + border[axis + 2]; 644 | if (rect.size[axis] < combinedBorders && combinedBorders != 0) 645 | { 646 | float borderScaleRatio = rect.size[axis] / combinedBorders; 647 | border[axis] *= borderScaleRatio; 648 | border[axis + 2] *= borderScaleRatio; 649 | } 650 | } 651 | return border; 652 | } 653 | 654 | 655 | /// Image's dimensions used for drawing. X = left, Y = bottom, Z = right, W = top. 656 | private Vector4 GetDrawingDimensions(bool shouldPreserveAspect) 657 | { 658 | Rect r = GetPixelAdjustedRect(); 659 | 660 | var size = overrideSprite == null ? Vector2.zero : new Vector2(overrideSprite.rect.width, overrideSprite.rect.height); 661 | var padding = overrideSprite == null ? Vector4.zero : UnityEngine.Sprites.DataUtility.GetPadding(overrideSprite); 662 | int spriteW = Mathf.RoundToInt(size.x); 663 | int spriteH = Mathf.RoundToInt(size.y); 664 | 665 | Vector4 v = new Vector4( 666 | padding.x / spriteW, 667 | padding.y / spriteH, 668 | (spriteW - padding.z) / spriteW, 669 | (spriteH - padding.w) / spriteH); 670 | 671 | if (shouldPreserveAspect) 672 | { 673 | PreserveAspect(ref r, size); 674 | } 675 | 676 | v = new Vector4( 677 | r.x + r.width * v.x, 678 | r.y + r.height * v.y, 679 | r.x + r.width * v.z, 680 | r.y + r.height * v.w 681 | ); 682 | 683 | return v; 684 | } 685 | 686 | private void PreserveAspect(ref Rect r,Vector2 size) 687 | { 688 | if (size.sqrMagnitude == 0.0f) 689 | return; 690 | 691 | var spriteRatio = size.x / size.y; 692 | var rectRatio = r.width / r.height; 693 | 694 | if (spriteRatio > rectRatio) 695 | { 696 | var oldHeight = r.height; 697 | r.height = r.width * (1.0f / spriteRatio); 698 | r.y += (oldHeight - r.height) * rectTransform.pivot.y; 699 | } 700 | else 701 | { 702 | var oldWidth = r.width; 703 | r.width = r.height * spriteRatio; 704 | r.x += (oldWidth - r.width) * rectTransform.pivot.x; 705 | } 706 | } 707 | 708 | #if UNITY_EDITOR 709 | protected override void OnValidate() 710 | { 711 | base.OnValidate(); 712 | UpdateVisible(); 713 | } 714 | 715 | private readonly static Vector3[] fourCorners = new Vector3[4]; 716 | private void OnDrawGizmosSelected() 717 | { 718 | if (this.raycastTarget) 719 | { 720 | Gizmos.color = Color.green; 721 | 722 | if (this.useSpriteHitArea) 723 | { 724 | Rect r = GetPixelAdjustedRect(); 725 | var size = new Vector2(overrideSprite.rect.width, overrideSprite.rect.height); 726 | Bounds bounds = overrideSprite.bounds; 727 | 728 | if (preserveAspect) 729 | { 730 | PreserveAspect(ref r, size); 731 | } 732 | 733 | float w = r.width / bounds.size.x; 734 | float h = r.height / bounds.size.y; 735 | Vector4 v = new Vector4(-w * bounds.center.x, 736 | -h * bounds.center.y, 737 | w, 738 | h); 739 | int count = overrideSprite.triangles.Length; 740 | var vertices = overrideSprite.vertices; 741 | var triangles = overrideSprite.triangles; 742 | Vector2 center = transform.position; 743 | for (int i = 0; i < count; i += 3) 744 | { 745 | Vector2 v1 = vertices[triangles[i]]; 746 | Vector2 v2 = vertices[triangles[i + 1]]; 747 | Vector2 v3 = vertices[triangles[i + 2]]; 748 | v1 = transform.TransformPoint(new Vector2(v.x + v1.x * v.z, v.y + v1.y * v.w)); 749 | v2 = transform.TransformPoint(new Vector2(v.x + v2.x * v.z, v.y + v2.y * v.w)); 750 | v3 = transform.TransformPoint(new Vector2(v.x + v3.x * v.z, v.y + v3.y * v.w)); 751 | v1 = transform.position + Vector3.Scale(v1 - center, hitScale); 752 | v2 = transform.position + Vector3.Scale(v2 - center, hitScale); 753 | v3 = transform.position + Vector3.Scale(v3 - center, hitScale); 754 | Gizmos.DrawLine(v1, v2); 755 | Gizmos.DrawLine(v2, v3); 756 | Gizmos.DrawLine(v3, v1); 757 | } 758 | } 759 | else 760 | { 761 | rectTransform.GetWorldCorners(fourCorners); 762 | for (int i = 0; i < 4; i++) 763 | { 764 | fourCorners[i] = transform.position + Vector3.Scale(fourCorners[i] - transform.position,hitScale); 765 | } 766 | for (int i = 0; i < 4; i++) 767 | { 768 | Gizmos.DrawLine(fourCorners[i], fourCorners[(i + 1) % 4]); 769 | } 770 | } 771 | } 772 | } 773 | #endif 774 | } 775 | } 776 | 777 | 778 | 779 | -------------------------------------------------------------------------------- /AdvancedComponent/AdvancedImage.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bee77fc9eb05d584590e222fbd6efa70 3 | timeCreated: 1509015394 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /AdvancedComponent/AdvancedText.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.UI; 5 | using System.Text.RegularExpressions; 6 | using UnityEngine.Serialization; 7 | using System; 8 | 9 | namespace UGUIExtend 10 | { 11 | [RequireComponent(typeof(RectTransform))] 12 | [RequireComponent(typeof(CanvasRenderer))] 13 | [AddComponentMenu("UI/AdvancedText", 12)] 14 | public class AdvancedText : Text 15 | { 16 | /// 17 | /// 加载图片的方法 18 | /// 19 | protected virtual void LoadSprite(Image image, string path) 20 | { 21 | if (image.sprite == null || image.sprite.name != path) 22 | { 23 | image.sprite = Resources.Load(imagePathRoot + path); ; 24 | } 25 | } 26 | 27 | [Serializable] 28 | public class CharOffest 29 | { 30 | public Vector2 position = Vector2.zero; 31 | public float rotation = 0f; 32 | public Vector2 scale = Vector2.one; 33 | } 34 | 35 | [Serializable] 36 | public class InLineImage 37 | { 38 | public bool cull; 39 | public Image image; 40 | public InLineImage(Image image) 41 | { 42 | this.image = image; 43 | this.cull = false; 44 | } 45 | } 46 | 47 | private static readonly Regex s_Regex = new Regex(@"", RegexOptions.Singleline); 48 | /// 49 | /// 可见度 50 | /// 51 | [SerializeField] 52 | private bool m_Visible = true; 53 | public bool visible 54 | { 55 | get { return m_Visible; } 56 | set 57 | { 58 | if (m_Visible != value) 59 | { 60 | m_Visible = value; 61 | UpdateVisible(); 62 | if (m_Visible) 63 | CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); 64 | } 65 | } 66 | } 67 | 68 | /// 69 | /// 外部图片加载目录 70 | /// 71 | [SerializeField] 72 | public string imagePathRoot = ""; 73 | 74 | public enum TextEffectType 75 | { 76 | NONE, 77 | SHADOW, 78 | OUTLINE4, 79 | OUTLINE8, 80 | MATERIAL 81 | } 82 | 83 | /// 84 | /// 文字描边类型 85 | /// 86 | [SerializeField] 87 | private TextEffectType m_EffectType = TextEffectType.NONE; 88 | public TextEffectType effectType 89 | { 90 | get { return m_EffectType; } 91 | set 92 | { 93 | if (m_EffectType != value) 94 | { 95 | m_EffectType = value; 96 | SetVerticesDirty(); 97 | } 98 | } 99 | } 100 | 101 | /// 102 | /// 文字描边颜色 103 | /// 104 | [SerializeField] 105 | private Color32 m_EffectColor = new Color(0, 0, 0, 128); 106 | public Color32 effectColor 107 | { 108 | get { return m_EffectColor; } 109 | set 110 | { 111 | if (!Equals(m_EffectColor, value)) 112 | { 113 | m_EffectColor = value; 114 | SetVerticesDirty(); 115 | } 116 | } 117 | } 118 | 119 | /// 120 | /// 文字描边宽度 121 | /// 122 | [SerializeField] 123 | private Vector2 m_EffectDistance = new Vector2(1f, -1f); 124 | public Vector2 effectDistance 125 | { 126 | get { return m_EffectDistance; } 127 | set 128 | { 129 | if (m_EffectDistance != value) 130 | { 131 | m_EffectDistance = value; 132 | SetVerticesDirty(); 133 | } 134 | } 135 | } 136 | 137 | /// 138 | /// 是否混合描边透明度(取消可增加性能) 139 | /// 140 | [SerializeField] 141 | private bool m_UseGraphicAlpha = false; 142 | public bool useGraphicAlpha 143 | { 144 | get { return m_UseGraphicAlpha; } 145 | set 146 | { 147 | if (m_UseGraphicAlpha != value) 148 | { 149 | m_UseGraphicAlpha = value; 150 | SetVerticesDirty(); 151 | } 152 | } 153 | } 154 | [SerializeField] 155 | private bool m_EnabledGradient = false; 156 | public bool enabledGradient 157 | { 158 | get { return m_EnabledGradient; } 159 | set 160 | { 161 | if (m_EnabledGradient != value) 162 | { 163 | m_EnabledGradient = value; 164 | SetVerticesDirty(); 165 | } 166 | } 167 | } 168 | [SerializeField] 169 | private Color m_GradientColor = Color.white; 170 | public Color gradientColor 171 | { 172 | get { return m_GradientColor; } 173 | set 174 | { 175 | if (m_GradientColor != value) 176 | { 177 | m_GradientColor = value; 178 | SetVerticesDirty(); 179 | } 180 | } 181 | } 182 | 183 | /// 184 | /// 单字位移 185 | /// 186 | [SerializeField] 187 | public List charOffests; 188 | 189 | /// 190 | /// 设置单字位移 191 | /// 192 | public void SetCharOffest(int index, Vector3 position) 193 | { 194 | SeekToCharOffestIndex(index); 195 | this.charOffests[index].position = position; 196 | SetVerticesDirty(); 197 | } 198 | 199 | public void SetCharOffest(int index, Vector3 position, float rotation) 200 | { 201 | SetCharOffest(index, position); 202 | this.charOffests[index].rotation = rotation; 203 | SetVerticesDirty(); 204 | } 205 | 206 | public void SetCharOffest(int index, Vector3 position, float rotation, Vector3 scale) 207 | { 208 | SetCharOffest(index, position, rotation); 209 | this.charOffests[index].scale = scale; 210 | SetVerticesDirty(); 211 | } 212 | 213 | private void SeekToCharOffestIndex(int index) 214 | { 215 | for (int i = charOffests.Count; i <= index; i++) 216 | this.charOffests.Add(null); 217 | 218 | if (this.charOffests[index] == null) 219 | this.charOffests[index] = new CharOffest(); 220 | } 221 | 222 | protected override void OnEnable() 223 | { 224 | base.OnEnable(); 225 | if (inlineImages != null) 226 | { 227 | int count = inlineImages.Count; 228 | for (int i = 0; i < count; i++) 229 | { 230 | if (inlineImages[i].image != null) 231 | inlineImages[i].image.enabled = true; 232 | } 233 | } 234 | UpdateVisible(); 235 | } 236 | 237 | protected override void OnDisable() 238 | { 239 | base.OnDisable(); 240 | if (inlineImages != null) 241 | { 242 | int count = inlineImages.Count; 243 | for (int i = 0; i < count; i++) 244 | { 245 | if (inlineImages[i].image != null) 246 | inlineImages[i].image.enabled = false; 247 | } 248 | } 249 | } 250 | 251 | protected virtual void UpdateVisible() 252 | { 253 | this.canvasRenderer.cull = !m_Visible; 254 | if (inlineImages != null) 255 | { 256 | int count = inlineImages.Count; 257 | for (int i = 0; i < count; i++) 258 | { 259 | InLineImage item = inlineImages[i]; 260 | if (item.image != null) 261 | { 262 | bool cull = !m_Visible || item.cull; 263 | if (cull != item.image.canvasRenderer.cull) 264 | { 265 | item.image.canvasRenderer.cull = cull; 266 | if (!cull) 267 | { 268 | CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(item.image);//不加这个在隐藏状态时有变化不会更新 269 | } 270 | } 271 | } 272 | } 273 | } 274 | } 275 | 276 | /// 277 | /// 清除不使用的图片,释放内存 278 | /// 279 | public void ClearUnUsedInLineImage() 280 | { 281 | if (inlineImages != null) 282 | { 283 | int needCount = inlineCharIndex.Count; 284 | int count = inlineImages.Count; 285 | for (int i = count - 1; i > 0; i--) 286 | { 287 | InLineImage item = inlineImages[i]; 288 | if (item.image != null && i >= needCount) 289 | { 290 | if (Application.isPlaying) 291 | GameObject.Destroy(item.image.gameObject); 292 | #if UNITY_EDITOR 293 | else 294 | GameObject.DestroyImmediate(item.image.gameObject); 295 | #endif 296 | item.image = null; 297 | } 298 | if (item.image == null) 299 | { 300 | inlineImages.RemoveAt(i); 301 | } 302 | } 303 | } 304 | SetVerticesDirty(); 305 | m_FilterText = FilterRichText(m_Text); 306 | } 307 | 308 | private string m_OldNoFilterText; 309 | private string m_FilterText; 310 | private bool m_OldSupportRichText; 311 | public override void SetVerticesDirty() 312 | { 313 | base.SetVerticesDirty(); 314 | if (m_OldNoFilterText != m_Text || m_OldSupportRichText != supportRichText) 315 | { 316 | m_OldNoFilterText = m_Text; 317 | m_OldSupportRichText = supportRichText; 318 | m_FilterText = FilterRichText(m_Text); 319 | } 320 | } 321 | 322 | [SerializeField] private List inlineImages = new List(); 323 | private List inlineCharIndex = new List(); 324 | private void SetInLineImageCull(int index, bool cull) 325 | { 326 | InLineImage item = inlineImages[index]; 327 | if (item.image == null) 328 | return; 329 | 330 | item.cull = cull; 331 | if (cull != item.image.canvasRenderer.cull) 332 | { 333 | item.image.canvasRenderer.cull = cull; 334 | if (!cull) 335 | { 336 | item.image.Rebuild(CanvasUpdate.PreRender);//不加这个在隐藏状态时有变化不会更新 337 | } 338 | } 339 | } 340 | 341 | private string FilterRichText(string text) 342 | { 343 | inlineCharIndex.Clear(); 344 | int i = 0; 345 | if (supportRichText) 346 | { 347 | Match match; 348 | do 349 | { 350 | match = s_Regex.Match(text); 351 | if (match.Success) 352 | { 353 | inlineCharIndex.Add(match.Index); 354 | 355 | string src = match.Groups[1].Value; 356 | float width = string.IsNullOrEmpty(match.Groups[2].Value) ? float.NaN : float.Parse(match.Groups[2].Value); 357 | float height = string.IsNullOrEmpty(match.Groups[3].Value) ? float.NaN : float.Parse(match.Groups[3].Value); 358 | string newText = ""; 359 | Image img = null; 360 | if (i >= inlineImages.Count || inlineImages[i].image == null) 361 | { 362 | img = new GameObject("InlineImage" + (i + 1).ToString()).AddComponent(); 363 | img.transform.SetParent(this.transform, false); 364 | img.raycastTarget = false; 365 | if (i < inlineImages.Count) 366 | { 367 | inlineImages[i].image = img; 368 | inlineImages[i].cull = false; 369 | } 370 | else 371 | inlineImages.Add(new InLineImage(img)); 372 | } 373 | else 374 | { 375 | img = inlineImages[i].image; 376 | } 377 | 378 | LoadSprite(img, match.Groups[1].Value); 379 | Sprite spr = img.sprite; 380 | if (spr != null) 381 | { 382 | if (float.IsNaN(height) && float.IsNaN(width)) 383 | { 384 | height = fontSize; 385 | width = height / spr.rect.height * spr.rect.width; 386 | } 387 | else if (float.IsNaN(width)) 388 | { 389 | width = height / spr.rect.height * spr.rect.width; 390 | } 391 | else if (float.IsNaN(height)) 392 | { 393 | height = width / spr.rect.width * spr.rect.height; 394 | } 395 | img.rectTransform.sizeDelta = new Vector2(width, height); 396 | newText = ""; 399 | } 400 | text = text.Substring(0, match.Index) + newText + text.Substring(match.Index + match.Length); 401 | i++; 402 | } 403 | } while (match.Success); 404 | } 405 | int c = inlineImages.Count - 1; 406 | while (i <= c) 407 | { 408 | if (inlineImages[c].image != null) 409 | { 410 | inlineImages[c].image.sprite = null; 411 | SetInLineImageCull(c, true); 412 | } 413 | #if UNITY_EDITOR 414 | else 415 | { 416 | inlineImages.RemoveAt(c); 417 | } 418 | #endif 419 | c--; 420 | } 421 | return text; 422 | } 423 | 424 | readonly UIVertex[] m_TempVerts = new UIVertex[4]; 425 | readonly UIVertex[] m_TempEffectVerts = new UIVertex[4]; 426 | protected override void OnPopulateMesh(VertexHelper toFill) 427 | { 428 | if (font == null) 429 | return; 430 | 431 | // We don't care if we the font Texture changes while we are doing our Update. 432 | // The end result of cachedTextGenerator will be valid for this instance. 433 | // Otherwise we can get issues like Case 619238. 434 | m_DisableFontTextureRebuiltCallback = true; 435 | 436 | Vector2 extents = rectTransform.rect.size; 437 | 438 | var settings = GetGenerationSettings(extents); 439 | cachedTextGenerator.PopulateWithErrors(m_FilterText, settings, gameObject);//这里有缓存,不需要处理 440 | OnPopulateVertsPosition(toFill); 441 | 442 | m_DisableFontTextureRebuiltCallback = false; 443 | } 444 | 445 | protected virtual void OnPopulateVertsPosition(VertexHelper toFill) 446 | { 447 | // Apply the offset to the vertices 448 | IList verts = cachedTextGenerator.verts; 449 | float unitsPerPixel = 1 / pixelsPerUnit; 450 | //Last 4 verts are always a new line... (\n) 451 | int vertCount = verts.Count - 4; 452 | 453 | Vector2 roundingOffset = new Vector2(verts[0].position.x, verts[0].position.y) * unitsPerPixel; 454 | roundingOffset = PixelAdjustPoint(roundingOffset) - roundingOffset; 455 | toFill.Clear(); 456 | bool needOffest = roundingOffset != Vector2.zero; 457 | 458 | //处理图文混排的图片 459 | int count = this.inlineCharIndex.Count; 460 | for (int i = 0; i < count; i++) 461 | { 462 | int index = inlineCharIndex[i]; 463 | if (index * 4 + 3 < vertCount) 464 | { 465 | if (i < inlineImages.Count && inlineImages[i].image != null) 466 | { 467 | Vector2 topLeft = verts[index * 4 + 1].position; 468 | Vector2 bottomRight = verts[index * 4 + 3].position; 469 | Vector2 center = new Vector2((topLeft.x + bottomRight.x) * 0.5f, topLeft.y + (bottomRight.y - topLeft.y) * 0.6f); 470 | topLeft.y += (bottomRight.y - topLeft.y) * 0.5f; 471 | var image = inlineImages[i].image; 472 | image.transform.localPosition = center * unitsPerPixel; 473 | SetInLineImageCull(i, false); 474 | UIVertex newVertex = UIVertex.simpleVert; 475 | newVertex.position = center; 476 | verts[index * 4] = newVertex; 477 | verts[index * 4 + 1] = newVertex; 478 | verts[index * 4 + 2] = newVertex; 479 | verts[index * 4 + 3] = newVertex; 480 | } 481 | } 482 | else 483 | { 484 | if (i < inlineImages.Count) 485 | { 486 | SetInLineImageCull(i, true); 487 | } 488 | } 489 | } 490 | 491 | int charIndex = 0; 492 | bool hasCharOffests = charOffests != null && charOffests.Count > 0; 493 | 494 | float bottomY = float.MaxValue; 495 | float topY = float.MinValue; 496 | if (m_EnabledGradient) 497 | { 498 | for (int i = 0; i < vertCount; i += 2) 499 | { 500 | float y = verts[i].position.y; 501 | if (y > topY) 502 | { 503 | topY = y; 504 | } 505 | else if (y < bottomY) 506 | { 507 | bottomY = y; 508 | } 509 | } 510 | } 511 | 512 | for (int i = 0; i < vertCount; i += 4) 513 | { 514 | if (verts[i].position == verts[i + 1].position) 515 | continue; 516 | 517 | for (int j = 0; j < 4; ++j) 518 | { 519 | m_TempVerts[j] = verts[i + j]; 520 | m_TempVerts[j].position *= unitsPerPixel; 521 | if (needOffest) 522 | { 523 | m_TempVerts[j].position.x += roundingOffset.x; 524 | m_TempVerts[j].position.y += roundingOffset.y; 525 | } 526 | } 527 | 528 | //文字位移 529 | float cosRotate = 0f; 530 | float sinRotate = 0f; 531 | if (hasCharOffests && charIndex < charOffests.Count) 532 | { 533 | CharOffest charOffest = charOffests[charIndex]; 534 | bool needScale = charOffest.scale != Vector2.one; 535 | if (charOffest.rotation != 0f) 536 | { 537 | cosRotate = Mathf.Cos(charOffest.rotation); 538 | sinRotate = Mathf.Sin(charOffest.rotation); 539 | } 540 | if (charOffest != null) 541 | { 542 | Vector2 center = (m_TempVerts[0].position + m_TempVerts[2].position) / 2f; 543 | for (int j = 0; j < 4; ++j) 544 | { 545 | if (needScale) 546 | { 547 | m_TempVerts[j].position.x = center.x + (m_TempVerts[j].position.x - center.x) * charOffest.scale.x; 548 | m_TempVerts[j].position.y = center.y + (m_TempVerts[j].position.y - center.y) * charOffest.scale.y; 549 | } 550 | if (charOffest.rotation != 0f) 551 | { 552 | float dx = m_TempVerts[j].position.x - center.x; 553 | float dy = m_TempVerts[j].position.y - center.y; 554 | m_TempVerts[j].position.x = center.x + dx * cosRotate - dy * sinRotate; 555 | m_TempVerts[j].position.y = center.y + dx * sinRotate + dy * cosRotate; 556 | } 557 | m_TempVerts[j].position.x += charOffest.position.x; 558 | m_TempVerts[j].position.y += charOffest.position.y; 559 | } 560 | } 561 | } 562 | 563 | //渐变 564 | if (m_EnabledGradient) 565 | { 566 | ApplyGradientColor(m_TempVerts, color, m_GradientColor, topY, bottomY); 567 | } 568 | 569 | //阴影与描边 570 | if (m_EffectType != TextEffectType.NONE) 571 | { 572 | if (m_EffectType == TextEffectType.MATERIAL) 573 | { 574 | Vector2 bottomLeft = m_TempVerts[0].uv0; 575 | Vector2 topRight = m_TempVerts[2].uv0; 576 | if (bottomLeft.x > topRight.x) 577 | { 578 | bottomLeft = m_TempVerts[2].uv0; 579 | topRight = m_TempVerts[0].uv0; 580 | } 581 | Vector4 uvBounds = new Vector4(bottomLeft.x, bottomLeft.y, topRight.x, topRight.y); 582 | m_TempVerts[0].tangent = uvBounds; 583 | m_TempVerts[1].tangent = uvBounds; 584 | m_TempVerts[2].tangent = uvBounds; 585 | m_TempVerts[3].tangent = uvBounds; 586 | } 587 | else 588 | { 589 | m_TempVerts.CopyTo(m_TempEffectVerts, 0); 590 | ApplyColor(m_TempEffectVerts, m_EffectColor); 591 | ApplyOffestX(m_TempEffectVerts, m_EffectDistance.x); 592 | ApplyOffestY(m_TempEffectVerts, m_EffectDistance.y); 593 | toFill.AddUIVertexQuad(m_TempEffectVerts); 594 | if (m_EffectType != TextEffectType.SHADOW) 595 | { 596 | ApplyOffestY(m_TempEffectVerts, -m_EffectDistance.y - m_EffectDistance.y); 597 | toFill.AddUIVertexQuad(m_TempEffectVerts); 598 | ApplyOffestX(m_TempEffectVerts, -m_EffectDistance.x - m_EffectDistance.x); 599 | toFill.AddUIVertexQuad(m_TempEffectVerts); 600 | ApplyOffestY(m_TempEffectVerts, m_EffectDistance.y + m_EffectDistance.y); 601 | toFill.AddUIVertexQuad(m_TempEffectVerts); 602 | if (m_EffectType != TextEffectType.OUTLINE4) 603 | { 604 | const float sqrt2 = 1.414214f; 605 | ApplyOffestX(m_TempEffectVerts, m_EffectDistance.x); 606 | ApplyOffestY(m_TempEffectVerts, (sqrt2 - 1) * m_EffectDistance.y); 607 | toFill.AddUIVertexQuad(m_TempEffectVerts); 608 | ApplyOffestY(m_TempEffectVerts, -sqrt2 * 2 * m_EffectDistance.y); 609 | toFill.AddUIVertexQuad(m_TempEffectVerts); 610 | ApplyOffestY(m_TempEffectVerts, sqrt2 * m_EffectDistance.y); 611 | ApplyOffestX(m_TempEffectVerts, sqrt2 * m_EffectDistance.x); 612 | toFill.AddUIVertexQuad(m_TempEffectVerts); 613 | ApplyOffestX(m_TempEffectVerts, -sqrt2 * 2 * m_EffectDistance.x); 614 | toFill.AddUIVertexQuad(m_TempEffectVerts); 615 | } 616 | } 617 | } 618 | }; 619 | toFill.AddUIVertexQuad(m_TempVerts); 620 | charIndex++; 621 | }; 622 | } 623 | 624 | void ApplyColor(UIVertex[] vertexs, Color32 effectColor) 625 | { 626 | if (m_UseGraphicAlpha) 627 | effectColor.a = (byte)(effectColor.a * vertexs[0].color.a / 255); 628 | vertexs[0].color = effectColor; 629 | vertexs[1].color = effectColor; 630 | vertexs[2].color = effectColor; 631 | vertexs[3].color = effectColor; 632 | } 633 | 634 | void ApplyGradientColor(UIVertex[] vertexs, Color32 topColor, Color32 bottomColor, float topY, float bottomY) 635 | { 636 | if (m_UseGraphicAlpha) 637 | { 638 | topColor.a = (byte)(topColor.a * vertexs[0].color.a / 255); 639 | bottomColor.a = (byte)(bottomColor.a * vertexs[0].color.a / 255); 640 | } 641 | float uiElementHeight = topY - bottomY; 642 | vertexs[0].color = vertexs[1].color = Color32.Lerp(bottomColor, topColor, (vertexs[0].position.y - bottomY) / uiElementHeight); 643 | vertexs[2].color = vertexs[3].color = Color32.Lerp(bottomColor, topColor, (vertexs[2].position.y - bottomY) / uiElementHeight); 644 | } 645 | 646 | void ApplyOffestX(UIVertex[] vertexs, float v) 647 | { 648 | vertexs[0].position.x += v; 649 | vertexs[1].position.x += v; 650 | vertexs[2].position.x += v; 651 | vertexs[3].position.x += v; 652 | } 653 | 654 | void ApplyOffestY(UIVertex[] vertexs, float v) 655 | { 656 | vertexs[0].position.y += v; 657 | vertexs[1].position.y += v; 658 | vertexs[2].position.y += v; 659 | vertexs[3].position.y += v; 660 | } 661 | 662 | 663 | #if UNITY_EDITOR 664 | private readonly static Vector3[] fourCorners = new Vector3[4]; 665 | private void OnDrawGizmosSelected() 666 | { 667 | if (this.raycastTarget) 668 | { 669 | Gizmos.color = Color.green; 670 | rectTransform.GetWorldCorners(fourCorners); 671 | for (int i = 0; i < 4; i++) 672 | { 673 | Gizmos.DrawLine(fourCorners[i], fourCorners[(i + 1) % 4]); 674 | } 675 | } 676 | } 677 | 678 | protected override void OnValidate() 679 | { 680 | base.OnValidate(); 681 | UpdateVisible(); 682 | 683 | 684 | } 685 | #endif 686 | } 687 | } 688 | -------------------------------------------------------------------------------- /AdvancedComponent/AdvancedText.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 158dd5200e4d2634c99a208e0af5cad5 3 | timeCreated: 1509474729 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /AdvancedComponent/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0e92a42c4b8ad0f4ea65c8bfa2bd86ea 3 | folderAsset: yes 4 | timeCreated: 1516558021 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /AdvancedComponent/Editor/AdvancedImageEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.UI; 3 | using UnityEditor; 4 | using UnityEditor.AnimatedValues; 5 | 6 | namespace UGUIExtend 7 | { 8 | [CustomEditor(typeof(AdvancedImage), false)] 9 | [CanEditMultipleObjects] 10 | 11 | public class AdvancedImageEditor : UnityEditor.UI.ImageEditor 12 | { 13 | [MenuItem("GameObject/UI/Advanced Image", false, 3)] 14 | static void CreatePanel() 15 | { 16 | GameObject spriteObject = new GameObject("Sprite"); 17 | if (Selection.activeGameObject != null) 18 | { 19 | spriteObject.transform.parent = Selection.activeGameObject.transform; 20 | spriteObject.layer = Selection.activeGameObject.layer; 21 | } 22 | else 23 | { 24 | Canvas mainCanvas = GameObject.FindObjectOfType(); 25 | if (mainCanvas != null) 26 | { 27 | spriteObject.transform.parent = mainCanvas.transform; 28 | spriteObject.layer = mainCanvas.gameObject.layer; 29 | } 30 | } 31 | spriteObject.AddComponent(); 32 | Selection.objects = new Object[] { spriteObject }; 33 | } 34 | 35 | SerializedProperty m_Type; 36 | SerializedProperty m_UseSpriteMesh; 37 | SerializedProperty m_EnabledPopulateMesh; 38 | SerializedProperty m_Visible; 39 | SerializedProperty m_HorizontalMirror; 40 | SerializedProperty m_VerticalMirror; 41 | SerializedProperty m_FillCenter; 42 | SerializedProperty m_FillBorders; 43 | SerializedProperty m_HitArea; 44 | SerializedProperty m_UseSpriteHitArea; 45 | SerializedProperty m_HitScale; 46 | AnimBool m_ShowFillBorders; 47 | AnimBool m_ShowFillMirror; 48 | protected override void OnEnable() 49 | { 50 | base.OnEnable(); 51 | 52 | m_Type = serializedObject.FindProperty("m_Type"); 53 | 54 | m_UseSpriteMesh = serializedObject.FindProperty("m_UseSpriteMesh"); 55 | m_EnabledPopulateMesh = serializedObject.FindProperty("m_EnabledPopulateMesh"); 56 | m_Visible = serializedObject.FindProperty("m_Visible"); 57 | m_HorizontalMirror = serializedObject.FindProperty("m_HorizontalMirror"); 58 | m_VerticalMirror = serializedObject.FindProperty("m_VerticalMirror"); 59 | m_FillCenter = serializedObject.FindProperty("m_FillCenter"); 60 | m_FillBorders = serializedObject.FindProperty("m_FillBorders"); 61 | m_HitArea = serializedObject.FindProperty("hitArea"); 62 | m_UseSpriteHitArea = serializedObject.FindProperty("useSpriteHitArea"); 63 | m_HitScale = serializedObject.FindProperty("hitScale"); 64 | 65 | 66 | m_ShowFillBorders = new AnimBool(!m_FillCenter.hasMultipleDifferentValues && m_FillCenter.boolValue == false); 67 | m_ShowFillBorders.valueChanged.AddListener(Repaint); 68 | m_ShowFillMirror = new AnimBool(!m_FillCenter.hasMultipleDifferentValues && m_FillCenter.boolValue == false); 69 | m_ShowFillMirror.valueChanged.AddListener(Repaint); 70 | } 71 | 72 | protected override void OnDisable() 73 | { 74 | base.OnDisable(); 75 | m_ShowFillBorders.valueChanged.AddListener(Repaint); 76 | m_ShowFillMirror.valueChanged.AddListener(Repaint); 77 | } 78 | 79 | public override void OnInspectorGUI() 80 | { 81 | base.OnInspectorGUI(); 82 | 83 | Image.Type typeEnum = (Image.Type)m_Type.enumValueIndex; 84 | 85 | if (!m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Simple) 86 | { 87 | m_ShowFillBorders.target = !m_FillCenter.hasMultipleDifferentValues && m_FillCenter.boolValue == false; 88 | m_ShowFillMirror.target = !m_UseSpriteMesh.hasMultipleDifferentValues && m_UseSpriteMesh.boolValue == false; 89 | ++EditorGUI.indentLevel; 90 | EditorGUILayout.PropertyField(m_UseSpriteMesh); 91 | if (EditorGUILayout.BeginFadeGroup(m_ShowFillMirror.faded)) 92 | { 93 | EditorGUILayout.PropertyField(m_FillCenter); 94 | if (m_ShowFillBorders.target) 95 | { 96 | ++EditorGUI.indentLevel; 97 | m_FillBorders.vector4Value = EditorGUILayout.Vector4Field("Fill Borders", m_FillBorders.vector4Value); m_FillBorders.vector4Value = new Vector4(Mathf.Clamp01(m_FillBorders.vector4Value.x), 98 | Mathf.Clamp01(m_FillBorders.vector4Value.y), 99 | Mathf.Clamp01(m_FillBorders.vector4Value.z), 100 | Mathf.Clamp01(m_FillBorders.vector4Value.w)); 101 | --EditorGUI.indentLevel; 102 | } 103 | else 104 | { 105 | EditorGUILayout.PropertyField(m_HorizontalMirror); 106 | EditorGUILayout.PropertyField(m_VerticalMirror); 107 | } 108 | } 109 | EditorGUILayout.EndFadeGroup(); 110 | --EditorGUI.indentLevel; 111 | } 112 | else if (!m_Type.hasMultipleDifferentValues && typeEnum == Image.Type.Sliced) 113 | { 114 | m_ShowFillBorders.target = !m_FillCenter.hasMultipleDifferentValues && m_FillCenter.boolValue == false; 115 | m_ShowFillMirror.target = !m_UseSpriteMesh.hasMultipleDifferentValues && m_UseSpriteMesh.boolValue == false; 116 | ++EditorGUI.indentLevel; 117 | if (EditorGUILayout.BeginFadeGroup(m_ShowFillBorders.faded)) 118 | { 119 | ++EditorGUI.indentLevel; 120 | m_FillBorders.vector4Value = EditorGUILayout.Vector4Field("Fill Borders", m_FillBorders.vector4Value); 121 | m_FillBorders.vector4Value = new Vector4(Mathf.Clamp01(m_FillBorders.vector4Value.x), 122 | Mathf.Clamp01(m_FillBorders.vector4Value.y), 123 | Mathf.Clamp01(m_FillBorders.vector4Value.z), 124 | Mathf.Clamp01(m_FillBorders.vector4Value.w)); 125 | --EditorGUI.indentLevel; 126 | } 127 | EditorGUILayout.EndFadeGroup(); 128 | EditorGUILayout.PropertyField(m_HorizontalMirror); 129 | EditorGUILayout.PropertyField(m_VerticalMirror); 130 | --EditorGUI.indentLevel; 131 | } 132 | EditorGUILayout.PropertyField(m_EnabledPopulateMesh); 133 | EditorGUILayout.PropertyField(m_Visible); 134 | EditorGUILayout.Separator(); 135 | EditorGUILayout.PropertyField(m_HitArea); 136 | EditorGUILayout.PropertyField(m_UseSpriteHitArea); 137 | EditorGUILayout.PropertyField(m_HitScale); 138 | m_HitScale.vector2Value = new Vector2(Mathf.Clamp01(m_HitScale.vector2Value.x), Mathf.Clamp01(m_HitScale.vector2Value.y)); 139 | 140 | serializedObject.ApplyModifiedProperties(); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /AdvancedComponent/Editor/AdvancedImageEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aa06f024240497e4a8f1826b5fbed5b0 3 | timeCreated: 1508839631 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /AdvancedComponent/Editor/AdvancedTextEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | 4 | namespace UGUIExtend 5 | { 6 | [CustomEditor(typeof(AdvancedText), false)] 7 | [CanEditMultipleObjects] 8 | 9 | public class AdvancedTextEditor : UnityEditor.UI.TextEditor 10 | { 11 | [MenuItem("GameObject/UI/Advanced Text", false, 3)] 12 | static void CreatePanel() 13 | { 14 | GameObject spriteObject = new GameObject("Text"); 15 | if (Selection.activeGameObject != null) 16 | { 17 | spriteObject.transform.parent = Selection.activeGameObject.transform; 18 | spriteObject.layer = Selection.activeGameObject.layer; 19 | } 20 | else 21 | { 22 | Canvas mainCanvas = GameObject.FindObjectOfType(); 23 | if (mainCanvas != null) 24 | { 25 | spriteObject.transform.parent = mainCanvas.transform; 26 | spriteObject.layer = mainCanvas.gameObject.layer; 27 | } 28 | } 29 | AdvancedText t = spriteObject.AddComponent(); 30 | t.supportRichText = false; 31 | t.raycastTarget = false; 32 | Selection.objects = new Object[] { spriteObject }; 33 | } 34 | 35 | SerializedProperty m_EffectType; 36 | SerializedProperty m_EffectColor; 37 | SerializedProperty m_EffectDistance; 38 | SerializedProperty m_UseGraphicAlpha; 39 | SerializedProperty m_EnabledGradient; 40 | SerializedProperty m_GradientColor; 41 | SerializedProperty imagePathRoot; 42 | SerializedProperty charOffests; 43 | SerializedProperty m_Visible; 44 | protected override void OnEnable() 45 | { 46 | base.OnEnable(); 47 | 48 | m_EffectType = serializedObject.FindProperty("m_EffectType"); 49 | m_EffectColor = serializedObject.FindProperty("m_EffectColor"); 50 | m_EffectDistance = serializedObject.FindProperty("m_EffectDistance"); 51 | m_UseGraphicAlpha = serializedObject.FindProperty("m_UseGraphicAlpha"); 52 | m_EnabledGradient = serializedObject.FindProperty("m_EnabledGradient"); 53 | m_GradientColor = serializedObject.FindProperty("m_GradientColor"); 54 | imagePathRoot = serializedObject.FindProperty("imagePathRoot"); 55 | charOffests = serializedObject.FindProperty("charOffests"); 56 | m_Visible = serializedObject.FindProperty("m_Visible"); 57 | } 58 | 59 | public override void OnInspectorGUI() 60 | { 61 | base.OnInspectorGUI(); 62 | EditorGUILayout.PropertyField(m_Visible); 63 | EditorGUILayout.PropertyField(m_EffectType); 64 | if (m_EffectType.enumValueIndex != 0) 65 | { 66 | EditorGUILayout.PropertyField(m_EffectColor); 67 | EditorGUILayout.PropertyField(m_EffectDistance); 68 | EditorGUILayout.PropertyField(m_UseGraphicAlpha); 69 | } 70 | EditorGUILayout.PropertyField(m_EnabledGradient); 71 | if (m_EnabledGradient.boolValue) 72 | { 73 | EditorGUILayout.PropertyField(m_GradientColor); 74 | } 75 | EditorGUILayout.PropertyField(imagePathRoot); 76 | if (GUILayout.Button("Clear InlineImage")) 77 | { 78 | foreach (Object target in this.targets) 79 | { 80 | AdvancedText text = target as AdvancedText; 81 | if (text != null) 82 | text.ClearUnUsedInLineImage(); 83 | } 84 | } 85 | EditorGUILayout.PropertyField(charOffests,true); 86 | serializedObject.ApplyModifiedProperties(); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /AdvancedComponent/Editor/AdvancedTextEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0c23a9248f27538448cef8070cd43317 3 | timeCreated: 1509635601 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /AdvancedComponent/ShaderOutLine.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine.UI; 5 | 6 | namespace UnityEngine.UI 7 | { 8 | [AddComponentMenu("UI/Effects/OutLineMaterial")] 9 | public class ShaderOutLine : BaseMeshEffect 10 | { 11 | private static List output = new List(); 12 | public override void ModifyMesh(VertexHelper vh) 13 | { 14 | if (!IsActive()) 15 | return; 16 | 17 | vh.GetUIVertexStream(output); 18 | 19 | int count = output.Count; 20 | for (int i = 0; i < count; i += 6) 21 | { 22 | if (i + 3 >= count) 23 | break; 24 | 25 | UIVertex v1 = output[i]; 26 | UIVertex v2 = output[i + 1]; 27 | UIVertex v3 = output[i + 2]; 28 | UIVertex v4 = output[i + 3]; 29 | UIVertex v5 = output[i + 4]; 30 | UIVertex v6 = output[i + 5]; 31 | Vector2 bottomLeft = v1.uv0; 32 | Vector2 topRight = v4.uv0; 33 | if (bottomLeft.x > topRight.x) 34 | { 35 | bottomLeft = v4.uv0; 36 | topRight = v1.uv0; 37 | } 38 | Vector4 uvBounds = new Vector4(bottomLeft.x, bottomLeft.y, topRight.x, topRight.y); 39 | v1.tangent = uvBounds; 40 | v2.tangent = uvBounds; 41 | v3.tangent = uvBounds; 42 | v4.tangent = uvBounds; 43 | v5.tangent = uvBounds; 44 | v6.tangent = uvBounds; 45 | output[i] = v1; 46 | output[i + 1] = v2; 47 | output[i + 2] = v3; 48 | output[i + 3] = v4; 49 | output[i + 4] = v5; 50 | output[i + 5] = v6; 51 | } 52 | 53 | vh.Clear(); 54 | vh.AddUIVertexTriangleStream(output); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /AdvancedComponent/ShaderOutLine.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eb612963d5018aa42bd4f9928e0b8bcb 3 | timeCreated: 1511101807 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /AdvancedComponent/UI-OutLine.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_PrefabParentObject: {fileID: 0} 8 | m_PrefabInternal: {fileID: 0} 9 | m_Name: UI-OutLine 10 | m_Shader: {fileID: 4800000, guid: cb41d288784463b4e90274fae29514e4, type: 3} 11 | m_ShaderKeywords: 12 | m_LightmapFlags: 4 13 | m_EnableInstancingVariants: 0 14 | m_DoubleSidedGI: 0 15 | m_CustomRenderQueue: -1 16 | stringTagMap: {} 17 | disabledShaderPasses: [] 18 | m_SavedProperties: 19 | serializedVersion: 3 20 | m_TexEnvs: 21 | - _MainTex: 22 | m_Texture: {fileID: 0} 23 | m_Scale: {x: 1, y: 1} 24 | m_Offset: {x: 0, y: 0} 25 | m_Floats: 26 | - _BorderClipWidth: 0.07 27 | - _BorderWidth: 0.55 28 | - _ColorMask: 15 29 | - _Stencil: 0 30 | - _StencilComp: 8 31 | - _StencilOp: 0 32 | - _StencilReadMask: 255 33 | - _StencilWriteMask: 255 34 | - _UseUIAlphaClip: 0 35 | m_Colors: 36 | - _BorderColor: {r: 0, g: 0, b: 0, a: 1} 37 | - _Color: {r: 1, g: 1, b: 1, a: 1} 38 | -------------------------------------------------------------------------------- /AdvancedComponent/UI-OutLine.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: beefb686d684f454082dcf44965a7138 3 | timeCreated: 1509438980 4 | licenseType: Free 5 | NativeFormatImporter: 6 | externalObjects: {} 7 | mainObjectFileID: 2100000 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /AdvancedComponent/UI-OutLine.shader: -------------------------------------------------------------------------------- 1 | Shader "UI/OutLine" 2 | { 3 | Properties 4 | { 5 | [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} 6 | _Color ("Tint", Color) = (1,1,1,1) 7 | 8 | _StencilComp ("Stencil Comparison", Float) = 8 9 | _Stencil ("Stencil ID", Float) = 0 10 | _StencilOp ("Stencil Operation", Float) = 0 11 | _StencilWriteMask ("Stencil Write Mask", Float) = 255 12 | _StencilReadMask ("Stencil Read Mask", Float) = 255 13 | 14 | _ColorMask ("Color Mask", Float) = 15 15 | _BorderWidth ("Border Width", Float) = 1 16 | _BorderColor ("Border Color", Color) = (0,0,0,1) 17 | 18 | [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0 19 | } 20 | 21 | SubShader 22 | { 23 | Tags 24 | { 25 | "Queue"="Transparent" 26 | "IgnoreProjector"="True" 27 | "RenderType"="Transparent" 28 | "PreviewType"="Plane" 29 | "CanUseSpriteAtlas"="True" 30 | } 31 | 32 | Stencil 33 | { 34 | Ref [_Stencil] 35 | Comp [_StencilComp] 36 | Pass [_StencilOp] 37 | ReadMask [_StencilReadMask] 38 | WriteMask [_StencilWriteMask] 39 | } 40 | 41 | Cull Off 42 | Lighting Off 43 | ZWrite Off 44 | ZTest [unity_GUIZTestMode] 45 | Blend SrcAlpha OneMinusSrcAlpha 46 | ColorMask [_ColorMask] 47 | 48 | Pass 49 | { 50 | Name "Default" 51 | CGPROGRAM 52 | #pragma vertex vert 53 | #pragma fragment frag 54 | #pragma target 2.0 55 | 56 | #include "UnityCG.cginc" 57 | #include "UnityUI.cginc" 58 | 59 | #pragma multi_compile __ UNITY_UI_ALPHACLIP 60 | 61 | struct appdata_t 62 | { 63 | float4 vertex : POSITION; 64 | float4 color : COLOR; 65 | float2 texcoord : TEXCOORD0; 66 | float4 tangent : TANGENT; 67 | UNITY_VERTEX_INPUT_INSTANCE_ID 68 | }; 69 | 70 | struct v2f 71 | { 72 | float4 vertex : SV_POSITION; 73 | fixed4 color : COLOR; 74 | float2 texcoord : TEXCOORD0; 75 | float4 worldPosition : TEXCOORD1; 76 | half4 clipRect : TEXCOORD2; 77 | half2 borderWidth : TEXCOORD3; 78 | UNITY_VERTEX_OUTPUT_STEREO 79 | }; 80 | 81 | 82 | sampler2D _MainTex; 83 | half4 _MainTex_TexelSize; 84 | 85 | fixed4 _Color; 86 | fixed4 _TextureSampleAdd; 87 | float4 _ClipRect; 88 | half _BorderWidth; 89 | fixed4 _BorderColor; 90 | 91 | 92 | v2f vert(appdata_t v) 93 | { 94 | v2f OUT; 95 | UNITY_SETUP_INSTANCE_ID(v); 96 | UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); 97 | OUT.worldPosition = v.vertex; 98 | OUT.vertex = UnityObjectToClipPos(OUT.worldPosition); 99 | 100 | OUT.texcoord = v.texcoord; 101 | 102 | half2 borderWidth = _BorderWidth / _MainTex_TexelSize.zw; 103 | OUT.clipRect = half4(v.tangent.xy + borderWidth,v.tangent.zw - borderWidth); 104 | OUT.borderWidth = borderWidth; 105 | 106 | OUT.color = v.color * _Color; 107 | 108 | return OUT; 109 | } 110 | 111 | fixed4 frag(v2f IN) : SV_Target 112 | { 113 | half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color; 114 | half4 border1 = tex2D(_MainTex, IN.texcoord + IN.borderWidth); 115 | half4 border2 = tex2D(_MainTex, IN.texcoord - IN.borderWidth); 116 | IN.borderWidth.x = -IN.borderWidth.x; 117 | half4 border3 = tex2D(_MainTex, IN.texcoord + IN.borderWidth); 118 | half4 border4 = tex2D(_MainTex, IN.texcoord - IN.borderWidth); 119 | half2 insideXY = step(IN.clipRect.xy,IN.texcoord.xy); 120 | half2 insideZW = step(IN.texcoord.xy,IN.clipRect.zw); 121 | border1 *= insideZW.x * insideZW.y; 122 | border2 *= insideXY.x * insideXY.y; 123 | border3 *= insideXY.x * insideZW.y; 124 | border4 *= insideZW.x * insideXY.y; 125 | half4 border = (saturate(border1 + border2 + border3 + border4) + _TextureSampleAdd) * _BorderColor; 126 | 127 | color = color * color.a + border * (1 - color.a); 128 | color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect); 129 | 130 | #ifdef UNITY_UI_ALPHACLIP 131 | clip (color.a - 0.001); 132 | #endif 133 | 134 | //color.ba = fixed2(0,1); 135 | //color.rg = (IN.texcoord.xy - IN.clipRect.xy) / (IN.clipRect.zw - IN.clipRect.xy); 136 | 137 | return color; 138 | } 139 | ENDCG 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /AdvancedComponent/UI-OutLine.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cb41d288784463b4e90274fae29514e4 3 | timeCreated: 1509438924 4 | licenseType: Free 5 | ShaderImporter: 6 | externalObjects: {} 7 | defaultTextures: [] 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /AutoCreateImage.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f2b80565ddcac3c468a99bdb901df00a 3 | folderAsset: yes 4 | timeCreated: 1516558974 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /AutoCreateImage/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 96a7cc95126b21f449ca04a162a943bb 3 | folderAsset: yes 4 | timeCreated: 1516558992 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /AutoCreateImage/Editor/AutoCreateImage.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | using System.Collections.Generic; 4 | 5 | namespace UGUIExtend 6 | { 7 | [InitializeOnLoad] 8 | public class AutoCreateImage 9 | { 10 | static AutoCreateImage() 11 | { 12 | EditorApplication.hierarchyWindowItemOnGUI += HierarchyWindowItemCallback; 13 | SceneView.onSceneGUIDelegate += HierarchyWindowItemCallback; 14 | } 15 | 16 | static void HierarchyWindowItemCallback(SceneView scene) 17 | { 18 | if (Event.current.type != EventType.DragPerform) 19 | return; 20 | 21 | Vector2 mousePos = Event.current.mousePosition; 22 | mousePos.y = scene.camera.pixelHeight - mousePos.y; 23 | HierarchyWindowItemCallback(null, scene.camera.ScreenToWorldPoint(mousePos)); 24 | } 25 | 26 | static void HierarchyWindowItemCallback(int pID, Rect pRect) 27 | { 28 | if (Event.current.type != EventType.DragPerform) 29 | return; 30 | 31 | if (!pRect.Contains(Event.current.mousePosition)) 32 | return; 33 | 34 | GameObject targetGo = EditorUtility.InstanceIDToObject(pID) as GameObject; 35 | if (targetGo == null || targetGo.GetComponentInParent() == null) 36 | return; 37 | 38 | HierarchyWindowItemCallback(targetGo.transform, Vector2.zero); 39 | } 40 | 41 | static void HierarchyWindowItemCallback(Transform target, Vector2 position) 42 | { 43 | List sprites = new List(); 44 | foreach (Object obj in DragAndDrop.objectReferences) 45 | { 46 | string path = AssetDatabase.GetAssetPath(obj); 47 | if (!string.IsNullOrEmpty(path)) 48 | { 49 | if (obj is Sprite) 50 | { 51 | sprites.Add(obj as Sprite); 52 | } 53 | else if (obj is Texture2D) 54 | { 55 | Sprite sprite = AssetDatabase.LoadAssetAtPath(path); 56 | if (sprite != null) 57 | sprites.Add(sprite); 58 | } 59 | } 60 | } 61 | 62 | if (sprites.Count == 0) 63 | return; 64 | 65 | Canvas canvas = GameObject.FindObjectOfType(); 66 | if (canvas != null) 67 | canvas = canvas.rootCanvas; 68 | 69 | List selecteds = new List(); 70 | foreach (Sprite sprite in sprites) 71 | { 72 | var gameObject = new GameObject(sprite.name); 73 | if (target != null) 74 | { 75 | gameObject.transform.SetParent(target, false); 76 | } 77 | else if (canvas != null) 78 | { 79 | gameObject.transform.SetParent(canvas.transform, false); 80 | gameObject.transform.position = position; 81 | } 82 | var image = gameObject.AddComponent(); 83 | image.sprite = sprite; 84 | image.SetNativeSize(); 85 | selecteds.Add(gameObject); 86 | } 87 | Selection.objects = selecteds.ToArray(); 88 | Event.current.Use(); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /AutoCreateImage/Editor/AutoCreateImage.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5923b80080874bb42bdbe897b1d58068 3 | timeCreated: 1515410844 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 flashyiyi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 45139f7077a2a0140865b322722cc98a 3 | timeCreated: 1516557868 4 | licenseType: Pro 5 | DefaultImporter: 6 | externalObjects: {} 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /PrefabLoader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 86288c837e7407343867fbd210957604 3 | folderAsset: yes 4 | timeCreated: 1516558950 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /PrefabLoader/PrefabLoader.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.UI; 3 | using System.Collections.Generic; 4 | #if UNITY_EDITOR 5 | using UnityEditor; 6 | using UnityEditor.Callbacks; 7 | #endif 8 | namespace UGUIExtend 9 | { 10 | /// 11 | /// 加载Prefab 12 | /// 13 | [ExecuteInEditMode] 14 | public class PrefabLoader : MonoBehaviour 15 | { 16 | #if UNITY_EDITOR 17 | 18 | [MenuItem("Tools/Apply All Canvas Prefab")] 19 | public static void ApplyAllCanvasPrefab() 20 | { 21 | Canvas[] canvases = GameObject.FindObjectsOfType(); 22 | foreach (Canvas canvas in canvases) 23 | { 24 | ApplyAllPrefab(canvas.transform); 25 | } 26 | } 27 | 28 | static void ApplyAllPrefab(Transform root) 29 | { 30 | int count = root.childCount; 31 | for (int i = 0; i < count; i++) 32 | { 33 | Transform trans = root.GetChild(i); 34 | ApplyAllPrefab(trans); 35 | PrefabLoader loader = trans.GetComponent(); 36 | if (loader != null && loader.mChild != null) 37 | { 38 | GameObject loaderGo = loader.mChild.gameObject; 39 | Object childPrefab = PrefabUtility.GetPrefabParent(loaderGo); 40 | if (childPrefab != null) 41 | { 42 | PrefabUtility.ReplacePrefab(loaderGo, childPrefab, ReplacePrefabOptions.ConnectToPrefab); 43 | } 44 | } 45 | } 46 | } 47 | 48 | [InitializeOnLoadMethod] 49 | static void StartInitializeOnLoadMethod() 50 | { 51 | PrefabUtility.prefabInstanceUpdated += RemoveAllTempPrefab; 52 | SceneView.onSceneGUIDelegate += OnSceneGUI; 53 | } 54 | 55 | static bool isDraging; 56 | static void OnSceneGUI(SceneView sceneview) 57 | { 58 | Event e = Event.current; 59 | if (!isDraging && e.type == EventType.MouseDrag) 60 | { 61 | isDraging = true; 62 | } 63 | if (isDraging && e.type == EventType.MouseUp) 64 | { 65 | isDraging = false; 66 | } 67 | } 68 | 69 | static void FindPrefabLoader(Transform root, ref List loaders) 70 | { 71 | int count = root.childCount; 72 | for (int i = 0; i < count; i++) 73 | { 74 | Transform trans = root.GetChild(i); 75 | PrefabLoader loader = trans.GetComponent(); 76 | if (loader != null) 77 | { 78 | if (loader.transform.childCount > 0) 79 | loaders.Add(loader); 80 | } 81 | else 82 | { 83 | FindPrefabLoader(trans, ref loaders); 84 | } 85 | } 86 | } 87 | 88 | static void RemoveAllTempPrefab(GameObject go) 89 | { 90 | List loaders = new List(); 91 | FindPrefabLoader(go.transform, ref loaders); 92 | 93 | if (loaders.Count > 0) 94 | { 95 | //foreach (PrefabLoader loader in loaders) 96 | //{ 97 | // GameObject loaderGo = loader.mChild != null ? loader.mChild.gameObject : null; 98 | // if (loaderGo != null && PrefabUtility.GetPrefabType(loaderGo) == PrefabType.PrefabInstance) 99 | // { 100 | // Object childPrefab = PrefabUtility.GetPrefabParent(go); 101 | // PrefabUtility.ReplacePrefab(loaderGo, childPrefab, ReplacePrefabOptions.ConnectToPrefab); 102 | // } 103 | //} 104 | foreach (PrefabLoader loader in loaders) 105 | { 106 | if (loader != null) 107 | { 108 | RemoveAllChildren(loader.transform); 109 | } 110 | } 111 | loaders = null; 112 | 113 | Object prefab = PrefabUtility.GetPrefabParent(go); 114 | PrefabUtility.ReplacePrefab(go, prefab, ReplacePrefabOptions.ConnectToPrefab); 115 | 116 | EditorApplication.CallbackFunction oldCallBack = EditorApplication.delayCall; 117 | EditorApplication.delayCall = () => 118 | { 119 | Selection.activeGameObject = go; 120 | if (oldCallBack != null) 121 | oldCallBack.Invoke(); 122 | }; 123 | } 124 | } 125 | 126 | void Update() 127 | { 128 | if (!Application.isPlaying) 129 | { 130 | if (source != null) 131 | { 132 | Object selfPrefab = PrefabUtility.GetPrefabParent(PrefabUtility.FindPrefabRoot(gameObject)); 133 | if (selfPrefab == source) 134 | { 135 | source = null; 136 | return; 137 | } 138 | 139 | if (mChild == null || PrefabUtility.GetPrefabParent(mChild.gameObject) != source) 140 | { 141 | RemoveAllChildren(transform); 142 | mChild = null; 143 | GameObject prefab = PrefabUtility.InstantiatePrefab(source) as GameObject; 144 | if (prefab != null) 145 | { 146 | mChild = prefab.transform; 147 | mChild.SetParent(transform, false); 148 | mChild.localPosition = Vector3.zero; 149 | } 150 | } 151 | 152 | if (!isDraging && mChild != null) 153 | { 154 | transform.position = mChild.position; 155 | mChild.localPosition = Vector3.zero; 156 | } 157 | } 158 | else 159 | { 160 | if (mChild != null) 161 | { 162 | RemoveAllChildren(transform); 163 | mChild = null; 164 | } 165 | } 166 | } 167 | } 168 | #endif 169 | 170 | public static void RemoveAllChildren(Transform trans) 171 | { 172 | int count = trans.childCount; 173 | for (int i = count - 1; i >= 0; i--) 174 | { 175 | if (Application.isPlaying) 176 | GameObject.Destroy(trans.GetChild(i).gameObject); 177 | else 178 | GameObject.DestroyImmediate(trans.GetChild(i).gameObject); 179 | } 180 | } 181 | 182 | // Prefab 183 | [SerializeField] 184 | public GameObject source; 185 | 186 | // Awake时自动加载 187 | [SerializeField] 188 | public bool autoLoad = true; 189 | 190 | Transform mChild; 191 | 192 | void Awake() 193 | { 194 | if (Application.isPlaying && autoLoad) 195 | { 196 | Load(); 197 | } 198 | } 199 | 200 | public void Load() 201 | { 202 | if (source != null) 203 | { 204 | RemoveAllChildren(transform); 205 | 206 | mChild = GameObject.Instantiate(source).transform; 207 | mChild.name = source.name; 208 | mChild.SetParent(transform, false); 209 | mChild.localPosition = Vector3.zero; 210 | } 211 | } 212 | } 213 | 214 | 215 | //public class RespectReadOnly : UnityEditor.AssetModificationProcessor 216 | //{ 217 | // public static string[] OnWillSaveAssets(string[] paths) 218 | // { 219 | // PrefabLoader.ApplyAllCanvasPrefab(); 220 | // return paths; 221 | // } 222 | //} 223 | } -------------------------------------------------------------------------------- /PrefabLoader/PrefabLoader.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 50c6972ff694dd34d8f42386b6d0b4e5 3 | timeCreated: 1508806715 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UGUI-Extend 2 | - AdvancedComponent 扩展后的Image和Text 3 | - AutoCreateImage 拖进场景自动生成Image 4 | - PrefabLoader 预制嵌套 5 | - UIBake 合并UI组件增加性能(限制单图集) 6 | - UIPackage 保存内部UI组件的引用,避免出现Find 7 | - UIPSDViewer 直接显示PSD结构,方便拼界面 8 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8c239415133cfa741a4a6437c474583b 3 | timeCreated: 1516557868 4 | licenseType: Pro 5 | DefaultImporter: 6 | externalObjects: {} 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /UI3DModifier.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3c2fd43ba29619b459498c3090bd9031 3 | folderAsset: yes 4 | timeCreated: 1523760248 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /UI3DModifier/UI-3DModifier.shader: -------------------------------------------------------------------------------- 1 | // Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt) 2 | 3 | Shader "UI/3DModifier" 4 | { 5 | Properties 6 | { 7 | [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} 8 | _Color ("Tint", Color) = (1,1,1,1) 9 | 10 | _StencilComp ("Stencil Comparison", Float) = 8 11 | _Stencil ("Stencil ID", Float) = 0 12 | _StencilOp ("Stencil Operation", Float) = 0 13 | _StencilWriteMask ("Stencil Write Mask", Float) = 255 14 | _StencilReadMask ("Stencil Read Mask", Float) = 255 15 | 16 | _ColorMask ("Color Mask", Float) = 15 17 | 18 | [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0 19 | } 20 | 21 | SubShader 22 | { 23 | Tags 24 | { 25 | "Queue"="Transparent" 26 | "IgnoreProjector"="True" 27 | "RenderType"="Transparent" 28 | "PreviewType"="Plane" 29 | "CanUseSpriteAtlas"="True" 30 | } 31 | 32 | Stencil 33 | { 34 | Ref [_Stencil] 35 | Comp [_StencilComp] 36 | Pass [_StencilOp] 37 | ReadMask [_StencilReadMask] 38 | WriteMask [_StencilWriteMask] 39 | } 40 | 41 | Cull Off 42 | Lighting Off 43 | ZWrite Off 44 | ZTest [unity_GUIZTestMode] 45 | Blend SrcAlpha OneMinusSrcAlpha 46 | ColorMask [_ColorMask] 47 | 48 | Pass 49 | { 50 | Name "Default" 51 | CGPROGRAM 52 | #pragma vertex vert 53 | #pragma fragment frag 54 | #pragma target 2.0 55 | 56 | #include "UnityCG.cginc" 57 | #include "UnityUI.cginc" 58 | 59 | #pragma multi_compile __ UNITY_UI_ALPHACLIP 60 | 61 | struct appdata_t 62 | { 63 | float4 vertex : POSITION; 64 | float4 color : COLOR; 65 | float2 texcoord : TEXCOORD0; 66 | UNITY_VERTEX_INPUT_INSTANCE_ID 67 | }; 68 | 69 | struct v2f 70 | { 71 | float4 vertex : SV_POSITION; 72 | fixed4 color : COLOR; 73 | float2 texcoord : TEXCOORD0; 74 | float4 worldPosition : TEXCOORD1; 75 | UNITY_VERTEX_OUTPUT_STEREO 76 | }; 77 | 78 | fixed4 _Color; 79 | fixed4 _TextureSampleAdd; 80 | float4 _ClipRect; 81 | float4x4 _TransformModifier; 82 | 83 | v2f vert(appdata_t v) 84 | { 85 | v2f OUT; 86 | UNITY_SETUP_INSTANCE_ID(v); 87 | UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); 88 | OUT.worldPosition = mul(_TransformModifier,v.vertex); 89 | OUT.vertex = UnityObjectToClipPos(OUT.worldPosition); 90 | 91 | OUT.texcoord = v.texcoord; 92 | 93 | OUT.color = v.color * _Color; 94 | return OUT; 95 | } 96 | 97 | sampler2D _MainTex; 98 | 99 | fixed4 frag(v2f IN) : SV_Target 100 | { 101 | half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color; 102 | 103 | color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect); 104 | 105 | #ifdef UNITY_UI_ALPHACLIP 106 | clip (color.a - 0.001); 107 | #endif 108 | 109 | return color; 110 | } 111 | ENDCG 112 | } 113 | } 114 | } 115 | 116 | 117 | -------------------------------------------------------------------------------- /UI3DModifier/UI-3DModifier.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f738481a21a59ba4ca5a5ae46255a95d 3 | timeCreated: 1509000023 4 | licenseType: Free 5 | ShaderImporter: 6 | externalObjects: {} 7 | defaultTextures: [] 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /UI3DModifier/UI3DModifier.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.EventSystems; 5 | using UnityEngine.UI; 6 | namespace UGUIExtend 7 | { 8 | public class UI3DModifier : MonoBehaviour 9 | { 10 | static readonly int propertyNameHash = Shader.PropertyToID("_TransformModifier"); 11 | static Shader m_defaultModifierShader; 12 | static Shader defaultModifierShader 13 | { 14 | get 15 | { 16 | if (m_defaultModifierShader == null) 17 | m_defaultModifierShader = Shader.Find("UI/3DModifier"); 18 | return m_defaultModifierShader; 19 | } 20 | } 21 | 22 | public Vector3 position = new Vector3(0, 0, 0); 23 | public Vector3 rotation = new Vector3(0, 0, 0); 24 | public bool containMaskComponent = false; 25 | 26 | List graphics = new List(); 27 | 28 | Material modifierMat; 29 | HashSet modifierMats = new HashSet(); 30 | Dictionary customMatDict = new Dictionary(); 31 | 32 | 33 | void OnEnable() 34 | { 35 | modifierMat = new Material(defaultModifierShader); 36 | RefreshGraphics(); 37 | } 38 | 39 | static Dictionary customMatInvDict = new Dictionary(); 40 | void OnDisable() 41 | { 42 | foreach (var pair in customMatDict) 43 | { 44 | customMatInvDict.Add(pair.Value, pair.Key); 45 | } 46 | 47 | foreach (Graphic g in graphics) 48 | { 49 | Material curMat = g.material; 50 | if (curMat == modifierMat) 51 | { 52 | g.material = null; 53 | } 54 | else 55 | { 56 | Material m; 57 | customMatInvDict.TryGetValue(curMat, out m); 58 | if (m != null) 59 | { 60 | g.material = m; 61 | } 62 | } 63 | } 64 | modifierMat = null; 65 | modifierMats.Clear(); 66 | customMatDict.Clear(); 67 | customMatInvDict.Clear(); 68 | } 69 | 70 | void FindGraphics(Transform mTrans) 71 | { 72 | Graphic g = mTrans.GetComponent(); 73 | if (g != null) 74 | { 75 | graphics.Add(g); 76 | } 77 | int count = mTrans.childCount; 78 | for (int i = 0;i < count;i++) 79 | { 80 | Transform t = mTrans.GetChild(i); 81 | if (t.GetComponent() != null) 82 | continue; 83 | 84 | FindGraphics(t); 85 | } 86 | } 87 | 88 | public void RefreshGraphics() 89 | { 90 | graphics.Clear(); 91 | FindGraphics(transform); 92 | 93 | modifierMats.Clear(); 94 | modifierMats.Add(modifierMat); 95 | 96 | foreach (Graphic g in graphics) 97 | { 98 | Material curMat = g.material; 99 | if (curMat == g.defaultMaterial) 100 | { 101 | g.material = modifierMat; 102 | } 103 | else 104 | { 105 | Material m; 106 | customMatDict.TryGetValue(curMat, out m); 107 | if (m == null) 108 | { 109 | m = GameObject.Instantiate(curMat); 110 | customMatDict.Add(curMat, m); 111 | } 112 | g.material = m; 113 | } 114 | 115 | modifierMats.Add(containMaskComponent ? g.materialForRendering : g.material); 116 | } 117 | } 118 | 119 | public void Refresh() 120 | { 121 | Matrix4x4 matrix = Matrix4x4.TRS(position, Quaternion.Euler(rotation), Vector3.one); 122 | foreach (var m in modifierMats) 123 | { 124 | if (m != null) 125 | m.SetMatrix(propertyNameHash, matrix); 126 | } 127 | } 128 | 129 | void Update() 130 | { 131 | Refresh(); 132 | } 133 | } 134 | } 135 | 136 | 137 | -------------------------------------------------------------------------------- /UI3DModifier/UI3DModifier.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6a5e38bd7df98004da05516d0dba7c3e 3 | timeCreated: 1523760327 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /UIBake.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1b2c4a65971b9284a8f599ba4d4ce476 3 | folderAsset: yes 4 | timeCreated: 1516558379 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /UIBake/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 18db1040aeebb694e8095e86ee302d96 3 | folderAsset: yes 4 | timeCreated: 1516558516 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /UIBake/Editor/UIMeshBakeEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.UI; 3 | using UnityEditor; 4 | using UnityEditor.UI; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | using UnityEditor.Callbacks; 8 | 9 | namespace UGUIExtend 10 | { 11 | [CustomEditor(typeof(UIBakeMeshAsset), false)] 12 | public class UIBakeMeshAssetEditor : Editor 13 | { 14 | [PostProcessBuildAttribute(1)] 15 | static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject) 16 | { 17 | string[] guids = AssetDatabase.FindAssets("t:GameObject", new string[] { "Assets/MeskBakePrefab" }); 18 | foreach (string guid in guids) 19 | { 20 | GameObject go = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid)); 21 | if (go != null) 22 | { 23 | UIBakeMeshCreater[] bakes = go.GetComponentsInChildren(true); 24 | foreach (UIBakeMeshCreater bake in bakes) 25 | { 26 | bake.BatchAll(); 27 | Debug.Log(string.Format("Combine Mesh Asset \"{0}\" in \"{1}\"", bake.name, go.name)); 28 | } 29 | } 30 | } 31 | } 32 | 33 | private SerializedProperty meshProperty; 34 | private PreviewRenderUtility m_PreviewUtility; 35 | 36 | protected virtual void OnEnable() 37 | { 38 | meshProperty = this.serializedObject.FindProperty("mesh"); 39 | if (m_PreviewUtility == null) 40 | { 41 | m_PreviewUtility = new PreviewRenderUtility(true); 42 | } 43 | } 44 | 45 | protected virtual void OnDisable() 46 | { 47 | if (m_PreviewUtility != null) 48 | { 49 | m_PreviewUtility.Cleanup(); 50 | m_PreviewUtility = null; 51 | } 52 | } 53 | 54 | public override bool HasPreviewGUI() 55 | { 56 | return true; 57 | } 58 | 59 | public override GUIContent GetPreviewTitle() 60 | { 61 | return new GUIContent("Mesh"); 62 | } 63 | 64 | protected virtual Mesh GetMesh() 65 | { 66 | if (meshProperty == null) 67 | return null; 68 | 69 | return meshProperty.objectReferenceValue as Mesh; 70 | } 71 | 72 | public override void OnPreviewGUI(Rect r, GUIStyle background) 73 | { 74 | if (Event.current.type != EventType.Repaint) 75 | return; 76 | 77 | Mesh mesh = GetMesh(); 78 | if (mesh == null) 79 | return; 80 | 81 | m_PreviewUtility.BeginPreview(r, background); 82 | Graphics.DrawMeshNow(mesh, r.size, Quaternion.identity); 83 | m_PreviewUtility.EndAndDrawPreview(r); 84 | } 85 | } 86 | 87 | [CustomEditor(typeof(UIBakeMeshCreater), false)] 88 | public class UIBakeMeshCreaterEditor : UIBakeMeshAssetEditor 89 | { 90 | SerializedProperty asset; 91 | 92 | protected override void OnEnable() 93 | { 94 | base.OnEnable(); 95 | asset = serializedObject.FindProperty("asset"); 96 | } 97 | 98 | protected override Mesh GetMesh() 99 | { 100 | if (asset != null && asset.objectReferenceValue != null) 101 | return (asset.objectReferenceValue as UIBakeMeshAsset).mesh; 102 | 103 | return null; 104 | } 105 | 106 | public override void OnInspectorGUI() 107 | { 108 | EditorGUI.BeginChangeCheck(); 109 | 110 | EditorGUILayout.PropertyField(asset); 111 | 112 | if (asset.objectReferenceValue == null) 113 | { 114 | if (GUILayout.Button("CreateMesh")) 115 | { 116 | string assetPath = EditorUtility.SaveFilePanelInProject("CreateMesh", serializedObject.targetObject.name + "_Mesh", "asset", ""); 117 | if (assetPath != null) 118 | { 119 | UIBakeMeshAsset assetData = new UIBakeMeshAsset(); 120 | assetData.mesh = new Mesh(); 121 | assetData.mesh.name = "mesh"; 122 | AssetDatabase.CreateAsset(assetData, assetPath); 123 | AssetDatabase.AddObjectToAsset(assetData.mesh, assetData); 124 | asset.objectReferenceValue = assetData; 125 | serializedObject.ApplyModifiedProperties(); 126 | AssetDatabase.SaveAssets(); 127 | AssetDatabase.Refresh(); 128 | } 129 | } 130 | } 131 | else 132 | { 133 | 134 | if (EditorSettings.spritePackerMode != SpritePackerMode.AlwaysOn) 135 | { 136 | EditorGUILayout.LabelField("You must set SpritePackerMode to AlwaysOn, \nand in the Play state, make the Mesh data correctly.",GUILayout.Height(30)); 137 | if (GUILayout.Button("Set SpritePackerMode To AlwaysOn")) 138 | { 139 | EditorSettings.spritePackerMode = SpritePackerMode.AlwaysOn; 140 | } 141 | } 142 | else 143 | { 144 | if (!Application.isPlaying) 145 | { 146 | EditorGUILayout.LabelField("You must in the Play state, \nmake the Mesh data correctly.", GUILayout.Height(30)); 147 | if (GUILayout.Button("Press 'Play' To Combine")) 148 | { 149 | EditorApplication.ExecuteMenuItem("Edit/Play"); 150 | } 151 | } 152 | else 153 | { 154 | if (GUILayout.Button("Combine")) 155 | { 156 | (serializedObject.targetObject as UIBakeMeshCreater).BatchAll(); 157 | AssetDatabase.SaveAssets(); 158 | } 159 | } 160 | } 161 | } 162 | 163 | if (EditorGUI.EndChangeCheck()) 164 | serializedObject.ApplyModifiedProperties(); 165 | } 166 | } 167 | 168 | [CustomEditor(typeof(UIBakeMesh), false)] 169 | public class UIBakeMeshEditor : UIBakeMeshAssetEditor 170 | { 171 | SerializedProperty asset; 172 | SerializedProperty m_Mat; 173 | SerializedProperty m_RaycastTarget; 174 | 175 | protected override void OnEnable() 176 | { 177 | base.OnEnable(); 178 | asset = serializedObject.FindProperty("asset"); 179 | m_Mat = serializedObject.FindProperty("m_Material"); 180 | m_RaycastTarget = serializedObject.FindProperty("m_RaycastTarget"); 181 | } 182 | 183 | protected override Mesh GetMesh() 184 | { 185 | if (asset != null && asset.objectReferenceValue != null) 186 | return (asset.objectReferenceValue as UIBakeMeshAsset).mesh; 187 | 188 | return null; 189 | } 190 | 191 | public override void OnInspectorGUI() 192 | { 193 | EditorGUI.BeginChangeCheck(); 194 | 195 | EditorGUILayout.PropertyField(asset); 196 | EditorGUILayout.PropertyField(m_Mat); 197 | EditorGUILayout.PropertyField(m_RaycastTarget); 198 | 199 | if (EditorGUI.EndChangeCheck()) 200 | serializedObject.ApplyModifiedProperties(); 201 | } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /UIBake/Editor/UIMeshBakeEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ca8cad2feef51cb4789ec4377cd7b1a3 3 | timeCreated: 1510472687 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /UIBake/UIBakeMesh.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using UnityEngine; 5 | using UnityEngine.EventSystems; 6 | using UnityEngine.UI; 7 | using System; 8 | 9 | namespace UGUIExtend 10 | { 11 | [AddComponentMenu("UI/BakeMesh", 12)] 12 | public class UIBakeMesh : MaskableGraphic 13 | { 14 | [SerializeField] 15 | public UIBakeMeshAsset asset; 16 | 17 | public override Texture mainTexture 18 | { 19 | get 20 | { 21 | if (!Application.isPlaying) 22 | return s_WhiteTexture; 23 | 24 | if (asset == null || asset.sprite == null) 25 | { 26 | if (material != null && material.mainTexture != null) 27 | { 28 | return material.mainTexture; 29 | } 30 | return s_WhiteTexture; 31 | } 32 | return asset.sprite.texture; 33 | } 34 | } 35 | 36 | protected override void UpdateGeometry() 37 | { 38 | if (asset != null && asset.mesh != null) 39 | canvasRenderer.SetMesh(asset.mesh); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /UIBake/UIBakeMesh.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cbda106b1a777044ab448341e22f2dfe 3 | timeCreated: 1509353123 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /UIBake/UIBakeMeshAsset.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | namespace UGUIExtend 4 | { 5 | [Serializable] 6 | public class UIBakeMeshAsset : ScriptableObject 7 | { 8 | [SerializeField] public Mesh mesh; 9 | [SerializeField] public Sprite sprite; 10 | } 11 | } -------------------------------------------------------------------------------- /UIBake/UIBakeMeshAsset.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 397d0d13da32cf84f8b0f9f86a0c4345 3 | timeCreated: 1516561172 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /UIBake/UIBakeMeshCreater.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Reflection; 3 | using UnityEngine; 4 | using UnityEngine.UI; 5 | 6 | namespace UGUIExtend 7 | { 8 | [AddComponentMenu("UI/UIBakeMeshCreater", 12)] 9 | public class UIBakeMeshCreater : Graphic 10 | { 11 | [SerializeField] 12 | public UIBakeMeshAsset asset; 13 | 14 | protected override void OnEnable() 15 | { 16 | base.OnEnable(); 17 | if (Application.isPlaying) 18 | BatchAll(); 19 | 20 | } 21 | 22 | protected override void UpdateGeometry() 23 | { 24 | } 25 | 26 | private List tempCombines = new List(); 27 | public void BatchAll() 28 | { 29 | if (asset == null) 30 | return; 31 | 32 | 33 | Image[] graphics = GetComponentsInChildren(true); 34 | int count = graphics.Length; 35 | 36 | asset.sprite = null; 37 | int index = 0; 38 | for (int i = 0;i < count;i++) 39 | { 40 | Image g = graphics[i]; 41 | if (g == this) 42 | continue; 43 | 44 | if (asset.sprite == null) 45 | { 46 | asset.sprite = g.sprite; 47 | } 48 | else if (asset.sprite.texture != g.sprite.texture) 49 | { 50 | continue; 51 | } 52 | 53 | CombineInstance combine; 54 | if (index < tempCombines.Count) 55 | { 56 | combine = tempCombines[index]; 57 | } 58 | else 59 | { 60 | combine = new CombineInstance(); 61 | combine.mesh = new Mesh(); 62 | tempCombines.Add(combine); 63 | } 64 | 65 | BakeMesh(g, combine.mesh); 66 | combine.transform = transform.worldToLocalMatrix * g.transform.localToWorldMatrix; 67 | tempCombines[index] = combine; 68 | 69 | index++; 70 | } 71 | 72 | tempCombines.RemoveRange(index, tempCombines.Count - index); 73 | 74 | asset.mesh.CombineMeshes(tempCombines.ToArray(),true, true); 75 | asset.mesh.RecalculateBounds(); 76 | } 77 | 78 | private void BakeMesh(Graphic graphic, Mesh mesh) 79 | { 80 | var methodInfo = graphic.GetType().GetMethod("UpdateGeometry", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 81 | if (methodInfo != null) 82 | methodInfo.Invoke(graphic, null); 83 | 84 | Mesh workMesh = Graphic.workerMesh; 85 | if (workMesh == null) 86 | { 87 | mesh.Clear(); 88 | return; 89 | } 90 | 91 | mesh.vertices = workerMesh.vertices; 92 | mesh.colors = workerMesh.colors; 93 | mesh.uv = workerMesh.uv; 94 | //mesh.uv2 = workerMesh.uv2; 95 | //mesh.normals = workerMesh.normals; 96 | //mesh.tangents = workerMesh.tangents; 97 | mesh.triangles = workerMesh.triangles; 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /UIBake/UIBakeMeshCreater.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 608c22d9d92860f44b2d5272c41eb1bc 3 | timeCreated: 1509353123 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /UIEffect.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 97e69b9d999a95f4ab79ef8e52e41472 3 | folderAsset: yes 4 | timeCreated: 1517655268 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /UIEffect/Particle Add Clip.shader: -------------------------------------------------------------------------------- 1 | // Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt) 2 | 3 | Shader "Particles/Additive (Clip)" { 4 | Properties { 5 | _TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5) 6 | _MainTex ("Particle Texture", 2D) = "white" {} 7 | _InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0 8 | [PerRendererData]_ClipRect ("Clip Rect", Vector) = (0,0,0,0) 9 | } 10 | 11 | Category { 12 | Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" } 13 | Blend SrcAlpha One 14 | ColorMask RGB 15 | Cull Off Lighting Off ZWrite Off 16 | 17 | SubShader { 18 | Pass { 19 | 20 | CGPROGRAM 21 | #pragma vertex vert 22 | #pragma fragment frag 23 | #pragma target 2.0 24 | #pragma multi_compile_particles 25 | #pragma multi_compile_fog 26 | 27 | #include "UnityCG.cginc" 28 | #include "UnityUI.cginc" 29 | 30 | sampler2D _MainTex; 31 | fixed4 _TintColor; 32 | 33 | struct appdata_t { 34 | float4 vertex : POSITION; 35 | fixed4 color : COLOR; 36 | float2 texcoord : TEXCOORD0; 37 | UNITY_VERTEX_INPUT_INSTANCE_ID 38 | }; 39 | 40 | struct v2f { 41 | float4 vertex : SV_POSITION; 42 | fixed4 color : COLOR; 43 | float2 texcoord : TEXCOORD0; 44 | UNITY_FOG_COORDS(1) 45 | #ifdef SOFTPARTICLES_ON 46 | float4 projPos : TEXCOORD2; 47 | #endif 48 | float2 worldPos : TEXCOORD3; 49 | UNITY_VERTEX_OUTPUT_STEREO 50 | }; 51 | 52 | float4 _MainTex_ST; 53 | 54 | v2f vert (appdata_t v) 55 | { 56 | v2f o; 57 | UNITY_SETUP_INSTANCE_ID(v); 58 | UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); 59 | o.vertex = UnityObjectToClipPos(v.vertex); 60 | o.worldPos = mul(unity_ObjectToWorld, v.vertex).xy; 61 | #ifdef SOFTPARTICLES_ON 62 | o.projPos = ComputeScreenPos (o.vertex); 63 | COMPUTE_EYEDEPTH(o.projPos.z); 64 | #endif 65 | o.color = v.color; 66 | o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex); 67 | UNITY_TRANSFER_FOG(o,o.vertex); 68 | return o; 69 | } 70 | 71 | UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); 72 | float _InvFade; 73 | float4 _ClipRect; 74 | 75 | fixed4 frag (v2f i) : SV_Target 76 | { 77 | #ifdef SOFTPARTICLES_ON 78 | float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos))); 79 | float partZ = i.projPos.z; 80 | float fade = saturate (_InvFade * (sceneZ-partZ)); 81 | i.color.a *= fade; 82 | #endif 83 | 84 | fixed4 col = 2.0f * i.color * _TintColor * tex2D(_MainTex, i.texcoord); 85 | UNITY_APPLY_FOG_COLOR(i.fogCoord, col, fixed4(0,0,0,0)); // fog towards black due to our blend mode 86 | col.a *= UnityGet2DClipping(i.worldPos,_ClipRect); 87 | return col; 88 | } 89 | ENDCG 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /UIEffect/Particle Add Clip.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4e90e3fc90e9c944585203fdcc5120b6 3 | timeCreated: 1509000111 4 | licenseType: Free 5 | ShaderImporter: 6 | externalObjects: {} 7 | defaultTextures: [] 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /UIEffect/Particle Alpha Blend Clip.shader: -------------------------------------------------------------------------------- 1 | // Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt) 2 | 3 | Shader "Particles/Alpha Blended (Clip)" { 4 | Properties { 5 | _TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5) 6 | _MainTex ("Particle Texture", 2D) = "white" {} 7 | _InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0 8 | [PerRendererData]_ClipRect ("Clip Rect", Vector) = (0,0,0,0) 9 | } 10 | 11 | Category { 12 | Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" } 13 | Blend SrcAlpha OneMinusSrcAlpha 14 | ColorMask RGB 15 | Cull Off Lighting Off ZWrite Off 16 | 17 | SubShader { 18 | Pass { 19 | 20 | CGPROGRAM 21 | #pragma vertex vert 22 | #pragma fragment frag 23 | #pragma target 2.0 24 | #pragma multi_compile_particles 25 | #pragma multi_compile_fog 26 | 27 | #include "UnityCG.cginc" 28 | #include "UnityUI.cginc" 29 | 30 | sampler2D _MainTex; 31 | fixed4 _TintColor; 32 | 33 | struct appdata_t { 34 | float4 vertex : POSITION; 35 | fixed4 color : COLOR; 36 | float2 texcoord : TEXCOORD0; 37 | UNITY_VERTEX_INPUT_INSTANCE_ID 38 | }; 39 | 40 | struct v2f { 41 | float4 vertex : SV_POSITION; 42 | fixed4 color : COLOR; 43 | float2 texcoord : TEXCOORD0; 44 | UNITY_FOG_COORDS(1) 45 | #ifdef SOFTPARTICLES_ON 46 | float4 projPos : TEXCOORD2; 47 | #endif 48 | float2 worldPos : TEXCOORD3; 49 | UNITY_VERTEX_OUTPUT_STEREO 50 | }; 51 | 52 | float4 _MainTex_ST; 53 | 54 | v2f vert (appdata_t v) 55 | { 56 | v2f o; 57 | UNITY_SETUP_INSTANCE_ID(v); 58 | UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); 59 | o.vertex = UnityObjectToClipPos(v.vertex); 60 | o.worldPos = mul(unity_ObjectToWorld, v.vertex).xy; 61 | #ifdef SOFTPARTICLES_ON 62 | o.projPos = ComputeScreenPos (o.vertex); 63 | COMPUTE_EYEDEPTH(o.projPos.z); 64 | #endif 65 | o.color = v.color * _TintColor; 66 | o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex); 67 | UNITY_TRANSFER_FOG(o,o.vertex); 68 | return o; 69 | } 70 | 71 | UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); 72 | float _InvFade; 73 | float4 _ClipRect; 74 | 75 | fixed4 frag (v2f i) : SV_Target 76 | { 77 | #ifdef SOFTPARTICLES_ON 78 | float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos))); 79 | float partZ = i.projPos.z; 80 | float fade = saturate (_InvFade * (sceneZ-partZ)); 81 | i.color.a *= fade; 82 | #endif 83 | 84 | fixed4 col = 2.0f * i.color * tex2D(_MainTex, i.texcoord); 85 | UNITY_APPLY_FOG(i.fogCoord, col); 86 | col.a *= UnityGet2DClipping(i.worldPos,_ClipRect); 87 | return col; 88 | } 89 | ENDCG 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /UIEffect/Particle Alpha Blend Clip.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a6e379d92a4f2334bb444ab94fc24516 3 | timeCreated: 1509000014 4 | licenseType: Free 5 | ShaderImporter: 6 | externalObjects: {} 7 | defaultTextures: [] 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /UIEffect/Particles_Alpha Blended (Clip).mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_PrefabParentObject: {fileID: 0} 8 | m_PrefabInternal: {fileID: 0} 9 | m_Name: Particles_Alpha Blended (Clip) 10 | m_Shader: {fileID: 4800000, guid: a6e379d92a4f2334bb444ab94fc24516, type: 3} 11 | m_ShaderKeywords: 12 | m_LightmapFlags: 4 13 | m_EnableInstancingVariants: 0 14 | m_DoubleSidedGI: 0 15 | m_CustomRenderQueue: -1 16 | stringTagMap: {} 17 | disabledShaderPasses: [] 18 | m_SavedProperties: 19 | serializedVersion: 3 20 | m_TexEnvs: 21 | - _MainTex: 22 | m_Texture: {fileID: 10300, guid: 0000000000000000f000000000000000, type: 0} 23 | m_Scale: {x: 1, y: 1} 24 | m_Offset: {x: 0, y: 0} 25 | m_Floats: 26 | - _InvFade: 1 27 | m_Colors: 28 | - _ClipRect: {r: 0, g: 0, b: 0, a: 0} 29 | - _TintColor: {r: 0.5, g: 0.5, b: 0.5, a: 0.5} 30 | -------------------------------------------------------------------------------- /UIEffect/Particles_Alpha Blended (Clip).mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 63480b0f39815a243a91fb560c7ab713 3 | timeCreated: 1517672523 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | externalObjects: {} 7 | mainObjectFileID: 2100000 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /UIEffect/UIClipAble.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | namespace UGUIExtend 3 | { 4 | /// 5 | /// 按RectTransform裁切Renderer 6 | /// 7 | [ExecuteInEditMode] 8 | public class UIClipAble : MonoBehaviour 9 | { 10 | static readonly int clipRectId = Shader.PropertyToID("_ClipRect"); 11 | 12 | [SerializeField] public RectTransform mask; 13 | 14 | MaterialPropertyBlock materialBlock; 15 | Renderer[] renderers; 16 | Vector4 clipRect; 17 | 18 | private void OnEnable() 19 | { 20 | materialBlock = new MaterialPropertyBlock(); 21 | renderers = GetComponentsInChildren(); 22 | } 23 | 24 | static readonly Vector3[] corners = new Vector3[4]; 25 | private void Update() 26 | { 27 | if (mask != null) 28 | { 29 | mask.GetWorldCorners(corners); 30 | Vector4 r = new Vector4(corners[0].x, corners[0].y, corners[2].x, corners[2].y); 31 | if (r != clipRect) 32 | { 33 | clipRect = r; 34 | materialBlock.SetVector(clipRectId, clipRect); 35 | foreach (Renderer renderer in renderers) 36 | { 37 | renderer.SetPropertyBlock(materialBlock); 38 | } 39 | } 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /UIEffect/UIClipAble.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f5dca2bbb85f65541bc054a2b0e9a82d 3 | timeCreated: 1517655298 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /UILineFeedFixed/LineFeedFixed.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using UnityEngine; 5 | using UnityEngine.UI; 6 | 7 | [RequireComponent(typeof(Text))] 8 | public class LineFeedFixed : BaseMeshEffect 9 | { 10 | static readonly HashSet charset = new HashSet(new char[] { ',',';','.','?','!',',','。',';','?','!',')','”','’',')','》' }); 11 | private Text textCompent; 12 | 13 | protected override void OnEnable() 14 | { 15 | base.OnEnable(); 16 | if (textCompent == null) 17 | textCompent = GetComponent(); 18 | } 19 | 20 | private static List output = new List(); 21 | private static List lines = new List(); 22 | private static List characters = new List(); 23 | 24 | public override void ModifyMesh(VertexHelper vh) 25 | { 26 | if (!IsActive()) 27 | return; 28 | 29 | vh.GetUIVertexStream(output); 30 | 31 | Vector2 alignment = Text.GetTextAnchorPivot(textCompent.alignment); 32 | 33 | string text = textCompent.text; 34 | textCompent.cachedTextGenerator.GetLines(lines); 35 | textCompent.cachedTextGenerator.GetCharacters(characters); 36 | 37 | for (int i = 0;i < lines.Count;i++) 38 | { 39 | var line = lines[i]; 40 | if (i > 0 && charset.Contains(text[line.startCharIdx])) //行首出现标点 41 | { 42 | var character = characters[line.startCharIdx]; 43 | var preCharacter = characters[line.startCharIdx - 1]; 44 | var preLine = lines[i - 1]; 45 | int lineEndIdx = i < lines.Count - 1 ? lines[i + 1].startCharIdx : text.Length; 46 | MoveChars(line.startCharIdx - 1, line.startCharIdx, character.cursorPos - new Vector2(preCharacter.charWidth, 0f) - preCharacter.cursorPos); 47 | MoveChars(preLine.startCharIdx, line.startCharIdx - 1, new Vector2(preCharacter.charWidth, 0) * alignment); 48 | MoveChars(line.startCharIdx - 1, lineEndIdx, new Vector2(preCharacter.charWidth * (1 - alignment.x), 0)); 49 | line.startCharIdx--; 50 | lines[i] = line; 51 | } 52 | if (i < lines.Count - 1) 53 | { 54 | var nextLine = lines[i + 1]; 55 | var lastCharacter = characters[nextLine.startCharIdx - 1]; 56 | if (lastCharacter.cursorPos.x + lastCharacter.charWidth > textCompent.rectTransform.rect.xMax) //行末字符超出范围 57 | { 58 | var nextCharacter = characters[nextLine.startCharIdx]; 59 | int lineEndIdx = i + 1 < lines.Count - 1 ? lines[i + 2].startCharIdx : text.Length; 60 | MoveChars(nextLine.startCharIdx - 1, nextLine.startCharIdx, nextCharacter.cursorPos - new Vector2(lastCharacter.charWidth, 0f) - lastCharacter.cursorPos); 61 | MoveChars(line.startCharIdx, nextLine.startCharIdx - 1, new Vector2(lastCharacter.charWidth, 0) * alignment); 62 | MoveChars(nextLine.startCharIdx - 1, lineEndIdx, new Vector2(lastCharacter.charWidth * (1 - alignment.x), 0)); 63 | nextLine.startCharIdx--; 64 | lines[i + 1] = nextLine; 65 | } 66 | } 67 | } 68 | 69 | vh.Clear(); 70 | vh.AddUIVertexTriangleStream(output); 71 | } 72 | 73 | void MoveChars(int start,int end, Vector2 offest) 74 | { 75 | for (int index = start; index < end; index++) 76 | { 77 | UICharInfo charInfo = characters[index]; 78 | charInfo.cursorPos += offest; 79 | characters[index] = charInfo; 80 | 81 | int i = index * 6; 82 | UIVertex v1 = output[i]; 83 | UIVertex v2 = output[i + 1]; 84 | UIVertex v3 = output[i + 2]; 85 | UIVertex v4 = output[i + 3]; 86 | UIVertex v5 = output[i + 4]; 87 | UIVertex v6 = output[i + 5]; 88 | 89 | v1.position += (Vector3)offest; 90 | v2.position += (Vector3)offest; 91 | v3.position += (Vector3)offest; 92 | v4.position += (Vector3)offest; 93 | v5.position += (Vector3)offest; 94 | v6.position += (Vector3)offest; 95 | 96 | output[i] = v1; 97 | output[i + 1] = v2; 98 | output[i + 2] = v3; 99 | output[i + 3] = v4; 100 | output[i + 4] = v5; 101 | output[i + 5] = v6; 102 | } 103 | } 104 | } 105 | 106 | 107 | -------------------------------------------------------------------------------- /UIPSDViewer.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: da84aec0e19a1e44c8f04b6bd4647a49 3 | folderAsset: yes 4 | timeCreated: 1516557239 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /UIPSDViewer/Plugins.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d9e3bfbd174340f44af55726068944d1 3 | folderAsset: yes 4 | timeCreated: 1516557308 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /UIPSDViewer/Plugins/PsdParser.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flashyiyi/UGUI-Extend/605757e0ce5e4bb0b169eb5237f77775ec0aff47/UIPSDViewer/Plugins/PsdParser.dll -------------------------------------------------------------------------------- /UIPSDViewer/Plugins/PsdParser.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 24f5f5e17dc58854fae5ceed50de7e0d 3 | timeCreated: 1516367432 4 | licenseType: Pro 5 | PluginImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | iconMap: {} 9 | executionOrder: {} 10 | isPreloaded: 0 11 | isOverridable: 0 12 | platformData: 13 | - first: 14 | '': Any 15 | second: 16 | enabled: 0 17 | settings: 18 | Exclude Android: 0 19 | Exclude Editor: 0 20 | Exclude Linux: 0 21 | Exclude Linux64: 0 22 | Exclude LinuxUniversal: 0 23 | Exclude OSXIntel: 0 24 | Exclude OSXIntel64: 0 25 | Exclude OSXUniversal: 0 26 | Exclude Win: 0 27 | Exclude Win64: 0 28 | Exclude iOS: 0 29 | - first: 30 | Android: Android 31 | second: 32 | enabled: 1 33 | settings: 34 | CPU: ARMv7 35 | - first: 36 | Any: 37 | second: 38 | enabled: 1 39 | settings: {} 40 | - first: 41 | Editor: Editor 42 | second: 43 | enabled: 1 44 | settings: 45 | CPU: AnyCPU 46 | DefaultValueInitialized: true 47 | OS: AnyOS 48 | - first: 49 | Facebook: Win 50 | second: 51 | enabled: 0 52 | settings: 53 | CPU: AnyCPU 54 | - first: 55 | Facebook: Win64 56 | second: 57 | enabled: 0 58 | settings: 59 | CPU: AnyCPU 60 | - first: 61 | Standalone: Linux 62 | second: 63 | enabled: 1 64 | settings: 65 | CPU: x86 66 | - first: 67 | Standalone: Linux64 68 | second: 69 | enabled: 1 70 | settings: 71 | CPU: x86_64 72 | - first: 73 | Standalone: LinuxUniversal 74 | second: 75 | enabled: 1 76 | settings: {} 77 | - first: 78 | Standalone: OSXIntel 79 | second: 80 | enabled: 1 81 | settings: 82 | CPU: AnyCPU 83 | - first: 84 | Standalone: OSXIntel64 85 | second: 86 | enabled: 1 87 | settings: 88 | CPU: AnyCPU 89 | - first: 90 | Standalone: OSXUniversal 91 | second: 92 | enabled: 1 93 | settings: {} 94 | - first: 95 | Standalone: Win 96 | second: 97 | enabled: 1 98 | settings: 99 | CPU: AnyCPU 100 | - first: 101 | Standalone: Win64 102 | second: 103 | enabled: 1 104 | settings: 105 | CPU: AnyCPU 106 | - first: 107 | Windows Store Apps: WindowsStoreApps 108 | second: 109 | enabled: 0 110 | settings: 111 | CPU: AnyCPU 112 | - first: 113 | iPhone: iOS 114 | second: 115 | enabled: 1 116 | settings: 117 | CompileFlags: 118 | FrameworkDependencies: 119 | userData: 120 | assetBundleName: 121 | assetBundleVariant: 122 | -------------------------------------------------------------------------------- /UIPSDViewer/TestFile.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flashyiyi/UGUI-Extend/605757e0ce5e4bb0b169eb5237f77775ec0aff47/UIPSDViewer/TestFile.psd -------------------------------------------------------------------------------- /UIPSDViewer/TestFile.psd.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b131aa24e1d8758498a07005e5699bfe 3 | timeCreated: 1516557240 4 | licenseType: Pro 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | externalObjects: {} 8 | serializedVersion: 4 9 | mipmaps: 10 | mipMapMode: 0 11 | enableMipMap: 1 12 | sRGBTexture: 1 13 | linearTexture: 0 14 | fadeOut: 0 15 | borderMipMap: 0 16 | mipMapsPreserveCoverage: 0 17 | alphaTestReferenceValue: 0.5 18 | mipMapFadeDistanceStart: 1 19 | mipMapFadeDistanceEnd: 3 20 | bumpmap: 21 | convertToNormalMap: 0 22 | externalNormalMap: 0 23 | heightScale: 0.25 24 | normalMapFilter: 0 25 | isReadable: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: -1 36 | mipBias: -1 37 | wrapU: -1 38 | wrapV: -1 39 | wrapW: -1 40 | nPOTScale: 1 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 49 | spritePixelsToUnits: 100 50 | alphaUsage: 1 51 | alphaIsTransparency: 0 52 | spriteTessellationDetail: -1 53 | textureType: 0 54 | textureShape: 1 55 | maxTextureSizeSet: 0 56 | compressionQualitySet: 0 57 | textureFormatSet: 0 58 | platformSettings: 59 | - buildTarget: DefaultTexturePlatform 60 | maxTextureSize: 2048 61 | resizeAlgorithm: 0 62 | textureFormat: -1 63 | textureCompression: 1 64 | compressionQuality: 50 65 | crunchedCompression: 0 66 | allowsAlphaSplitting: 0 67 | overridden: 0 68 | spriteSheet: 69 | serializedVersion: 2 70 | sprites: [] 71 | outline: [] 72 | physicsShape: [] 73 | spritePackingTag: 74 | userData: 75 | assetBundleName: 76 | assetBundleVariant: 77 | -------------------------------------------------------------------------------- /UIPSDViewer/UIPSDViewer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.UI; 5 | using SubjectNerd.PsdImporter.PsdParser; 6 | 7 | [ExecuteInEditMode] 8 | public class UIPSDViewer : MonoBehaviour 9 | { 10 | public Object asset; 11 | 12 | PsdDocument psd; 13 | RectTransform rectTransform; 14 | List sprites; 15 | 16 | public bool createTexture = true; 17 | public bool drawGimzos = true; 18 | public bool replaceByName = false; 19 | 20 | void Awake() 21 | { 22 | rectTransform = GetComponent(); 23 | if (rectTransform == null) 24 | rectTransform = gameObject.AddComponent(); 25 | } 26 | 27 | public void LoadDocument() 28 | { 29 | UnLoadDocument(); 30 | #if UNITY_EDITOR 31 | if (asset != null) 32 | { 33 | string path = UnityEditor.AssetDatabase.GetAssetPath(asset); 34 | if (path.EndsWith(".psd")) 35 | psd = PsdDocument.Create(path); 36 | } 37 | #endif 38 | } 39 | 40 | public void CreateTextures() 41 | { 42 | DestoryTextures(); 43 | if (psd == null) 44 | return; 45 | 46 | rectTransform.sizeDelta = new Vector2(psd.Width, psd.Height); 47 | sprites = new List(); 48 | CreateLayers(rectTransform, psd.Childs); 49 | } 50 | 51 | public void UnLoadDocument() 52 | { 53 | if (psd != null) 54 | { 55 | psd.Dispose(); 56 | psd = null; 57 | } 58 | } 59 | 60 | public void DestoryTextures() 61 | { 62 | if (sprites != null) 63 | { 64 | foreach (var sprite in sprites) 65 | { 66 | if (sprite != null) 67 | { 68 | GameObject.DestroyImmediate(sprite.texture); 69 | GameObject.DestroyImmediate(sprite); 70 | } 71 | } 72 | sprites = null; 73 | } 74 | 75 | if (rectTransform != null) 76 | { 77 | int count = rectTransform.childCount; 78 | for (int i = count - 1; i >= 0; i--) 79 | { 80 | GameObject.DestroyImmediate(rectTransform.GetChild(i).gameObject); 81 | } 82 | } 83 | } 84 | 85 | private void OnDestroy() 86 | { 87 | UnLoadDocument(); 88 | DestoryTextures(); 89 | } 90 | 91 | private void CreateLayers(RectTransform parent,IPsdLayer[] layers) 92 | { 93 | if (layers == null) 94 | return; 95 | 96 | Vector2 rootSize = rectTransform.sizeDelta; 97 | Vector2 rootOffest = (Vector2)(rectTransform.position) - rootSize / 2f; 98 | foreach (var layer in layers) 99 | { 100 | GameObject go = new GameObject(layer.Name); 101 | RectTransform t = go.AddComponent(); 102 | t.anchoredPosition = new Vector2(layer.Left + layer.Width / 2f, rootSize.y - (layer.Top + layer.Height / 2f)) + rootOffest; 103 | t.sizeDelta = new Vector2(layer.Width,layer.Height); 104 | t.SetParent(parent, true); 105 | 106 | if (layer.HasImage && createTexture) 107 | { 108 | Image image = t.gameObject.AddComponent(); 109 | Sprite sprite = null; 110 | #if UNITY_EDITOR 111 | if (replaceByName) 112 | { 113 | string[] findedSprites = UnityEditor.AssetDatabase.FindAssets(layer.Name + " t:sprite"); 114 | if (findedSprites.Length > 0) 115 | { 116 | sprite = UnityEditor.AssetDatabase.LoadAssetAtPath(UnityEditor.AssetDatabase.GUIDToAssetPath(findedSprites[0])); 117 | } 118 | } 119 | #endif 120 | if (sprite == null) 121 | { 122 | Texture2D tex = GetTexture2D(layer); 123 | sprite = Sprite.Create(tex, new Rect(0, 0, layer.Width, layer.Height), Vector2.zero); 124 | sprites.Add(sprite); 125 | } 126 | image.sprite = sprite; 127 | } 128 | 129 | CreateLayers(t,layer.Childs); 130 | go.SetActive(layer is PsdLayer ? (layer as PsdLayer).IsVisible : true); 131 | } 132 | } 133 | 134 | public Texture2D GetTexture2D(IPsdLayer layer) 135 | { 136 | byte[] data = layer.MergeChannels(); 137 | var channelCount = layer.Channels.Length; 138 | var pitch = layer.Width * layer.Channels.Length; 139 | var w = layer.Width; 140 | var h = layer.Height; 141 | 142 | var format = channelCount == 3 ? TextureFormat.RGB24 : TextureFormat.ARGB32; 143 | var tex = new Texture2D(w, h, format, false); 144 | var colors = new Color32[data.Length / channelCount]; 145 | 146 | var k = 0; 147 | for (var y = h - 1; y >= 0; --y) 148 | { 149 | for (var x = 0; x < pitch; x += channelCount) 150 | { 151 | var n = x + y * pitch; 152 | var c = new Color32(); 153 | if (channelCount == 5) 154 | { 155 | c.b = data[n++]; 156 | c.g = data[n++]; 157 | c.r = data[n++]; 158 | n++; 159 | c.a = (byte)Mathf.RoundToInt((float)(data[n++]) * layer.Opacity); 160 | } 161 | else if (channelCount == 4) 162 | { 163 | c.b = data[n++]; 164 | c.g = data[n++]; 165 | c.r = data[n++]; 166 | c.a = (byte)Mathf.RoundToInt((float)data[n++] * layer.Opacity); 167 | } 168 | else 169 | { 170 | c.b = data[n++]; 171 | c.g = data[n++]; 172 | c.r = data[n++]; 173 | c.a = (byte)Mathf.RoundToInt(layer.Opacity * 255f); 174 | } 175 | colors[k++] = c; 176 | } 177 | } 178 | tex.SetPixels32(colors); 179 | tex.Apply(false, true); 180 | return tex; 181 | } 182 | 183 | private void OnDrawGizmos() 184 | { 185 | if (!drawGimzos) 186 | return; 187 | Vector3[] vectors = new Vector3[4]; 188 | foreach (var t in GetComponentsInChildren()) 189 | { 190 | t.GetWorldCorners(vectors); 191 | Gizmos.DrawLine(vectors[0], vectors[1]); 192 | Gizmos.DrawLine(vectors[1], vectors[2]); 193 | Gizmos.DrawLine(vectors[2], vectors[3]); 194 | Gizmos.DrawLine(vectors[3], vectors[0]); 195 | } 196 | } 197 | 198 | #if UNITY_EDITOR 199 | private void OnValidate() 200 | { 201 | if (!gameObject.activeInHierarchy) 202 | return; 203 | 204 | UnityEditor.EditorApplication.delayCall += () => 205 | { 206 | LoadDocument(); 207 | CreateTextures(); 208 | }; 209 | } 210 | [UnityEditor.InitializeOnLoadMethod] 211 | static void AutoCreateMethod() 212 | { 213 | UnityEditor.EditorApplication.hierarchyWindowItemOnGUI += HierarchyWindowItemCallback; 214 | } 215 | 216 | static void HierarchyWindowItemCallback(int pID, Rect pRect) 217 | { 218 | if (!pRect.Contains(Event.current.mousePosition)) 219 | return; 220 | 221 | GameObject targetGo = UnityEditor.EditorUtility.InstanceIDToObject(pID) as GameObject; 222 | if (targetGo == null || targetGo.GetComponentInParent() == null) 223 | return; 224 | 225 | if (Event.current.type == EventType.DragUpdated) 226 | { 227 | foreach (string path in UnityEditor.DragAndDrop.paths) 228 | { 229 | if (!string.IsNullOrEmpty(path) && path.EndsWith(".psd")) 230 | { 231 | UnityEditor.DragAndDrop.visualMode = UnityEditor.DragAndDropVisualMode.Link; 232 | UnityEditor.DragAndDrop.AcceptDrag(); 233 | Event.current.Use(); 234 | } 235 | } 236 | } 237 | else if (Event.current.type == EventType.DragPerform) 238 | { 239 | foreach (string path in UnityEditor.DragAndDrop.paths) 240 | { 241 | if (!string.IsNullOrEmpty(path) && path.EndsWith(".psd")) 242 | { 243 | Object asset = UnityEditor.AssetDatabase.LoadMainAssetAtPath(path); 244 | GameObject go = new GameObject(asset.name); 245 | go.transform.SetParent(targetGo.transform, false); 246 | go.AddComponent().asset = asset; 247 | Event.current.Use(); 248 | } 249 | } 250 | } 251 | } 252 | [UnityEditor.MenuItem("GameObject/UI/Create Text By Name", false)] 253 | public static void CreateTextByName() 254 | { 255 | GameObject[] gameObjects = UnityEditor.Selection.gameObjects; 256 | foreach (GameObject go in gameObjects) 257 | { 258 | Graphic g = go.GetComponent(); 259 | if (g != null) 260 | GameObject.DestroyImmediate(g); 261 | Text t = go.AddComponent(); 262 | t.verticalOverflow = VerticalWrapMode.Overflow; 263 | t.text = go.name; 264 | } 265 | } 266 | 267 | #endif 268 | } 269 | -------------------------------------------------------------------------------- /UIPSDViewer/UIPSDViewer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8217c58c7bf1b124d90cab74fe7333ca 3 | timeCreated: 1516609925 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /UIPackage.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b202b73281287ae49a700ab41b925169 3 | folderAsset: yes 4 | timeCreated: 1513260703 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /UIPackage/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 36d92e656e9527b4e8e2761901ce1eb0 3 | folderAsset: yes 4 | timeCreated: 1516561712 5 | licenseType: Pro 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /UIPackage/Editor/UIPackageEditor.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | using UnityEngine.UI; 4 | using UnityEditor; 5 | using System; 6 | using System.Reflection; 7 | using System.Text; 8 | 9 | namespace UGUIExtend 10 | { 11 | [CustomEditor(typeof(UIPackage), false)] 12 | public class UIPackageEditor : Editor 13 | { 14 | UIPackage package 15 | { 16 | get { return target as UIPackage; } 17 | } 18 | 19 | public override void OnInspectorGUI() 20 | { 21 | if (Event.current.type == EventType.DragPerform) 22 | { 23 | foreach (object item in DragAndDrop.objectReferences) 24 | { 25 | if (item is GameObject) 26 | { 27 | AddCustomComponent((item as GameObject).transform); 28 | } 29 | else if (item is Component) 30 | { 31 | AddCustomComponent(item as Component); 32 | } 33 | } 34 | Event.current.Use(); 35 | } 36 | else if (Event.current.type == EventType.DragUpdated) 37 | { 38 | DragAndDrop.AcceptDrag(); 39 | DragAndDrop.visualMode = DragAndDropVisualMode.Link; 40 | Event.current.Use(); 41 | } 42 | 43 | if (package.objects != null && package.objects.Count > 0) 44 | { 45 | EditorGUILayout.BeginHorizontal(); 46 | if (GUILayout.Button("Generate Code")) 47 | { 48 | EditorUtility.DisplayDialog("", GreateCode(), "ok"); 49 | } 50 | if (GUILayout.Button("Copy To Clipboard")) 51 | { 52 | TextEditor t = new TextEditor(); 53 | t.text = GreateCode(); 54 | t.OnFocus(); 55 | t.Copy(); 56 | } 57 | EditorGUILayout.EndHorizontal(); 58 | 59 | foreach (var pair in package.objects) 60 | { 61 | if (pair.Value == null) 62 | continue; 63 | 64 | if (pair.Value is Component) 65 | { 66 | DrawCompent(pair.Value as Component); 67 | } 68 | else 69 | { 70 | Dictionary typeObj = pair.Value as Dictionary; 71 | foreach (var pair2 in typeObj) 72 | { 73 | object obj2 = pair2.Value; 74 | if (obj2 == null) 75 | continue; 76 | if (obj2 is Component) 77 | { 78 | DrawCompent(obj2 as Component); 79 | } 80 | else 81 | { 82 | EditorGUILayout.BeginVertical(GUI.skin.box); 83 | foreach (var item in obj2 as IEnumerable) 84 | { 85 | if (item == null) 86 | continue; 87 | DrawCompent(item); 88 | } 89 | EditorGUILayout.EndVertical(); 90 | } 91 | } 92 | } 93 | } 94 | } 95 | else 96 | { 97 | EditorGUILayout.LabelField("Children Empty"); 98 | } 99 | 100 | if (Event.current.type == EventType.Repaint) 101 | { 102 | package.RefreshDatas(); 103 | EditorUtility.SetDirty(target); 104 | } 105 | } 106 | 107 | string GreateCode() 108 | { 109 | StringBuilder result = new StringBuilder(); 110 | foreach (var pair in package.objects) 111 | { 112 | if (pair.Value is Component) 113 | { 114 | result.AppendLine("[UI]" + pair.Value.GetType().Name + " " + pair.Key + ";"); 115 | } 116 | else 117 | { 118 | Dictionary typeObj = pair.Value as Dictionary; 119 | foreach (var pair2 in typeObj) 120 | { 121 | object obj2 = pair2.Value; 122 | if (obj2 is Component) 123 | { 124 | result.AppendLine("[UI]" + obj2.GetType().Name + " " + pair.Key + ";"); 125 | } 126 | else 127 | { 128 | foreach (var item in obj2 as IEnumerable) 129 | { 130 | result.AppendLine("[UI]" + item.GetType().Name + "[] " + pair.Key + ";"); 131 | break; 132 | } 133 | } 134 | } 135 | } 136 | } 137 | return result.ToString(); 138 | } 139 | 140 | string GetCompentFullName(Transform trans, bool isEnd = true) 141 | { 142 | if (trans.parent == null || trans.parent.parent == null) 143 | return trans.name; 144 | else 145 | return GetCompentFullName(trans.parent,false) + "/" + (isEnd ? "" + trans.name + "" : trans.name); 146 | } 147 | 148 | string GetCompentValue(Component asset) 149 | { 150 | if (asset is Text) 151 | { 152 | return "(" + (asset as Text).text + ")"; 153 | } 154 | else if (asset is Image && ((asset as Image).sprite != null)) 155 | { 156 | return "(" + (asset as Image).sprite.name + ")"; 157 | } 158 | return ""; 159 | } 160 | 161 | void DrawCompent(Component asset) 162 | { 163 | if (asset == null) 164 | return; 165 | 166 | GUIContent content = EditorGUIUtility.ObjectContent(asset, asset.GetType()); 167 | content.text = GetCompentFullName(asset.transform) + " " + GetCompentValue(asset); 168 | GUIStyle style = new GUIStyle(GUI.skin.label) { richText = true }; 169 | EditorGUILayout.BeginHorizontal(); 170 | EditorGUILayout.LabelField(content,style); 171 | if (package.customComponents != null && package.customComponents.Contains(asset)) 172 | { 173 | Component[] components = asset.gameObject.GetComponents(typeof(Component)); 174 | string[] componentNames = new string[components.Length]; 175 | int c = components.Length; 176 | int selectIndex = 0; 177 | for (int i = 0;i < c;i++) 178 | { 179 | componentNames[i] = components[i].GetType().Name; 180 | if (components[i] == asset) 181 | selectIndex = i; 182 | } 183 | EditorGUI.BeginChangeCheck(); 184 | selectIndex = EditorGUILayout.Popup(selectIndex, componentNames); 185 | if (EditorGUI.EndChangeCheck()) 186 | { 187 | package.customComponents.Remove(asset); 188 | AddCustomComponent(asset.GetComponent(componentNames[selectIndex])); 189 | } 190 | 191 | if (GUILayout.Button("X", GUILayout.Width(25))) 192 | { 193 | package.customComponents.Remove(asset); 194 | } 195 | } 196 | else 197 | { 198 | EditorGUILayout.LabelField(asset.GetType().Name); 199 | } 200 | EditorGUILayout.EndHorizontal(); 201 | if (Event.current.type == EventType.MouseDown && GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition)) 202 | { 203 | if (Event.current.clickCount >= 2) 204 | AssetDatabase.OpenAsset(asset); 205 | else if (Event.current.clickCount == 1) 206 | EditorGUIUtility.PingObject(asset); 207 | } 208 | } 209 | 210 | void AddCustomComponent(Component asset) 211 | { 212 | if (!package.customComponents.Contains(asset)) 213 | package.customComponents.Add(asset); 214 | } 215 | } 216 | 217 | } 218 | 219 | -------------------------------------------------------------------------------- /UIPackage/Editor/UIPackageEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: de68db2faff2a3445a159c90efc03ccf 3 | timeCreated: 1516561726 4 | licenseType: Pro 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /UIPackage/UIPackage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.UI; 5 | using System; 6 | using System.Reflection; 7 | 8 | namespace UGUIExtend 9 | { 10 | [ExecuteInEditMode] 11 | public class UIPackage : MonoBehaviour, ISerializationCallbackReceiver 12 | { 13 | [SerializeField] 14 | string[] names; 15 | 16 | [SerializeField] 17 | Component[] components; 18 | 19 | [SerializeField] 20 | public List customComponents = new List(); 21 | 22 | [NonSerialized] 23 | public Dictionary objects; 24 | 25 | #region Get Method 26 | public T Get(string name) where T : Component 27 | { 28 | return Get(name, typeof(T)) as T; 29 | } 30 | 31 | public T[] GetAll(string name) where T : Component 32 | { 33 | return GetAll(name, typeof(T)) as T[]; 34 | } 35 | 36 | public Component Get(string name, Type type = null) 37 | { 38 | object result = RawGet(name, type); 39 | if (result is Component[]) 40 | return (result as Component[])[0]; 41 | else 42 | return result as Component; 43 | } 44 | 45 | public Component[] GetAll(string name, Type type) 46 | { 47 | object result = RawGet(name, type); 48 | if (result is Component[]) 49 | return result as Component[]; 50 | else if (result is Component) 51 | return new Component[1] { result as Component }; 52 | else 53 | return null; 54 | } 55 | 56 | public object this[string name] 57 | { 58 | get 59 | { 60 | return Get(name); 61 | } 62 | } 63 | 64 | object RawGet(string name, Type type = null) 65 | { 66 | object obj; 67 | if (!objects.TryGetValue(name, out obj)) 68 | return null; 69 | 70 | if (obj is Component) 71 | return obj; 72 | 73 | Dictionary typeObj = obj as Dictionary; 74 | if (typeObj != null) 75 | { 76 | object obj2 = null; 77 | if (type == null) 78 | { 79 | foreach (var pair in typeObj) 80 | { 81 | obj2 = pair.Value; 82 | break; 83 | } 84 | } 85 | else 86 | { 87 | typeObj.TryGetValue(type, out obj2); 88 | } 89 | return obj2; 90 | } 91 | 92 | return null; 93 | } 94 | 95 | /// 96 | /// 不通过缓存直接查找组件 97 | /// 98 | /// 是否查找禁用状态的组件 99 | /// 100 | public Component FindByPath(string name, Type type, bool includeInactive = false) 101 | { 102 | string[] parts = name.Split('/'); 103 | Transform cur = transform; 104 | foreach (string part in parts) 105 | { 106 | cur = FindByName(cur, part, includeInactive); 107 | if (cur == null) 108 | return null; 109 | } 110 | return cur.GetComponent(type); 111 | } 112 | public T FindByPath(string name, bool includeInactive = false) where T : Component 113 | { 114 | return FindByPath(name, typeof(T), includeInactive) as T; 115 | } 116 | 117 | Transform FindByName(Transform trans, string name, bool includeactive = false) 118 | { 119 | if (!includeactive) 120 | { 121 | return trans.Find(name); 122 | } 123 | else 124 | { 125 | int c = trans.childCount; 126 | for (int i = 0; i < c; i++) 127 | { 128 | Transform child = trans.GetChild(i); 129 | if (child.name == name) 130 | return child; 131 | } 132 | return null; 133 | } 134 | } 135 | 136 | #endregion 137 | #region Serialize 138 | void ISerializationCallbackReceiver.OnBeforeSerialize() 139 | { 140 | if (objects == null) 141 | return; 142 | 143 | var names = new List(); 144 | var components = new List(); 145 | 146 | foreach (var pair in objects) 147 | { 148 | if (pair.Value == null) 149 | continue; 150 | 151 | if (pair.Value is Component) 152 | { 153 | names.Add(pair.Key); 154 | components.Add(pair.Value as Component); 155 | } 156 | else 157 | { 158 | Dictionary typeObj = pair.Value as Dictionary; 159 | if (typeObj != null) 160 | { 161 | foreach (var pair2 in typeObj) 162 | { 163 | if (pair2.Value == null) 164 | continue; 165 | 166 | if (pair2.Value is Component) 167 | { 168 | names.Add(pair.Key); 169 | components.Add(pair2.Value as Component); 170 | } 171 | else if (pair2.Value is Component[]) 172 | { 173 | foreach (Component item in pair2.Value as Component[]) 174 | { 175 | if (item == null) 176 | continue; 177 | 178 | names.Add(pair.Key); 179 | components.Add(item); 180 | } 181 | } 182 | } 183 | } 184 | } 185 | } 186 | this.names = names.ToArray(); 187 | this.components = components.ToArray(); 188 | } 189 | 190 | void ISerializationCallbackReceiver.OnAfterDeserialize() 191 | { 192 | objects = new Dictionary(); 193 | int count = names.Length; 194 | for (int i = 0; i < count; i++) 195 | { 196 | string name = names[i]; 197 | Component component = components[i]; 198 | AddData(name, component); 199 | } 200 | } 201 | #endregion 202 | #region Create Datas 203 | HashSet customComponentSet; 204 | 205 | /// 206 | /// 临时创建时可以用此方法手动初始化数据 207 | /// 208 | public void RefreshDatas() 209 | { 210 | if (objects == null) 211 | objects = new Dictionary(); 212 | else 213 | objects.Clear(); 214 | 215 | ChangeGameObjectName(); 216 | 217 | customComponentSet = new HashSet(customComponents); 218 | foreach (var item in customComponents) 219 | { 220 | AddData(item.name, item); 221 | } 222 | AddDataFromChildren(transform); 223 | } 224 | 225 | //删除空格,括号等非法命名 226 | void ChangeGameObjectName() 227 | { 228 | #if UNITY_EDITOR 229 | foreach (Transform t in GetComponentsInChildren()) 230 | { 231 | t.name = t.name.Replace(" ", "").Replace("(", "").Replace(")", ""); 232 | } 233 | #endif 234 | } 235 | 236 | void AddDataFromChildren(Transform trans) 237 | { 238 | foreach (var item in trans.GetComponents