#include "ofApp.h"
///////////////////////////////////////////////////
///////////////////////////////////////////////
///////////////////////////////////////////
///////////////////////////////////////
///////////////////////////////////
//
//
// ADVANCED 3D EXAMPLE
// ofNode3d, ofCamera, ofEasyCam
//
//
///////////////////////////////////
///////////////////////////////////////
///////////////////////////////////////////
///////////////////////////////////////////////
///////////////////////////////////////////////////
//
// SUGGESTED EXERCISES
//
// 0. Run and understand the example
//
// 1. Change number of particles in the swarm.
// 2. Change the dynamic properties of the swarm (speed, orbit radius)
// 3. Change the near and far clipping planes of camEasyCam
//
// 4. Add another camera to the existing 4.
// Have all parts of the example working with all 5 cameras.
//
// 6. Create your own custom node class and add an instance of it
// to the scene.
//
// 7. Understand how the 'frustrum preview' works
//
///////////////////////////////////////////////////
//--------------------------------------------------------------
void ofApp::setup(){
ofSetVerticalSync(true);
ofBackground(70, 70, 70);
ofEnableSmoothing();
ofEnableDepthTest();
/////////////////////
// SETUP CAMERAS
/////////////////////
//
iMainCamera = 0;
bCamParent = false;
// user camera
camEasyCam.setTarget(nodeSwarm);
camEasyCam.setDistance(100);
cameras[0] = &camEasyCam;
// front
camFront.scale = 20;
cameras[1] = &camFront;
// top
camTop.scale = 20;
camTop.tilt(-90);
cameras[2] = &camTop;
// left
camLeft.scale = 20;
camLeft.pan(-90);
cameras[3] = &camLeft;
/////////////////////
// DEFINE VIEWPORTS
/////////////////////
//
setupViewports();
//
/////////////////////
/////////////////////
// SETUP SWARM
/////////////////////
//
nodeSwarm.init(100, 50, 20);
//
/////////////////////
}
//--------------------------------------------------------------
void ofApp::setupViewports()
{
//call here whenever we resize the window
/////////////////////
// DEFINE VIEWPORTS
/////////////////////
//
float xOffset = ofGetWidth()/3;
float yOffset = ofGetHeight()/N_CAMERAS;
viewMain.x = xOffset;
viewMain.y = 0;
viewMain.width = xOffset * 2;
viewMain.height = ofGetHeight();
for (int i=0; i<N_CAMERAS; i++) {
viewGrid[i].x = 0;
viewGrid[i].y = yOffset * i;
viewGrid[i].width = xOffset;
viewGrid[i].height = yOffset;
}
//
/////////////////////
}
//--------------------------------------------------------------
void ofApp::update(){
}
//--------------------------------------------------------------
void ofApp::draw(){
ofDrawBitmapString("test", 10, 10);
//////////////////////////
// BACKGROUND HIGHLIGHT
//////////////////////////
//
ofDisableDepthTest();
ofPushStyle();
ofSetColor(100, 100, 100);
ofDrawRectangle(viewGrid[iMainCamera]);
ofPopStyle();
ofEnableDepthTest();
//
//////////////////////////
//////////////////////////
// DRAW ALL VIEWPORTS
//////////////////////////
//
//draw main viewport
cameras[iMainCamera]->begin(viewMain);
drawScene(iMainCamera);
//calculate mouse ray whilst this camera is active
updateMouseRay();
cameras[iMainCamera]->end();
//draw side viewports
for (int i=0; i<N_CAMERAS; i++)
{
cameras[i]->begin(viewGrid[i]);
drawScene(i);
cameras[i]->end();
}
//
//////////////////////////
//////////////////////////
// DRAW STUFF ON TOP
//////////////////////////
//
ofPushStyle();
glDepthFunc(GL_ALWAYS); // draw on top of everything
//draw some labels
ofSetColor(255, 255, 255);
ofDrawBitmapString("Press keys 1-4 to select a camera for main view", viewMain.x + 20, 30);
ofDrawBitmapString("Camera selected: " + ofToString(iMainCamera+1), viewMain.x + 20, 50);
ofDrawBitmapString("Press 'f' to toggle fullscreen", viewMain.x + 20, 70);
ofDrawBitmapString("Press 'p' to toggle parents on OrthoCamera's", viewMain.x + 20, 90);
ofDrawBitmapString("EasyCam", viewGrid[0].x + 20, viewGrid[0].y + 30);
ofDrawBitmapString("Front", viewGrid[1].x + 20, viewGrid[1].y + 30);
ofDrawBitmapString("Top", viewGrid[2].x + 20, viewGrid[2].y + 30);
ofDrawBitmapString("Left", viewGrid[3].x + 20, viewGrid[3].y + 30);
//draw outlines on views
ofSetLineWidth(5);
ofNoFill();
ofSetColor(255, 255, 255);
//
for (int i=0; i<N_CAMERAS; i++)
ofDrawRectangle(viewGrid[i]);
//
ofDrawRectangle(viewMain);
glDepthFunc(GL_LESS);
ofPopStyle();
//
//////////////////////////
}
void ofApp::drawScene(int iCameraDraw){
nodeSwarm.draw();
nodeGrid.draw();
//////////////////////////////////
// DRAW EASYCAM FRUSTUM PREVIEW
//////////////////////////////////
//
// This code draws our camera in
// the scene (reddy/pink lines)
//
// The pyramid-like shape defined
// by the cameras view is called
// a 'frustum'.
//
// Often we refer to the volume
// which can be seen by the
// camera as 'the view frustum'.
//
//let's not draw the camera
//if we're looking through it
if (iCameraDraw != 0)
{
ofPushStyle();
//in 'camera space' this frustum
//is defined by a box with bounds
//-1->1 in each axis
//
//to convert from camera to world
//space, we multiply by the inverse
//matrix of the camera
//
//by applying this transformation
//our box in camera space is
//transformed into a frustum in
//world space.
//the camera's matricies are dependant on
//the aspect ratio of the viewport
//so we must send the viewport if it's not
//the same as fullscreen
//
//watch the aspect ratio of preview camera
glm::mat4 inverseCameraMatrix = glm::inverse(camEasyCam.getModelViewProjectionMatrix( (iMainCamera == 0 ? viewMain : viewGrid[0]) ));
// By default, we can say
// 'we are drawing in world space'
//
// The camera matrix performs
// world->camera
//
// The inverse camera matrix performs
// camera->world
//
// Our box is in camera space, if we
// want to draw that into world space
// we have to apply the camera->world
// transformation.
//
ofPushMatrix();
ofMultMatrix(inverseCameraMatrix);
ofSetColor(255, 100, 100);
//////////////////////
// DRAW WIREFRAME BOX
//
// xy plane at z=-1 in camera sapce
// (small rectangle at camera position)
//
GLfloat vertices1[] = {
-1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f
};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices1);
glDrawArrays(GL_LINE_LOOP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
// xy plane at z=1 in camera space
// (generally invisible because so far away)
//
GLfloat vertices2[] = {
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices2);
glDrawArrays(GL_LINE_LOOP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
// connecting lines between above 2 planes
// (these are the long lines)
//
GLfloat vertices3[] = {
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f
};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices3);
glDrawArrays(GL_LINE_LOOP, 0, 8);
glDisableClientState(GL_VERTEX_ARRAY);
//
//////////////////////
ofPopStyle();
ofPopMatrix();
}
//
//////////////////////////////////
//////////////////////////////////
// DRAW RAY
//////////////////////////////////
//
//draw if we've got camEasyCam selected
//and we're not looking through it
if (iMainCamera == 0 && iCameraDraw != 0)
{
ofPushStyle();
ofSetColor(100, 100, 255);
ofDrawLine(ray[0], ray[1]);
ofPopStyle();
}
//
//////////////////////////////////
}
//--------------------------------------------------------------
void ofApp::updateMouseRay()
{
//define ray in screen space
ray[0] = glm::vec3(ofGetMouseX(), ofGetMouseY(), -1);
ray[1] = glm::vec3(ofGetMouseX(), ofGetMouseY(), 1);
//transform ray into world space
ray[0] = cameras[iMainCamera]->screenToWorld(ray[0], viewMain);
ray[1] = cameras[iMainCamera]->screenToWorld(ray[1], viewMain);
}
//--------------------------------------------------------------
void ofApp::keyPressed(int key){
if (key >= '1' && key <= '4')
iMainCamera = key - '1';
if (key == 'f')
ofToggleFullscreen();
if (key == 'p')
{
if (bCamParent)
{
camFront.clearParent();
camTop.clearParent();
camLeft.clearParent();
bCamParent = false;
} else {
camFront.setParent(nodeSwarm.light);
camTop.setParent(nodeSwarm.light);
camLeft.setParent(nodeSwarm.light);
bCamParent = true;
}
}
}
//--------------------------------------------------------------
void ofApp::keyReleased(int key){
}
//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){
setupViewports();
}
//--------------------------------------------------------------
void ofApp::touchDown(int x, int y, int id){
}
//--------------------------------------------------------------
void ofApp::touchMoved(int x, int y, int id){
}
//--------------------------------------------------------------
void ofApp::touchUp(int x, int y, int id){
}
//--------------------------------------------------------------
void ofApp::touchDoubleTap(int x, int y, int id){
}
//--------------------------------------------------------------
void ofApp::touchCancelled(int x, int y, int id){
}
//--------------------------------------------------------------
void ofApp::swipe(ofxAndroidSwipeDir swipeDir, int id){
}
//--------------------------------------------------------------
void ofApp::pause(){
}
//--------------------------------------------------------------
void ofApp::stop(){
}
//--------------------------------------------------------------
void ofApp::resume(){
}
//--------------------------------------------------------------
void ofApp::reloadTextures(){
}
//--------------------------------------------------------------
bool ofApp::backPressed(){
return false;
}
//--------------------------------------------------------------
void ofApp::okPressed(){
}
//--------------------------------------------------------------
void ofApp::cancelPressed(){
}
Comments