Bonsai v0.2

256x256x256 8 - 9 FPS.. Need Optimisation already...

After hours spent on struggling with the VBO’s and GLSL I have managed to draw my first voxel based model.. the bonsai tree *fanfare*.
File loading time and processing takes about 20seconds, 8.3 FPS without culling or optimisation.. primitive brute force.. get all the points process them through marching cubes algorithm and then draw on the screen.. barbarity I know. but I had to start somehow.
Camera system allow to move around which is kind a nice..

Good night.

Content added

last week I have improved collision detection between zombies – now I am trying to implement one universal.
New animations added for marines – shooting and die.
Additional content – stone and tree,
tile set has been changed to nicer one,
behaviour manager implemented for zombies,
range added to marines,
different collision added for different types of entities,
live variable added to SCV, Marine, Zombie

Current issues I have is marines formation – not sure how to solve it yet.
When more than one marine is selected and destination location is selected – collision detection is not applied correctly. the can stand at the same place at the same time.

I see meshes everywhere!

Huzza!! I did it!

I have learned how to create a mesh from .x file format! – now I only need to apply picking and I am good to go!

// Mesh.h
#pragma once
#ifndef MESH_H
#define MESH_H

[...]

class Mesh
{
  friend class MeshInstance;
public:
  Mesh();
  ~Mesh();
  Mesh(LPCSTR fName, IDirect3DDevice9* dev);
  HRESULT Load(LPCSTR fName, IDirect3DDevice9* Dev);
  void Render();
  void Release();
private:
  IDirect3DDevice9* m_pDevice;
  ID3DXMesh* m_pMesh;
  std::vector m_textures;
  std::vector m_materials;
  D3DMATERIAL9 m_white;
};

class MeshInstance{
public: 
  MeshInstance();
  MeshInstance(Mesh* meshPtr);
  void Render();

  void SetMesh(Mesh* m) { m_pMesh = m;}
  void SetPosition(D3DXVECTOR3 p) { m_pos = p; }
  void SetRotation(D3DXVECTOR3 r) { m_rot = r; }
  void SetScale(D3DXVECTOR3 s) { m_sca = s; }

private:
  Mesh* m_pMesh;
  D3DXVECTOR3 m_pos, m_rot, m_sca;
};
#endif
// Mesh.cpp
#include "Mesh.h"

Mesh::Mesh(){
  m_pDevice = NULL;
  m_pMesh = NULL;
}

Mesh::Mesh(LPCSTR fName, IDirect3DDevice9* dev){
  m_pDevice = dev;
  m_pMesh = NULL;
  Load(fName, m_pDevice);
}

Mesh::~Mesh(){
  Release();
}

HRESULT Mesh::Load(LPCSTR fName, IDirect3DDevice9* dev){
  m_pDevice = dev;

  //Set m_white material
  m_white.Ambient = m_white.Specular = m_white.Diffuse  = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
  m_white.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
  m_white.Power = 1.0f;

  Release();

  //Load new m_pMesh
  ID3DXBuffer * adjacencyBfr = NULL;
  ID3DXBuffer * materialBfr = NULL;
  DWORD noMaterials = NULL;

  if(FAILED(D3DXLoadMeshFromX(fName, D3DXMESH_MANAGED, m_pDevice,	
			      &adjacencyBfr, &materialBfr, NULL, 
			      &noMaterials, &m_pMesh)))
    return E_FAIL;

  D3DXMATERIAL *mtrls = (D3DXMATERIAL*)materialBfr->GetBufferPointer();

  for(int i=0;i< (int)noMaterials;i++){
    m_materials.push_back(mtrls[i].MatD3D);

    if(mtrls[i].pTextureFilename != NULL){
      char textureFileName[90];
      strcpy(textureFileName, "meshes/");
      strcat(textureFileName, mtrls[i].pTextureFilename);
      IDirect3DTexture9 * newTexture = NULL;
      D3DXCreateTextureFromFile(m_pDevice, textureFileName, &newTexture);			
      m_textures.push_back(newTexture);
    }
    else m_textures.push_back(NULL);
  }

  m_pMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE,
			   (DWORD*)adjacencyBfr->GetBufferPointer(), NULL, NULL, NULL);

  adjacencyBfr->Release();
  materialBfr->Release();

  return S_OK;
}

void Mesh::Render(){
  for(int i=0;i< (int)m_materials.size();i++) {	
    if(m_textures[i] != NULL)m_pDevice->SetMaterial(&m_white);
    else m_pDevice->SetMaterial(&m_materials[i]);
    m_pDevice->SetTexture(0,m_textures[i]);
    m_pMesh->DrawSubset(i);
  }
}

