Rubber Ducky, you’re the one!
Riveting. That number in the upper left is the FPS display. I don’t like it. Let’s mess with it.
Now if you have built the sample application you’ll notice that my build looks a bit different than yours. I did some work on automatic recognition of the target system, the build environment, and so on. This is relatively easy, but I made it difficult (three header files that will recognize pretty much every processor/build environment since 1980). I split the previous drawFrameRate function into two, making a new function drawText that drawFrameRate calls. I then added a new function, drawBuildString. All preprocessor definitions are strings (automatically selected, but I’m not posting that) with the exception of GAMEVERSION, which is a float. In any case, the relevant code looks like this:
// Debug vs Release
#ifdef _DEBUG
#define BUILD "Debug"
#else
#define BUILD "Release"
#endif
#define BUILDSTRINGPARAMS GAMENAME, GAMEVERSION, GAMESUBVERSION, __DATE__, __TIME__
, BUILD, OS_NAME, HW_PROCESSOR_NAME
#define BUILDSTRINGFORMAT "%s %1.2f%s.%s.%s.%s %s %s"
void Core::render(long elapsedTime)
{
//…
// Draw compile info
drawBuildString(5, 1);
// Draw the fps
//drawFrameRate(_font, Vector4(0, 0.5f, 1, 1), 5, 10, getFrameRate());
drawFrameRate(5, 15);
}
void Core::drawFrameRate(unsigned int x, unsigned int y)
{
char buffer[16];
sprintf(buffer, "%u FPS", getFrameRate());
drawText(_font, Vector4(0, 0.5f, 1, 1), x, y, buffer);
}
void Core::drawBuildString(unsigned int x, unsigned int y)
{
char buffer[128];
sprintf(buffer, BUILDSTRINGFORMAT, BUILDSTRINGPARAMS);
drawText(_font, Vector4(0, 0.5f, 1, 1), x, y, buffer);
}
void Core::drawText(Font* font, const Vector4& color, unsigned int x, unsigned int y, char* buffer)
{
font->begin();
font->drawText(buffer, x, y, color, 20);
font->end();
}
Now we have a baseline to build a real application. My first concern is file system/network streaming. I want a system where I can precache octree nodes and stream them regardless of data source (the application does not know or care whether the data comes from the file system or the interwebs). Additionally, I want each level of the octree to contain a mipmap of the combined sublevels. By this I mean that if I load the top level of the octree, that level contains a lo-res version of all necessary data for rendering. Each subdivision (leaf) of the octree contains increased detail. We will see how well this goes.
Prior to that, I need to deal with file formats. Gameplay includes a proprietary bundle format (.gpb) that requires a proprietary tool to build (think Doom WADs back in the day - http://doom.wikia.com/wiki/WAD). It is a well thought out, comprehensive format. What seems to be lacking is support for compression and encryption. For this, I will use the public domain LZMA SDK that can run on ARM, x86 (actually 386 onward!!!), PowerPC, and so on. The question is how to do this. If I were designing this from scratch, I’d say that I would want to compress the data within the container. I want to minimize my impact on the SDK, and avoid unnecessary rewriting of the toolchain, so I don’t think that is the way to go.
What I think I need to build is a comprehensive Resource Management system. The Bundle code does a lot of this already; however, it appears to be path dependent. By this, I mean that assets are represented in code by their string path. If I want my rubber ducky model, I load it:
// Load mesh/scene from file
Bundle* bundle = Bundle::create("res/duck.gpb");
_scene = bundle->loadScene();
SAFE_RELEASE(bundle);
Then every time I want it I attempt:
// Get the duck node
_modelNode = _scene->findNode("duck");
This code isn’t checked, so if “duck” doesn’t exist in the scene, I crash. I don’t want to hardcode “duck” all over the place. And, I don’t want to crash if “duck” doesn’t exist. So what can I do with this?
So, to sum up, I need to build a resource manager with the following properties:
- Transparent streaming from either local or remote file system
- Precache capability
- Intelligent unload capability
- Mipmaps/Clipmaps/Level of detail (ideally the lowest level of detail will be compact enough to always be in memory)
- Compression/Encryption support
- Null (default, placeholder) models/objects
- Ability to load resources individually or by node/cell
- Centralized media manager not reliant on path or object strings
- Reference counting for automatic release of memory?