Hostingheaderbarlogoj
Join InMotion Hosting for $3.49/mo & get a year on Tuts+ FREE (worth $180). Start today.
Advertisement

Post Mortem: Porting Quell Memento to the PlayStation Vita

by
Gift

Want a free year on Tuts+ (worth $180)? Start an InMotion Hosting plan for $3.49/mo.

Daniel Schuller and I formed Bigyama in 2012, after having worked on numerous titles such as Magic the Gathering: Duel of the Planeswalkers and Star Wars: Battlefront. The company started with an ill-timed jump into PlayStation Home and a move to Scotland, before a return to Nottingham and a refocusing on our core talents: programming and making great games! Our first step was to supply the technical chops to help Fallen Tree Games bring Quell Memento to the PlayStation Vita.


This article discusses how we at Bigyama ported Quell Memento to Vita. If you'd like to know more about the design of Quell, please check out Fallen Tree's article, The Making of Quell.


Getting Started

Memento is the third game in the Quell series; the previous games had done very well on mobile and I had known Joe and Lewis at FTG for some time, having worked with them at Free Radical Design before its demise. It was great to get the chance to work with them again and to have the chance to work on a new platform.

Some time back I had met the team from Honeyslug, developers of the successful PSP Mini Kahoots who then went on to develop Vita launch title Frobisher Says. They put us in touch with the developer relations team at SCEE (Sony Computer Entertainment Europe).

We went to the SCEE studio in London and discussed the options - PSP Mini, PlayStation Mobile or PlayStation Vita - each of which give developers access to Vita with varying degrees of functionality. After a few emails back and forth, we decided that the best option for Quell was to make a native Vita game, giving us full access to the power of the Vita and all the features of PSN, such as leaderboards and trophies.

Post Mortem: Porting Quell Memento to the PlayStation Vita

Tackling the Port

Engines

Often the first task in creating a game is deciding which engine to use. There are a number of engines available on the Vita, but most are complete overkill from a technical perspective and just unfeasible from a financial perspective for a project of this size.

There is also the often overlooked PhyreEngine, developed by Sony themselves and free to use by registered PlayStation developers - it's been used to develop games from Demon Souls to Colin McRae: Dirt and Journey. Again, as you can probably imagine this was so much more than we really needed, like trying to crack a nut with a sledgehammer.

Conveniently, Quell Memento used Fallen Tree Games' own engine, and both the engine and game code were written using C. C and its variants are the standard language used to make games and if you are developing a game to release on many different platforms you really shouldn't go with anything else.

This made our decision obvious: we would port Fallen Tree Game's engine itself to the Vita. It was free, it was built specifically to run the Quell games and it was a nice codebase.

It might sound counter-intuitive to ignore all the engines that already run on Vita and choose an engine that doesn't, but moving a game to a new engine can mean recreating the entire game for that engine because it operates in a very different way. Porting the engine addresses the root of the problem. You don't have to worry about recreating each individual gameplay feature - you just have to recreate the functionality they all sit on top of.

If you are lucky, a port may provide you with an opportunity to develop your own tech for a new platform while getting paid to do so. Bigyama has its own in-house engine and, had Quell Memento been built on an engine with no source code access, such as UDK or Unity, this would have been worth considering.

Key Areas

The beauty of developing a port is that you have a clear goal to aim for.

The beauty of developing a port is that you have a clear goal to aim for.

This may seem daunting at first, but it can be broken down into a few key areas: graphics, user input, audio, networking, and save games.

As I've already mentioned, porting the engine meant there was no significant game code to be written or rewritten; in this situation, getting these key areas working should mean that the game largely takes care of itself. The early stages of making a game is a dash to find the fun in the gameplay, but with a port it's a dash to get enough up and running to figure out where it is broken.

Graphics

When doing a port, start with the graphics.

Post Mortem: Porting Quell Memento to the PlayStation Vita

It's the best place to start - if you can't display anything on screen, it's going to be very hard to know whether you're making progress. We got started on the graphics before even getting our hands on a Vita. The Vita's graphics API is very similar to OpenGL and Quell Memento was already using OpenGL.

Quell used a fixed function pipeline (meaning that the user can only configure stages of the rendering process through a fixed set of functions), but the Vita used a programmable pipeline (shader programs allow stages of the rendering process that were previously fixed to be programmed as the user desires).

