Flash

Introducing Printomi

I’m extremely proud to announce the launch of a project I have been working on for quite a while now.

Printomi is a service for social games that allows players to take snapshots of their worlds and upload them to their own personal gallery. Players can like, comment share and order poster prints of their virtual creations.

The way it works is we provide the game owner with a tiny API that is used to interface with Printomi. The bulk of the Printomi client is downloaded at runtime from the Printomi servers. This is good for two reasons. Firstly by keeping down the size of the code that must be embedded into the game we can keep down the initial load time the player must sit through before they can play the game. Secondly we can upload changes and fixes to Printomi without requiring the game owner to recompile their code.

Once downloaded the printomi client is ready to be be used. In the case of Gourmet Ranch a themed button is shown to the player inviting them to click:

Once clicked (or activated by the JavaScript API) the main Printomi window opens:

The window has controls to zoom in and move the print about allowing the player to get the perfect angle of their world:

Once happy the player can then saves the print to the printomi servers. While the image is uploading the user can continue to play the game. Once the upload is complete the window is opened once more offering to show the player their print.

Printomi is tightly integrated with Facebook so that it’s as easy as possible for new users to get started:

Once connected the new print is then available for viewing, sharing, liking, commenting, etc:

In addition the prints are organised into galleries so that users can browse the uploads of others:

If a user particularly likes one print then they can order it as a poster:

Currently we only offer posters to people living in the US however we plan on opening it up to other countries when we can.

To print to such a large poster (24×18″ @ 150DPI) and maintain the quality of the final product we must capture a large number of pixels. For example here is a comparison between what a user would see on printomi.com and what we store behind the scenes:

The technology that lets us capture these large images and store them in a compressed way (to conserve disk space and therefore cost) is quite complex and will have to wait for a later post.

Printomi is currently only available to a small subset of the Gourmet Ranch user base but we are performing a steady-rollout to everyone, so if you don’t have access to the button in Gourmet Ranch just yet then don’t worry it should be available for you soon!

Printomi is a culmination of many many hours of hard work, late nights and stress. But its been worth it! I’ve had a blast throughout the whole process and am proud of the result. I have also learnt a whole bunch in the process. I have had to work with so many technologies to pull this off, to name a few: AS3, C++, C#, ASP.Net, MySQL, IIS, AWS. I have particularly enjoyed the C# work having largely abandoned the language since my early work with it.

If you would like to support me or if you would like to keep up to date with the goings on with Printomi then you can like us on Facebook or follow us on Twitter :)

Try { Harder } 2012 Levelup

Last year I was fortunate to be one of the lucky 16 to attend the first try { harder } experimental conference / coder retreat in Nottingham. As mentioned in my blog post at the time it was an incredible 4-day event in which I learnt so much from some of the most talented and experienced people in the flash community.

The event was such a success that not only is it going to run again this year (which I hope very much to attend) but there is also an additional “levelup” conference happening next week. The idea behind the levelup is to provide businesses and freelancers with an intensive 4-day training and motoring session. The mentors are hand picked from the previous try harder members and so represent some of the best in their field.

What’s more Stray, the primary organiser of the event has just announced that Jetbrains the makers of the popular IntelliJ IDEA IDE are going to be sponsoring the event meaning each paying participant will receive a licence to use the IDE!

Interested? Head over to the levelup site and sign up: http://www.tryharder.org.uk/level-up-2012/

 

Why Developing for WebGL Sucks!

For some time now I have been working with WebGL and have developed a sort of love/hate relationship with it. I love the ability to instantly target millions of people with GPU accelerated code without any plugins or barriers (excluding the targets that dont support it). However as a developer, writing code that takes advantage of WebGL kinda sucks.

Procedural Based

First off is the way you have to structure your GL calls. For example take a look at the following generic bit of webGL harvested from the net:

  1. texture = gl.createTexture();
  2. gl.activeTexture(gl.TEXTURE0);
  3. gl.bindTexture(gl.TEXTURE_2D, texture);
  4. gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
  5. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 64, 64, 0,
  6. gl.RGB, gl.FLOAT, new Float32Array(pix));
  7. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  8. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  9.  
  10. texture1 = gl.createTexture();
  11. gl.activeTexture(gl.TEXTURE1);
  12. gl.bindTexture(gl.TEXTURE_2D, texture1);
  13. gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
  14. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 64, 64, 0,
  15. gl.RGB, gl.FLOAT, new Float32Array(pix1));
  16. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  17. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  18.  
  19. FBO = gl.createFramebuffer();
  20. gl.bindFramebuffer(gl.FRAMEBUFFER, FBO);
  21. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
  22. gl.TEXTURE_2D, texture, 0);
  23. FBO1 = gl.createFramebuffer();
  24. gl.bindFramebuffer(gl.FRAMEBUFFER, FBO1);
  25. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
  26. gl.TEXTURE_2D, texture1, 0);
  27. if( gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)
  28. alert(err + "FLOAT as the color attachment to an FBO");

All it does is create a couple of textures, setting their starting values and creates two frame buffers for rendering to. Its just it looks complicated and difficult to understand.

