Limegarden.net Personal site of Wouter Lindenhof

17May/100

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)

7Apr/103

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.

  1. Q: Why do you use explicit with the constructor?
    A: Because that prevents the implicit use of constructors. If I would allow it a Vector4u could be implicit assigned to Vector3f, 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.
  2. Q: Why have you commented out the default value for elements?
    A: Because you don't know how many elements there are in values might be (there is a method to find out).
  3. 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  ( check ? true-value : false-value) check will be removed.
6Apr/100

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;
	}
}
24Mar/100

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/* 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;
}

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:

1
2
3
4
5
6
template <typename T>
class smart_ptr
{
    T* m_Data;
    unsigned int* m_Copies;
};

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:

1
2
class CObject;  // Just an object
void accidental_copy(smart_ptr<CObject> copyParam) { /** does something **/ }

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.

23Mar/100

Nova – Alpha 1

I have given Nova, my graphics engine, a milestone named “Alpha 1”. This means that the engine will need to fulfill certain conditions at a certain time.

The good news is that I might release it to the public for free (including source) if I find the quality good enough.

I have been using Nova for quite sometime now for my graduation project and except for a few small issues (the math part is not to my liking) I have absolute no issues with it. This is rare since I tend to over criticize my work (I once argued with my teacher after getting the highest possible score because I felt the need to point out the mistakes I made).

If your expecting a fully fledged engine with scene graphs, model loaders and million of other features I think I will have to disappoint you. Nova was intended to be an engine that was in the first place easy to use and in the second place was flexible. At the current state it is a perfect engine for rapid prototyping and highly specialized low level work. But that might change with later iterations. After all this is only the first release (an alpha to boot).

Anyway I will post more information about the possible release over time. The milestone for now has been set on 1 may of 2010.

21Mar/101

“Ordered Programming” Technique

When it comes to programming there many, many techniques. One of the techniques I tried is ordered programming. The idea behind it is that quality is assured and nothing can be forgotten. While I was rewriting Brick I decided to use this technique. What it basically does is that you write a “TODO” in the code, for example: “Load configuration file”. And when you run the application in debug mode, it will break when it arrives at that point.

As you can see this has one huge disadvantage and that is that in order to run the entire program all the “TODO” have to be resolved. There is also one huge advantage which is that after you have done something, you will change “TODO” in to “DONE”. The next time you go trough your application, you will notice that the code has now been documented. This is a huge advantage when you write large pieces of code, which you will rarely though in the near future.

However the disadvantage, having to program in the order that the program runs might be too big in some cases. For example some features will be added later as they are not needed now. For example you have written a OBJ loader that handles triangles, but not quads, in this case you might not want to write the quad loading code just yet as you have to focus on the rendering part. For that reason I have decided to add levels, the lower the level the higher the priority. You can think of it in terms as first todo, second todo, etc. If you reach a stage in your development, where you have done all first todo’s, you just increase the number and see where it breaks then.

Here is an example of how it looks when you are writing todo’s.

1
2
3
4
5
6
7
8
9
#include "OrderProgramming.hpp"
int main(int argc, const char** argv)
{
    ORDER_PROG_TODO("Setup Memory Checkpoint", 0);
    ORDER_PROG_TODO("Initialize graphics engine", 0);
    ORDER_PROG_TODO("Run the game", 0);
    ORDER_PROG_TODO("Shutdown the graphics engine", 0);
    ORDER_PROG_TODO("Check if there are memory leaks", 0);
}

