Nano Aenigma

Nano Aenigma is a game for Android mobile. You are a ball that can transform in to 4 different materials with unique properties that you can utilize to solve puzzles and reach the next level.

1st year group project (grade: 8)
Genre: Puzzle
Engine: Adobe Flash
Platform: Android

Programmers:
Richard Nazarian
Rune de Groot
Willem-Jan Eeftingh

Artwork:
Eric Jeths
Hang Nguyen

Vind Het

Vind het is a Dutch game for people with dementia. Can be played with Kinect. Made by Saxion students for FUN-IE-FIT. 

2nd year group project for client (grade: 9)
Genre: Serious Game/Puzzle
Engine: Unity 4
Platform: Windows PC (Kinect support)

Programmers:
Richard Nazarian
Willem-Jan Eeftingh
Michelle Tang

Artwork:
Kassym Kushkimbayev
Hang Nguyen
Aaron Wichevski
Juri Albreht

Client:
FUN-IE-FIT
Carintreggeland

The Torch

Description

The Torch was a group project during my 2nd year at Game Technology & Producing at Saxion. A 3D adventure puzzle game using a self made C++ OpenGL engine. Darkness is everywhere, but with the power of "The Torch" you can move orbs of light from one source to another, making a pathway to the next area.

There is one bug in the game. If you watch the whole intro without skipping then the statues will be invisible to you. Press enter during the intro to skip it and this won't happen.

My contribution

  • Deferred rendering
  • Lighting (dynamic) (with bounding spheres)
  • Shadow maps (dynamic)
  • Fog
  • Transform class
  • Level loading through XML parsing (from Unity exported scenes)
  • Player controls
  • Object spawning
  • Switch object
  • Bugfixing and additions in other code

Code snippets