GL works on a procedural basis, so you tell GL that you are about to work on something by calling a function like “bindTexture()” then on the next line you perform an operation on it such as “pixelStorei()”. Now this may have made perfect sense back when we were writing everything in C which is procedural anyway however this is Javascript (or haXe in my case) which is an Object based language, code like this is difficult to understand and follow.

The procedural nature of WebGL means you have to be much more careful about unsetting things you have previously set. For example if you bind a texture to perform some operation, you must then remember to unbind it else you could inadvertently cause operations to be applied to it on subsequent calls elsewhere in your codebase. It this ‘hidden state’ that has caused me alot of headaches when developing my samples.

The principal behind WebGL was to provide a very low-level library which other developers can build upon to build more complex and abstracted libraries. And there are numerous libraries out there. I personally have tried several of them including the very popular three.js. Three.js is great for doing common things like loading models and putting quads on the screen. I however encountered a problem with render targets which I struggled with for days before I discovered that you had to set “needsUpdate” to true on your texture before using it. In the end I decided to drop three.js beacuse of another issue I encountered and instead attempt to reduce my complications by working with webGL directly.

Flash11′s Stage3D has the same philosophy as webGL, to provide a low level API for other developers to build libraries upon. The thing is Flash11′s low-level API makes more sense and is more readable. For example the following to me is much more readable than its webGL equivalent:

  1. texture = c.createTexture(logo.width, logo.height, Context3DTextureFormat.BGRA, false);
  2. texture.uploadFromBitmapData(logo);

The Stage3D API also uses language like “upload” to let you know when you are transferring data to the GPU, for a new comer to GL you have no clue when things are going to the GPU. Its small things like this that reduce the “WTF?” factor when tackling the tricky world of hardware-accelerated 3D programming.

Cross-domain textures

This one cropped up around July time this year and took me ages to work out what was going on. For some inexplicable reason (or so it seemed) my code one day stopped working. When I looked for demo code online it all worked fine, however when I downloaded it and run it locally it also didnt work. I was getting errors like the following:

Uncaught Error: SECURITY_ERR: DOM Exception 18
Uncaught Error: SECURITY_ERR: DOM Exception 18
Uncaught Error: SECURITY_ERR: DOM Exception 18
Uncaught Error: SECURITY_ERR: DOM Exception 18
Uncaught Error: SECURITY_ERR: DOM Exception 18 

I was so baffled that I posted about it on the HaXe mailing list asking for help, thinking it was something I was doing wrong with HaXe. It turns out (after much wall-head-butting) this was a change that they brought into Chrome 13 and Firefox 5 to combat a security problem when using shaders that use textures from a different domain to the one running the code:

http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html

Now I have no problem with cross-domain issues, im used to this from Flash where we have the same sort of setPixel() restrictions on cross-domain BitmapData’s. The thing is, it appears that this restriction applies when running code locally too. So If you are developing something on your local machine and trying to access a texture from disk it throws the same security errors because the browser thinks you are reaching across domains to access the image.

At the time the only way to get around this was to create your own webserver that you run on localhost to server up the files. So to do that I had to download python so I could run a simple localhost commandline webserver from my bin directory. What an effort! There may be easier ways these days to solve it but at the time it really frustrated me and formed yet another barrier to developing webGL.

No Error Messages

This is by far the most annoying thing about developing for WebGL. So many times I have been trying to write something that I know SHOULD work but for some reason it doesn’t. I dont get any error messages, nothing. It makes writing something from scratch neigh on impossible.

In my last post “GPU State Preserving Particle Systems with WebGL & HaXe” I started with an idea. I attempted to code it ‘bottom-up’. That is start with nothing and then add more code until I reached what I wanted. Unfortunately having no error messages in WebGL makes this very difficult indeed. I would spend some time writing something really simple, like trying to get a textured quad to render on the screen only to find I get nothing. I double check my camera matrices my vertex and texture buffers, my shader and still nothing. Eventually I found that I hadn’t bound something first before trying to operate on it *sigh*

In the end I found the best way to get anywhere is to go from the other direction, a ‘top-down’ method. Start with something kind of simmilar to what you want then cut bits out one line at a time until you get what you want. Its extremely time consuming and frustrating, but its less frustrating than going from the other way.

There are tools out there that help with debugging what is going wrong. Namely the WebGL Inspector (see above) is intended to provide gDEBugger / PIX like debugging information about what is going on inside webGL. Its a clever bit of tech, it lets you inspect buffers and traces each gl call, however it suffers from the same underlying problem of having no errors. You setup a buffer incorrectly and what you get is “INVALID_VALUE”. No indication as to which of the values is invalid or what part of the call you messed up on :(

Googling Doesn’t Help

If you do happen to get an error message (unlikely) or you word your problem in a sufficiently succinct and googaleble way you will then run into the next big problem with WebGL; theres very few people using it. Now I know I am likely to be flamed for that comment, but it just seems that way to me. Whenever I tried to google my problem, or google for what I was trying to achieve (because working bottom-up doesnt work) there would be a very sparse smattering of relevant posts. Usually the results are forum posts and are OpenGL not WebGL related and are from 5-10 years ago.

But..

Now having just ranted on for several hundred words about why it sucks im going to finish it off by saying that im going to continue to develop for WebGL using haXe regardless. Why? Well I just like making pretty things that run fast and GPGPU programming appeals to me for some unknown (likely sadistic) reason.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  Scroll to top