Kolor is a first-person 3D shooter game developed using only C++ & OpenGL. The objective of the game is to gain dominance in the world by coloring other players to your own color. Players belong to a team, represented by a captain and his color. You can Kolor(paint) all the players on the team or just kolor the master to claim the team.

I built a prototype using C# & XNA to determine if the game would be fun. XNA takes care of a lot of details, which forced me to dig deeper into the math involved. This motivated me to adopt C++/OpenGL as the only tools. This turned out to be a huge undertaking. As a part of this, I implemented my own COLLADA DAE model library.

Interesting things I did along the way:

- COLLADA DAE loader
- How do I move in this world ? (FrameTransform)
- First-Person View (my own gluLookAt)
- Coloring Players
- Team architecture

COLLADA DAE Model Library

I needed a way to load & render 3D models for players/weapons/world. I was advised to use COLLADA DAE since it's the industry standard. I had to write my own Collada importer since there was no open source library at the time. I interpreted DAE's Directed Acyclic Graph into my own scene-graph. Take a look at:

- VSGNode & VSceneGraph.h / cpp (DAE Model is accessed using this facade)

- Scene Graph
- Model Mesh information (organised in a tree structure)
- Node in scenegraph can have the following operations defined in DAE (VSGNode.h / cpp):
- Lookat
- Transformation defined by a 4x4 matrix
- Translate along X / Y or Z axis
- Rotation at a given angle about an arbitrary axis
- Scale / Skew

- Primitives supported:
- Triangle List
- Polygon List

- Vertex (.h) represents the heart of the model which stores data attributes as boost::hash_map { Semantic, (float*) }

Indexed Vertex Buffer Objects

Initially, I was using glBegin/glEnd to render models. However, when I loaded a high poly count model, the FPS crippled. I resorted to using Indexed Vertex Buffer Objects (VBOs) which helped FPS. For generating vertex indices, I ran the list of vertices through a hash-map and assign a unique index for each vertex. This can be seen in GeomMesh.cpp constructor and bool VertexExists(...) function.
Top

FrameTransform

Once the model was rendered, I wanted to create a "player" who could move around in the world, keeping track of its position and orientation. This gave birth to FrameTransform. I did this using three vectors:

- Origin
- Up
- Forward vector

FrameTransform was generic in nature and players could fly. PlayerTransform restricts this behavior by enabling movement only along the X/Z axis:

- Move (..)
- Rotate(...)

My own gluLookAt

For the First-person view, I needed to position world and everything else relative to player's coordinate system. Camera class uses the OpenGL transformation stack to transform everything as per player's Coordinate system. It is a 'friend' of (Human)Player, since the camera is tightly coupled to the player.

` ````
class FrameTransform (6 DOF)
- glm::vec3 m_Origin;
- glm::vec3 m_Forward;
- glm::vec3 m_Up;
• MoveForward/Right/Up ( amt )
• RotateAround X/Y/Z ( amt )
• void ApplyActorTransform () => calls glMultMatrix(..)
class Player : public GameObject
- FrameTransform m_Transform; => Coordinate system w.r.t the world CS
class World : public GameObject (level class)
- FrameTransform m_Transform; => Coordinate system w.r.t the world CS
```

A first person camera helps to view the world from the player’s eyes. Thus, we need a transformation which enables the view from player’s reference. Example:

- WCS (0, 0)W
- PCS (2, 2)W => Player is at 2, 2 in the world coordinate system => PW<=P (2, 2)
- Chair P = (.5, .5)P
- => Chair W = PW<=P * ChairP = (2.5, 2.5)W

Player.m_Transform represents PW<=P . If we invert this matrix, we get P’P<-W which brings everything from World coordinate space to Player Coordinate space.

```
void Camera :: ApplyCameraTransform()
{
glm::mat4 l_TransformationMatrix;
m_Player->m_Transformation.GetTransformation(l_TransformationMatrix, false);
l_TransformationMatrix = glm::core::function::matrix::inverse(l_TransformationMatrix);
glMultMatrixf(glm::value_ptr(l_TransformationMatrix));
}
```

It is invoked as follows:
```
void GameGL :: paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
mp_Camera->ApplyCameraTransform();
std::list<GameObject*>::iterator it_GameObjs;
for(it_GameObjs = m_GameObjectList.begin(); it_GameObjs != m_GameObjectList.end(); it_GameObjs++) {
(*it_GameObjs)->Render();
}
...
}
```

Top
Coloring Players - When player and bullet collide!
As players move about and fire bullets, I manage collision detection/resolution by splitting it into broad and narrow phase.

The involved actors are :-

- Players are approximated by a bounding sphere, located at a position and moving with a velocity. Player can potentially collide with weapons, world & bullets.
- Bullets are represented by a segment with a start point & end point (using posn, posn + vel). Bullet can hit other fired bullets, players or world.

- For each player, find Cell(s); it is associated with :=> list< Cell* > PlayerCells
- For each Bullet (segment), find Cell(s); it is associated with :=> list< Cell* > BulletCells
- For each entity, the cell(s) can be found out based on the entity.
- Player: Bounding sphere: The grid size are uniformly sized cell(M) such that, M = 2R. At any given time, the bounding sphere can be in contact with max 4 cells. To determine the cells associated, find the 8 points for a given sphere (each at 45 degrees X,Y,Z axis along 8 octants). (And then find out, in which grid cell does each of the point lie. This could return max 4 cells).
- Bullet: Segmented Ray with endpoints at: Posn and (Posn + vel). All the cells that the line passes through would yield the cells.

- Cell can be a structure like:
`Cell { List < Player*> List < Bullet* > Value (x,y,z) => unique value based on these three coordinates }`

- Iterate through all the points on the model tracking min/max point
- Compute Sphere center & radius = distance(minimumPt, maximumPt) * 0.5;
- This is run recursively on the scenegraph to return a hierarchy of bounding spheres
- The resulting bounding spheres tight-approximation for the underlying model