I’m really excited to announce the release of Rush for Glory on Steam. I can’t wait to hear all feedback about the game and I will do my very best to deliver a great game experience!
Here is the latest test on the game and I’m just playing with my additional camera in the scene 😉
I changed the design of the engine in the next version. In the new design, I have separate main library of the engine. It includes memory allocators, containers, random system, basic math functions, simple memory leak and memory corruption detector, callstack system and crash reporter. All of these stuffs are now simpler, more optimized and more easy to use.
Developing memory leak detector and callstack system is straight forward and you can find many samples on the net easily. But I was thinking to find a solution to detect memory corruptions. I found that it’s really complicated and it isn’t suits on me. My problem was not much trouble and there was no need to use complex solutions. All I needs was a simple system to checks the array bounds. So my memory corruption detector does that for me fast and secure. Although it may not report all memory corruptions but it can do for many of them.
The new system can report memory status, callstack with every value in every call when the system is running or crashed. It is a trick. When a crash happens on the application side, the function “DllMain()” called to detach the library. There I check the flags and memory status to verify that application closed unexpectedly and report memory statuses. This works well on Microsoft Windows. But I have no idea about the other platforms.
My next news title is about the network system. The new version has a basic network system based on UDP protocol. The system has been guaranteed to create a connection which supports reliable data order, request for loosed critical data, merge and compress data packets and connection speed controller to prevent data accumulation. The network system contains Client, Server, Connection and socket objects which allows the developer to design any network paradigm based on the genre of the game.
In the Client/Server architecture, the Server object has been featured by broadcast capabilities to create a game session with specified number of clients to join. The Client object can list the game sessions and let the player to choose a game to join. Also there are Connection object and Socket object to design the other network architectures as like as peer to peer connections, stars, mesh, etc. I wrote the network system recently and still need more optimization and debug and probably we will test it on “Rush for Glory”.
Developing Rush for Glory game is going to be finished. so I decided to rewrite some parts of the engine recently. this may cause to rewrite the whole source code. at the first step I rewrote the containers library. in this new version I changed structure of containers for decrease usage of templates<> which make code ugly. I used sampler to decrease allocations. also implementing memory allocators is more easy that before and changeable during the code in some cases. finally implementing new memory allocator which uses stack memory to avoid calling malloc function.
Note that some new features are not designed for general purposes. there are many limitations to using them and must be used with care because those features are designed to develop game and most of capabilities are depend on needs of a game engine.
Here are some highlights :
Added math base functions to the library with some fast functions like :
float sx_sqrt_fast( const float x );
// return sine( x ) from table. maximum absolute error is 0.001f
float sx_sin_fast( const float x );
// return cosine( x ) from table. maximum absolute error is 0.001f
float sx_cos_fast( const float x );
// compute sine and cosine of the angle x in same time. maximum error is 0.001f
void sx_sin_cos_fast( const float IN x, float& OUT s, float& OUT c);
and some useful conventional functions
I can change the memory buffer of the allocator by setting a new buffer. this feature is available only on fixed memory manager. it means that it’s suitable just for arrays and strings.
For example I wanna change/fill an string in an structure. in this example when I set members of structure to the allocator, all string functions can be applied easily.
String strTmp( 0, &memTmp );
// extract file path from file name and copy that to fileInfo.path
memTmp.SetBuffer( &fileInfo.path );
strTmp = fileName;
// extract name of the file and copy that to fileInfo.name
memTmp.SetBuffer( &fileInfo.name );
strTmp = fileName;
// extract file type and copy that to the fileInfo.type
memTmp.SetBuffer( &fileInfo.type );
strTmp = fileName;
This memory manager use memory stack of function. by the way this feature is available only on fixed memory manager. this means that it’s suitable just for arrays and strings.
In this example I try to collect some nodes from the scene manager. this will happens at each frame more than once, at renderer, AI system & etc. implementing new Array class cause to calling allocation/deallocation. the other solution is declaring static array. the other solution is using memory stack with some limitation but fast and easy memory management.
Array<Node*> nodes( 0, &tmpMem );
// collect nodes from the scene manager
g_engine->m_scene->GetNodesByFrustum( cameraFrustum, nodes );
for ( int i = 0; i < nodes.Count(); ++i )
// ... do something !
Although there are some changes like adding new functions, changing algorithms in the other stuff to increase performance and capabilities, but those still need to be optimized more and more. oh I forgot to say that I put away namespaces in c++. those things are not suitable for game programming and maybe not suitable at all !
The Terrain for seganx engine is going to be completed. in this post I will describe the geometry algorithms I used for rendering the terrain briefly. my approach to design this feature was easy to use, simple and straight forward implementing. Artist/Level designer can easily:
– create geometry every where and every amount that was required.
– increase performance by implementing LOD and patching geometries to reach minimum draw call.
As I mentioned before, everything in the scene is a kind of node member. In this method the terrain is like the other members ( mesh, particle, sound, … ). The terrain is a node member too. Thus for importing terrain to the scene we must create terrain and attach it to the node and then add the node to the scene. so we can create any number of terrain and add them to the scene. But to reaching the goals which mentioned above I design terrain members with some more information.
Each terrain member has a fixed 33×33 vertices placed in grid style. I choose this size because I want to generate 6 levels of details. With 33×33 vertices we have 32×32 quads for first level. This means if we half each level for 6 times, finally we will have one quad for lowest level of details. Choosing vertices for each level will do by using 6 static fixed size LOD structures called TerrainLOD that used for all terrain members. Thus, there is no need to more indices/vertices for each level and we just choose a correct LOD structure depends on view distance. So for rendering all terrain members I used a big buffer and append to that big buffer vertices of all terrain members in view port. Appending process just applied on vertices which described in LOD structure. Finally, the terrain will draw by one draw call.
T-junction problem appears between terrain blocks with different LOD and make terrain ugly. The picture in below illustrate this problem clearly:
There are several ways to remove these junction problems. according to ‘Geometry Data’ of terrain in engine I defined and implemented a simple structure to describe indices for each LOD. this structure split indices for each LOD to 9 part :
TerrainChunk center; // standard center
TerrainChunk sideFUL; // standard 4 sides
TerrainChunk sideLOD; // simplified 4 sides
Indices of center in this structure contain polygon indices that cover the center except 4 sides “up, right, down, left”. these sides will covered by sideFUL or sideLOD. sideFUL contain indices to cover with all polygons in that LOD and sideLOD contain simplified indices.
Choosing which side ( sideFUL or sideLOD ) to use as indices is simple. we can easily predict the LOD of neighbors. to predict LOD of each neighbors I compute the neighbor’s position by adding fixed terrain size to current position. by passing this position to some special functions we can get neighbor’s LOD number depend on current camera properties. for each neighbor which uses less details we append sideLOD to the big buffer, otherwise we use sideFUL. here is an screen shot for terrain in wire frame mode :
My next task is choosing and implementing terrain material system. current system support multilayer material system. but implementing brush, gathering information of each brush on terrain to increasing performance, optimization and optimization and optimization still need more and more and more works. but now I have to spend more time to cnep game project.