Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Problem with porting from NinePatch to C#  (Read 12469 times)

0 Members and 1 Guest are viewing this topic.

DeafMan1983

  • Newbie
  • *
  • Posts: 3
    • View Profile
Problem with porting from NinePatch to C#
« on: March 12, 2021, 03:53:02 pm »
Hello I have ported from NinePatch to C#. But It can't display :(

using SFML.Graphics;
using SFML.System;

namespace SFML_Test
{
    public class NinePatch : Transformable, Drawable
    {
        private PrimitiveType m_primitiveType;
        private Vertex[] m_vertices;
        private Texture m_texture;
        private Vector2f m_trimmedSize;
        private Vector2f m_size;
        private Vector2f m_scaleTopLeft;
        private Vector2f m_scaleBottomRight;
        private Vector2f m_contentTopLeft;
        private Vector2f m_contentBottomRight;
        private IntRect m_textureRectangle;
        private Vector2f trimAmount = new Vector2f(1, 1);

        public NinePatch() : base()
        {
            m_primitiveType = PrimitiveType.Quads;
            m_vertices = new Vertex[36];
            m_texture = null;
            m_trimmedSize = new Vector2f(0, 0);
            m_size = new Vector2f(0, 0);
            m_scaleTopLeft = new Vector2f(0, 0);
            m_scaleBottomRight = new Vector2f(0, 0);
            m_contentTopLeft = new Vector2f(0, 0);
            m_contentBottomRight = new Vector2f(0, 0);
            m_textureRectangle = new IntRect(0, 0, 3, 3);
        }

        private void ExtractScalePositionsAndContentAreaFromTexture(Texture pTexture, IntRect textureRectangle, ref Vector2f topLeft, ref Vector2f bottomRight, ref Vector2f contentTopLeft, ref Vector2f contentBottomRight)
        {
            Image image = pTexture.CopyToImage();

            topLeft = new Vector2f(0, 0);
            bottomRight = new Vector2f(textureRectangle.Width - 2f, textureRectangle.Height - 2f);
            bool foundStart = false;
            for (uint x = 1u; x < textureRectangle.Width; x++)
            {
                if (!foundStart)
                {
                    if (image.GetPixel((uint)textureRectangle.Left + x, (uint)textureRectangle.Top) == Color.Black)
                    {
                        foundStart = true;
                        topLeft.X = x - 1f;
                    }
                    else
                        continue;
                }
                if (foundStart)
                {
                    if (image.GetPixel((uint)textureRectangle.Left + x, (uint)textureRectangle.Top) == Color.Black)
                        bottomRight.X = x - 1f;
                    else
                        break;
                }
            }

            for (uint y = 1u; y < textureRectangle.Height; y++)
            {
                if (!foundStart)
                {
                    if (image.GetPixel((uint)textureRectangle.Left, (uint)textureRectangle.Top + y) == Color.Black)
                    {
                        foundStart = true;
                        topLeft.Y = y - 1f;
                    }
                    else
                        continue;
                }
                if (foundStart)
                {
                    if (image.GetPixel((uint)textureRectangle.Left, (uint)textureRectangle.Top + y) == Color.Black)
                        bottomRight.Y = y - 1f;
                    else
                        break;
                }
            }

            contentTopLeft = new Vector2f(0, 0);
            contentBottomRight = new Vector2f(textureRectangle.Width - 2f, textureRectangle.Height - 2f);

            Vector2u textureBottomRightPixel = new Vector2u((uint)textureRectangle.Width - 1u, (uint)textureRectangle.Height - 1u);

            for (uint x = 1u; x < textureRectangle.Width; x++)
            {
                if (!foundStart)
                {
                    if (image.GetPixel((uint)textureRectangle.Left + x, (uint)textureRectangle.Top + textureBottomRightPixel.Y) == Color.Black)
                    {
                        foundStart = true;
                        contentTopLeft.X = x - 1f;
                    }
                    else
                        continue;
                }

                if (foundStart)
                {
                    if (image.GetPixel((uint)textureRectangle.Left + x, (uint)textureRectangle.Top + textureBottomRightPixel.Y) == Color.Black)
                        contentBottomRight.X = x - 1f;
                    else
                        break;
                }
            }

            for(uint y = 1u; y < textureRectangle.Height; y++)
            {
                if (!foundStart)
                {
                    if (image.GetPixel((uint)textureRectangle.Left + textureBottomRightPixel.X, (uint)textureRectangle.Top + y) == Color.Black)
                    {
                        foundStart = true;
                        contentTopLeft.Y = y - 1f;
                    }
                    else
                        continue;
                }

                if (foundStart)
                {
                    if (image.GetPixel((uint)textureRectangle.Left + textureBottomRightPixel.X, (uint)textureRectangle.Top + y) == Color.Black)
                        contentBottomRight.Y = y - 1f;
                    else
                        break;
                }
            }

        }

