[XNA 4.0] WTF is going on here?

Started by ForeverZer0, August 10, 2014, 10:27:03 am

Previous topic - Next topic

ForeverZer0

As most everyone knows by now, I am creating a new engine using XNA.
I am getting a very strange bug that I cannot figure out to save my life, and it is really starting to irritate me. As I mentioned in the Shoutbox a few days ago, I was having problems loading very large tilesets. As it turned out, XNA has some a maximum texture size of 2048x2048 using the Reach profile, and a maximum texture size of 4096x4096 on HiDef profile.

I changed the profile to HiDef (goodbye Windows Phone compatibility!), which vastly increased the size of the textures I can use. As far as RMXP is concerned, the largest images that are going to be used are going to be tilesets. Some of these tilesets have a height larger than 4096 pixels obviously, so in order for them to be used, I have to modify the image internally when it loads to fit within the 4096x4096 bounds. For testing purposes, I have been using Inquisitor's Medieval Exterior tileset, since it is one that I know off the top of my head to be one of the largest.

All these images are fairly large, so be warned.

Original Image (256 x 16704): ShowHide


Now, here it is loaded internally. Basically the width just gets expanded and overflow greater than 4096 pixels gets moved to columns. This is the actual texture as it is loaded and used to draw a tilemap.

Internal Image (1280 x 4096): ShowHide


Pretty straightforward conversion, and easy to work with, just have to do a quick calculation to adjust coordinates for over-sized source images.
This works perfectly with the exception of a bug that I cannot find or understand. For some stupid reason, a white border is being placed around some of the tiles, specifically the bottom of the last column (where actual image data is contained, not the extreme bottom), and the right side of some tiles in the next to last column, where beside it is blank data.

Example 1
The damn tents along the right side of the next to last column.
What it is doing: ShowHide

Source: ShowHide


As you can see, there are no white pixels there to be copied. I checked the coordinates, they are correct, its just adding white there. I have tried clearing the GraphicsDevice with all sorts of colors, no change. I have tried changing the blend color, and all I get is white with a tint of whatever color I choose, not just the color, so it's reading that portion of the texture as white.

Example 2
Basically the same thing, just a different area of the tileset, this time at the very bottom. I added the "signature" section of the tileset to a map, and here is how it comes out.
What it is doing: ShowHide

Source: ShowHide


I am at a loss for this one, and thus far, it seems to ONLY do it with them specific areas, the rest of the map looks perfect.
Any ideas?
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

G_G

My guess is that it's coming from when the image gets altered. Because it seems to only do it at the edges of the tileset when you're expanding it. Are you creating a completely blank canvas when you go to create the expanded version? Or how are you doing it I should ask. And then have you tried using the converted tileset just by itself and not use the internally modified one? (If that makes any sense.)

ForeverZer0

Unless the source image has a dimension larger than 4096, the image is just loaded normally.
Here is the static load method of the Bitmap class.

http://pastebin.com/j1pnE6K2

I assumed what you said as well, so I tested all different ways clearing the texture data, or setting it to a solid color before overwriting with the image's data, and nothing changes.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

G_G

But I mean have you tried loading the converted image instead of the original? As in, just import the modified image and use that and see if it still causes errors.

ForeverZer0

August 10, 2014, 10:53:48 am #4 Last Edit: August 10, 2014, 10:59:51 am by ForeverZer0
Oh, I see what you mean, no I have not tried that yet.

I will get back to you, let me try that.


EDIT:
And that works, no white.
Okay, so I have discovered a possible way to fix it, but it's going to mean I have to save the tileset and reload it, which kinda sucks, but is doable.
I suppose I could implement converting oversized images, and prefixing them with a "$" or something so that they do not need to be loaded like that every time, but I was not trying to go that route.

I still wonder what the hell is going on with it, now I am even more confused, even with a way out of it.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

G_G

August 10, 2014, 11:05:38 am #5 Last Edit: August 10, 2014, 11:12:09 am by gameus
Perhaps when you're shifting colors from the system bitmap to an XNA texture something's going on. At least this way you know where to look. It has something to do with the conversion method.

EDIT: Perhaps a different conversion method? Here's one I found and if I remember right I found reliable.

public static Texture2D GetTexture2DFromBitmap(GraphicsDevice device, Bitmap bitmap)
{
   Texture2D tex = new Texture2D(device, bitmap.Width, bitmap.Height, 1, TextureUsage.None, SurfaceFormat.Color);

   BitmapData data = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);

   int bufferSize = data.Height * data.Stride;

   //create data buffer
   byte[] bytes = new byte[bufferSize];    

   // copy bitmap data into buffer
   Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);

   // copy our buffer to the texture
   tex.SetData(bytes);

   // unlock the bitmap data
   bitmap.UnlockBits(data);

   return tex;
}


It's similar to yours but you're not shifting bytes.

ForeverZer0

August 10, 2014, 11:17:08 am #6 Last Edit: August 10, 2014, 01:12:35 pm by ForeverZer0
Perhaps I will give that a try, and do some benchmarking. I used to use Marshal for copying, but then during my time making Rpg.NET, I found it was much faster using unsafe code, but I wasn't shifting bits and converting from ABGR to ARGB, so perhaps my method is no longer the way to go.

