Posts Tagged ‘Continuum Engine’

h1

threading the memory management and future dev plans

July 2, 2009

So, I finally got the memory management system threaded and defeated the only race condition, which could be found on the close down because of the order it waited for shit in. I fixed it with a shut down event that would poke when both mutexes were released in a timeout waiting loop so there was no wrong order to wait for them in. Anyway, I’m not here to show you that, but instead my threading library. It’s very bare bones, and only has a Win32 implementation for now, but could easily be implemented in another threading library, and I will do so with pthreads sometime in the future.

But I want to show it. I will show it now. SHOWING!

It makes use of factories and singletons, but those should be obvious in terms of their functionality. Factory inherits Factory<Singleton > as well. I might change this if it becomes more efficient to create multiple factory instances for different creation modes (i.e.) each has a different set of creation parameters.

threading.h
#ifndef THREADING_H
#define THREADING_H

#include
#include
#include
#include
#include
#include

#include “dlmalloc_object.h”
#include “factory.h”

namespace SpaceSim
{
class WaitingObject: public DLMallocAlloced
{
protected:
static std::list *wobjs;
public:
WaitingObject();
~WaitingObject();

static bool WaitForAll(std::list *objs = NULL);

virtual bool Wait() = 0;
};

class Mutex: public WaitingObject
{
public:
static Mutex *Create(bool is_global = false, unsigned long spincount = 0x80000400);

virtual bool Lock() = 0;
virtual void Unlock() = 0;

virtual unsigned long SpinCount() const = 0;
};

class GlobalMutex: public Mutex
{
protected:
HANDLE mutex;
public:
GlobalMutex();
~GlobalMutex();

virtual bool Lock();
virtual void Unlock();

virtual bool Wait();

virtual unsigned long SpinCount() const;
};

class LocalMutex: public Mutex
{
protected:
unsigned long spincount;
CRITICAL_SECTION mutex;

public:
LocalMutex(unsigned long spincount);
~LocalMutex();

virtual bool Lock();
virtual void Unlock();

virtual bool Wait();

virtual unsigned long SpinCount() const;
};

class Event: public WaitingObject
{
protected:
HANDLE event;

public:
static Event *Create();

Event();
~Event();

bool Wait();
void Poke();
void Reset();
};

typedef int (*ThreadMainProc)(void *args);
typedef unsigned long ThreadID;

class Thread: public WaitingObject
{
protected:
void *args;
HANDLE thread;
ThreadMainProc proc;
bool is_running;

public:
static Thread *Create(ThreadMainProc main_proc, void *args);
static ThreadID GetID();

Thread(ThreadMainProc main_proc, void *args);
~Thread();

bool Run();
bool Break();
bool Wait();

bool IsRunning() const;
};
};

#endif

threading.cpp
#include “threading.h”
#include “logger.h”

