Map with displayOffset - rendering mysteries

Feb 1, 2012 at 6:44 AM
Edited Feb 2, 2012 at 5:01 AM

I want to render the map offset from the top in order to display Scores and other stats.  I'm attempting to use the following method to draw the map

Map.Draw(IDisplayDevice displayDevice, Rectangle mapViewport, Location displayOffset, bool wrapAround);

Perhaps I'm just not understanding the exact purpose or function of this method.

I have a simple map with 2 layers:-

1. Layer Size 2x1 , Tile Size 500x500px  
2.  Layer Size 40x20, Tile Size 25x25px 

So both layers are 1000x500px.  I'm writing a WP app so my display area is 800x480.  

The problem is exagerated the larger the offset, so for this exercise I want to scroll around a 800x390 viewport into the map rendered 90 pixels from the top of the screen.  

In an attempt to scroll to the bottom right corner of the map I make the following call...

map.Draw(displayDevice, {[200, 200] - 800 x 390}, {[0, 90]}, false);


Layer 1: Is correct. 
On the screen is correctly rendered within the rectangle [[0,90], 800x390]. the viewport into the map is [[200, 110], [800x390]]

Layer 2: Is **incorrect**
On the screen is incorrectly rendered within the rectangle {[0, 180], 800x300], the viewport into the map is [[200, 200], [800x300]]
i.e  the viewport into the map is 90px less and rendered 90px below where the first layer is rendered, giving the appearance of it being cut off.

When I attempt to scroll to the top right its just as bizarre...

map.Draw(displayDevice, {[200, 0] - 800 x 390}, {[0, 90]}, false);

Both Layer 1 & Layer2: Are **incorrect** 
They are both rendered on the screen incorrectly within the rectangle [[0,180], 800x300]. the viewport into the map is [[200, 200], [800x300]]
i.e. instead of a 90 pixel gap, I have double that, a 180 pixel gap.

As an addendum originally to scroll to the bottom of the map I tried...

map.Draw(displayDevice, {[200, 110] - 800 x 390}, {[0, 90]}, false);

This resulted in the bottom map being truncated and a similar problem with a smaller viewport of Layer 1 being rendered than layer 2.

Feb 4, 2012 at 8:13 AM

I will have to try it out when I have the time. Would it be possible to
send me an example project that I can try out?

Feb 6, 2012 at 3:21 PM

Hey there,

I've created a project you can download it here...

Contains code, map and tiles.  Interestingly enough it doesn't quite behave the same way, not sure why that is, however it's still clearly not what I"m after


Feb 7, 2012 at 1:44 PM

By using

            Debug.WriteLine("Memory in use: " + Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage.ToString());I

inbetween map loads, I've also noticed there's a pretty huge memory leak (about 10-20Mb) occuring each time I unload and load another map.  It takes about 60/70 map unloads reloads but eventually you get an out of memory exception.  I added IDisposeable interface to IDisplayDevice and disposed the SpriteBatch objects created in XnaDisplayDevice.  I also put a using around 

            using (MemoryStream memoryStream = new MemoryStream(data))
                Map map = FormatManager.Instance.BinaryFormat.Load(memoryStream);
                return map;

In TideReader.cs

That helped somewhat... down to 6-12Mb... it's still leaky though.  

Feb 8, 2012 at 6:58 AM

Well I've hacked a work around for myself.  Not sure it's of much help to anyone else.  

I commented out the code in the Map.Draw( method

            //Rectangle clippingRegion = new Rectangle(displayOffset, mapViewport.Size);

I now set the viewport on the GraphicsDevice before calling draw on the Map and then restore the original viewport after the draw.  Naturally the same process is applied to all other items I draw which are overlayed on top of the map.  I also reduced the size of the viewport rendered by the tIDE.  

e.g So tIDE thinks its drawing to 0,0 with a 800x390 viewport, however it's using a GraphicsDevice with the Viewport set to {{0, 90} 800 x 390}.   The end result is all layers are drawn correctly with a 90px gap at the top of the screen.

Without commenting out the code in the Map.Draw method it resets the GraphicsDevice viewport to {{0, 0} 800 x 390}

Feb 8, 2012 at 7:05 AM
Edited Feb 8, 2012 at 7:07 AM

I've also resolved my leaking issues.  Some of the leaks were in my own code.  I also create and dispose a ContentManager passed tIDE Map.Draw.  There are a number of changes required to the tIDE libraries though, mainly using statements around Streams and disposing of SpriteBatch objects.  Golden rule, if a class owns an object and that object implements dispose, you need to implement dispose on the class.  I can merge these changes into the tIDE source if you want, or send you a copy of the code.

Feb 8, 2012 at 9:10 AM

Thanks for taking the time to look into this! :) I think I failed to take into account the fact that the graphicsDevice Viewport property not only sets a clipping region but also moves the drawing origin. Hence, in addition to the offset shift, I am adding a further offset shift so the net offset is effectively doubled.

Feb 9, 2012 at 1:41 AM

Hey Colin,

The issue wasn't so much that the margin was doubled, as a simple work around I could have simply halved the margin.  The issue was that when using the DisplayOffset, the clipping regions appeared to be different for each layer, which in my example didn't make sense as the layers are the same size.