protected static void SaveLibgdxFile(StreamWriter sw, AtlasNode node)
        {
            // This node write contents only if it is a leaf node
            if (node.name != "Unknown")
            {
                int index = GetIndex(ref node.name);
                // image name
                sw.WriteLine(node.name);
                // rotate
                sw.WriteLine("  rotate: false");
                // xy
                sw.WriteLine("  xy: {0}, {1}", node.rc.X, node.rc.Y);
                // size
                sw.WriteLine("  size: {0}, {1}", node.rc.Width, node.rc.Height);
                // orig
                sw.WriteLine("  orig: {0}, {1}", node.rc.Width, node.rc.Height);
                // offset
                sw.WriteLine("  offset: {0}, {1}", 0, 0);
                // index
                sw.WriteLine("  index: {0}", index);
            }


            if (node.child != null)
            {
                if (node.child[0] != null)
                {
                    SaveLibgdxFile(sw, node.child[0]);
                }
                if (node.child[1] != null)
                {
                    SaveLibgdxFile(sw, node.child[1]);
                }
            }
        }
 public AtlasAllocator(int width, int height)
 {
     m_Root = new AtlasNode();
     m_Root.m_Rect.Set(width, height, 0, 0);
     m_Width  = width;
     m_Height = height;
 }
示例#3
0
        private bool IsUniq(AtlasNode atlasMap)
        {
            var uniqTest = GameController.Memory.ReadStringU(GameController.Memory.Read <long>(atlasMap.Address + 0x3c, 0));

            return(!string.IsNullOrEmpty(uniqTest) && uniqTest.Contains("Uniq") ||
                   Vector2.Distance(atlasMap.Pos, new Vector2(294.979f, 386.641f)) < 5);
        }
示例#4
0
        private void load(AtlasNode root)
        {
            // heavily based on
            // http://www.blackpawn.com/texts/lightmaps/default.html
            // basically it uses a kd-tree to pack the lightmaps

            // TODO: this shoudln't be hardcoded!!
            int outputWidth  = 512;
            int outputHeight = 512;

            _packedTexture = new BitmapSurface(512, 512, null);
            root.AddToBitmap(_packedTexture);

            // create the packed rectangles
            root.UpdateRectList(_packedTextureRects);

            // now we have the rects, but they need to be converted from pixel coords

            /* for (int i = 0; i < _packedTextureRects.Length; i++)
             * {
             *   Rect r = _packedTextureRects[i];
             *   r.X /= outputWidth;
             *   r.Y /= outputHeight;
             *   r.Width /= outputWidth;
             *   r.Height /= outputHeight;
             *
             *   _packedTextureRects[i] = r;
             * }*/

            Utils.WriteTga("lightmap.tga", _packedTexture.Pixels, 512, 512);
        }
示例#5
0
 public AtlasAllocator(int width, int height, bool potPadding)
 {
     m_Root = new AtlasNode();
     m_Root.m_Rect.Set(width, height, 0, 0);
     m_Width           = width;
     m_Height          = height;
     powerOfTwoPadding = potPadding;
 }
示例#6
0
        // The insert function traverses the tree looking for a place to insert the texture. 
        // It returns the node of the atlas the texture can go into or null to say it can't fit. 
        // Note we really don't have to store the rectangle for each node.
        // All we need is a split direction and coordinate like in a kd-tree, but it's more convenient with rects.
        public AtlasNode Insert(Texture2D image, int index)
        {
            if (image == null) // Obviously an error!
                return null;

            if (child != null)
            {// If this node is not a leaf, try inserting into first child.
                AtlasNode newNode = child[0].Insert(image, index);
                if (newNode != null)
                    return newNode;

                // No more room in first child, insert into second child!
                return child[1].Insert(image, index);
            }
            else
            {
                // If there is already a lightmap in this node, early out
                if (hasImage)
                    return null;

                // If this node is too small for the image, return
                if (!ImageFits(image, rc))
                    return null;

                // If the image is perfect, accept!
                if (PerfectFit(image, rc))
                {
                    hasImage = true;
                    imageRef = image;
                    name = imageRef.name;
                    sortIndex = index;
                    return this;
                }

                // If we made it this far, this node must be split.
                child = new AtlasNode[2];
                child[0] = new AtlasNode();
                child[1] = new AtlasNode();

                // Decide which way to split image
                float deltaW = rc.width - image.width;
                float deltaH = rc.height - image.height;

                if (deltaW > deltaH)
                {
                    child[0].rc = new Rect(rc.xMin, rc.yMin, image.width, rc.height);
                    child[1].rc = new Rect(rc.xMin + image.width + TEXTURE_PADDING, rc.yMin, rc.width - (image.width + TEXTURE_PADDING), rc.height);
                }
                else
                {
                    child[0].rc = new Rect(rc.xMin, rc.yMin, rc.width, image.height);
                    child[1].rc = new Rect(rc.xMin, rc.yMin + image.height + TEXTURE_PADDING, rc.width, rc.height - (image.height + TEXTURE_PADDING));
                }

                // Lets try inserting into first child, eh?
                return child[0].Insert(image, index);
            }
        }
 private void KeyboardMouseEvents_MouseDownExt(object sender, Gma.System.MouseKeyHook.MouseEventExtArgs e)
 {
     if (BuyAtlasNode == null)
     {
         return;
     }
     TradeProcessor.OpenBuyMap(BuyAtlasNode.Area.Name, IsUniq(BuyAtlasNode), GameController.Game.IngameState.ServerData.League);
     BuyAtlasNode = null;
 }
示例#8
0
 public AtlasAllocator(int width, int height, bool potPadding)
 {
     m_Root = new AtlasNode();
     m_Root.m_Rect.Set(width, height, 0, 0);
     m_Width           = width;
     m_Height          = height;
     powerOfTwoPadding = potPadding;
     m_NodePool        = new ObjectPool <AtlasNode>(_ => { }, _ => { });
 }
 private void KeyboardMouseEvents_MouseDownExt(object sender, Gma.System.MouseKeyHook.MouseEventExtArgs e)
 {
     if (BuyAtlasNode == null)
     {
         return;
     }
     TradeProcessor.OpenBuyMap(BuyAtlasNode.Area.Name, IsUniq(BuyAtlasNode));
     BuyAtlasNode = null;
 }
