void _C::generateRandCamBounce(){
    //reset cam path.
    cloudsPathCam.clear();

    jtn::TreeNode::clearPathFlags();
    
    float s = 50;
    ofVec3f firstPos;
    for(int i=0;i<10.0;i++){
        // add a random point somewhere
        ofVec3f p = ofVec3f(
                            ofRandomf() * s,
                            ofRandomf() * s,
                            ofRandomf() * s
                            );
        cloudsPathCam.addPositionControlVertex( p );
        cloudsPathCam.addTargetControlVertex(ofVec3f());
        
        if(i==0)firstPos = p;
    }
    
    //one more to make it loop.
    
    cloudsPathCam.addPositionControlVertex( firstPos );
    cloudsPathCam.addTargetControlVertex(ofVec3f());
    
    
    // orient cam path to look inward,
    // so we always start out seeing something full
    
    ofCamera& cam = getCameraRef();
    cam.lookAt(ofVec3f());
}
//normal update call
void CloudsVisualSystemOscillations::selfUpdate(){
    
    //MA: changed ofGetWidth() to getCanvasWidth() and ofGetHeight() to getCanvasHeight()
    width = getCanvasWidth();
    height = getCanvasHeight();
    offsetX += speed;
    
    if (renderLines){
        mesh.setMode(OF_PRIMITIVE_LINE_LOOP);
    } else {
        mesh.setMode(OF_PRIMITIVE_POINTS);
    }
    
    //FIXME: This shouldn't happen unprovoked. It needs to be a callback to the UI.
    BuildGrid();
	
	getCameraRef().setNearClip(clipPlanes.min);
	getCameraRef().setFarClip(clipPlanes.max);
}
void CloudsVisualSystemFireworks::explodeFireWorkAtRandom()
{
	float t = ofGetElapsedTimef();
	nextFireworkExplosionTime = t + ofRandom( minExplosionTime, maxExplosionTime ) * explosionFrequencey;
	
	ofVec3f offset( ofRandom(-1, 1), ofRandom(-.75,.75), ofRandom(-1.5, .5));
	offset.normalize();
	offset *= spawnDistance;
	
	ofVec3f rocketStart = offset + ofVec3f( ofRandom(-400, 400), 2000, 0);
	
	offset = offset * getCameraRef().getOrientationQuat();
	rocketStart = rocketStart;
	
	fireWorkExplosionTime = ofGetElapsedTimef();
	
	
	//get an active firework type and explode it
	int randFWType;
	vector<int> fwIndex;
	
	if(bDodecagedron) fwIndex.push_back( 0 );
	if(bBurst) fwIndex.push_back( 1 );
	if(bOctahedron) fwIndex.push_back( 2 );
	if(bTetrahedron) fwIndex.push_back( 3 );
	
	if(fwIndex.size() == 0)	randFWType = 4;
	else randFWType = fwIndex[ min( int(fwIndex.size())-1, (int) ofRandom(0, fwIndex.size() ) ) ];

	switch (randFWType) {
		case 0:
			explodeGeometry( dodecagedronPoints, camTarget + offset, camTarget + rocketStart );
			break;
			
		case 1:
			explodeFireWork( camTarget + offset );
			break;
			
		case 2:
			explodeGeometry( octahedronPoints, camTarget + offset, camTarget + rocketStart );
			break;
			
		case 3:
			explodeGeometry( tetrahedronPoints, camTarget + offset, camTarget + rocketStart );
			break;
			
		default:
			explodeFireWork( camTarget + offset );
			break;
	}
}
void CloudsVisualSystemCubeCraft::selfUpdate()
{
	float currentTime = ofGetElapsedTimef();
//	ofSetWindowTitle( ofToString( ofGetFrameRate() ) );
	float tDelta = currentTime - lastTime;
	noiseTime += tDelta * speed;
	
	lastTime = currentTime;
	
	cameraOffset += getCameraRef().getLookAtDir() * tDelta * speed;

//#ifndef CLOUDS_APP
//	ofSetWindowTitle( ofToString( ofGetFrameRate() ) );
//#endif
    
}
void CloudsVisualSystemFireworks::selfBegin()
{	
	//shader
	shader.begin();
	shader.setUniform3f( "gravity", gravity.x, gravity.y, gravity.z );
	shader.end();
	
	//particle rendering
	bUpdateVbo = true;
	indexCount = 0;
	nextIndex = 0;
	numSprites = 0;
	
	nextFireworkExplosionTime = ofGetElapsedTimef() + 1;
	
	ofEnableArbTex();
	
	getCameraRef().setPosition(0, 0, 0);
	camTarget.set( 0,0,spawnDistance);
}
void _C::selfUpdate(){
    
    cloudsPathCam.update();
    
    rotation += spinSlider->getScaledValue();
    
    ofCamera& cam = getCameraRef();
    
    jtn::TreeNode::terminals.clear();
    vector<jtn::TreeNode*>::iterator it;
    for(it=rootNodes.begin();it!=rootNodes.end();it++){
        (*it)->update();
    }
    
    
    // these are separate because children are born in the previous update calls
    // and we want to catch them all
    
    for(it=jtn::TreeNode::all.begin();it!=jtn::TreeNode::all.end();it++){
        (*it)->updateScreenSpace(cam);
    }
    
    
    updateBoundingBox();
    
    axonThickness = axonThicknessSlider->getScaledValue();
    dotSize = dotSizeSlider->getScaledValue();
    alpha = alphaSlider->getScaledValue();
    sway = swaySlider->getScaledValue();
    nodeMax = nodeMaxSlider->getScaledValue();
    rootCount = rootCountSlider->getScaledValue();
    danceAmp = danceAmpSlider->getScaledValue();
    danceFreq = danceFreqSlider->getScaledValue();
    danceOffset = danceOffsetSlider->getScaledValue();
    
    
}
void CloudsVisualSystemFireworks::selfDraw()
{
	glPushAttrib(GL_ALL_ATTRIB_BITS);
	ofPushStyle();
	
	ofEnableDepthTest();
    glEnable(GL_NORMALIZE);
	
	ofEnableAlphaBlending();
	ofBlendMode( OF_BLENDMODE_ADD );
	ofEnablePointSprites();
	
	vector<ofFloatColor> fireworkColorArray;
	for (map<string, ofColor>::iterator it=fwColors.begin(); it!=fwColors.end(); it++)
	{
		fireworkColorArray.push_back( ofFloatColor(it->second) );
	}
	vector<ofFloatColor> fireworkDeathColorArray;
	for (map<string, ofColor>::iterator it=fwDeathColors.begin(); it!=fwDeathColors.end(); it++)
	{
		fireworkDeathColorArray.push_back( ofFloatColor(it->second) );
	}
	
	shader.begin();
	shader.setUniform4fv("fwColors", &fireworkColorArray[0].r, fireworkColorArray.size() );
	shader.setUniform4fv("fwDeathColors", &fireworkDeathColorArray[0].r, fireworkDeathColorArray.size() );
	shader.setUniform1f( "time", ofGetElapsedTimef() );
	shader.setUniform1f( "nearClip", getCameraRef().getNearClip() );
	shader.setUniform1f( "farClip", getCameraRef().getFarClip() );
	shader.setUniform1f( "speed", speed);
	shader.setUniform1f( "particleSize", particleSize);
	
	shader.setUniform3f("cameraPosition", camPos.x, camPos.y, camPos.z );
	
	ofFloatColor c0 = startColor;
	c0.setSaturation( startColorSaturation * 255 );
	
	ofFloatColor c1 = endColor;
	c1.setSaturation( endColorSaturation * 255 );
	shader.setUniform4f("startColor", c0.r, c0.g, c0.b, c0.a );
	shader.setUniform4f("endColor", c1.r, c1.g, c1.b, c1.a );
	
	shader.setUniform3f( "gravity", gravity.x, gravity.y, gravity.z );
	
	shader.setUniformTexture("dotMap", dotImage.getTextureReference(), 4 );
	shader.setUniformTexture("triangleMap", triangleImage.getTextureReference(), 3 );
	shader.setUniformTexture("squareMap", squareImage.getTextureReference(), 2 );
	shader.setUniformTexture("circleMap", circleImage.getTextureReference(), 1 );
	
	shader.setUniform1f( "useCircleMap", bUseCircle );
	shader.setUniform1f( "useSquareMap", bUseSquare );
	shader.setUniform1f( "useTriangleMap", bUseTriangle );
	shader.setUniform1f( "useDotMap", bUseDot );
	
	ofVec3f camPos = getCameraRef().getPosition();
	shader.setUniform3f("camearPosition", camPos.x, camPos.y, camPos.z);
	shader.setUniform1f("fogDistance", fogDistance);
	shader.setUniform1f("fogAttenuation", fogAttenuation);
	ofFloatColor fc = fogColor;
	fc.setSaturation(fogSaturation);
	shader.setUniform4f("fogColor", fc.r, fc.g, fc.b, fc.a );
	
	vbo.drawElements( GL_POINTS, indexCount );
	
	shader.end();
	
	glPopAttrib();
	ofPopStyle();
}
void CloudsVisualSystemFireworks::selfUpdate()
{
	float t = ofGetElapsedTimef();
	
	//camera
	if(bAnimateCamera)
	{
		ofVec3f eul = getCameraRef().getOrientationEuler();
		float xDamp = ofMap( abs(eul.x), 70, 90, 1, 0, true );
		
		float noiseTimeScl = .1;
		float noiseOffsetScl = 800;
		
		float panScl = -5;
		
		float noiseValX = ofSignedNoise( ofGetElapsedTimef() * noiseTimeScl + 1. ) * noiseOffsetScl;
		float noiseValY = ofSignedNoise( ofGetElapsedTimef() * noiseTimeScl ) * noiseOffsetScl;
		
		//pan and tilt with mouse
        //MA: changed ofGetWidth() to getCanvasWidth() and ofGetHeight() to getCanvasHeight()
		float pan = ofMap(GetCloudsInputX() + noiseValX, 0, getCanvasWidth(), cameraMotionScl, -cameraMotionScl);
		float tilt = ofMap(GetCloudsInputY() + noiseValY, 0, getCanvasHeight(), cameraMotionScl, -cameraMotionScl) * xDamp;

		if(abs(eul.x) < 90) getCameraRef().tilt( tilt );
		getCameraRef().pan( pan );
		
		//roll it when we move left to right
		float roll = abs(pan) * pan * panScl;
		getCameraRef().roll( -roll );
		getCameraRef().move(0, abs(roll), 0);
		
		//move it
		ofVec3f vel = getCameraRef().getLookAtDir();
		getCameraRef().move( vel * camSpeed );
		
		//use this to determine where to explode fireworks
		float targetDistance = 300;
		camTarget = vel * targetDistance + getCameraRef().getPosition();
	}
	
	
	//emitters
	ofVec3f p0, nScl;
	float nx, ny, nz;
	ofVec3f relativeDown = getCameraRef().getUpDir() * gravity.y;
	for (int i=emitters.size()-1; i>=0; i--)
	{
		emitters[i].update( t );
		
		if( emitters[i].bStarted )
		{
			emitters[i].pos += relativeDown * emitters[i].span * CubicIn(emitters[i].age);
			
			p0 = emitters[i].pos;
			nScl = p0 * .01;
			nx = ofSignedNoise(nScl.x + emitters[i].age, nScl.y, nScl.z);
			ny = ofSignedNoise(nScl.x, nScl.y + emitters[i].age, nScl.z);
			nz = ofSignedNoise(nScl.x, nScl.y, nScl.z + emitters[i].age);
			p0 += ofVec3f( nx, ny, nz ) * 10. * emitters[i].age;
			
			trailPoint( p0, emitters[i].vel, emissonRate, emitters[i].textureIndex, emitters[i].colorIndex );
		}
		
		if(emitters[i].bEnded)
		{
			emitters.erase( emitters.begin() + i );
		}
	}
	
	//particles
	bool updateIndices = false;
	
	indexCount = 0;
	for(int i=0; i<FIREWORKS_NUM_PARTICLES; i++){
		//if the age + lifespan is less then the current time we want to draw it. otherwise? it is dead to us.
		if(lifeData[i].r + lifeData[i].g / speed > t){
			indices[indexCount] = i;
			indexCount++;
			updateIndices = true;
		}
	}
	
	if(updateIndices){
		vbo.updateIndexData( &indices[0], indexCount );
	}
	
	if(	bUpdateVbo )
	{
		updateVbo();
	}
	
	if( nextFireworkExplosionTime < t )
	{
		explodeFireWorkAtRandom();
	}
	
}
// selfSetup is called when the visual system is first instantiated
// This will be called during a "loading" screen, so any big images or
// geometry should be loaded here
void CloudsVisualSystemFireworks::selfSetup()
{
	//defaults
	bAnimateCamera = true;
	minLifeSpan = .5;
	maxLifeSpan = 1.5;
	
	minExplosionTime = .75;
	maxExplosionTime = 1.25;
	
	speed = .25;
	explosionFrequencey = .1;
	emissonRate = 2;
	particleSpread = 10;
	particleSize = 10;
	spawnDistance = 250;
	
	camSpeed = .7;
	cameraMotionScl = .25;
	
	gravity.set( 0, 0, 0);
	
	minVel = .75;
	maxVel = 1.25;
	
	maxFWVel = 200;
	
	fogDistance = 800;
	fogAttenuation = 1;
	fogColor.set(0,1,0,1);
	
	bUseCircle = bUseSquare = bUseTriangle = bUseDot = true;
	
	bBurst = bOctahedron = bTetrahedron = bDodecagedron = true;
	
	startColorSaturation = endColorSaturation = fogSaturation = 1;
	
	for (int i=0; i<3; i++) {
		string key = "C" + ofToString(i) + "_birth";
		fwColors[key];
		fwSaturations[key];
		
		key = "C" + ofToString(i) + "_death";
		fwDeathColors[key];
		fwDeathSaturations[key];
	}
	
	//setupParticles
	FIREWORKS_NUM_PARTICLES = 200000;
	
	//positions = new ofVec3f[ FIREWORKS_NUM_PARTICLES ];
	//velocities = new ofVec3f[ FIREWORKS_NUM_PARTICLES ];
	//lifeData = new ofFloatColor[ FIREWORKS_NUM_PARTICLES ];
	//indices = new ofIndexType[ FIREWORKS_NUM_PARTICLES ];
	positions.resize( FIREWORKS_NUM_PARTICLES );
	velocities.resize( FIREWORKS_NUM_PARTICLES );
	lifeData.resize( FIREWORKS_NUM_PARTICLES );
	indices.resize( FIREWORKS_NUM_PARTICLES );
	
	float lifespan;
	float t = ofGetElapsedTimef();
	
	vbo.setVertexData( &positions[0], FIREWORKS_NUM_PARTICLES, GL_DYNAMIC_DRAW );
	vbo.setNormalData( &velocities[0], FIREWORKS_NUM_PARTICLES, GL_DYNAMIC_DRAW );
	vbo.setIndexData( &indices[0], FIREWORKS_NUM_PARTICLES, GL_DYNAMIC_DRAW );
	
	
	vbo.setColorData( &lifeData[0], FIREWORKS_NUM_PARTICLES, GL_DYNAMIC_DRAW );
	
	//TODO: mention to james that we might need a getCloudsData method
	colorSampleImage.loadImage( GetCloudsDataPath() + "colors/defaultColorPalette.png" );
	
	loadFileToGeometry( getVisualSystemDataPath() +  "animationTargets/dodecahedron.txt", dodecagedronPoints );
	loadFileToGeometry( getVisualSystemDataPath() +  "animationTargets/octahedron.txt", octahedronPoints );
	loadFileToGeometry( getVisualSystemDataPath() +  "animationTargets/tetrahedron.txt", tetrahedronPoints );
	loadFileToGeometry( getVisualSystemDataPath() + "animationTargets/icosahedron.txt", icosahedronPoints );
	
	//shader
	shader.load(getVisualSystemDataPath() + "shaders/base.vert", getVisualSystemDataPath() + "shaders/base.frag");
	
	shader.begin();
	shader.setUniform3f( "gravity", gravity.x, gravity.y, gravity.z );
	shader.end();
	startColor.set( .9, .95, 1.95, 1 );
	endColor.set( .6, 1.3, .2, 1 );
	
	spriteImage.loadImage(getVisualSystemDataPath() + "images/sphereNormal.png");
		
	//particle rendering
	bUpdateVbo = true;
	indexCount = 0;
	nextIndex = 0;
	numSprites = 0;
	
	nextFireworkExplosionTime = ofGetElapsedTimef() + 1;
	
	
	
	ofDisableArbTex();
	
	dotImage.loadImage(  getVisualSystemDataPath() + "images/sphereNormal.png" );
	triangleImage.loadImage(  getVisualSystemDataPath() + "images/triangle-sprite.png" );
	squareImage.loadImage(  getVisualSystemDataPath() + "images/square-sprite.png" );
	circleImage.loadImage(  getVisualSystemDataPath() + "images/circle-sprite.png" );
	
	ofEnableArbTex();
	
	getCameraRef().setPosition(0, 0, 0);
	camTarget.set( 0,0,spawnDistance);
	
    //MA: changed ofGetWidth() to getCanvasWidth() and ofGetHeight() to getCanvasHeight()
//	glowFbo0.allocate( getCanvasWidth(), getCanvasHeight(), GL_RGB );
//	glowFbo1.allocate( glowFbo0.getWidth()/2, glowFbo0.getHeight()/2, GL_RGB );;
//	glowFbo2.allocate( glowFbo1.getWidth()/2, glowFbo1.getHeight()/2, GL_RGB );;
//	glowFbo3.allocate( glowFbo2.getWidth()/2, glowFbo2.getHeight()/2, GL_RGB );;
//	glowFbo4.allocate( glowFbo3.getWidth()/2, glowFbo3.getHeight()/2, GL_RGB );;
//	glowFbo5.allocate( glowFbo4.getWidth()/2, glowFbo4.getHeight()/2, GL_RGB );;
//	glowFbo6.allocate( glowFbo5.getWidth()/2, glowFbo5.getHeight()/2, GL_RGB );;
	
	glowShader.load(getVisualSystemDataPath() + "shaders/post");
}
void Dimentions::selfDraw(){
    
    if (!bDebug){
        ofEnableAlphaBlending();
        
        ofPushMatrix();
        ofPushStyle();
        materials["MATERIAL 1"]->begin();
        
        //  Labels
        //
        if(categoriesTintColor.a > 0.0 ){
            for(int i = 0; i < categories.size(); i++){
                ofSetColor(categoriesTintColor);
                drawBrakets(categories[i], 15, 10);
                
                categories[i].draw(bDebug);
            }
        }
        
        for (int i = 0; i < booksWithTags.size(); i++) {
            drawLabel( *booksWithTags[i], booksWithTags[i]->text );
        }
        
        if(categoriesNodesTintColor.a > 0.0){
            for(int i = 0; i < categories.size(); i++){
                for(int j = 0; j < categories[i].nodes.size(); j++){
                    ofPushMatrix();
                    ofTranslate(categories[i].nodes[j]->x,
                                categories[i].nodes[j]->y,
                                categories[i].nodes[j]->z);
                    ofSetColor(categoriesNodesTintColor);
                    float scale = 0.4;
                    ofScale(scale,scale,scale);
                    //orientBillBoard();
                    ofRectangle box = font.getStringBoundingBox(categories[i].nodesText[j], 0, 0);
                    font.drawStringAsShapes(categories[i].nodesText[j], -box.width*0.5,0);
                    ofPopMatrix();
                }
            }
        }
    
        
        {
            ofSetColor(255);
            ofDisableArbTex();
            glDepthMask(GL_FALSE);
            glEnable(GL_NORMALIZE);
            ofEnablePointSprites();
            
            spriteShader.begin();
            spriteTexture.bind();
            
            spriteShader.setUniformTexture("tex", spriteTexture, 0);
            spriteShader.setUniform1f("nearClip", getCameraRef().getNearClip());
            spriteShader.setUniform1f("farClip", getCameraRef().getFarClip());
            spriteShader.setUniform1f("size",spriteSize);
            spriteShader.setUniform1f("minPointSize", 1.0);//spriteSizeMin);
            spriteShader.setUniform1f("maxPointSize", spriteSizeMax);
            spriteShader.setUniform1f("focusDistance", spriteFocusDistance);
            spriteShader.setUniform1f("focusAperture", spriteFocusAperture*0.01);
            
            spriteVBO.draw(GL_POINTS, 0, TOTAL_OF_BOOKS );
            
            spriteTexture.unbind();
            spriteShader.end();
            
            ofDisablePointSprites();
            glDisable(GL_NORMALIZE);
            glDepthMask(GL_TRUE);
            ofEnableArbTex();
        }

        materials["MATERIAL 1"]->end();
        ofPopStyle();
        ofPopMatrix();
    }
}
void _C::generateFlythrough(){
    //reset cam path.
    cloudsPathCam.clear();

    jtn::TreeNode::clearPathFlags();
    
    // find someone in the youngest possible generation of terminal
    // therefore insuring a long path between a terminal and a root parent.
    
    int youngestGen = 0;
    jtn::TreeNode *thisNode = NULL;
    vector<jtn::TreeNode*>::iterator nit = jtn::TreeNode::all.begin();
    for(;nit!=jtn::TreeNode::all.end();nit++){
        if( (*nit)->isTerminal() ){
            if((*nit)->generation > youngestGen) {
                youngestGen = (*nit)->generation;
                thisNode = (*nit);
            }
        }
    }
    
    
    deque<ofVec3f> pts; //collecting points as i go, so i can add them backwards, later.
    
    ofVec3f firstPoint = *thisNode; // make a copy of the first point for lookAt() later.
    
    float camPosOffset = 1.5;
    
	//this node is null??
    while(thisNode != NULL && thisNode->parent != NULL  ){

        thisNode->isPartOfCamPath = true;
        cloudsPathCam.addPositionControlVertex( *thisNode);
        //cloudsPathCam.addTargetControlVertex(ofVec3f());
        //cloudsPathCam.addUpControlVertex(ofVec3f(1,0,0));
        pts.push_back( *thisNode );

        //traverse up the parent
        
        if( thisNode->parent != NULL ){
            thisNode = thisNode->parent;
        }
		else{
            break;
        }
    }
    
    // then add the same points in reverse, to scrub back and forth
    // rather than seeing where the loop wraps around.
    
    deque<ofVec3f>::reverse_iterator pit = pts.rbegin();
    for(; pit != pts.rend(); pit++){
        cloudsPathCam.addPositionControlVertex( *pit);
        //cloudsPathCam.addTargetControlVertex(ofVec3f());
        //cloudsPathCam.addUpControlVertex(ofVec3f(1,0,0));
    }

    // orient cam path to look inward,
    // so we always start out seeing something nefull
    ofCamera& cam = getCameraRef();
    cam.lookAt( -firstPoint );
}
void CloudsVisualSystemCubeCraft::drawCubeCraft()
{
	ofPushStyle();
	glPushAttrib(GL_ALL_ATTRIB_BITS);
	
	glEnable( GL_DEPTH_TEST );
	ofDisableAlphaBlending();
	
	glEnable(GL_CULL_FACE);
	glCullFace(cullDirection);
	
	float scale = 30.;
	ofPushMatrix();
	ofScale(scale,scale,scale);
	ofVec3f cp = getCameraRef().getPosition() / scale;
	ofVec3f cloudVel = noiseDirection * noiseTime * cloudSpeed;
	
	mineCraftGroundShader.begin();

	mineCraftGroundShader.setUniform1f("maxHeight", 10);
	mineCraftGroundShader.setUniform1f("cameraCutoffDistance", 3);
	
	mineCraftGroundShader.setUniform1f("specExpo", specExpo);
	mineCraftGroundShader.setUniform1f("specScale", specScale);

	fc = fogColor;
	mineCraftGroundShader.setUniform4f("fogColor", fc.r, fc.g, fc.b, fc.a );
	mineCraftGroundShader.setUniform1f("fogDist", fogDist );
	mineCraftGroundShader.setUniform1f("fogExpo", fogExpo );

	mineCraftGroundShader.setUniform1f("useFog", bUseFog);

	fc = groundColor;
	mineCraftGroundShader.setUniform4f("groundColor", fc.r, fc.g, fc.b, fc.a );

	fc = undergroundColor;
	mineCraftGroundShader.setUniform4f("undergroundColor", fc.r, fc.g, fc.b, fc.a );

	fc = cloudShadowColor;
	mineCraftGroundShader.setUniform4f("cloudShadowColor", fc.r, fc.g, fc.b, fc.a );

	//ofVec3f cp = getCameraRef().getPosition() / scale;
	mineCraftGroundShader.setUniform3f("cameraPos", cp.x, cp.y, cp.z );
	
	mineCraftGroundShader.setUniform1f("cloudThreshold", cloudThreshold);
	mineCraftGroundShader.setUniform1f("cloudShadow", 1. - cloudShadow);
	mineCraftGroundShader.setUniform1f("groundDrama", groundDrama);

	mineCraftGroundShader.setUniform3f("noiseOffset", cloudVel.x, cloudVel.y, cloudVel.z);
	mineCraftGroundShader.setUniform3f("cameraOffset", -cameraOffset.x, 0., -cameraOffset.z);
	
	mineCraftGroundShader.setUniform3f("cubeScale", 1,1,1 );

	voxelVbo.draw(GL_TRIANGLES, 0, voxelIndexCount );

	mineCraftGroundShader.end();

	
	//CLOUDS
	mineCraftCloudsShader.begin();
	mineCraftCloudsShader.setUniform1f("cameraCutoffDistance", 3);
	
	mineCraftCloudsShader.setUniform1f("specExpo", specExpo);
	mineCraftCloudsShader.setUniform1f("specScale", specScale);
	
	fc = fogColor;
	mineCraftCloudsShader.setUniform4f("fogColor", fc.r, fc.g, fc.b, fc.a );
	mineCraftCloudsShader.setUniform1f("fogDist", fogDist );
	mineCraftCloudsShader.setUniform1f("fogExpo", fogExpo );
	
	mineCraftCloudsShader.setUniform1f("useFog", bUseFog);
	
	fc = fillColor2;
	mineCraftCloudsShader.setUniform4f("specularColor", fc.r, fc.g, fc.b, fc.a );
	
	fc = groundColor;
	mineCraftCloudsShader.setUniform4f("groundColor", fc.r, fc.g, fc.b, fc.a );
	
	fc = undergroundColor;
	mineCraftCloudsShader.setUniform4f("undergroundColor", fc.r, fc.g, fc.b, fc.a );
	
	
	mineCraftCloudsShader.setUniform1f("cloudHeight", cloudHeight);
	mineCraftCloudsShader.setUniform1f("cloudThickness", cloudThickness);

	mineCraftCloudsShader.setUniform3f("cameraPos", cp.x, cp.y, cp.z );
	
	mineCraftCloudsShader.setUniform1f("cloudThreshold", cloudThreshold);
	mineCraftCloudsShader.setUniform1f("cloudShadow", 1. - cloudShadow);
	mineCraftCloudsShader.setUniform1f("groundDrama", groundDrama);
	
	mineCraftCloudsShader.setUniform3f("noiseOffset", cloudVel.x, cloudVel.y, cloudVel.z);
	mineCraftCloudsShader.setUniform3f("cameraOffset", -cameraOffset.x, 0., -cameraOffset.z);
	
	voxelVbo.draw(GL_TRIANGLES, 0, voxelIndexCount );
	
	mineCraftCloudsShader.end();
	
	ofPopMatrix();
	
	glPopAttrib();
	ofPopStyle();
}
void CloudsVisualSystemCubeCraft::drawVoxelGrid()
{
	ofPushStyle();
	glPushAttrib(GL_ALL_ATTRIB_BITS);
	glEnable( GL_DEPTH_TEST );
	
	ofDisableAlphaBlending();
	
	glEnable(GL_CULL_FACE);
	glCullFace(cullDirection);
	
	float scale = 30.;
	ofPushMatrix();
	ofScale(scale,scale,scale);
	
	voxelShader.begin();
	voxelShader.setUniform1i("scaleCube", bScaleCubes);
	voxelShader.setUniform1f("cubeScale", cubeScale);
	voxelShader.setUniform1f("drawCenters", bFillCubes);
	voxelShader.setUniform1f("noiseCutoff", noiseThreshold);
	voxelShader.setUniform1f("cameraCutoffDistance", 3);
	voxelShader.setUniform1f("edgeThreshold", 1. - edgeWidth);
	
	voxelShader.setUniform1f("specExpo", specExpo);
	voxelShader.setUniform1f("specScale", specScale);
	
	fc = fogColor;
	voxelShader.setUniform4f("fogColor", fc.r, fc.g, fc.g, fc.a );
	voxelShader.setUniform1f("fogDist", fogDist );
	voxelShader.setUniform1f("fogExpo", fogExpo );
	
	voxelShader.setUniform1f("useFog", bUseFog);
	
	voxelShader.setUniform1f("edgeSmoothing", edgeSmoothing );
	
	fc = edgeColor;
	voxelShader.setUniform4f("edgeColor", fc.r, fc.g, fc.b, fc.a );
	fc = fillColor;
	voxelShader.setUniform4f("fillColor", fc.r, fc.g, fc.b, fc.a );
	fc = fillColor2;
	voxelShader.setUniform4f("specularColor", fc.r, fc.g, fc.b, fc.a );
	
	voxelShader.setUniform1f("dimX", dimX );
	voxelShader.setUniform1f("dimY", dimY );
	voxelShader.setUniform1f("dimZ", dimZ );
	
	voxelShader.setUniform1f("noiseScale", noiseScale);
	voxelShader.setUniform3f("noiseOffset", noiseDirection.x * noiseTime, noiseDirection.y * noiseTime, noiseDirection.z * noiseTime);
	
	ofVec3f cp = getCameraRef().getPosition() / scale;
	voxelShader.setUniform3f("cameraPos", cp.x, cp.y, cp.z );
	
	voxelVbo.draw(GL_TRIANGLES, 0, voxelIndexCount );
	
	voxelShader.end();
	
	ofPopMatrix();
	
	glPopAttrib();
	ofPopStyle();
}
void CloudsVisualSystem3DModelLoader::selfGuiEvent(ofxUIEventArgs &e)
{
//	cout << "e.getName(): " << e.getName() << endl;
	string name = e.widget->getName();
	int kind = e.widget->getKind();
	
//	if( name == "smooth model" )
//	{
//		bSmoothModel = e.getToggle()->getValue();
//		if( bSmoothModel ){
//			//smoothMesh( modelMesh, modelMesh );
//		}else{
//			//facetMesh( modelMesh, modelMesh );
//		}
//	}
	if(name =="minTilt" || name == "maxTilt")
	{
		if(perspCam.getMaxTilt() - perspCam.getMinTilt() < 10)
		{
			perspCam.getMinTilt() = perspCam.getMaxTilt() - 10;
		}
		perspCam.setToStartPosition( boundCenter );
	}
	
	else if( name == "reset transforms")
	{
		positionOffset.set(0,0,0);
		globalRotation.set(0,0,0);
		globalRotationVelocity.set(0,0,0);
	}
	
	else if(name == "arrowHeight" || name == "arrowRadius" || name == "arrowPointHeight" )
	{
		resizeTheArrowMesh( arrowRadius, arrowHeight, arrowPointHeight );
	}
	
	else if( e.widget->getName() == "c1"){
		ofxUIImageSampler* sampler = (ofxUIImageSampler *) e.widget;
		modelColor = sampler->getColor();
	}
	
	else if( e.widget->getName() == "gridColor"){
		ofxUIImageSampler* sampler = (ofxUIImageSampler *) e.widget;
		gridColor = sampler->getColor();
	}
	
	else if( e.widget->getName() == "gridMajorColor"){
		ofxUIImageSampler* sampler = (ofxUIImageSampler *) e.widget;
		gridMajorColor = sampler->getColor();
	}
	
	else if( kind == OFX_UI_WIDGET_TOGGLE)
	{
		
		if (name == "loop")
		{
			bUseDuration = e.getToggle()->getValue();
		}
		
		if( e.getToggle()->getValue() )
		{
			string parent = e.getToggle()->getParent()->getName();
			cout << "**** " << name << " TRIGGERED TOGGLE " << parent << endl;
			
			if (parent == "shaders")
			{
				//switch to this active shader from a shader map
				if(shaderMap.find( name ) != shaderMap.end() )
				{
					cout << parent << " : " << name << " : " << shaderMap[ name ] << endl;
					activeShader = shaderMap[ name ];
				}
			}
			
			else if(parent == "model files")
			{
				//load the model from the selected file
				for (int i=0; i<objFiles.size(); i++)
				{
					if(objFiles[i] == name )
					{
						cout << "loading model: " << name << endl;
						loadModel(name);
						//loadModel( "models/" + name, bSmoothModel );
						//loadModel( getVisualSystemDataPath(true) + "models/" + name, bSmoothModel );
					}
				}
			}
			
			
			else if(parent == "camera paths")
			{
				//load the model from the selected file
				for (int i=0; i<cameraPaths.size(); i++)
				{
					if(cameraPaths[i] == name )
					{
						cout << "loading camera path: " << name << endl;
//						pathCamera.loadPathFromFile(getVisualSystemDataPath(false) + "cameraPaths/" + name );
						pathCamera.loadPathFromFile(getVisualSystemDataPath() + "cameraPaths/" + name );
					}
				}
			}
			
			else if(parent == "camera views")
			{
				cout << "set current camera to view: " << name << endl;
				singleViewName = name;
				
				leftCam.disableMouseInput();
				frontCam.disableMouseInput();
				planCam.disableMouseInput();
				perspCam.disableMouseInput();
				bLeftCamIsActive = bFrontCamIsActive = bPlanCamIsActive = bPerspCamIsActive = false;
				
				bDoNotScaleModel = false;
				
				if(name == "left view")
				{
					currentSingleCam = &leftCam;
					leftCam.enableMouseInput();
					bFourView = false;
					
					bLeftCamIsActive = true;
				}
				else if(name == "front view")
				{
					currentSingleCam = &frontCam;
					frontCam.enableMouseInput();
					bFourView = false;
					
					bFrontCamIsActive = true;
				}
				else if(name == "persp view")
				{
					currentSingleCam = &getCameraRef();
					perspCam.enableMouseInput();
					bFourView = false;
					
					bPerspCamIsActive = true;
				}
				else if(name == "plan view")
				{
					currentSingleCam = &planCam;
					planCam.enableMouseInput();
					bFourView = false;
					
					bPlanCamIsActive = true;
				}
				
				else if( name == "path camera")
				{
					currentSingleCam = &pathCamera;
					bDoNotScaleModel = true;
				}
				
				else if( name == "four view")
				{
					bFourView = true;
					
					perspCam.enableMouseInput();
					
					leftCam.enableMouseInput();
					
					frontCam.enableMouseInput();
					
					planCam.enableMouseInput();
					
					bLeftCamIsActive = bFrontCamIsActive = bPlanCamIsActive = bPerspCamIsActive = true;
				}
			}
		}
	}
}
void CloudsVisualSystem3DModelLoader::drawSceneGeometry( ofCamera* cam)
{
	
	//rotation velocity
	float t = ofGetElapsedTimef();
	accumulatedRotation += globalRotationVelocity * 1. / ofGetFrameRate();
	
	//draw infinite grid by positioning it infront of the camera
	if(bDrawGrid)
	{
		//	ofVec3f camPos;
		//	camPos = cam->getPosition();
		//	camPos += cam->getUpDir().cross(cam->getSideDir()).normalize() * gridDim * gridScale * .5;
		
		ofSetColor(255,255, 255, 150 );// make this an adjustable color in th GUI
		
		gridShader.begin();
		gridShader.setUniform1f("halfGridDim", gridDim * .5 );
		gridShader.setUniform1f("falloffDist", fogFalloffDistance );
		gridShader.setUniform1f("falloffExpo", fogFalloffExpo );
		gridShader.setUniform1f("falloffScl", fogFalloffScale );
		gridShader.setUniform1f("alphaScale", gridAlphaScale );
		
		//draw  minor grid
		ofPushMatrix();
		ofScale( gridScale, gridScale, gridScale );
		
		ofSetLineWidth( gridLineWidth );
		ofSetColor( gridColor.r*gridBrightness, gridColor.g*gridBrightness, gridColor.b*gridBrightness, gridAlpha );
		grid.draw(GL_LINES, 0, numGridVertices );
		
		ofPopMatrix();
		
		//draw  major grid
		ofPushMatrix();
		int gms = gridMajorScale;
		ofTranslate( getCameraRef().getLookAtDir() * -gridLineWidth / gridScale );
		ofScale( gridScale * gms,gridScale * gms, gridScale * gms );
		
		ofSetLineWidth( majorGridLineWidth );
		ofSetColor( gridMajorColor.r*gridMajorBrightness, gridMajorColor.g*gridMajorBrightness, gridMajorColor.b*gridMajorBrightness, gridMajorAlpha );
		grid.draw(GL_LINES, 0, numGridVertices );
		
		ofPopMatrix();
		
		gridShader.end();
	}
	
	//draw wireframe view cameras to the scene
	if(bDrawCameras)
	{
		drawMultipleViewCameras( cameraLineScale, cam );
	}
	
	if(bDrawArrows)
	{
		//draw arrows at model's min bound
		ofPushMatrix();
		ofTranslate( minBound * modelTransform.getGlobalTransformMatrix() );
		ofMultMatrix( modelTransform.getGlobalOrientation() );
		
		ofSetColor(0, 255, 0);
		ofPushMatrix();
		ofScale( arrowScale.x, arrowScale.y, arrowScale.z );
		arrowMesh.draw();
		ofPopMatrix();
		
		ofSetColor(255, 0, 0);
		ofPushMatrix();
		ofRotate(90, 1, 0, 0);
		ofScale( arrowScale.x, arrowScale.y, arrowScale.z );
		arrowMesh.draw();
		ofPopMatrix();
		
		ofSetColor(0, 0, 255);
		ofPushMatrix();
		ofRotate(90, 1, 0, 0);
		ofRotate(90, 0, 0, -1);
		ofScale( arrowScale.x, arrowScale.y, arrowScale.z );
		arrowMesh.draw();
		ofPopMatrix();
		
		ofPopMatrix();
	}
	
	
	//draw our model
	ofPushMatrix();
	
//	ofTranslate(-boundCenter);
	
	ofMultMatrix( modelTransform.getGlobalTransformMatrix() );
	
	if(currentSingleCam != &pathCamera)
	{
		ofTranslate( positionOffset - boundCenter );
		ofRotateX( globalRotation.x + accumulatedRotation.x );
		ofRotateY( globalRotation.y + accumulatedRotation.y );
		ofRotateZ( globalRotation.z + accumulatedRotation.z );
	}
	
	//draw bounding box
	if(bDrawBoundingBox)
	{
		ofSetColor(255, 255, 255, 255);
		drawBoundingBox();
	}
	
	if(bDrawCameraPath)
	{
		ofSetLineWidth(majorGridLineWidth);
		simpleShader.begin();
		pathCamera.drawPaths();
		simpleShader.end();
	}
	
	ofSetColor(modelColor);
	if(activeShader != NULL )
	{
		
		activeShader->begin();
		activeShader->setUniform1f( "discardThreshold", discardThreshold );
		activeShader->setUniform1f( "specularExpo", specularExpo );
		activeShader->setUniform1f( "specularScale", specularScale );
		activeShader->setUniform1f("falloffDist", fogFalloffDistance );
		activeShader->setUniform1f("falloffExpo", fogFalloffExpo );
		activeShader->setUniform1f("falloffScl", fogFalloffScale );
		
		if(activeShader == &XRayShader){
			/*
			 sfactor
			 Specifies how the red, green, blue, and alpha source blending factors are computed. The following symbolic constants are accepted: GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR, GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA, and GL_SRC_ALPHA_SATURATE. The initial value is GL_ONE.
			 
			 dfactor
			 Specifies how the red, green, blue, and alpha destination blending factors are computed. The following symbolic constants are accepted: GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA. GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR, GL_CONSTANT_ALPHA, and GL_ONE_MINUS_CONSTANT_ALPHA. The initial value is GL_ZERO.
			 */
			
			//GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
			glDisable( GL_DEPTH_TEST );
			glBlendFunc(GL_ONE, GL_ONE);
			
//			modelMesh.draw();
			bWireframe?	modelMesh.drawWireframe() : modelMesh.draw();
			
			ofBlendMode( OF_BLENDMODE_ADD );
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		}
		else{
			if(bWireframe)	ofSetLineWidth( wireframeLinewidth );
			bWireframe?	modelMesh.drawWireframe() : modelMesh.draw();
		}
		
		activeShader->end();
	}
	
	ofPopMatrix();
}