Code for deferred rendering. A bit dirty but it works. Each pointlight has a bounding sphere and through stencil tests only the lit geometry is rendered for lighting calculations. Shadows are dynamic and fade out when far away. Objects can be toggled to cast shadows or not.

    void SceneManager::geometryPass(){
        glDepthFunc(GL_LESS);
        glDisable(GL_DEPTH_CLAMP);
        _gBuffer.StartFrame();
        glm::mat4 id;
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        geometryShader->use();
        _gBuffer.BindForGeomPass(); // set draw buffer to gbuffer

        glDepthMask(GL_TRUE);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clean up buffer
        glEnable(GL_DEPTH_TEST); // enable depth testing

        if( _camera ) _camera->render( geometryShader ); // set perspective and view matrices
        for ( auto j = _objects.begin(); j != _objects.end(); ++j ) {
            GameObject * object = (GameObject*) *j;
            object->render( geometryShader ); // render data into buffer
        }
        if(_terrain != NULL){
            terrainShader->use();
            if( _camera ) _camera->render( terrainShader );
            _terrain->render(terrainShader);
        }
        glDepthMask(GL_FALSE);
        glEnable(GL_DEPTH_CLAMP);
        glDepthFunc(GL_LEQUAL);
    }

    void SceneManager::pointLightPass(){
        glm::mat4 id;
        for (unsigned int i = 0 ; i < _pointLights.size(); i++) { bool castShadow = false; float camDistance = glm::length(_pointLights[i]->getPosition() - _camera->getPosition());
            if(_pointLights[i]->_castShadow && camDistance < 20 ){ castShadow = true; shadowPass(_pointLights[i]); // shadows glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _gBuffer.m_fbo); // dirty } stencilPass(_pointLights[i]); pointLightShader->use();
            _gBuffer.BindForLightPass(pointLightShader); // give textures

            glStencilFunc(GL_NOTEQUAL, 0, 0xFF);

            glDisable(GL_DEPTH_TEST);
            glEnable(GL_BLEND);
            glBlendEquation(GL_FUNC_ADD);
            glBlendFunc(GL_ONE, GL_ONE);

            glEnable(GL_CULL_FACE);
            glCullFace( GL_FRONT );

            glViewport(0,0,windowX,windowY);

            pointLightShader->setUniform(pointLightShader->gScreenSize, glm::vec2(windowX,windowY));
            pointLightShader->setUniform(pointLightShader->cameraPos, _camera->getPosition());
            if(_camera)
                _camera->render(pointLightShader);
            pointLightShader->setPointLightElement(0,_pointLights[i]);
            if(castShadow){
                pointLightShader->setCubeMap(pointLightShader->shadowMap, 20, _shadowMapFBO.m_shadowMap);
                pointLightShader->setUniform(pointLightShader->useShadow,1.0f);
                float shadowFadeFactor = 0;
                if(camDistance >= 15){
                        shadowFadeFactor = 1-(20-camDistance)/5;
                }
                pointLightShader->setUniform(pointLightShader->shadowFadeFactor,shadowFadeFactor);
            }
            else{
                pointLightShader->setUniform(pointLightShader->useShadow,0.0f);
            }
            _pointLights[i]->renderBoundingSphere(pointLightShader);
            glCullFace(GL_BACK);
            glDisable(GL_BLEND);
        }
    }

    void SceneManager::shadowPass(PointLight * light){
        glDisable(GL_BLEND);
        glm::mat4 id;
        glViewport(0,0,shadowRes,shadowRes);
        shadowShader->use();
        glEnable(GL_CULL_FACE);
        glCullFace( GL_BACK );
        glEnable( GL_DEPTH_TEST ); // must be enabled after use program
        glDepthMask(GL_TRUE);
        glClearColor(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX);
        _shadowMapFBO.BindForWriting();
        float shadowFOV = 90.0f/180.f*M_PI; // 90 degrees to cover each side
        glm::mat4 depthProjectionMatrix = glm::perspective( shadowFOV, 1.f, 0.1f, 100.0f );
        shadowShader->setPointLightElement(0,light);
        shadowShader->setUniform( shadowShader->projection, depthProjectionMatrix );
        for (int k = 0 ; k < 6 ; k++) { _shadowMapFBO.WriteCubeFace(gCameraDirections[k].CubemapFace); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glm::mat4 depthViewMatrix = glm::lookAt( light->getPosition(), light->getPosition()+gCameraDirections[k].Target, gCameraDirections[k].Up );
            shadowShader->setUniform( shadowShader->view, depthViewMatrix );
            for ( auto j = _objects.begin(); j != _objects.end(); ++j ) {
                GameObject * object = (GameObject*) *j;
                if(object->castShadows){
                    object->render( shadowShader );
                }
            }
        }
        glDepthMask(GL_FALSE);
        glEnable(GL_BLEND);
    }

    void SceneManager::stencilPass(PointLight * pointLight){
        glViewport(0,0,windowX,windowY);
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

        stencilShader->use();
        glDrawBuffer(GL_NONE);

        glEnable(GL_DEPTH_TEST);
        glDisable(GL_CULL_FACE);
        glClear(GL_STENCIL_BUFFER_BIT);

        glStencilFunc(GL_ALWAYS, 0, 0);
        glStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR_WRAP, GL_KEEP);
        glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR_WRAP, GL_KEEP);

        if(_camera)
            _camera->render(stencilShader);
        pointLight->renderBoundingSphere(stencilShader);
    }

    void SceneManager::dirLightPass(){
        glm::mat4 id;
        for (unsigned int i = 0 ; i < _directionalLights.size(); i++) { dirLightShader->use();
            _gBuffer.BindForLightPass(dirLightShader); // give textures
            glDisable(GL_DEPTH_TEST);
            glEnable(GL_BLEND);
            glBlendEquation(GL_FUNC_ADD);
            glBlendFunc(GL_ONE, GL_ONE);
            glCullFace( GL_FRONT );
            glViewport(0,0,windowX,windowY);
            dirLightShader->setUniform(dirLightShader->gScreenSize, glm::vec2(windowX,windowY));
            dirLightShader->setUniform(dirLightShader->cameraPos, _camera->getPosition());
            dirLightShader->setUniform(dirLightShader->view,id);
            dirLightShader->setUniform(dirLightShader->projection,id);
            dirLightShader->setDirLightElement(0,_directionalLights[i]);
            screenQuad->render(dirLightShader,id);
        }
        glDisable(GL_BLEND);
        glCullFace(GL_BACK);
    }

    void SceneManager::fogPass(){
        glm::mat4 id;
        fogShader->use();
        _gBuffer.BindForLightPass(fogShader); // give textures
        glDisable(GL_DEPTH_TEST);
        glEnable(GL_BLEND);
        glBlendEquation(GL_FUNC_ADD);
        glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
        glCullFace( GL_FRONT );
        glViewport(0,0,windowX,windowY);
        fogShader->setUniform(fogShader->gScreenSize, glm::vec2(windowX,windowY));
        fogShader->setUniform(fogShader->cameraPos, _camera->getPosition());
        fogShader->setUniform(fogShader->view,id);
        fogShader->setUniform(fogShader->projection,id);
        screenQuad->render(fogShader,id);

        glDisable(GL_BLEND);
        glCullFace(GL_BACK);
    }

    void SceneManager::showTextures(){
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        _gBuffer.ShowBuffer();

        GLsizei HalfWidth = (GLsizei)(windowX / 2.0f);
        GLsizei HalfHeight = (GLsizei)(windowY / 2.0f);

        _gBuffer.SetReadBuffer(GBuffer::GBUFFER_TEXTURE_TYPE_POSITION);
        glBlitFramebuffer(0, 0, windowX, windowY,
                        0, 0, HalfWidth, HalfHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);

        _gBuffer.SetReadBuffer(GBuffer::GBUFFER_TEXTURE_TYPE_DIFFUSE);
        glBlitFramebuffer(0, 0, windowX, windowY,
                        0, HalfHeight, HalfWidth, windowY, GL_COLOR_BUFFER_BIT, GL_LINEAR);

        _gBuffer.SetReadBuffer(GBuffer::GBUFFER_TEXTURE_TYPE_NORMAL);
        glBlitFramebuffer(0, 0, windowX, windowY,
                        HalfWidth, HalfHeight, windowX, windowY, GL_COLOR_BUFFER_BIT, GL_LINEAR);

    }

    void SceneManager::finalPass(){
        _gBuffer.BindForFinalPass();
        glBlitFramebuffer(0, 0, windowX, windowY,
                      0, 0, windowX, windowY, GL_COLOR_BUFFER_BIT, GL_LINEAR);
    }

    // render pipeline
	void SceneManager::render( sf::RenderWindow * window )
	{
        if(_camera != NULL){
            geometryPass();
            glEnable(GL_STENCIL_TEST);
            pointLightPass();
            glDisable(GL_STENCIL_TEST);
            dirLightPass();
            //showTextures();
            if(showFog && levelNumber != 0){
                fogPass();
            }
            finalPass();
        }
		window->display();
		if(levelToLoad != ""){
            std::cout << "loading level" << std::endl;
            loadLevel(levelToLoad,levelNumber);
		}
	}

