/* 
 * @Description: setup function ( more aesthetic as could be in constructor here )
 * @param: none
 * @return: none
 */
void Base_ThreeD_ProjectApp::setup()
{
	RENDER_MODE = 3;
	
	glEnable( GL_LIGHTING );
	glEnable( GL_DEPTH_TEST );
	glEnable(GL_RESCALE_NORMAL); //important if things are being scaled as OpenGL also scales normals ( for proper lighting they need to be normalized )
	
	mParams = params::InterfaceGl( "3D_Scene_Base", Vec2i( 225, 125 ) );
	mParams.addParam( "Framerate", &mCurrFramerate, "", true );
	mParams.addParam( "Eye Distance", &mCameraDistance, "min=-100.0 max=-5.0 step=1.0 keyIncr== keyDecr=-");
	mParams.addParam( "Lighting On", &mLightingOn, "key=l");
	mParams.addParam( "Show/Hide Params", &mShowParams, "key=x");
	mParams.addSeparator();
    
	
	mCurrFramerate = 0.0f;
	mLightingOn = true;
	mViewFromLight = false;
	mShowParams = true;
	
	//create camera
	mCameraDistance = CAM_POSITION_INIT.z;
	mEye		= Vec3f(CAM_POSITION_INIT.x, CAM_POSITION_INIT.y, CAM_POSITION_INIT.z);
	mCenter		= Vec3f::zero();
	mUp			= Vec3f::yAxis();
	
	mCam = new CameraPersp( getWindowWidth(), getWindowHeight(), 180.0f );
	mCam->lookAt(mEye, mCenter, mUp);
	mCam->setPerspective( 45.0f, getWindowAspectRatio(), 1.0f, 50.0f );
	gl::setMatrices( *mCam );
	
	//create light
	mLight = new gl::Light( gl::Light::DIRECTIONAL, 0 );
	mLight->lookAt( Vec3f(LIGHT_POSITION_INIT.x, LIGHT_POSITION_INIT.y * -1, LIGHT_POSITION_INIT.z), Vec3f( 0, 0, 0 ) );
	mLight->setAmbient( Color( 1.0f, 1.0f, 1.0f ) );
	mLight->setDiffuse( Color( 1.0f, 1.0f, 1.0f ) );
	mLight->setSpecular( Color( 1.0f, 1.0f, 1.0f ) );
	mLight->setShadowParams( 100.0f, 1.0f, 20.0f );
	mLight->update( *mCam );
	mLight->enable();
	
	//create light ref
	mLightRef = new gl::Light( gl::Light::DIRECTIONAL, 0 );
	mLightRef->lookAt( LIGHT_POSITION_INIT, Vec3f( 0, 0, 0 ) );
	mLightRef->setShadowParams( 100.0f, 1.0f, 20.0f );
	
	//DEBUG Test objects
	ci::ColorA pink( CM_RGB, 0.84f, 0.49f, 0.50f, 1.0f );
	ci::ColorA green( CM_RGB, 0.39f, 0.78f, 0.64f, 1.0f );
	ci::ColorA blue( CM_RGB, 0.32f, 0.59f, 0.81f, 1.0f );
	ci::ColorA orange( CM_RGB, 0.77f, 0.35f, 0.35f, 1.0f );
	
	gl::Material torusMaterial;
	torusMaterial.setSpecular( ColorA( 1.0, 1.0, 1.0, 1.0 ) );
	torusMaterial.setDiffuse( pink );
	torusMaterial.setAmbient( ColorA( 0.3, 0.3, 0.3, 1.0 ) );
	torusMaterial.setShininess( 25.0f );
	
	gl::Material boardMaterial;
	boardMaterial.setSpecular( ColorA( 0.0, 0.0, 0.0, 0.0 ) );
	boardMaterial.setAmbient( ColorA( 0.3, 0.3, 0.3, 1.0 ) );
	boardMaterial.setDiffuse( green );	
	boardMaterial.setShininess( 0.0f );
	
	gl::Material boxMaterial;
	boxMaterial.setSpecular( ColorA( 0.0, 0.0, 0.0, 0.0 ) );
	boxMaterial.setAmbient( ColorA( 0.3, 0.3, 0.3, 1.0 ) );
	boxMaterial.setDiffuse( blue );	
	boxMaterial.setShininess( 0.0f );
	
	gl::Material sphereMaterial;
	sphereMaterial.setSpecular( ColorA( 1.0, 1.0, 1.0, 1.0 ) );
	sphereMaterial.setAmbient( ColorA( 0.3, 0.3, 0.3, 1.0 ) );
	sphereMaterial.setDiffuse( orange ) ;	
	sphereMaterial.setShininess( 35.0f );	
	
    //using DisplayLists for simplicity but highly recommend to use VBO's for serious work ( as DisplayLists will be deprecated soon ... and speed difference in now negligible )
	mTorus = gl::DisplayList( GL_COMPILE );
	mTorus.newList();
	gl::drawTorus( 1.0f, 0.3f, 32, 64 );
	mTorus.endList();
	mTorus.setMaterial( torusMaterial );
	
	mBoard = gl::DisplayList( GL_COMPILE );
	mBoard.newList();
	gl::drawCube( Vec3f( 0.0f, 0.0f, 0.0f ), Vec3f( 10.0f, 0.1f, 10.0f ) );
	mBoard.endList();
	mBoard.setMaterial( boardMaterial );
	
	mBox = gl::DisplayList( GL_COMPILE );
	mBox.newList();
	gl::drawCube( Vec3f( 0.0f, 0.0f, 0.0f ), Vec3f( 1.0f, 1.0f, 1.0f ) );
	mBox.endList();
	mBox.setMaterial( boxMaterial );
	
	mSphere = gl::DisplayList( GL_COMPILE );
	mSphere.newList();
	gl::drawSphere( Vec3f::zero(), 0.8f, 30 );
	mSphere.endList();
	mSphere.setMaterial( sphereMaterial );
	
    //noise texture required for SSAO calculations
	mRandomNoise = gl::Texture( loadImage( loadResource( NOISE_SAMPLER ) ) );
	
	initFBOs();
	initShaders();
}
void DeferredRenderingApp::setup()
{
    //!!test texture for diffuse texture
    mEarthTex = gl::Texture( loadImage( loadResource( RES_TEX_EARTH ) ) );
    
	gl::disableVerticalSync(); //so I can get a true representation of FPS (if higher than 60 anyhow :/)
    
	RENDER_MODE = DeferredRenderer::SHOW_FINAL_VIEW;
    
	mParams = params::InterfaceGl( "3D_Scene_Base", Vec2i( 225, 125 ) );
	mParams.addParam( "Framerate", &mCurrFramerate, "", true );
    mParams.addParam( "Selected Light Index", &mCurrLightIndex);
	mParams.addParam( "Show/Hide Params", &mShowParams, "key=x");
	mParams.addSeparator();
    
	mCurrFramerate = 0.0f;
	mShowParams = true;
	
	//set up camera
	mCam.setPerspective( 45.0f, getWindowAspectRatio(), 0.1f, 10000.0f );
    mCam.lookAt(CAM_POSITION_INIT * 1.5f, Vec3f::zero(), Vec3f(0.0f, 1.0f, 0.0f) );
    mCam.setCenterOfInterestPoint(Vec3f::zero());
    mMayaCam.setCurrentCam(mCam);
    
    //create functions pointers to send to deferred renderer
    boost::function<void(gl::GlslProg*)> fRenderShadowCastersFunc = boost::bind( &DeferredRenderingApp::drawShadowCasters, this, boost::lambda::_1 );
    boost::function<void(gl::GlslProg*)> fRenderNotShadowCastersFunc = boost::bind( &DeferredRenderingApp::drawNonShadowCasters, this,  boost::lambda::_1 );
    boost::function<void(void)> fRenderOverlayFunc = boost::bind( &DeferredRenderingApp::drawOverlay, this );
    boost::function<void(void)> fRenderParticlesFunc = boost::bind( &DeferredRenderingApp::drawDepthParticles, this );
    
    //NULL value represents the opportunity to a function pointer to an "overlay" method. Basically only basic textures can be used and it is overlayed onto the final scene.
    //see example of such a function (from another project) commented out at the bottom of this class ...
    
    mDeferredRenderer.setup( fRenderShadowCastersFunc, fRenderNotShadowCastersFunc, NULL, NULL, &mCam, Vec2i(APP_RES_HORIZONTAL, APP_RES_VERTICAL), 1024, true, true ); //no overlay or "particles"
    //mDeferredRenderer.setup( fRenderShadowCastersFunc, fRenderNotShadowCastersFunc, fRenderOverlayFunc, NULL, &mMayaCam, Vec2i(APP_RES_HORIZONTAL, APP_RES_VERTICAL), 1024, true, true ); //overlay enabled
    //mDeferredRenderer.setup( fRenderShadowCastersFunc, fRenderNotShadowCastersFunc, fRenderOverlayFunc, fRenderParticlesFunc, &mMayaCam, Vec2i(APP_RES_HORIZONTAL, APP_RES_VERTICAL), 1024, true, true ); //overlay and "particles" enabled -- not working yet
    
    //have these cast point light shadows
    mDeferredRenderer.addCubeLight(    Vec3f(-2.0f, 4.0f, 6.0f),      Color(0.10f, 0.69f, 0.93f) * LIGHT_BRIGHTNESS_DEFAULT, true);      //blue
    mDeferredRenderer.addCubeLight(    Vec3f(4.0f, 6.0f, -4.0f),      Color(0.94f, 0.15f, 0.23f) * LIGHT_BRIGHTNESS_DEFAULT, true);      //red
    
    //add a bunch of lights
    for(int i = 0; i < NUM_LIGHTS; i++) {
        
        int randColIndex = Rand::randInt(5);
        Color randCol;
        switch( randColIndex ) {
            case 0:
                randCol = Color(0.99f, 0.67f, 0.23f); //orange
                break;
            case 1:
                randCol = Color(0.97f, 0.24f, 0.85f); //pink
                break;
            case 2:
                randCol = Color(0.00f, 0.93f, 0.30f); //green
                break;
            case 3:
                randCol = Color(0.98f, 0.96f, 0.32f); //yellow
                break;
            case 4:
                randCol = Color(0.10f, 0.69f, 0.93f); //blue
                break;
            case 5:
                randCol = Color(0.94f, 0.15f, 0.23f); //red
                break;
        };
        
        mDeferredRenderer.addCubeLight( Vec3f(Rand::randFloat(-1000.0f, 1000.0f),Rand::randFloat(0.0f, 50.0f),Rand::randFloat(-1000.0f, 1000.0f)),
                                       randCol * LIGHT_BRIGHTNESS_DEFAULT,
                                       false,
                                       true);
    }
    
    mCurrLightIndex = 0;
}
void CinderDeferredRenderingApp::setup()
{
    //!!test texture for diffuse texture
    mEarthTex = gl::Texture( loadImage( loadResource( RES_EARTH_TEX ) ) );
    
	gl::disableVerticalSync(); //so I can get a true representation of FPS (if higher than 60 anyhow :/)
    
    #if defined( CINDER_MAC )
    //setAlwaysOnTop(true); //the easy but inconvenient way to have fullscreen but not have app have complete control
    AppleUtilities::autohideMenuBar(); //a better but more complicated way to do the above
    #endif
    
	RENDER_MODE = DeferredRenderer::SHOW_FINAL_VIEW;
    
	mParams = params::InterfaceGl( "3D_Scene_Base", Vec2i( 225, 125 ) );
	mParams.addParam( "Framerate", &mCurrFramerate, "", true );
    mParams.addParam( "Selected Light Index", &mCurrLightIndex);
	mParams.addParam( "Show/Hide Params", &mShowParams, "key=x");
	mParams.addSeparator();
    
	mCurrFramerate = 0.0f;
	mShowParams = true;
	
	//set up camera
    CameraPersp initialCam;
	initialCam.setPerspective( 45.0f, getWindowAspectRatio(), 0.1, 10000 );
    initialCam.lookAt(CAM_POSITION_INIT * 1.5f, Vec3f::zero(), Vec3f(0.0f, 1.0f, 0.0f) );
    initialCam.setCenterOfInterestPoint(Vec3f::zero());
	mMayaCam.setCurrentCam( initialCam );

    //create functions pointers to send to deferred renderer
    boost::function<void(gl::GlslProg*)> fRenderShadowCastersFunc;
    boost::function<void(gl::GlslProg*)> fRenderNotShadowCastersFunc;
    fRenderShadowCastersFunc = boost::bind(&CinderDeferredRenderingApp::drawShadowCasters, this, boost::lambda::_1 );
    fRenderNotShadowCastersFunc = boost::bind(&CinderDeferredRenderingApp::drawNonShadowCasters, this,  boost::lambda::_1 );
    
    //setting up deferred renderer ...
    mDeferredRenderer.setup( fRenderShadowCastersFunc, fRenderNotShadowCastersFunc, &mMayaCam );
    
    //have these cast point light shadows
    mDeferredRenderer.addCubeLight(    Vec3f(-2.0f, 4.0f, 6.0f),      Vec3f(0.10f, 0.69f, 0.93f) * LIGHT_BRIGHTNESS, true);      //blue
    mDeferredRenderer.addCubeLight(    Vec3f(4.0f, 6.0f, -4.0f),      Vec3f(0.94f, 0.15f, 0.23f) * LIGHT_BRIGHTNESS, true);      //red
    
//    mDeferredRenderer.addCubeLight(    Vec3f(-10.0f, 8.0f, 12.0f),    Vec3f(0.99f, 0.67f, 0.23f) * LIGHT_BRIGHTNESS, true);           //orange
//    mDeferredRenderer.addCubeLight(    Vec3f(6.0f, 10.0f, -10.0f),    Vec3f(0.97f, 0.24f, 0.85f) * LIGHT_BRIGHTNESS, true);           //pink
//    mDeferredRenderer.addCubeLight(    Vec3f(-8.0f, 12.0f, -8.0f),    Vec3f(0.00f, 0.93f, 0.30f) * LIGHT_BRIGHTNESS, true);           //green
//    mDeferredRenderer.addCubeLight(    Vec3f(12.0f, 8.0f, 14.0f),     Vec3f(0.98f, 0.96f, 0.32f) * LIGHT_BRIGHTNESS, true);            //yellow
    
    //add a bunch of lights
    for(int i = 0; i < NUM_LIGHTS; i++) {
        
        int randColIndex = Rand::randInt(5);
        Vec3f randCol;
        switch( randColIndex ) {
            case 0:
                randCol = Vec3f(0.99f, 0.67f, 0.23f); //orange
                break;
            case 1:
                randCol = Vec3f(0.97f, 0.24f, 0.85f); //pink
                break;
            case 2:
                randCol = Vec3f(0.00f, 0.93f, 0.30f); //green
                break;
            case 3:
                randCol = Vec3f(0.98f, 0.96f, 0.32f); //yellow
                break;
            case 4:
                randCol = Vec3f(0.10f, 0.69f, 0.93f); //blue
                break;
            case 5:
                randCol = Vec3f(0.94f, 0.15f, 0.23f); //red
                break;
        };
        
        mDeferredRenderer.addCubeLight( Vec3f(Rand::randFloat(-1000.0f, 1000.0f), Rand::randFloat(0.0f, 50.0f), Rand::randFloat(-1000.0f, 1000.0f)),
                                        randCol * LIGHT_BRIGHTNESS);
    }
    
    mCurrLightIndex = 0;
}