void Mesh::Release(){
  //Clear old mesh...
  if(m_pMesh != NULL){
    m_pMesh->Release();
    m_pMesh = NULL;
  }

  //Clear textures and materials
  for(int i=0;i< (int)m_textures.size();i++)
    if(m_textures[i] != NULL)
      m_textures[i]->Release();
    m_textures.clear();
}

MeshInstance::MeshInstance(){
  m_pMesh = NULL;
  m_pos = m_rot = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  m_sca = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
}

MeshInstance::MeshInstance(Mesh* meshPtr){
  m_pMesh = meshPtr;
  m_pos = m_rot = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  m_sca = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
}

void MeshInstance::Render(){
  if(m_pMesh != NULL){
    D3DXMATRIX p, r, s;
    D3DXMatrixTranslation(&p, m_pos.x, m_pos.y, m_pos.z);
    D3DXMatrixRotationYawPitchRoll(&r, m_rot.y, m_rot.x, m_rot.z);
    D3DXMatrixScaling(&s, m_sca.x, m_sca.y, m_sca.z);		
    D3DXMATRIX world = s * r * p;
    m_pMesh->m_pDevice->SetTransform(D3DTS_WORLD, &world);
    m_pMesh->Render();
  }
}
// ObjectClass.h
#ifndef OBJECTCLASS_H
#define OBJECTCLASS_H

[...]
#include "debug.h"
#include "mesh.h"

HRESULT LoadObjectResources(IDirect3DDevice9* Device);
void UnloadObjectResources();

#define OBJ_TREE 0
#define OBJ_STONE 1

class ObjectClass{
public:
  ObjectClass();
  ObjectClass(int t, D3DXVECTOR3 pos, D3DXVECTOR3 rot, D3DXVECTOR3 sca);
  void Render();

private:
  MeshInstance m_meshInstance;
  int m_type;
};
#endif
// ObjectClass.cpp
#include "ObjectClass.h"

std::vector objectMeshes;

HRESULT LoadObjectResources(IDirect3DDevice9* device){
  Mesh* one = new Mesh("meshes/one.x", device);
  objectMeshes.push_back(one);
  Mesh* two= new Mesh("meshes/two.x", device);
  objectMeshes.push_back(two);
  return S_OK;
}

void UnloadObjectResources(){
  for(int i=0; i< (int)objectMeshes.size(); i++)
    objectMeshes[i]->Release();
  objectMeshes.clear();
}

ObjectClass::ObjectClass(){
  m_type =0;
}

ObjectClass::ObjectClass(int t, D3DXVECTOR3 pos, D3DXVECTOR3 rot, D3DXVECTOR3 sca){
  m_type = t;
  m_meshInstance.SetPosition(pos);
  m_meshInstance.SetRotation(rot);
  m_meshInstance.SetScale(sca);
  m_meshInstance.SetMesh(objectMeshes[m_type]);
}

void ObjectClass::Render(){
  m_meshInstance.Render();
}

usage is really simple:

in our main program class game/application/app you name it.

we need to add include

#include "ObjectClass.h"

then in Init method for your program place

  LoadObjectResources(m_pDevice); 

it is loading resources do our device.

to add object call

  AddObject(0, INTPOINT(x, y));	//objec one
  else if(m_pHeightMap->GetHeight(x, y) >= 1.0f && hm3.GetHeight(x, y) > 0.9f && rand()%20 == 0)
    AddObject(1, INTPOINT(x, y));	//object two

I am calling it in terrain class.

at the moment placed randomly

void Terrain::AddObject(int type, INTPOINT mappos)
{
  D3DXVECTOR3 pos = D3DXVECTOR3((float)mappos.x, m_pHeightMap->GetHeight(mappos), (float)-mappos.y);	
  D3DXVECTOR3 rot = D3DXVECTOR3((rand()%1000 / 1000.0f) * 0.13f, (rand()%1000 / 1000.0f) * 3.0f, (rand()%1000 / 1000.0f) * 0.13f);

  float sca_xz = (rand()%1000 / 1000.0f) * 0.5f + 0.5f;
  float sca_y = (rand()%1000 / 1000.0f) * 1.0f + 0.5f;
  D3DXVECTOR3 sca = D3DXVECTOR3(sca_xz, sca_y, sca_xz);

  m_objects.push_back(ObjectClass(type, pos, rot, sca));
}

374 FPS not bad!

Frame Animation manager – 2D