I will give it a try.


EDIT:
Tried it and it doesn't work, still need to swap the blue and red channels. That would have worked in earlier versions of XNA, but not 4.0, which is what I am using, so guess I am sticking with what I got. Performance isn't really an issue anyway, and it only needs to do it once then its cached, so no biggie.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Blizzard

August 10, 2014, 03:52:58 pm #7 Last Edit: August 10, 2014, 03:56:23 pm by Blizzard
Texture addressing mode. http://msdn.microsoft.com/en-us/library/windows/desktop/bb206239(v=vs.85).aspx

I suggest you use CLAMP. Just find the equivalent in XNA, the one in the link is for DX9.

EDIT: Actually that might be completely wrong. Make sure you initialize the texture with all zeros. Try rendering the entire texture, not just the tiles, to see if the texture looks properly in the memory. You should also make sure that you are using proper RGBA textures and that you copy all pixels properly, even if they are blank (color 0,0,0,0).
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

ForeverZer0

Quote from: ForeverZer0 on August 10, 2014, 10:48:01 am
I tested all different ways clearing the texture data, or setting it to a solid color before overwriting with the image's data, and nothing changes.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

G_G

Got any idea. Instead of converting, let na do it. Save the system bitmap into a memory stream then use xna texture2d.fromstream.

ForeverZer0

Quote from: gameus on August 10, 2014, 11:39:27 pm
Got any idea. Instead of converting, let na do it. Save the system bitmap into a memory stream then use xna texture2d.fromstream.


Would be quicker than writing to disk, I'll probably implement that instead of using saving the modified file with a prefix. It doesn't really need to be saved like that, and doing that also invites other issues. Speed isn't a terrible issue, and as I stated before, it only needs done once, and only for large images, such as large tilesets.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Blizzard

You should still try this to figure out at which point the texture gets messed up or whether the actual rendering is messed up.

Quote from: Blizzard on August 10, 2014, 03:52:58 pm
Try rendering the entire texture, not just the tiles, to see if the texture looks properly in the memory.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Soulshaker3

Ok i'm not really an expert but i don't think it has nothing to to with the color conversion but it has when drawing the bitmap and specifying the rectangle the reason why that doesn't appear when you draw the whole texture is probably because when you were setting the rectangle to draw it would be (0,0,width,height) and it would draw it perfect let me try to explain:
Spoiler: ShowHide

Here you see that there are 2 white pixels in the right side, well if you check the image you see that in the right side of that there's nothing the image just ends so there's no data on those spots and if you're using Color.White when drawing that might explain. On the left side it is the same thing it's trying to draw pixels that there's no data. The reason that only happens on all sides in the image is because even tought you're specifing a wrong rectangle there's data in the middle tiles that are not closed to the borders is because it's getting data from the tile from it's left/right etc.

This is only a theory probably it isn't because of this but this is my explanation. One thing that you can do to see if it is what i said it's to add a rectangle all the same color in the bootom of the image and have a stroke 3 pixels in so it only has different color in the sides and see if it draws that properly.
Hellow?

ForeverZer0

August 11, 2014, 05:06:35 pm #13 Last Edit: August 11, 2014, 05:07:47 pm by ForeverZer0
I checked the coordinates a million times, and compared them with the image, they are correct. If they weren't being calculated correctly, then everything would be off, not just tiles at the end.

I have also used other colors than white, but the color is always white. I copied data to the entire texture so that there is no area of "no data", and no matter what, the area is always white.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Soulshaker3

Now that i remember in the tileset the 1st tile is always white right? in xna if you use a rectangle that goes beyond the resolution of an image it just loops the image and no if the coordinates were wrong you would only notice on the sides, imagine you've a texure 320x320 if you do new Rectangle(33,33,32,32) it would display that part of the texture correctly but if you do new Rectangle(300,300,32,32) the 12px that overextended the image width and height would been get from (0,0) i believe
Hellow?

ForeverZer0

The first blank tile is an autotile, and is not loaded using the source tilemap.
Believe me, I messed with the coordinates a million times, that's not the issue. Even if was, it does not explain the tile always being white. It would also not explain why in the bottom of the page, the white is on the left-side of the image, not the right.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Blizzard

Have you checked on the pitch? I remember in DX9 that sometimes you would get a pitch (number of bytes for a row in the texture) that has actually more bytes than the actual row (it's usually always a number divisible by 4 so it has problems with 3 bpp or 1 bpp textures). Even though this usually manifests as a "tearing" effect rather than a white border. There is also the issue with BLTs.

As I already said, I haven't used XNA, but in DX9 you have to lock a texture portion before you can write on it. And when you lock it, you can decide what happens with the previous contents. Usually they are discarded since fetching them from the GPU is expensive. I doubt that this is the problem, but it's worth looking into it if XNA uses a locking mechanism for data transfer onto and from textures. If there is a locking mechanism, you should also check if XNA allows to lock the texture at any coordinates or if there are some restrictions like the coordinates having to be divisible by 4 or something like that.

Last but not least, have you tried reproducing this in a plain new project? (I haven't read the entire thread, sorry.) You should try to pin down whether the bug is yours or in the system or whether this is simply how the system behaves.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Soulshaker3

He fixed this already i don't know what he did but he fixed
Hellow?