And here how it looks at a later stage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <crtdbg.h>
#include "OrderProgramming.hpp"
class IGraphics;
IGraphics* InitGraphicsEngine();
void GameFunction(IGraphics* graphics);
int main(int argc, const char** argv)
{
    _CrtMemState memstate;
    _CrtMemCheckpoint(&memstate);
    ORDER_PROG_DONE("Setup Memory Checkpoint", 0);
   
    IGraphics* myGraphics = InitGraphicsEngine();
    ORDER_PROG_DONE("Initialize graphics engine", 0);
   
    GameFunction(myGraphics);
    ORDER_PROG_DONE("Run the game", 0);
   
    if(myGraphics)
        delete myGraphics;
    ORDER_PROG_DONE("Shutdown the graphics engine", 0);
   
    _CrtMemDumpAllObjectsSince(&memstate);
    ORDER_PROG_DONE("Check if there are memory leaks", 0);
}

And here is the header you will need to include:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// OrderProgramming.hpp
// Generic functions can be defined before inclusion
// - ORDER_PROG_DEBUGBREAK:     Breaks the process if possible
// - ORDER_PROG_ASSERT:         Tries to assert a function
// - ORDER_PROG_OUTPUT:         Debug output function
#ifndef __ORDER_PROGRAMMING_HPP__
#define __ORDER_PROGRAMMING_HPP__

#define ORDER_PROG_STRINGIFY(x) #x
#define ORDER_PROG_TOSTRING(x) ORDER_PROG_STRINGIFY(x)
#define ORDER_PROG_FILE __FILE__
#define ORDER_PROG_LINE ORDER_PROG_TOSTRING(__LINE__)
#define ORDER_PROG_HERE ORDER_PROG_FILE"("ORDER_PROG_LINE") : "

#ifndef ORDER_PROG_DUMMY
#   define ORDER_PROG_DUMMY() {(void)0;}
#endif
// Lower than this level will cause the order to be taken in account
#ifndef ORDER_PROG_LEVEL
#   define ORDER_PROG_LEVEL 1
#endif

#ifndef ORDER_PROG_DEBUGBREAK
#   if defined(_WIN32)
#       include <intrin.h>
#       define ORDER_PROG_DEBUGBREAK __debugbreak();
// #   elif (???)
#   else
#       define ORDER_PROG_DEBUGBREAK {__asm{int 3};}
#   endif
#endif

// Platform independent (most of the time)
#ifndef ORDER_PROG_ASSERT
#   include <cassert>
#   define ORDER_PROG_ASSERT(expression) assert(expression);
#endif

// Platform dependent
#ifndef ORDER_PROG_OUTPUT
#   if defined(_WIN32)
#       include <windows.h>
#       define ORDER_PROG_OUTPUT(output) OutputDebugStringA((output));
//# elif (???)
//#     define ORDER_PROG_OUTPUT(output) ::std::clog << (output);
#   else
#       define ORDER_PROG_OUTPUT(output) ORDER_PROG_DUMMY()
#   endif
#endif

#ifdef ORDER_PROG_NOBLOCK
#   define ORDER_PROG_BLOCK(reason) ORDER_PROG_DUMMY();
#else
#   define ORDER_PROG_BLOCK(reason) ORDER_PROG_ASSERT(0 && (reason))
#endif

#define ORDER_PROG_TODO(reason, level) { if((level) < ORDER_PROG_LEVEL){ ORDER_PROG_DEBUGBREAK; ORDER_PROG_BLOCK(reason) } }
#define ORDER_PROG_TODO0(reason) ORDER_PROG_TODO(reason, 0);

#define ORDER_PROG_DONE(reason, level) { if( (level) < ORDER_PROG_LEVEL) { static bool _once=true; if(_once) { ORDER_PROG_OUTPUT(ORDER_PROG_HERE); ORDER_PROG_OUTPUT(reason); ORDER_PROG_OUTPUT("\n"); _once = false; } } }
#define ORDER_PROG_DONE0(reason) ORDER_PROG_DONE(reason, 0)

#endif // __ORDER_PROGRAMMING_HPP__
10Mar/100

Marketing and fuzzy distribution

I have mentioned fuzzy logic and random distribution before but I think that it is also being applied in some marketing strategies.