示例#10
0
 public void Release()
 {
     if (m_RightChild != null)
     {
         m_RightChild.Release();
         m_BottomChild.Release();
     }
     m_RightChild  = null;
     m_BottomChild = null;
 }
            public AtlasNode Insert(Image surface)
            {
                if (left != null)
                {
                    AtlasNode rv;

                    if (right == null)
                    {
                        throw new InvalidOperationException("AtlasNode(): error");
                    }

                    rv = left.Insert(surface);

                    if (rv == null)
                    {
                        rv = right.Insert(surface);
                    }

                    return(rv);
                }

                int img_width  = surface.Width + padding * 2;
                int img_height = surface.Height + padding * 2;

                if (in_use || img_width > width || img_height > height)
                {
                    return(null);
                }

                if (img_width == width && img_height == height)
                {
                    in_use = true;
                    tex    = surface;
                    return(this);
                }

                if (width - img_width > height - img_height)
                {
                    /* extend to the right */
                    left  = new AtlasNode(x, y, img_width, height, padding);
                    right = new AtlasNode(x + img_width, y,
                                          width - img_width, height, padding);
                }
                else
                {
                    /* extend to bottom */
                    left  = new AtlasNode(x, y, width, img_height, padding);
                    right = new AtlasNode(x, y + img_height,
                                          width, height - img_height, padding);
                }

                return(left.Insert(surface));
            }
 public AtlasNode(int x, int y, int width, int height, int padding)
 {
     left         = null;
     right        = null;
     tex          = null;
     this.x       = x;
     this.y       = y;
     this.width   = width;
     this.height  = height;
     in_use       = false;
     this.padding = padding;
 }
示例#13
0
        public TextureAtlas(BitmapSurface[] surfaces)
        {
            AtlasNode root = new AtlasNode();

            root.Rectangle      = new Rect(0, 0, 512, 512);
            _packedTextureRects = new Rect[surfaces.Length];

            for (int i = 0; i < surfaces.Length; i++)
            {
                root.Insert(surfaces[i], i);
            }

            load(root);
        }
示例#14
0
            public void Release(ref ObjectPool <AtlasNode> pool)
            {
                if (m_RightChild != null)
                {
                    m_RightChild.Release(ref pool);
                    m_BottomChild.Release(ref pool);
                    pool.Release(m_RightChild);
                    pool.Release(m_BottomChild);
                }

                m_RightChild  = null;
                m_BottomChild = null;
                m_Rect        = Vector4.zero;
            }
            public Vector4 m_Rect          = new Vector4(0, 0, 0, 0); // x,y is width and height (scale) z,w offset into atlas (bias)

            public AtlasNode Allocate(int width, int height)
            {
                // not a leaf node, try children
                if (m_RightChild != null)
                {
                    AtlasNode node = m_RightChild.Allocate(width, height);
                    if (node == null)
                    {
                        node = m_BottomChild.Allocate(width, height);
                    }
                    return(node);
                }

                //leaf node, check for fit
                if ((width <= m_Rect.x) && (height <= m_Rect.y))
                {
                    // perform the split
                    m_RightChild  = new AtlasNode();
                    m_BottomChild = new AtlasNode();

                    if (width > height)                           // logic to decide which way to split
                    {                                             //  +--------+------+
                        m_RightChild.m_Rect.z = m_Rect.z + width; //  |        |      |
                        m_RightChild.m_Rect.w = m_Rect.w;         //  +--------+------+
                        m_RightChild.m_Rect.x = m_Rect.x - width; //  |               |
                        m_RightChild.m_Rect.y = height;           //  |               |
                                                                  //  +---------------+
                        m_BottomChild.m_Rect.z = m_Rect.z;
                        m_BottomChild.m_Rect.w = m_Rect.w + height;
                        m_BottomChild.m_Rect.x = m_Rect.x;
                        m_BottomChild.m_Rect.y = m_Rect.y - height;
                    }
                    else
                    {                                                           //  +---+-----------+
                        m_RightChild.m_Rect.z = m_Rect.z + width;               //  |   |           |
                        m_RightChild.m_Rect.w = m_Rect.w;                       //  |   |           |
                        m_RightChild.m_Rect.x = m_Rect.x - width;               //  +---+           +
                        m_RightChild.m_Rect.y = m_Rect.y;                       //  |   |           |
                                                                                //  +---+-----------+
                        m_BottomChild.m_Rect.z = m_Rect.z;
                        m_BottomChild.m_Rect.w = m_Rect.w + height;
                        m_BottomChild.m_Rect.x = width;
                        m_BottomChild.m_Rect.y = m_Rect.y - height;
                    }
                    m_Rect.x = width;
                    m_Rect.y = height;
                    return(this);
                }
                return(null);
            }
示例#16
0
        public bool Allocate(ref Vector4 result, int width, int height)
        {
            AtlasNode node = m_Root.Allocate(width, height, powerOfTwoPadding);

            if (node != null)
            {
                result = node.m_Rect;
                return(true);
            }
            else
            {
                result = Vector4.zero;
                return(false);
            }
        }
示例#17
0
            public Int16 AtlasNodeCreate(Int16 parent)
            {
                Debug.Assert((m_Next < m_Nodes.Length) || (m_FreelistHead != -1), "Error: AtlasNodePool: Out of memory. Please pre-allocate pool to larger capacity");

                if (m_FreelistHead != -1)
                {
                    Int16 freelistHeadNext = m_Nodes[m_FreelistHead].m_FreelistNext;
                    m_Nodes[m_FreelistHead] = new AtlasNode(m_FreelistHead, parent);
                    Int16 res = m_FreelistHead;
                    m_FreelistHead = freelistHeadNext;
                    return(res);
                }

                m_Nodes[m_Next] = new AtlasNode(m_Next, parent);
                return(m_Next++);
            }
示例#18
0
        public TextureAtlas(TextureResource[] textures)
        {
            // heavily based on
            // http://www.blackpawn.com/texts/lightmaps/default.html
            // basically it uses a kd-tree to pack the lightmaps

            AtlasNode root = new AtlasNode();

            root.Rectangle      = new Rect(0, 0, 512, 512);
            _packedTextureRects = new Rect[textures.Length];

            for (int i = 0; i < textures.Length; i++)
            {
                root.Insert(new BitmapSurface(textures[i]), i);
            }

            load(root);
        }