        public void SetTexture(Texture texture, bool resetsize = true, bool resetrect = true)
        {
            m_texture = texture;
            if (resetrect)
            {
                m_textureRectangle = new IntRect(new Vector2i(0, 0), (Vector2i)m_texture.Size);
            }

            m_trimmedSize = new Vector2f(m_textureRectangle.Width, m_textureRectangle.Height) - trimAmount * 2f;

            if (resetsize)
                m_size = m_trimmedSize;

            ExtractScalePositionsAndContentAreaFromTexture(m_texture, m_textureRectangle, ref m_scaleTopLeft, ref m_scaleBottomRight, ref m_contentTopLeft, ref m_contentBottomRight);
            UpdateVerticies();
        }

        public Vector2f Size
        {
            get
            {
                return m_size;
            }
            set
            {
                m_size = value;
                Vector2f minimumSize = m_scaleTopLeft + (m_trimmedSize - m_scaleBottomRight);
                if (m_size.X < minimumSize.X)
                    m_size.X = minimumSize.X;
                if (m_size.Y < minimumSize.Y)
                    m_size.Y = minimumSize.Y;
                UpdateVerticiesPositions();
            }
        }

        public Color Color
        {
            get
            {
                return m_vertices[0].Color;
            }
            set
            {
                foreach (Vertex vertex in m_vertices)
                {
                    Vertex tempvex = vertex;
                    tempvex.Color = value;
                }
            }
        }

        public FloatRect LocalBounds
        {
            get
            {
                return new FloatRect(new Vector2f(0, 0), m_size);
            }
        }

        public FloatRect GlocalBounds
        {
            get
            {
                return Transform.TransformRect(LocalBounds);
            }
        }

        public FloatRect LocalContentArea
        {
            get
            {
                Vector2f topleft = GetResultingPositionOfTexCoord(m_contentTopLeft);
                return new FloatRect(topleft, GetResultingPositionOfTexCoord(m_contentBottomRight) - topleft + new Vector2f(1, 1));
            }
        }

        public FloatRect GlocalContentArea
        {
            get
            {
                return Transform.TransformRect(LocalContentArea);
            }
        }

        public void SetTextureRect(IntRect texrect, bool resetsize = true)
        {
            m_textureRectangle = texrect;
            m_trimmedSize = new Vector2f(m_textureRectangle.Width, m_textureRectangle.Height) - trimAmount * 2f;

            if (resetsize)
                m_size = m_trimmedSize;

            if (m_texture != null)
            {
                ExtractScalePositionsAndContentAreaFromTexture(m_texture, m_textureRectangle, ref m_scaleTopLeft, ref m_scaleBottomRight, ref m_contentTopLeft, ref m_contentBottomRight);
                UpdateVerticies();
            }

        }

        public void ResetSize()
        {
            Size = m_trimmedSize;
        }

        public bool IsPointInsideTransformedContentArea(Vector2f point)
        {
            return LocalContentArea.Contains(InverseTransform.TransformPoint(point).X, InverseTransform.TransformPoint(point).Y);
        }

        public void Draw(RenderTarget target, RenderStates states)
        {
            states.Texture = m_texture;
            states.Transform = Transform;
            target.Draw(m_vertices, m_primitiveType, states);
        }

        private void UpdateVerticies()
        {
            UpdateVerticiesPositions();
            UpdateVerticiesTextCoords();
        }