A supermarket chain in our country is giving away collectibles in the form of images of football players (soccer for the Americans). For every, Oh… I don’t know, € 5 , you spend you will get 5 random pictures.

At lunch my mother, who collects them, was going over a list of friends seeing if they have a picture she doesn’t have or the other way around and she noted that certain images nobody seems to have.

If you think about it from a marketing perspective it makes a lot sense why she doesn’t have certain images. The marketing strategy is all about making you willing to pay a certain amount or attract customers because you want those pictures. Once you have them, the marketing strategy will no longer have affect on you. It is in interest of the marketing company to try and keep you as long as possible under the effect of the marketing strategy.

One way of doing it by doing an imbalanced distribution: Certain pictures will not be distributed in certain locations. That way the customer under the effect of marketing will keep buying. Of course this won’t hold in the long run, so what you do is slowly slide the distribution.

Sliding random distribution:

A distribution whose content is randomized will only distribute a small subset which moves over the entire distribution so that in the end the entire content was equally distributed, however if a moment in time was used only a small subset would have been available.

If you have trouble understanding think of it as traveling from the north pole to the south pole visiting every restaurant you can find. At every stop you will select one random soup on the menu. Each place has different flavors and as you go more and more south you will encounter different flavors. However because your are “sliding” you will often encounter the same soup.

Anyway if that wasn’t clear here is it in code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <algorithm>
#include <iomanip>

#define MAX_AMOUNT 100
#define SLIDER_SIZE 5
/* Uncomment the next line to see the values in random order */
#define USE_RANDOM_ORDER

class SlidingDistribution{
    int m_Values[MAX_AMOUNT];
    int m_SliderBegin;
    int m_SubPos;
public:
    SlidingDistribution() : m_SliderBegin(0), m_SubPos(0) {
        for(int i =0; i < MAX_AMOUNT; ++i)
        {
            m_Values[i] = i;
        }
#ifdef USE_RANDOM_ORDER
        std::random_shuffle(m_Values, m_Values + MAX_AMOUNT);
#endif
    }

    int GetRandomNumber(){
        m_SubPos += 1;
        if(m_SubPos % SLIDER_SIZE == 0)
        {
            m_SliderBegin = (m_SliderBegin + 1) % MAX_AMOUNT;
            m_SubPos = 0;
        }
        return m_Values[(m_SliderBegin + (m_SubPos % SLIDER_SIZE))%MAX_AMOUNT];
    }
};


int main(int argc, const char** argv)
{
    SlidingDistribution distribution;
    int amounts = 0;
    do{    
        int alignCounter = 0;
        while(amounts)
        {
            std::cout << std::setfill(' ') << std::setw(3) << distribution.GetRandomNumber();
            alignCounter++;
            if(alignCounter >= 14)
            {
                std::cout << "\n";
                alignCounter = 0;
            }else
            {
                std::cout << " ";
            }
           
            amounts--;
        }
        std::cout << "\n" << "How many values do you wish to see? (type 0 to quit)\nLoops: ";
        std::cin >> amounts;
    } while(amounts);
    return 0;
}
2Mar/102

Wavefront Obj Mesh Loader

UPDATED 2010-03-02 11:07: There was a minor bug in the code which caused to tokens recognition to file. You won't encounter it in an obj file, but I fixed it for the good order.

I can remember the first time I wrote my Obj Mesh loader. It took hours. Today I needed also an obj mesh loader and this time it took mere minutes (under 15 minutes at least), so I have decided to share it. Keep in mind you should most likely separate it in header and source files.


/**
 * The MIT License
 *
 * Copyright (c) 2010 Wouter Lindenhof (http://limegarden.net)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <string>
#include <vector>
#include <sstream>
#include <fstream>

#define TOKEN_VERTEX_POS "v"
#define TOKEN_VERTEX_NOR "vn"
#define TOKEN_VERTEX_TEX "vt"
#define TOKEN_FACE "f"

struct Vector2f{
    float x, y;
};
struct Vector3f{
    float x, y, z;
};

struct ObjMeshVertex{
    Vector3f pos;
    Vector2f texcoord;
    Vector3f normal;
};

/* This is a triangle, that we can render */
struct ObjMeshFace{
    ObjMeshVertex vertices[3];
};