We had a short period between becoming licensed developers and receiving the development kits, so in our own engine (which was using Lua/C++/OpenGL) we emulated the behaviour of the OpenGL matrix stack using shaders and little custom code. This meant all the existing Quell code - which was based on the traditional fixed function pipeline - could remain largely untouched.

// Part of our wrapper to emulate the OpenGL matrix stack
// You can find the full file here: https://github.com/balaam/glfacade
Matrix4 glfCalcProjMatrix()
{

    Matrix4 mat;
    mat = mat.identity();
    for(int i = 0; i < (int)g_glFacade.projectStack.size(); i++)
    {
        mat = mat * g_glFacade.projectStack[i];
    }
    return mat;
	
}

Once we had kits, we quickly had something up and running. There was a little work to do, such as converting the colour format of the vertices into that expected by the shader and repacking the vertex data from several separate buffers, each containing separate vertex attributes - position, UVs, and so on - into a single interleaved buffer as shown in the diagram below:

Post Mortem: Porting Quell Memento to the PlayStation Vita

With the addition of a very basic shader, we soon had our splash screen up and running on the kit... kind of:

Post Mortem: Porting Quell Memento to the PlayStation Vita
Using vertex colour is a good way to ensure your game is actually working and geometry is rendering correctly before worrying about textures

With the addition of a simple shader to apply textures, that soon became this:

Post Mortem: Porting Quell Memento to the PlayStation Vita

As I mentioned Quell was using the fixed function pipeline and the Vita's was programmable - meaning all the rendering had to be converted to use shaders rather than the fixed function approach of setting a multitude of various render states to achieve a given effect.

There are a couple of schools of thought regarding just how to manage your shaders. One is to create a separate shader for each material or effect; the other is the 'uber-shader' approach, a huge shader using pre-processor definitions to produce the variants needed at compile time. Each has its own pros and cons:

Individual shaders - Pros:

  • Easier to optimise
  • Easier to read and understand

Individual shaders - Cons:

  • Hard to manage as the number of shaders required can grow incredibly quickly
  • Will often require programmer intervention every time an artist want to use a new combination of effects

Uber-shader - Pros:

  • Less coder support required by artists (after the initial work is done)
  • A much more manageable number of files

Uber-shader - Cons:

  • More tricky to debug and optimise
  • Increased compile times

In reality, most projects are likely to use a combination of both approaches. For our Quell port we chose to go entirely with the individual shader approach, as our requirements were so simple and fixed.

The game relied on relatively few different combinations of the OpenGL render states. To give an idea of just how straightforward our shader requirements were, I have added the most complex here:

float4 main(
	float4 vColor : COLOR0,	
	float2 vTexCoord : TEXCOORD0,
	float2 vTexCoord1 : TEXCOORD1,
	float2 vTexCoord2 : TEXCOORD2,
	uniform sampler2D testTex : TEXUNIT0,
	uniform sampler2D testTex1 : TEXUNIT1,
	uniform sampler2D testTex2 : TEXUNIT2)
{
	float4 texResult = tex2D(testTex, vTexCoord);
	float4 texResult2 = tex2D(testTex1, vTexCoord1);
	float4 texResult3 = tex2D(testTex2, vTexCoord2);

	float4 currentCol = texResult;
	currentCol[0] = texResult3[0]*vColor[0];
	currentCol[1] = texResult3[1]*vColor[1];
	currentCol[2] = texResult3[2]*vColor[2];
	currentCol[3] = ((texResult2[3])*(texResult[3]))*vColor[3];
	
	return currentCol;
}

The Quell Vita code had a total of 13 shaders: eight shader programs (one vertex and seven fragment shaders), combined with specific blend modes. It was fairly easy to replace code in the Quell engine that set up all the OpenGL variables with calls to set a shader instead:

rlSetBlend(RL_BLEND_RGBA);
	rlSetMultiTexture(0, rlGetTexture(quellGame_getAtlasImage(QUELLATLAS_SURROUND, true)));
	rlSetMultiTexBlend(0, RL_TEXBLEND_MODULATE_PASS_INV_ALPHA_TO_NEXT);
	rlSetMultiTexture(1, rlGetTexture(paneDesatTexture));
	rlSetMultiTexBlend(1, RL_TEXBLEND_PREVIOUS_ALPHA_WITH_TEX_ALPHA);

became:

rlSetShader(RL_SHADER_BLEND_RGBA_4 );
The rl (render layer) functions are a set of functions wrapping the OpenGL functionality; the 4 in RL_SHADER_BLEND_RGBA_4 simply indicated this was our fourth variation of this RGBA shader - with so few shaders we didn't require a particularly descriptive naming convention.

