//
//  ScreenG4.cpp
//  MetarealEngine
//
//  Created by David Van Brink on 2/21/15.
//  Copyright (c) 2015 David Van Brink. All rights reserved.
//

#include "ScreenG4.h"



void ScreenG4::addWallBlock(MeVec3 center, MeVec3 radius)
{
//    MeCollisionVolume2 *cv = new MeCollisionVolume2(0, center, radius);
    MeCollisionVolume2 *cv = this->cvw->newCollisionVolume(center, radius * 2);
    MeGeometry *wallGeo = makeBoxGeometry(-radius, +radius);
    
    bool glass = rr(0,10) > 5;

    MeGaud *wallGaud = new MeGaud();
    
    //glass = 0;
    if(glass)
    {
        MePart *wallPart1 = new MePart(this->materialTransparent, wallGeo); // it's just geometry, could cat em
        this->rememberPartId(wallPart1, cv);
        wallGaud->addPart(wallPart1);
        
        wallGaud->setPartAttribute("color", MeVec3(rr(0,1), rr(0,1), rr(0,1)));

    }
    else
    {
        MePart *wallPart = new MePart(this->materialOpaque, wallGeo); // it's just geometry, could cat em
        this->rememberPartId(wallPart, cv);
        wallGaud->addPart(wallPart);
    }


    MeMatrix4 ma;
    ma.lTranslate(center);
    this->renderWorld->addGaud(wallGaud);
    setGaudMatrix(wallGaud, ma);
    this->walls.push_back(cv);
}



ScreenG4::ScreenG4()
{
    this->renderWorld = new MeRenderWorld();
    this->makeSkybox();
    
    float r = 4;
    MeGeometry *sog = makeStellatedOctohedronGeometry(-r, -r, -r, r, r, r, 0.6);
    
    this->materialOpaque = loadMaterialGl("vert1_v4.vsh", "frag1_v4.fsh");
    this->materialTransparent = loadMaterialGl("vert1_v4.vsh", "transparent.fsh");
    
    
    MeIMaterial *simpleTrans = loadMaterialGl("simpleTrans.vsh", "simpleTrans.fsh");
    simpleTrans->setBlendMode(MBM_ADD);


    MePart *pa = new MePart(this->materialOpaque, sog);
    
    this->rememberPartId(pa);
    
    this->rememberPartId(pa, NULL);
    this->starGaud = new MeGaud();
    this->starGaud->addPart(pa);
    this->renderWorld->addGaud(this->starGaud);
    setGaudMatrix(this->starGaud, this->ma);
    
    this->vw = new MeVolumeWorld();
    this->cvw = new MeCollisionVolumeWorld2(this->vw);
    
    this->addWallBlock(MeVec3(12,0,0), MeVec3(1,10,10));
    this->addWallBlock(MeVec3(-12,0,0), MeVec3(1,10,10));
    this->addWallBlock(MeVec3(0,12,0), MeVec3(15,1,15));
    this->addWallBlock(MeVec3(0,0,12), MeVec3(10,10,1));
    
    {
        for(int i = 0; i < 16000; i++)
        {
            this->addWallBlock(MeVec3(rr(20,220), rr(20,180), rr(20,150)), MeVec3(rr(0.2, 2.0), rr(0.2, 2.0), rr(0.2, 2.0)));
        }
    }
    
    this->cameraCv = this->cvw->newCollisionVolume(MeVec3(0,0,0), MeVec3(.3,.3,.3));
    
//    this->renderWorld->addStepClear("", 0xff000020);
//    this->renderWorld->addStepDraw(this->materialSky, "");
//    this->renderWorld->addStepDraw(this->materialOpaque, "");
    
    
    MeRenderWorld *rw = this->renderWorld;
    rw->addStepClear("b0", 0x123456);
    rw->addStepDraw(this->materialSky, "b0");
    rw->addStepDraw(this->materialOpaque, "b0");
//    rw->addStepDraw(this->materialTransparent, "b0", simpleTrans);

    addCopyingStep(rw, "b0", "b1");
    rw->addStepSetTextureColor("b1", this->materialTransparent, "texture1");
    rw->addStepDraw(this->materialTransparent, "b0");
    
    addCopyingStep(rw, "b0", "");

    {
        // add a second render sequence for part Id Hitting.
        MeIMaterial *mPid1 = loadMaterialGl("partId.vsh", "partId.fsh");
        MeIMaterial *mPid2 = loadMaterialGl("partId.vsh", "partId.fsh");
        rw->setActiveSequence(1);
        rw->addStepClear("", 0xff000000);
        rw->addStepDraw(this->materialOpaque, "", mPid1);
        rw->addStepDraw(this->materialTransparent, "", mPid2);
        rw->setActiveSequence(1);
    }


}

void ScreenG4::begin()
{
    
}
void ScreenG4::keyDown(int k)
{
    switch(k)
    {
        case 'q':
            this->renderSequence = 1;
            break;
        default:
            this->Screen::keyDown(k);
            break;
    }
}
void ScreenG4::keyUp(int k)
{
    switch(k)
    {
        case 'q':
            this->renderSequence = 0;
            break;
        default:
            this->Screen::keyUp(k);
            break;
    }
}

void ScreenG4::partClicked(int partId)
{
    if(this->partsById.count(partId))
    {
        MePart *part = this->partsById[partId];
        MeGaud *gaud = part->getGaud();
        meLogInfo("clicked on part id %d, part:0x%x gaud:0x%x", partId, part, gaud);
        
        if(gaud == starGaud)
        {
            float r = 20;
            MeVec3 newPos(rr(-r,r), rr(-r,r), rr(-r,r));
            this->ma.lTranslate(newPos);
            this->ma.lRotateZ(rr(-1,1));
        }
        else
        {
            MeMatrix4 ma;
            float r = 20;
            MeVec3 newPos(rr(-r,r), rr(-r,r), rr(-r,r));
            ma.lTranslate(newPos);
            setGaudMatrix(gaud, ma);
            
            if(this->collisionVolumesByPartId.count(partId))
            {
                MeCollisionVolume2 *cv = this->collisionVolumesByPartId[partId];
                cv->moveTo(newPos,1);
            }
        }
    }
}

void ScreenG4::tick()
{
    this->Screen::tick();
    MeVec3 cameraPosition = this->cameraMatrix.getPosition();
    this->cameraCv->moveTo(cameraPosition,1);
    this->vw->getIntersections();
//    meLogInfo("volume loops:%d tests:%d", this->vw->diagGetIntersectionLoopCount, this->vw->diagIntersectionTestCount);
    
    this->cvw->tick();
//    this->cvw->checkMoves();
    
    MeVec3 cameraPositionAdjusted = this->cameraCv->getPosition();  //getWentTo();
    MeVec3 cameraBump = cameraPositionAdjusted - cameraPosition;
    this->cameraMatrix.wTranslate(cameraBump);

    MeMatrix4 camM = this->cameraMatrix;
    rigidInvert(&camM);
    this->renderWorld->setUniformMatrix4("cameraMatrix", camM);

    if(cameraPosition != cameraPositionAdjusted)
    {
        MeVec3 camAt = this->cameraMatrix.getPosition();
        meLogInfo("cam at:(%.2f,%.2f,%.2f)", camAt[0], camAt[1], camAt[2]);
    }
    
    this->ma.lRotateX(0.011);
    setGaudMatrix(this->starGaud, this->ma);

}

void ScreenG4::rememberPartId(MePart *part, MeCollisionVolume2 *cv)
{
    int partId = part->getId();
    this->partsById[partId] = part;
    if(cv)
        this->collisionVolumesByPartId[partId] = cv;
}
