private static void ProcessAtlas(SVGBasicAtlas atlas) { Texture2D tmpTexture = new Texture2D(1, 1, TextureFormat.ARGB32, false); List <SVGSpriteAssetFile> spritesAssets = atlas.SpriteAssets(); foreach (SVGSpriteAssetFile spriteAsset in spritesAssets) { SVGSpriteData spriteData = spriteAsset.SpriteData; Sprite original = spriteData.Sprite; // we must reference the original texture, because we want to keep the file reference (rd->texture.IsValid()) Sprite tmpSprite = Sprite.Create(original.texture, new Rect(0, 0, 1, 1), new Vector2(0, 0), SVGBasicAtlas.SPRITE_PIXELS_PER_UNIT, 0, SpriteMeshType.FullRect); // now we change the (sprite) asset content: actually we have just reduced its rectangle to a 1x1 pixel EditorUtility.CopySerialized(tmpSprite, original); } for (int i = 0; i < atlas.TextureAssetsCount(); i++) { AssetFile file = atlas.TextureAsset(i); Texture2D original = file.Object as Texture2D; // copy the 1x1 texture inside the original texture EditorUtility.CopySerialized(tmpTexture, original); } }
private int SortingOrderGenerate(SVGSpriteAssetFile spriteAsset) { if (spriteAsset != null) { SVGSpriteRef spriteRef = spriteAsset.SpriteRef; SVGSpriteData spriteData = spriteAsset.SpriteData; int svgIndex = this.SvgAssetIndexGet(spriteRef.TxtAsset); if (svgIndex >= 0) { SVGSpritesList spritesList; SVGAssetInput svgAsset = this.m_SvgList[svgIndex]; // if needed, advance in the instances group if (spriteData.InCurrentInstancesGroup) { // get the list of sprites (references) relative to the SVG input asset if (this.m_GeneratedSpritesLists.TryGetValue(svgAsset.TxtAsset.GetInstanceID(), out spritesList)) { // advance instances group, telling that we are going to instantiate one sprite only this.NextInstancesGroup(svgAsset, spritesList, 1); } } return(SVGAtlas.SortingOrderCalc(svgIndex, svgAsset.InstanceBaseIdx, spriteData.ZOrder)); } } return(-1); }
// Constructor. public SVGSpriteAssetFile(string path, SVGSpriteRef spriteRef, SVGSpriteData spriteData) { this.Path = path; this.SpriteRef = spriteRef; this.SpriteData = spriteData; #if UNITY_EDITOR this.InstantiatedWidgetType = SVGUIWidgetType.Button; #endif }
private void ResetGroupFlags(SVGSpritesList spritesList) { // now we can unflag sprites foreach (SVGSpriteRef spriteRef in spritesList.Sprites) { // get sprite and its data SVGSpriteAssetFile spriteAsset; if (this.m_GeneratedSpritesFiles.TryGetValue(spriteRef, out spriteAsset)) { SVGSpriteData spriteData = spriteAsset.SpriteData; spriteData.InCurrentInstancesGroup = false; } } }
public void UpdateBorder(SVGSpriteAssetFile spriteAsset, Vector4 newBorder) { SVGSpriteData spriteData = spriteAsset.SpriteData; Sprite oldSprite = spriteData.Sprite; // create a new sprite (same texture, same rectangle, same pivot, different border) Sprite newSprite = Sprite.Create(oldSprite.texture, oldSprite.rect, spriteData.Pivot, SVGBasicAtlas.SPRITE_PIXELS_PER_UNIT, 0, SpriteMeshType.FullRect, newBorder); spriteData.Border = newBorder; newSprite.name = oldSprite.name; // serialized copy from the new sprite (i.e. the sprite with updated border) to the old sprite (i.e. the sprite to be updated) // NB: we use this technique because there isn't an explicit sprite method that allows the change of border property EditorUtility.CopySerialized(newSprite, oldSprite); SVGUtils.MarkObjectDirty(oldSprite); // destroy the temporary sprite GameObject.DestroyImmediate(newSprite); }
private GameObject Instantiate(SVGSpriteAssetFile spriteAsset, int sortingOrder) { SVGSpriteRef spriteRef = spriteAsset.SpriteRef; SVGSpriteData spriteData = spriteAsset.SpriteData; GameObject gameObj = new GameObject(); SpriteRenderer renderer = (SpriteRenderer)gameObj.AddComponent <SpriteRenderer>(); SVGSpriteLoaderBehaviour spriteLoader = (SVGSpriteLoaderBehaviour)gameObj.AddComponent <SVGSpriteLoaderBehaviour>(); renderer.sprite = spriteData.Sprite; renderer.sortingOrder = sortingOrder; spriteLoader.Atlas = this; spriteLoader.SpriteReference = spriteRef; spriteLoader.ResizeOnStart = true; gameObj.name = spriteData.Sprite.name; spriteData.InCurrentInstancesGroup = true; return(gameObj); }
public void UpdatePivot(SVGSpriteAssetFile spriteAsset, Vector2 newPivot) { SVGSpriteRef spriteRef = spriteAsset.SpriteRef; SVGSpriteData spriteData = spriteAsset.SpriteData; Sprite oldSprite = spriteData.Sprite; // keep track of pivot movement Vector2 deltaPivot = newPivot - spriteData.Pivot; Vector2 deltaMovement = (new Vector2(deltaPivot.x * oldSprite.rect.width, deltaPivot.y * oldSprite.rect.height)) / SVGBasicAtlas.SPRITE_PIXELS_PER_UNIT; // create a new sprite (same texture, same rectangle, different pivot) Sprite newSprite = Sprite.Create(oldSprite.texture, oldSprite.rect, newPivot, SVGBasicAtlas.SPRITE_PIXELS_PER_UNIT, 0, SpriteMeshType.FullRect, spriteData.Border); GameObject[] allObjects = GameObject.FindObjectsOfType <GameObject>(); foreach (GameObject gameObj in allObjects) { if (gameObj.activeInHierarchy) { SVGSpriteLoaderBehaviour loader = gameObj.GetComponent <SVGSpriteLoaderBehaviour>(); // we must be sure that the loader component must refer to this atlas if (loader != null && loader.Atlas == this) { // check if the instance uses the specified sprite if (loader.SpriteReference.TxtAsset == spriteRef.TxtAsset && loader.SpriteReference.ElemIdx == spriteRef.ElemIdx) { SVGAtlas.UpdatePivotHierarchy(gameObj, deltaMovement, 0); } } } } spriteData.Pivot = newPivot; newSprite.name = oldSprite.name; EditorUtility.CopySerialized(newSprite, oldSprite); SVGUtils.MarkObjectDirty(oldSprite); // destroy the temporary sprite GameObject.DestroyImmediate(newSprite); }
public GameObject[] InstantiateGroups(SVGAssetInput svgAsset) { SVGSpritesList spritesList; if (svgAsset != null && this.m_GeneratedSpritesLists.TryGetValue(svgAsset.TxtAsset.GetInstanceID(), out spritesList)) { int spritesCount = spritesList.Sprites.Count; int svgIndex = this.SvgAssetIndexGet(svgAsset.TxtAsset); if (svgIndex >= 0 && spritesCount > 0) { // list of sprite assets (file) relative to the specified SVG; in this case we can set the right list capacity List <SVGSpriteAssetFile> spriteAssets = new List <SVGSpriteAssetFile>(spritesCount); bool advanceInstancesGroup = false; // now we are sure that at least one valid sprite box exists float xMin = float.MaxValue; float yMin = float.MaxValue; float xMax = float.MinValue; float yMax = float.MinValue; foreach (SVGSpriteRef spriteRef in spritesList.Sprites) { SVGSpriteAssetFile spriteAsset; if (this.m_GeneratedSpritesFiles.TryGetValue(spriteRef, out spriteAsset)) { SVGSpriteData spriteData = spriteAsset.SpriteData; Sprite sprite = spriteData.Sprite; //float scl = 1 / spriteData.Scale; float scl = 1; float ox = (float)spriteData.OriginalX; float oy = (float)spriteData.OriginalY; float spriteMinX = ox * scl; float spriteMinY = oy * scl; float spriteMaxX = (ox + sprite.rect.width) * scl; float spriteMaxY = (oy + sprite.rect.height) * scl; // update min corner if (spriteMinX < xMin) { xMin = spriteMinX; } if (spriteMinY < yMin) { yMin = spriteMinY; } // update max corner if (spriteMaxX > xMax) { xMax = spriteMaxX; } if (spriteMaxY > yMax) { yMax = spriteMaxY; } // if there is a single sprite already instantiated in the current group, we have to advance in the next instances group if (spriteData.InCurrentInstancesGroup) { advanceInstancesGroup = true; } // keep track of this sprite asset spriteAssets.Add(spriteAsset); } } if (spriteAssets.Count > 0) { // because at least one valid sprite box exists, now we are sure that a valid "global" box has been calculated float centerX = (xMin + xMax) / 2; float centerY = (yMin + yMax) / 2; float boxHeight = yMax - yMin; List <GameObject> instances = new List <GameObject>(); if (advanceInstancesGroup) { // advance in the instances group, telling that we are going to instantiate N sprites this.NextInstancesGroup(svgAsset, spritesList, spriteAssets.Count); } foreach (SVGSpriteAssetFile spriteAsset in spriteAssets) { SVGSpriteData spriteData = spriteAsset.SpriteData; Sprite sprite = spriteData.Sprite; Vector2 pivot = spriteData.Pivot; //float scl = 1 / spriteData.Scale; float scl = 1; float px = (sprite.rect.width * pivot.x + (float)spriteData.OriginalX) * scl - centerX; float py = boxHeight - (sprite.rect.height * (1 - pivot.y) + (float)spriteData.OriginalY) * scl - centerY; Vector2 worldPos = new Vector2(px / SVGBasicAtlas.SPRITE_PIXELS_PER_UNIT, py / SVGBasicAtlas.SPRITE_PIXELS_PER_UNIT); // instantiate the object int sortingOrder = SVGAtlas.SortingOrderCalc(svgIndex, svgAsset.InstanceBaseIdx, spriteData.ZOrder); //instances.Add(this.InstantiateSprite(spriteAsset, worldPos, sortingOrder)); GameObject newObj = this.InstantiateSprite(spriteAsset, worldPos, sortingOrder); newObj.transform.localScale = new Vector3(scl, scl, 1); spriteData.InCurrentInstancesGroup = true; } // return the created instances return(instances.ToArray()); } } } return(null); }
private void UpdateEditorSprites(float newScale) { // get the list of instantiated SVG sprites List <GameObject> spritesInstances = new List <GameObject>(); this.GetSpritesInstances(spritesInstances); // regenerate the list of sprite locations this.m_GeneratedSpritesLists = new SVGSpritesListDictionary(); if (this.m_SvgList.Count <= 0) { AssetDatabase.StartAssetEditing(); // delete previously generated textures (i.e. get all this.GeneratedTextures entries and delete the relative files) this.DeleteTextures(); // delete previously generated sprites (i.e. get all this.GeneratedSprites entries and delete the relative files) this.DeleteSprites(); if (spritesInstances.Count > 0) { bool remove = EditorUtility.DisplayDialog("Missing sprite!", string.Format("{0} gameobjects reference sprites that do not exist anymore. Would you like to remove them from the scene?", spritesInstances.Count), "Remove", "Keep"); if (remove) { this.DeleteGameObjects(spritesInstances); } } AssetDatabase.StopAssetEditing(); // input SVG list is empty, simply reset both hash this.m_SvgListHashOld = this.m_SvgListHashCurrent = ""; return; } // generate textures and sprites List <Texture2D> textures = new List <Texture2D>(); List <KeyValuePair <SVGSpriteRef, SVGSpriteData> > sprites = new List <KeyValuePair <SVGSpriteRef, SVGSpriteData> >(); if (SVGRuntimeGenerator.GenerateSprites(// input this.m_SvgList, this.m_MaxTexturesDimension, this.m_SpritesBorder, this.m_Pow2Textures, newScale, this.m_ClearColor, this.m_FastUpload, this.m_GeneratedSpritesFiles, // output textures, sprites, this.m_GeneratedSpritesLists)) { int i, j; if ((this.m_EditorGenerationScale > 0) && (newScale != this.m_EditorGenerationScale)) { // calculate how much we have to scale (relative) positions float deltaScale = newScale / this.m_EditorGenerationScale; // fix objects positions and animations foreach (GameObject gameObj in spritesInstances) { this.FixPositions(gameObj, deltaScale, deltaScale); } } // keep track of the new generation scale this.m_EditorGenerationScale = newScale; AssetDatabase.StartAssetEditing(); // delete previously generated textures (i.e. get all this.GeneratedTextures entries and delete the relative files) this.DeleteTextures(); // delete previously generated sprites (i.e. get all this.GeneratedSprites entries and delete the relative files) this.DeleteSprites(); // ensure the presence of needed subdirectories string atlasesPath = this.CreateOutputFolders(); string texturesDir = atlasesPath + "/Textures/"; string spritesDir = atlasesPath + "/Sprites/"; // save new texture assets i = 0; foreach (Texture2D texture in textures) { string textureFileName = texturesDir + "texture" + i + ".asset"; // save texture AssetDatabase.CreateAsset(texture, textureFileName); // DEBUG STUFF //byte[] pngData = texture.EncodeToPNG(); //if (pngData != null) // System.IO.File.WriteAllBytes(texturesDir + "texture" + i + ".png", pngData); // keep track of the saved texture this.m_GeneratedTexturesFiles.Add(new AssetFile(textureFileName, texture)); i++; } // save sprite assets j = sprites.Count; for (i = 0; i < j; ++i) { // get sprite reference and its pivot SVGSpriteRef spriteRef = sprites[i].Key; SVGSpriteData spriteData = sprites[i].Value; // build sprite file name string spriteFileName = spritesDir + spriteData.Sprite.name + ".asset"; // save sprite asset AssetDatabase.CreateAsset(spriteData.Sprite, spriteFileName); // keep track of the saved sprite and its pivot this.m_GeneratedSpritesFiles.Add(spriteRef, new SVGSpriteAssetFile(spriteFileName, spriteRef, spriteData)); } AssetDatabase.StopAssetEditing(); // for already instantiated (SVG) game object, set the new sprites // in the same loop we keep track of those game objects that reference missing sprites (i.e. sprites that do not exist anymore) List <GameObject> missingSpriteObjs = new List <GameObject>(); foreach (GameObject gameObj in spritesInstances) { SVGSpriteAssetFile spriteAsset; SVGSpriteLoaderBehaviour spriteLoader = (SVGSpriteLoaderBehaviour)gameObj.GetComponent <SVGSpriteLoaderBehaviour>(); if (spriteLoader.SpriteReference.TxtAsset != null) { if (this.m_GeneratedSpritesFiles.TryGetValue(spriteLoader.SpriteReference, out spriteAsset)) { // link the new sprite to the renderer SpriteRenderer renderer = (SpriteRenderer)gameObj.GetComponent <SpriteRenderer>(); if (renderer != null) { SVGSpriteData spriteData = spriteAsset.SpriteData; // assign the new sprite renderer.sprite = spriteData.Sprite; // NB: existing instances do not change sorting order! } } else { missingSpriteObjs.Add(gameObj); } } } if (missingSpriteObjs.Count > 0) { bool remove = EditorUtility.DisplayDialog("Missing sprite!", string.Format("{0} gameobjects reference sprites that do not exist anymore. Would you like to remove them from the scene?", missingSpriteObjs.Count), "Remove", "Keep"); if (remove) { this.DeleteGameObjects(missingSpriteObjs); } } // now SVG documents are instantiable foreach (SVGAssetInput svgAsset in this.m_SvgList) { svgAsset.Instantiable = true; } // keep track of the new hash this.m_SvgListHashOld = this.m_SvgListHashCurrent; } }
private static bool GenerateSpritesFromBins(// input SVGPackedBin[] bins, Dictionary <uint, PackedSvgDocRef> loadedDocuments, float generationScale, Color clearColor, bool fastUpload, SVGSpritesDictionary previousSprites, // output List <Texture2D> textures, List <KeyValuePair <SVGSpriteRef, SVGSpriteData> > sprites, SVGSpritesListDictionary spritesListDict) { if (bins == null || loadedDocuments == null || textures == null || sprites == null) { return(false); } // sprite reference/key used to get pivot SVGSpriteRef tmpRef = new SVGSpriteRef(null, 0); for (int i = 0; i < bins.Length; ++i) { // extract the bin SVGPackedBin bin = bins[i]; // create drawing surface SVGSurface surface = SVGAssets.CreateSurface(bin.Width, bin.Height); if (surface != null) { // draw packed rectangles of the current bin if (surface.Draw(bin, new SVGColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a), SVGRenderingQuality.Better)) { // bin rectangles SVGPackedRectangle[] rectangles = bin.Rectangles; // create a 2D texture compatible with the drawing surface Texture2D texture = surface.CreateCompatibleTexture(true, false); if (texture != null) { // push the created texture textures.Add(texture); for (int j = 0; j < rectangles.Length; ++j) { PackedSvgDocRef svgDocRef; SVGPackedRectangle rect = rectangles[j]; // get access to the referenced SVG document if (loadedDocuments.TryGetValue(rect.DocHandle, out svgDocRef)) { SVGSpriteAssetFile spriteAsset; Vector2 pivot; Vector4 border; bool inCurrentInstancesGroup; // try to see if this sprite was previously generated, and if so get its pivot tmpRef.TxtAsset = svgDocRef.TxtAsset; tmpRef.ElemIdx = (int)rect.ElemIdx; // get the previous pivot if present, else start with a default centered pivot if (previousSprites.TryGetValue(tmpRef, out spriteAsset)) { float deltaScaleRatio = generationScale / spriteAsset.SpriteData.GenerationScale; pivot = spriteAsset.SpriteData.Pivot; border = spriteAsset.SpriteData.Border * deltaScaleRatio; inCurrentInstancesGroup = spriteAsset.SpriteData.InCurrentInstancesGroup; } else { pivot = new Vector2(0.5f, 0.5f); border = Vector4.zero; inCurrentInstancesGroup = false; } // create a new sprite Sprite sprite = Sprite.Create(texture, new Rect((float)rect.X, (float)((int)bin.Height - rect.Y - rect.Height), (float)rect.Width, (float)rect.Height), pivot, SVGBasicAtlas.SPRITE_PIXELS_PER_UNIT, 0, SpriteMeshType.FullRect, border); sprite.name = svgDocRef.Name + "_" + rect.Name; // push the sprite reference SVGSpriteRef key = new SVGSpriteRef(svgDocRef.TxtAsset, (int)rect.ElemIdx); SVGSpriteData value = new SVGSpriteData(sprite, pivot, border, rect.ZOrder, rect.OriginalX, rect.OriginalY, generationScale, inCurrentInstancesGroup); sprites.Add(new KeyValuePair <SVGSpriteRef, SVGSpriteData>(key, value)); // check if we are interested in getting, for each SVG document, the list of its generated sprites if (spritesListDict != null) { SVGSpritesList spritesList; if (!spritesListDict.TryGetValue(svgDocRef.TxtAsset.GetInstanceID(), out spritesList)) { // create the list of sprites location relative to the SVG text asset spritesList = new SVGSpritesList(); spritesListDict.Add(svgDocRef.TxtAsset.GetInstanceID(), spritesList); } // add the new sprite the its list spritesList.Sprites.Add(key); } // decrement document references if (svgDocRef.Dec(1) == 0) { // we can free AmanithSVG native SVG document svgDocRef.Document.Dispose(); } } } // copy the surface content into the texture if (fastUpload && (Application.isPlaying)) { surface.CopyAndDestroy(texture); } else { if (surface.Copy(texture)) { // call Apply() so it's actually uploaded to the GPU texture.Apply(false, false); } } } } // destroy the AmanithSVG rendering surface surface.Dispose(); } } return(true); }
private GameObject InstantiateWidget(Canvas canvas, SVGSpriteAssetFile spriteAsset, SVGUIWidgetType widgetType) { Image uiImage; InputField inputField = null; SVGSpriteRef spriteRef = spriteAsset.SpriteRef; SVGSpriteData spriteData = spriteAsset.SpriteData; GameObject gameObj = new GameObject(); gameObj.layer = LayerMask.NameToLayer("UI"); // add Image component; NB: it will add a RectTransform component too uiImage = gameObj.AddComponent <Image>(); uiImage.fillCenter = true; uiImage.material = null; uiImage.color = new Color(1.0f, 1.0f, 1.0f, 1.0f); uiImage.sprite = spriteData.Sprite; switch (widgetType) { case SVGUIWidgetType.Button: gameObj.AddComponent <Button>(); break; case SVGUIWidgetType.InputField: inputField = gameObj.AddComponent <InputField>(); break; default: break; } // get RectTransform component and set size according to the associated sprite RectTransform rectTransform = gameObj.GetComponent <RectTransform>(); rectTransform.SetParent(canvas.transform); // attach SVGUISpriteLoaderBehaviour component SVGUISpriteLoaderBehaviour spriteLoader = (SVGUISpriteLoaderBehaviour)gameObj.AddComponent <SVGUISpriteLoaderBehaviour>(); spriteLoader.UIAtlas = this; spriteLoader.SpriteReference = spriteRef; spriteLoader.ResizeOnStart = true; // anchor presets if (widgetType == SVGUIWidgetType.Panel) { rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.localPosition = Vector3.zero; rectTransform.sizeDelta = Vector2.zero; } else { rectTransform.anchorMin = new Vector2(0.5f, 0.5f); rectTransform.anchorMax = new Vector2(0.5f, 0.5f); rectTransform.sizeDelta = new Vector2(spriteData.Sprite.rect.width, spriteData.Sprite.rect.height); } // set image type uiImage.type = (spriteData.Sprite.border != Vector4.zero) ? Image.Type.Sliced : Image.Type.Simple; if (widgetType == SVGUIWidgetType.InputField) { this.PopulateInputField(canvas, gameObj, inputField); } gameObj.name = spriteData.Sprite.name; gameObj.SetActive(true); return(gameObj); }