This week at university we have covered 2D frame animation – simple idea every frame is separate image.

what we need are two classes:

  • Animation
  • AnimationManager
// Animation.h
#pragma once
#ifndef ANIMATION_H
#define ANIMATION_H

#include 

class Animation
{
private: 
  IDirect3DTexture9* texture;
  int frameWidth;
  int frameHeight;
  int startFrame;
  int endFrame;
  int frameCount;
  float frameTime;
  bool isLooping;
public:
  Animation(IDirect3DTexture9* texture);
  Animation(IDirect3DTexture9* texture, float frameTime, bool isLooping);
  Animation(IDirect3DTexture9* texture, float frameTime, bool isLooping, int startFrame, int endFrame,int frameWidth, int frameHeight);
  ~Animation();

  void setTexture(IDirect3DTexture9* newTexture){ texture = newTexture; }
  IDirect3DTexture9* getTexture(){ return texture;}

  void setFrameTime(float newFrameTime){ frameTime = newFrameTime;};
  float getFrameTime(){return frameTime;}

  void setIsLooping(bool newIsLooping){ isLooping = newIsLooping; }
  bool getIsLooping() { return isLooping; }

  void setStartFrame(int newStartFrame) { startFrame = newStartFrame;}
  int getStartFrame() { return startFrame;}

  void setEndFrame(int newEndFrame) { endFrame = newEndFrame; }
  int getEndFrame() { return endFrame; }

  void setFrameCount(int newFrameCount) { frameCount = newFrameCount; }
  int getFrameCount() { return frameCount;}

  void setFrameWidth(int newFrameWidht) { frameWidth = newFrameWidht; }
  int getFrameWidth() { return frameWidth; }

  void setFrameHeight(int newFrameHeight) { frameHeight = newFrameHeight; } 
  int getFrameHeight() { return frameHeight; }
};
#endif

as we can see just bunch of attributes and geters/seters

// Animation.cpp
#include "Animation.h"

Animation::Animation(IDirect3DTexture9* texture): texture(texture){
  frameTime = 1.0f/ 30.0f;
  isLooping = true;
  D3DSURFACE_DESC desc;
  texture->GetLevelDesc(0, &desc);
  startFrame = 0;
  endFrame = desc.Width / desc.Height;
  frameCount = endFrame - startFrame;
  frameWidth = desc.Height; 
  frameHeight = desc.Height;
}

Animation::Animation(IDirect3DTexture9* texture, float frameTime, bool isLooping)
: texture(texture), frameTime(frameTime),isLooping(isLooping){
  D3DSURFACE_DESC desc;
  texture->GetLevelDesc(0, &desc);
  startFrame = 0;
  endFrame = desc.Width / desc.Height;
  frameCount = endFrame - startFrame;
  frameWidth = desc.Height; 
  frameHeight = desc.Height;
}

Animation::Animation(IDirect3DTexture9* texture, float frameTime, bool isLooping, int startFrame, int endFrame,int frameWidth, int frameHeight)
: texture(texture),
frameTime(frameTime),
isLooping(isLooping),
startFrame(startFrame),
endFrame(endFrame),
frameWidth(frameWidth),
frameHeight(frameHeight) {
  frameCount = endFrame - startFrame;
}

Animation::~Animation(){}
// AnimationManager.h
#pragma once
#ifndef ANIMATIONPLAYER_H
#define ANIMATIONPLAYER_H

#include "Animation.h"
[...]
class AnimationPlayer
{
private:
  Animation* currentAnimation;
  std::string playing;
  std::map animations;
  int frameIndex;
  float time;
public:
  AnimationPlayer();
  void playAnimation(std::string name);
  void addAnimation(std::string name, Animation* anim);
  void update(float frameTime);
  void draw(ID3DXSprite* spriteBatch, D3DXVECTOR3 position, D3DXMATRIX transform);

  ~AnimationPlayer();
  Animation* getCurrentAnimation(){return currentAnimation;}

  std::string getPlaying(){ return playing; }
  int getFrameIndes() { return frameIndex;}
};
#endif

Animation manager keeps all animations in map, pointer to current animation, playing are easy to guess.

same with methods: playAnimation, addAnimation, draw and getCurrentAnimation but why there is an update method?
well code should make that clear.

// AnimationManager.cpp
#include "AnimationPlayer.h"

AnimationPlayer::AnimationPlayer(){}

AnimationPlayer::~AnimationPlayer(){
  std::map::iterator iter = animations.begin();
  for(; iter != animations.end(); ++iter){
    delete iter->second;
  }
  animations.clear();
}

