Never release poor quality!

One of the rules I have adopted is that I will never (if the choice is mine to make) release poor quality software/games/code/content/etc. I hate that rule with a passion even though I use it constantly. The reason why I hate it is because I often promise to release some code in the near future but then decide I would rather break my promise than release poor quality.
The reason why I don't want to release poor quality code can be summarized as followed:
- Improving the quality of an existing product is hard. If anyone (me included) would use my code then there is good chance that some of the poorer quality rubs off on the other code, making the final product of lower quality.
- Never feed a critic except his own words. I can't and won't recall the amount of times that I complained about some piece of code written by myself or others. If I complain about the code, why wouldn't others?
- Poor craftmanships reflects poorly.
- Releasing poor quality once, sets a precedent to lower the bar the next time you need to release something
And for those reasons only a shocking 10% of my work is released and that excludes any projects that I write pure for testing. When I look at my blog I know that I have more drafts (articles I wrote, but never posted) than actually posted articles.
So if you were ever wondering when I would release the code, then there is good chance that I won't. And for that I'm sorry. (but frankly you should be glad I don't release it
)
Release of 1.0.0.8 of Story Editor
Wait? What happend to 1.0.0.7? Did you skip it?
Well, truth be told it was released but a minute later i decided to pullback that release as there was a major bug with moving around the chapters and scenes (which was there also in the previous versions) and since that part of the code was next on my list of rewriting I have actually decided to rewrite it.
The version in front of you should work and the bugs with the outline are fixed.
Which brings me to another point. Rememeber me talking about how cool it would be if you could just keep track of al kinds of stuf? Well, you can now!
Just take a look under "View" and then "Manage" and you can create your own content types. So far the solution is rather bare bone, but then again it is only two days of work.
Because I have no achieved the minimum feature set I'm going to do some creative writing, after all that is why I created the application and see what other minor bugs and annoyances I can encounter. So don't expect any updates soon.
By the way: If you still haven't tried Story Editor, then you can download the installer and if for some reason you don't like it just uninstall it.
PS: There is a minor bug in the update checker of 1.0.0.6, it says it was unable to check, but in reality it did... Whoops
Story Editor v 1.0.0.4 (installer and auto-update)
It took longer than I had hoped, but the very first version of Story Editor, my favorite creative story writing software, now has an installer. No longer you will need to move around files. Just launch the installer and you are set to go.
I have also spend a bit of time to ensure that you don't need to worry if you have the latest version, because Story Editor will check if there is a new release for you. Nothing too intrusive, of course, because you are writing and you don't want to grab the mouse to click away an annoying "please restart your system" while you are writing.
When you see this at the bottom, just click on it and it will ask if you want the update, say yes and while it is being downloaded you can continue writing.
Once the download is complete, hit it again and the new version will be installed.
So what will be in the next version? Well, I'm going a bit back to add some more text editing functionality and also exporting/printing.
Don't worry about checking the website or reading my blog. From now on you will be notified
Extending exceptions
Sometimes you have a function which needs to communicate back on failure through special exceptions as you want to program have the option to fix certain functions. For example a formula whose input parameter is bad (example: begin date is after the end date) or when the database throws up or anything.
Now you could do the following:
public class EndDateBeforeBeginDateException : Exception { }
class example
{
void SomethingWithTime(DateTime begin, DateTime end)
{
if (begin > end) throw new EndDateBeforeBeginDateException();
// ... do something with time ....
}
void DemonstrateFunctionTriesToCorrectInsteadOfFail()
{
DateTime input_begin = new DateTime();
DateTime input_end = input_begin.AddDays(-1); // WRONG DATE ON PURPOSE!
do
{
try
{
SomethingWithTime(input_begin, input_end);
}
catch (EndDateBeforeBeginDateException)
{
// Date was most likely wrong ask user
var r = MessageBox.Show("The end date was before the begin date."
+ "Do you want to switch them and try again?",
"Switch dates?",
MessageBoxButtons.YesNo);
if (r != DialogResult.No) { return; } // quit function
var temp = input_begin;
input_begin = input_end;
input_end = temp;
continue; // Try again now
}
} while (false);
}
}
But what if you have a lot of parameters. You don't want to create thousands of exceptions. Well, you can try using tagged exceptions which looks like this.
public class TaggedException<T> : Exception { }
struct _EndDateBeforeBeginDateTag{}
struct _SameDateTag {}
struct _TimeDoesNotExistTag {}
struct _ThinkOfATagOnYourOwn {}
class example
{
void SomethingWithTime(DateTime begin, DateTime end)
{
if (begin > end) throw new TaggedException<_EndDateBeforeBeginDateTag>();
if (begin == end) throw new TaggedException<_SameDateTag>();
// ... do something with time ....
}
void DemonstrateFunctionTriesToCorrectInsteadOfFail()
{
DateTime input_begin = new DateTime();
DateTime input_end = input_begin.AddDays(-1); // WRONG DATE ON PURPOSE!
do
{
try
{
SomethingWithTime(input_begin, input_end);
}
catch (TaggedException<_EndDateBeforeBeginDateTag>)
{
// Date was most likely wrong ask user
var r = MessageBox.Show("The end date was before the begin date."
+ "Do you want to switch them and try again?",
"Switch dates?",
MessageBoxButtons.YesNo);
if (r != DialogResult.No) { return; } // quit function
var temp = input_begin;
input_begin = input_end;
input_end = temp;
continue; // Try again now
}catch (TaggedException<_SameDateTag>)
{
// Force the user to change one date
}catch (TaggedException<_ThinkOfATagOnYourOwn>)
{
// Tag seems obvious enough *wink*
}
} while (false);
}
}
Now you only have one Exception in your code though you can quickly and without having to write much code.
(And if you are smart you store extra info the tag which is stored in the exception).
The same trick also works in C++ using templates.
Comments
This part is almost straight from my programming style document.
This might sound stupid, but try to comment every other line (unless you have a lot of repeating or similar tasks). By doing so you get two advantages:
- Someone unskilled in programming or unfamiliar with what you are doing is able to read your code.
- You know what you are doing
The first advantage is important unless you are working alone and never expect to see your code again. In that case you should really ask yourself if you should even be writing that code.
The second one is important even if you have no trouble reading code. Let's take a look at the following example.
for(int index_person = 0; index_person < persons.size(); ++index_person)
{
for(int index_kids = 0; index_kids < persons[index_person].kids.size(); ++index_kids)
{
/* ... */
}
}
And then take a look at this example:
/* Iterating through the persons in the lists */
for(int index_person = 0; index_person < persons.size(); ++index_person)
{
/* Iterating through the kids of the persons in the list */
for(int index_kids = 0; index_kids < persons[index_person].kids.size(); ++index_kids)
{
/* checking if any of the persons in the list have a kid who is dead */
/* ... */
}
}
In the last example I only have to track back to the first comment prior to my line of code to know what I'm doing here. It's a pain to write so many comments but it makes code a whole lot easier to read.
Events in C++
This week I have decided to do some little work on Nova as I would like to use it for a game. But I’m currently missing a GUI. Since writing a GUI is often a pain while a nice GUI is its weight worth in gold it was worth to invest some time in it.
One of the very first things I have decided on is that I want a good and proper event management system. I like how it is done in C#
myButton.Click += new EventHandler(this.myButton_Click);
However something equally nice doesn't exist in plain C++, so I have decided to write one.
struct GuiEvent
{
bool cancel;
GuiEvent() : cancel(false) {}
};
class Button
{
public:
Event<GuiEvent> OnDown;
Event<GuiEvent> OnUp;
void FireClickEvent()
{
size_t cycle = 0; GuiEvent e;
while(OnDown.Fire(cycle, e)) {
if(e.cancel == true) return;
}
e = GuiEvent(); cycle = 0;
while(OnUp.Fire(cycle, e));
}
};
class Application : public BaseEvent::Receiver<Application>
{
Button m_StartButton;
public:
Application()
{
RegisterEvent<GuiEvent>(m_StartButton.OnDown, &Application::StartDown);
RegisterEvent<GuiEvent>(m_StartButton.OnUp, &Application::StartUp);
m_StartButton.FireClickEvent();
}
void StartUp(GuiEvent& eventParam)
{
std::cout << "The start button was released" << "\n";
}
void StartDown(GuiEvent& eventParam)
{
// If you set event param to true the release will never be called
//eventParam.cancel = true;
std::cout << "The start button is pressed down" << "\n";
}
};
int main(int argc, const char* argv[])
{
Application myApp;
return 0;
}
The above is rather primitive as I have written it quickly, but it looks nice and is code that is easy to understand. For the full source click here (C++ example of events)
Large scene rendering
There is one thing I don't like about floating point and integers and that is that they consist out of only certain amount of bits. An integer is at least 32 bits (on 32 systems at least). A float is also 32 bits. A double is 64 bits.
Since I'm currently thinking about a space game, I was wondering how to create a huge battle field (a whole solar system) in real time while having all the precision I need.
Doubles are not fast and take a lot of space and although I don't worry about space, speed is a bigger issue. If I want a huge battle and here I'm going to throw some numbers: One side can have as maximum 85 huge ships, 3010 fighters, makes 3960 weapon slots, which makes 19800 bullets flying around. And that is only one side. Since I need two sides for a war, I need to double the values (190 ships, 6020 fighters, 7920 hardpoints, 39600 bullets). Lets say that everything is represented by one location (which a 3D vector) it would mean 53730 locations. 53730 locations times 3 would be 161190 and that times [cci_cpp]sizeof(double)[/cci_cpp] would be 161190 * 8 bytes = 1289520 bytes (about 1MB) which is a lot to start with even if you ignore the fact that the problem is more that I have a lot than the doubles are bigger.
As I was considering the problem I realized something else. When I'm rendering, I will need to use floats. DirectX 9 requires floats and although I could send doubles it would half my data bandwidth. So what ever I choose, in the end I will need to use floats unless I want to have some penalty.
Using doubles for vertices are is a bad idea for the sake of precision alone.
But then I started thinking...
I don't need to render using doubles, I can simply render everything with floats and to ensure that precision is maintained. If something is not within the safe area of floating point rendering (let's say floats can have a maximum of 1024, and yes I now it can be a lot more) but the object in question is 2048 units away, I still want to render it. You can't simply let a sun disappear because it is beyond the range of your numbers, that would be weird.
Instead everything that is more than 1024 units away will be rendered first (farthest away first) and the distance also scales it down. Than I clear the Z buffer and render everything in the 1024 range.
[cc_text]
Sun has a size of 100
Sun is 2048 units away
Sun needs to be rendered.
To render it but maintain the correct look:
Scale sun down so that at 1024 it would have the same
size on screen as if it was rendered at 2048.
[/cc_text]
It was so simple that I thought it was silly I never thought about it. How you scale it however depends on the view and projection matrix.
I'm still not certain if I want to use doubles, but for my second problem I have a solution. Now I need to find one for my first.
Solved undesired template specification
A while ago (why do I always start with that) I wrote an blog entry about undesired template specification, what to encounter and how to work around it.
Anyway here is a quick definition of two structures I will be using in the article:
/**
* I will be using the following structures throughout the article
*/
template <typename T> struct Vector3<T> {
union {
struct { T x, y, z; }
T array[3];
};
Vector3<T>() : x(0), y(0), z(0) {}
Vector3<T>(T nx, T ny, T nz) : x(nx), y(ny), z(nz) {}
};
template <typename T> struct Vector4<T> {
union {
struct { T x, y, z, w; }
T array[4];
};
Vector4<T>() : x(0), y(0), z(0), w(0) {}
Vector3<T>(T nx, T ny, T nz, T nw) : x(nx), y(ny), z(nz), w(nw) {}
};
typedef Vector3<unsigned int> Vector3u;
typedef Vector3<float> Vector3f;
typedef Vector4<unsigned int> Vector4u;
typedef Vector4<float> Vector4f;
struct SVertex
{
Vector4f pos;
Vector3f normal;
Vector2f texcoord;
};
Because of Brick (3D random dungeon generator that takes design into account) I have noticed that there is one thing I do failry often:
Vector3f position; SVertex vertex; /* Need to draw it, so I store position in vertex */ vertex.pos = position; // ERROR! Trying to assign Vector3f to Vector4f!!
And finally I used defines to do the conversion for me:
#define VEC3TOVEC4(v) Vector4f((v).x, (v).y, (v).z, 0) #define VEC4TOVEC3(v) Vector3f((v).x, (v).y, (v).z) /* New code becomes */ vertex.pos = VEC3TOVEC4(position); // Works
Of course the above code is not nice to look at and I find it even plain ugly, but it works. However I don't want to do that in future projects (it feels like a hack), I would need to define something like that for every type (float, double, unsigned int et cetera) and on top of that it generates warnings:
Vector3<double> position; // Notice it is unsigned! SVertex vertex; /* Need to draw it, so I store position in vertex */ vertex.pos = VEC3TOVEC4(position); // Works, but generates warning about losing information
But I wouldn't be writing this post unless I tackled that little issue, and for once I can add that the solution is quite nice as well.
Vector3<double> position; // Notice it is unsigned! SVertex vertex; /* Need to draw it, so I store position in vertex */ vertex.pos.Set(position.array, 3); // Works, no errors and no warnings vertex.pos = Vector4f(position.array, 3); // Works fine as well
So what did I change?
Well, I used mutliple template (one for the class and for the function/constructor). This looks something like this:
template <typename T> struct Vector4
{
/* ... */
template <typename R>
explicit inline Vector4<T>(const R* values, const unsigned int elements/*=4*/);
template <typename R>
inline Vector4<T>& Set(const R* values, const unsigned int elements/*=4*/);
/* ... */
};
// Implementation
template <typename T> template <typename R>
Vector4<T>::Vector4(const R* values, unsigned int elements)
: x(elements > 0 ? (T)values[0] : 0), y(elements > 1 ? (T)values[1] : 0)
, z(elements > 2 ? (T)values[2] : 0), w(elements > 3 ? (T)values[3] : 0)
{
}
template <typename T> template <typename R>
Vector4<T>& Vector4<T>::Set(const R* values, const unsigned int elements)
{
x = (elements > 0 ? (T)values[0] : 0);
y = (elements > 1 ? (T)values[1] : 0);
z = (elements > 2 ? (T)values[2] : 0);
w = (elements > 3 ? (T)values[3] : 0);
return *this;
}
If you take a look at the code I think it is quite clear except that you might have some questions.
-
Q: Why do you use [cci_cpp]explicit[/cci_cpp] with the constructor?A: Because that prevents the implicit use of constructors. If I would allow it a [cci_cpp]Vector4u[/cci_cpp] could be implicit assigned to [cci_cpp]Vector3f[/cci_cpp], although it would be missing an argument. However I think that when you are converting, you should be somewhat aware of it, especially when it can be expensive.
-
Q: Why have you commented out the default value for [cci_cpp]elements[/cci_cpp]?A: Because you don't know how many elements there are in [cci_cpp]values[/cci_cpp] might be (there is a method to find out).
-
Q: So why don't you find out automatically and what is with those conditionals in the constructor?A: Those two are related. By telling it explicitly there is a real good chance that the compiler removes the conditionals, so the [cci_cpp] ( check ? true-value : false-value) [/cci_cpp] check will be removed.
Combo hit!! in code
I have always wondered how hard it would be to write a combo system. Not that hard I guess. And after a bit of morning programming I already got it working.
The only reason it took longer than anticipated was because of muscle memory. One of the features I wanted to test was the delay. For example you want to do the "asdf" combo, but you are for some reason not fast enough, than the combo should not start. Simulating this is easy, just begin the combo and stop somewhere for a second and then complete the combo. So "asd", pause and then "f".
However when I tried that for some reason the combo was sometimes completed. Only after adding the debug messages I noticed that I often automatically did complete the combo. The problem was muscle memory.
Anyway below is the code and if anyone wants to extend it (wrong next key, combo breakers, roman cancel, and follow-up combos) feel free to do so and let me know.
/*******************************************************************************
* The MIT License
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright (c) 2010 Wouter Lindenhof (http://limegarden.net)
*
* Demonstration of a simple ComboHit system
*******************************************************************************/
#include <Windows.h>
#include <iostream>
#include <vector>
#pragma comment(lib, "Winmm.lib")
#define DEBUGLOG 1 // Set to 0 to turn debug messages off
class KeyHit
{
public:
UINT m_Key;
UINT m_Delay;
UINT m_Waiting;
public:
KeyHit(UINT key, UINT delay) : m_Key(key), m_Delay(delay), m_Waiting(0) { }
};
class HitCombo
{
UINT m_SequenceIndex;
std::vector<KeyHit> m_Keys;
public:
HitCombo() : m_SequenceIndex(0) { }
void Cancel();
void Update(DWORD ms);
operator bool();
HitCombo& operator << (const KeyHit& hit);
};
int main(int argc, const char* argv[])
{
std::cout << "-----------------------------------------------" << std::endl;
std::cout << "This is a combo key tester: " << std::endl;
std::cout << "Press \"ASDF\" quickly to do a combo hit" << std::endl;
std::cout << "Press \"Wouter\" quickly to write my name" << std::endl;
std::cout << "Press SHIFT and then escape to quit" << std::endl;
std::cout << "-----------------------------------------------" << std::endl;
HitCombo QuitApplication, ComboHit, WouterCombo;
QuitApplication << KeyHit(VK_SHIFT, 250) << KeyHit(VK_ESCAPE, 250);
ComboHit << KeyHit('A', 250) << KeyHit('S', 250) << KeyHit('D', 250)
<< KeyHit('F', 250);
WouterCombo << KeyHit('W', 250) << KeyHit('O', 250) << KeyHit('U', 250)
<< KeyHit('T', 250) << KeyHit('E', 250) << KeyHit('R', 250);
DWORD lastTime = timeGetTime();
DWORD curTime = lastTime;
DWORD difference = 0;
while(true)
{
curTime = timeGetTime();
difference = curTime - lastTime;
lastTime = curTime;
if(ComboHit)
{
std::cout << "You did a combo hit!!" << std::endl;
WouterCombo.Cancel();
QuitApplication.Cancel();
}
if(WouterCombo)
{
std::cout << "You wrote 'Wouter', good for you!" << std::endl;
ComboHit.Cancel();
QuitApplication.Cancel();
}
if(QuitApplication)
{
std::cout << "You quit the application!" << std::endl;
ComboHit.Cancel();
WouterCombo.Cancel();
break;
}
ComboHit.Update(difference);
QuitApplication.Update(difference);
WouterCombo.Update(difference);
}
return 0;
}
void HitCombo::Cancel() {
m_SequenceIndex = 0;
}
// Implementation
HitCombo& HitCombo::operator <<(const KeyHit &hit) {
m_Keys.push_back(hit);
return *this;
}
HitCombo::operator bool() {
return m_SequenceIndex == m_Keys.size();
}
void HitCombo::Update(DWORD ms)
{
if(m_SequenceIndex < m_Keys.size())
{
KeyHit& hit = m_Keys[m_SequenceIndex];
hit.m_Waiting += ms;
if(GetAsyncKeyState(hit.m_Key) != 0)
{
if(hit.m_Waiting < hit.m_Delay)
{
hit.m_Waiting = 0;
m_SequenceIndex++;
#if DEBUGLOG = 1
std::cout << "you pressed key " << (char)hit.m_Key << std::endl;
#endif
}else
{
#if DEBUGLOG = 1
std::cout << "Delay too long" << std::endl;
#endif
hit.m_Waiting = 0;
m_SequenceIndex = 0;
}
if(m_SequenceIndex == 0)
{
hit.m_Waiting = 0;
}
}else if(m_SequenceIndex==0)
{
hit.m_Waiting = 0;
}else
{
if(hit.m_Waiting > hit.m_Delay)
{
m_SequenceIndex = 0;
hit.m_Waiting = 0;
#if DEBUGLOG
std::cout << "Delay too long" << std::endl;
#endif
}
}
}else
{
m_SequenceIndex = 0;
KeyHit& hit = m_Keys[m_SequenceIndex];
hit.m_Waiting = 0;
}
}
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!