        private void UpdateVerticiesPositions()
        {
            Vector2f newBottomRightScaled = m_size - (m_trimmedSize - m_scaleBottomRight);

            // top row
            m_vertices[0].Position = new Vector2f(0f, 0f);
            m_vertices[1].Position = new Vector2f(m_scaleTopLeft.X, 0f);
            m_vertices[2].Position = m_scaleTopLeft;
            m_vertices[3].Position = new Vector2f(0f, m_scaleTopLeft.Y);

            m_vertices[4].Position = new Vector2f(m_scaleTopLeft.Y, 0f);
            m_vertices[5].Position = new Vector2f(newBottomRightScaled.X, 0f);
            m_vertices[6].Position = new Vector2f(newBottomRightScaled.X, m_scaleTopLeft.Y);
            m_vertices[7].Position = m_scaleTopLeft;

            m_vertices[8].Position = new Vector2f(newBottomRightScaled.X, 0f );
            m_vertices[9].Position = new Vector2f(m_size.X, 0f);
            m_vertices[10].Position = new Vector2f( m_size.X, m_scaleTopLeft.Y );
            m_vertices[11].Position = new Vector2f(newBottomRightScaled.X, m_scaleTopLeft.X );

            // centre row
            m_vertices[12].Position = new Vector2f(0f, m_scaleTopLeft.Y);
            m_vertices[13].Position = new Vector2f(m_scaleTopLeft.X, m_scaleTopLeft.Y);
            m_vertices[14].Position = new Vector2f(m_scaleTopLeft.X, newBottomRightScaled.Y);
            m_vertices[15].Position = new Vector2f(0f, newBottomRightScaled.Y );

            m_vertices[16].Position = new Vector2f( m_scaleTopLeft.X, m_scaleTopLeft.Y);
            m_vertices[17].Position = new Vector2f(newBottomRightScaled.X, m_scaleTopLeft.Y);
            m_vertices[18].Position = new Vector2f(newBottomRightScaled.X, newBottomRightScaled.Y );
            m_vertices[19].Position = new Vector2f(m_scaleTopLeft.X, newBottomRightScaled.Y);

            m_vertices[20].Position = new Vector2f(newBottomRightScaled.X, m_scaleTopLeft.Y);
            m_vertices[21].Position = new Vector2f(m_size.X, m_scaleTopLeft.Y);
            m_vertices[22].Position = new Vector2f(m_size.X, newBottomRightScaled.Y);
            m_vertices[23].Position = new Vector2f(newBottomRightScaled.X, newBottomRightScaled.Y);

            // bottom row
            m_vertices[24].Position = new Vector2f(0f, newBottomRightScaled.Y);
            m_vertices[25].Position = new Vector2f(m_scaleTopLeft.X, newBottomRightScaled.Y);
            m_vertices[26].Position = new Vector2f(m_scaleTopLeft.X, m_size.Y);
            m_vertices[27].Position = new Vector2f(0f, m_size.Y);

            m_vertices[28].Position = new Vector2f(m_scaleTopLeft.X, newBottomRightScaled.Y);
            m_vertices[29].Position = new Vector2f(newBottomRightScaled.X, newBottomRightScaled.Y);
            m_vertices[30].Position = new Vector2f(newBottomRightScaled.X, m_size.Y );
            m_vertices[31].Position = new Vector2f(m_scaleTopLeft.X, m_size.Y);

            m_vertices[32].Position = new Vector2f(newBottomRightScaled.X, newBottomRightScaled.Y);
            m_vertices[33].Position = new Vector2f(m_size.X, newBottomRightScaled.Y);
            m_vertices[34].Position = new Vector2f(m_size.X, m_size.Y);
            m_vertices[35].Position = new Vector2f(newBottomRightScaled.X, m_size.Y);
        }

