Monday, November 19, 2012

Haxe NME Follow-up

A few weeks ago, I began working on a Haxe NME version of the NEO Scavenger encounter editor. I endeavored to share my first impressions of NME, but I had two more weeks of experimenting with it, so I wanted to share what I learned. What follows, then, is a brief discussion of each of the highlights from that experiment.

Encounter Editor Screenshot


Speed

The main reason I chose to rewrite the NEO Scavenger editor in Haxe NME was because the Flash version had performance issues. The recent increase in data caused loading to timeout and crash. And what's more, even before this loading failure, I was reluctant to use the tool due to its sluggishness. Faced with rewriting lots of code no matter what, I decided to try Haxe NME.

I'm happy to say that Haxe NME showed its strength as a high performance framework. I haven't done any proper comparisons between NME and Flash, but the editor is quite responsive at 2560x1600 resolution. This was while drawing hundreds of boxes, hundreds of bitmaps, and thousands of triangles simultaneously, all with scaling (no bitmap rotations, though). 

The Windows target also loaded (SQL/URL-based) data much faster than the old Flash version. Though, the NME Flash target still needed optimization to complete data loading before the 15 second timeout.

UI

Form fields are still a weakness with NME on Windows targets. I was able to hack together some quick and dirty UI elements as stopgaps for buttons, toggle buttons, and drop-down boxes. But not having Flash's built-in UI elements was an obstacle.

TextFields

TextFields work on Windows targets, but are extremely limited. They lack support for getting the current caret position, selected text, and copy/paste. Flash targets work fine, however.

Performance can be an issue, though. I was able to get about 2-3 TextField elements per encounter node (about 2200 total) without any noticeable slow-down on my machine. However, much beyond that, and the framerate seemed to drop. I ultimately opted to hide TextFields on all nodes, and reveal them as-needed to keep framerates high.

A closer look at some of the editable fields I have in each node/connector.
Copy/Paste

Copy/paste, itself, turns out to be a general issue in Windows targets. I wasn't able to get access to the clipboard with vanilla NME, and the systools library that I tried wouldn't compile for NME Windows targets. Copy/paste on Flash targets appeared to work fine, though.

Object/Dynamic Weirdness

Haxe uses a type called "Dynamic" to handle generic objects (instead of Flash's Object class). On the Windows target, I was able to use .get() to access dynamically-named properties in a URLVariables object. But when compiling on Flash, the compiler didn't like that method. What's more, the traditional Flash method of Object["propertyName"] threw compiler errors. In the end, I had to use Reflect.getProperty(). Not too much of a pain, just unexpected.

URLRequest and 413 Error

Using URLRequest on Flash targets worked as expected, but caused errors when tried on Windows targets. I kept receiving 413 "request entity too large" errors when trying to execute the request. As it turned out, I needed to initialize the .data field of the URLRequest object to quell the 413 error. I'm not sure why a null data field would cause a "request entity too large" error, which is why it took me a while to figure out. I ended up finding the solution by looking up libcurl issues of a similar nature, since that's the library used by NME.

Key Handling

Flash and Windows targets for NME seem to trigger different key codes for ascii characters. I ended up writing special handling code to convert all key codes to uppercase so each platform interpreted results consistently.

Mouse Handling

I ran into issues getting any mouse scroll wheel events to fire on Windows. I didn't pursue this very far, though, as I could work around it, and had bigger fish to fry.

Extensibility

There were one or two instances where I started digging into NME source code itself, to see if I could work around problems I was having (such as enabling unexposed TextField properties). However, I was unable to navigate the matryoshka-doll-like layers of code to the source I needed.

Specifically, I was trying to expose a field in TextField, like caretIndex, so I could hack together a copy/paste stopgap on Windows. I decided to look at how existing fields were exposed, like .numLines. When I dug into the TextField.hx class, I found that Windows targets used the neash.text.TextField implementation.

However, the neash.text.TextField code redirected .numLines to:
Loader.load("nme_text_field_get_num_lines", 1);

Loader.load uses cpp.Lib on Windows targets, so looking into that, I found that cpp.Lib.load used:
__global__.__loadprim(lib,prim,nargs);

which was loading a primitive from a DLL. I wasn't clear where to go from here, though. It seemed like there should be some sort of table or Rosetta stone for mapping strings like "nme_text_field_get_num_lines" to a block of code somewhere, but no amount of searching seemed to reveal it.

I was pretty frustrated by my inability to get to the bottom of that question. And ultimately, had to switch targets to Flash to get the TextField behavior I needed. Though, that in itself is a pretty strong endorsement for Haxe NME.

Cross-Platform

Being able to change a drop-down from "Windows" to "Flash" was almost all that I needed to do to get around the aforementioned TextField issues. That, and some tweaking in the way I accessed dynamically-named fields of a Dynamic object, had me well on my way to continuing work with almost no interruption. Literally, a couple weeks' worth of development on the Windows target was ported to the Flash target within about two hours. Pretty impressive.

Updates

It's also important to point out that NME is updating fairly frequently. Even in the couple months between the version of NME I first downloaded, and one I recently downloaded, there was significant improvement. In fact, several bugs I was encountering were solved by an update to NME 3,4,4.

Conclusion

I'm still pretty impressed with what I'm finding in NME. It has gaps here and there, and it can be tricky to find support. But I was surprised how far I could take it, given it's relative infancy compared to platforms like Flash. I suspect that if I were making a purely game-like app, without the need for text editing, it would do all that I need without issue. I think that the only feature NEO Scavenger uses which I've not yet tested is the audio playback.
Hopefully, some of the info I've shared above helps other intrepid developers in overcoming similar obstacles. And it'd be great if this info was enough to embolden a few new developers to put Haxe NME through its paces. I truly feel that it's a powerful tool, and just a few more concurrent users could be all that's needed to sustain further growth.

By the way, if you're interested in a more chronological account of my explorations, you can find out more about the editor overhaul in these Blue Bottle Games posts:


Thanks for reading, and see you next time!