UltravioletFramework / ultraviolet

The Ultraviolet Framework is a .NET game development framework written in C#.
https://github.com/UltravioletFramework/ultraviolet/wiki
MIT License
542 stars 46 forks source link

Write a new sample detailing the proper use of Surface2D and RenderTarget2D #28

Closed tlgkccampbell closed 8 years ago

tlgkccampbell commented 8 years ago

Multiple people have expressed confusion over the lack of a GetData() method on the Texture2D class. A new sample project, and perhaps additional documentation, could probably be useful for helping Ultraviolet's users find the proper alternative.

ghost commented 8 years ago

Awesome that would be cool, im having few issues with mixing Surface2D and Texture2D, the texture is updated but i get weird bahaviors, here is a gif: http://i.imgur.com/3xYSn6b.gifv

As you can see it starts to flicker as soon as the texture is edited

If i fill the texture in one time, there is no problem, but as i edit it it starts to be buggy

Here is how i do:

I store colors of a texture using Surface2D

                var fileName = Path.GetFileNameWithoutExtension(path);
                var texture = content.Load<Texture2D>("textures/sheets/" + fileName + ".png");
                var surface = Surface2D.Create(texture.Width, texture.Height);
                surface = Surface2D.Create(SurfaceSource.Create(File.Open(path, FileMode.Open)));
                Color[] colors = new Color[texture.Width * texture.Height];
                surface.GetData(colors);

Then once i want to edit a texture i do this:

    public class Chunk
    {
        private Texture2D m_texture;
        public Vector2 Position;
        private Color[] m_chunkPixels;
        private bool m_dirty;

        public Chunk(int offsetX, int offsetY)
        {
            Position = new Vector2(offsetX, offsetY);

            m_texture = Texture2D.Create(TileMap.CHUNK_SIZE * TileMap.TILE_SIZE, TileMap.CHUNK_SIZE * TileMap.TILE_SIZE);

            m_chunkPixels = new Color[m_texture.Width * m_texture.Height];
        }

        public void Draw(SpriteBatch batch)
        {
            batch.Draw(m_texture, new Vector2(Position.X,Position.Y), Color.White);
        }

        public void Update(int time, int delta)
        {
            if (m_dirty)
            {
                m_texture.SetData(m_chunkPixels);
                m_dirty = false;
            }
        }

        public void Paint(int x, int y, TextureData textureData)
        {
            var textureRegion = AssetManager.Instance.GetRegion(textureData);

            int world_x = x * TileMap.TILE_SIZE;
            int world_y = y * TileMap.TILE_SIZE;

            for (int tex = 0; tex < textureRegion.Width; tex++)
            {
                for (int tey = 0; tey < textureRegion.Height; tey++)
                {
                    Color colorHex = textureRegion.GetColor(tex, tey);
                    int width = TileMap.CHUNK_SIZE*TileMap.TILE_SIZE;
                    int pix_x = world_x + tex;
                    int pix_y = world_y + tey;
                    int pix_index = pix_x + pix_y * width;

                    m_chunkPixels[pix_index] = colorHex;
                }
            }

            m_dirty = true;
        }
    }

I don't know why it does this, the code works fine with MonoGame Is it Thread Safe?

tlgkccampbell commented 8 years ago

Interacting with Ultraviolet resources like surfaces and textures is not thread safe. Generally speaking, if you're on a background thread and you're going to modify an Ultraviolet resource, you should queue the operation as a work item using the QueueWorkItem() method on UltravioletContext.

Looking at the MonoGame source code, it looks like it does the equivalent for you automatically as part of SetData(), which is probably where the difference lies.

tlgkccampbell commented 8 years ago

Also, there's some redundancy in your surface loading code. You can load a Surface2D directly through ContentManager:

var surface = content.Load<Surface2D>("textures/sheets/" + fileName + ".png");

And then create the texture from it:

var texture = surface.CreateTexture();

In fact, this is what Ultraviolet does internally when you load a texture.

tlgkccampbell commented 8 years ago

These topics will be covered in Sample 14 and Sample 15, which have been merged to the develop branch and will be available in 1.3.9.

ghost commented 8 years ago

Awesome thanks :p