示例#19
0
        private void Initialize()
        {
            AtlasNode atlasnode = m_fontAtlas.atlas.GetNode(m_character);

            MaterialDX11 mat = new MaterialDX11("vDefault.cso", "pText.cso");

            mat.SetMainColor(1.0f, 0.0f, 0.0f, 1.0f);

            mat.AddShaderResourceView(m_fontAtlas.atlas.SRV);


            transform_.Translate(
                ((float)atlasnode.Width / 2.0f),
                -(atlasnode.Height / 2.0f) - atlasnode.YOffset,
                0.0f);

            transform_.SetScale(
                atlasnode.Width,
                atlasnode.Height,
                1.0f);

            //modelrenderer_ = new MeshRenderer(mat, Quad.GetMesh());

            SamplerState state = new SamplerState(ApplicationDX11.Instance.Device, new SamplerStateDescription()
            {
                AddressU           = TextureAddressMode.Wrap,
                AddressV           = TextureAddressMode.Wrap,
                AddressW           = TextureAddressMode.Wrap,
                BorderColor        = new Color4(0.0f, 1.0f, 0.0f, 1.0f),
                ComparisonFunction = Comparison.LessEqual,
                Filter             = Filter.MinLinearMagMipPoint,
                MaximumAnisotropy  = 0,
                MaximumLod         = 0,
                MinimumLod         = 0,
                MipLodBias         = 0
            });

            mat.samplers.Add(state);
            mat.SetTextureXOffset((float)atlasnode.X / (float)m_fontAtlas.atlas.Width);
            mat.SetTextureYOffset((float)atlasnode.Y / (float)m_fontAtlas.atlas.Height);
            mat.SetTextureWidth((float)atlasnode.Width / (float)m_fontAtlas.atlas.Width);
            mat.SetTextureHeight((float)atlasnode.Height / (float)m_fontAtlas.atlas.Height);
        }
示例#20
0
        /// <summary>
        /// Retrieves the final (exported) texture info, with the final texture
        /// id and rect
        /// </summary>
        /// <param name="textureID"></param>
        /// <returns></returns>
        public FinalTexture GetFinalTexture(int textureID)
        {
            TextureInfo info = GetTextureInfo(textureID);

            if (info == null)
            {
                return(null);
            }

            FinalTexture finalTexture = new FinalTexture();

            finalTexture.mRectangle      = new RectangleF(0.0f, 0.0f, 1.0f, 1.0f);
            finalTexture.mFinalTextureID = GetUniqueTextureID(textureID);
            finalTexture.mTextureInfo    = info;

            foreach (TextureAtlas atlas in TextureAtlasses)
            {
                AtlasNode node = atlas.FindNode(info);
                if (node != null)
                {
                    int padding = (info.AtlasPadding < 0) ? mAtlasPadding : info.AtlasPadding;

                    float x = (node.mRectangle.X + padding) / (float)atlas.mRoot.mRectangle.Width;
                    float y = (node.mRectangle.Y + padding) / (float)atlas.mRoot.mRectangle.Height;
                    float w = (node.mRectangle.Width - (padding * 2)) / (float)atlas.mRoot.mRectangle.Width;
                    float h = (node.mRectangle.Height - (padding * 2)) / (float)atlas.mRoot.mRectangle.Height;

                    finalTexture.mRectangle = new RectangleF(x, y, w, h);

                    finalTexture.mFinalTextureID = atlas.mID;
                    finalTexture.mTextureAtlas   = atlas;
                    return(finalTexture);
                }
            }

            return(finalTexture);
        }
示例#21
0
        private void DisposeAtlasNode(AtlasNode node)
        {
            if (node == null)
            {
                return;
            }

            DisposeAtlasNode(node.mLeft);
            DisposeAtlasNode(node.mRight);

            FontBuilder.Glyph glyph = node.mUserData as FontBuilder.Glyph;
            if (glyph != null && glyph.mBitmap != null)
            {
                glyph.mBitmap.Dispose();

                if (node.mImage != glyph.mBitmap)
                {
                    node.mImage.Dispose();
                }

                node.mImage   = null;
                glyph.mBitmap = null;
            }
        }
		/// <summary>
		/// 
		/// </summary>
		/// <param name="buildContext"></param>
		public override void Build ( BuildContext buildContext )
		{
			var fileNames	=	buildContext.ExpandAndResolveSearchPatterns( Dependencies );
			var images		=	fileNames
								.Select( fn => Image.LoadTga( fn ) )
								.OrderByDescending( img0 => img0.Width * img0.Height )
								.ThenByDescending( img1 => img1.Width )
								.ThenByDescending( img2 => img2.Height )
								.ToList();

			if (!images.Any()) {
				throw new InvalidOperationException("At least one subimage must be added to teh texture atlas");
			}


			//
			//	Pack atlas :
			//			
			AtlasNode root = new AtlasNode(0,0, Width, Height, Padding );

			foreach ( var img in images ) {
				var n = root.Insert( img );
				if (n==null) {
					throw new InvalidOperationException("No enough room to place image");
				}
			}

			//
			//	Create image and fill it with atlas elements :
			//	
			var targetImage	=	new Image( Width, Height );
			targetImage.Fill( FillColor );

			root.WriteImages( targetImage );

			//
			//	Save and compress :
			//
			var tgaOutput	=	buildContext.GetTempFileName( AssetPath, ".tga" );
			var ddsOutput	=	buildContext.GetTempFileName( AssetPath, ".dds" );
			Image.SaveTga( targetImage, tgaOutput );

			var compression =	UseDXT ? ImageFileTextureAsset.TextureCompression.BC3 : ImageFileTextureAsset.TextureCompression.RGB;
			ImageFileTextureAsset.RunNVCompress( buildContext, tgaOutput, ddsOutput, NoMips, false, false, true, true, false, compression );


			//
			//	Write binary blob (text + dds texture):
			//
			using ( var fs = buildContext.OpenTargetStream( this ) ) {
				var bw = new BinaryWriter( fs );

				bw.Write(new[]{'A','T','L','S'});
				bw.Write( images.Count ); 

				root.WriteLayout( bw );

				bw.Write( (int)(new FileInfo(ddsOutput).Length) );
				
				using ( var dds = File.OpenRead( ddsOutput ) ) {
					dds.CopyTo( fs );
				}
			}
		}
