/// <summary> /// Add a dark shadowy outline around the sprite, giving it some visual depth. /// </summary> void AddOutline(UISpriteData sprite) { var sprites = new List <UIAtlasMaker.SpriteEntry>(); UIAtlasMaker.ExtractSprites(mAtlas, sprites); UIAtlasMaker.SpriteEntry se = null; for (int i = 0; i < sprites.Count; ++i) { if (sprites[i].name == sprite.name) { se = sprites[i]; break; } } if (se != null) { int w1 = se.tex.width; int h1 = se.tex.height; int w2 = w1 + 2; int h2 = h1 + 2; var c2 = NGUIEditorTools.AddBorder(se.tex.GetPixels32(), w1, h1); NGUIEditorTools.AddDepth(c2, w2, h2, NGUISettings.backgroundColor); if (se.temporaryTexture) { DestroyImmediate(se.tex); } if ((se.borderLeft | se.borderRight | se.borderBottom | se.borderTop) != 0) { ++se.borderLeft; ++se.borderRight; ++se.borderTop; ++se.borderBottom; } se.tex = new Texture2D(w2, h2); se.tex.name = sprite.name; se.tex.SetPixels32(c2); se.tex.Apply(); se.temporaryTexture = true; var before = NGUISettings.atlasTrimming; NGUISettings.atlasTrimming = false; UIAtlasMaker.UpdateAtlas(mAtlas, sprites); NGUISettings.atlasTrimming = before; DestroyImmediate(se.tex); se.tex = null; } }
/// <summary> /// Apply an effect to the font. /// </summary> void ApplyEffect(Effect effect, Color foreground, Color background) { BMFont bf = mFont.bmFont; int offsetX = 0; int offsetY = 0; if (mFont.atlas != null) { UISpriteData sd = mFont.atlas.GetSprite(bf.spriteName); if (sd == null) { return; } offsetX = sd.x; offsetY = sd.y + mFont.texHeight - sd.paddingTop; } string path = AssetDatabase.GetAssetPath(mFont.texture); Texture2D bfTex = NGUIEditorTools.ImportTexture(path, true, true, false); Color32[] atlas = bfTex.GetPixels32(); // First we need to extract textures for all the glyphs, making them bigger in the process List <BMGlyph> glyphs = bf.glyphs; List <Texture2D> glyphTextures = new List <Texture2D>(glyphs.Count); for (int i = 0, imax = glyphs.Count; i < imax; ++i) { BMGlyph glyph = glyphs[i]; if (glyph.width < 1 || glyph.height < 1) { continue; } int width = glyph.width; int height = glyph.height; if (effect == Effect.Outline || effect == Effect.Shadow || effect == Effect.Border) { width += 2; height += 2; --glyph.offsetX; --glyph.offsetY; } else if (effect == Effect.Crop && width > 2 && height > 2) { width -= 2; height -= 2; ++glyph.offsetX; ++glyph.offsetY; } int size = width * height; Color32[] colors = new Color32[size]; Color32 clear = background; clear.a = 0; for (int b = 0; b < size; ++b) { colors[b] = clear; } if (effect == Effect.Crop) { for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { int fx = x + glyph.x + offsetX + 1; int fy = y + (mFont.texHeight - glyph.y - glyph.height) + 1; if (mFont.atlas != null) { fy += bfTex.height - offsetY; } colors[x + y * width] = atlas[fx + fy * bfTex.width]; } } } else { for (int y = 0; y < glyph.height; ++y) { for (int x = 0; x < glyph.width; ++x) { int fx = x + glyph.x + offsetX; int fy = y + (mFont.texHeight - glyph.y - glyph.height); if (mFont.atlas != null) { fy += bfTex.height - offsetY; } Color c = atlas[fx + fy * bfTex.width]; if (effect == Effect.Border) { colors[x + 1 + (y + 1) * width] = c; } else { if (effect == Effect.AlphaCurve) { c.a = Mathf.Clamp01(mCurve.Evaluate(c.a)); } Color bg = background; bg.a = (effect == Effect.BackgroundCurve) ? Mathf.Clamp01(mCurve.Evaluate(c.a)) : c.a; Color fg = foreground; fg.a = (effect == Effect.ForegroundCurve) ? Mathf.Clamp01(mCurve.Evaluate(c.a)) : c.a; if (effect == Effect.Outline || effect == Effect.Shadow) { colors[x + 1 + (y + 1) * width] = Color.Lerp(bg, c, c.a); } else { colors[x + y * width] = Color.Lerp(bg, fg, c.a); } } } } // Apply the appropriate affect if (effect == Effect.Shadow) { NGUIEditorTools.AddShadow(colors, width, height, NGUISettings.backgroundColor); } else if (effect == Effect.Outline) { NGUIEditorTools.AddDepth(colors, width, height, NGUISettings.backgroundColor); } } Texture2D tex = new Texture2D(width, height, TextureFormat.ARGB32, false); tex.SetPixels32(colors); tex.Apply(); glyphTextures.Add(tex); } // Pack all glyphs into a new texture Texture2D final = new Texture2D(bfTex.width, bfTex.height, TextureFormat.ARGB32, false); Rect[] rects = final.PackTextures(glyphTextures.ToArray(), 1); final.Apply(); // Make RGB channel use the background color (Unity makes it black by default) Color32[] fcs = final.GetPixels32(); Color32 bc = background; for (int i = 0, imax = fcs.Length; i < imax; ++i) { if (fcs[i].a == 0) { fcs[i].r = bc.r; fcs[i].g = bc.g; fcs[i].b = bc.b; } } final.SetPixels32(fcs); final.Apply(); // Update the glyph rectangles int index = 0; int tw = final.width; int th = final.height; for (int i = 0, imax = glyphs.Count; i < imax; ++i) { BMGlyph glyph = glyphs[i]; if (glyph.width < 1 || glyph.height < 1) { continue; } Rect rect = rects[index++]; glyph.x = Mathf.RoundToInt(rect.x * tw); glyph.y = Mathf.RoundToInt(rect.y * th); glyph.width = Mathf.RoundToInt(rect.width * tw); glyph.height = Mathf.RoundToInt(rect.height * th); glyph.y = th - glyph.y - glyph.height; } // Update the font's texture dimensions mFont.texWidth = final.width; mFont.texHeight = final.height; if (mFont.atlas == null) { // Save the final texture byte[] bytes = final.EncodeToPNG(); NGUITools.DestroyImmediate(final); System.IO.File.WriteAllBytes(path, bytes); AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); } else { // Update the atlas final.name = mFont.spriteName; bool val = NGUISettings.atlasTrimming; NGUISettings.atlasTrimming = false; UIAtlasMaker.AddOrUpdate(mFont.atlas, final); NGUISettings.atlasTrimming = val; NGUITools.DestroyImmediate(final); } // Cleanup for (int i = 0; i < glyphTextures.Count; ++i) { NGUITools.DestroyImmediate(glyphTextures[i]); } // Refresh all labels mFont.MarkAsChanged(); }