Loading a sprite from ContentManager will always have the same address?

I recently discovered something odd. I used a Texture to modify pixels (specific ones to specific colors), so i decided to reuse the same texture and create a random pixel random color demonstration as well. The thing i was not expecting is that when loading the Content from the manager even with two separate variables for each Texture2D object, they share the same memory address so the changes i made on each separately in code effected eachother the same. I looked at trying to do a Clone or a Memberwise close but that won’t compile. Basically i want to use the same texture over and over and manipulate in different objects that change them separately, here’s a screen of what i have so far, by adding the same image under a different name in the ContentManager but i would rather not have to do this, say i wanted to create an army of units and it would be easier to load one content and be able to recolor them. I would never have thought that the content manager would cause this sort of issue, i just assumed it would give me a new address each time i loaded it into a different texture object.
//I analyzed the memory addresses on two separate runs to verify my hunch of why this happened
_nativePointer = 0x000002106ccd61f8 //RecolorBox
_nativePointer = 0x000002106ccd61f8 //RandomRecolorBox

_nativePointer = 0x0000025d279e9f38 //RecolorBox
_nativePointer = 0x0000025d279e9f38 //RandomRecolorBox

I am even storing these objects in separate texture objects here:

public RecolorBox(Texture2D texture, Vector2 position, Color color)
{
this.texture = texture;
this.position = position;
this.color = color;
this.drawRect = new Rectangle(0, 0, this.texture.Width, this.texture.Height);
//this.spriteBatch = spriteBatch;
}

public RandomRecolorBox(Texture2D texture, Vector2 position, Color color)
{
this.texture = texture;
this.position = position;
this.color = color;
this.drawRect = new Rectangle(0, 0, this.texture.Width, this.texture.Height);
this.random = new Random();
//this.spriteBatch = spriteBatch;
}

posting here in case this is a potential bug with Xna and or Monogame

This behavior by the content loader is intentional. I would say that when drawing these textures, use a shader to alter them at draw-time. If you really need to programmatically store/alter/use 2 different textures based on the same Texture2D content source you can do so by making a RenderTarget2D and then drawing the texture to that. You can then manipulate that “copy” of the texture however you like without it effecting the originally loaded Texture2D.

1 Like

I have not tried to do the same as you with pointers and trying to modify the texture by setting up colors there, instead I did that through pixel shaders.

So I had a render target with the list of colored sprites through pixel shaders, and then use that render target as my texture source to put all sprites in one batch on screen. I was able to render hundreds of units that way each with their own colors without any issues. Since each unit had hundreds of animation sprites I only rendered the one I needed for a frame.

I am not sure if rendering all sprites with all the colors needed in memory is a good idea, since you may not need to have all the sprites at the same time per frame. That will waste a lot of memory, it will give you speed since everything is already colored but pixel shaders and render target is quite fast in my opinion.

I rendered about 600 to 800 units on screen and I didn’t notice a slowdown in my game, each with their one colors.

1 Like

Oh cool thanks for the reply, yeah im just starting to see something about RenderTarget2D. I was able to do a number of projects til now starting in xna years ago for my capstone and now monogame but this was first time i ran into this problem. Do i use spriteBatch.Draw() with the rendertarget or there’s some kind of Texture property that i pass, i really appreciate this because yeah if all goes well i want to be able to render and perform well, as i am currently working on metroid vania, and action rpg as well. I will also look into understanding RenderTarget2D, if anyone has any sample code of using that with spritebatch to draw that would be great. Glad i posted this. Thanks again!

Good News Everyone!!! I figured out a solution that probably others thought of

I decided to look at loading the Texture2D.FromFile and Texture2DFromStream,

I did a couple of separate runs and was able to see that i could get different addressed Texture2D’s so i could draw on one and not mess with the other, i appreciate the recommendation for RenderTarget2D but the problem i had with that is i’ve already figured out how to update and draw textures from and even an animation engine using Texture2D and rectangles so i wasn’t seeing that using that was going to allow me to move the target around which is my other goal (or rather desire to keep), here is some code and yeah i found some stuff on stack overflow that was very helpful just had to peice it together. I left both of the examples but i’ll only be keeping one obviously, but figuring things out for now

//Here are 2 separate runs showing the different addresses for anyones curiosity
NativePointer = 0x0000018072569238 //origin
NativePointer = 0x0000018072f50fb8 //copy

//2nd run
NativePointer = 0x000001ade71ca338 //origin
NativePointer = 0x000001ade7c0d738 //copy

