2010-11-22

More MonoTouch Gotchas

In my previous post I took a break about discussing my adventure developing for the iPhone with .NET and discussed some issues I've had blogging with Blogger. In this post I get back to the main of subject and describe an odd issue I've encountered with MonoTouch.

The issue is due to the way that MonoTouch compiles to native iPhone binaries. It does not support JIT compilation, which a "normal" .NET environment does support. In most cases this is fine, but sometimes the compiler cannot fully detect the types that are needed and therefore doesn't compile them into the binary. Then, during runtime, when it detects it needs a type that was not compiled it crashes.

The code below is a pretty simple example of this issue:
/// <summary>Initializes a new instance of the <see cref="Shape"/> class.</summary>
/// <param name="points">The points.</param>
public Shape(Vector2d[] points)
     : this(points.Select(point => new Vector2((float)point.X, (float)point.Y)).ToArray())
{
}

This is a very simple alternate constructor for my Shape class. It is a convenience constructor to allow passing in Vector2d values (these are double based vectors) instead of Vector2 values (these are float based). The LINQ expression just enumerates over the array and converts the values.

So, why doesn't this work? Well, the error I get is something like:
Attempting to JIT compile method
'System.Linq.Enumerable/PredicateOf`1<OpenTK.Vector2d>:.cctor
()' while running with --aot-only.

I believe what this is saying is that the constructor for System.Linq.Enumerable/PredicateOf`1<OpenTK.Vector2d> is not found, and since JIT isn't supported it can't compile it at runtime. The reason it isn't compiled initially is because the compiler doesn't recognize that the LINQ expression will ultimately need this constructor. The way around this is it reference the needed type explicitly in code. Unfortunately, I didn't figure out a way to do that. Fortunately, I found a different workaround, although it does include a little bit of unnecessary overhead:

/// <summary>Initializes a new instance of the <see cref="Shape"/> class.</summary>
/// <param name="points">The points.</param>
public Shape(Vector2d[] points)
     : this(new List<Vector2d>(points).Select(point => new Vector2((float)point.X, (float)point.Y)).ToArray())
{
}

In this case, the LINQ expression is over the List<Vector2d>, which works fine. I believe the reason this works is because List<Vector2d> explicitly implements System.Linq.Enumerable/PredicateOf`1<OpenTK.Vector2d>, where the array does not.

I need to play around with this a bit more to see how I can fix it without the List wrapper. The problem is this only shows up when I deploy to the iPhone, so the build/run/test cycle is a bit slower. For now my workaround works ok, so improving this is not a high priority.

Next time: Phunky Physics.

2010-11-18

Fighting with Blogger

In my previous post I described some work I spent optimizing my .NET code to make it perform well on an iPhone. I expect I'll have a follow up post when I do more optimizations in the future, but next I want to take a slight detour from coding to discuss a small battle I had with getting Blogger to work well with the type of info I'm posting.

Before getting into that discussion I want briefly give an update on the game. These blog posts are lagging actual development by a couple months. Basically it takes me a while to finish a blog entry, so I try to queue them up and revise them when I have time. So, in reality the game is coming along pretty well. It is still slow going because I can only put in a few hours here and there, but it is progressing nicely.

Now, on to fighting with Blogger...

So, as mentioned above, I wanted to be able to post source code that looks good and has syntax highlighting. Initially I tried a simple solution that I know worked to some degrees from my previous experience, simply copy the code from Visual Studio (VS) and paste into Blogger. Oops, no, that doesn't quite work. If you do that no formatting is included. But, if you copy and paste into Word then it is included. Hmm, ok, how about copying and pasting into Word, then re-copying from Word and pasting into Blogger? Yep, that works, and gives output like below:
/// <summary>
/// Binds the texture.
/// </summary>
/// <param name="textureData">The texture data.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <returns>The texture's bound id.</returns>
private static uint BindTexture(byte[] textureData, int width, int height)
{
     uint textureId = 0;
     GL.GenTextures(1, ref textureId);
     GL.BindTexture(All.Texture2D, textureId);
     All format = (System.Environment.OSVersion.Platform == PlatformID.Win32NT) ? All.Bgra : All.Rgba; // useless comment placed here just to make the line very long
     GL.TexImage2D(All.Texture2D, 0, (int)format, width, height, 0, format, All.UnsignedByte, textureData);
     textureData = null;
     GL.TexParameter(All.Texture2D, All.TextureMinFilter, (float)All.Linear);
     GL.TexParameter(All.Texture2D, All.TextureMagFilter, (float)All.Linear);
     GL.Enable(All.Texture2D);
     return textureId;
}

Actually, the above is wrapped in a pre, which I have styled to make the grey background and such. But, there's still a problem, the long lines wrap and make it harder to read. So, what I really want is for the code area to scroll horizontally when the lines are too long. Fortunately, a bit of CSS can do that:

.csharpcode
{
  font-family: Consolas, "Courier New", Courier, Monospace;
  margin: 0em;
  padding: 0.5em;
  border: solid 0.1em #000000;
  background: #222222;
  white-space: pre;
  white-space: nowrap;
  overflow: auto;
  overflow-y: hidden;
}

So, if I change the simple pre to pre class="csharpcode" then I get the following instead. Notice the horizontal scrollbar and the long lines no longer wrap.
/// <summary>
/// Binds the texture.
/// </summary>
/// <param name="textureData">The texture data.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <returns>The texture's bound id.</returns>
private static uint BindTexture(byte[] textureData, int width, int height)
{
     uint textureId = 0;
     GL.GenTextures(1, ref textureId);
     GL.BindTexture(All.Texture2D, textureId);
     All format = (System.Environment.OSVersion.Platform == PlatformID.Win32NT) ? All.Bgra : All.Rgba; // useless comment placed here just to make the line very long
     GL.TexImage2D(All.Texture2D, 0, (int)format, width, height, 0, format, All.UnsignedByte, textureData);
     textureData = null;
     GL.TexParameter(All.Texture2D, All.TextureMinFilter, (float)All.Linear);
     GL.TexParameter(All.Texture2D, All.TextureMagFilter, (float)All.Linear);
     GL.Enable(All.Texture2D);
     return textureId;
}

The only remaining problem is that this HTML that comes from VS via Word is very verbose. Just the very first line, a comment, contains all of this HTML:
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="color: grey; font-family: Consolas; font-size: 12pt;">///</span><span style="color: green; font-family: Consolas; font-size: 12pt;"> </span><span style="color: grey; font-family: Consolas; font-size: 12pt;">&lt;summary&gt;</span><span style="font-family: Consolas; font-size: 12pt;"></span></div>

So, the entire code block ends up being quite a lot of HTML.

To address this issue I actually jumped through a number of other hoops to create less verbose HTML. In fact, the earlier pages in this blog use that simpler HTML. But, going forward, I've decided to use the above method. It is easier and creates more nicely formatted output. It is a bit more verbose, but then if you look at all of the other CSS that Blogger includes the pages are pretty heavy to start with.

I actually might go back and reformat the previous pages at some point, so the above statement might become inaccurate.

Anyway, I guess my fight with Blogger is a lot less interesting that I thought. As I was figuring out how to do all of the above it was annoyingly painful. But not that I have a solution it is pretty simple.

Next time: More MonoTouch Gotchas.