        private void UpdateVerticiesTextCoords()
        {
            Vector2f textureBottomRight = m_trimmedSize;

            // top row
            m_vertices[0].TexCoords = new Vector2f(0, 0);
            m_vertices[1].TexCoords = new Vector2f(m_scaleTopLeft.X, 0);
            m_vertices[2].TexCoords = m_scaleTopLeft;
            m_vertices[3].TexCoords = new Vector2f(0f, m_scaleTopLeft.Y);

            m_vertices[4].TexCoords = new Vector2f(m_scaleTopLeft.X, 0f );
            m_vertices[5].TexCoords = new Vector2f(m_scaleBottomRight.X, 0f );
            m_vertices[6].TexCoords = new Vector2f(m_scaleBottomRight.X, m_scaleTopLeft.Y );
            m_vertices[7].TexCoords = m_scaleTopLeft;

            m_vertices[8].TexCoords = new Vector2f(m_scaleBottomRight.X, 0f);
            m_vertices[9].TexCoords = new Vector2f(textureBottomRight.X, 0f );
            m_vertices[10].TexCoords = new Vector2f(textureBottomRight.X, m_scaleTopLeft.Y );
            m_vertices[11].TexCoords = new Vector2f(m_scaleBottomRight.X, m_scaleTopLeft.Y );

            // centre row
            m_vertices[12].TexCoords = new Vector2f( 0f, m_scaleTopLeft.Y );
            m_vertices[13].TexCoords = m_scaleTopLeft;
            m_vertices[14].TexCoords = new Vector2f( m_scaleTopLeft.X, m_scaleBottomRight.Y );
            m_vertices[15].TexCoords = new Vector2f(0f, m_scaleBottomRight.Y);

            m_vertices[16].TexCoords = m_scaleTopLeft;
            m_vertices[17].TexCoords = new Vector2f(m_scaleBottomRight.X, m_scaleTopLeft.Y);
            m_vertices[18].TexCoords = m_scaleBottomRight;
            m_vertices[19].TexCoords = new Vector2f(m_scaleTopLeft.X, m_scaleBottomRight.Y );

            m_vertices[20].TexCoords = new Vector2f(m_scaleBottomRight.X, m_scaleTopLeft.Y);
            m_vertices[21].TexCoords = new Vector2f(textureBottomRight.X, m_scaleTopLeft.Y );
            m_vertices[22].TexCoords = new Vector2f(textureBottomRight.X, m_scaleBottomRight.Y);
            m_vertices[23].TexCoords = m_scaleBottomRight;

            // bottom row
            m_vertices[24].TexCoords = new Vector2f(0f, m_scaleBottomRight.Y );
            m_vertices[25].TexCoords = new Vector2f(m_scaleTopLeft.X, m_scaleBottomRight.Y );
            m_vertices[26].TexCoords = new Vector2f(m_scaleTopLeft.X, textureBottomRight.Y );
            m_vertices[27].TexCoords = new Vector2f(0f, textureBottomRight.Y );

            m_vertices[28].TexCoords = new Vector2f(m_scaleTopLeft.X, m_scaleBottomRight.Y);
            m_vertices[29].TexCoords = m_scaleBottomRight;
            m_vertices[30].TexCoords = new Vector2f(m_scaleBottomRight.X, textureBottomRight.Y);
            m_vertices[31].TexCoords = new Vector2f(m_scaleTopLeft.X, textureBottomRight.Y );

            m_vertices[32].TexCoords = m_scaleBottomRight;
            m_vertices[33].TexCoords = new Vector2f(textureBottomRight.X, m_scaleBottomRight.Y );
            m_vertices[34].TexCoords = textureBottomRight;
            m_vertices[35].TexCoords = new Vector2f(m_scaleBottomRight.X, textureBottomRight.Y );

            Vector2f textureRectangleOffset = new Vector2f(m_textureRectangle.Left, m_textureRectangle.Top);
            foreach ( Vertex vertex in m_vertices)
            {
                Vector2f texCoords = vertex.TexCoords;
                texCoords += textureRectangleOffset + trimAmount;
            }
        }

        private Vector2f GetResultingPositionOfTexCoord(Vector2f textureCoords)
        {
            Vector2f result = new Vector2f();

            Vector2f newBottomRightScaled = m_size - (m_trimmedSize - m_scaleBottomRight);
            Vector2f scaleSize = m_scaleBottomRight - m_scaleTopLeft;
            Vector2f newScaleSize = newBottomRightScaled - m_scaleTopLeft;

            if (textureCoords.X <= m_scaleTopLeft.X)
                result.X = textureCoords.X;
            else if (textureCoords.X >= m_scaleTopLeft.X)
                result.X = newBottomRightScaled.X + (textureCoords.X - m_scaleBottomRight.X);
            else
                result.X = (textureCoords.X- m_scaleTopLeft.X) / scaleSize.X * newScaleSize.X + m_scaleTopLeft.X;

            if (textureCoords.Y <= m_scaleTopLeft.Y)
                result.Y = textureCoords.Y;
            else if (textureCoords.Y >= m_scaleTopLeft.Y)
                result.Y = newBottomRightScaled.Y + (textureCoords.Y - m_scaleBottomRight.Y);
            else
                result.Y = (textureCoords.Y - m_scaleTopLeft.Y) / scaleSize.Y * newScaleSize.Y + m_scaleTopLeft.Y;

            return result;
        }
    }
}
This code was ported from Github NinePatch

