void OnDisable() { ClearTextureCache(); _spriteCollection = null; tk2dEditorUtility.CollectAndUnloadUnusedAssets(); }
public void SetGenerator(tk2dSpriteCollection spriteCollection) { this._spriteCollection = spriteCollection; this.firstRun = true; spriteCollectionProxy = new SpriteCollectionProxy(spriteCollection); PopulateEntries(); }
public static void CreateSpriteCollectionModified() { string path = tk2dEditorUtility.CreateNewPrefab("SpriteCollection"); if (path.Length != 0) { GameObject go = new GameObject(); tk2dSpriteCollection spriteCollection = go.AddComponent <tk2dSpriteCollection>(); spriteCollection.filterMode = FilterMode.Bilinear; spriteCollection.sizeDef = tk2dSpriteCollectionSize.PixelsPerMeter(40); spriteCollection.version = tk2dSpriteCollection.CURRENT_VERSION; if (tk2dCamera.Editor__Inst != null) { spriteCollection.sizeDef.CopyFrom(tk2dSpriteCollectionSize.ForTk2dCamera(tk2dCamera.Editor__Inst)); } tk2dEditorUtility.SetGameObjectActive(go, false); Object p = PrefabUtility.CreateEmptyPrefab(path); PrefabUtility.ReplacePrefab(go, p, ReplacePrefabOptions.ConnectToPrefab); GameObject.DestroyImmediate(go); // Select object Selection.activeObject = AssetDatabase.LoadAssetAtPath(path, typeof(UnityEngine.Object)); } }
public override void OnInspectorGUI() { tk2dSpriteCollection gen = (tk2dSpriteCollection)target; GUILayout.BeginVertical(); GUILayout.Space(8); if (gen.managedSpriteCollection) { string label = showDefaultInspector?"Hide Default Inspector":"Show Default Inspector"; int buttonPressed = tk2dGuiUtility.InfoBoxWithButtons("This is a managed sprite collection. Please do not modify.", tk2dGuiUtility.WarningLevel.Info, new string[] { label }); if (buttonPressed == 0) { showDefaultInspector = !showDefaultInspector; } if (showDefaultInspector) { GUILayout.Space(16); DrawDefaultInspector(); } } else { string assetPath = AssetDatabase.GetAssetPath(gen).ToLower(); bool inResources = assetPath.IndexOf("/resources/") != -1; if (inResources) { string msg = "Sprite collection is in a resources directory. " + "All source textures will be included in build.\n\n" + "Editor is disabled. Move it out of the resources directory to continue."; tk2dGuiUtility.InfoBox(msg, tk2dGuiUtility.WarningLevel.Error); } else { GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Open Editor...", GUILayout.MinWidth(120))) { if (gen.name == defaultSpriteCollectionName) { EditorUtility.DisplayDialog("Invalid Sprite Collection name", "Please rename sprite collection before proceeding", "Ok"); } else { tk2dSpriteCollectionEditorPopup v = EditorWindow.GetWindow(typeof(tk2dSpriteCollectionEditorPopup), false, "SpriteCollection") as tk2dSpriteCollectionEditorPopup; v.SetGenerator(gen); } } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } } EditorGUILayout.EndVertical(); GUILayout.Space(64); }
static void DoCollectionCreate() { string path = tk2dEditorUtility.CreateNewPrefab(defaultSpriteCollectionName); if (path.Length != 0) { GameObject go = new GameObject(); tk2dSpriteCollection spriteCollection = go.AddComponent <tk2dSpriteCollection>(); spriteCollection.version = tk2dSpriteCollection.CURRENT_VERSION; if (tk2dCamera.Editor__Inst != null) { spriteCollection.sizeDef.CopyFrom(tk2dSpriteCollectionSize.ForTk2dCamera(tk2dCamera.Editor__Inst)); } tk2dEditorUtility.SetGameObjectActive(go, false); #if (UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4) Object p = EditorUtility.CreateEmptyPrefab(path); EditorUtility.ReplacePrefab(go, p, ReplacePrefabOptions.ConnectToPrefab); #else Object p = PrefabUtility.CreateEmptyPrefab(path); PrefabUtility.ReplacePrefab(go, p, ReplacePrefabOptions.ConnectToPrefab); #endif GameObject.DestroyImmediate(go); // Select object Selection.activeObject = AssetDatabase.LoadAssetAtPath(path, typeof(UnityEngine.Object)); } }
public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) { if (string.IsNullOrEmpty(mainTranslation)) { return; } //--[ Localize Atlas ]---------- tk2dSpriteCollection newCollection = cmp.GetSecondaryTranslatedObj <tk2dSpriteCollection>(ref mainTranslation, ref secondaryTranslation); if (newCollection != null) { if (mTarget.CurrentSprite.name != mainTranslation || mTarget.Collection.name != secondaryTranslation) { mTarget.SetSprite(newCollection.spriteCollection, mainTranslation); } } else { if (mTarget.CurrentSprite.name != mainTranslation) { mTarget.SetSprite(mainTranslation); } } }
public static void Build(tk2dSpriteCollection data) { if (data.linkedSpriteCollections.Count > 0 && !data.disableTrimming) { return; } string errors = ""; int errorCount = 0; string root = System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(data)) + "/Linked"; foreach (tk2dLinkedSpriteCollection link in data.linkedSpriteCollections) { if (link.spriteCollection == null) { if (!System.IO.Directory.Exists(root)) { System.IO.Directory.CreateDirectory(root); } link.spriteCollection = tk2dSpriteCollectionEditor.CreateSpriteCollection(root, data.name + link.name); } tk2dEditor.SpriteCollectionEditor.SpriteCollectionProxy proxy = new tk2dEditor.SpriteCollectionEditor.SpriteCollectionProxy(data, false); proxy.CopyBuiltFromSource(link.spriteCollection); proxy.linkedSpriteCollections.Clear(); // stop recursion string thisErrors = ""; foreach (tk2dSpriteCollectionDefinition tp in proxy.textureParams) { if (tp.texture != null) { Texture2D repl = FindReplacementTexture(tp.texture, link.name); if (repl == null) { thisErrors += string.Format("Unable to find replacement for texture '{0}' for link '{1}'\n", tp.texture.name, link.name); ++errorCount; } tp.texture = repl; } } if (thisErrors.Length == 0) { proxy.CopyToTarget(link.spriteCollection); link.spriteCollection.linkParent = data; EditorUtility.SetDirty(link.spriteCollection); tk2dSpriteCollectionBuilder.Rebuild(link.spriteCollection); } else { errors += thisErrors; } } if (errors.Length > 0) { Debug.LogError("There were " + errorCount.ToString() + " errors building the sprite collection\n" + errors); } }
public static void SpriteSelector(tk2dSpriteCollectionData spriteCollection, int spriteId, SpriteChangedCallback callback, object callbackData) { tk2dSpriteCollectionData newCollection = spriteCollection; int newSpriteId = spriteId; GUILayout.BeginHorizontal(); GUILayout.BeginVertical(); GUILayout.BeginHorizontal(); newCollection = SpriteCollectionList("Collection", spriteCollection); if (tk2dPreferences.inst.displayEditSpriteButton && GUILayout.Button("o", EditorStyles.miniButton, GUILayout.Width(18))) { EditorGUIUtility.PingObject(spriteCollection); } GUILayout.EndHorizontal(); if (spriteCollection != null && spriteCollection.Count != 0) { if (spriteId < 0 || spriteId >= spriteCollection.Count || !spriteCollection.inst.spriteDefinitions[spriteId].Valid) { newSpriteId = spriteCollection.FirstValidDefinitionIndex; } GUILayout.BeginHorizontal(); newSpriteId = SpriteList("Sprite", newSpriteId, spriteCollection); if (tk2dPreferences.inst.displayEditSpriteButton && spriteCollection != null && spriteCollection.dataGuid != TransientGUID && GUILayout.Button("e", EditorStyles.miniButton, GUILayout.Width(18), GUILayout.MaxHeight(14f))) { tk2dSpriteCollection gen = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(spriteCollection.spriteCollectionGUID), typeof(tk2dSpriteCollection)) as tk2dSpriteCollection; if (gen != null) { tk2dSpriteCollectionEditorPopup v = EditorWindow.GetWindow(typeof(tk2dSpriteCollectionEditorPopup), false, "Sprite Collection Editor") as tk2dSpriteCollectionEditorPopup; v.SetGeneratorAndSelectedSprite(gen, spriteId); } } GUILayout.EndHorizontal(); } if (callback != null && (newCollection != spriteCollection || newSpriteId != spriteId)) { callback(newCollection, newSpriteId, callbackData); } GUILayout.EndVertical(); if (GUILayout.Button("...", GUILayout.Height(32), GUILayout.Width(32))) { SpriteSelectorPopup(spriteCollection, spriteId, callback, callbackData); } GUILayout.EndHorizontal(); }
public static void ValidateTextureParam(tk2dSpriteCollection gen, int i) { var param = gen.textureParams[i]; if (param.texture != null && gen.linkParent != null) { if (gen.linkParent.textureParams[i].texture == null || gen.linkParent.textureParams[i].texture.width != param.texture.width || gen.linkParent.textureParams[i].texture.height != param.texture.height) { Debug.LogError("Linked sprite collection mismatch " + param.texture.name); } } }
public void SelectBody3() { playerCollection = null; playerCollection = database.GetCollectionByName("皮肤3"); //playerCollection = Resources.Load("Collections/人物3图集", typeof(tk2dSpriteCollection)) as tk2dSpriteCollection; if (playerCollection == null) { Debug.LogWarning("加载图集失败!"); } }
public static void ValidateLinkedSpriteCollection(tk2dSpriteCollection gen) { if (gen.linkParent == null) { return; } if (gen.textureParams.Length != gen.linkParent.textureParams.Length) { Debug.LogError("Linked sprite collection mismatch. Please rebuild source collection"); gen.linkParent = null; } }
public void CopyBuiltFromSource(tk2dSpriteCollection source) { SpriteCollectionProxy target = this; target.spriteCollection = source.spriteCollection; CopyArray(ref target.altMaterials, source.altMaterials); CopyArray(ref target.atlasMaterials, source.atlasMaterials); CopyArray(ref target.atlasTextures, source.atlasTextures); CopyArray(ref target.atlasTextureFiles, source.atlasTextureFiles); }
public void SelectWeapon2() { weaponCollection = null; weaponCollection = database.GetCollectionByName("武器2"); //weaponCollection = Resources.Load("Collections/武器2图集", typeof(tk2dSpriteCollection)) as tk2dSpriteCollection; if (weaponCollection == null) { Debug.LogWarning("加载图集失败!"); } }
override public void OnInspectorGUI () { serializedObject.Update(); SkeletonDataAsset asset = (SkeletonDataAsset)target; tk2dSpriteCollection sprites = EditorGUILayout.ObjectField("Sprite Collection", asset.spriteCollection, typeof(tk2dSpriteCollection), false) as tk2dSpriteCollection; if (sprites != null) spriteCollection.objectReferenceValue = sprites.spriteCollection; EditorGUILayout.PropertyField(skeletonJSON); EditorGUILayout.PropertyField(scale); SkeletonData skeletonData = asset.GetSkeletonData(asset.spriteCollection == null || asset.skeletonJSON == null); if (skeletonData != null) { showAnimationStateData = EditorGUILayout.Foldout(showAnimationStateData, "Animation State Data"); if (showAnimationStateData) { // Animation names. String[] animations = new String[skeletonData.Animations.Count]; for (int i = 0; i < animations.Length; i++) animations[i] = skeletonData.Animations[i].Name; for (int i = 0; i < fromAnimation.arraySize; i++) { SerializedProperty from = fromAnimation.GetArrayElementAtIndex(i); SerializedProperty to = toAnimation.GetArrayElementAtIndex(i); SerializedProperty durationProp = duration.GetArrayElementAtIndex(i); EditorGUILayout.BeginHorizontal(); from.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, from.stringValue), 0), animations)]; to.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, to.stringValue), 0), animations)]; durationProp.floatValue = EditorGUILayout.FloatField(durationProp.floatValue); if (GUILayout.Button("Delete")) { duration.DeleteArrayElementAtIndex(i); toAnimation.DeleteArrayElementAtIndex(i); fromAnimation.DeleteArrayElementAtIndex(i); } EditorGUILayout.EndHorizontal(); } EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); if (GUILayout.Button("Add Mix")) { duration.arraySize++; toAnimation.arraySize++; fromAnimation.arraySize++; } EditorGUILayout.Space(); EditorGUILayout.EndHorizontal(); } } if (!Application.isPlaying) { if (serializedObject.ApplyModifiedProperties() || (UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed") ) { asset.Clear(); } } }
public void CopyToTarget(tk2dSpriteCollection target) { target.textureParams = textureParams.ToArray(); target.spriteSheets = spriteSheets.ToArray(); target.fonts = fonts.ToArray(); var source = this; target.platforms = new List <tk2dSpriteCollectionPlatform>(); foreach (tk2dSpriteCollectionPlatform plat in source.platforms) { tk2dSpriteCollectionPlatform p = new tk2dSpriteCollectionPlatform(); p.CopyFrom(plat); target.platforms.Add(p); } target.assetName = source.assetName; target.loadable = source.loadable; target.maxTextureSize = source.maxTextureSize; target.forceTextureSize = source.forceTextureSize; target.forcedTextureWidth = source.forcedTextureWidth; target.forcedTextureHeight = source.forcedTextureHeight; target.textureCompression = source.textureCompression; target.atlasWidth = source.atlasWidth; target.atlasHeight = source.atlasHeight; target.forceSquareAtlas = source.forceSquareAtlas; target.atlasWastage = source.atlasWastage; target.allowMultipleAtlases = source.allowMultipleAtlases; target.spriteCollection = source.spriteCollection; target.premultipliedAlpha = source.premultipliedAlpha; CopyArray(ref target.altMaterials, source.altMaterials); CopyArray(ref target.atlasMaterials, source.atlasMaterials); CopyArray(ref target.atlasTextures, source.atlasTextures); target.useTk2dCamera = source.useTk2dCamera; target.targetHeight = source.targetHeight; target.targetOrthoSize = source.targetOrthoSize; target.globalScale = source.globalScale; target.physicsDepth = source.physicsDepth; target.disableTrimming = source.disableTrimming; target.normalGenerationMode = source.normalGenerationMode; target.padAmount = source.padAmount; target.autoUpdate = source.autoUpdate; target.editorDisplayScale = source.editorDisplayScale; // Texture settings target.filterMode = source.filterMode; target.wrapMode = source.wrapMode; target.userDefinedTextureSettings = source.userDefinedTextureSettings; target.mipmapEnabled = source.mipmapEnabled; target.anisoLevel = source.anisoLevel; }
public static bool CheckAndFixUpParams(tk2dSpriteCollection gen) { if (gen.DoNotUse__TextureRefs != null && gen.textureParams != null && gen.DoNotUse__TextureRefs.Length != gen.textureParams.Length) { tk2dSpriteCollectionDefinition[] newDefs = new tk2dSpriteCollectionDefinition[gen.DoNotUse__TextureRefs.Length]; int c = Mathf.Min(newDefs.Length, gen.textureParams.Length); if (gen.DoNotUse__TextureRefs.Length > gen.textureParams.Length) { Texture2D[] newTexRefs = new Texture2D[gen.DoNotUse__TextureRefs.Length - gen.textureParams.Length]; System.Array.Copy(gen.DoNotUse__TextureRefs, gen.textureParams.Length, newTexRefs, 0, newTexRefs.Length); System.Array.Sort(newTexRefs, (Texture2D a, Texture2D b) => tk2dSpriteGuiUtility.NameCompare(a?a.name:"", b?b.name:"")); System.Array.Copy(newTexRefs, 0, gen.DoNotUse__TextureRefs, gen.textureParams.Length, newTexRefs.Length); } for (int i = 0; i < c; ++i) { newDefs[i] = new tk2dSpriteCollectionDefinition(); newDefs[i].CopyFrom(gen.textureParams[i]); } for (int i = c; i < newDefs.Length; ++i) { newDefs[i] = new tk2dSpriteCollectionDefinition(); newDefs[i].pad = gen.defaults.pad; newDefs[i].additive = gen.defaults.additive; newDefs[i].anchor = gen.defaults.anchor; newDefs[i].scale = gen.defaults.scale; newDefs[i].colliderType = gen.defaults.colliderType; } gen.textureParams = newDefs; } // clear thumbnails on build foreach (var param in gen.textureParams) { param.thumbnailTexture = null; } foreach (var param in gen.textureParams) { if (gen.allowMultipleAtlases && param.dice) { EditorUtility.DisplayDialog("Error", "Multiple atlas spanning is not allowed when there are textures with dicing enabled in the SpriteCollection.", "Ok"); gen.allowMultipleAtlases = false; return(false); } } return(true); }
public static bool CheckAndFixUpParams(tk2dSpriteCollection gen) { if (gen.DoNotUse__TextureRefs != null && gen.textureParams != null && gen.DoNotUse__TextureRefs.Length != gen.textureParams.Length) { tk2dSpriteCollectionDefinition[] newDefs = new tk2dSpriteCollectionDefinition[gen.DoNotUse__TextureRefs.Length]; int c = Mathf.Min( newDefs.Length, gen.textureParams.Length ); if (gen.DoNotUse__TextureRefs.Length > gen.textureParams.Length) { Texture2D[] newTexRefs = new Texture2D[gen.DoNotUse__TextureRefs.Length - gen.textureParams.Length]; System.Array.Copy(gen.DoNotUse__TextureRefs, gen.textureParams.Length, newTexRefs, 0, newTexRefs.Length); System.Array.Sort(newTexRefs, (Texture2D a, Texture2D b) => tk2dSpriteGuiUtility.NameCompare(a?a.name:"", b?b.name:"")); System.Array.Copy(newTexRefs, 0, gen.DoNotUse__TextureRefs, gen.textureParams.Length, newTexRefs.Length); } for (int i = 0; i < c; ++i) { newDefs[i] = new tk2dSpriteCollectionDefinition(); newDefs[i].CopyFrom( gen.textureParams[i] ); } for (int i = c; i < newDefs.Length; ++i) { newDefs[i] = new tk2dSpriteCollectionDefinition(); newDefs[i].pad = gen.defaults.pad; newDefs[i].additive = gen.defaults.additive; newDefs[i].anchor = gen.defaults.anchor; newDefs[i].scale = gen.defaults.scale; newDefs[i].colliderType = gen.defaults.colliderType; } gen.textureParams = newDefs; } // clear thumbnails on build foreach (var param in gen.textureParams) { param.thumbnailTexture = null; } foreach (var param in gen.textureParams) { if (gen.allowMultipleAtlases && param.dice) { EditorUtility.DisplayDialog("Error", "Multiple atlas spanning is not allowed when there are textures with dicing enabled in the SpriteCollection.", "Ok"); gen.allowMultipleAtlases = false; return false; } } return true; }
static void SetUpSourceTextureFormats(tk2dSpriteCollection gen) { // make sure all textures are in the right format int numTexturesReimported = 0; List <Texture2D> texturesToProcess = new List <Texture2D>(); for (int i = 0; i < gen.textureParams.Length; ++i) { if (gen.textureRefs[i] != null) { texturesToProcess.Add(gen.textureRefs[i]); } } if (gen.spriteSheets != null) { for (int i = 0; i < gen.spriteSheets.Length; ++i) { if (gen.spriteSheets[i].texture != null) { texturesToProcess.Add(gen.spriteSheets[i].texture); } } } foreach (var tex in texturesToProcess) { // make sure the source texture is npot and readable, and uncompressed string thisTextPath = AssetDatabase.GetAssetPath(tex); TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(thisTextPath); if (importer.textureType != TextureImporterType.Advanced || importer.textureFormat != TextureImporterFormat.AutomaticTruecolor || importer.npotScale != TextureImporterNPOTScale.None || importer.isReadable != true || importer.maxTextureSize < 4096) { importer.textureFormat = TextureImporterFormat.AutomaticTruecolor; importer.textureType = TextureImporterType.Advanced; importer.npotScale = TextureImporterNPOTScale.None; importer.isReadable = true; importer.mipmapEnabled = false; importer.maxTextureSize = 4096; AssetDatabase.ImportAsset(thisTextPath); numTexturesReimported++; } } if (numTexturesReimported > 0) { AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } }
public static void TrimTextureList(tk2dSpriteCollection gen) { // trim textureRefs & textureParams int lastNonEmpty = -1; for (int i = 0; i < gen.DoNotUse__TextureRefs.Length; ++i) { if (gen.DoNotUse__TextureRefs[i] != null) lastNonEmpty = i; } Texture2D[] textureRefs = gen.DoNotUse__TextureRefs; System.Array.Resize(ref textureRefs, lastNonEmpty + 1); System.Array.Resize(ref gen.textureParams, lastNonEmpty + 1); gen.DoNotUse__TextureRefs = textureRefs; }
public static string GetOrCreateDataPath(tk2dSpriteCollection gen) { if (gen.spriteCollection != null) { return System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(gen.spriteCollection)); } else { string path = System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(gen)) + "/" + gen.name + " Data"; if (!System.IO.Directory.Exists(path)) System.IO.Directory.CreateDirectory(path); return path; } }
public static void InitializeSpriteCollectionPlatforms(tk2dSpriteCollection gen, string root) { // Create all missing platform directories and sprite collection objects for (int i = 0; i < gen.platforms.Count; ++i) { tk2dSpriteCollectionPlatform plat = gen.platforms[i]; if (plat.name.Length > 0 && !plat.spriteCollection) { plat.spriteCollection = tk2dSpriteCollectionEditor.CreateSpriteCollection(root, gen.name + "@" + plat.name); plat.spriteCollection.managedSpriteCollection = true; EditorUtility.SetDirty(gen.spriteCollection); } } }
public static tk2dSpriteCollection CreateSpriteCollection(string basePath, string name) { string path = AssetDatabase.GenerateUniqueAssetPath(basePath + "/" + name + ".prefab"); GameObject go = new GameObject(); tk2dSpriteCollection spriteCollection = go.AddComponent <tk2dSpriteCollection>(); spriteCollection.version = tk2dSpriteCollection.CURRENT_VERSION; tk2dEditorUtility.SetGameObjectActive(go, false); PrefabUtility.SaveAsPrefabAsset(go, path); GameObject.DestroyImmediate(go); return(AssetDatabase.LoadAssetAtPath(path, typeof(tk2dSpriteCollection)) as tk2dSpriteCollection); }
public void SetGeneratorAndSelectedSprite(tk2dSpriteCollection spriteCollection, int selectedSprite) { searchFilter = ""; SetGenerator(spriteCollection); foreach (var entry in entries) { if (entry.type == SpriteCollectionEditorEntry.Type.Sprite && entry.index == selectedSprite) { entry.selected = true; break; } } UpdateSelection(); }
static void TrimTextureList(tk2dSpriteCollection gen) { // trim textureRefs & textureParams int lastNonEmpty = -1; for (int i = 0; i < gen.textureRefs.Length; ++i) { if (gen.textureRefs[i] != null) { lastNonEmpty = i; } } System.Array.Resize(ref gen.textureRefs, lastNonEmpty + 1); System.Array.Resize(ref gen.textureParams, lastNonEmpty + 1); }
static void SetUpTargetTexture(tk2dSpriteCollection gen, Texture2D tex) { bool textureDirty = false; string targetTexPath = AssetDatabase.GetAssetPath(tex); TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(targetTexPath); if (gen.maxTextureSize != importer.maxTextureSize) { importer.maxTextureSize = gen.maxTextureSize; textureDirty = true; } TextureImporterFormat targetFormat; switch (gen.textureCompression) { case tk2dSpriteCollection.TextureCompression.Uncompressed: targetFormat = TextureImporterFormat.AutomaticTruecolor; break; case tk2dSpriteCollection.TextureCompression.Reduced16Bit: targetFormat = TextureImporterFormat.Automatic16bit; break; case tk2dSpriteCollection.TextureCompression.Compressed: targetFormat = TextureImporterFormat.AutomaticCompressed; break; default: targetFormat = TextureImporterFormat.AutomaticTruecolor; break; } if (targetFormat != importer.textureFormat) { importer.textureFormat = targetFormat; textureDirty = true; } // Make sure texture is set to point filtered when no pad mode is selected FilterMode targetFilterMode = gen.pixelPerfectPointSampled?FilterMode.Point:FilterMode.Bilinear; if (tex.filterMode != targetFilterMode) { importer.filterMode = targetFilterMode; EditorUtility.SetDirty(importer); textureDirty = true; } if (textureDirty) { EditorUtility.SetDirty(importer); AssetDatabase.ImportAsset(targetTexPath); } }
// Rebuild a sprite collection when out of date // Identifies changed textures by comparing GUID public static void RebuildOutOfDate(string[] changedPaths) { // This should only take existing indices, as we don't want to slow anything down here tk2dIndex index = tk2dEditorUtility.GetExistingIndex(); if (index == null) { return; } tk2dSpriteCollectionData[] scg = tk2dEditorUtility.GetExistingIndex().GetSpriteCollectionData(); if (scg == null) { return; } foreach (tk2dSpriteCollectionData thisScg in scg) { bool needRebuild = false; foreach (var def in thisScg.spriteDefinitions) { foreach (string changedPath in changedPaths) { if (def.sourceTextureGUID == AssetDatabase.AssetPathToGUID(changedPath)) { needRebuild = true; break; } } if (needRebuild) { break; } } if (needRebuild) { tk2dSpriteCollection spriteCollectionSource = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(thisScg.spriteCollectionGUID), typeof(tk2dSpriteCollection)) as tk2dSpriteCollection; if (spriteCollectionSource != null) { Rebuild(spriteCollectionSource); } tk2dEditorUtility.UnloadUnusedAssets(); } } }
public override void OnInspectorGUI() { tk2dSpriteCollection gen = (tk2dSpriteCollection)target; GUILayout.BeginVertical(); GUILayout.Space(8); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Open Editor...", EditorStyles.miniButton, GUILayout.MinWidth(120))) { tk2dSpriteCollectionEditorPopup v = EditorWindow.GetWindow(typeof(tk2dSpriteCollectionEditorPopup), false, "Sprite Collection Editor") as tk2dSpriteCollectionEditorPopup; v.SetGenerator(gen); } GUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); }
public void DefaultSkin() { playerCollection = null; playerCollection = database.GetCollectionByName("默认皮肤"); if (playerCollection == null) { Debug.LogWarning("加载图集失败!"); } weaponCollection = null; weaponCollection = database.GetCollectionByName("默认武器"); if (weaponCollection == null) { Debug.LogWarning("加载图集失败!"); } }
public override void OnInspectorGUI() { tk2dSpriteCollection gen = (tk2dSpriteCollection)target; GUILayout.BeginVertical(); GUILayout.Space(8); if (gen.managedSpriteCollection) { string label = showDefaultInspector?"Hide Default Inspector":"Show Default Inspector"; int buttonPressed = tk2dGuiUtility.InfoBoxWithButtons("This is a managed sprite collection. Please do not modify.", tk2dGuiUtility.WarningLevel.Info, new string[] { label }); if (buttonPressed == 0) { showDefaultInspector = !showDefaultInspector; } if (showDefaultInspector) { GUILayout.Space(16); DrawDefaultInspector(); } } else { GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Open Editor...", GUILayout.MinWidth(120))) { if (gen.name == defaultSpriteCollectionName) { EditorUtility.DisplayDialog("Invalid Sprite Collection name", "Please rename sprite collection before proceeding", "Ok"); } else { tk2dSpriteCollectionEditorPopup v = EditorWindow.GetWindow(typeof(tk2dSpriteCollectionEditorPopup), false, "Sprite Collection Editor") as tk2dSpriteCollectionEditorPopup; v.SetGenerator(gen); } } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } EditorGUILayout.EndVertical(); GUILayout.Space(64); }
/* */ void OnEnable() { tk2dSpineSkeletonDataAsset skeletonDataAsset = target as tk2dSpineSkeletonDataAsset; if (skeletonDataAsset != null) { tk2dSpriteCollectionData spritesData = skeletonDataAsset.spritesData; if (spritesData != null) { sprites = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(spritesData.spriteCollectionGUID), typeof(tk2dSpriteCollection)) as tk2dSpriteCollection; } } skeletonJSON = serializedObject.FindProperty("skeletonJSON"); fromAnimation = serializedObject.FindProperty("fromAnimation"); toAnimation = serializedObject.FindProperty("toAnimation"); duration = serializedObject.FindProperty("duration"); }
/// <summary> /// Reload the collection that changed. /// </summary> public void ReloadCollection() { // safety if (_spriteCollectionData == null) { return; } // grab the sprite collection path string collectionPath = AssetDatabase.GUIDToAssetPath(_spriteCollectionData.spriteCollectionGUID); // reload the collection tk2dSpriteCollection spriteCollectionReload = AssetDatabase.LoadAssetAtPath(collectionPath, typeof(tk2dSpriteCollection)) as tk2dSpriteCollection; if (spriteCollectionReload != null) { // reassign the collection instance _spriteCollectionData = spriteCollectionReload.spriteCollection.inst; } }
public void DoLocalize_tk2dBaseSprite(string MainTranslation, string SecondaryTranslation) { //--[ Localize Atlas ]---------- tk2dSpriteCollection newCollection = GetSecondaryTranslatedObj <tk2dSpriteCollection>(ref MainTranslation, ref SecondaryTranslation); if (newCollection != null) { if (mTarget_tk2dBaseSprite.CurrentSprite.name != MainTranslation || mTarget_tk2dBaseSprite.Collection.name != SecondaryTranslation) { mTarget_tk2dBaseSprite.SetSprite(newCollection.spriteCollection, MainTranslation); } } else { if (mTarget_tk2dBaseSprite.CurrentSprite.name != MainTranslation) { mTarget_tk2dBaseSprite.SetSprite(MainTranslation); } } }
public static tk2dSpriteCollection CreateSpriteCollection(string basePath, string name) { string path = AssetDatabase.GenerateUniqueAssetPath(basePath + "/" + name + ".prefab"); GameObject go = new GameObject(); tk2dSpriteCollection spriteCollection = go.AddComponent <tk2dSpriteCollection>(); spriteCollection.version = tk2dSpriteCollection.CURRENT_VERSION; tk2dEditorUtility.SetGameObjectActive(go, false); #if (UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4) Object p = EditorUtility.CreateEmptyPrefab(path); EditorUtility.ReplacePrefab(go, p, ReplacePrefabOptions.ConnectToPrefab); #else Object p = PrefabUtility.CreateEmptyPrefab(path); PrefabUtility.ReplacePrefab(go, p, ReplacePrefabOptions.ConnectToPrefab); #endif GameObject.DestroyImmediate(go); return(AssetDatabase.LoadAssetAtPath(path, typeof(tk2dSpriteCollection)) as tk2dSpriteCollection); }
static void UpdateVertexCache(tk2dSpriteCollection gen, tk2dAtlas.AtlasData[] packers, tk2dSpriteCollectionData coll, List<SCGE.SpriteLut> spriteLuts) { float scale = 2.0f * gen.targetOrthoSize / gen.targetHeight; int padAmount = GetPadAmount(gen); for (int i = 0; i < sourceTextures.Length; ++i) { SCGE.SpriteLut _lut = null; for (int j = 0; j < spriteLuts.Count; ++j) { if (spriteLuts[j].source == i) { _lut = spriteLuts[j]; break; } } tk2dSpriteCollectionDefinition thisTexParam = gen.textureParams[i]; tk2dAtlas.AtlasData packer = null; tk2dAtlas.AtlasEntry atlasEntry = null; int atlasIndex = 0; foreach (var p in packers) { if ((atlasEntry = p.FindEntryWithIndex(_lut.atlasIndex)) != null) { packer = p; break; } ++atlasIndex; } float fwidth = packer.width; float fheight = packer.height; int tx = atlasEntry.x + padAmount, ty = atlasEntry.y + padAmount, tw = atlasEntry.w - padAmount * 2, th = atlasEntry.h - padAmount * 2; int sd_y = packer.height - ty - th; float uvOffsetX = 0.001f / fwidth; float uvOffsetY = 0.001f / fheight; Vector2 v0 = new Vector2(tx / fwidth + uvOffsetX, 1.0f - (sd_y + th) / fheight + uvOffsetY); Vector2 v1 = new Vector2((tx + tw) / fwidth - uvOffsetX, 1.0f - sd_y / fheight - uvOffsetY); Mesh mesh = null; Transform meshTransform = null; GameObject instantiated = null; Vector3 colliderOrigin = new Vector3(); if (thisTexParam.overrideMesh) { // Disabled instantiated = GameObject.Instantiate(thisTexParam.overrideMesh) as GameObject; MeshFilter meshFilter = instantiated.GetComponentInChildren<MeshFilter>(); if (meshFilter == null) { Debug.LogError("Unable to find mesh"); GameObject.DestroyImmediate(instantiated); } else { mesh = meshFilter.sharedMesh; meshTransform = meshFilter.gameObject.transform; } } if (mesh) { coll.spriteDefinitions[i].positions = new Vector3[mesh.vertices.Length]; coll.spriteDefinitions[i].uvs = new Vector2[mesh.vertices.Length]; for (int j = 0; j < mesh.vertices.Length; ++j) { coll.spriteDefinitions[i].positions[j] = meshTransform.TransformPoint(mesh.vertices[j]); coll.spriteDefinitions[i].uvs[j] = new Vector2(v0.x + (v1.x - v0.x) * mesh.uv[j].x, v0.y + (v1.y - v0.y) * mesh.uv[j].y); } coll.spriteDefinitions[i].indices = new int[mesh.triangles.Length]; for (int j = 0; j < mesh.triangles.Length; ++j) { coll.spriteDefinitions[i].indices[j] = mesh.triangles[j]; } coll.spriteDefinitions[i].material = gen.atlasMaterials[atlasIndex]; GameObject.DestroyImmediate(instantiated); } else { Texture2D thisTextureRef = sourceTextures[i]; float texHeight = thisTextureRef?thisTextureRef.height:2; float texWidth = thisTextureRef?thisTextureRef.width:2; float h = thisTextureRef?thisTextureRef.height:64; float w = thisTextureRef?thisTextureRef.width:64; h *= thisTexParam.scale.y; w *= thisTexParam.scale.x; float scaleX = w * scale; float scaleY = h * scale; Vector3 pos0 = new Vector3(-0.5f * scaleX, 0, -0.5f * scaleY); switch (thisTexParam.anchor) { case tk2dSpriteCollectionDefinition.Anchor.LowerLeft: pos0 = new Vector3(0, 0, 0); break; case tk2dSpriteCollectionDefinition.Anchor.LowerCenter: pos0 = new Vector3(-0.5f * scaleX, 0, 0); break; case tk2dSpriteCollectionDefinition.Anchor.LowerRight: pos0 = new Vector3(-scaleX, 0, 0); break; case tk2dSpriteCollectionDefinition.Anchor.MiddleLeft: pos0 = new Vector3(0, 0, -0.5f * scaleY); break; case tk2dSpriteCollectionDefinition.Anchor.MiddleCenter: pos0 = new Vector3(-0.5f * scaleX, 0, -0.5f * scaleY); break; case tk2dSpriteCollectionDefinition.Anchor.MiddleRight: pos0 = new Vector3(-scaleX, 0, -0.5f * scaleY); break; case tk2dSpriteCollectionDefinition.Anchor.UpperLeft: pos0 = new Vector3(0, 0, -scaleY); break; case tk2dSpriteCollectionDefinition.Anchor.UpperCenter: pos0 = new Vector3(-0.5f * scaleX, 0, -scaleY); break; case tk2dSpriteCollectionDefinition.Anchor.UpperRight: pos0 = new Vector3(-scaleX, 0, -scaleY); break; case tk2dSpriteCollectionDefinition.Anchor.Custom: { pos0 = new Vector3(-thisTexParam.anchorX * thisTexParam.scale.x * scale, 0, -(h - thisTexParam.anchorY * thisTexParam.scale.y) * scale); } break; } colliderOrigin = new Vector3(pos0.x, pos0.z, 0.0f); Vector3 pos1 = pos0 + new Vector3(scaleX, 0, scaleY); List<Vector3> positions = new List<Vector3>(); List<Vector2> uvs = new List<Vector2>(); // build mesh if (_lut.isSplit) { coll.spriteDefinitions[i].flipped = false; // each split could be rotated, but not consistently for (int j = 0; j < spriteLuts.Count; ++j) { if (spriteLuts[j].source == i) { _lut = spriteLuts[j]; int thisAtlasIndex = 0; foreach (var p in packers) { if ((atlasEntry = p.FindEntryWithIndex(_lut.atlasIndex)) != null) { packer = p; break; } ++thisAtlasIndex; } if (thisAtlasIndex != atlasIndex) { // This is a serious problem, dicing is not supported when multi atlas output is selected Debug.Break(); } fwidth = packer.width; fheight = packer.height; tx = atlasEntry.x + padAmount; ty = atlasEntry.y + padAmount; tw = atlasEntry.w - padAmount * 2; th = atlasEntry.h - padAmount * 2; sd_y = packer.height - ty - th; v0 = new Vector2(tx / fwidth + uvOffsetX, 1.0f - (sd_y + th) / fheight + uvOffsetY); v1 = new Vector2((tx + tw) / fwidth - uvOffsetX, 1.0f - sd_y / fheight - uvOffsetY); float x0 = _lut.rx / texWidth; float y0 = _lut.ry / texHeight; float x1 = (_lut.rx + _lut.rw) / texWidth; float y1 = (_lut.ry + _lut.rh) / texHeight; Vector3 dpos0 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x0), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y0)); Vector3 dpos1 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x1), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y1)); positions.Add(new Vector3(dpos0.x, dpos0.z, 0)); positions.Add(new Vector3(dpos1.x, dpos0.z, 0)); positions.Add(new Vector3(dpos0.x, dpos1.z, 0)); positions.Add(new Vector3(dpos1.x, dpos1.z, 0)); if (atlasEntry.flipped) { uvs.Add(new Vector2(v0.x,v0.y)); uvs.Add(new Vector2(v0.x,v1.y)); uvs.Add(new Vector2(v1.x,v0.y)); uvs.Add(new Vector2(v1.x,v1.y)); } else { uvs.Add(new Vector2(v0.x,v0.y)); uvs.Add(new Vector2(v1.x,v0.y)); uvs.Add(new Vector2(v0.x,v1.y)); uvs.Add(new Vector2(v1.x,v1.y)); } } } } else { coll.spriteDefinitions[i].flipped = atlasEntry.flipped; float x0 = _lut.rx / texWidth; float y0 = _lut.ry / texHeight; float x1 = (_lut.rx + _lut.rw) / texWidth; float y1 = (_lut.ry + _lut.rh) / texHeight; Vector3 dpos0 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x0), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y0)); Vector3 dpos1 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x1), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y1)); positions.Add(new Vector3(dpos0.x, dpos0.z, 0)); positions.Add(new Vector3(dpos1.x, dpos0.z, 0)); positions.Add(new Vector3(dpos0.x, dpos1.z, 0)); positions.Add(new Vector3(dpos1.x, dpos1.z, 0)); if (atlasEntry.flipped) { uvs.Add(new Vector2(v0.x,v0.y)); uvs.Add(new Vector2(v0.x,v1.y)); uvs.Add(new Vector2(v1.x,v0.y)); uvs.Add(new Vector2(v1.x,v1.y)); } else { uvs.Add(new Vector2(v0.x,v0.y)); uvs.Add(new Vector2(v1.x,v0.y)); uvs.Add(new Vector2(v0.x,v1.y)); uvs.Add(new Vector2(v1.x,v1.y)); } } // build sprite definition coll.spriteDefinitions[i].indices = new int[ 6 * (positions.Count / 4) ]; for (int j = 0; j < positions.Count / 4; ++j) { coll.spriteDefinitions[i].indices[j * 6 + 0] = j * 4 + 0; coll.spriteDefinitions[i].indices[j * 6 + 1] = j * 4 + 3; coll.spriteDefinitions[i].indices[j * 6 + 2] = j * 4 + 1; coll.spriteDefinitions[i].indices[j * 6 + 3] = j * 4 + 2; coll.spriteDefinitions[i].indices[j * 6 + 4] = j * 4 + 3; coll.spriteDefinitions[i].indices[j * 6 + 5] = j * 4 + 0; } if (positions.Count > 0) { // http://forum.unity3d.com/threads/98781-Compute-mesh-inertia-tensor-failed-for-one-of-the-actor-Behaves-differently-in-3.4 Vector3 p = positions[positions.Count - 1]; p.z -= 0.001f; positions[positions.Count - 1] = p; } coll.spriteDefinitions[i].positions = new Vector3[positions.Count]; coll.spriteDefinitions[i].uvs = new Vector2[uvs.Count]; for (int j = 0; j < positions.Count; ++j) { coll.spriteDefinitions[i].positions[j] = positions[j]; coll.spriteDefinitions[i].uvs[j] = uvs[j]; } coll.spriteDefinitions[i].material = gen.atlasMaterials[atlasIndex]; } Vector3 boundsMin = new Vector3(1.0e32f, 1.0e32f, 1.0e32f); Vector3 boundsMax = new Vector3(-1.0e32f, -1.0e32f, -1.0e32f); foreach (Vector3 v in coll.spriteDefinitions[i].positions) { boundsMin = Vector3.Min(boundsMin, v); boundsMax = Vector3.Max(boundsMax, v); } coll.spriteDefinitions[i].boundsData = new Vector3[2]; coll.spriteDefinitions[i].boundsData[0] = (boundsMax + boundsMin) / 2.0f; coll.spriteDefinitions[i].boundsData[1] = (boundsMax - boundsMin); coll.spriteDefinitions[i].name = gen.textureParams[i].name; // Generate collider data here UpdateColliderData(gen, coll, i, colliderOrigin); } }
// Update target platforms public static void UpdatePlatformSpriteCollection(tk2dSpriteCollection source, tk2dSpriteCollection target, string dataPath, bool root, float scale, string platformName) { tk2dEditor.SpriteCollectionEditor.SpriteCollectionProxy proxy = new tk2dEditor.SpriteCollectionEditor.SpriteCollectionProxy(source); // Restore old sprite collection proxy.spriteCollection = target.spriteCollection; proxy.atlasTextures = target.atlasTextures; proxy.atlasMaterials = target.atlasMaterials; proxy.altMaterials = target.altMaterials; // This must always be zero, as children cannot have nested platforms. // That would open the door to a lot of unnecessary insanity proxy.platforms = new List<tk2dSpriteCollectionPlatform>(); // Update atlas sizes proxy.atlasWidth = (int)(proxy.atlasWidth * scale); proxy.atlasHeight = (int)(proxy.atlasHeight * scale); proxy.maxTextureSize = (int)(proxy.maxTextureSize * scale); proxy.forcedTextureWidth = (int)(proxy.forcedTextureWidth * scale); proxy.forcedTextureHeight = (int)(proxy.forcedTextureHeight * scale); if (!proxy.useTk2dCamera) proxy.targetOrthoSize *= 1.0f; proxy.globalScale = 1.0f / scale; // Don't bother changing stuff on the root object // The root object is the one that the sprite collection is defined on initially if (!root) { // Update textures foreach (tk2dSpriteCollectionDefinition param in proxy.textureParams) { if (param.texture == null) continue; string path = AssetDatabase.GetAssetPath(param.texture); string platformTexture = FindAssetForPlatform(platformName, path, textureExtensions); if (platformTexture.Length == 0) { LogNotFoundError(platformName, param.texture.name, "texture"); } else { Texture2D tex = AssetDatabase.LoadAssetAtPath(platformTexture, typeof(Texture2D)) as Texture2D; if (tex == null) { Debug.LogError("Unable to load platform specific texture '" + platformTexture + "'"); } else { param.texture = tex; } } // Handle spritesheets. Odd coordinates could cause issues if (param.extractRegion) { param.regionX = (int)(param.regionX * scale); param.regionY = (int)(param.regionY * scale); param.regionW = (int)(param.regionW * scale); param.regionH = (int)(param.regionH * scale); } if (param.anchor == tk2dSpriteCollectionDefinition.Anchor.Custom) { param.anchorX = (int)(param.anchorX * scale); param.anchorY = (int)(param.anchorY * scale); } if (param.customSpriteGeometry) { foreach (tk2dSpriteColliderIsland geom in param.geometryIslands) { for (int p = 0; p < geom.points.Length; ++p) geom.points[p] *= scale; } } if (param.colliderType == tk2dSpriteCollectionDefinition.ColliderType.Polygon) { foreach (tk2dSpriteColliderIsland geom in param.polyColliderIslands) { for (int p = 0; p < geom.points.Length; ++p) geom.points[p] *= scale; } } else if (param.colliderType == tk2dSpriteCollectionDefinition.ColliderType.BoxCustom) { param.boxColliderMax *= scale; param.boxColliderMin *= scale; } } } // We ALWAYS duplicate fonts if (target.fonts == null) target.fonts = new tk2dSpriteCollectionFont[0]; for (int i = 0; i < proxy.fonts.Count; ++i) { tk2dSpriteCollectionFont font = proxy.fonts[i]; if (!font.InUse || font.texture == null || font.data == null || font.editorData == null || font.bmFont == null) continue; // not valid for some reason or other bool needFontData = true; bool needFontEditorData = true; bool hasCorrespondingData = i < target.fonts.Length && target.fonts[i] != null; if (hasCorrespondingData) { tk2dSpriteCollectionFont targetFont = target.fonts[i]; if (targetFont.data != null) { font.data = targetFont.data; needFontData = false; } if (targetFont.editorData != null) { font.editorData = targetFont.editorData; needFontEditorData = false; } } string bmFontPath = AssetDatabase.GetAssetPath(font.bmFont); string texturePath = AssetDatabase.GetAssetPath(font.texture); if (!root) { // find platform specific versions bmFontPath = FindAssetForPlatform(platformName, bmFontPath, fontExtensions); texturePath = FindAssetForPlatform(platformName, texturePath, textureExtensions); if (bmFontPath.Length != 0 && texturePath.Length == 0) { // try to find a texture tk2dEditor.Font.Info fontInfo = tk2dEditor.Font.Builder.ParseBMFont(bmFontPath); if (fontInfo != null) texturePath = System.IO.Path.GetDirectoryName(bmFontPath).Replace('\\', '/') + "/" + System.IO.Path.GetFileName(fontInfo.texturePaths[0]); } if (bmFontPath.Length == 0) LogNotFoundError(platformName, font.bmFont.name, "font"); if (texturePath.Length == 0) LogNotFoundError(platformName, font.texture.name, "texture"); if (bmFontPath.Length == 0 || texturePath.Length == 0) continue; // not found // load the assets font.bmFont = AssetDatabase.LoadAssetAtPath(bmFontPath, typeof(UnityEngine.Object)); font.texture = AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D)) as Texture2D; } string targetDir = System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(target)); // create necessary assets if (needFontData) { string srcPath = AssetDatabase.GetAssetPath(font.data); string destPath = AssetDatabase.GenerateUniqueAssetPath(GetCopyAtTargetPath(platformName, targetDir, srcPath)); AssetDatabase.CopyAsset(srcPath, destPath); AssetDatabase.Refresh(); font.data = AssetDatabase.LoadAssetAtPath(destPath, typeof(tk2dFontData)) as tk2dFontData; } if (needFontEditorData) { string srcPath = AssetDatabase.GetAssetPath(font.editorData); string destPath = AssetDatabase.GenerateUniqueAssetPath(GetCopyAtTargetPath(platformName, targetDir, srcPath)); AssetDatabase.CopyAsset(srcPath, destPath); AssetDatabase.Refresh(); font.editorData = AssetDatabase.LoadAssetAtPath(destPath, typeof(tk2dFont)) as tk2dFont; } if (font.editorData.bmFont != font.bmFont || font.editorData.texture != font.texture || font.editorData.data != font.data) { font.editorData.bmFont = font.bmFont; font.editorData.texture = font.texture; font.editorData.data = font.data; EditorUtility.SetDirty(font.editorData); } } proxy.CopyToTarget(target); }
static int GetPadAmount(tk2dSpriteCollection gen) { return (gen.pixelPerfectPointSampled)?0:defaultPad; }
static void SetUpSourceTextureFormats(tk2dSpriteCollection gen) { // make sure all textures are in the right format int numTexturesReimported = 0; List<Texture2D> texturesToProcess = new List<Texture2D>(); for (int i = 0; i < gen.textureParams.Length; ++i) { if (gen.textureParams[i].texture != null) { texturesToProcess.Add(gen.textureParams[i].texture); } } if (gen.spriteSheets != null) { foreach (var v in gen.spriteSheets) { if (v.texture != null) texturesToProcess.Add(v.texture); } } if (gen.fonts != null) { foreach (var v in gen.fonts) { if (v.active && v.texture != null) texturesToProcess.Add(v.texture); } } foreach (var tex in texturesToProcess) { string thisTexturePath = AssetDatabase.GetAssetPath(tex); if (ConfigureSpriteTextureImporter(thisTexturePath)) { numTexturesReimported++; AssetDatabase.ImportAsset(thisTexturePath); } } if (numTexturesReimported > 0) { AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } }
void OnDisable() { ClearTextureCache(); _spriteCollection = null; }
static void UpdateFontData(tk2dSpriteCollection gen, float scale, tk2dEditor.Atlas.Data[] packers, List<SpriteLut> spriteLuts, tk2dSpriteCollectionFont font, tk2dEditor.Font.Info fontInfo) { Dictionary<int, SpriteLut> glyphLut = new Dictionary<int, SpriteLut>(); List<SpriteLut> values = new List<SpriteLut>(); foreach (var k in glyphLut.Keys) values.Add(glyphLut[k]); foreach (var v in spriteLuts) glyphLut[v.charId] = v; int padAmount = GetPadAmount(gen, -1); foreach (var c in fontInfo.chars) { if (glyphLut.ContainsKey(c.id)) { var glyphSprite = glyphLut[c.id]; var atlasEntry = packers[0].FindEntryWithIndex(glyphSprite.atlasIndex); c.texOffsetX = glyphSprite.rx; c.texOffsetY = glyphSprite.ry; c.texX = atlasEntry.x + padAmount; c.texY = atlasEntry.y + padAmount; c.texW = atlasEntry.w - padAmount * 2; c.texH = atlasEntry.h - padAmount * 2; c.texFlipped = atlasEntry.flipped; } else { var glyphSprite = glyphLut[-1]; var atlasEntry = packers[0].FindEntryWithIndex(glyphSprite.atlasIndex); c.texOffsetX = 0; c.texOffsetY = 0; c.texX = atlasEntry.x + 1; c.texY = atlasEntry.y + 1; c.texW = 0; c.texH = 0; c.texFlipped = false; } c.texOverride = true; } tk2dEditor.Font.Builder.BuildFont(fontInfo, font.data, scale, font.charPadX, font.dupeCaps, false, null, 0); }
static void SetUpSourceTextureFormats(tk2dSpriteCollection gen) { // make sure all textures are in the right format int numTexturesReimported = 0; List<Texture2D> texturesToProcess = new List<Texture2D>(); for (int i = 0; i < gen.textureParams.Length; ++i) { if (gen.textureRefs[i] != null) { texturesToProcess.Add(gen.textureRefs[i]); } } if (gen.spriteSheets != null) { for (int i = 0; i < gen.spriteSheets.Length; ++i) { if (gen.spriteSheets[i].texture != null) { texturesToProcess.Add(gen.spriteSheets[i].texture); } } } foreach (var tex in texturesToProcess) { // make sure the source texture is npot and readable, and uncompressed string thisTextPath = AssetDatabase.GetAssetPath(tex); TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(thisTextPath); if (importer.textureType != TextureImporterType.Advanced || importer.textureFormat != TextureImporterFormat.AutomaticTruecolor || importer.npotScale != TextureImporterNPOTScale.None || importer.isReadable != true || importer.maxTextureSize < 4096) { importer.textureFormat = TextureImporterFormat.AutomaticTruecolor; importer.textureType = TextureImporterType.Advanced; importer.npotScale = TextureImporterNPOTScale.None; importer.isReadable = true; importer.mipmapEnabled = false; importer.maxTextureSize = 4096; AssetDatabase.ImportAsset(thisTextPath); numTexturesReimported++; } } if (numTexturesReimported > 0) { AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } }
static void UpdateVertexCache(tk2dSpriteCollection gen, float scale, tk2dEditor.Atlas.Data[] packers, tk2dSpriteCollectionData coll, List<SpriteLut> spriteLuts) { for (int i = 0; i < sourceTextures.Length; ++i) { SpriteLut _lut = null; for (int j = 0; j < spriteLuts.Count; ++j) { if (spriteLuts[j].source == i) { _lut = spriteLuts[j]; break; } } int padAmount = GetPadAmount(gen, i); tk2dSpriteCollectionDefinition thisTexParam = gen.textureParams[i]; tk2dEditor.Atlas.Data packer = null; tk2dEditor.Atlas.Entry atlasEntry = null; int atlasIndex = 0; foreach (var p in packers) { if ((atlasEntry = p.FindEntryWithIndex(_lut.atlasIndex)) != null) { packer = p; break; } ++atlasIndex; } float fwidth = packer.width; float fheight = packer.height; int tx = atlasEntry.x + padAmount, ty = atlasEntry.y + padAmount, tw = atlasEntry.w - padAmount * 2, th = atlasEntry.h - padAmount * 2; int sd_y = packer.height - ty - th; float uvOffsetX = 0.001f / fwidth; float uvOffsetY = 0.001f / fheight; Vector2 v0 = new Vector2(tx / fwidth + uvOffsetX, 1.0f - (sd_y + th) / fheight + uvOffsetY); Vector2 v1 = new Vector2((tx + tw) / fwidth - uvOffsetX, 1.0f - sd_y / fheight - uvOffsetY); Mesh mesh = null; Transform meshTransform = null; GameObject instantiated = null; Vector3 colliderOrigin = new Vector3(); if (thisTexParam.overrideMesh) { // Disabled instantiated = GameObject.Instantiate(thisTexParam.overrideMesh) as GameObject; MeshFilter meshFilter = instantiated.GetComponentInChildren<MeshFilter>(); if (meshFilter == null) { Debug.LogError("Unable to find mesh"); GameObject.DestroyImmediate(instantiated); } else { mesh = meshFilter.sharedMesh; meshTransform = meshFilter.gameObject.transform; } } Vector3 untrimmedPos0 = Vector3.zero, untrimmedPos1 = Vector3.one; if (mesh) { coll.spriteDefinitions[i].positions = new Vector3[mesh.vertices.Length]; coll.spriteDefinitions[i].uvs = new Vector2[mesh.vertices.Length]; for (int j = 0; j < mesh.vertices.Length; ++j) { coll.spriteDefinitions[i].positions[j] = meshTransform.TransformPoint(mesh.vertices[j]); coll.spriteDefinitions[i].uvs[j] = new Vector2(v0.x + (v1.x - v0.x) * mesh.uv[j].x, v0.y + (v1.y - v0.y) * mesh.uv[j].y); } coll.spriteDefinitions[i].indices = new int[mesh.triangles.Length]; for (int j = 0; j < mesh.triangles.Length; ++j) { coll.spriteDefinitions[i].indices[j] = mesh.triangles[j]; } GameObject.DestroyImmediate(instantiated); } else { Texture2D thisTextureRef = sourceTextures[i]; int texHeightI = thisTextureRef?thisTextureRef.height:2; int texWidthI = thisTextureRef?thisTextureRef.width:2; float texHeight = texHeightI; float texWidth = texWidthI; float h = thisTextureRef?thisTextureRef.height:64; float w = thisTextureRef?thisTextureRef.width:64; h *= thisTexParam.scale.y; w *= thisTexParam.scale.x; float scaleX = w * scale; float scaleY = h * scale; // anchor coordinate system is (0, 0) = top left, to keep it the same as photoshop, etc. switch (thisTexParam.anchor) { case tk2dSpriteCollectionDefinition.Anchor.LowerLeft: thisTexParam.anchorX = 0; thisTexParam.anchorY = texHeightI; break; case tk2dSpriteCollectionDefinition.Anchor.LowerCenter: thisTexParam.anchorX = texWidthI / 2; thisTexParam.anchorY = texHeightI; break; case tk2dSpriteCollectionDefinition.Anchor.LowerRight: thisTexParam.anchorX = texWidthI; thisTexParam.anchorY = texHeightI; break; case tk2dSpriteCollectionDefinition.Anchor.MiddleLeft: thisTexParam.anchorX = 0; thisTexParam.anchorY = texHeightI / 2; break; case tk2dSpriteCollectionDefinition.Anchor.MiddleCenter: thisTexParam.anchorX = texWidthI / 2; thisTexParam.anchorY = texHeightI / 2; break; case tk2dSpriteCollectionDefinition.Anchor.MiddleRight: thisTexParam.anchorX = texWidthI; thisTexParam.anchorY = texHeightI / 2; break; case tk2dSpriteCollectionDefinition.Anchor.UpperLeft: thisTexParam.anchorX = 0; thisTexParam.anchorY = 0; break; case tk2dSpriteCollectionDefinition.Anchor.UpperCenter: thisTexParam.anchorX = texWidthI / 2; thisTexParam.anchorY = 0; break; case tk2dSpriteCollectionDefinition.Anchor.UpperRight: thisTexParam.anchorX = texWidthI; thisTexParam.anchorY = 0; break; } Vector3 pos0 = new Vector3(-thisTexParam.anchorX * thisTexParam.scale.x * scale, 0, -(h - thisTexParam.anchorY * thisTexParam.scale.y) * scale); colliderOrigin = new Vector3(pos0.x, pos0.z, 0.0f); Vector3 pos1 = pos0 + new Vector3(scaleX, 0, scaleY); untrimmedPos0 = new Vector3(pos0.x, pos0.z); untrimmedPos1 = new Vector3(pos1.x, pos1.z); List<Vector3> positions = new List<Vector3>(); List<Vector2> uvs = new List<Vector2>(); // build mesh if (_lut.isSplit) { coll.spriteDefinitions[i].flipped = false; // each split could be rotated, but not consistently for (int j = 0; j < spriteLuts.Count; ++j) { if (spriteLuts[j].source == i) { _lut = spriteLuts[j]; int thisAtlasIndex = 0; foreach (var p in packers) { if ((atlasEntry = p.FindEntryWithIndex(_lut.atlasIndex)) != null) { packer = p; break; } ++thisAtlasIndex; } if (thisAtlasIndex != atlasIndex) { // This is a serious problem, dicing is not supported when multi atlas output is selected Debug.Break(); } fwidth = packer.width; fheight = packer.height; tx = atlasEntry.x + padAmount; ty = atlasEntry.y + padAmount; tw = atlasEntry.w - padAmount * 2; th = atlasEntry.h - padAmount * 2; sd_y = packer.height - ty - th; v0 = new Vector2(tx / fwidth + uvOffsetX, 1.0f - (sd_y + th) / fheight + uvOffsetY); v1 = new Vector2((tx + tw) / fwidth - uvOffsetX, 1.0f - sd_y / fheight - uvOffsetY); float x0 = _lut.rx / texWidth; float y0 = _lut.ry / texHeight; float x1 = (_lut.rx + _lut.rw) / texWidth; float y1 = (_lut.ry + _lut.rh) / texHeight; Vector3 dpos0 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x0), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y0)); Vector3 dpos1 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x1), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y1)); positions.Add(new Vector3(dpos0.x, dpos0.z, 0)); positions.Add(new Vector3(dpos1.x, dpos0.z, 0)); positions.Add(new Vector3(dpos0.x, dpos1.z, 0)); positions.Add(new Vector3(dpos1.x, dpos1.z, 0)); if (atlasEntry.flipped) { uvs.Add(new Vector2(v0.x,v0.y)); uvs.Add(new Vector2(v0.x,v1.y)); uvs.Add(new Vector2(v1.x,v0.y)); uvs.Add(new Vector2(v1.x,v1.y)); } else { uvs.Add(new Vector2(v0.x,v0.y)); uvs.Add(new Vector2(v1.x,v0.y)); uvs.Add(new Vector2(v0.x,v1.y)); uvs.Add(new Vector2(v1.x,v1.y)); } } } } else if (thisTexParam.customSpriteGeometry) { coll.spriteDefinitions[i].flipped = atlasEntry.flipped; List<int> indices = new List<int>(); foreach (var island in thisTexParam.geometryIslands) { int baseIndex = positions.Count; for (int x = 0; x < island.points.Length; ++x) { var v = island.points[x]; Vector2 origin = new Vector2(pos0.x, pos0.z); positions.Add(new Vector2(v.x * thisTexParam.scale.x, (texHeight - v.y) * thisTexParam.scale.y) * scale + new Vector2(origin.x, origin.y)); tx = atlasEntry.x + padAmount; ty = atlasEntry.y + padAmount; tw = atlasEntry.w - padAmount * 2; th = atlasEntry.h - padAmount * 2; //v0 = new Vector2(tx / fwidth + uvOffsetX, 1.0f - (sd_y + th) / fheight + uvOffsetY); //v1 = new Vector2((tx + tw) / fwidth - uvOffsetX, 1.0f - sd_y / fheight - uvOffsetY); Vector2 uv = new Vector2(); if (atlasEntry.flipped) { uv.x = (tx - _lut.ry + texHeight - v.y) / fwidth + uvOffsetX; uv.y = (ty - _lut.rx + v.x) / fheight + uvOffsetY; } else { uv.x = (tx - _lut.rx + v.x) / fwidth + uvOffsetX; uv.y = (ty - _lut.ry + texHeight - v.y) / fheight + uvOffsetY ; } uvs.Add(uv); } tk2dEditor.Triangulator triangulator = new tk2dEditor.Triangulator(island.points); int[] localIndices = triangulator.Triangulate(); //for (int x = localIndices.Length - 1; x >= 0; --x) for (int x = 0; x < localIndices.Length; x += 3) { indices.Add(baseIndex + localIndices[x + 2]); indices.Add(baseIndex + localIndices[x + 1]); indices.Add(baseIndex + localIndices[x + 0]); } } coll.spriteDefinitions[i].indices = indices.ToArray(); } else { coll.spriteDefinitions[i].flipped = atlasEntry.flipped; float x0 = _lut.rx / texWidth; float y0 = _lut.ry / texHeight; float x1 = (_lut.rx + _lut.rw) / texWidth; float y1 = (_lut.ry + _lut.rh) / texHeight; Vector3 dpos0 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x0), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y0)); Vector3 dpos1 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x1), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y1)); positions.Add(new Vector3(dpos0.x, dpos0.z, 0)); positions.Add(new Vector3(dpos1.x, dpos0.z, 0)); positions.Add(new Vector3(dpos0.x, dpos1.z, 0)); positions.Add(new Vector3(dpos1.x, dpos1.z, 0)); if (atlasEntry.flipped) { uvs.Add(new Vector2(v0.x,v0.y)); uvs.Add(new Vector2(v0.x,v1.y)); uvs.Add(new Vector2(v1.x,v0.y)); uvs.Add(new Vector2(v1.x,v1.y)); } else { uvs.Add(new Vector2(v0.x,v0.y)); uvs.Add(new Vector2(v1.x,v0.y)); uvs.Add(new Vector2(v0.x,v1.y)); uvs.Add(new Vector2(v1.x,v1.y)); } } // build sprite definition if (!thisTexParam.customSpriteGeometry) { coll.spriteDefinitions[i].indices = new int[ 6 * (positions.Count / 4) ]; for (int j = 0; j < positions.Count / 4; ++j) { coll.spriteDefinitions[i].indices[j * 6 + 0] = j * 4 + 0; coll.spriteDefinitions[i].indices[j * 6 + 1] = j * 4 + 3; coll.spriteDefinitions[i].indices[j * 6 + 2] = j * 4 + 1; coll.spriteDefinitions[i].indices[j * 6 + 3] = j * 4 + 2; coll.spriteDefinitions[i].indices[j * 6 + 4] = j * 4 + 3; coll.spriteDefinitions[i].indices[j * 6 + 5] = j * 4 + 0; } coll.spriteDefinitions[i].complexGeometry = false; } else { coll.spriteDefinitions[i].complexGeometry = true; } // This doesn't seem to be necessary in UNITY_3_5_3 #if (UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5_0 || UNITY_3_5_1 || UNITY_3_5_2) if (positions.Count > 0) { // http://forum.unity3d.com/threads/98781-Compute-mesh-inertia-tensor-failed-for-one-of-the-actor-Behaves-differently-in-3.4 Vector3 p = positions[positions.Count - 1]; p.z -= 0.001f; positions[positions.Count - 1] = p; } #endif coll.spriteDefinitions[i].positions = new Vector3[positions.Count]; coll.spriteDefinitions[i].uvs = new Vector2[uvs.Count]; for (int j = 0; j < positions.Count; ++j) { coll.spriteDefinitions[i].positions[j] = positions[j]; coll.spriteDefinitions[i].uvs[j] = uvs[j]; } // empty out to a sensible default, which corresponds to what Unity does by default coll.spriteDefinitions[i].normals = new Vector3[0]; coll.spriteDefinitions[i].tangents = new Vector4[0]; // fill out tangents and normals if (gen.normalGenerationMode != tk2dSpriteCollection.NormalGenerationMode.None) { Mesh tmpMesh = new Mesh(); tmpMesh.vertices = coll.spriteDefinitions[i].positions; tmpMesh.uv = coll.spriteDefinitions[i].uvs; tmpMesh.triangles = coll.spriteDefinitions[i].indices; tmpMesh.RecalculateNormals(); coll.spriteDefinitions[i].normals = tmpMesh.normals; if (gen.normalGenerationMode != tk2dSpriteCollection.NormalGenerationMode.NormalsOnly) { coll.spriteDefinitions[i].tangents = tmpMesh.tangents; } } } // fixup in case something went wrong if (coll.allowMultipleAtlases) { coll.spriteDefinitions[i].material = gen.atlasMaterials[atlasIndex]; } else { coll.spriteDefinitions[i].material = gen.altMaterials[thisTexParam.materialId]; coll.spriteDefinitions[i].materialId = thisTexParam.materialId; if (coll.spriteDefinitions[i].material == null) // fall back gracefully in case something went wrong { coll.spriteDefinitions[i].material = gen.atlasMaterials[atlasIndex]; coll.spriteDefinitions[i].materialId = 0; } } Vector3 boundsMin = new Vector3(1.0e32f, 1.0e32f, 1.0e32f); Vector3 boundsMax = new Vector3(-1.0e32f, -1.0e32f, -1.0e32f); foreach (Vector3 v in coll.spriteDefinitions[i].positions) { boundsMin = Vector3.Min(boundsMin, v); boundsMax = Vector3.Max(boundsMax, v); } coll.spriteDefinitions[i].boundsData = new Vector3[2]; coll.spriteDefinitions[i].boundsData[0] = (boundsMax + boundsMin) / 2.0f; coll.spriteDefinitions[i].boundsData[1] = (boundsMax - boundsMin); // this is the dimension of exactly one pixel, scaled to match sprite dimensions and scale coll.spriteDefinitions[i].texelSize = new Vector3(scale * thisTexParam.scale.x, scale * thisTexParam.scale.y, 0.0f); coll.spriteDefinitions[i].untrimmedBoundsData = new Vector3[2]; if (mesh) { // custom meshes aren't trimmed, the untrimmed bounds are exactly the same as the regular ones coll.spriteDefinitions[i].untrimmedBoundsData[0] = coll.spriteDefinitions[i].boundsData[0]; coll.spriteDefinitions[i].untrimmedBoundsData[1] = coll.spriteDefinitions[i].boundsData[1]; } else { boundsMin = Vector3.Min(untrimmedPos0, untrimmedPos1); boundsMax = Vector3.Max(untrimmedPos0, untrimmedPos1); coll.spriteDefinitions[i].untrimmedBoundsData[0] = (boundsMax + boundsMin) / 2.0f; coll.spriteDefinitions[i].untrimmedBoundsData[1] = (boundsMax - boundsMin); } coll.spriteDefinitions[i].name = gen.textureParams[i].name; // Generate collider data here UpdateColliderData(gen, scale, coll, i, colliderOrigin); } }
static void UpdateFontData(tk2dSpriteCollection gen, float scale, tk2dEditor.Atlas.Data[] packers, List<SpriteLut> spriteLuts, tk2dSpriteCollectionFont font, tk2dEditor.Font.Info fontInfo) { Dictionary<int, SpriteLut> glyphLut = new Dictionary<int, SpriteLut>(); List<SpriteLut> values = new List<SpriteLut>(); foreach (var k in glyphLut.Keys) values.Add(glyphLut[k]); foreach (var v in spriteLuts) glyphLut[v.charId] = v; int padAmount = GetPadAmount(gen, -1); foreach (var c in fontInfo.chars) { if (glyphLut.ContainsKey(c.id)) { var glyphSprite = glyphLut[c.id]; var atlasEntry = packers[0].FindEntryWithIndex(glyphSprite.atlasIndex); c.texOffsetX = glyphSprite.rx; if (font.flipTextureY) { // This is the offset from the bottom of the font c.texOffsetY = glyphSprite.ry; } else { // ry is offset from top, we want offset from bottom // height is the original glyph height before cropping, the remainder of which is // the offset from bottom c.texOffsetY = c.height - glyphSprite.rh - glyphSprite.ry; } c.texX = atlasEntry.x + padAmount; c.texY = atlasEntry.y + padAmount; c.texW = atlasEntry.w - padAmount * 2; c.texH = atlasEntry.h - padAmount * 2; c.texFlipped = atlasEntry.flipped; } else { var glyphSprite = glyphLut[-1]; var atlasEntry = packers[0].FindEntryWithIndex(glyphSprite.atlasIndex); c.texOffsetX = 0; c.texOffsetY = 0; c.texX = atlasEntry.x + 1; c.texY = atlasEntry.y + 1; c.texW = 0; c.texH = 0; c.texFlipped = false; } c.texOverride = true; } tk2dEditor.Font.Builder.BuildFont(fontInfo, font.data, scale, font.charPadX, font.dupeCaps, font.flipTextureY, font.gradientTexture, font.gradientCount); }
static void UpdateColliderData(tk2dSpriteCollection gen, float scale, tk2dSpriteCollectionData coll, int spriteIndex, Vector3 origin) { var colliderType = gen.textureParams[spriteIndex].colliderType; var def = coll.spriteDefinitions[spriteIndex]; var src = gen.textureParams[spriteIndex]; def.colliderVertices = null; def.colliderIndicesFwd = null; def.colliderIndicesBack = null; float texHeight = 0; if (src.extractRegion) { texHeight = src.regionH; } else { texHeight = gen.textureParams[spriteIndex].texture?gen.textureParams[spriteIndex].texture.height:2.0f; } if (colliderType == tk2dSpriteCollectionDefinition.ColliderType.BoxTrimmed) { def.colliderVertices = new Vector3[2]; def.colliderVertices[0] = def.boundsData[0]; def.colliderVertices[1] = def.boundsData[1] * 0.5f; // extents is 1/2x size def.colliderVertices[1].z = gen.physicsDepth; def.colliderType = tk2dSpriteDefinition.ColliderType.Box; } else if (colliderType == tk2dSpriteCollectionDefinition.ColliderType.BoxCustom) { Vector2 v0 = new Vector3(src.boxColliderMin.x * src.scale.x, (texHeight - src.boxColliderMax.y) * src.scale.y) * scale + origin; Vector2 v1 = new Vector3(src.boxColliderMax.x * src.scale.x, (texHeight - src.boxColliderMin.y) * src.scale.y) * scale + origin; def.colliderVertices = new Vector3[2]; def.colliderVertices[0] = (v0 + v1) * 0.5f; def.colliderVertices[1] = (v1 - v0) * 0.5f; def.colliderVertices[1].z = gen.physicsDepth; def.colliderType = tk2dSpriteDefinition.ColliderType.Box; } else if (colliderType == tk2dSpriteCollectionDefinition.ColliderType.Polygon) { List<Vector3> meshVertices = new List<Vector3>(); List<int> meshIndicesFwd = new List<int>(); foreach (var island in src.polyColliderIslands) { List<Vector2> points = new List<Vector2>(); List<Vector2> points2D = new List<Vector2>(); // List all points for (int i = 0; i < island.points.Length; ++i) { Vector2 v = island.points[i]; points.Add(new Vector2(v.x * src.scale.x, (texHeight - v.y) * src.scale.y) * scale + new Vector2(origin.x, origin.y)); } int baseIndex = meshVertices.Count; for (int i = 0; i < points.Count; ++i) { meshVertices.Add( new Vector3(points[i].x, points[i].y, -gen.physicsDepth) ); meshVertices.Add( new Vector3(points[i].x, points[i].y, gen.physicsDepth) ); points2D.Add( new Vector2(points[i].x, points[i].y) ); } // body int numPoints = island.connected?points.Count:(points.Count - 1); for (int i = 0; i < numPoints; ++i) { int i0 = i * 2; int i1 = i0 + 1; int i2 = ((i + 1)%island.points.Length) * 2; int i3 = i2 + 1; // Classify primary edge direction, and flip accordingly bool flipIndices = false; Vector2 grad = points2D[i] - points2D[(i + 1) % points2D.Count]; if (Mathf.Abs(grad.x) < Mathf.Abs(grad.y)) { flipIndices = (grad.y > 0.0f); } else { flipIndices = (grad.x > 0.0f); } if (flipIndices) { meshIndicesFwd.Add(baseIndex + i2); meshIndicesFwd.Add(baseIndex + i3); meshIndicesFwd.Add(baseIndex + i0); meshIndicesFwd.Add(baseIndex + i0); meshIndicesFwd.Add(baseIndex + i3); meshIndicesFwd.Add(baseIndex + i1); } else { meshIndicesFwd.Add(baseIndex + i2); meshIndicesFwd.Add(baseIndex + i1); meshIndicesFwd.Add(baseIndex + i0); meshIndicesFwd.Add(baseIndex + i2); meshIndicesFwd.Add(baseIndex + i3); meshIndicesFwd.Add(baseIndex + i1); } } // cap if allowed and necessary var cap = src.polyColliderCap; if (island.connected && cap != tk2dSpriteCollectionDefinition.PolygonColliderCap.None) { tk2dEditor.Triangulator triangulator = new tk2dEditor.Triangulator(points2D.ToArray()); int[] indices = triangulator.Triangulate(); if (cap == tk2dSpriteCollectionDefinition.PolygonColliderCap.Front || cap == tk2dSpriteCollectionDefinition.PolygonColliderCap.FrontAndBack) { for (int i = 0; i < indices.Length; ++i) meshIndicesFwd.Add(baseIndex + indices[i] * 2); } if (cap == tk2dSpriteCollectionDefinition.PolygonColliderCap.Back || cap == tk2dSpriteCollectionDefinition.PolygonColliderCap.FrontAndBack) { for (int i = 0; i < indices.Length; i += 3) { meshIndicesFwd.Add(baseIndex + indices[i + 2] * 2 + 1); meshIndicesFwd.Add(baseIndex + indices[i + 1] * 2 + 1); meshIndicesFwd.Add(baseIndex + indices[i + 0] * 2 + 1); } } } } int[] meshIndicesBack = new int[meshIndicesFwd.Count]; for (int i = 0; i < meshIndicesFwd.Count; i += 3) { meshIndicesBack[i + 0] = meshIndicesFwd[i + 2]; meshIndicesBack[i + 1] = meshIndicesFwd[i + 1]; meshIndicesBack[i + 2] = meshIndicesFwd[i + 0]; } def.colliderVertices = meshVertices.ToArray(); def.colliderIndicesFwd = meshIndicesFwd.ToArray(); def.colliderIndicesBack = meshIndicesBack; def.colliderConvex = src.colliderConvex; def.colliderType = tk2dSpriteDefinition.ColliderType.Mesh; def.colliderSmoothSphereCollisions = src.colliderSmoothSphereCollisions; } else if (colliderType == tk2dSpriteCollectionDefinition.ColliderType.ForceNone) { def.colliderType = tk2dSpriteDefinition.ColliderType.None; } else if (colliderType == tk2dSpriteCollectionDefinition.ColliderType.UserDefined) { def.colliderType = tk2dSpriteDefinition.ColliderType.Unset; } }
static void SetUpTargetTexture(tk2dSpriteCollection gen, Texture2D tex) { bool textureDirty = false; string targetTexPath = AssetDatabase.GetAssetPath(tex); TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(targetTexPath); if (gen.maxTextureSize != importer.maxTextureSize) { importer.maxTextureSize = gen.maxTextureSize; textureDirty = true; } TextureImporterFormat targetFormat; switch (gen.textureCompression) { case tk2dSpriteCollection.TextureCompression.Uncompressed: targetFormat = TextureImporterFormat.AutomaticTruecolor; break; case tk2dSpriteCollection.TextureCompression.Reduced16Bit: targetFormat = TextureImporterFormat.Automatic16bit; break; case tk2dSpriteCollection.TextureCompression.Dithered16Bit_Alpha: targetFormat = TextureImporterFormat.Automatic16bit; break; case tk2dSpriteCollection.TextureCompression.Dithered16Bit_NoAlpha: targetFormat = TextureImporterFormat.Automatic16bit; break; case tk2dSpriteCollection.TextureCompression.Compressed: targetFormat = TextureImporterFormat.AutomaticCompressed; break; default: targetFormat = TextureImporterFormat.AutomaticTruecolor; break; } if (targetFormat != importer.textureFormat) { importer.textureFormat = targetFormat; textureDirty = true; } if (importer.filterMode != gen.filterMode) { importer.filterMode = gen.filterMode; textureDirty = true; } if (!gen.userDefinedTextureSettings) { if (importer.wrapMode != gen.wrapMode) { importer.wrapMode = gen.wrapMode; textureDirty = true; } if (importer.mipmapEnabled != gen.mipmapEnabled) { importer.mipmapEnabled = gen.mipmapEnabled; textureDirty = true; } if (importer.anisoLevel != gen.anisoLevel) { importer.anisoLevel = gen.anisoLevel; textureDirty = true; } } if (textureDirty) { EditorUtility.SetDirty(importer); AssetDatabase.ImportAsset(targetTexPath); } }
public static bool Rebuild(tk2dSpriteCollection gen) { // avoid "recursive" build being triggered by texture watcher if (currentBuild != null) return false; currentBuild = gen; List<Texture2D> allocatedTextures = new List<Texture2D>(); string path = AssetDatabase.GetAssetPath(gen); string subDirName = Path.GetDirectoryName( path.Substring(7) ); if (subDirName.Length > 0) subDirName += "/"; string dataDirFullPath = Application.dataPath + "/" + subDirName + Path.GetFileNameWithoutExtension(path) + "_Data"; string dataDirName = "Assets/" + dataDirFullPath.Substring( Application.dataPath.Length + 1 ) + "/"; if (gen.atlasTextures == null || gen.atlasTextures.Length == 0 || gen.atlasMaterials == null || gen.atlasMaterials.Length == 0 || gen.spriteCollection == null) { if (!Directory.Exists(dataDirFullPath)) Directory.CreateDirectory(dataDirFullPath); AssetDatabase.Refresh(); } string prefabObjectPath = gen.spriteCollection?AssetDatabase.GetAssetPath(gen.spriteCollection):(dataDirName + "data.prefab"); if (!CheckAndFixUpParams(gen)) { // Params failed check return false; } SetUpSourceTextureFormats(gen); SetUpSpriteSheets(gen); TrimTextureList(gen); // blank texture used when texture has been deleted Texture2D blankTexture = new Texture2D(2, 2); blankTexture.SetPixel(0, 0, Color.magenta); blankTexture.SetPixel(0, 1, Color.yellow); blankTexture.SetPixel(1, 0, Color.cyan); blankTexture.SetPixel(1, 1, Color.grey); blankTexture.Apply(); // make local texture sources sourceTextures = new Texture2D[gen.textureRefs.Length]; for (int i = 0; i < gen.textureParams.Length; ++i) { var param = gen.textureParams[i]; if (param.extractRegion && gen.textureRefs[i] != null) { Texture2D localTex = new Texture2D(param.regionW, param.regionH); for (int y = 0; y < param.regionH; ++y) { for (int x = 0; x < param.regionW; ++x) { localTex.SetPixel(x, y, gen.textureRefs[i].GetPixel(param.regionX + x, param.regionY + y)); } } localTex.name = gen.textureRefs[i].name + "/" + param.regionId.ToString(); localTex.Apply(); allocatedTextures.Add(localTex); sourceTextures[i] = localTex; } else { sourceTextures[i] = gen.textureRefs[i]; } } // catalog all textures to atlas int numTexturesToAtlas = 0; List<SpriteLut> spriteLuts = new List<SpriteLut>(); for (int i = 0; i < gen.textureParams.Length; ++i) { Texture2D currentTexture = sourceTextures[i]; if (sourceTextures[i] == null) { gen.textureParams[i].dice = false; gen.textureParams[i].anchor = tk2dSpriteCollectionDefinition.Anchor.MiddleCenter; gen.textureParams[i].name = ""; gen.textureParams[i].extractRegion = false; gen.textureParams[i].fromSpriteSheet = false; currentTexture = blankTexture; } else { if (gen.textureParams[i].name == null || gen.textureParams[i].name == "") { if (gen.textureParams[i].texture != currentTexture && !gen.textureParams[i].fromSpriteSheet) { gen.textureParams[i].name = currentTexture.name; } } } gen.textureParams[i].texture = currentTexture; if (gen.textureParams[i].dice) { // prepare to dice this up int diceUnitX = gen.textureParams[i].diceUnitX; int diceUnitY = gen.textureParams[i].diceUnitY; if (diceUnitX <= 0) diceUnitX = 128; // something sensible, please if (diceUnitY <= 0) diceUnitY = diceUnitX; // make square if not set Texture2D srcTex = currentTexture; for (int sx = 0; sx < srcTex.width; sx += diceUnitX) { for (int sy = 0; sy < srcTex.height; sy += diceUnitY) { int tw = Mathf.Min(diceUnitX, srcTex.width - sx); int th = Mathf.Min(diceUnitY, srcTex.height - sy); SpriteLut diceLut = new SpriteLut(); diceLut.source = i; diceLut.isSplit = true; diceLut.sourceTex = srcTex; diceLut.isDuplicate = false; // duplicate diced textures can be chopped up differently, so don't detect dupes here Texture2D dest = ProcessTexture(gen, gen.textureParams[i].additive, true, srcTex, sx, sy, tw, th, ref diceLut, GetPadAmount(gen, i)); if (dest) { diceLut.atlasIndex = numTexturesToAtlas++; spriteLuts.Add(diceLut); } } } } else { SpriteLut lut = new SpriteLut(); lut.sourceTex = currentTexture; lut.source = i; lut.isSplit = false; lut.isDuplicate = false; for (int j = 0; j < spriteLuts.Count; ++j) { if (spriteLuts[j].sourceTex == lut.sourceTex) { lut.isDuplicate = true; lut.atlasIndex = spriteLuts[j].atlasIndex; lut.tex = spriteLuts[j].tex; // get old processed tex lut.rx = spriteLuts[j].rx; lut.ry = spriteLuts[j].ry; lut.rw = spriteLuts[j].rw; lut.rh = spriteLuts[j].rh; break; } } if (!lut.isDuplicate) { lut.atlasIndex = numTexturesToAtlas++; bool stretchPad = false; if (gen.textureParams[i].pad == tk2dSpriteCollectionDefinition.Pad.Extend) stretchPad = true; Texture2D dest = ProcessTexture(gen, gen.textureParams[i].additive, stretchPad, currentTexture, 0, 0, currentTexture.width, currentTexture.height, ref lut, GetPadAmount(gen, i)); if (dest == null) { // fall back to a tiny blank texture lut.tex = new Texture2D(1, 1); lut.tex.SetPixel(0, 0, new Color( 0, 0, 0, 0 )); PadTexture(lut.tex, GetPadAmount(gen, i), stretchPad); lut.tex.Apply(); lut.rx = currentTexture.width / 2; lut.ry = currentTexture.height / 2; lut.rw = 1; lut.rh = 1; } } spriteLuts.Add(lut); } } // Font Dictionary<tk2dSpriteCollectionFont, tk2dEditor.Font.Info> fontInfoDict = new Dictionary<tk2dSpriteCollectionFont, tk2dEditor.Font.Info>(); if (gen.fonts != null) { for (int i = 0; i < gen.fonts.Length; ++i) { var font = gen.fonts[i]; if (!font.InUse) continue; var fontInfo = tk2dEditor.Font.Builder.ParseBMFont( AssetDatabase.GetAssetPath(font.bmFont) ); fontInfoDict[font] = fontInfo; foreach (var c in fontInfo.chars) { // skip empty textures if (c.width <= 0 || c.height <= 0) continue; SpriteLut lut = new SpriteLut(); int cy = font.flipTextureY?c.y:(fontInfo.scaleH - c.y - c.height); Texture2D dest = ProcessTexture(gen, false, false, font.texture, c.x, cy, c.width, c.height, ref lut, GetPadAmount(gen, -1)); if (dest == null) { // probably fully transparent continue; } lut.sourceTex = dest; lut.tex = dest; lut.source = -1; lut.isFont = true; lut.isDuplicate = false; lut.fontId = i; lut.charId = c.id; lut.rx = lut.rx - c.x; lut.ry = lut.ry - cy; lut.atlasIndex = numTexturesToAtlas++; spriteLuts.Add(lut); } // Add one blank char for fallbacks { int dims = 5; SpriteLut lut = new SpriteLut(); lut.tex = new Texture2D(dims, dims); for (int y = 0; y < dims; ++y) for (int x = 0; x < dims; ++x) lut.tex.SetPixel(x, y, Color.clear); lut.tex.Apply(); lut.sourceTex = lut.tex; lut.isFont = true; lut.isDuplicate = false; lut.fontId = i; lut.charId = -1; lut.atlasIndex = numTexturesToAtlas++; spriteLuts.Add(lut); } } } // Create texture Texture2D[] textureList = new Texture2D[numTexturesToAtlas]; int titer = 0; for (int i = 0; i < spriteLuts.Count; ++i) { SpriteLut _lut = spriteLuts[i]; if (!_lut.isDuplicate) { textureList[titer++] = _lut.tex; } } // Build atlas tk2dEditor.Atlas.Builder atlasBuilder = new tk2dEditor.Atlas.Builder(gen.maxTextureSize, gen.maxTextureSize, gen.allowMultipleAtlases?64:1, gen.forceSquareAtlas); if (textureList.Length > 0) { foreach (Texture2D currTexture in textureList) { atlasBuilder.AddRect(currTexture.width, currTexture.height); } if (atlasBuilder.Build() != 0) { if (atlasBuilder.HasOversizeTextures()) { EditorUtility.DisplayDialog("Unable to fit in atlas", "You have a texture which exceeds the atlas size." + "Consider putting it in a separate atlas, enabling dicing, or" + "reducing the texture size", "Ok"); } else { EditorUtility.DisplayDialog("Unable to fit textures in requested atlas area", "There are too many textures in this collection for the requested " + "atlas size.", "Ok"); } return false; } } // Fill atlas textures tk2dEditor.Atlas.Data[] atlasData = atlasBuilder.GetAtlasData(); System.Array.Resize(ref gen.atlasTextures, atlasData.Length); System.Array.Resize(ref gen.atlasMaterials, atlasData.Length); for (int atlasIndex = 0; atlasIndex < atlasData.Length; ++atlasIndex) { Texture2D tex = new Texture2D(64, 64, TextureFormat.ARGB32, false); gen.atlasWastage = (1.0f - atlasData[0].occupancy) * 100.0f; gen.atlasWidth = atlasData[0].width; gen.atlasHeight = atlasData[0].height; tex.Resize(atlasData[atlasIndex].width, atlasData[atlasIndex].height); // Clear texture, unsure if this is REALLY necessary // Turns out it is for (int yy = 0; yy < tex.height; ++yy) { for (int xx = 0; xx < tex.width; ++xx) { tex.SetPixel(xx, yy, Color.clear); } } for (int i = 0; i < atlasData[atlasIndex].entries.Length; ++i) { var entry = atlasData[atlasIndex].entries[i]; Texture2D source = textureList[entry.index]; if (!entry.flipped) { for (int y = 0; y < source.height; ++y) { for (int x = 0; x < source.width; ++x) { tex.SetPixel(entry.x + x, entry.y + y, source.GetPixel(x, y)); } } } else { for (int y = 0; y < source.height; ++y) { for (int x = 0; x < source.width; ++x) { tex.SetPixel(entry.x + y, entry.y + x, source.GetPixel(x, y)); } } } } tex.Apply(); string texturePath = gen.atlasTextures[atlasIndex]?AssetDatabase.GetAssetPath(gen.atlasTextures[atlasIndex]):(dataDirName + "atlas" + atlasIndex + ".png"); // Write filled atlas to disk byte[] bytes = tex.EncodeToPNG(); System.IO.FileStream fs = System.IO.File.Create(texturePath); fs.Write(bytes, 0, bytes.Length); fs.Close(); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Object.DestroyImmediate(tex); tex = AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D)) as Texture2D; gen.atlasTextures[atlasIndex] = tex; // Make sure texture is set up with the correct max size and compression type SetUpTargetTexture(gen, tex); // Create material if necessary if (gen.atlasMaterials[atlasIndex] == null) { Material mat; if (gen.premultipliedAlpha) mat = new Material(Shader.Find("tk2d/PremulVertexColor")); else mat = new Material(Shader.Find("tk2d/BlendVertexColor")); mat.mainTexture = tex; string materialPath = gen.atlasMaterials[atlasIndex]?AssetDatabase.GetAssetPath(gen.atlasMaterials[atlasIndex]):(dataDirName + "atlas" + atlasIndex + "_material.mat"); AssetDatabase.CreateAsset(mat, materialPath); AssetDatabase.SaveAssets(); gen.atlasMaterials[atlasIndex] = AssetDatabase.LoadAssetAtPath(materialPath, typeof(Material)) as Material; } } // Create prefab if (gen.spriteCollection == null) { GameObject go = new GameObject(); go.AddComponent<tk2dSpriteCollectionData>(); #if (UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_4) Object p = EditorUtility.CreateEmptyPrefab(prefabObjectPath); EditorUtility.ReplacePrefab(go, p); #else Object p = PrefabUtility.CreateEmptyPrefab(prefabObjectPath); PrefabUtility.ReplacePrefab(go, p); #endif GameObject.DestroyImmediate(go); AssetDatabase.SaveAssets(); gen.spriteCollection = AssetDatabase.LoadAssetAtPath(prefabObjectPath, typeof(tk2dSpriteCollectionData)) as tk2dSpriteCollectionData; } tk2dSpriteCollectionData coll = gen.spriteCollection; coll.textures = new Texture[gen.atlasTextures.Length]; coll.materials = new Material[gen.atlasMaterials.Length]; for (int i = 0; i < gen.atlasTextures.Length; ++i) { coll.textures[i] = gen.atlasTextures[i]; } for (int i = 0; i < gen.atlasMaterials.Length; ++i) { coll.materials[i] = gen.atlasMaterials[i]; } // Wipe out legacy data coll.material = null; coll.premultipliedAlpha = gen.premultipliedAlpha; coll.spriteDefinitions = new tk2dSpriteDefinition[gen.textureParams.Length]; coll.version = tk2dSpriteCollectionData.CURRENT_VERSION; coll.spriteCollectionGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(gen)); coll.spriteCollectionName = gen.name; coll.invOrthoSize = 1.0f / gen.targetOrthoSize; coll.halfTargetHeight = gen.targetHeight * 0.5f; int buildKey = Random.Range(0, int.MaxValue); while (buildKey == coll.buildKey) { buildKey = Random.Range(0, int.MaxValue); } coll.buildKey = buildKey; // a random build number so we can identify changed collections quickly for (int i = 0; i < coll.spriteDefinitions.Length; ++i) { coll.spriteDefinitions[i] = new tk2dSpriteDefinition(); if (gen.textureRefs[i]) { string assetPath = AssetDatabase.GetAssetPath(gen.textureRefs[i]); string guid = AssetDatabase.AssetPathToGUID(assetPath); coll.spriteDefinitions[i].sourceTextureGUID = guid; } else { coll.spriteDefinitions[i].sourceTextureGUID = ""; } coll.spriteDefinitions[i].extractRegion = gen.textureParams[i].extractRegion; coll.spriteDefinitions[i].regionX = gen.textureParams[i].regionX; coll.spriteDefinitions[i].regionY = gen.textureParams[i].regionY; coll.spriteDefinitions[i].regionW = gen.textureParams[i].regionW; coll.spriteDefinitions[i].regionH = gen.textureParams[i].regionH; } coll.allowMultipleAtlases = gen.allowMultipleAtlases; coll.dataGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(coll)); float scale = 1.0f; if (gen.useTk2dCamera) { scale = 1.0f; } else { scale = 2.0f * gen.targetOrthoSize / gen.targetHeight; } // Build fonts foreach (var font in fontInfoDict.Keys) { var fontInfo = fontInfoDict[font]; List<SpriteLut> fontSpriteLut = new List<SpriteLut>(); int fontId = 0; for (fontId = 0; fontId < gen.fonts.Length; ++fontId) if (gen.fonts[fontId] == font) break; foreach (var v in spriteLuts) { if (v.isFont && v.fontId == fontId) fontSpriteLut.Add(v); } fontInfo.scaleW = coll.textures[0].width; fontInfo.scaleH = coll.textures[0].height; // Build a local sprite lut only relevant to this font UpdateFontData(gen, scale, atlasData, fontSpriteLut, font, fontInfo); // Set material font.data.material = coll.materials[0]; font.editorData.material = coll.materials[0]; // Mark to save EditorUtility.SetDirty(font.data); } // Build textures UpdateVertexCache(gen, scale, atlasData, coll, spriteLuts); // Free tmp textures foreach (var sprite in spriteLuts) { if (!sprite.isDuplicate) Object.DestroyImmediate(sprite.tex); } foreach (var tex in allocatedTextures) Object.DestroyImmediate(tex); // refresh existing RefreshExistingAssets(gen.spriteCollection); // save changes var index = tk2dEditorUtility.GetOrCreateIndex(); index.AddSpriteCollectionData(gen.spriteCollection); EditorUtility.SetDirty(gen.spriteCollection); EditorUtility.SetDirty(gen); sourceTextures = null; // need to clear, its static currentBuild = null; tk2dEditorUtility.GetOrCreateIndex().AddSpriteCollectionData(gen.spriteCollection); tk2dEditorUtility.CommitIndex(); Object.DestroyImmediate(blankTexture); return true; }
static Texture2D ProcessTexture(tk2dSpriteCollection settings, bool additive, bool stretchPad, Texture2D srcTex, int sx, int sy, int tw, int th, ref SpriteLut spriteLut, int padAmount) { // Can't have additive without premultiplied alpha if (!settings.premultipliedAlpha) additive = false; bool allowTrimming = !settings.disableTrimming; var textureCompression = settings.textureCompression; int[] ww = new int[tw]; int[] hh = new int[th]; for (int x = 0; x < tw; ++x) ww[x] = 0; for (int y = 0; y < th; ++y) hh[y] = 0; int numNotTransparent = 0; for (int x = 0; x < tw; ++x) { for (int y = 0; y < th; ++y) { Color col = srcTex.GetPixel(sx + x, sy + y); if (col.a > 0) { ww[x] = 1; hh[y] = 1; numNotTransparent++; } } } if (numNotTransparent > 0) { int x0 = 0, x1 = 0, y0 = 0, y1 = 0; for (int x = 0; x < tw; ++x) if (ww[x] == 1) { x0 = x; break; } for (int x = tw - 1; x >= 0; --x) if (ww[x] == 1) { x1 = x; break; } for (int y = 0; y < th; ++y) if (hh[y] == 1) { y0 = y; break; } for (int y = th - 1; y >= 0; --y) if (hh[y] == 1) { y1 = y; break; } int w1 = x1 - x0 + 1; int h1 = y1 - y0 + 1; if (!allowTrimming) { x0 = 0; y0 = 0; w1 = tw; h1 = th; } Texture2D dtex = new Texture2D(w1 + padAmount * 2, h1 + padAmount * 2); for (int x = 0; x < w1; ++x) { for (int y = 0; y < h1; ++y) { Color col = srcTex.GetPixel(sx + x0 + x, sy + y0 + y); dtex.SetPixel(x + padAmount, y + padAmount, col); } } if (settings.premultipliedAlpha) { for (int x = 0; x < dtex.width; ++x) { for (int y = 0; y < dtex.height; ++y) { Color col = dtex.GetPixel(x, y); col.r *= col.a; col.g *= col.a; col.b *= col.a; col.a = additive?0.0f:col.a; dtex.SetPixel(x, y, col); } } } PadTexture(dtex, padAmount, stretchPad); switch (textureCompression) { case tk2dSpriteCollection.TextureCompression.Dithered16Bit_4444: tk2dEditor.TextureProcessing.FloydSteinbergDithering.DitherTexture(dtex, TextureFormat.ARGB4444, 0, 0, dtex.width, dtex.height); break; case tk2dSpriteCollection.TextureCompression.Dithered16Bit_565: tk2dEditor.TextureProcessing.FloydSteinbergDithering.DitherTexture(dtex, TextureFormat.RGB565, 0, 0, dtex.width, dtex.height); break; } dtex.Apply(); spriteLut.rx = sx + x0; spriteLut.ry = sy + y0; spriteLut.rw = w1; spriteLut.rh = h1; spriteLut.tex = dtex; return dtex; } else { return null; } }
static int GetPadAmount(tk2dSpriteCollection gen, int spriteId) { int basePadAmount = 0; if (gen.padAmount == -1) basePadAmount = (gen.filterMode == FilterMode.Point)?0:defaultPad; else basePadAmount = gen.padAmount; if (spriteId >= 0) basePadAmount += (gen.textureParams[spriteId].extraPadding==-1)?0:gen.textureParams[spriteId].extraPadding; return Mathf.Max(0, basePadAmount); }
static void SetUpTargetTexture(tk2dSpriteCollection gen, Texture2D tex) { bool textureDirty = false; string targetTexPath = AssetDatabase.GetAssetPath(tex); TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(targetTexPath); if (gen.maxTextureSize != importer.maxTextureSize) { importer.maxTextureSize = gen.maxTextureSize; textureDirty = true; } TextureImporterFormat targetFormat; switch (gen.textureCompression) { case tk2dSpriteCollection.TextureCompression.Uncompressed: targetFormat = TextureImporterFormat.AutomaticTruecolor; break; case tk2dSpriteCollection.TextureCompression.Reduced16Bit: targetFormat = TextureImporterFormat.Automatic16bit; break; case tk2dSpriteCollection.TextureCompression.Dithered16Bit_4444: targetFormat = TextureImporterFormat.Automatic16bit; break; case tk2dSpriteCollection.TextureCompression.Dithered16Bit_565: targetFormat = TextureImporterFormat.Automatic16bit; break; case tk2dSpriteCollection.TextureCompression.Compressed: targetFormat = TextureImporterFormat.AutomaticCompressed; break; default: targetFormat = TextureImporterFormat.AutomaticTruecolor; break; } if (targetFormat != importer.textureFormat) { importer.textureFormat = targetFormat; textureDirty = true; } // Make sure texture is set to point filtered when no pad mode is selected FilterMode targetFilterMode = gen.pixelPerfectPointSampled?FilterMode.Point:FilterMode.Bilinear; if (tex.filterMode != targetFilterMode) { importer.filterMode = targetFilterMode; EditorUtility.SetDirty(importer); textureDirty = true; } if (textureDirty) { EditorUtility.SetDirty(importer); AssetDatabase.ImportAsset(targetTexPath); } }
static Texture2D ProcessTexture(tk2dSpriteCollection settings, bool additive, bool stretchPad, bool disableTrimming, bool isInjectedTexture, Texture2D srcTex, int sx, int sy, int tw, int th, ref SpriteLut spriteLut, int padAmount) { // Can't have additive without premultiplied alpha if (!settings.premultipliedAlpha) additive = false; bool allowTrimming = !settings.disableTrimming && !disableTrimming; var textureCompression = settings.textureCompression; int[] ww = new int[tw]; int[] hh = new int[th]; for (int x = 0; x < tw; ++x) ww[x] = 0; for (int y = 0; y < th; ++y) hh[y] = 0; int numNotTransparent = 0; for (int x = 0; x < tw; ++x) { for (int y = 0; y < th; ++y) { Color col = srcTex.GetPixel(sx + x, sy + y); if (col.a > 0) { ww[x] = 1; hh[y] = 1; numNotTransparent++; } } } if (numNotTransparent > 0) { int x0 = 0, x1 = 0, y0 = 0, y1 = 0; bool customSpriteGeometry = false; if (!isInjectedTexture && settings.textureParams[spriteLut.source].customSpriteGeometry) customSpriteGeometry = true; // For custom geometry, use the bounds of the geometry if (customSpriteGeometry) { var textureParams = settings.textureParams[spriteLut.source]; x0 = int.MaxValue; y0 = int.MaxValue; x1 = -1; y1 = -1; foreach (var island in textureParams.geometryIslands) { foreach (var vert in island.points) { int minX = Mathf.FloorToInt(vert.x); int maxX = Mathf.CeilToInt(vert.x); float y = th - 1 - vert.y; int minY = Mathf.FloorToInt(y); int maxY = Mathf.CeilToInt(y); x0 = Mathf.Min(x0, minX); y0 = Mathf.Min(y0, minY); x1 = Mathf.Max(x1, maxX); y1 = Mathf.Max(y1, maxY); } } } else { for (int x = 0; x < tw; ++x) if (ww[x] == 1) { x0 = x; break; } for (int x = tw - 1; x >= 0; --x) if (ww[x] == 1) { x1 = x; break; } for (int y = 0; y < th; ++y) if (hh[y] == 1) { y0 = y; break; } for (int y = th - 1; y >= 0; --y) if (hh[y] == 1) { y1 = y; break; } } x1 = Mathf.Min(x1, tw - 1); y1 = Mathf.Min(y1, th - 1); int w1 = x1 - x0 + 1; int h1 = y1 - y0 + 1; if (!allowTrimming) { x0 = 0; y0 = 0; w1 = tw; h1 = th; } Texture2D dtex = new Texture2D(w1 + padAmount * 2, h1 + padAmount * 2); for (int x = 0; x < w1; ++x) { for (int y = 0; y < h1; ++y) { Color col = srcTex.GetPixel(sx + x0 + x, sy + y0 + y); dtex.SetPixel(x + padAmount, y + padAmount, col); } } if (settings.premultipliedAlpha) { for (int x = 0; x < dtex.width; ++x) { for (int y = 0; y < dtex.height; ++y) { Color col = dtex.GetPixel(x, y); col.r *= col.a; col.g *= col.a; col.b *= col.a; col.a = additive?0.0f:col.a; dtex.SetPixel(x, y, col); } } } PadTexture(dtex, padAmount, stretchPad); switch (textureCompression) { case tk2dSpriteCollection.TextureCompression.Dithered16Bit_NoAlpha: tk2dEditor.TextureProcessing.FloydSteinbergDithering.DitherTexture(dtex, TextureFormat.ARGB4444, 0, 0, dtex.width, dtex.height); break; case tk2dSpriteCollection.TextureCompression.Dithered16Bit_Alpha: tk2dEditor.TextureProcessing.FloydSteinbergDithering.DitherTexture(dtex, TextureFormat.RGB565, 0, 0, dtex.width, dtex.height); break; } dtex.Apply(); spriteLut.rx = sx + x0; spriteLut.ry = sy + y0; spriteLut.rw = w1; spriteLut.rh = h1; spriteLut.tex = dtex; return dtex; } else { return null; } }
public static bool Rebuild(tk2dSpriteCollection gen) { // avoid "recursive" build being triggered by texture watcher if (currentBuild != null) return false; // Version specific checks. These need to be done before the sprite collection is upgraded. if (gen.version < 2) { if (!tk2dEditor.SpriteCollectionBuilder.Deprecated.CheckAndFixUpParams(gen)) { // Params failed check return false; } tk2dEditor.SpriteCollectionBuilder.Deprecated.SetUpSpriteSheets(gen); tk2dEditor.SpriteCollectionBuilder.Deprecated.TrimTextureList(gen); } currentBuild = gen; gen.Upgrade(); // upgrade if necessary. could be invoked by texture watcher. // Get some sensible paths to work with string dataDirName = GetOrCreateDataPath(gen) + "/"; string prefabObjectPath = ""; if (gen.spriteCollection) prefabObjectPath = AssetDatabase.GetAssetPath(gen.spriteCollection); else prefabObjectPath = dataDirName + gen.name + ".prefab"; BuildDirectoryToFile(prefabObjectPath); // Create prefab object, needed for next stage CreateDataObject( gen, prefabObjectPath ); // Special build for platform specific sprite collection if (gen.HasPlatformData) { // Initialize required sprite collections tk2dEditor.SpriteCollectionBuilder.PlatformBuilder.InitializeSpriteCollectionPlatforms(gen, System.IO.Path.GetDirectoryName(prefabObjectPath)); // The first sprite collection is always THIS tk2dAssetPlatform baseAssetPlatform = tk2dSystem.GetAssetPlatform(gen.platforms[0].name); float baseScale = (baseAssetPlatform != null)?baseAssetPlatform.scale:1.0f; // Building platform specific data, allow recursive builds temporarily currentBuild = null; // Transfer to platform sprite collections, and build those for (int i = 0; i < gen.platforms.Count; ++i) { tk2dSpriteCollectionPlatform platform = gen.platforms[i]; tk2dAssetPlatform thisAssetPlatform = tk2dSystem.GetAssetPlatform(gen.platforms[i].name); float thisScale = (thisAssetPlatform != null)?thisAssetPlatform.scale:1.0f; bool validPlatform = platform.name.Length > 0 && platform.spriteCollection != null; bool isRootSpriteCollection = (i == 0); if (validPlatform) { tk2dSpriteCollection thisPlatformCollection = gen.platforms[i].spriteCollection; // Make sure data directory exists, material overrides will be created in here string dataPath = GetOrCreateDataPath(thisPlatformCollection); tk2dEditor.SpriteCollectionBuilder.PlatformBuilder.UpdatePlatformSpriteCollection( gen, thisPlatformCollection, dataPath, isRootSpriteCollection, thisScale / baseScale, platform.name); Rebuild(thisPlatformCollection); } } // Pull atlas data from default platform gen.atlasMaterials = gen.platforms[0].spriteCollection.atlasMaterials; gen.altMaterials = gen.platforms[0].spriteCollection.altMaterials; // Fill up our sprite collection data List<string> platformNames = new List<string>(); List<string> platformGUIDs = new List<string>(); for (int i = 0; i < gen.platforms.Count; ++i) { tk2dSpriteCollectionPlatform platform = gen.platforms[i]; if (!platform.Valid) continue; platformNames.Add(platform.name); tk2dSpriteCollectionData data = platform.spriteCollection.spriteCollection; string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(data)); platformGUIDs.Add(guid); // Make loadable tk2dSystemUtility.MakeLoadableAsset(data, ""); // unnamed loadable object } // Set up fonts for (int j = 0; j < gen.fonts.Length; ++j) { tk2dSpriteCollectionFont font = gen.fonts[j]; if (font == null) continue; tk2dFontData data = font.data; if (!data) continue; data.hasPlatformData = true; data.material = null; data.materialInst = null; data.fontPlatforms = platformNames.ToArray(); data.fontPlatformGUIDs = new string[platformNames.Count]; for (int i = 0; i < gen.platforms.Count; ++i) { tk2dSpriteCollectionPlatform platform = gen.platforms[i]; if (!platform.Valid) continue; data.fontPlatformGUIDs[i] = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(gen.platforms[i].spriteCollection.fonts[j].data)); } EditorUtility.SetDirty(data); } gen.spriteCollection.version = tk2dSpriteCollectionData.CURRENT_VERSION; gen.spriteCollection.spriteCollectionName = gen.name; gen.spriteCollection.spriteCollectionGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(gen)); gen.spriteCollection.dataGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(gen.spriteCollection)); // Clear out data gen.spriteCollection.spriteDefinitions = new tk2dSpriteDefinition[0]; gen.spriteCollection.materials = new Material[0]; gen.spriteCollection.textures = new Texture2D[0]; gen.spriteCollection.hasPlatformData = true; gen.spriteCollection.spriteCollectionPlatforms = platformNames.ToArray(); gen.spriteCollection.spriteCollectionPlatformGUIDs = platformGUIDs.ToArray(); EditorUtility.SetDirty(gen); EditorUtility.SetDirty(gen.spriteCollection); // Index this properly tk2dEditorUtility.GetOrCreateIndex().AddSpriteCollectionData(gen.spriteCollection); tk2dEditorUtility.CommitIndex(); AssetDatabase.SaveAssets(); ResetCurrentBuild(); return true; } else { // clear platform data gen.spriteCollection.ResetPlatformData(); // in case its being used gen.spriteCollection.hasPlatformData = false; gen.spriteCollection.spriteCollectionPlatforms = new string[0]; gen.spriteCollection.spriteCollectionPlatformGUIDs = new string[0]; // Set up fonts for (int j = 0; j < gen.fonts.Length; ++j) { tk2dFontData f = gen.fonts[j].data; if (f != null) { f.ResetPlatformData(); f.hasPlatformData = false; f.fontPlatforms = new string[0]; f.fontPlatformGUIDs = new string[0]; EditorUtility.SetDirty(f); } } } // Make sure all source textures are in the correct format SetUpSourceTextureFormats(gen); // blank texture used when texture has been deleted Texture2D blankTexture = new Texture2D(2, 2); blankTexture.SetPixel(0, 0, Color.magenta); blankTexture.SetPixel(0, 1, Color.yellow); blankTexture.SetPixel(1, 0, Color.cyan); blankTexture.SetPixel(1, 1, Color.grey); blankTexture.Apply(); // make local texture sources List<Texture2D> allocatedTextures = new List<Texture2D>(); sourceTextures = new Texture2D[gen.textureParams.Length]; for (int i = 0; i < gen.textureParams.Length; ++i) { var param = gen.textureParams[i]; if (param.extractRegion && param.texture != null) { Texture2D localTex = new Texture2D(param.regionW, param.regionH); for (int y = 0; y < param.regionH; ++y) { for (int x = 0; x < param.regionW; ++x) { localTex.SetPixel(x, y, param.texture.GetPixel(param.regionX + x, param.regionY + y)); } } localTex.name = param.texture.name + "/" + param.regionId.ToString(); localTex.Apply(); allocatedTextures.Add(localTex); sourceTextures[i] = localTex; } else { sourceTextures[i] = gen.textureParams[i].texture; } } // catalog all textures to atlas int numTexturesToAtlas = 0; List<SpriteLut> spriteLuts = new List<SpriteLut>(); for (int i = 0; i < gen.textureParams.Length; ++i) { Texture2D currentTexture = sourceTextures[i]; if (sourceTextures[i] == null) { gen.textureParams[i].dice = false; gen.textureParams[i].anchor = tk2dSpriteCollectionDefinition.Anchor.MiddleCenter; gen.textureParams[i].name = ""; gen.textureParams[i].extractRegion = false; gen.textureParams[i].fromSpriteSheet = false; currentTexture = blankTexture; } else { if (gen.textureParams[i].name == null || gen.textureParams[i].name == "") { if (gen.textureParams[i].texture != currentTexture && !gen.textureParams[i].fromSpriteSheet) { gen.textureParams[i].name = currentTexture.name; } } } if (gen.textureParams[i].dice) { // prepare to dice this up int diceUnitX = gen.textureParams[i].diceUnitX; int diceUnitY = gen.textureParams[i].diceUnitY; if (diceUnitX <= 0) diceUnitX = 128; // something sensible, please if (diceUnitY <= 0) diceUnitY = diceUnitX; // make square if not set Texture2D srcTex = currentTexture; for (int sx = 0; sx < srcTex.width; sx += diceUnitX) { for (int sy = 0; sy < srcTex.height; sy += diceUnitY) { int tw = Mathf.Min(diceUnitX, srcTex.width - sx); int th = Mathf.Min(diceUnitY, srcTex.height - sy); SpriteLut diceLut = new SpriteLut(); diceLut.source = i; diceLut.isSplit = true; diceLut.sourceTex = srcTex; diceLut.isDuplicate = false; // duplicate diced textures can be chopped up differently, so don't detect dupes here Texture2D dest = ProcessTexture(gen, gen.textureParams[i].additive, true, gen.textureParams[i].disableTrimming, false, srcTex, sx, sy, tw, th, ref diceLut, GetPadAmount(gen, i)); if (dest) { diceLut.atlasIndex = numTexturesToAtlas++; spriteLuts.Add(diceLut); } } } } else { SpriteLut lut = new SpriteLut(); lut.sourceTex = currentTexture; lut.source = i; lut.isSplit = false; lut.isDuplicate = false; for (int j = 0; j < spriteLuts.Count; ++j) { if (spriteLuts[j].sourceTex == lut.sourceTex) { lut.isDuplicate = true; lut.atlasIndex = spriteLuts[j].atlasIndex; lut.tex = spriteLuts[j].tex; // get old processed tex lut.rx = spriteLuts[j].rx; lut.ry = spriteLuts[j].ry; lut.rw = spriteLuts[j].rw; lut.rh = spriteLuts[j].rh; break; } } if (!lut.isDuplicate) { lut.atlasIndex = numTexturesToAtlas++; bool stretchPad = false; if (gen.textureParams[i].pad == tk2dSpriteCollectionDefinition.Pad.Extend) stretchPad = true; Texture2D dest = ProcessTexture(gen, gen.textureParams[i].additive, stretchPad, gen.textureParams[i].disableTrimming, false, currentTexture, 0, 0, currentTexture.width, currentTexture.height, ref lut, GetPadAmount(gen, i)); if (dest == null) { // fall back to a tiny blank texture lut.tex = new Texture2D(1, 1); lut.tex.SetPixel(0, 0, new Color( 0, 0, 0, 0 )); PadTexture(lut.tex, GetPadAmount(gen, i), stretchPad); lut.tex.Apply(); lut.rx = currentTexture.width / 2; lut.ry = currentTexture.height / 2; lut.rw = 1; lut.rh = 1; } } spriteLuts.Add(lut); } } // Font Dictionary<tk2dSpriteCollectionFont, tk2dEditor.Font.Info> fontInfoDict = new Dictionary<tk2dSpriteCollectionFont, tk2dEditor.Font.Info>(); if (gen.fonts != null) { for (int i = 0; i < gen.fonts.Length; ++i) { var font = gen.fonts[i]; if (!font.InUse) continue; var fontInfo = tk2dEditor.Font.Builder.ParseBMFont( AssetDatabase.GetAssetPath(font.bmFont) ); fontInfoDict[font] = fontInfo; foreach (var c in fontInfo.chars) { // skip empty textures if (c.width <= 0 || c.height <= 0) continue; SpriteLut lut = new SpriteLut(); int cy = font.flipTextureY?c.y:(fontInfo.scaleH - c.y - c.height); Texture2D dest = ProcessTexture(gen, false, false, false, true, font.texture, c.x, cy, c.width, c.height, ref lut, GetPadAmount(gen, -1)); if (dest == null) { // probably fully transparent continue; } lut.sourceTex = dest; lut.tex = dest; lut.source = -1; lut.isFont = true; lut.isDuplicate = false; lut.fontId = i; lut.charId = c.id; lut.rx = lut.rx - c.x; lut.ry = lut.ry - cy; lut.atlasIndex = numTexturesToAtlas++; spriteLuts.Add(lut); } // Add one blank char for fallbacks { int dims = 5; SpriteLut lut = new SpriteLut(); lut.tex = new Texture2D(dims, dims); for (int y = 0; y < dims; ++y) for (int x = 0; x < dims; ++x) lut.tex.SetPixel(x, y, Color.clear); lut.tex.Apply(); lut.sourceTex = lut.tex; lut.isFont = true; lut.isDuplicate = false; lut.fontId = i; lut.charId = -1; lut.atlasIndex = numTexturesToAtlas++; spriteLuts.Add(lut); } } } // Create texture Texture2D[] textureList = new Texture2D[numTexturesToAtlas]; int titer = 0; for (int i = 0; i < spriteLuts.Count; ++i) { SpriteLut _lut = spriteLuts[i]; if (!_lut.isDuplicate) { textureList[titer++] = _lut.tex; } } // Build atlas bool forceAtlasSize = gen.forceTextureSize; int atlasWidth = forceAtlasSize?gen.forcedTextureWidth:gen.maxTextureSize; int atlasHeight = forceAtlasSize?gen.forcedTextureHeight:gen.maxTextureSize; bool forceSquareAtlas = forceAtlasSize?false:gen.forceSquareAtlas; bool allowFindingOptimalSize = !forceAtlasSize; tk2dEditor.Atlas.Builder atlasBuilder = new tk2dEditor.Atlas.Builder(atlasWidth, atlasHeight, gen.allowMultipleAtlases?64:1, allowFindingOptimalSize, forceSquareAtlas); if (textureList.Length > 0) { foreach (Texture2D currTexture in textureList) { atlasBuilder.AddRect(currTexture.width, currTexture.height); } if (atlasBuilder.Build() != 0) { if (atlasBuilder.HasOversizeTextures()) { EditorUtility.DisplayDialog("Unable to fit in atlas", "You have a texture which exceeds the atlas size. " + "Consider putting it in a separate atlas, enabling dicing, or " + "reducing the texture size", "Ok"); } else { EditorUtility.DisplayDialog("Unable to fit textures in requested atlas area", "There are too many textures in this collection for the requested " + "atlas size.", "Ok"); } return false; } } // Fill atlas textures tk2dEditor.Atlas.Data[] atlasData = atlasBuilder.GetAtlasData(); System.Array.Resize(ref gen.atlasTextures, atlasData.Length); System.Array.Resize(ref gen.atlasMaterials, atlasData.Length); if (atlasData.Length > 1) { // wipe out alt materials when atlas spanning is on gen.altMaterials = new Material[0]; } for (int atlasIndex = 0; atlasIndex < atlasData.Length; ++atlasIndex) { Texture2D tex = new Texture2D(64, 64, TextureFormat.ARGB32, false); gen.atlasWastage = (1.0f - atlasData[0].occupancy) * 100.0f; gen.atlasWidth = atlasData[0].width; gen.atlasHeight = atlasData[0].height; tex.Resize(atlasData[atlasIndex].width, atlasData[atlasIndex].height); // Clear texture, unsure if this is REALLY necessary // Turns out it is for (int yy = 0; yy < tex.height; ++yy) { for (int xx = 0; xx < tex.width; ++xx) { tex.SetPixel(xx, yy, Color.clear); } } for (int i = 0; i < atlasData[atlasIndex].entries.Length; ++i) { var entry = atlasData[atlasIndex].entries[i]; Texture2D source = textureList[entry.index]; if (!entry.flipped) { for (int y = 0; y < source.height; ++y) { for (int x = 0; x < source.width; ++x) { tex.SetPixel(entry.x + x, entry.y + y, source.GetPixel(x, y)); } } } else { for (int y = 0; y < source.height; ++y) { for (int x = 0; x < source.width; ++x) { tex.SetPixel(entry.x + y, entry.y + x, source.GetPixel(x, y)); } } } } tex.Apply(); string texturePath = gen.atlasTextures[atlasIndex]?AssetDatabase.GetAssetPath(gen.atlasTextures[atlasIndex]):(dataDirName + "atlas" + atlasIndex + ".png"); BuildDirectoryToFile(texturePath); // Write filled atlas to disk byte[] bytes = tex.EncodeToPNG(); System.IO.FileStream fs = System.IO.File.Create(texturePath); fs.Write(bytes, 0, bytes.Length); fs.Close(); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Object.DestroyImmediate(tex); tex = AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D)) as Texture2D; gen.atlasTextures[atlasIndex] = tex; // Make sure texture is set up with the correct max size and compression type SetUpTargetTexture(gen, tex); // Create material if necessary if (gen.atlasMaterials[atlasIndex] == null) { Material mat; if (gen.premultipliedAlpha) mat = new Material(Shader.Find("tk2d/PremulVertexColor")); else mat = new Material(Shader.Find("tk2d/BlendVertexColor")); mat.mainTexture = tex; string materialPath = gen.atlasMaterials[atlasIndex]?AssetDatabase.GetAssetPath(gen.atlasMaterials[atlasIndex]):(dataDirName + "atlas" + atlasIndex + " material.mat"); BuildDirectoryToFile(materialPath); AssetDatabase.CreateAsset(mat, materialPath); AssetDatabase.SaveAssets(); gen.atlasMaterials[atlasIndex] = AssetDatabase.LoadAssetAtPath(materialPath, typeof(Material)) as Material; } // gen.altMaterials must either have length 0, or contain at least the material used in the game if (!gen.allowMultipleAtlases && (gen.altMaterials == null || gen.altMaterials.Length == 0)) gen.altMaterials = new Material[1] { gen.atlasMaterials[0] }; } tk2dSpriteCollectionData coll = gen.spriteCollection; coll.textures = new Texture[gen.atlasTextures.Length]; for (int i = 0; i < gen.atlasTextures.Length; ++i) { coll.textures[i] = gen.atlasTextures[i]; } if (gen.atlasMaterials.Length == 1) { coll.materials = new Material[gen.altMaterials.Length]; for (int i = 0; i < gen.altMaterials.Length; ++i) coll.materials[i] = gen.altMaterials[i]; } else { coll.materials = new Material[gen.atlasMaterials.Length]; for (int i = 0; i < gen.atlasMaterials.Length; ++i) coll.materials[i] = gen.atlasMaterials[i]; } // Wipe out legacy data coll.material = null; coll.premultipliedAlpha = gen.premultipliedAlpha; coll.spriteDefinitions = new tk2dSpriteDefinition[gen.textureParams.Length]; coll.version = tk2dSpriteCollectionData.CURRENT_VERSION; coll.materialIdsValid = true; coll.spriteCollectionGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(gen)); coll.spriteCollectionName = gen.name; coll.invOrthoSize = 1.0f / gen.targetOrthoSize; coll.halfTargetHeight = gen.targetHeight * 0.5f; int buildKey = Random.Range(0, int.MaxValue); while (buildKey == coll.buildKey) { buildKey = Random.Range(0, int.MaxValue); } coll.buildKey = buildKey; // a random build number so we can identify changed collections quickly for (int i = 0; i < coll.spriteDefinitions.Length; ++i) { coll.spriteDefinitions[i] = new tk2dSpriteDefinition(); if (gen.textureParams[i].texture) { string assetPath = AssetDatabase.GetAssetPath(gen.textureParams[i].texture); string guid = AssetDatabase.AssetPathToGUID(assetPath); coll.spriteDefinitions[i].sourceTextureGUID = guid; } else { coll.spriteDefinitions[i].sourceTextureGUID = ""; } coll.spriteDefinitions[i].extractRegion = gen.textureParams[i].extractRegion; coll.spriteDefinitions[i].regionX = gen.textureParams[i].regionX; coll.spriteDefinitions[i].regionY = gen.textureParams[i].regionY; coll.spriteDefinitions[i].regionW = gen.textureParams[i].regionW; coll.spriteDefinitions[i].regionH = gen.textureParams[i].regionH; } coll.allowMultipleAtlases = gen.allowMultipleAtlases; coll.dataGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(coll)); float scale = 1.0f; if (gen.useTk2dCamera) { scale = 1.0f * gen.globalScale; } else { scale = (2.0f * gen.targetOrthoSize / gen.targetHeight) * gen.globalScale; } // Build fonts foreach (var font in fontInfoDict.Keys) { var fontInfo = fontInfoDict[font]; List<SpriteLut> fontSpriteLut = new List<SpriteLut>(); int fontId = 0; for (fontId = 0; fontId < gen.fonts.Length; ++fontId) if (gen.fonts[fontId] == font) break; foreach (var v in spriteLuts) { if (v.isFont && v.fontId == fontId) fontSpriteLut.Add(v); } fontInfo.scaleW = coll.textures[0].width; fontInfo.scaleH = coll.textures[0].height; // Set material if (font.useGradient && font.gradientTexture != null && font.gradientCount > 0) { font.editorData.gradientCount = font.gradientCount; font.editorData.gradientTexture = font.gradientTexture; } else { font.editorData.gradientCount = 1; font.editorData.gradientTexture = null; } // Build a local sprite lut only relevant to this font UpdateFontData(gen, scale, atlasData, fontSpriteLut, font, fontInfo); if (font.useGradient && font.gradientTexture != null) { font.data.gradientCount = font.editorData.gradientCount; font.data.gradientTexture = font.editorData.gradientTexture; font.data.textureGradients = true; } else { font.data.gradientCount = 1; font.data.gradientTexture = null; font.data.textureGradients = false; } font.data.spriteCollection = gen.spriteCollection; font.data.material = coll.materials[font.materialId]; font.editorData.material = coll.materials[font.materialId]; font.data.invOrthoSize = coll.invOrthoSize; font.data.halfTargetHeight = coll.halfTargetHeight; font.data.texelSize = new Vector3(scale, scale, 0.0f); // Managed? font.data.managedFont = gen.managedSpriteCollection; font.data.needMaterialInstance = gen.managedSpriteCollection; // Mark to save EditorUtility.SetDirty(font.editorData); EditorUtility.SetDirty(font.data); // Update font tk2dEditorUtility.GetOrCreateIndex().AddOrUpdateFont(font.editorData); tk2dEditorUtility.CommitIndex(); // Loadable? if (!tk2dSystemUtility.IsLoadableAsset(font.data)) tk2dSystemUtility.MakeLoadableAsset(font.data, ""); } // Build textures UpdateVertexCache(gen, scale, atlasData, coll, spriteLuts); // Free tmp textures foreach (var sprite in spriteLuts) { if (!sprite.isDuplicate) Object.DestroyImmediate(sprite.tex); } foreach (var tex in allocatedTextures) Object.DestroyImmediate(tex); // refresh existing RefreshExistingAssets(gen.spriteCollection); // save changes gen.spriteCollection.assetName = gen.assetName; gen.spriteCollection.managedSpriteCollection = gen.managedSpriteCollection; gen.spriteCollection.needMaterialInstance = gen.managedSpriteCollection; var index = tk2dEditorUtility.GetOrCreateIndex(); index.AddSpriteCollectionData(gen.spriteCollection); EditorUtility.SetDirty(gen.spriteCollection); EditorUtility.SetDirty(gen); sourceTextures = null; // need to clear, its static currentBuild = null; tk2dEditorUtility.GetOrCreateIndex().AddSpriteCollectionData(gen.spriteCollection); tk2dEditorUtility.CommitIndex(); Object.DestroyImmediate(blankTexture); // update resource system if (tk2dSystemUtility.IsLoadableAsset(gen.spriteCollection)) { tk2dSystemUtility.UpdateAssetName(gen.spriteCollection, gen.assetName); } return true; }
public static void ResetCurrentBuild() { currentBuild = null; }
static bool SetUpSpriteSheets(tk2dSpriteCollection gen) { // delete textures which aren't in sprite sheets any more // and delete textures which are out of range of the spritesheet for (int i = 0; i < gen.textureRefs.Length; ++i) { if (gen.textureParams[i].fromSpriteSheet) { bool found = false; foreach (var ss in gen.spriteSheets) { if (gen.textureRefs[i] == ss.texture) { found = true; int numTiles = (ss.numTiles == 0)?(ss.tilesX * ss.tilesY):Mathf.Min(ss.numTiles, ss.tilesX * ss.tilesY); // delete textures which are out of range if (gen.textureParams[i].regionId >= numTiles) { gen.textureRefs[i] = null; gen.textureParams[i].fromSpriteSheet = false; gen.textureParams[i].extractRegion = false; gen.textureParams[i].colliderType = tk2dSpriteCollectionDefinition.ColliderType.None; gen.textureParams[i].boxColliderMin = Vector3.zero; gen.textureParams[i].boxColliderMax = Vector3.zero; } } } if (!found) { gen.textureRefs[i] = null; gen.textureParams[i].fromSpriteSheet = false; gen.textureParams[i].extractRegion = false; gen.textureParams[i].colliderType = tk2dSpriteCollectionDefinition.ColliderType.None; gen.textureParams[i].boxColliderMin = Vector3.zero; gen.textureParams[i].boxColliderMax = Vector3.zero; } } } if (gen.spriteSheets == null) { gen.spriteSheets = new tk2dSpriteSheetSource[0]; } int spriteSheetId = 0; for (spriteSheetId = 0; spriteSheetId < gen.spriteSheets.Length; ++spriteSheetId) { var spriteSheet = gen.spriteSheets[spriteSheetId]; // New mode sprite sheets have sprites already created if (spriteSheet.version > 0) continue; // Sanity check if (spriteSheet.texture == null) { continue; // deleted, safely ignore this } if (spriteSheet.tilesX * spriteSheet.tilesY == 0 || (spriteSheet.numTiles != 0 && spriteSheet.numTiles > spriteSheet.tilesX * spriteSheet.tilesY)) { EditorUtility.DisplayDialog("Invalid sprite sheet", "Sprite sheet '" + spriteSheet.texture.name + "' has an invalid number of tiles", "Ok"); return false; } if ((spriteSheet.texture.width % spriteSheet.tilesX) != 0 || (spriteSheet.texture.height % spriteSheet.tilesY) != 0) { EditorUtility.DisplayDialog("Invalid sprite sheet", "Sprite sheet '" + spriteSheet.texture.name + "' doesn't match tile count", "Ok"); return false; } int numTiles = (spriteSheet.numTiles == 0)?(spriteSheet.tilesX * spriteSheet.tilesY):Mathf.Min(spriteSheet.numTiles, spriteSheet.tilesX * spriteSheet.tilesY); for (int y = 0; y < spriteSheet.tilesY; ++y) { for (int x = 0; x < spriteSheet.tilesX; ++x) { // limit to number of tiles, if told to int tileIdx = y * spriteSheet.tilesX + x; if (tileIdx >= numTiles) break; bool foundInCollection = false; // find texture in collection int textureIdx = -1; for (int i = 0; i < gen.textureParams.Length; ++i) { if (gen.textureParams[i].fromSpriteSheet && gen.textureParams[i].regionId == tileIdx && gen.textureRefs[i] == spriteSheet.texture) { textureIdx = i; foundInCollection = true; break; } } if (textureIdx == -1) { // find first empty texture slot for (int i = 0; i < gen.textureParams.Length; ++i) { if (gen.textureRefs[i] == null) { textureIdx = i; break; } } } if (textureIdx == -1) { // texture not found, so extend arrays System.Array.Resize(ref gen.textureRefs, gen.textureRefs.Length + 1); System.Array.Resize(ref gen.textureParams, gen.textureParams.Length + 1); textureIdx = gen.textureRefs.Length - 1; } gen.textureRefs[textureIdx] = spriteSheet.texture; var param = new tk2dSpriteCollectionDefinition(); param.fromSpriteSheet = true; param.name = spriteSheet.texture.name + "/" + tileIdx; param.regionId = tileIdx; param.regionW = spriteSheet.texture.width / spriteSheet.tilesX; param.regionH = spriteSheet.texture.height / spriteSheet.tilesY; param.regionX = (tileIdx % spriteSheet.tilesX) * param.regionW; param.regionY = (spriteSheet.tilesY - 1 - (tileIdx / spriteSheet.tilesX)) * param.regionH; param.extractRegion = true; param.additive = spriteSheet.additive; param.pad = spriteSheet.pad; param.anchor = (tk2dSpriteCollectionDefinition.Anchor)spriteSheet.anchor; param.scale = (spriteSheet.scale.sqrMagnitude == 0.0f)?Vector3.one:spriteSheet.scale; // Let the user tweak individually if (foundInCollection) { param.colliderType = gen.textureParams[textureIdx].colliderType; param.boxColliderMin = gen.textureParams[textureIdx].boxColliderMin; param.boxColliderMax = gen.textureParams[textureIdx].boxColliderMax; param.polyColliderIslands = gen.textureParams[textureIdx].polyColliderIslands; param.colliderConvex = gen.textureParams[textureIdx].colliderConvex; param.colliderSmoothSphereCollisions = gen.textureParams[textureIdx].colliderSmoothSphereCollisions; param.colliderColor = gen.textureParams[textureIdx].colliderColor; } else { param.colliderType = spriteSheet.colliderType; } gen.textureParams[textureIdx] = param; } } } return true; }
// Create the sprite collection data object // Its a prefab for historic reasons static void CreateDataObject(tk2dSpriteCollection gen, string prefabObjectPath) { // Create prefab if (gen.spriteCollection == null) { prefabObjectPath = AssetDatabase.GenerateUniqueAssetPath(prefabObjectPath); GameObject go = new GameObject(); go.AddComponent<tk2dSpriteCollectionData>(); #if (UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4) Object p = EditorUtility.CreateEmptyPrefab(prefabObjectPath); EditorUtility.ReplacePrefab(go, p); #else Object p = PrefabUtility.CreateEmptyPrefab(prefabObjectPath); PrefabUtility.ReplacePrefab(go, p); #endif GameObject.DestroyImmediate(go); AssetDatabase.SaveAssets(); gen.spriteCollection = AssetDatabase.LoadAssetAtPath(prefabObjectPath, typeof(tk2dSpriteCollectionData)) as tk2dSpriteCollectionData; } }