These rl functions already existed in the Quell engine, but if the game to be ported doesn't use this sort of abstraction it is something you will want to add early on. It allows the rendering code to be abstracted away so that platform-specific changes can be made without affecting game code.

The idealist in me would really have liked to have implemented an uber-shader based system. However, this would have been overkill and required work by the FTG guys to support, something we worked hard to minimise. Porting is no different from any other programming task, in that you are always going to be weighing up 'getting the job done' against your idealised vision of how it should be done.

Ultimately, there were very few headaches in getting the graphics side of the game up and running, although there was some frustrating time wasted tracking down what I assumed was a memory overwrite in the rendering code. It was a while before I realised that, unlike calls such as glDrawArrays in OpenGL, where your array is copied when you make the call, the Vita's draw calls do not - that is, you cannot reuse the vertex buffer you pass to the Vita's draw calls until it is done drawing. As you can see from the screenshot below, doing so can make quite a mess.

Post Mortem: Porting Quell Memento to the PlayStation Vita
The results of reusing the vertex buffer prematurely meant that this...
Post Mortem: Porting Quell Memento to the PlayStation Vita

...occasionally looked a little more like this, often for just a single frame.

The fix for this was simply to use existing functionality in the API to wait until it was done with the buffer, but it was a timely reminder of the dangers of making assumptions about the ways things work on a new platform (and also what your bug may be, on any platform).

User Input

We were lucky here in that the earlier games had already been released on Sony's Xperia Play, meaning not a great deal of work was required to get the buttons working - a lot of the physical controls that exist on the Vita exist on the Xperia and the related functionality was already in place.

The Xperia Play smartphone features a similar gamepad layout to the PS Vita. Picture from Sony Mobile.
The Xperia Play smartphone features a similar gamepad layout to the PS Vita. Picture from Sony Mobile.

This meant that it was really just a matter of mapping the hardware keys to the software keys and passing the button "pressed" and "released" states to the existing input handling code.

The PS Vita features a rear touch pad. Photo by popculturegeek.
The PS Vita features a rear touch pad. Photo by popculturegeek.

As the game had originated on mobile devices, the same was true of the front touch panel. The rear touch panel did require a little finessing, the obvious issue being that you cannot simply feed these both into the same stream of inputs, because if a player is touching both panels and releases the front, the game may want to register that as the equivalent of releasing the back or it may not.

There was also a little work in getting inputs from the rear panel (which is not the same size as the screen) to feel as though they were mapping correctly to the front screen. This was achieved by disregarding a dead zone border around the edge of the rear panel and scaling the inputs inside this area to map to the screen.

//rear inputs don't seem to fully match range of front screen, so stretch in code
//these are values that felt easily accessible
#define REAR_DEADZONE_MIN_X 10
#define REAR_DEADZONE_MIN_Y 75
#define REAR_DEADZONE_MAX_X 950
#define REAR_DEADZONE_MAX_Y 430

#define REAR_STRETCH_X 960
#define REAR_STRETCH_Y 544

static vec2 vitaMapRearInputToScreen(int inputX, int inputY)
{
	vec2 stretchedInput;
	stretchedInput.x=(inputX-REAR_DEADZONE_MIN_X)*REAR_STRETCH_X/(REAR_DEADZONE_MAX_X-REAR_DEADZONE_MIN_X);
	stretchedInput.x=clampf(stretchedInput.x, 0, REAR_STRETCH_X);
	stretchedInput.y=(inputY-REAR_DEADZONE_MIN_Y)*REAR_STRETCH_Y/(REAR_DEADZONE_MAX_Y-REAR_DEADZONE_MIN_Y);
	stretchedInput.y=clampf(stretchedInput.y, 0, REAR_STRETCH_Y);
	return stretchedInput;
}

All in all, I think we got off pretty lightly here, partly due to how the game relies entirely on a simple swipe gesture. Porting across radically different interfaces can be a real headache and, done badly, has the potential to cripple an otherwise great game. Had we been porting a third person action game to the Wii, this section would have been considerably longer.

Audio

I won't lie; I have a real love/hate relationship with audio. In my time at Free Radical Design I spent a lot of time working with the audio guys on the engine team and sound designers to get to get audio into game and enjoyed it immensely. Audio really lifts a game and brings it to life.