void AnimationPlayer::playAnimation(std::string name){
  Animation* anim = animations[name];
  if(anim == currentAnimation)
    return;

  currentAnimation = anim;
  playing = name;
  frameIndex = 0;
  time = 0.0f;
}

void AnimationPlayer::update(float frameTime){
  if(currentAnimation == 0)
    return;

  time += frameTime;

  while(time > currentAnimation->getFrameTime()){
    time -=currentAnimation->getFrameTime();
    if(currentAnimation->getIsLooping())
      frameIndex = (++frameIndex) % currentAnimation->getFrameCount();
    else
      frameIndex = min(++frameIndex, currentAnimation->getFrameCount() - 1);
  }
}

void AnimationPlayer::draw(ID3DXSprite* sprite, D3DXVECTOR3 position, D3DXMATRIX transform){
  if(currentAnimation == 0)
    return;
  D3DXMATRIX currentTransform;
  sprite->GetTransform(¤tTransform);
  sprite->SetTransform(&transform);

  int frameX = (frameIndex + currentAnimation->getStartFrame());
  frameX *= currentAnimation->getFrameWidth();

  int frameY = (frameIndex + currentAnimation->getStartFrame());
  frameY *= currentAnimation->getFrameWidth();
  frameY %= currentAnimation->getFrameWidth();

  RECT rect;
  rect.left = frameX;
  rect.right = frameX + currentAnimation->getFrameWidth();
  rect.top = frameY;
  rect.bottom = frameY + currentAnimation->getFrameHeight();

  sprite->Draw(currentAnimation->getTexture(), &rect, 0, &position, D3DCOLOR_XRGB(255,255,255));
  sprite->SetTransform(¤tTransform);
}

I am bit worried because all stuff we do leads us – students to develop 2D based platformer game.. next week we are going to do simple 2d physics and particles.. which is not really necessary in my game.

but good news is.. I have managed to get back on track with my 3D Zombeesh.. some tech demo should be ready by end of the week!! can’t wait!

PlayerManager – prototype class

Just a quick note. I have managed to write Player Manager class which is kind a prototype.. the two issues that I am having are how to get an offset of a map.. if I am trying to set up offset to static DXDVECTOR3 variable inside Level class linker is complaining, passing as attribute well it is a option but then I need to modify other classes.

Second problem is click in a frame. actually I have just figured this out :).. wow sometimes one sec break and step back can do the trick.

Anyway deep beta presents PlayerManager prototype class – probably it will be totally modified but as far as now I have something like that:

// PlayerManager.h

#pragma once
#ifndef PLAYERMANAGER_H
#define PLAYERMANAGER_H

[...]
#include "Entity.h"
#include "Level.h"

class PlayerManager
{
private:
  //players entities
  static std::map playersEntities;
  static std::map playersSelectedEntities;	
public:
  static PlayerManager* instance;
  static void init();
  static void registerPlayersEntity(Entity* playersEntity); // called in players unity type constructor
  static void removePlayersEntity(Entity* playersEntity);
  static Entity* getPlayersEntity(int id);
  static void clearSelected();
  static void addEntityToSelected(POINT mousePosition);

  PlayerManager();
  ~PlayerManager();
};
#endif
// PlayerManager.cpp
#include "PlayerManager.h"
#include "Collision.h"

PlayerManager* PlayerManager::instance =0;
std::map PlayerManager::playersEntities = std::map();
std::map PlayerManager::playersSelectedEntities = std::map();

PlayerManager::PlayerManager(){}

void PlayerManager::init(){
  PlayerManager::instance = new PlayerManager();
}

PlayerManager::~PlayerManager(){
  //clear selected units list
  std::map::iterator iter = playersSelectedEntities.begin();
  for(; iter != playersSelectedEntities.end(); ++iter){
    delete iter->second;
    iter->second = 0;
  }
  playersSelectedEntities.clear();
  playersEntities.clear();
}

//register entity in players list
void PlayerManager::registerPlayersEntity(Entity* entity){
  //register entity called only once and after registration in entity manager
  // we have entity ID and I am pretty sure it will not dublicate.
  playersEntities[entity->getID()] = entity;
}


void PlayerManager::removePlayersEntity(Entity* entity){
  //removes selecred entity from players entities lise
  std::map::iterator iter = playersEntities.find(entity->getID());
  if(iter != playersEntities.end())
    playersEntities.erase(iter);
}