namespace SpaceSim
{
std::list *WaitingObject::wobjs = NULL;

WaitingObject::WaitingObject()
{
if (!wobjs)
wobjs = new std::list;

wobjs->push_back(this);
}

WaitingObject::~WaitingObject()
{
wobjs->remove(this);

if (wobjs->empty())
{
delete wobjs;
wobjs = NULL;
}
}

bool WaitingObject::WaitForAll(std::list *objs)
{
bool success = true;
if ((!objs) || objs->empty())
objs = wobjs;

std::list::iterator it;
for (it = objs->begin(); it != objs->end(); ++it)
success = success && (*it)->Wait();

return success;
}

class MutexFactoryParameters: public FactoryParameters
{
public:
bool is_global;
unsigned long spincount;

MutexFactoryParameters(bool is_global = false, unsigned long spincount = 0x80000400):
is_global(is_global), spincount(spincount) {}
};

template<> class Factory: public Singleton >
{
public:
virtual Mutex *Create(const FactoryParameters &params)
{
const MutexFactoryParameters &mparams = param_cast(params);

if (mparams.is_global)
return new GlobalMutex();
else
return new LocalMutex(mparams.spincount);
}
};

Mutex *Mutex::Create(bool is_global, unsigned long spincount)
{
return Factory::GetSingleton().Create(MutexFactoryParameters(is_global, spincount));
}

GlobalMutex::GlobalMutex()
{
static unsigned long mtctr = 0;
char name[256], cvbuf[16];

ltoa(mtctr++, cvbuf, 16);
strcpy(name, “SPACESIM_MUTEX_0x”);
strcat(name, cvbuf);

assert(mutex = CreateMutex(NULL, FALSE, name));
}

GlobalMutex::~GlobalMutex()
{
CloseHandle(mutex);
}

bool GlobalMutex::Lock()
{
return WaitForSingleObject(mutex, INFINITE) == WAIT_OBJECT_0;
}

void GlobalMutex::Unlock()
{
ReleaseMutex(mutex);
}

bool GlobalMutex::Wait()
{
bool ls = Lock();
Unlock();
return ls;
}

unsigned long GlobalMutex::SpinCount() const {return 0;}

LocalMutex::LocalMutex(unsigned long spincount): spincount(spincount)
{
assert(InitializeCriticalSectionAndSpinCount(&mutex, spincount));
}

LocalMutex::~LocalMutex()
{
DeleteCriticalSection(&mutex);
}

bool LocalMutex::Lock()
{
EnterCriticalSection(&mutex);

return true;
}

void LocalMutex::Unlock()
{
LeaveCriticalSection(&mutex);
}

bool LocalMutex::Wait()
{
bool ls = Lock();
Unlock();
return ls;
}

unsigned long LocalMutex::SpinCount() const {return spincount;}

Event *Event::Create()
{
return Factory::GetSingleton().Create(FactoryParameters());
}

Event::Event()
{
static unsigned long evctr = 0;
char name[256], cvbuf[16];

ltoa(evctr++, cvbuf, 16);
strcpy(name, “SPACESIM_EVENT_0x”);
strcat(name, cvbuf);

assert(event = CreateEvent(NULL, TRUE, FALSE, name));
}

Event::~Event()
{
CloseHandle(event);
}

bool Event::Wait()
{
return WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0;
}

void Event::Poke()
{
SetEvent(event);
}

void Event::Reset()
{
ResetEvent(event);
}

class ThreadFactoryParameters: public FactoryParameters
{
public:
void *args;
ThreadMainProc proc;

ThreadFactoryParameters(ThreadMainProc proc, void *args): proc(proc), args(args) {}
};

template<> class Factory: public Singleton >
{
public:
virtual Thread *Create(const FactoryParameters &params)
{
const ThreadFactoryParameters &mparams = param_cast(params);

return new Thread(mparams.proc, mparams.args);
}
};

Thread *Thread::Create(ThreadMainProc main_proc, void *args)
{
return Factory::GetSingleton().Create(ThreadFactoryParameters(main_proc, args));
}

struct proc_attribs
{
ThreadMainProc proc;
void *args;
Event *mevent;
};

static DWORD WINAPI __ThreadMainProc(LPVOID param)
{
proc_attribs &pa = *((proc_attribs *)param);

ThreadMainProc proc = pa.proc;
void *args = pa.args;

pa.mevent->Poke();

return proc(args);
}

ThreadID Thread::GetID() {return GetCurrentThreadId();}

Thread::Thread(ThreadMainProc main_proc, void *args): proc(main_proc), args(args) {}

Thread::~Thread()
{
if (is_running) Break();
}

bool Thread::Run()
{
if (is_running) return false;

DWORD temp;

proc_attribs pa;
pa.args = args;
pa.proc = proc;
pa.mevent = Event::Create();

thread = CreateThread(NULL, 0,
__ThreadMainProc, (void *)&pa, 0, &temp);

is_running = (bool)thread;

pa.mevent->Wait();
return is_running;
}

bool Thread::Break()
{
if (!is_running) return false;

bool success = CloseHandle(thread);
is_running = !success;
return success;
}

bool Thread::Wait()
{
if (!is_running) return false;

bool success = (WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0);
return success && Break();
}

bool Thread::IsRunning() const {return is_running;}
};

Now, for stuff more interesting to the consumer who buys the final game (yes… the game will be sold, and I don’t care if people see snippets of the code). The Actor and StaticObject classes will extend the SceneObject class, and all that good stuff will be Lua bound. Actors will be partly virtual and will have to have trigger functions such as being told where to go by the controller filled in. This would be in certain implementations, especially ships and the like. Anyway, that about says it and all that good stuff. I’m making tracks, and it is AWESOME.

h1

Continuum Engine

June 3, 2009

That’s the name I have for it now.  It’s a badass name, no?

Anyway, I’ve got 3demon engine working as a rendering engine for now, but I still hate the Irrlicht style shadows it uses.  It IS a branch of Irrlicht.  They’re just so… broken.  They don’t even have a consistent appearance across subsystems.  OpenGL has a different volume method from D3D9 in it.  I want something like OGRE, but I absolutely hate the way it’s organized.

Does anyone have an idea as to what I should do?  I don’t want to use my own rendering engine because I’d like the focus of this project to be on the game itself this time, not every little technical thing to support it.  I will give OGRE a shot, and if that’s how it has to be, so be it.  But do you absolutely HAVE to use the ReferenceApp layer?  That, I put to you, is TERRIBLE API design.