Sadly, the more low level side of things, with its cocktail of file formats, sample rates, compression, voices, busses, file streaming and so on, has never really enthused me in the same way. So we approached this task with some trepidation.

Thankfully, the Vita SDK comes filled with (regularly updated) samples which thoroughly cover all the ways to use the audio API. The minimum you are going to want, even in the most simple of 2D games, is the ability to play one-off sounds (the game sound effects) and the ability to stream audio (music and any other large files which are too big to keep loaded into memory the entire time). In a lot of 2D games you could probably even choose to stick solely with mono and save yourself a little extra memory - perhaps even allowing you to avoid streaming completely.

With some great reference to work from in the samples, we had all the audio up and running in a couple of days. The only other major piece of work on the audio was a late switch in audio format from VAG to a proprietary format with a much higher level of compression, which reduced our audio memory usage to approximately 30% of what it had previously been.

In the end, the process of implementing the audio was a far less painful experience than I had feared.

Network

Quell Memento is a single player game with no networked gameplay and limited online features, so theoretically this should have been one of the more simple areas. The reality nicely highlights one of the challenges of porting to a PlayStation platform: the dreaded TRCs (Technical Requirement Checklist - a list of do's and don'ts developers must fulfill to pass QA).

I should point out that Sony isn't unique here; Microsoft and Nintendo have their equivalents. Unlike mobile, where online functionality is often provided by some third-party cross platform solution, or PC, where the only person passing judgement on your implementation will be the end user, on the consoles this area tends to come under a lot of scrutiny. This partly has to do with ensuring that the functionality provided by a service like PSN behaves in a consistent manner across titles and that parental locks, age ratings, and so on are adhered to.

As a result, if you are porting to a console, even for a game with relatively simple online features, this may take more time than you expect. For a port, complying with TRCs may be one of the most intrusive parts of the work you have to do. Specific requirements on how to handle events such as loss of connection or denial of access to features due to parental lock, and the timing and manner in which you must relay these things to the user, may well require a degree of back and forth between your game and network components that simply didn't exist in the original game.

We used a library provided by Sony that wraps up all of the low level setup and teardown of PSN and online tasks into a fairly simple interface, providing callbacks for all the asynchronous tasks. The calls from the game into the online functionality could be boiled down to a few distinct groups - login, store, and leaderboards - each with a few parameters to specify the details.

All this meant that an online request could be triggered with just a few lines of code, and we ended up with probably no more than five or six different functions called from the game to support the online features.

The callbacks from the Sony wrapper provide quite granular detail on anything that goes wrong, but for the most part these could simply be classed as a success or a failure and the appropriate callback to the game triggered. This meant we could also boil down the callbacks from the engine into the game into similarly few calls.

Failure states were handled as much as possible in the engine code. This meant that the Fallen Tree guys could continue to develop Quell without having to worry about Vita-specific failure states.

For example, if an engine function had a prerequisite call that could potentially fail, rather than requiring the game to call any prerequisites and then its request, we would call the prerequisite silently, caching the actual request. If the prerequisite failed we would dump the request and notify the game through the normal callback, invoking the dialog from the engine side. On success the request would be executed as intended.

Post Mortem: Porting Quell Memento to the PlayStation Vita

This generally worked well; as with any system that is added later and is doing its best to be non-intrusive there were one or two less-than-elegant pieces of code, but it did the job.

Save Games

Save games are worth mentioning because, as with the network functionality above, they're subject to a high degree of scrutiny in terms of TRCs. Save games are prone to two key errors: running out of file storage or running out of save quota.