Entity* PlayerManager::getPlayersEntity(int id){
  //returns pointer to entity defined by id
  std::map::iterator iter = playersEntities.find(id);
  if(iter != playersEntities.end())
    return iter->second;
  return 0;
}

void PlayerManager::addEntityToSelected(POINT mousePosition){
  D3DXVECTOR3 position(0.0f,0.0f,0.0f);
  float radius = 1.0f;

  D3DXVECTOR3 mPosition(mousePosition.x, mousePosition.y, 0.0f);

  Circle mouseCircle = {mPosition, radius };
  Circle unitCircle = {position, radius };
  mouseCircle.position.x = mousePosition.x; // need to figure out how to apply offset
  mouseCircle.position.y = mousePosition.y;
  mouseCircle.position.z = 0.0f;
  mouseCircle.radius = 2.0f;
	
  std::map::iterator iter = playersEntities.begin();
  for(; iter != playersEntities.end(); ++iter){
    unitCircle.position = iter->second->getPosition();
    unitCircle.radius = 20.0f; // need to set this global instead of calculated based on number images etc like TILEBASEWIDTH or something
    CollisionResults collisionResult = TestCollisionCircle(mouseCircle, unitCircle);
    if(collisionResult == OVERLAPPING){
      std::cout < < "AWESOME";
    }else {
      PlayerManager::clearSelected();
      std::cout << "NOT";
    }
  }
}

void PlayerManager::clearSelected(){
  std::map::iterator iter = playersSelectedEntities.begin();
  for(; iter != playersSelectedEntities.end(); ++iter){
    if(iter->second){
      delete iter->second;
      iter->second = 0;
    }
  }
  playersSelectedEntities.clear();	
}

Zombeesh overview 1 – Collision detection circle based

After less than one week – weekend not counted in (I have had over 24hrs of sleep during weekend, I really hate to be sick) I have cought up with university material. Material covered:

  • Tile system for map loaded from a file
  • offset for moving map
  • entity manager for all objects on the map – plus improvement
  • messaging system – communication between instances of objects
  • collision detection – and my own improvement
  • moving around the map – mouse based
  • font manager

Plans for next week

  • Selecting objects by mouse click – hoping to select more than one element
  • collision detection applied for object on a map
  • placing building on the map
  • shooting to zombies and other stuff.

Meanwhile I will post some code – I haven’t done that for a while.

Collision detection class with improvements

// Collision.h
#pragma once
#ifndef COLLISION_H
#define COLLISION_H

const float TOUCH_DISTANCE = 0.000000000001;

static enum CollisionResults {
  NO_COLLISION, TOUCHING, OVERLAPPING
};

struct Circle{
  D3DXVECTOR3& position;
  float radius;
};

struct BoundingBox{
  D3DXVECTOR3& position;
  D3DXVECTOR3& size;
};

bool TestCollision(const BoundingBox& a, const BoundingBox& b);

CollisionResults TestCollisionCircle(const Circle& a, const Circle& b);
#endif

Pretty easy stuff here – two structs for BoundingBox and Circle enum for collision between circles – I have added it because I want to base selecting objects and – well all collision on two circles.

// Collision.cpp
#include "Collision.h"

bool TestCollision(const BoundingBox& a, const BoundingBox& b){
  float t;
  if((t = a.position.x - b.position.x) > b.size.x || -t > a.size.x)
    return false;
  if((t = a.position.y - b.position.y) > b.size.y || -t > a.size.y)
    return false;
  if((t = a.position.z - b.position.z) > b.size.z || -t > a.size.z)
    return false;
  return true;
}

CollisionResults TestCollisionCircle(const Circle& a, const Circle& b){
  //for math
  CollisionResults colliding;
  float distance_squared;
  float radii_squared;

  //a*a + b*b = c*c
  distance_squared = ((a.position.x - b.position.x)* (a.position.x - b.position.x))+
                     ((a.position.y - b.position.y)* (a.position.y - b.position.y));

  //Multiplication is faster than taking a square root
  radii_squared = (a.radius + b.radius) * (a.radius + b.radius);

  if( -TOUCH_DISTANCE < radii_squared - distance_squared &&radii_squared - distance_squared < TOUCH_DISTANCE) 		
    colliding = TOUCHING;
  else if(radii_squared > distance_squared)
    colliding = OVERLAPPING;
  else
    colliding = NO_COLLISION;

  return colliding;
}

pretty simple stuff here as well – Pythagorean theorem based. if distance between two points is bigger than sum of radius of circles then there is no collision if it is equal there is a collision but if it is smaller they overlap – so we have covered all 3 states first two for collision detection on the map and third one for selecting. simple