示例#23
0
            public Vector4 m_Rect          = new Vector4(0, 0, 0, 0); // x,y is width and height (scale) z,w offset into atlas (offset)

            public AtlasNode Allocate(int width, int height, bool powerOfTwoPadding)
            {
                // not a leaf node, try children
                if (m_RightChild != null)
                {
                    AtlasNode node = m_RightChild.Allocate(width, height, powerOfTwoPadding);
                    if (node == null)
                    {
                        node = m_BottomChild.Allocate(width, height, powerOfTwoPadding);
                    }
                    return(node);
                }

                int wPadd = 0;
                int hPadd = 0;

                if (powerOfTwoPadding)
                {
                    wPadd = (int)m_Rect.x % width;
                    hPadd = (int)m_Rect.y % height;
                }

                //leaf node, check for fit
                if ((width <= m_Rect.x - wPadd) && (height <= m_Rect.y - hPadd))
                {
                    // perform the split
                    m_RightChild  = new AtlasNode();
                    m_BottomChild = new AtlasNode();

                    m_Rect.z += wPadd;
                    m_Rect.w += hPadd;
                    m_Rect.x -= wPadd;
                    m_Rect.y -= hPadd;

                    if (width > height) // logic to decide which way to split
                    {
                        //  +--------+------+
                        m_RightChild.m_Rect.z = m_Rect.z + width;               //  |        |      |
                        m_RightChild.m_Rect.w = m_Rect.w;                       //  +--------+------+
                        m_RightChild.m_Rect.x = m_Rect.x - width;               //  |               |
                        m_RightChild.m_Rect.y = height;                         //  |               |
                                                                                //  +---------------+
                        m_BottomChild.m_Rect.z = m_Rect.z;
                        m_BottomChild.m_Rect.w = m_Rect.w + height;
                        m_BottomChild.m_Rect.x = m_Rect.x;
                        m_BottomChild.m_Rect.y = m_Rect.y - height;
                    }
                    else
                    {                                                           //  +---+-----------+
                        m_RightChild.m_Rect.z = m_Rect.z + width;               //  |   |           |
                        m_RightChild.m_Rect.w = m_Rect.w;                       //  |   |           |
                        m_RightChild.m_Rect.x = m_Rect.x - width;               //  +---+           +
                        m_RightChild.m_Rect.y = m_Rect.y;                       //  |   |           |
                                                                                //  +---+-----------+
                        m_BottomChild.m_Rect.z = m_Rect.z;
                        m_BottomChild.m_Rect.w = m_Rect.w + height;
                        m_BottomChild.m_Rect.x = width;
                        m_BottomChild.m_Rect.y = m_Rect.y - height;
                    }
                    m_Rect.x = width;
                    m_Rect.y = height;
                    return(this);
                }
                return(null);
            }
示例#24
0
            public AtlasNode Insert(BitmapSurface surface, int index)
            {
                AtlasNode newNode = null;

                if (Child1 != null && Child2 != null)
                {
                    // not on a leaf...
                    newNode = Child1.Insert(surface, index);
                    if (newNode != null)
                    {
                        return(newNode);
                    }

                    // no room? try the other child...
                    return(Child2.Insert(surface, index));
                }
                else
                {
                    // we're on a leaf!
                    if (Surface != null)
                    {
                        return(null);
                    }

                    int fit = testFit(surface);
                    if (fit > 0)
                    {
                        return(null);         // too big
                    }
                    if (fit == 0)
                    {
                        Surface = surface;
                        Index   = index;
                        return(this);
                    }

                    // guess we need to split this node
                    Child1 = new AtlasNode();
                    Child2 = new AtlasNode();

                    int paddedWidth  = surface.Width + Padding * 2;
                    int paddedHeight = surface.Height + Padding * 2;

                    float dw = Rectangle.Width - paddedWidth;
                    float dh = Rectangle.Height - paddedHeight;

                    if (dw > dh)
                    {
                        Child1.Rectangle = new Rect(Rectangle.X, Rectangle.Y,
                                                    paddedWidth, Rectangle.Height);
                        Child2.Rectangle = new Rect(Rectangle.X + paddedWidth + 1, Rectangle.Y,
                                                    Rectangle.Width - paddedWidth - 1, Rectangle.Height);
                    }
                    else
                    {
                        Child1.Rectangle = new Rect(Rectangle.X, Rectangle.Y,
                                                    Rectangle.Width, paddedHeight);
                        Child2.Rectangle = new Rect(Rectangle.X, Rectangle.Y + paddedHeight + 1,
                                                    Rectangle.Width, Rectangle.Height - paddedHeight - 1);
                    }

                    return(Child1.Insert(surface, index));
                }
            }
        // The insert function traverses the tree looking for a place to insert the texture.
        // It returns the node of the atlas the texture can go into or null to say it can't fit.
        // Note we really don't have to store the rectangle for each node.
        // All we need is a split direction and coordinate like in a kd-tree, but it's more convenient with rects.
        public AtlasNode Insert(Texture2D image, int index)
        {
            if (image == null) // Obviously an error!
            {
                return(null);
            }

            if (child != null)
            {// If this node is not a leaf, try inserting into first child.
                AtlasNode newNode = child[0].Insert(image, index);
                if (newNode != null)
                {
                    return(newNode);
                }

                // No more room in first child, insert into second child!
                return(child[1].Insert(image, index));
            }
            else
            {
                // If there is already a lightmap in this node, early out
                if (hasImage)
                {
                    return(null);
                }

                // If this node is too small for the image, return
                if (!ImageFits(image, rc))
                {
                    return(null);
                }

                // If the image is perfect, accept!
                if (PerfectFit(image, rc))
                {
                    hasImage  = true;
                    imageRef  = image;
                    name      = imageRef.name;
                    sortIndex = index;
                    return(this);
                }

                // If we made it this far, this node must be split.
                child    = new AtlasNode[2];
                child[0] = new AtlasNode();
                child[1] = new AtlasNode();

                // Decide which way to split image
                float deltaW = rc.width - image.width;
                float deltaH = rc.height - image.height;

                if (deltaW > deltaH)
                {
                    child[0].rc = new Rect(rc.xMin, rc.yMin, image.width, rc.height);
                    child[1].rc = new Rect(rc.xMin + image.width + TEXTURE_PADDING, rc.yMin, rc.width - (image.width + TEXTURE_PADDING), rc.height);
                }
                else
                {
                    child[0].rc = new Rect(rc.xMin, rc.yMin, rc.width, image.height);
                    child[1].rc = new Rect(rc.xMin, rc.yMin + image.height + TEXTURE_PADDING, rc.width, rc.height - (image.height + TEXTURE_PADDING));
                }

                // Lets try inserting into first child, eh?
                return(child[0].Insert(image, index));
            }
        }
 public void Release()
 {
     m_Root.Release();
     m_Root = new AtlasNode();
     m_Root.m_Rect.Set(m_Width, m_Height, 0, 0);
 }