(I have excluded save corruption as there really isn't a great deal you can do about a corrupt save; the system will alert you to it and you can inform the user, but all either of you can do is remove it and move on... and maybe have quiet little cry at all those lost hours.)

Running out of file system storage is pretty self explanatory: there simply isn't enough space to save what you want. The save quota is set during development of your game; it is essentially a self-declared limit on the amount of memory your application will ever need for save game data. This quota is not all allocated on installation of your game, however - it is not guaranteed to exist.

In handling each of these you really have two options.

If the game runs out of file system storage, you can:

  1. Alert the user but allow the application to continue, or
  2. Prevent progress of the application.

Regarding running out of save quota, you can:

  1. Make provisions for overwriting or deleting save data, or
  2. Make sure it never happens!

The nature of Quell allowed us to deal with this rather concisely by going with options 2 and 1, respectively. Quell isn't a game where you may want to jump back to your save of five minutes ago, so only one save is required and this is auto-created, -saved, and -loaded. The content and therefore size of the save is somewhat predictable.

On the first play our save system will attempt to allocate the maximum amount of memory it will ever need for your save file. If it can't do so - that is, if there is already insufficient file system storage available - it will display the standard message shown below:

Post Mortem: Porting Quell Memento to the PlayStation Vita

The player is not allowed to continue until they have resolved this issue themselves (by minimising or closing the app and deleting some data). Once they hit OK it will try again to allocate the memory. Once this initial save is created successfully, it is safe to assume that a shortage in the file system and save quota will never occur.


Other Considerations

TRCs and Submission

I have already briefly mentioned TRCs (the Technical Requirements Checklist) and as a disclaimer I would say that I'm happy TRCs exist; as a gamer things, like PSN have become such an integral part of the experience that I appreciate knowing I can expect a certain degree of consistency across games' behaviour.

That said, as a developer, they are a pain. We were lucky that the game was relatively simple and as such many TRCs could simply be disregarded as they didn't apply. Even if you are working on bringing a relatively simple game to any of the consoles, however, I would strongly advise you familiarise yourself with the rules of that platform early and refer to them often. What may have been acceptable on one platform may not fly on another, and you don't want to wait until you receive a big list of reasons why you failed QA to realise that you are doing it all wrong.

For a small team without a dedicated QA department, this can seem like a really daunting task, but a small bit of sense and planning can make all the difference.

Firstly, plenty of the requirements are just a specifically worded way of asking you not to do stupid things that you probably don't want to be doing anyway - thankfully, the FTG guys had already avoided doing anything stupid, so this was a good start.

Secondly, we kept a spreadsheet of all the requirements and whether they currently passed, failed, couldn't be tested yet, or simply weren't applicable. As key features went into the game, we could do a sweep of this list to update the status of each requirement and at the same time refresh our memories on what restrictions applied.

By the time we reached our QA phase, we had a pretty clear idea of where we stood with regards to TRCs and didn't find ourselves facing any nasty surprises.

Porting a Moving Target

Make sure you have clearly agreed time-frames and goals. This is more a business issue than technical but crucial if you are porting a game for someone else, even if it's just a hobby project amongst friends. (You want to stay friends, right?!)

When we started work on Quell Memento it wasn't finished and whilst there was a general feeling about when the finish date would be, nothing was set in stone. Ultimately the whole project took longer than expected.

Post Mortem: Porting Quell Memento to the PlayStation Vita

In hindsight, it would have been preferable to wait for the game to be completely finished - or at least far more complete - before beginning our port. As we were porting the engine it was rarely affected by new gameplay and content, but there were occasions when features required engine changes. There were also times when progress on porting the engine was blocked as we waited on new features to be added.

We have a great relationship with the guys at FTG and were lucky enough in these situations to have the flexibility to switch to our own projects for these periods (including investigating some of the Vita's more unique features such as the augmented reality), but as anyone who has ever attempted a bit of multitasking should know, this is not the most efficient way to work.


Things We Have Learnt

It is hard to point to any singular standout lessons that we learnt; we gained more of an incremental accumulation of knowledge regarding new tools, APIs and processes.

In the future we would perhaps be more bold in forcing (or at the very least suggesting) changes in the game code where it felt reasonable - we may have made some tasks harder than they needed to be this time round. But the definition of 'reasonable' is always going to vary wildly from project to project.

Additionally, we would probably wait for a game to be more complete before beginning work on a port in the future, having more people work on solidly it for less time. Again, the feasibility of this could vary hugely between projects depending on the release schedule. Having done it once, though, we can now far better estimate how long we may need.

Most importantly, we have gained months of valuable experience on a new platform, including its submission process - even getting a chance to investigate some of its unique features For a team that relies largely on work-for-hire and contract work as a source of income, the value of this can not be underestimated.


Conclusion

My advice for any of you considering a port to Vita would be to give it a crack. I think there is a certain mystique surrounding console development; we were fortunate to have experience in this field, but even without that you shouldn't be put off.

Sony are very welcoming to indies and small developers (something I think is becoming apparent to the wider game dev community) and, if you have a reasonable degree of technical game development knowledge, then with the great support from the Sony developer support team you shouldn't run into any insurmountable challenges.

Quell Memento for Vita is available now in SCEA and SCEE.

Advertisement