//Initialise. public void initialise(VectorSpritesEditor vectorSpritesEditor, VectorSprites.VectorSpritesProperties vectorSpritesProperties) { this.vectorSpritesEditor = vectorSpritesEditor; this.vectorSpritesProperties = vectorSpritesProperties; currentSelectableEntity = vectorSpritesProperties.selectedEntity; for (int i = 0; i < vectorSpritesProperties.selectedEntities.Count; i++) { currentShapeGroups.Add(vectorSpritesProperties.selectedEntities[i].primaryID); currentShapes.Add(vectorSpritesProperties.selectedEntities[i].secondaryID); } //Get names and values for the enumerated types. enumeratedTypeNames = new string[Enum.GetNames(typeof(EnumeratedTypeNameArrays)).Length][]; enumeratedTypeValues = new int[enumeratedTypeNames.Length][]; for (int k = 0; k < enumeratedTypeNames.Length; k++) { enumeratedTypeNames[k] = Enum.GetNames(k == 0 ? typeof(VectorSprites.TransformType) : typeof(VectorSprites.TransformOrigin)); enumeratedTypeValues[k] = new int[enumeratedTypeNames[k].Length]; for (int i = 0; i < enumeratedTypeNames[k].Length; i++) { enumeratedTypeValues[k][i] = i; for (int j = 65; j <= 90; j++) { enumeratedTypeNames[k][i] = enumeratedTypeNames[k][i].Replace(((char)j).ToString(), " " + ((char)j).ToString()); } string[] enumeratedTypeNameWords = enumeratedTypeNames[k][i].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); enumeratedTypeNames[k][i] = ""; for (int j = 0; j < enumeratedTypeNameWords.Length; j++) { enumeratedTypeNames[k][i] += enumeratedTypeNameWords[j] + (enumeratedTypeNameWords[j].Length > 1 && j < enumeratedTypeNameWords.Length - 1 ? " " : ""); } } } }
//Initialise. public void initialise(VectorSprites.VectorSpritesProperties vectorSpritesProperties, Material shapeMaterial, Material pillowAndGlowMeshMaterial, Material pillowAndGlowRenderTextureMaterial, VectorSpritesRenderer vectorSpritesRenderer) { //Store properties. this.vectorSpritesProperties = vectorSpritesProperties; if (vectorSpritesProperties.selectedEntity == VectorSprites.SelectableEntity.SpriteSheet) { spriteSheetIndex = vectorSpritesProperties.selectedEntities[0].primaryID; spriteIndex = -1; } else { spriteSheetIndex = -1; spriteIndex = vectorSpritesProperties.selectedEntities[0].primaryID; } //Set all meshes to dirty to ensure they are re-generated (the export quality might not match the editor quality). for (int i = 0; i < vectorSpritesProperties.shapeGroups.Count; i++) { for (int j = 0; j < vectorSpritesProperties.shapeGroups[i].shapes.Count; j++) { vectorSpritesProperties.shapeGroups[i].shapes[j].resetAllMeshes(); } } //Create a list of packing spaces to pack all sprites in. If there is a single sprite, just create a single packing space, otherwise try to fit all //sprites in as smaller space as possible. packingSpaces.Clear(); if (spriteSheetIndex == -1) { packingSpaces.Add(new PackingSpace(0, 0, vectorSpritesProperties.vectorSprites[vectorSpritesProperties.selectedEntities[0].primaryID].width, vectorSpritesProperties.vectorSprites[vectorSpritesProperties.selectedEntities[0].primaryID].height, vectorSpritesProperties.selectedEntities[0].primaryID)); } //If multiple sprites are being added to the sprite sheet, pack the sprites on the sprite sheet in the most efficient way possible. else { //Sort the sprites in descending order of size (maximum dimension), which should produce more efficient packing. List <int> spriteOrder = new List <int>(); for (int i = 0; i < vectorSpritesProperties.vectorSprites.Count; i++) { if (vectorSpritesProperties.vectorSprites[i].spriteSheet == spriteSheetIndex) { spriteOrder.Add(i); } } bool spriteOrderSwapChanges = true; while (spriteOrderSwapChanges) { spriteOrderSwapChanges = false; for (int i = 0; i < spriteOrder.Count - 1; i++) { int thisMaxCoordinate = Math.Max(vectorSpritesProperties.vectorSprites[spriteOrder[i]].width, vectorSpritesProperties.vectorSprites[spriteOrder[i]].height); int nextMaxCoordinate = Math.Max(vectorSpritesProperties.vectorSprites[spriteOrder[i + 1]].width, vectorSpritesProperties.vectorSprites[spriteOrder[i + 1]].height); int thisMinCoordinate = Math.Min(vectorSpritesProperties.vectorSprites[spriteOrder[i]].width, vectorSpritesProperties.vectorSprites[spriteOrder[i]].height); int nextMinCoordinate = Math.Min(vectorSpritesProperties.vectorSprites[spriteOrder[i + 1]].width, vectorSpritesProperties.vectorSprites[spriteOrder[i + 1]].height); if (thisMaxCoordinate < nextMaxCoordinate || (thisMaxCoordinate == nextMaxCoordinate && thisMinCoordinate < nextMinCoordinate)) { int spriteOrderSwap = spriteOrder[i]; spriteOrder[i] = spriteOrder[i + 1]; spriteOrder[i + 1] = spriteOrderSwap; spriteOrderSwapChanges = true; } } } //Start with a single packing space, and loop over the sprites to place into spaces. packingSpaces.Add(new PackingSpace(0, 0, 65536, 65536)); for (int j = 0; j < spriteOrder.Count; j++) { //Get the Vector Sprite. VectorSprites.VectorSprite vectorSprite = vectorSpritesProperties.vectorSprites[spriteOrder[j]]; //Find the best space to put this sprite such that it keeps the overall area as small as possible. ulong lowestTotalArea = ulong.MaxValue; int smallestWastedArea = int.MaxValue; int bestPackingSpaceIndex = -1; for (int k = 0; k < packingSpaces.Count; k++) { if (packingSpaces[k].vectorSpriteIndex == -1) { packingSpaces[k].vectorSpriteIndex = spriteOrder[j]; int oldWidth = packingSpaces[k].width, oldHeight = packingSpaces[k].height; packingSpaces[k].width = vectorSprite.width; packingSpaces[k].height = vectorSprite.height; int newTextureSizeX, newTextureSizeY; getMaximumPackingSize(out newTextureSizeX, out newTextureSizeY); ulong newArea = ((ulong)newTextureSizeX * (ulong)newTextureSizeX) + ((ulong)newTextureSizeY * (ulong)newTextureSizeY); int newWastedArea = (oldWidth * oldHeight) - (vectorSprite.width * vectorSprite.height); if (newArea < lowestTotalArea || (newArea == lowestTotalArea && newWastedArea < smallestWastedArea)) { lowestTotalArea = newArea; smallestWastedArea = newWastedArea; bestPackingSpaceIndex = k; } packingSpaces[k].vectorSpriteIndex = -1; packingSpaces[k].width = oldWidth; packingSpaces[k].height = oldHeight; } } //Put the sprite in the assigned space. int originalWidth = packingSpaces[bestPackingSpaceIndex].width, originalHeight = packingSpaces[bestPackingSpaceIndex].height; packingSpaces[bestPackingSpaceIndex].width = vectorSprite.width; packingSpaces[bestPackingSpaceIndex].height = vectorSprite.height; packingSpaces[bestPackingSpaceIndex].vectorSpriteIndex = spriteOrder[j]; if (originalWidth - packingSpaces[bestPackingSpaceIndex].width > 0) { packingSpaces.Add(new PackingSpace(packingSpaces[bestPackingSpaceIndex].X + packingSpaces[bestPackingSpaceIndex].width, packingSpaces[bestPackingSpaceIndex].Y, originalWidth - packingSpaces[bestPackingSpaceIndex].width, packingSpaces[bestPackingSpaceIndex].height)); } if (originalHeight - packingSpaces[bestPackingSpaceIndex].height > 0) { packingSpaces.Add(new PackingSpace(packingSpaces[bestPackingSpaceIndex].X, packingSpaces[bestPackingSpaceIndex].Y + packingSpaces[bestPackingSpaceIndex].height, originalWidth, originalHeight - packingSpaces[bestPackingSpaceIndex].height)); } } } //Create an output texture, the size of which is the maximum size of all packing spaces. int textureSizeX, textureSizeY; getMaximumPackingSize(out textureSizeX, out textureSizeY); if (textureSizeX > 4096 || textureSizeY > 4096) { Close(); EditorUtility.DisplayDialog("Texture Too Big", "The sprite sheet cannot fit within a texture of size 4096 by 4096 pixels. Try reducing the size " + "of some of the individual sprites, or split the sprites into two sprite sheets.", "OK"); return; } texture = new Texture2D(textureSizeX, textureSizeY, TextureFormat.ARGB32, false); texture.hideFlags = HideFlags.HideAndDontSave; texture.wrapMode = TextureWrapMode.Clamp; RenderTexture clearRenderTexture = new RenderTexture(textureSizeX, textureSizeY, 16, RenderTextureFormat.ARGB32); clearRenderTexture.hideFlags = HideFlags.HideAndDontSave; RenderTexture.active = clearRenderTexture; GL.Clear(true, true, new Color(0, 0, 0, 0)); texture.ReadPixels(new Rect(0, 0, textureSizeX, textureSizeY), 0, 0, false); RenderTexture.active = null; DestroyImmediate(clearRenderTexture); //Loop over all the packing spaces that contain sprites, and add those sprites to the sprite sheet. VectorSprites.SelectableEntity oldSelectedEntity = vectorSpritesProperties.selectedEntity; List <int> oldSelectedEntityPrimaryIDs = new List <int>(); List <int> oldSelectedEntitySecondaryIDs = new List <int>(); for (int i = 0; i < vectorSpritesProperties.selectedEntities.Count; i++) { oldSelectedEntityPrimaryIDs.Add(vectorSpritesProperties.selectedEntities[i].primaryID); oldSelectedEntitySecondaryIDs.Add(vectorSpritesProperties.selectedEntities[i].secondaryID); } vectorSpritesProperties.selectedEntity = VectorSprites.SelectableEntity.Sprite; for (int i = 0; i < packingSpaces.Count; i++) { if (packingSpaces[i].vectorSpriteIndex == -1) { continue; } //Get the sprite and work out its scale. VectorSprites.VectorSprite vectorSprite = vectorSpritesProperties.vectorSprites[packingSpaces[i].vectorSpriteIndex]; Vector2 meshScale = new Vector2(2, 2); if (vectorSprite.spriteRectangleTransform == VectorSprites.SpriteRectangleTransform.Crop) { if (vectorSprite.width > vectorSprite.height) { meshScale.y *= (float)vectorSprite.width / vectorSprite.height; } else { meshScale.x *= (float)vectorSprite.height / vectorSprite.width; } } //Render the sprite to a render texture. Double the size of the render texture if anti-aliasing is enabled (so it can be scaled back down). RenderTexture renderTexture = new RenderTexture(vectorSprite.width * (vectorSprite.antialias ? 2 : 1), vectorSprite.height * (vectorSprite.antialias ? 2 : 1), 16, RenderTextureFormat.ARGB32); renderTexture.hideFlags = HideFlags.HideAndDontSave; vectorSpritesProperties.selectedEntities.Clear(); vectorSpritesProperties.selectedEntities.Add(new VectorSprites.SelectedEntity(packingSpaces[i].vectorSpriteIndex)); vectorSpritesRenderer.render(vectorSpritesProperties, shapeMaterial, pillowAndGlowMeshMaterial, pillowAndGlowRenderTextureMaterial, renderTexture, meshScale, false); //Get the texture directly from the render texture. RenderTexture.active = renderTexture; Texture2D textureFromRenderTexture = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.ARGB32, false); textureFromRenderTexture.hideFlags = HideFlags.HideAndDontSave; textureFromRenderTexture.wrapMode = TextureWrapMode.Clamp; textureFromRenderTexture.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0, false); textureFromRenderTexture.Apply(); RenderTexture.active = null; DestroyImmediate(renderTexture); //Copy the texture to the master texture, scaling down for anti-aliasing purposes if required. renderTexture = new RenderTexture(vectorSprite.width, vectorSprite.height, 16, RenderTextureFormat.ARGB32); renderTexture.hideFlags = HideFlags.HideAndDontSave; Graphics.Blit(textureFromRenderTexture, renderTexture); RenderTexture.active = renderTexture; texture.ReadPixels(new Rect(0, 0, vectorSprite.width, vectorSprite.height), packingSpaces[i].X, packingSpaces[i].Y, false); RenderTexture.active = null; DestroyImmediate(textureFromRenderTexture); DestroyImmediate(renderTexture); } //Apply the changes to the texture. texture.Apply(); //Restore the previous selected entity. vectorSpritesProperties.selectedEntity = oldSelectedEntity; vectorSpritesProperties.selectedEntities.Clear(); for (int i = 0; i < oldSelectedEntityPrimaryIDs.Count; i++) { vectorSpritesProperties.selectedEntities.Add(new VectorSprites.SelectedEntity(oldSelectedEntityPrimaryIDs[i], oldSelectedEntitySecondaryIDs[i])); } //Set all meshes to dirty again so they can be re-generated in the editor, which may have different quality settings from export. for (int i = 0; i < vectorSpritesProperties.shapeGroups.Count; i++) { for (int j = 0; j < vectorSpritesProperties.shapeGroups[i].shapes.Count; j++) { vectorSpritesProperties.shapeGroups[i].shapes[j].resetAllMeshes(); } } }