/* This contains a list of triangles */
struct ObjMesh{
    std::vector<ObjMeshFace> faces;
};

/* Internal structure */
struct _ObjMeshFaceIndex{
    int pos_index[3];
    int tex_index[3];
    int nor_index[3];
};

/* Call this function to load a model, only loads trianglized meshes */
ObjMesh LoadObjMesh(std::string filename){
    ObjMesh myMesh;

    std::vector<Vector3f>           positions;
    std::vector<Vector2f>           texcoords;
    std::vector<Vector3f>           normals;
    std::vector<_ObjMeshFaceIndex>  faces;
    /**
     * Load file, parse it
     * Lines beginning with:
     * '#'  are comments can be ignored
     * 'v'  are vertices positions (3 floats that can be positive or negative)
     * 'vt' are vertices texcoords (2 floats that can be positive or negative)
     * 'vn' are vertices normals   (3 floats that can be positive or negative)
     * 'f'  are faces, 3 values that contain 3 values which are separated by / and <space>
     */

    char char_buffer[256];
    std::ifstream filestream;
    filestream.open(filename.c_str());
    while(filestream.eof() == false && filestream.bad() == false){
        memset(char_buffer, 0, 256);
        filestream.getline(char_buffer, 256);
        /* FIXED:
         * Where strlen stood was first 256, however this would cause a problem
         * when you only have a token
         */
        std::stringstream str_stream(std::string(char_buffer, strlen(char_buffer)));
        std::string type_str;
        str_stream >> type_str;
        if(type_str == TOKEN_VERTEX_POS){
            Vector3f pos;
            str_stream >> pos.x >> pos.y >> pos.z;
            positions.push_back(pos);
        }else if(type_str == TOKEN_VERTEX_TEX){
            Vector2f tex;
            str_stream >> tex.x >> tex.y;
            texcoords.push_back(tex);
        }else if(type_str == TOKEN_VERTEX_NOR){
            Vector3f nor;
            str_stream >> nor.x >> nor.y >> nor.z;
            normals.push_back(nor);
        }else if(type_str == TOKEN_FACE){
            _ObjMeshFaceIndex face_index;
            char interupt;
            for(int i = 0; i < 3; ++i){
                str_stream >>  face_index.pos_index[i] >> interupt
                           >> face_index.tex_index[i]  >> interupt
                           >> face_index.nor_index[i];
            }
            faces.push_back(face_index);
        }
    }
    filestream.close();

    for(size_t i = 0; i < faces.size(); ++i){
        ObjMeshFace face;
        for(size_t j = 0; j < 3; ++j){
            face.vertices[j].pos        = positions[faces[i].pos_index[j] - 1];
            face.vertices[j].texcoord   = texcoords[faces[i].tex_index[j] - 1];
            face.vertices[j].normal     = normals[faces[i].nor_index[j] - 1];
        }
        myMesh.faces.push_back(face);
    }

    return myMesh;
}
23Feb/100

STL algorithms

UPDATE@2010-Feb-23 22:11: Thanks to Arseny Kapoulkine (his blog is : http://zeuxcg.blogspot.com/ ) I discovered that there was a bug in the code I showed. I have fixed this bug

I'm not a huge fan of the STL library (you know std::vectorand it's relatives) as I don't like the syntax and the naming of some functions and yes, I'm well aware those are mood points but then again I'm always looking for perfection. But there is one part of the STL library I really love which is STL algorithms.

For example, let's say we have the following code


#include <vector>
/* ...
 * Somewhere in the code
 * ...
 */
std::vector<int> numbers;
numbers.push_back(1);
numbers.push_back(2);
numbers.push_back(3);

