Next Container Library

Developing CNep game is going to finished. so recently I decide to rewrite some part of engine which may cause to rewrite whole source code. at the first step I rewrite containers library. in this new version I change container structures to decrease template<> usage which make code ugly. use sampler to decrease allocation. implementing memory allocator is more easy and in some cases changeable during the code and finally implementing new memory allocator which uses stack memory and also some algorithms are changed to increase speed in some container.

Note that some new features are not designed for general purpose. there are many limitations to use them and must 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 :

// fast sqrt root using Log Base 2 Approximation With One Extra Babylonian Steps
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 absolute error is 0.001f
void sx_sin_cos_fast( const float IN x, float& OUT s, float& OUT c);

and some useful conventional functions


MemManFixed::SetBuffer(void* buffer);
I can change the memory buffer of 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 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.

struct FileInfo {
    wchar   path[256];
    wchar   name[64];
    wchar   type[32];
}

FileIfo fileInfo;

MemManFixed memTmp;
String strTmp( 0, &memTmp );

// extract file path from file name and copy that to fileInfo.path
memTmp.SetBuffer( &fileInfo.path );
strTmp = fileName;
strTmp.ExtractFilePath();

// extract name of the file and copy that to fileInfo.name
memTmp.SetBuffer( &fileInfo.name );
strTmp = fileName;
strTmp.ExtractFileName();

// extract file type and copy that to the fileInfo.type
memTmp.SetBuffer( &fileInfo.type );
strTmp = fileName;
strTmp.ExtractFileExtension();



MemManFixed_inline<memSizeInByte>
This memory manager use memory stack of functions. 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 that 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.
example :

MemManFixed_inline<MAX_NODE_COUNT> tmpMem;
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 !
}



Finally although there are some changes like adding new functions, changing algorithms in the other stuff to increase performance and capabilities. but those still need optimize 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 !



Terrain :: Geometry

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.

Geometry data
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
T-junction problem appears between terrain blocks with different LOD and make terrain ugly. The picture in below illustrate this problem clearly:

T-Junction between LODs


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 :

typedef struct TerrainLOD
{
    TerrainChunk    center;         //  standard center
    TerrainChunk    sideFUL[4];     //  standard 4 sides
    TerrainChunk    sideLOD[4];     //  simplified 4 sides
}
*PTerrainLOD;

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 :

Terrain rendering in seganx engine

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.



Steve Jobs

www.apple.com



AI for Cnep

It’s about 3 weeks that our playable demo of Cnep is ready. it has 2 main mechanics. create and place towers, shoot on enemies. you can find more info about the game here. I improved some features of engine during the demo was developing. AI was one of these features.
Currently the AI includes path finding, mission based decision making and Hierarchical State-Driven Agent Behavior from “Programming Game AI by Example by Mat Buckland”. here I try to explain it briefly to give you some concepts.

States
Each state is a class which inherits from standard state class interface. each agent in the game has a primary state. in addition agents can also have a parallel state to do some parallel operations. we can create an state and replace it with the current state slot of the agent. these states will control the behavior of agent. in other word each agent is similar to a Atari game consul and each state is similar to cartridge of that. by replacing states, the behavior of agent will change.
in Buckland’s design, each state can be atomic or composite. atomic states have no sub states and just do simple operations. for instance pressing a button in the game to open a door. but composite states have a list of sub states. depending on the circumstances in the game, composite states may create sub states and add them to the list. sub states will process consecutively. each sub state will removed when operation completed.
for example when an agent is traversing a path which is closed by a door, the agent can create a sub state for pressing a key to open the door and push it to the list. this new sub state may include some more sub states to find a path to the key, push the key and etc. this process of decomposing and satisfying states continues until the entire hierarchy has been traversed and the agent arrives to the goal.

here is a shot to describes traversing a path which closed by a door :

Hierarchical State-Driven Agent Behavior


in www.ai-junkie.com you can find more books, tutorials, source codes and …

Missions
In this game each Mission is a simple data structure contains position, time, behavior flag and etc. flag of mission can be a combination of different behavior. the brain of agent uses this data structure to make a decision depending on mission flag. there is a queue of missions in the brain of agent. we can push new mission to the brain and the brain will perform each mission respectively.
here is a simple sample which I used in one of our game prototype to set the enemies behavior. the game is in tower defense genre and enemies try to reach the base which placed in the center of game world. also enemies can attack to the towers and when they arrive to the base, they must remove themselves from the game :

Mission m;
m.flag      = MISSION_GOTO_POSITION | MISSION_KILL_ENEMY;
m.pos       = float3(0, 0, 0);
m.status    = Mission::MS_ACTIVE;
pAgent->GetBrain()->AddMission(m);

m.flag = MISSION_SUICIDE;
pAgent->GetBrain()->AddMission(m);

in this example I added two missions to the brain of enemy agent. in the first mission, the flag is the combination of two behaviors include “go to specified position” and “kill the enemies”. the brain creates one state for agents move to the specified position and set that as main state. also the brain creates the other state to find and kill enemies and set that as parallel state. finally if the first mission was successfully completed the brain will process the next mission. the flag of next mission is “suicide” which cause the brain remove his agent from the game.



Cnep

We start to making a simple game by the engine. so many works I have to do and the time is limited. deadline is so closed and I have no time to update weblog frequently. in this regard I start to develop the engine and editor simultaneous.

Currently the engine has background loading of textures and geometries with 3 level of LOD, step by step validation/invalidation system to load/unload resources in scene, simple shader based material system, particle system, AI path nodes ( POV ), simple 2×2 PCF shadow map, an incomplete forward shading pipeline and some usual features which every engine should have. some works that I have done will described later.

official site of Cnep

Here is some screen shots : [Intel sonoma 1.8 GH - Nvidia GF GO 6400]

Material editor


Particle system


use POV node to handle this game


using LOD increase performance dramatically



Copyright © 1996-2010 SeganX. All rights reserved.
Jarrah theme by Templates Next | Powered by WordPress