示例#27
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="buildContext"></param>
        public override void Process(AssetSource assetFile, BuildContext context)
        {
            var fileDir = Path.GetDirectoryName(assetFile.FullSourcePath);

            var fileNames = File.ReadAllLines(assetFile.FullSourcePath)
                            .Select(f1 => f1.Trim())
                            .Where(f2 => !f2.StartsWith("#") && !string.IsNullOrWhiteSpace(f2))
                            .Select(f3 => Path.Combine(fileDir, f3))
                            .ToArray();


            var depNames = File.ReadAllLines(assetFile.FullSourcePath)
                           .Select(f1 => f1.Trim())
                           .Where(f2 => !f2.StartsWith("#") && !string.IsNullOrWhiteSpace(f2))
                           .Select(f3 => Path.Combine(Path.GetDirectoryName(assetFile.KeyPath), f3))
                           .ToArray();

            var images = fileNames
                         .Select(fn => LoadImage(fn))
                         .OrderByDescending(img0 => img0.Width * img0.Height)
                         .ThenByDescending(img1 => img1.Width)
                         .ThenByDescending(img2 => img2.Height)
                         .ToList();

            if (!images.Any())
            {
                throw new InvalidOperationException("At least one subimage must be added to the texture atlas");
            }


            //
            //	Pack atlas :
            //
            AtlasNode root = new AtlasNode(0, 0, Width, Height, Padding);

            foreach (var img in images)
            {
                var n = root.Insert(img);
                if (n == null)
                {
                    throw new InvalidOperationException("No enough room to place image");
                }
            }

            //
            //	Create image and fill it with atlas elements :
            //
            var targetImage = new Image(Width, Height);

            targetImage.Fill(FillColor);

            root.WriteImages(targetImage);

            //
            //	Save and compress :
            //
            var tgaOutput = context.GetTempFileFullPath(assetFile.KeyPath, ".tga");
            var ddsOutput = context.GetTempFileFullPath(assetFile.KeyPath, ".dds");

            Image.SaveTga(targetImage, tgaOutput);

            var compression = UseDXT ? TextureProcessor.TextureCompression.BC3 : TextureProcessor.TextureCompression.RGB;

            TextureProcessor.RunNVCompress(context, tgaOutput, ddsOutput, NoMips, false, false, true, true, false, compression);


            //
            //	Write binary blob (text + dds texture):
            //
            using (var fs = assetFile.OpenTargetStream(depNames)) {
                var bw = new BinaryWriter(fs);

                bw.Write(new[] { 'A', 'T', 'L', 'S' });
                bw.Write(images.Count);

                root.WriteLayout(bw);

                bw.Write((int)(new FileInfo(ddsOutput).Length));

                using (var dds = File.OpenRead(ddsOutput)) {
                    dds.CopyTo(fs);
                }
            }
        }
        private void DrawAtlasMaps()
        {
            if (!Settings.ShowOnAtlas.Value)
            {
                return;
            }

            var atlas = GameController.Game.IngameState.IngameUi.AtlasPanel;

            if (LastVisible != atlas.IsVisible || CompletedMaps == null)
            {
                LastVisible = atlas.IsVisible;
                if (LastVisible)
                {
                    CompletedMaps      = GameController.Game.IngameState.ServerData.CompletedAreas;
                    BonusCompletedMaps = GameController.Game.IngameState.ServerData.BonusCompletedAreas;
                    ShapeUpgradedMaps  = GameController.Game.IngameState.ServerData.ShapedMaps;
                    ScanPlayerInventForShapersOrb();
                }
            }

            if (!atlas.IsVisible)
            {
                return;
            }

            var root    = atlas.GetChildAtIndex(0);
            var rootPos = new Vector2(root.X, root.Y);
            var scale   = root.Scale;

            BuyAtlasNode = null;
            foreach (var atlasMap in GameController.Files.AtlasNodes.EntriesList)
            {
                var area    = atlasMap.Area;
                var mapName = area.Name;
                if (mapName.Contains("Realm"))
                {
                    continue;
                }

                var centerPos = (atlasMap.Pos * 5.69f + rootPos) * scale;


                var textPos = centerPos;
                textPos.Y -= 30 * scale;
                var testSize  = (int)Math.Round(Settings.TextSize.Value * scale);
                var fontFlags = FontDrawFlags.Center | FontDrawFlags.Bottom;


                byte  textTransp;
                Color textBgColor;
                bool  fill;
                Color fillColor;
                if (BonusCompletedMaps.Contains(area))
                {
                    textTransp  = Settings.BonusCompletedTextTransparency.Value;
                    textBgColor = Settings.BonusCompletedTextBg.Value;
                    fill        = Settings.BonusCompletedFilledCircle.Value;
                    fillColor   = Settings.BonusCompletedFillColor.Value;
                }
                else if (CompletedMaps.Contains(area))
                {
                    textTransp  = Settings.CompletedTextTransparency.Value;
                    textBgColor = Settings.CompletedTextBg.Value;
                    fill        = Settings.CompletedFilledCircle.Value;
                    fillColor   = Settings.CompletedFillColor.Value;
                }
                else
                {
                    textTransp  = Settings.UnCompletedTextTransparency.Value;
                    textBgColor = Settings.UnCompletedTextBg.Value;
                    fill        = Settings.UnCompletedFilledCircle.Value;
                    fillColor   = Settings.UnCompletedFillColor.Value;
                }

                Color textColor = Settings.WhiteMapColor.Value;

                if (area.AreaLevel >= 78)
                {
                    textColor = Settings.RedMapColor.Value;
                }
                else if (area.AreaLevel >= 73)
                {
                    textColor = Settings.YellowMapColor.Value;
                }

                textColor.A = textTransp;

                Graphics.DrawText(mapName, testSize, textPos, textColor, fontFlags);

                var mapNameSize = Graphics.MeasureText(mapName, testSize, fontFlags);
                mapNameSize.Width += 5;
                var nameBoxRect = new RectangleF(textPos.X - mapNameSize.Width / 2, textPos.Y - mapNameSize.Height, mapNameSize.Width, mapNameSize.Height);
                Graphics.DrawBox(nameBoxRect, textBgColor);

                if (WinApi.IsKeyDown(Keys.ControlKey))
                {
                    var upgraded     = ShapeUpgradedMaps.Contains(area);
                    var areaLvlColor = Color.White;
                    var areaLvl      = area.AreaLevel;

                    if (upgraded)
                    {
                        areaLvl     += 5;
                        areaLvlColor = Color.Orange;
                    }

                    var penalty          = LevelXpPenalty(areaLvl);
                    var penaltyTextColor = Color.Lerp(Color.Red, Color.Green, (float)penalty);
                    var labelText        = $"{penalty:p0}";
                    var textSize         = Graphics.MeasureText(labelText, testSize, FontDrawFlags.Left | FontDrawFlags.Bottom);
                    textSize.Width += 6;
                    var penaltyRect = new RectangleF(textPos.X + mapNameSize.Width / 2, textPos.Y - textSize.Height, textSize.Width, textSize.Height);
                    Graphics.DrawBox(penaltyRect, Color.Black);
                    Graphics.DrawText(labelText, testSize, penaltyRect.Center, penaltyTextColor, FontDrawFlags.Center | FontDrawFlags.VerticalCenter);

                    labelText   = $"{areaLvl}";
                    textSize    = Graphics.MeasureText(labelText, testSize, FontDrawFlags.Right | FontDrawFlags.Bottom);
                    penaltyRect = new RectangleF(textPos.X - mapNameSize.Width / 2 - textSize.Width, textPos.Y - textSize.Height, textSize.Width, textSize.Height);
                    Graphics.DrawBox(penaltyRect, Color.Black);
                    Graphics.DrawText(labelText, testSize, penaltyRect.Center, areaLvlColor, FontDrawFlags.Center | FontDrawFlags.VerticalCenter);


                    if (Settings.ShowBuyButton.Value)
                    {
                        var butTextWidth  = 50 * scale;
                        var buyButtonRect = new RectangleF(textPos.X - butTextWidth / 2, textPos.Y - testSize * 2, butTextWidth, testSize);
                        //Graphics.DrawBox(buyButtonRect, Color.Black);
                        //Graphics.DrawPluginImage(System.IO.Path.Combine(PluginDirectory, "images/buy.png"), buyButtonRect, new Color(255, 255, 255, 200));
                        //Graphics.DrawText("Buy$", testSize, buyButtonRect.Center, Color.Yellow, FontDrawFlags.Center | FontDrawFlags.VerticalCenter);

                        if (buyButtonRect.Contains(MousePos))
                        {
                            Graphics.DrawPluginImage(System.IO.Path.Combine(PluginDirectory, "images/buy.png"), buyButtonRect, new Color(255, 255, 255, 255));
                            Graphics.DrawFrame(buyButtonRect, 1, Color.White);
                            BuyAtlasNode = atlasMap;
                        }
                        else
                        {
                            Graphics.DrawPluginImage(System.IO.Path.Combine(PluginDirectory, "images/buy.png"), buyButtonRect, new Color(255, 255, 255, 200));
                        }
                    }
                }
                else
                {
                    BuyAtlasNode = null;
                }
                var imgRectSize = 60 * scale;
                var imgDrawRect = new RectangleF(centerPos.X - imgRectSize / 2, centerPos.Y - imgRectSize / 2, imgRectSize, imgRectSize);

                if (InventShapersOrbs.Count > 0)
                {
                    var areaLvl = area.AreaLevel;

                    if (!ShapeUpgradedMaps.Contains(area))
                    {
                        var tier = areaLvl - 67;

                        if (InventShapersOrbs.Contains(tier))
                        {
                            var shapedRect = imgDrawRect;
                            var sizeOffset = 30 * scale;
                            shapedRect.Left   -= sizeOffset;
                            shapedRect.Right  += sizeOffset;
                            shapedRect.Top    -= sizeOffset;
                            shapedRect.Bottom += sizeOffset;
                            Graphics.DrawPluginImage(System.IO.Path.Combine(PluginDirectory, "images/AtlasMapCircle.png"), shapedRect, new Color(155, 0, 255, 255));
                        }
                    }
                }

                if (fill)
                {
                    Graphics.DrawPluginImage(System.IO.Path.Combine(PluginDirectory, "images/AtlasMapCircleFilled.png"), imgDrawRect, fillColor);
                }

                Graphics.DrawPluginImage(System.IO.Path.Combine(PluginDirectory, "images/AtlasMapCircle.png"), imgDrawRect, Color.Black);

                if (Settings.ShowAmount.Value)
                {
                    if (IsUniq(atlasMap))
                    {
                        mapName += ":Uniq";
                    }

                    if (Settings.MapStashAmount.TryGetValue(mapName, out var amount))
                    {
                        var mapCountSize = Graphics.MeasureText(amount.ToString(), testSize, fontFlags);
                        mapCountSize.Width += 6;
                        Graphics.DrawBox(new RectangleF(centerPos.X - mapCountSize.Width / 2, centerPos.Y - mapCountSize.Height / 2, mapCountSize.Width, mapCountSize.Height), Color.Black);
                        textColor.A = 255;
                        Graphics.DrawText(amount.ToString(), testSize, centerPos, textColor, FontDrawFlags.Center | FontDrawFlags.VerticalCenter);
                    }
                }
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="buildContext"></param>
        public override void Build(BuildContext buildContext)
        {
            var fileNames = buildContext.ExpandAndResolveSearchPatterns(Dependencies);
            var images    = fileNames
                            .Select(fn => Image.LoadTga(fn))
                            .OrderByDescending(img0 => img0.Width * img0.Height)
                            .ThenByDescending(img1 => img1.Width)
                            .ThenByDescending(img2 => img2.Height)
                            .ToList();

            if (!images.Any())
            {
                throw new InvalidOperationException("At least one subimage must be added to teh texture atlas");
            }


            //
            //	Pack atlas :
            //
            AtlasNode root = new AtlasNode(0, 0, Width, Height, Padding);

            foreach (var img in images)
            {
                var n = root.Insert(img);
                if (n == null)
                {
                    throw new InvalidOperationException("No enough room to place image");
                }
            }

            //
            //	Create image and fill it with atlas elements :
            //
            var targetImage = new Image(Width, Height);

            targetImage.Fill(FillColor);

            root.WriteImages(targetImage);

            //
            //	Save and compress :
            //
            var tgaOutput = buildContext.GetTempFileName(AssetPath, ".tga", true);
            var ddsOutput = buildContext.GetTempFileName(AssetPath, ".dds", true);

            Image.SaveTga(targetImage, tgaOutput);

            var compression = UseDXT ? ImageFileTextureAsset.TextureCompression.BC3 : ImageFileTextureAsset.TextureCompression.RGB;

            ImageFileTextureAsset.RunNVCompress(buildContext, tgaOutput, ddsOutput, NoMips, false, false, true, true, false, compression);


            //
            //	Write binary blob (text + dds texture):
            //
            using (var fs = buildContext.TargetStream(this)) {
                var bw = new BinaryWriter(fs);

                bw.Write(new[] { 'A', 'T', 'L', 'S' });
                bw.Write(images.Count);

                root.WriteLayout(bw);

                bw.Write((int)(new FileInfo(ddsOutput).Length));

                using (var dds = File.OpenRead(ddsOutput)) {
                    dds.CopyTo(fs);
                }
            }
        }
        private bool IsUniq(AtlasNode atlasMap)
        {
            string uniqTest = Memory.ReadStringU(Memory.ReadLong(atlasMap.Address + 0x3c, 0));

            return((!string.IsNullOrEmpty(uniqTest) && uniqTest.Contains("Uniq")) || Vector2.Distance(atlasMap.Pos, new Vector2(294.979f, 386.641f)) < 5);
        }
		/// <summary>
		/// 
		/// </summary>
		/// <param name="buildContext"></param>
		public override void Process ( AssetSource assetFile, BuildContext context )
		{
			var fileDir		=	Path.GetDirectoryName( assetFile.FullSourcePath );

			var fileNames	=	File.ReadAllLines(assetFile.FullSourcePath)
								.Select( f1 => f1.Trim() )
								.Where( f2 => !f2.StartsWith("#") && !string.IsNullOrWhiteSpace(f2) )
								.Select( f3 => Path.Combine( fileDir, f3 ) )
								.ToArray();


			var depNames	=	File.ReadAllLines(assetFile.FullSourcePath)
								.Select( f1 => f1.Trim() )
								.Where( f2 => !f2.StartsWith("#") && !string.IsNullOrWhiteSpace(f2) )
								.Select( f3 => Path.Combine( Path.GetDirectoryName(assetFile.KeyPath), f3 ) )
								.ToArray();

			var images		=	fileNames
								.Select( fn => LoadImage( fn ) )
								.OrderByDescending( img0 => img0.Width * img0.Height )
								.ThenByDescending( img1 => img1.Width )
								.ThenByDescending( img2 => img2.Height )
								.ToList();

			if (!images.Any()) {
				throw new InvalidOperationException("At least one subimage must be added to the texture atlas");
			}


			//
			//	Pack atlas :
			//			
			AtlasNode root = new AtlasNode(0,0, Width, Height, Padding );

			foreach ( var img in images ) {
				var n = root.Insert( img );
				if (n==null) {
					throw new InvalidOperationException("No enough room to place image");
				}
			}

			//
			//	Create image and fill it with atlas elements :
			//	
			var targetImage	=	new Image( Width, Height );
			targetImage.Fill( FillColor );

			root.WriteImages( targetImage );

			//
			//	Save and compress :
			//
			var tgaOutput	=	context.GetTempFileName( assetFile.KeyPath, ".tga" );
			var ddsOutput	=	context.GetTempFileName( assetFile.KeyPath, ".dds" );
			Image.SaveTga( targetImage, tgaOutput );

			var compression =	UseDXT ? TextureProcessor.TextureCompression.BC3 : TextureProcessor.TextureCompression.RGB;
			TextureProcessor.RunNVCompress( context, tgaOutput, ddsOutput, NoMips, false, false, true, true, false, compression );


			//
			//	Write binary blob (text + dds texture):
			//
			using ( var fs = assetFile.OpenTargetStream(depNames) ) {
				var bw = new BinaryWriter( fs );

				bw.Write(new[]{'A','T','L','S'});
				bw.Write( images.Count ); 

				root.WriteLayout( bw );

				bw.Write( (int)(new FileInfo(ddsOutput).Length) );
				
				using ( var dds = File.OpenRead( ddsOutput ) ) {
					dds.CopyTo( fs );
				}
			}
		}
			public AtlasNode Insert( Image surface )
			{
				if (left!=null) {
					AtlasNode rv;
					
					if (right==null) {
						throw new InvalidOperationException("AtlasNode(): error");
					}

					rv = left.Insert(surface);
					
					if (rv==null) {
						rv = right.Insert(surface);
					}
					
					return rv;
				}

				int img_width  = surface.Width  + padding * 2;
				int img_height = surface.Height + padding * 2;

				if (in_use || img_width > width || img_height > height) {
					return null;
				}

				if (img_width == width && img_height == height) {
					in_use = true;
					tex = surface;
					return this;
				}

				if (width - img_width > height - img_height) {
					/* extend to the right */
					left = new AtlasNode(x, y, img_width, height, padding);
					right = new AtlasNode(x + img_width, y,
										   width - img_width, height, padding);
				} else {
					/* extend to bottom */
					left = new AtlasNode(x, y, width, img_height, padding);
					right = new AtlasNode(x, y + img_height,
										   width, height - img_height, padding);
				}

				return left.Insert(surface);
			}
			public AtlasNode (int x, int y, int width, int height, int padding)
			{
				left = null;
				right = null;
				tex = null;
				this.x = x;
				this.y = y;
				this.width = width;
				this.height = height;
				in_use = false;
				this.padding = padding;
			}
示例#34
0
        /// <summary>
        /// Reloads the font
        /// </summary>
        public void ReloadFont()
        {
            if (mProject == null)
            {
                return;
            }

            int borderWidth = 2;

            string fullPath = mProject.ProjectDirectory + "/" + mFontFile;

            if (System.IO.File.Exists(fullPath))
            {
                // Ensure that the character list ALWAYS contains at least the ? character.
                if (!Characters.Contains('?'))
                {
                    Characters.Add('?');
                }

                // Load the image glyph textures
                foreach (FontBuilder.ImageGlyph imageGlyph in Images)
                {
                    imageGlyph.Load(mProject.ProjectDirectory);
                }

                if (mFontData != null)
                {
                    mFontData.Dispose();
                }

                mFontData = new FontBuilder.FontData(Characters, Images);
                FontBuilder.Glyph[] glyphs = mFontData.GetGlyphs(fullPath, mFontSize);

                // Clear out our existing textures and texture atlasses
                foreach (TextureAtlas atlas in mTextureAtlasses)
                {
                    DisposeAtlasNode(atlas.mRoot);
                }
                mTextureAtlasses.Clear();

                mTextures.Clear();
                mCharInfoList.Clear();
                mMaxTop = -99999;

                Image  texture       = null;
                Bitmap textureBitmap = null;
                if (File.Exists(mProject.ProjectDirectory + "/" + mTextureFile))
                {
                    texture       = Image.FromFile(mProject.ProjectDirectory + "/" + mTextureFile);
                    textureBitmap = new Bitmap(texture);
                }

                TextureAtlas curAtlas = null;
                foreach (FontBuilder.Glyph glyph in glyphs)
                {
                    if (glyph == null)
                    {
                        continue;
                    }

                    if (mMaxTop < glyph.mTop)
                    {
                        mMaxTop = glyph.mTop;
                    }

                    Bitmap finalBitmap = null;
                    if (glyph.mBitmap != null)
                    {
                        finalBitmap = (borderWidth == 0) ? new Bitmap(glyph.mBitmap) : Utils.ExpandImageBorder(glyph.mBitmap, borderWidth, true);
                        if (finalBitmap == null)
                        {
                            continue;
                        }

                        Bitmap outlinedBitmap = null;
                        Bitmap texturedBitmap = null;

                        if (OutlineAmount > 0.0f && OutlineColor.A != 0)
                        {
                            float s = Math.Min(1.0f, Math.Max(OutlineSharpness, 0.0f));
                            outlinedBitmap = BlurBitmap(finalBitmap, OutlineAmount, OutlineSharpness, OutlineColor);
                            finalBitmap.Dispose();
                            finalBitmap = outlinedBitmap;
                        }

                        BitmapData texturedBitmapData = null;
                        if (textureBitmap != null && glyph.mImageGlyph == 0)
                        {
                            texturedBitmap     = ApplyTexture(textureBitmap, glyph.mBitmap, mTextureBaseline, glyph.mTop);
                            texturedBitmapData = texturedBitmap.LockBits(new Rectangle(0, 0,
                                                                                       texturedBitmap.Width,
                                                                                       texturedBitmap.Height),
                                                                         ImageLockMode.ReadOnly,
                                                                         texturedBitmap.PixelFormat);
                        }

                        // Now we need to use the original bitmap (from the glyph) and reapply it to the new
                        // bitmap (that may or may not have been blurred) with the fill color
                        BitmapData sourceBitmapData = glyph.mBitmap.LockBits(new Rectangle(0, 0, glyph.mBitmap.Width, glyph.mBitmap.Height),
                                                                             ImageLockMode.ReadOnly,
                                                                             glyph.mBitmap.PixelFormat);

                        BitmapData targetBitmapData = finalBitmap.LockBits(new Rectangle((finalBitmap.Width - glyph.mBitmap.Width) / 2,
                                                                                         (finalBitmap.Height - glyph.mBitmap.Height) / 2,
                                                                                         glyph.mBitmap.Width,
                                                                                         glyph.mBitmap.Height),
                                                                           ImageLockMode.WriteOnly,
                                                                           finalBitmap.PixelFormat);

                        try
                        {
                            for (int x = 0; x < sourceBitmapData.Width; x++)
                            {
                                for (int y = 0; y < sourceBitmapData.Height; y++)
                                {
                                    IntPtr sourcePixel  = (IntPtr)((int)sourceBitmapData.Scan0 + sourceBitmapData.Stride * y + x * 4);
                                    IntPtr targetPixel  = (IntPtr)((int)targetBitmapData.Scan0 + targetBitmapData.Stride * y + x * 4);
                                    IntPtr texturePixel = IntPtr.Zero;

                                    if (texturedBitmapData != null)
                                    {
                                        texturePixel = (IntPtr)((int)texturedBitmapData.Scan0 + texturedBitmapData.Stride * y + x * 4);
                                    }

                                    Color srcColor = Color.FromArgb(Marshal.ReadInt32(sourcePixel));
                                    Color tgtColor = Color.FromArgb(Marshal.ReadInt32(targetPixel));
                                    Color texColor = (texturePixel != IntPtr.Zero) ? Color.FromArgb(Marshal.ReadInt32(texturePixel)) : Color.White;

                                    float alpha = srcColor.A / 255.0f;
                                    if (alpha == 0.0f)
                                    {
                                        continue;
                                    }

                                    byte r = (byte)(tgtColor.R * (1.0f - alpha) + FillColor.R * (srcColor.R / 255.0f) * (texColor.R / 255.0f) * alpha);
                                    byte g = (byte)(tgtColor.G * (1.0f - alpha) + FillColor.G * (srcColor.G / 255.0f) * (texColor.G / 255.0f) * alpha);
                                    byte b = (byte)(tgtColor.B * (1.0f - alpha) + FillColor.B * (srcColor.B / 255.0f) * (texColor.B / 255.0f) * alpha);
                                    byte a = (byte)(tgtColor.A * (1.0f - alpha) + FillColor.A * (srcColor.A / 255.0f) * (texColor.A / 255.0f) * alpha);

                                    Color finalColor = Color.FromArgb(a, r, g, b);

                                    Marshal.WriteInt32(targetPixel, finalColor.ToArgb());
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            System.Console.WriteLine("Exception : " + ex);
                        }

                        glyph.mBitmap.UnlockBits(sourceBitmapData);
                        finalBitmap.UnlockBits(targetBitmapData);

                        if (texturedBitmapData != null)
                        {
                            texturedBitmap.UnlockBits(texturedBitmapData);
                        }
                    }
                    else
                    {
                        finalBitmap = new Bitmap(4, 4);
                    }

                    if (curAtlas == null || !curAtlas.AddTexture(finalBitmap, glyph))
                    {
                        curAtlas = new TextureAtlas(0, AtlasSize.Width, AtlasSize.Height, "tmp");
                        mTextureAtlasses.Add(curAtlas);

                        curAtlas.AddTexture(finalBitmap, glyph);
                    }
                }

                if (textureBitmap != null)
                {
                    textureBitmap.Dispose();
                }

                if (texture != null)
                {
                    texture.Dispose();
                }

                // Unload the image glyph textures
                foreach (FontBuilder.ImageGlyph imageGlyph in Images)
                {
                    imageGlyph.Unload();
                }

                // Then iterate and add to the texture atlas(ses).
                if (Otter.Interface.Graphics.Instance != null)
                {
                    foreach (int textureID in mTextures)
                    {
                        Otter.Interface.Graphics.Instance.UnloadTexture(textureID);
                    }

                    foreach (TextureAtlas atlas in mTextureAtlasses)
                    {
                        Bitmap bitmap = atlas.GetBitmap();

                        // BitmapData
                        BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);

                        // Get the address of the first line.
                        IntPtr ptr = bitmapData.Scan0;

                        // Declare an array to hold the bytes of the bitmap.
                        int    size  = Math.Abs(bitmapData.Stride) * bitmap.Height;
                        byte[] bytes = new byte[size];

                        System.Runtime.InteropServices.Marshal.Copy(ptr, bytes, 0, size);

                        int textureID = Otter.Interface.Graphics.Instance.LoadTexture(bytes, bitmap.Width, bitmap.Height, 32);

                        bitmap.UnlockBits(bitmapData);

                        mTextures.Add(textureID);

                        bitmap.Dispose();

                        // SLOW
                        foreach (FontBuilder.Glyph glyph in glyphs)
                        {
                            if (glyph == null)
                            {
                                continue;
                            }

                            AtlasNode node = atlas.FindNode(glyph);

                            if (node != null)
                            {
                                NewCharInfo info = new NewCharInfo();

                                int diffW = node.mRectangle.Width - borderWidth * 2 - glyph.mW;
                                int diffH = node.mRectangle.Height - borderWidth * 2 - glyph.mH;

                                info.mCharCode   = glyph.mCharCode;
                                info.mImageGlyph = glyph.mImageGlyph;
                                info.mX          = node.mRectangle.X + borderWidth;
                                info.mY          = node.mRectangle.Y + borderWidth;
                                info.mW          = glyph.mW + diffW;
                                info.mH          = glyph.mH + diffH;

                                info.mTop         = glyph.mTop + diffH / 2;
                                info.mAdvance     = glyph.mAdvance;
                                info.mLeftBearing = glyph.mLeftBearing - diffW / 2;

                                info.mAtlasIndex = mTextureAtlasses.IndexOf(atlas);

                                mCharInfoList.Add(info);
                            }
                        }
                    }

                    MemoryStream stream = new MemoryStream();

                    Platform platform = new Platform();
                    platform.Endianness  = Endian.Little;
                    platform.ColorFormat = ColorFormat.ARGB;

                    PlatformBinaryWriter bw = new PlatformBinaryWriter(stream, platform);
                    this.Export(bw);

                    mFontID = Otter.Interface.Graphics.Instance.LoadFont(this.Name, stream.GetBuffer(), mTextures);

                    bw.Close();
                    stream.Close();
                }
            }
        }