//********************************************************
// Syzygy is licensed under the BSD license v2
// see the file SZG_CREDITS for details
//********************************************************

// precompiled header include MUST appear as the first non-comment line
#include "arPrecompiled.h"
#include "arMesh.h"
#include "arInterfaceObject.h"
#include "arDistSceneGraphFramework.h"
#include "arSoundAPI.h"

#include "visual.h"

struct QTAudioFrequencyLevels {
   int      numChannels;
   int      numFrequencyBands;
   float    level[];
};

// stuff that's really specific to this app

ARfloat  vertexPosition1[900];
ARfloat  colors[1200];
arStructuredData* linesData = NULL;
arStructuredData* linePointsData = NULL;
int linePointsID = -1;
int visibilityID = -1;

arMatrix4 worldTransform, navTransform;
arMatrix4 local1Matrix, local2Matrix, local3Matrix, local4Matrix;
int worldTransformID[2], navTransformID[2];
int local1TransformID, local2TransformID, local3TransformID, local4TransformID;
int billboardTransformID;
arMatrix4 billboardTransform;
int lightTransformID[3];
arMatrix4 lightTransform[3];

arDistSceneGraphFramework* framework;
arInterfaceObject* interfaceObject;

const arVector3 xyz(0,0,0);
int idLoop;

void worldInit(arDistSceneGraphFramework* framework) {
  // global transform, as controlled by the input device
  //const string navNodeName = framework->getNavNodeName();
  // drew's trick to get peer root churning
  const string navNodeName = framework->getNavNodeName();

  // The lights.
  dgLight("light0","root",0,arVector4(0,0,1,0),arVector3(1,1,1));
  dgLight("light1","root",1,arVector4(0,0,-1,0),arVector3(1,1,1));
  dgLight("light2","root",2,arVector4(0,-1,0,0),arVector3(1,1,1));
  dgLight("light3","root",3,arVector4(0,1,0,0),arVector3(1,1,1));

  lightTransformID[0] = dgTransform("light trans 0",navNodeName,lightTransform[0]);
  lightTransformID[1] = dgTransform("light trans 1",navNodeName,lightTransform[1]);
  lightTransformID[2] = dgTransform("light trans 2",navNodeName,lightTransform[2]);

  // object transform
  worldTransformID[0] = dgTransform("world",navNodeName,worldTransform);
  worldTransformID[1] = dsTransform("world",navNodeName,worldTransform);
  string myParent;

  // attach cube 1
  local1TransformID = dgTransform("local1","world",local1Matrix);
  dgTexture("texture1", "local1", "happy.ppm");
  dgMaterial("material1", "texture1", arVector3(1,0.6,0.6));
  arCubeMesh theMesh(local1Matrix);
  theMesh.attachMesh("torus1","material1");
}

void worldAlter(QTAudioFrequencyLevels* mFreqResults){
  static bool init = false;
  static ar_timeval oldTime;
  float factor = 1.;
  if (!init)
    init = true;
  else
    factor = ar_difftime(ar_time(),oldTime)/30000.0;
  oldTime = ar_time();

    // iterate though the frequency level array and though the UI elements getting
    // and setting the levels appropriately
/*    for (i = 0; i < mFreqResults->numChannels; i++) {
        for (j = 0; j < mFreqResults->numFrequencyBands; j++) {
                // the frequency levels are Float32 values between 0. and 1.
            //Float32 value = (mFreqResults->level[(i * mFreqResults->numFrequencyBands) + j]);
        }
    } */

  // Precomputing these rotation matrices would be faster, of course.
  lightTransform[0] = ar_rotationMatrix('y',factor*0.005) * lightTransform[0];
  lightTransform[1] = ar_rotationMatrix('x',factor*0.009) * lightTransform[1];
  lightTransform[2] = ar_rotationMatrix('z',factor*0.011) * lightTransform[2];
  dgTransform(lightTransformID[0], lightTransform[0]);
  dgTransform(lightTransformID[1], lightTransform[1]);
  dgTransform(lightTransformID[2], lightTransform[2]);
  
  local1Matrix = ar_scaleMatrix(1, 10 *  mFreqResults->level[4], 1);
  dgTransform(local1TransformID,local1Matrix * !local3Matrix);

  dgTransform(worldTransformID[0],worldTransform);

  static int currentVis = 1;
  dgVisibility(visibilityID,currentVis);
  static int howMany = 0;
  if (++howMany>30){
    currentVis = 1-currentVis;
    howMany = 0;
  }
}

extern "C" {
        int visual_init(int, char**);
}
int visual_init(int argc, char* argv[]) {
        // We could dispense with the pointer, but it *might* cause that
        // intermittent constructor-hang.  To be tested more.
        framework = new arDistSceneGraphFramework;
        // MUST set the buffer swap mode BEFORE init!
        framework->setAutoBufferSwap(false);
        if (!framework->init(argc,argv)){
                return 1;
        }

        // Where we can put the textures and sounds.
        framework->setDataBundlePath("SZG_DATA", "cosmos");
        interfaceObject = new arInterfaceObject();
        interfaceObject->setInputDevice(framework->getInputNode());
        // The following is VERY important... otherwise the navigation is
        // WAY too fast.
        interfaceObject->setSpeedMultiplier(0.15);
        
        worldInit(framework, peer); */
        worldInit(framework);

        // Configure stereo view.
        framework->setEyeSpacing( 6/(2.54*12) );
        framework->setClipPlanes( .3, 1000. );
        framework->setUnitConversion( 1. );
        // More initializing.

        if (!framework->start() || !interfaceObject->start()){
        return 1;
        }

        // Place scene in the center of the front wall.
        interfaceObject->setNavMatrix(ar_translationMatrix(0,5,-5));

        //idLoop = dsLoop("ambience", "world", "dre.mp3", 1, 1, xyz);

        return 1;
}

extern "C" {
        int visual_loop(QTAudioFrequencyLevels*);
}
int visual_loop(QTAudioFrequencyLevels* mFreqResults) {
        navTransform = interfaceObject->getNavMatrix().inverse();
        worldTransform = interfaceObject->getObjectMatrix();
        ar_setNavMatrix( navTransform );

        // No lock needed, since there's only one thread.
        dgTransform(worldTransformID[0], worldTransform);
        dsTransform(worldTransformID[1], worldTransform);
        framework->loadNavMatrix();

        worldAlter(mFreqResults);

        // DO NOT TURN THE AMBIENT SOUND ON/OFF, THIS IS A NICE TEST OF
        // "IS SPATIALIZED SOUNDS WORKING" AND TURNING ON/OFF MESSES THAT
        // UP.
        //(void)dsLoop(idLoop, "dre.mp3", 1, 1, xyz);

        // Change viewpoint.
        framework->setViewer();
        framework->setPlayer();

        // and now we go ahead and force a buffer swap (which we are controlling
        // manually)
        framework->swapBuffers();

        return 0;
}