Transform class

#include "Transform.hpp"

# define M_PI           3.14159265358979323846  /* pi */

Transform::Transform()
: parentTransform(NULL)
{
}

Transform::~Transform()
{
	//dtor
}

// return position
glm::vec3 Transform::getPosition(){
    glm::mat4 trans = getWorldTransform();
    return glm::vec3 (trans[3]);
}

glm::vec3 Transform::getScale(){
    return glm::vec3 (scaleMatrix[0][0],scaleMatrix[1][1],scaleMatrix[2][2]);
}

// set position TODO
void Transform::setPosition(glm::vec3 newPosition){
    glm::vec4 temp = glm::vec4( newPosition, 1.0f );
    if(parentTransform)
        temp = glm::inverse(parentTransform->getWorldTransform()) * glm::vec4( newPosition, 1.0f );
    translationMatrix[3] = temp;
}

void Transform::setRotation(glm::vec3 newRotation){
    eulerRotation = newRotation;
    while (eulerRotation.x >= 180) eulerRotation.x -= 360;
    while (eulerRotation.x < -180) eulerRotation.x += 360; while (eulerRotation.y >= 180) eulerRotation.y -= 360;
    while (eulerRotation.y < -180) eulerRotation.y += 360; while (eulerRotation.z >= 180) eulerRotation.z -= 360;
    while (eulerRotation.z < -180) eulerRotation.z += 360; rotationMatrix = glm::eulerAngleYXZ(eulerRotation.y*M_PI/180, eulerRotation.x*M_PI/180, eulerRotation.z*M_PI/180); } void Transform::setScale(glm::vec3 newScale){ scaleMatrix = glm::scale( glm::mat4(), newScale ); } // calculate world transform with parents, maybe not efficient doing this each time you want world transform? glm::mat4 Transform::getWorldTransform(){ glm::mat4 tempTransform = getLocalTransform(); if(parentTransform){ tempTransform = parentTransform->getWorldTransform() * tempTransform;
    }
    return tempTransform;
}