But It can't display and I have downloaded picture into root directory of my compiled Release version of executable.

I have tried...
using System;
using System.IO;

namespace SFML_Test
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Hello SMFL.Net!");
            new SimpleWindow().Run();
        }

        class SimpleWindow
        {
            public void Run()
            {
                var mode = new SFML.Window.VideoMode(800, 600, 32);
                var window = new SFML.Graphics.RenderWindow(mode, "SFML works!", SFML.Window.Styles.Default);
                var orange = new SFML.Graphics.Color(255, 102, 0);
                var texture = new SFML.Graphics.Texture(Path.Combine("pixelcyan9patch.png"));
                var nine9sprite = new NinePatch();
                nine9sprite.SetTexture(texture);
                window.Position = new SFML.System.Vector2i((int)(SFML.Window.VideoMode.DesktopMode.Width - window.Size.X) / 2, (int)(SFML.Window.VideoMode.DesktopMode.Height - window.Size.Y) / 2);
                window.KeyPressed += Window_KeyPressed;
                window.Closed += Window_Closed;
                window.Resized += Window_Resized;

                var context = new SFML.Window.Context();
                context.SetActive(true);

                while (window.IsOpen)
                {
                    // Process events
                    window.DispatchEvents();
                    SFML.System.Vector2f mousePosition = window.MapPixelToCoords(SFML.Window.Mouse.GetPosition());
                    nine9sprite.Size = mousePosition;
                    window.Clear(orange);
                    window.Draw(nine9sprite);
                    window.Display();
                }
            }

            private void Window_KeyPressed(object sender, SFML.Window.KeyEventArgs e)
            {
                var window = (SFML.Window.Window)sender;
                if (e.Code == SFML.Window.Keyboard.Key.Escape)
                {
                    window.Close();
                }
            }

            private void Window_Closed(object sender, EventArgs e)
            {
                var window = (SFML.Graphics.RenderWindow)sender;
                window.Close();
            }

            private void Window_Resized(object sender, SFML.Window.SizeEventArgs e)
            {
                var window = (SFML.Graphics.RenderWindow)sender;
                window.DefaultView.Size = new SFML.System.Vector2f(e.Width, e.Height);
            }
        }
    }
}
And I have same picture name by SalbeWard.
Result: picture doesn't show....

How do I resolve if image loads into SFML and doesn't shows me.

Thanks!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Problem with porting from NinePatch to C#
« Reply #1 on: March 19, 2021, 09:32:29 pm »
Hard to say without spending quite some time on it.
I suggest to run it through the debugger and double checking that all the values are correctly set and calculated.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

kojack

  • Sr. Member
  • ****
  • Posts: 343
  • C++/C# game dev teacher.
    • View Profile
Re: Problem with porting from NinePatch to C#
« Reply #2 on: May 02, 2021, 06:27:36 am »
The vertex array used to draw the patch has all of it's colour members defaulting to (0,0,0,0), so the patch is fully transparent (ie. invisible).
After making the patch, call this:
nine9sprite.Color = Color.White;

However this won't work yet, because there's a bug in the Color property setter. This is the current code:
        public Color Color
        {
            get
            {
                return m_vertices[0].Color;
            }
            set
            {
                foreach (Vertex vertex in m_vertices)
                {
                    Vertex tempvex = vertex;
                    tempvex.Color = value;
                }
            }
        }
The foreach loop goes over every vertex, but assigns the colour to a temp vertex, not the actual vertex array.
C# doesn't like foreach loops that modify values (if Vertex was a class, it would be ok, but as a struct, the foreach variable "vertex" is read only). So we need to change it to a normal loop like this:
        public Color Color
        {
            get
            {
                return m_vertices[0].Color;
            }
            set
            {
                for(int i=0;i<m_vertices.Length;++i)
                {
                    m_vertices[i].Color = value;
                }
            }
        }

After both of those changes, it's rendering.