And we want to remove the number "2" from the vector, sadly std::vector is lacking a remove function. It does have an erase function but that would require an iterator. We could switch to std::list who does have a remove function. Without STL algorithms we would write something like this:


/* Written for readability
 * And it only removes the first one it finds.
 */
template <typename T>
void RemoveFromVector(const T val, std::vector<T> vec)
{
    for(std::vector<T>::iterator begin = vec.begin(); begin != vec.end(); ++begin)
    {
        if(*begin == val)
        {
            vec.erase(begin);
            return;
        }
    }
}
/* ... And here we call it */
RemoveFromVector<int>(2, numbers);

The only thing I can say about it is that it looks ugly. Now let's use stl algorithms and see how that looks like.


/**
 * Previously the code was:
 * std::remove(numbers.begin(), numbers.end(), 2);
 * But that only removes the number, but keeps the same size. std::remove instead
 * returns an iterator which holds the end. (numbers.size() would give the same
 * result before and after the above code.
 * Thanks to  Arseny Kapoulkine this has been corrected and the good version is
 * now here available.
 */
numbers.erase( std::find(numbers.begin(), numbers.end(), 2) );

One line of code and that's all. Well, it's still one line of code, but two rather simple functions. The erase function takes an iterator as input (which std::find returns for you). However keep in mind that if std::find can't find a result (for example "2" was already missing, your application will crash.
One thing I always hate was when I stored pointers in an object that needed destruction


#include <vector>
#define SAFE_DELETE(p) if(p) delete(p); (p)=0;
class StorageObject1;
class StorageObject2;
class StorageContainer
{
    std::vector<StorageObject1*> m_Objects1;
    std::vector<StorageObject2*> m_Objects2;
public:
    ~StorageContainer()
    {
        for(size_t i = 0; i < m_Objects1.size(); ++i)
        {
            SAFE_DELETE(m_Objects1[i]);
        }
        for(size_t i = 0; i < m_Objects2.size(); ++i)
        {
            SAFE_DELETE(m_Objects2[i]);
        }
    }
};

The above example is rather tame but if you have a lot of different objects it quickly becomes ugly to look at. However with a bit of ingenuity you can become a lazier programmer. Here is the same example but then easier to read


#include <algorithm>
#include <vector>
#define SAFE_DELETE(p) if(p) delete(p); (p)=0;
template <typename T> void SAFE_DELETE_FUNC(T* object) { SAFE_DELETE(object); }
class StorageObject1;
class StorageObject2;
class StorageContainer
{
    std::vector<StorageObject1*> m_Objects1;
    std::vector<StorageObject2*> m_Objects2;
public:
    ~StorageContainer()
    {
        std::for_each(m_Objects1.begin(), m_Objects1.end(), SAFE_DELETE_FUNC<StorageObject1>);
        std::for_each(m_Objects2.begin(), m_Objects2.end(), SAFE_DELETE_FUNC<StorageObject2>);
    }
}

Of course you can make the function even a bit smarter so that you don't have to write the start and end iterators, but I prefer it like this.
Here you can find the other versions of STL algorithm: http://www.cplusplus.com/reference/algorithm/

10Jan/100

Undesired template specification

Updated 10 January 2010: The download was not working, this is now fixed

Yesterday I decided to improve my math library and to make it more flexible. One of the things that I wanted to do was convert it to a template, so that I could easily make vectors of different types. However when it was finished and I started testing it I came across a lot of issues which my old math library didn't have. The reason that my old library didn't have them was because all of the structures used floats and when used with any other variable type would be automatically be casted, promoted or demoted to match the type float. However templates are more strict on that area since templates need to specialize. I know this is confusing so let me explain by example.
I will show three examples of the above problem and I will explain how to solve any of them. I hope that throughout the progress you will also understand why the problems happen.
But first let me define the class that I use. This piece of code won't change until I cover the solution of the third problem.
The Vector2 class:

1
2
3
4
5
6
7
8
9
10
template <typename T> class tVector2
{
public:
    T X, Y;
    tVector2(T x, T y) : X(x), Y(y) {}
    // Assigrnent operator
    tVector2<T> operator = (tVector2<T> v) { X = v.X, Y=v.Y; return *this; }  
};
// Multiplication operator
template <typename T> tVector2<T> operator * (tVector2<T> v, T r) { return tVector2<T>(v.X*r, v.Y*r); }

FIRST PROBLEM: ONLY A SINGLE TEMPLATE ARGUMENT

The first problem shows itself rather fast.

1
2
3
4
5
6
7
int testMain1() // Think of this as a normal main
{
    tVector2<float> Vec2(1,1);
    Vec2 = Vec2 * 2.0f; // Does compile
    Vec2 = Vec2 * 2.0;  // Does not compile
    return 0;
}

Visual Studio comes with two errors:

error C2782: 'tVector2<T> operator *(tVector2<T>,T)' : template parameter 'T' is ambiguous
error C2676: binary '*' : 'tVector2<T>' does not define this operator or a conversion to a type acceptable to the predefined operator

If we think about the reason for this problem is rather easy. If we would think as the compiler we would have the following two forms of multiplication:

1
2
    tVector2<float>  operator * (tVector2<float>  v, float  r);
    tVector2<double> operator * (tVector2<double> v, double r);

The first multiplication in the example does compile as it makes use of the first form, the second multiplication in the example however raises two errors. As you can see neither form can be applied on our multiplication, which has the form tVector2<float> multiplied by a double. Since the compiler can't figure out whether template argument T is a float or a double, he throws the error that is ambiguous.
The second error comes forth because the compiler still tries to solve. However it cannot convert tVector2<float> to a tVector2<double> and he can't demote the second argument "2.0" to a float because their second form exists and denies him from demoting just like the following examples forbids only using the first form.

1
2
3
4
5
6
7
8
9
void TestFunction(float  v);
void TestFunction(double v);

int main()
{
    TestFunction(2.0f); // Use first form
    TestFunction(2.0 ); // Use second form
    return 0;
}

FIRST SOLUTION: USE MULTIPLE TEMPLATE ARGUMENTS

The title of the first solution might feel contradicting as tVector2<float> does not change, but it is rather easy. We simply add another operator which look as followed.

1
2
3
4
template <typename T, typename R>
tVector2<T> operator * (tVector2<T> v, R r) {
    return tVector2<T>(v.X*r, v.Y*r);
}

The biggest change is that because of using two template arguments, which are used for the first and second argument, is that compiler no longer have to match the types. So the compiler can generate the following:

1
2
3
tVector2<float>  operator * (tVector2<float> v, int    r);
tVector2<float>  operator * (tVector2<float> v, float  r);
tVector2<float>  operator * (tVector2<float> v, double r);

And the everything works. You can even remove the old multiplication method if you want.

SECOND PROBLEM: MULTIPLYING DIFFERENT TYPES

This problem is exactly the same as the first one, but I cover it none the less as it took me a few seconds more to realize this than I wanted.

1
2
3
4
5
6
7
8
int testMain2() // Think of it as a seperate program
{
    // Second problem: Multiplying different types
    tVector2<float> Vec2(1,1);
    tVector2<double> Vec2d(1,1);
    Vec2d = Vec2d * Vec2;   // tVector2<double>=tVector2<double>*tVector2<float>
    return 0;
}

When we compile this visual studio comes two times with two different errors (total is four):

error C2784: 'tVector2<T> operator *(tVector2<T>,R)' : could not deduce template argument for 'tVector2<T>' from 'double'
error C2677: binary '*' : no global operator found which takes type 'tVector2<T>' (or there is no acceptable conversion)

The errors all take place in the solution of the previous problem as it tries to solve that function in to the following form:

1
2
3
tVector2<float> operator * (tVector2<float> v, tVector2<double> r){
    return tVector2<float>(v.X*r, v.Y*r);
}

I have added on purpose also the body of the form because that is what you should concentrate on. As you can see it tries to multiply v.X with r. While v.Xis a float, which is correct. r is of the type tVector2<double> and although there are times where this kind of multiplication is correct, the result would be a tVector2 which is wrong. In fact the above code could even be made working with a few simple steps. It would not give the result we are looking for, but it would work. The wrong steps would be, adding a new constructor which has as input two vectors and allowing numbers be multiplied by vectors (like in the first solution, but then the two function arguments switched around). However I will provide you with the correct solution.

SECOND SOLUTION: USE MULTIPLE TEMPLATE ARGUMENTS WITH TYPES

Similar to the first problem we add the following function:

1
2
3
4
template <typename T, typename R>
tVector2<T> operator * (tVector2<T> v, tVector2<R> r) {
    return tVector2<T>(v.X*r.X, v.Y*r.Y);
}

There is however one down side to this solution and that is that type returned is the same as the first template argument, even if the second template argument would be bigger. For example the first template argument is a float and the second is of the type double. In that case we would lose precision.

THIRD PROBLEM: CONVERTING FROM ONE TYPE TO ANOTHER TYPE

The test case is similar to that of the second problem, but with a little change.

1
2
3
4
5
6
7
8
int testMain3() // Think of it as a seperate program
{
    // Third problem: Storing different types
    tVector2<float> Vec2(1,1);
    tVector2<double> Vec2d(1,1);
    Vec2d = Vec2 * Vec2d;   // tVector2<double> = tVector2<float> * tVector2<double>
    return 0;
}

As you can see the result of the multiplication is now tVector2<float> while it previously was a tVector2<double>. This multiplication works, but the problem is the assignment operation. We try to store a tVector2<float> in a tVector2<double> and that is not allowed. If you look back at the original class you will see that the assignment operator requires that the function argument is of the same type as the class to which it belongs. And if there is one thing I have learned from the previous problem then it is that is not allowed.
However unlike the solutions of the first two problems, this operator needs to be a member function. So we should store a tVector of a unknown type in a tVector of a specialized type (which is actually also unknown, but the compiler specializes this so it is known to him, but not to us).

THIRD SOLUTION: TEMPLATE FUNCTION INSIDE A TEMPLATE CLASS

To be honest, I didn't think this was at all possible but since I had solved the previous two problems I was intended to find a solution for this one as well. In retrospect the solution was just as simple as the previous one, but then again everything seems easy in retrospect.
The new class looks as followed:

1
2
3
4
5
6
7
8
9
10
11
12
template <typename T> class tVector2
{
public:
    T X, Y;
    tVector2(T x, T y) : X(x), Y(y) {}
    // Assigment operator (didn't solve the third problem)
    tVector2<T> operator = (tVector2<T> v) { X = v.X, Y=v.Y; return *this; }

    // Assigment operator which allows other types (solved third problem)
    template <typename R> tVector2<T> operator = (tVector2<R> v){
        X = v.X, Y=v.Y; return *this; }
};

As you can see a new function has been added, which is a template function. Quite a simple and elegant solution once you accept the fact that you are allowed to create template functions inside a class as well.

FINAL WORDS

Although the title of the article is "Undesired template specification" it was only how I felt when I encountered all these problems. Afterwards I think it was not undesired at all, because this is how the language should work. If it wouldn't work like this we would barely have control what some of the functions would and then it would really become undesired.
I hope that the all of the above was easy enough to follow (assuming you are familiar with templates) and helped you understand in what went wrong and how to solve it.
As usual I have added the full source code at the bottom of the article. All the functions are in it, however in a production environment I would recommend you remove the old versions of some of the functions since the new functions also cover the functionality of the old ones.

Source code: templatetest_0.zip (2 kb)