// translate transform, update children
void Transform::translate(glm::vec3 translation, bool bWorldSpace){
    if (!bWorldSpace){
        glm::vec4 rotatedTranslation = rotationMatrix * glm::vec4(translation,1);
        translationMatrix = glm::translate(translationMatrix, glm::vec3(rotatedTranslation)); // world space
    }
    else{
        translationMatrix = glm::translate(translationMatrix, translation);
    }
}

void Transform::scale(glm::vec3 scaleVector){
    scaleMatrix = glm::scale( scaleMatrix, scaleVector );
}

void Transform::eulerRotate(glm::vec3 deltaRotation, bool bWorldSpace){
    eulerRotation += deltaRotation;
    while (eulerRotation.x >= 180) eulerRotation.x -= 360;
    while (eulerRotation.x < -180) eulerRotation.x += 360; while (eulerRotation.y >= 180) eulerRotation.y -= 360;
    while (eulerRotation.y < -180) eulerRotation.y += 360; while (eulerRotation.z >= 180) eulerRotation.z -= 360;
    while (eulerRotation.z < -180) eulerRotation.z += 360; if(bWorldSpace) rotationMatrix = glm::eulerAngleYXZ(eulerRotation.y*M_PI/180, eulerRotation.x*M_PI/180, eulerRotation.z*M_PI/180); else{ glm::mat4 tempMatrix = (glm::mat4) glm::eulerAngleYXZ(deltaRotation.y*M_PI/180, deltaRotation.x*M_PI/180, deltaRotation.z*M_PI/180); rotationMatrix = rotationMatrix * tempMatrix; } } // add a child transform to this transform void Transform::addChild(Transform* child){ childTransforms.push_back(child); child->setParent(this);
}

void Transform::removeChild( Transform * child ){
    std::vector<Transform*>::iterator myIterator = std::find(childTransforms.begin(), childTransforms.end(), child);
    if (myIterator != childTransforms.end())
    {
        Transform* toRemove = (Transform*) *myIterator;
        toRemove->removeParent();
        childTransforms.erase( myIterator );
    }
}

glm::mat4 Transform::getLocalTransform(){
    return translationMatrix * rotationMatrix * scaleMatrix;
}

// called by addChild when this transform is parented to a parent transform
void Transform::setParent(Transform* parent){
    parentTransform = parent;
    setScale(getScale()/parent->getScale());
}

void Transform::removeParent(){
    setScale(getScale()*parentTransform->getScale());
    parentTransform = NULL;
}

glm::vec3 Transform::eulerToDirection(glm::vec3 angle){
    glm::vec3 dir;
    float yaw = angle.y*M_PI/180;
    float pitch = angle.x*M_PI/180;

    dir.x = sin(yaw);
    dir.y = (sin(pitch)*cos(yaw));
    dir.z = -(cos(pitch)*cos(yaw));
    return dir;
}

Info

2nd year group project (grade: 10)
Genre: Adventure/Puzzle
Engine: Self made C++ OpenGL engine
Platform: Windows PC

Programming:
Richard Nazarian
Willem-Jan Eeftingh
Michelle Tang

Artwork:
Kassym Kushkimbayev
Ulvis Bariss
Jonathan van Immerzeel
Hang Nguyen
Juri Albreht