Last active
May 30, 2018 21:04
-
-
Save huiliu/45d7392146e56b8c7e3d89de13ddb95b to your computer and use it in GitHub Desktop.
九宫格形式拉伸贴图
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.UI; | |
using UnityEngine.Sprites; | |
public class ChildImage : Image{ | |
protected override void OnPopulateMesh(VertexHelper toFill) | |
{ | |
base.OnPopulateMesh(toFill); | |
if (overrideSprite == null) | |
{ | |
base.OnPopulateMesh(toFill); | |
return; | |
} | |
if (type == Type.Sliced) | |
{ | |
//GenerateSlicedSprite_(toFill); | |
GenerateSprite(toFill); | |
} | |
} | |
Vector4 GetAdjustedBorders(Vector4 border, Rect rect) | |
{ | |
for (int axis = 0; axis <= 1; axis++) | |
{ | |
// If the rect is smaller than the combined borders, then there's not room for the borders at their normal size. | |
// In order to avoid artefacts with overlapping borders, we scale the borders down to fit. | |
float combinedBorders = border[axis] + border[axis + 2]; | |
if (rect.size[axis] < combinedBorders && combinedBorders != 0) | |
{ | |
float borderScaleRatio = rect.size[axis] / combinedBorders; | |
border[axis] *= borderScaleRatio; | |
border[axis + 2] *= borderScaleRatio; | |
} | |
} | |
return border; | |
} | |
static void AddQuad(VertexHelper vertexHelper, Vector2 posMin, Vector2 posMax, Color32 color, Vector2 uvMin, Vector2 uvMax) | |
{ | |
int startIndex = vertexHelper.currentVertCount; | |
vertexHelper.AddVert(new Vector3(posMin.x, posMin.y, 0), color, new Vector2(uvMin.x, uvMin.y)); | |
vertexHelper.AddVert(new Vector3(posMin.x, posMax.y, 0), color, new Vector2(uvMin.x, uvMax.y)); | |
vertexHelper.AddVert(new Vector3(posMax.x, posMax.y, 0), color, new Vector2(uvMax.x, uvMax.y)); | |
vertexHelper.AddVert(new Vector3(posMax.x, posMin.y, 0), color, new Vector2(uvMax.x, uvMin.y)); | |
vertexHelper.AddTriangle(startIndex, startIndex + 1, startIndex + 2); | |
vertexHelper.AddTriangle(startIndex + 2, startIndex + 3, startIndex); | |
} | |
private void GenerateSlicedSprite_(VertexHelper toFill) | |
{ | |
Vector4 outer, inner, padding, border; | |
if (overrideSprite != null) | |
{ | |
outer = DataUtility.GetOuterUV(overrideSprite); | |
inner = DataUtility.GetInnerUV(overrideSprite); | |
padding = DataUtility.GetPadding(overrideSprite); | |
border = overrideSprite.border; | |
} | |
else | |
{ | |
outer = Vector4.zero; | |
inner = Vector4.zero; | |
padding = Vector4.zero; | |
border = Vector4.zero; | |
} | |
Rect rect = GetPixelAdjustedRect(); | |
border = GetAdjustedBorders(border / pixelsPerUnit, rect); | |
padding = padding / pixelsPerUnit; | |
float condition = (border.z + border.x) / rect.width; | |
#region 实际显示size | |
float[] x={0,0,0,0}; | |
x[0] = 0; | |
if (fillAmount <condition) | |
{ | |
x[1] = fillAmount / 2 * rect.width; | |
x[2] = x[1]+ 0; | |
x[3] = x[1]*2; | |
} | |
else | |
{ | |
x[1] = border.x; | |
x[2] = rect.width *fillAmount-border.z; | |
x[3] =x[2]+border.z; | |
} | |
float []y ={0+rect.y,rect.height+rect.y}; | |
for (int i = 0; i < 4; ++i) | |
{ | |
x[i] += rect.x; | |
} | |
#endregion | |
#region uv值 | |
float[] x_uv = {0,0,0,0 }; | |
x_uv[0] =0; | |
if (fillAmount <condition) | |
{ | |
x_uv[1] = fillAmount*rect.width/2/sprite.rect.size.x; | |
x_uv[2] = 1 - x_uv[1]; | |
} | |
else | |
{ | |
x_uv[1] = inner.x; | |
x_uv[2] = inner.z; | |
} | |
x_uv[3] = outer.z; | |
float y_uv = 1; | |
#endregion | |
toFill.Clear(); | |
for (int i = 0; i < 3; i++) | |
{ | |
int i2 = i + 1; | |
AddQuad(toFill, | |
new Vector2(x[i],y[0]), | |
new Vector2(x[i2],y[1]), | |
color, | |
new Vector2(x_uv[i],0), | |
new Vector2(x_uv[i2],y_uv)); | |
} | |
} | |
public SliceFilledType sliceFilledType; | |
static readonly Vector2[] s_VertScratch = new Vector2[4]; | |
static readonly Vector2[] s_UVScratch = new Vector2[4]; | |
private void GenerateSprite(VertexHelper toFill) | |
{ | |
Vector4 outer, inner, padding, border; | |
if (overrideSprite != null) | |
{ | |
outer = DataUtility.GetOuterUV(overrideSprite); | |
inner = DataUtility.GetInnerUV(overrideSprite); | |
padding = DataUtility.GetPadding(overrideSprite); | |
border = overrideSprite.border; | |
} | |
else | |
{ | |
outer = Vector4.zero; | |
inner = Vector4.zero; | |
padding = Vector4.zero; | |
border = Vector4.zero; | |
} | |
Rect rect = GetPixelAdjustedRect(); | |
var adjustedBorders = GetAdjustedBorders(border / pixelsPerUnit, rect); | |
padding = padding / pixelsPerUnit; | |
var tx0 = outer.x; | |
var ty0 = outer.y; | |
var tx1 = outer.z; | |
var ty1 = outer.w; | |
var v = GetDrawingDimensions(preserveAspect); | |
var fill = (tx1 - tx0) * fillAmount; | |
v.x = v.z - (v.x - v.z) * fillAmount; | |
tx0 = tx1 - fill; | |
switch (sliceFilledType) | |
{ | |
case SliceFilledType.Left: | |
{ | |
s_VertScratch[0] = new Vector2(padding.x, padding.y); | |
//s_VertScratch[3] = new Vector2(rect.width - padding.z, rect.height - padding.w); | |
s_VertScratch[1].x = adjustedBorders.x; | |
s_VertScratch[1].y = adjustedBorders.y; | |
s_VertScratch[2].x = (rect.width - adjustedBorders.z) * fillAmount; | |
s_VertScratch[2].y = rect.height - adjustedBorders.w; | |
s_VertScratch[3] = new Vector2(s_VertScratch[2].x + adjustedBorders.z, rect.height - padding.w); | |
} | |
break; | |
case SliceFilledType.Right: | |
{ | |
s_VertScratch[2].x = rect.width - adjustedBorders.z; | |
s_VertScratch[2].y = rect.height - adjustedBorders.w; | |
s_VertScratch[3] = new Vector2(rect.width - padding.z, rect.height - padding.w); | |
s_VertScratch[0].x = rect.width - (rect.width - adjustedBorders.x) * fillAmount - adjustedBorders.x; | |
s_VertScratch[0].y = padding.y; | |
s_VertScratch[1].x = s_VertScratch[0].x + adjustedBorders.x; | |
s_VertScratch[1].y = adjustedBorders.y; | |
} | |
break; | |
case SliceFilledType.Center: | |
{ | |
s_VertScratch[0].x = (rect.width - adjustedBorders.x) * fillAmount / 2; | |
s_VertScratch[0].y = padding.y; | |
s_VertScratch[1].x = s_VertScratch[0].x + adjustedBorders.x; | |
s_VertScratch[1].y = adjustedBorders.y; | |
s_VertScratch[2].x = rect.width - (rect.width - adjustedBorders.z) * fillAmount/2 - adjustedBorders.z; | |
s_VertScratch[2].y = rect.height - adjustedBorders.w; | |
s_VertScratch[3] = new Vector2(s_VertScratch[2].x + adjustedBorders.z, rect.height - padding.w); | |
} | |
break; | |
} | |
for (int i = 0; i < 4; ++i) | |
{ | |
s_VertScratch[i].x += rect.x; | |
s_VertScratch[i].y += rect.y; | |
} | |
s_UVScratch[0] = new Vector2(outer.x, outer.y); | |
s_UVScratch[1] = new Vector2(inner.x, inner.y); | |
s_UVScratch[2] = new Vector2(inner.z, inner.w); | |
s_UVScratch[3] = new Vector2(outer.z, outer.w); | |
toFill.Clear(); | |
for (int x = 0; x < 3; ++x) | |
{ | |
int x2 = x + 1; | |
for (int y = 0; y < 3; ++y) | |
{ | |
if (!fillCenter && x == 1 && y == 1) | |
continue; | |
int y2 = y + 1; | |
AddQuad(toFill, | |
new Vector2(s_VertScratch[x].x, s_VertScratch[y].y), | |
new Vector2(s_VertScratch[x2].x, s_VertScratch[y2].y), | |
color, | |
new Vector2(s_UVScratch[x].x, s_UVScratch[y].y), | |
new Vector2(s_UVScratch[x2].x, s_UVScratch[y2].y)); | |
} | |
} | |
} | |
/// Image's dimensions used for drawing. X = left, Y = bottom, Z = right, W = top. | |
private Vector4 GetDrawingDimensions(bool shouldPreserveAspect) | |
{ | |
var padding = overrideSprite == null ? Vector4.zero : UnityEngine.Sprites.DataUtility.GetPadding(overrideSprite); | |
var size = overrideSprite == null ? Vector2.zero : new Vector2(overrideSprite.rect.width, overrideSprite.rect.height); | |
Rect r = GetPixelAdjustedRect(); | |
// Debug.Log(string.Format("r:{2}, size:{0}, padding:{1}", size, padding, r)); | |
int spriteW = Mathf.RoundToInt(size.x); | |
int spriteH = Mathf.RoundToInt(size.y); | |
var v = new Vector4( | |
padding.x / spriteW, | |
padding.y / spriteH, | |
(spriteW - padding.z) / spriteW, | |
(spriteH - padding.w) / spriteH); | |
if (shouldPreserveAspect && size.sqrMagnitude > 0.0f) | |
{ | |
var spriteRatio = size.x / size.y; | |
var rectRatio = r.width / r.height; | |
if (spriteRatio > rectRatio) | |
{ | |
var oldHeight = r.height; | |
r.height = r.width * (1.0f / spriteRatio); | |
r.y += (oldHeight - r.height) * rectTransform.pivot.y; | |
} | |
else | |
{ | |
var oldWidth = r.width; | |
r.width = r.height * spriteRatio; | |
r.x += (oldWidth - r.width) * rectTransform.pivot.x; | |
} | |
} | |
v = new Vector4( | |
r.x + r.width * v.x, | |
r.y + r.height * v.y, | |
r.x + r.width * v.z, | |
r.y + r.height * v.w | |
); | |
return v; | |
} | |
public enum SliceFilledType | |
{ | |
Left, | |
Right, | |
Center | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEditor.UI; | |
using UnityEditor; | |
using UnityEditor.AnimatedValues; | |
using System.Linq; | |
[CustomEditor(typeof(SlicedImage))] | |
public class SlicedImageInspector : ImageEditor | |
{ | |
SerializedProperty m_FillMethod; | |
SerializedProperty m_FillOrigin; | |
SerializedProperty m_FillAmount; | |
SerializedProperty m_FillClockwise; | |
SerializedProperty m_Type; | |
SerializedProperty m_FillCenter; | |
SerializedProperty m_Sprite; | |
SerializedProperty m_PreserveAspect; | |
GUIContent m_SpriteContent; | |
GUIContent m_SpriteTypeContent; | |
GUIContent m_ClockwiseContent; | |
AnimBool m_ShowSlicedOrTiled; | |
AnimBool m_ShowSliced; | |
AnimBool m_ShowFilled; | |
AnimBool m_ShowType; | |
void SetShowNativeSize(bool instant) | |
{ | |
SlicedImage.Type type = (SlicedImage.Type)m_Type.enumValueIndex; | |
bool showNativeSize = (type == SlicedImage.Type.Simple || type == SlicedImage.Type.Filled); | |
base.SetShowNativeSize(showNativeSize, instant); | |
} | |
protected override void OnEnable() | |
{ | |
base.OnEnable(); | |
m_SpriteContent = new GUIContent("Source childImage"); | |
m_SpriteTypeContent = new GUIContent("childImage Type"); | |
m_ClockwiseContent = new GUIContent("Clockwise"); | |
m_Sprite = serializedObject.FindProperty("m_Sprite"); | |
m_Type = serializedObject.FindProperty("m_Type"); | |
m_FillCenter = serializedObject.FindProperty("m_FillCenter"); | |
m_FillMethod = serializedObject.FindProperty("m_FillMethod"); | |
m_FillOrigin = serializedObject.FindProperty("m_FillOrigin"); | |
m_FillClockwise = serializedObject.FindProperty("m_FillClockwise"); | |
m_FillAmount = serializedObject.FindProperty("m_FillAmount"); | |
m_PreserveAspect = serializedObject.FindProperty("m_PreserveAspect"); | |
m_ShowType = new AnimBool(m_Sprite.objectReferenceValue != null); | |
m_ShowType.valueChanged.AddListener(Repaint); | |
var typeEnum = (SlicedImage.Type)m_Type.enumValueIndex; | |
m_ShowSlicedOrTiled = new AnimBool(!m_Type.hasMultipleDifferentValues && typeEnum == SlicedImage.Type.Sliced); | |
m_ShowSliced = new AnimBool(!m_Type.hasMultipleDifferentValues && typeEnum == SlicedImage.Type.Sliced); | |
m_ShowFilled = new AnimBool(!m_Type.hasMultipleDifferentValues && typeEnum == SlicedImage.Type.Filled); | |
m_ShowSlicedOrTiled.valueChanged.AddListener(Repaint); | |
m_ShowSliced.valueChanged.AddListener(Repaint); | |
m_ShowFilled.valueChanged.AddListener(Repaint); | |
SetShowNativeSize(true); | |
} | |
public override void OnInspectorGUI() | |
{ | |
serializedObject.Update(); | |
SpriteGUI(); | |
AppearanceControlsGUI(); | |
RaycastControlsGUI(); | |
m_ShowType.target = m_Sprite.objectReferenceValue != null; | |
if (EditorGUILayout.BeginFadeGroup(m_ShowType.faded)) | |
{ | |
EditorGUILayout.PropertyField(m_Type, m_SpriteTypeContent); | |
++EditorGUI.indentLevel; | |
{ | |
SlicedImage.Type typeEnum = (SlicedImage.Type)m_Type.enumValueIndex; | |
bool showSlicedOrTiled = (!m_Type.hasMultipleDifferentValues && (typeEnum == SlicedImage.Type.Sliced || typeEnum == SlicedImage.Type.Tiled)); | |
if (showSlicedOrTiled && targets.Length > 1) | |
showSlicedOrTiled = targets.Select(obj => obj as SlicedImage).All(img => img.hasBorder); | |
m_ShowSlicedOrTiled.target = showSlicedOrTiled; | |
m_ShowSliced.target = (showSlicedOrTiled && !m_Type.hasMultipleDifferentValues && typeEnum == SlicedImage.Type.Sliced); | |
m_ShowFilled.target = (!m_Type.hasMultipleDifferentValues && (typeEnum == SlicedImage.Type.Filled)); | |
SlicedImage cImage = target as SlicedImage; | |
if (EditorGUILayout.BeginFadeGroup(m_ShowSlicedOrTiled.faded)) | |
{ | |
if (cImage.hasBorder) | |
{ | |
EditorGUILayout.PropertyField(m_FillCenter); | |
cImage.slicedType = (SlicedImage.SlicedType)EditorGUILayout.EnumPopup("Fill Origin", cImage.slicedType); | |
EditorGUILayout.PropertyField(m_FillAmount); | |
} | |
} | |
EditorGUILayout.EndFadeGroup(); | |
if (EditorGUILayout.BeginFadeGroup(m_ShowSliced.faded)) | |
{ | |
if (cImage.sprite != null && !cImage.hasBorder) | |
EditorGUILayout.HelpBox("This childImage doesn't have a border.", MessageType.Warning); | |
} | |
EditorGUILayout.EndFadeGroup(); | |
if (EditorGUILayout.BeginFadeGroup(m_ShowFilled.faded)) | |
{ | |
EditorGUI.BeginChangeCheck(); | |
EditorGUILayout.PropertyField(m_FillMethod); | |
if (EditorGUI.EndChangeCheck()) | |
{ | |
m_FillOrigin.intValue = 0; | |
} | |
switch ((SlicedImage.FillMethod)m_FillMethod.enumValueIndex) | |
{ | |
case SlicedImage.FillMethod.Horizontal: | |
m_FillOrigin.intValue = (int)(SlicedImage.OriginHorizontal)EditorGUILayout.EnumPopup("Fill Origin", (SlicedImage.OriginHorizontal)m_FillOrigin.intValue); | |
break; | |
case SlicedImage.FillMethod.Vertical: | |
m_FillOrigin.intValue = (int)(SlicedImage.OriginVertical)EditorGUILayout.EnumPopup("Fill Origin", (SlicedImage.OriginVertical)m_FillOrigin.intValue); | |
break; | |
case SlicedImage.FillMethod.Radial90: | |
m_FillOrigin.intValue = (int)(SlicedImage.Origin90)EditorGUILayout.EnumPopup("Fill Origin", (SlicedImage.Origin90)m_FillOrigin.intValue); | |
break; | |
case SlicedImage.FillMethod.Radial180: | |
m_FillOrigin.intValue = (int)(SlicedImage.Origin180)EditorGUILayout.EnumPopup("Fill Origin", (SlicedImage.Origin180)m_FillOrigin.intValue); | |
break; | |
case SlicedImage.FillMethod.Radial360: | |
m_FillOrigin.intValue = (int)(SlicedImage.Origin360)EditorGUILayout.EnumPopup("Fill Origin", (SlicedImage.Origin360)m_FillOrigin.intValue); | |
break; | |
} | |
EditorGUILayout.PropertyField(m_FillAmount); | |
if ((SlicedImage.FillMethod)m_FillMethod.enumValueIndex > SlicedImage.FillMethod.Vertical) | |
{ | |
EditorGUILayout.PropertyField(m_FillClockwise, m_ClockwiseContent); | |
} | |
} | |
EditorGUILayout.EndFadeGroup(); | |
} | |
--EditorGUI.indentLevel; | |
} | |
EditorGUILayout.EndFadeGroup(); | |
SetShowNativeSize(false); | |
if (EditorGUILayout.BeginFadeGroup(m_ShowNativeSize.faded)) | |
{ | |
EditorGUI.indentLevel++; | |
EditorGUILayout.PropertyField(m_PreserveAspect); | |
EditorGUI.indentLevel--; | |
} | |
EditorGUILayout.EndFadeGroup(); | |
NativeSizeButtonGUI(); | |
serializedObject.ApplyModifiedProperties(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment