Limegarden.net Personal site of Wouter Lindenhof

26Apr/100

Evil dutch internet law proposal

This morning I got a mail which was about a dutch law proposal. In the mail it said that the proposal basically means that you need to pay more when you download certain things from the internet. (the proposal can be found here however it's in dutch)

I haven't read it as I don't know the original and basically 21 pages of legal stuff is not what I see as entertaining. But after asking around it seems that the dutch government wants Internet providers to split. If you want access to certain things (like filesharing) you will need to pay extra.

Besides the fact that this is entirely evil, I only wonder "why?".
Does the government (because that is where your money goes) need the money so bad, that they think of this?
Or is it because to counter file sharing?

In either case there are tons of ways around it and besides: File sharing is legal. Sharing files you don't have the rights to (like the latest movie) is of course illegal. But using bittorrent, DC++, emule, IRC, Kazzaa (god forbids) or whatever tool you use is legal. Uploading material which you don't own (the "legal own" not the "physical, I-have-it-in-my-hands, own") is also not legal, and that seems common sense to me.

But if this change in the law is accepted than it means that legal sharing (for example sharing huge files to the other office overseas) requires you to pay extra for it. Even a kid would think of this as unfair and any adult should know better.

Sigh, I'm ranting but the Netherlands is slowly turning in a police state, where it seems you have to proof your innocence. :S

26Apr/100

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 sizeof(double) 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.

1
2
3
4
5
6
7
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.

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.

13Apr/104

EULA of Visual Studio 2010 from dreamspark

EULA: End User License Agreement

You know that annoying check box you need to check when you install new software or games? The one that says "I have read and agree with the EULA"? Do you ever read what it says above it? No? Oh...

Seriously. The EULA is important and you should read it... in some cases.

One of those cases was when I was browsing DreamSpark (free Microsoft development tools) which after registering and confirming you are a student (one of the few times I happily admit I'm a student) you can download all kind of free development tools at no charge with all features.

In general there is no such thing as free stuff. "Buy one and get another free" is not free, it is 50% discount when you buy two. Still I decided to check it out and to my surprise (actually, the school forum had point it out). There was also the new Microsoft Visual Studio 2010 Professional.

"Cool!!" was my first reaction, but after checking the site further out I noticed that Visual Studio 2008 and many others had a license that by downloading I agree to not use it for "commercial". Here is the section I refer to:

b. Restrictions. You may not use the Software:
• for commercial purposes (except as permitted under Section 3(d); or
• to develop or maintain Your own administrative or IT systems, or those of Your educational institution.

(Full Microsoft DreamSpark License)

However for some strange reason the above EULA was not on the screen of VS2010. So after downloading I checked if the installer had such a restriction and it did not. That means I now have a full and legal version of Visual Studio at no cost with no restrictions other than those you would have if you bought it.

For that I thank you Microsoft!

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;
	}
}