Nova’s Achilles heel
Nova’s Achilles heel is the math and a lot needs to be improved there. Instead of attempting to improve I thought I would use a high quality math library instead (in this case vmmlib). Using SVN external I added it so that it would automatically fetch the latest version from their SVN and be done with it. Problem is that I’m using DirectX which uses row major matrices and vmmlib was written to be used with OpenGL which uses column major matrices. So after a huge rewrite and removing the old math headers I tried to run Brick and see if it worked, I had hoped that by setting the effect files to use column major matrices I would let it use one system. Seeing the result, it either didn’t work or something else had gone wrong.
I don’t know what exactly went wrong (besides the obvious) but I guess that instead of using another library I just have to finish and improve my own math library. It’s a good thing SVN allows me to revert.
A good math library is essential for a game developer. It has to be easy to use and clear but I also want answers on the following questions when I’m using it:
- When I define a quaternion is it written as W-X-Y-Z or as X-Y-Z-W?
- Does a multiplication operator between two matrices do a matrix multiplication or an unit multiplication?
- Also how safe are the functions?
- How do I prevent hidden cost?
- And how easy is it to cast from one to another? Vector3<float> to Vector3<int> might seems obvious but it requires code to support it. And I could also cast Vector3 to Vector2.
Then there are the bigger question about optimization, like do we use SIMD or not.
The biggest problem is of course to ensure that all math is correct. Most of the time I use it by instinct, but in this case I actually have to relearn all the math again, double check, ensure that I’m using the right version, triple check. Obviously I experience it as a pain, but it as they say:
No pain, no gain!
Smart pointers: A dumb idea?
A while ago I wrote a smart pointer for Nova and I have been wondering on whether or not I should use it. And if I did choose to use it to what degree.
Smart pointers are useful, I use the boost variant often enough, but like everything you shouldn’t fully depend on it. Pointers are in many cases good enough. The only thing why smart pointers are so useful is that you don’t have to worry about the lifetime of the object (when the object is destroyed).
In many cases the only time you worry about is when data needs to be shared, for example a texture, as you don’t want to load the same data twice. But another simple technique is the IUnknown interface which creates an object that will delete itself when it has been released as many times as it was created. You still don’t have to worry about the lifetime of the object, you only have to remind you to call release when you no longer need an object. If nothing requires that object the call to release will cause it to delete itself.
Here is the basic code:
[cc_cpp]
/* IBaseObject.h */
class IBaseObject{
private:
unsigned int m_ReferenceCounter;
protected:
IBaseObject();
public:
virtual ~IBaseObject() = 0;
unsigned int AddRef();
unsigned int Release();
};
/* IBaseObject.cpp */
#include "IBaseObject.h"
IBaseObject::IBaseObject() : m_ReferenceCounter(1)
{
}
IBaseObject::~IBaseObject() {}
unsigned int IBaseObject::AddRef(){
return ++m_ReferenceCounter;
}
unsigned int IBaseObject::Release() {
--m_ReferenceCounter;
if(m_ReferenceCounter == 0)
{
delete this;
}
return m_ReferenceCounter;
}
[/cc_cpp]
After some thought on the issue I have decided that IUnknown is far superior to a smart pointer. The majority of the smart pointers I have encountered and written work on the same basic principle. Each smart pointer has a pointer to the object and also a pointer to an integer in which you store the amount of copies. That means that if you look at the code it will look something like this:
[cc_cpp]
template
class smart_ptr
{
T* m_Data;
unsigned int* m_Copies;
};
[/cc_cpp]
When you think about how smart_ptr really works, you will think how stupid the idea is. For every copy of the object you will have two extra pointers, assuming 32 bit system, that would be 8 bytes extra for every copy.
The second issue is a bit more hidden but if you have this function:
[cc_cpp]
class CObject; // Just an object
void accidental_copy(smart_ptr
[/cc_cpp]
You will be making an copy of the object, which means that you will have an extra construct and destruct function to take in account. Which means that a smart pointer not only increases the amount of memory needed, but also reduces the speed. With a pointer you won't have the above problems.
There is however one huge advantage that a smart pointer has but IUnknown doesn't: Smart pointers can work with virtually any type while to use IUnknown the object needs to be derived from it. However since I'm writing the code for Nova I can just make sure that all objects derive from IUnknown.
To add an conclusion, I have decided to before using smart pointers I should first try and see if there is another solution.
Developing for the iPhone
For those who follow me on twitter this post is old news or it might be a minor refreshment as the majority of the content has already been posted on twitter.
At my internship I have been developing for the iPhone and boy oh boy, can I make a list of things to complain about. Luckily there are also a few good things and they balance each other but it’s a pain when you cannot unleash every bit of skill you have. Let’s start with the sour part.
- There is no stencil buffer. I think that the stencil buffer is as old as Duke Nukem 3D, which was released in 1993. It’s used for shadows and a few other things. However for some reason it is not supported on the iPhone (at V2.2.1 but this might change in the future) and it makes no sense.
- Secondly the iPhone is under clocked (meaning the CPU is running at lower speed than what it should run at). The majority of the hardware these days are able to dynamically set the clock speed of the hardware. I can accept the reason why apple has done it (preserving the battery) but when it comes to games it’s like with racing cars. You don’t want a F1 car being capped at 120 KM/H because you aren’t suppose to go faster than that on the highway. In apple’s defense, the iPhone has never been intended to be primarily a gaming device.
- Third is apple is really strict in what is allowed or not and some parts of the iPhone (like the photo camera) should only be accessed by calling a function and then except you have no longer control until a picture has been taken using the graphical user interface apple designed. Using it directly in some other fashion increases the chance that the application will be rejected. On the other hand some applications are allowed because some big guys back it (google is one of the companies that ignored the guidelines of apple and still got accepted).
There are still a few other problems (no multitasking for example, API might break with new firmware update) with the iPhone but let’s move on to the sweet part of the iPhone.
Actually the only one I can think of is that the distribution of applications can only be done through the apple app store. There is no such thing for the windows mobile or symbian. This way apple can also guarantee the quality of the applications, however I find it a mood point since an application that is poorly written is unlikely to be successful.
Actually there are a few more things, the emulator is good (better than the one for the Nintendo DS) and the API is reasonable documented (inconsistence in quality, but overall reasonable).