this.replaceColorTexture = this.Content.Load(@“Textures\RecolorBox”);
this.randomReplaceColorTexture = (Texture2D)(
this.Content.Load(@“Textures\RandomRecolorBox”));
string fileLocation = @“D:\My New Games\Monogame\PixelColorReplace\PixelColorReplace\Content\Textures\RecolorBox.png”;

        this.randomReplaceColorTexture = Texture2D.FromFile(GraphicsDevice, fileLocation);
        Texture2D tempTexture;
        using (MemoryStream s = new MemoryStream())
        {
            SD.Bitmap bmp = new SD.Bitmap((fileLocation));
            bmp.Save(s, SDI.ImageFormat.Png);
            tempTexture  = Texture2D.FromStream(GraphicsDevice, s);
        }

again i greatly appreciate the community and feedback and hope this helps anyone else save time

I would normally let this one go, but this is horrible post that got tagged as solution and self recommended to other people to use it.

You yourself said: " well i want to be able to render and perform well". Loading from HDD is by far slowest part of the process and you load bitmaps over and over again to get data that you have already loaded, exactly same data. From all wrong approaches, this is the worst one. Lets assume that for all the wrong reasons you are simply stuck with doing the modification on CPU and creating additional copies of very similar, slightly modified texture in VRAM. Worst yet, what you are doing is loading from HDD multiple times, getting it into own textures living in VRAM, then I assume you pull that data back to CPU and then I can only hope that after modification you either dispose of old texture in GPU memory or set its existing buffers (well, they should be created as immutable buffers but that’s story for another time).

Everything here is wrong, no one do this, please, don’t consider this to be a solution. So back to assumption this modification has to be done on CPU and persist as separate textures. Look at loading FromStream in MG’s source code, at one point it is array of Colors, that’s the data you need, that’s the only part that needs to be persistent. Create functions that load these data from file, keep them in array, modify data as you see fit, then from modified results create Textures2D using SetData.

Monogame did its best to prevent you doing it wrong, you called it a bug and found “work around”.

8 Likes

Are you actually saving a Texture to disk and load it again, just to get a copy? (and there is a Texture2D.SaveAsPng, just FYI)

Just make a “new Texture2D” - GetData from the old, SetData to the new. Done. This is actually one of the bare basics, so I wonder why you make things that much more complicated.

(and yes, from what you want to do, the correct approach would be to do the coloring in the shader … or if you use a Spritebatch just apply the color there [which would ultimately do it in the shader] … from your post I don’t really see the need of having separate textures just for coloring purposes)

I still believe one of the best options is to use shaders as I mentioned before.

As Ravendarke mentioned, the reply marked as a solution is not a good solution, but I would say it is still a solution, though it is one of the slowest and one of the most inefficient ways to do it.

I guess if you have a lot of sprites to change color, you will end up using a huge amount of memory and will run very slowly. On the other side, if you have very few sprites to modify and load all of them in memory it will run ok, though it can be improved.

To any senior programmer it should be instantly clear that it is not a bug. To me it seems you still do not understand what you are doing wrong, worst yet, you refuse to do so. However it doesn’t matter to me, you are free to use whatever solution you want to, I wanted to protect people that might get confused. You’ve been explained, by multiple people, that this data juggle is completely unnecessary even if all processing would happen on CPU. If you don’t want listen to me, listen to reiti.net (he said same thing).

Right here we can see references sadly don’t matter, but since you started. I have Master’s degree in CS, I wrote three engines (two of them MG based), one framework. I find technical solution for companies all over the world. I am also tutoring. Thing is, it shouldn’t matter here, as this is completely entry level issue that you are still getting wrong while being insanely arrogant about it, last screenshots you posted are better case, meaning you should be able to understand what’s so wrong with post you tagged as solution, it’s still not ideal as there is unnecessary GPU-CPU transfer of data that were already on CPU during loading texture, but way more acceptable than “solution”.

Which again, I wouldn’t care about if you wouldn’t try to pass it as solution potentially confusing large amount of people. Also this is necro posting.

@weberj81 I would not do it that way, if you really need to clone the sprite just clone the data. You don’t need to load from stream or reload the textures or anything like that. Something like this should work:

Color[] ColorData = new Color[Texture1.Width * Texture1.Height];
Texture1.GetData(ColorData);  // Copies color data from Texture1 into ColorData 
Texture2.SetData(ColorData); // Sets Texture2's data to the new array

Also you can clone the color array just calling the array.Clone method:
TextureData = (Color[])TextureData.Clone();

2 Likes