#include "testApp.h" //-------------------------------------------------------------- //units ~ 10cm // /* Can use a floating point image or array to accumulate the screen and generate averaged background? Is this too much work for every frame? Should it be put in a seperate thread? */ void testApp::setup(){ printf("setup: %ix%i on screen %ix%i\n",ofGetWidth(),ofGetHeight(),ofGetScreenWidth(),ofGetScreenHeight()); int windowMode = ofGetWindowMode(); if(windowMode == OF_FULLSCREEN){ this->windowWidth = ofGetScreenWidth(); this->windowHeight = ofGetScreenHeight(); } else if(windowMode == OF_WINDOW){ this->windowWidth = ofGetWidth(); this->windowHeight = ofGetHeight(); } bLearnBakground = true; cam_angle=0; threshold = 80; loadSettings("settings.xml"); vidGrabber.setVerbose(true); if (vidGrabber.initGrabber(640,480)) { hasCamera=true; useCamera=true; } else { hasCamera=false; useCamera=false; vidPlayer.loadMovie("camoutput.mov"); //footage/ camera needs to be the same res as opencv planes and output vidPlayer.setLoopState(OF_LOOP_NORMAL); vidPlayer.play(); } /* accumImg.allocate(640,480); bgImg.allocate(640,480); bgImg.setUseTexture(true); grayImage.allocate(640,480); grayBg.allocate(640,480); */ colorImg.allocate(640,480); colorImg.setUseTexture(true); currentFrame.allocate(CAM_WIDTH_FG, CAM_HEIGHT_FG); background.allocate(CAM_WIDTH_FG, CAM_HEIGHT_FG); background.setUseTexture(true); grayFrame.allocate(CAM_WIDTH_FG, CAM_HEIGHT_FG); grayBg.allocate(CAM_WIDTH_FG, CAM_HEIGHT_FG); grayDiff.allocate(CAM_WIDTH_FG, CAM_HEIGHT_FG); mogoutput.allocate(CAM_WIDTH_FG, CAM_HEIGHT_FG); learningRate = 0.01f; bFirstFrame=true; diffchannel=chan_V; hsvback = cvCreateImage(cvGetSize(currentFrame.getCvImage()), currentFrame.getCvImage()->depth, currentFrame.getCvImage()->nChannels); //backchan = cvCreateImage(cvGetSize(currentFrame.getCvImage()), 8, 1); removeShadows=false; shadowThreshold=10; //////////////////////////// blobsManager.normalizePercentage = 0.7; blobsManager.giveLowestPossibleIDs = false; blobsManager.maxUndetectedTime = 500; blobsManager.minDetectedTime = 500; blobsManager.debugDrawCandidates = true; ofVec3f centre=ofVec3f(windowWidth/2,0,0); ofVec3f normal=ofVec3f(0,0,-1); ray=ofRay(); plane=ofPlane(centre,normal); plane.color=ofColor(255,255,255); projector=ofProjector(2.0f, ofVec2f(0.0f, 0.0f),windowWidth,windowHeight); //1.535f projector.setPosition(windowWidth/2,windowHeight/2,-windowWidth); projector.lookAt(ofVec3f(windowWidth/2,windowHeight/2,0),ofVec3f(0, -1, 0)); cam=ofCamera(); cam.setPosition(windowWidth/2,windowHeight/2,-windowWidth); cam.lookAt(ofVec3f(windowWidth/2,windowHeight/2,0),ofVec3f(0, -1, 0)); cam.setFov(41.1); //39.85); //53.13); cam.cacheMatrices(); //stop error messages testpts=new ofVec3f[4]; bounds=new ofPlane[4]; //trapDoor=trapdoor(screen2plane(ofVec2f(windowWidth,0)),screen2plane(ofVec2f(windowWidth,windowHeight)),35); trapdoorSize=35; trapdoorSlotSize=50; trapdoorTime=10.0; //time per trapdoor; mode=PLAY; drawStats=false; bgnum=1000; firstframe=true; light.setPosition(windowWidth,0,windowHeight); light.enable(); drawingborder=false; billboards=new ofImage[4]; billboards[0].loadImage("GUI_title.png"); billboards[1].loadImage("GUI_nzsLogo.png"); billboards[2].loadImage("GUI_objective.png"); billboards[3].loadImage("GUI_gotya.png"); for (int i=0;i<4;i++) { billboards[i].setAnchorPercent(0.5,0.5); } scaleFactor=ofVec2f(windowWidth/1280.0f,windowHeight/768.0f); gameState=TITLES; //PLAYING; // segTimes[TITLES]=4.0; segTimes[CREDIT]=2.5; segTimes[EXPLAIN]=5.0; segTimes[PLAYING]=60.0; segTimes[GOTCHA]=4.0; gameStart=ofGetElapsedTimef(); sounds=new ofSoundPlayer[1]; sounds[0].loadSound("arp5.mp3"); //game start doorsounds=new ofSoundPlayer[4]; doorsounds[0].loadSound("creeky door short1.wav"); doorsounds[1].loadSound("creeky door short2.wav"); doorsounds[2].loadSound("creeky door short3.wav"); doorsounds[3].loadSound("voice falling down hole.wav"); cam.begin(); cam.end(); updatePlane(); } ofVec2f testApp::screen2plane(ofVec2f screenpos){ ofVec3f p; ray=projector.castPixel(screenpos.x,screenpos.y); bool hit = plane.intersect(ray,p); return ofVec2f(p.x,pow(pow(p.y,2)+pow(p.z,2),0.5f)); } ofVec3f testApp::plane2world(ofVec2f planepos){ return ofVec3f(planepos.x,planepos.y,0); } bool testApp::rectsCross(ofRectangle rect1,ofRectangle rect2) { bool overlap=true; //must overlap in x and y if (rect1.x corners=trapdoors[num].getCorners(); ofPolyline pol2; for (int i=0;i corners=trapdoors[doornumber].getCorners(); ofVec2f screenCorners[4]; for (int i=0;i trapdoors; // float trapdoorSize; // float trapdoorSlotSize; // int numtrapdoorSlots; //create all trapdoors at once, deactivated. //shuffle them //at each timeout, pick the next door to activate (check if within bounds) and rebuild ground with holes //on update, check all active doors against all players //when a falling in sequence is over, start again trapdoors.clear(); l=ofVec2f(windowWidth/2,19*windowHeight/20); r=projector.castPixel(l.x,l.y); plane.intersect(r,p); float closestY=p.rotated(cam_angle,ofVec3f(-1,0,0)).y; numtrapdoorSlots=closestY/trapdoorSlotSize; //get middle position in the slot on the ground visible at front of screen ofVec3f rp=ofVec3f(windowWidth/2,closestY-(0.5*trapdoorSlotSize),0); //translate to the screen ofVec3f sp=cam.worldToScreen(rp.rotated(cam_angle,ofVec3f(1,0,0))); //printf("front slot: %f,%f to %f,%f,%f\n",rp.x,rp.y,sp.x,sp.y,sp.z); //get point at left of this line //project back on ground ofVec2f gb=screen2plane(ofVec2f(windowWidth/8,sp.y)); r=projector.castPixel(sp.x,sp.y); plane.intersect(r,p); float range=(((windowWidth/2)-p.x)*2); for (int i=0;i corners=trapdoors[0].getCorners(); ofVec2f screenCorners[4]; for (int i=0;iwidth,tmp->height,tmp->nChannels,tmp->depth); //get correct channel into backchan vector chans; //to remove shadows, need hsv of foreground and background if (diffchannel>chan_B||removeShadows) cvtColor(outmat, hsvback, CV_BGR2HSV); switch (diffchannel) { case chan_R: split(outmat,chans); chans[0].copyTo(backchan); break; case chan_G: split(outmat,chans); chans[1].copyTo(backchan); break; case chan_B: split(outmat,chans); chans[2].copyTo(backchan); break; case chan_H: split(hsvback,chans); chans[0].copyTo(backchan); break; case chan_S: split(hsvback,chans); chans[1].copyTo(backchan); break; case chan_V: split(hsvback,chans); chans[2].copyTo(backchan); break; } tmp = new IplImage(backchan); grayBg = tmp; //} //first, optionally remove shadows from FG //possibly use 1/4 screen res? //to remove shadows, need hsv of foreground and background if (diffchannel>chan_B||removeShadows) cvtColor(img, hsvfront, CV_BGR2HSV); cv::Mat outimg; if (removeShadows) { vector slicesFront, slicesBack; cv::Mat valFront, valBack, satFront, satBack; // split image to H,S and V images split(hsvfront, slicesFront); split(hsvback, slicesBack); slicesFront[2].copyTo(valFront); // get the value channel slicesFront[1].copyTo(satFront); // get the sat channel slicesBack[2].copyTo(valBack); // get the value channel slicesBack[1].copyTo(satBack); // get the sat channel int x,y; for(x=0; x(y,x)[0] > satBack.at(y,x)[0]-shadowThreshold) && (satFront.at(y,x)[0] < satBack.at(y,x)[0]+shadowThreshold)); if(sat && (valFront.at(y,x)[0] < valBack.at(y,x)[0])) { hsvfront.at(y,x)[0]= hsvback.at(y,x)[0]; hsvfront.at(y,x)[1]= hsvback.at(y,x)[1]; hsvfront.at(y,x)[2]= hsvback.at(y,x)[2]; } } } //convert back into RGB if necessary if (diffchannel chans; split(outimg,chans); switch (diffchannel) { case chan_R: chans[0].copyTo(frontchan); break; case chan_G: chans[1].copyTo(frontchan); break; case chan_B: chans[2].copyTo(frontchan); break; case chan_H: chans[0].copyTo(frontchan); break; case chan_S: chans[1].copyTo(frontchan); break; case chan_V: chans[2].copyTo(frontchan); break; } //IplImage* tmp = new IplImage(outmat); tmp = new IplImage(frontchan); grayFrame = tmp; grayDiff.clear(); grayDiff.allocate(640,480); // take the abs value of the difference between background and incoming and then threshold: grayDiff.absDiff(grayBg, grayFrame); grayDiff.threshold(threshold); //grayFrame.adaptiveThreshold( threshold,10,false,true); //int blockSize, int offset=0,bool invert=false, bool gauss=false); //grayDiff.erode_3x3(); //grayDiff.resize(windowWidth,windowHeight); /* //MOG mog(img, outmat, mogf); // Complement the image //cv::threshold(outmat, output, threshold, 255, cv::THRESH_BINARY_INV); IplImage* tmp1 = new IplImage(outmat); //printf("tmp: %ix%i channels: %i depth:%i\n",tmp->width,tmp->height,tmp->nChannels,tmp->depth); //printf("grayDiff: %ix%i channels: %i depth:%i\n",grayDiff.getCvImage()->width,grayDiff.getCvImage()->height,grayDiff.getCvImage()->nChannels,grayDiff.getCvImage()->depth); grayDiff=tmp1; //copy to ofx */ grayDiff.resize(windowWidth,windowHeight); //wasteful?? contourFinder.findContours(grayDiff, 500, (640*480)/3, 20, false); // find holes blobsManager.update(contourFinder.blobs); //check players against blob ids - bland do ray casting, update players //ids are always in order //players can be a map vs ID //check if a key exists in a map - map::count //do we purge them or just stop drawing them? is it a problem inheriting tesselator re memory? //if we keep them we can have a 'loserboard' set ids; for(int i=0;i::iterator it; for (it=players.begin();it!=players.end();it++) { if (ids.find(it->first)==ids.end()||(border.size()>3&&OutsidePolygon(border,ofPoint(it->second.getWorldPosition().x,it->second.getWorldPosition().y)))) it->second.active=false; else it->second.active=true; } } for (int i=0;itrapdoorTime) { if (trapdoors.size()>trapdoorCounter+1) { trapdoorCounter++; trapdoorTimer=ofGetElapsedTimef(); tessGround(trapdoorCounter); } //else updatePlane(); } ofSetHexColor(0xffffff); ofPushMatrix(); ofRotate(cam_angle,1,0,0); //trapDoor.draw(); for (int i=0;i<=trapdoorCounter;i++) { trapdoors[i].draw(); } ofPopMatrix(); //should be in front with holes being recreated for activated trapdoors ofSetHexColor(0xffffff); if (mode==CALIBRATE) bindTexture(colorImg); else bindTexture(background); ground.draw(); if (mode==CALIBRATE) unbindTexture(colorImg); else unbindTexture(background); ofPushMatrix(); ofRotate(cam_angle,1,0,0); Bird.drawShadow(); ofPopMatrix(); glDisable(GL_DEPTH_TEST); ofSetHexColor(0xffffff); ofPushMatrix(); ofRotate(cam_angle,1,0,0); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); for (int i=0;i<=trapdoorCounter;i++) { trapdoors[i].drawSplash(cam_angle); } glDisable(GL_BLEND); ofPopMatrix(); glDisable(GL_DEPTH_TEST); ofSetHexColor(0xffffff); bindTexture(colorImg); //colorImg.getTextureReference().bind(); map::iterator it; for(int i=0;isegTimes[gameState]) { gameState++; gameStart=ofGetElapsedTimef(); gameTime=0.0f; } break; case PLAYING: if (gameTime>segTimes[gameState]) { gameState=TITLES; sounds[0].play(); gameStart=ofGetElapsedTimef(); gameTime=0.0f; trapdoorTimer=ofGetElapsedTimef(); } break; case GOTCHA: if (gameTime>segTimes[gameState]) { gameState=PLAYING; gameStart=ofGetElapsedTimef(); gameTime=0.0f; updatePlane(); //for new trapdoors } break; } float segElapsed=pow(gameTime/segTimes[gameState],2); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); switch(gameState) { case TITLES: billboards[0].draw(windowWidth/6 ,scaleFactor.y*((-billboards[0].height/2)+(billboards[0].height*pow(sin(segElapsed*PI),0.5))) ,billboards[0].width*scaleFactor.x ,billboards[0].height*scaleFactor.y); break; case CREDIT: billboards[1].draw(windowWidth/6 ,windowHeight+(scaleFactor.y*((billboards[1].height/2)-(billboards[1].height*pow(sin(segElapsed*PI),0.5)))) ,billboards[1].width*scaleFactor.x ,billboards[1].height*scaleFactor.y); break; case EXPLAIN: billboards[2].draw(windowWidth/2 ,scaleFactor.y*((-billboards[2].height/2)+(billboards[2].height*pow(sin(segElapsed*PI),0.5))) ,billboards[2].width*scaleFactor.x ,billboards[2].height*scaleFactor.y); break; case PLAYING: break; case GOTCHA: billboards[3].draw(windowWidth/2 ,scaleFactor.y*((-billboards[2].height/2)+(billboards[3].height*pow(sin(segElapsed*PI),0.5))) ,billboards[3].width*scaleFactor.x ,billboards[3].height*scaleFactor.y); break; } glDisable(GL_BLEND); switch(mode) { case PLAY: break; case CALIBRATE: ofSetHexColor(0xffffff); ofPushMatrix(); ofRotate(cam_angle,1,0,0); for (float i=0;i<=windowWidth;i+=windowWidth/10) { glBegin(GL_LINES); glVertex3f(i,0,0); glVertex3f(i,windowWidth,0); glEnd(); glBegin(GL_LINES); glVertex3f(0,i,0); glVertex3f(windowWidth,i,0); glEnd(); } ofVec2f pp=screen2plane(pos); //ofSphere(pp.x,pp.y,0,5); ofPopMatrix(); ofPushMatrix(); ofRotate(cam_angle,1,0,0); for (int i=0;i1) { ofSetHexColor(0x00ff00); ofPushMatrix(); ofRotate(cam_angle,1,0,0); for (int i=0;i 255) threshold = 255; break; case '-': threshold --; if (threshold < 0) threshold = 0; break; case 'a': cam_angle+=1; updatePlane(); break; case 'z': cam_angle-=1; updatePlane(); break; case 'q': drawStats=!drawStats; break; case 's': saveSettings("settings.xml"); break; case '9': mode=PLAY; break; case '0': mode=CALIBRATE; break; case '1': diffchannel = chan_R; break; case '2': diffchannel = chan_G; break; case '3': diffchannel = chan_B; break; case '4': diffchannel = chan_H; break; case '5': diffchannel = chan_S; break; case '6': diffchannel = chan_V; break; /* case 's': removeShadows=!removeShadows; printf(removeShadows?"removing shadows\n":"not removing shadows\n"); break; case '1': if (Bird.currentseq!="hover") { //mesh.sequences["trans_flaphover"].stopAt(0.3); //mesh.sequences["trans_flaphover"].start(); Bird.model.sequences[Bird.currentseq].fadeout(0.5); Bird.model.sequences["hover"].fadein(0.5); Bird.currentseq="hover"; } break; case '2': if (Bird.currentseq!="flap") { //mesh.sequences["trans_hoverflap"].stopAt(0.3); //mesh.sequences["trans_hoverflap"].start(); Bird.model.sequences[Bird.currentseq].fadeout(0.5); Bird.model.sequences["flap"].fadein(0.5); Bird.currentseq="flap"; } break; case '3': if (Bird.currentseq!="swoop") { //mesh.sequences["trans_hoverflap"].stopAt(0.3); //mesh.sequences["trans_hoverflap"].start(); Bird.model.sequences[Bird.currentseq].fadeout(0.25); Bird.model.sequences["swoop_trans"].fadein(0.25); Bird.model.sequences["swoop_trans"].stopTime=ofGetElapsedTimef()+1.0; Bird.model.sequences["swoop"].startAt(1.0); Bird.currentseq="swoop"; } break; case '4': if (Bird.currentseq!="attack") { //mesh.sequences["trans_hoverflap"].stopAt(0.3); //mesh.sequences["trans_hoverflap"].start(); Bird.model.sequences[Bird.currentseq].fadeout(0.2); Bird.model.sequences["attack_trans"].fadein(0.2); Bird.model.sequences["attack_trans"].stopTime=ofGetElapsedTimef()+0.6; Bird.model.sequences["attack"].startAt(0.6); Bird.currentseq="attack"; } break; */ /* case 'y': light.setPosition(light.getX(),light.getY()-100,light.getZ()); printf("light at %f,%f,%f\n",light.getX(),light.getY(),light.getZ()); break; case 'n': light.setPosition(light.getX(),light.getY()+100,light.getZ()); printf("light at %f,%f,%f\n",light.getX(),light.getY(),light.getZ()); break; case 'g': light.setPosition(light.getX()-100,light.getY(),light.getZ()); printf("light at %f,%f,%f\n",light.getX(),light.getY(),light.getZ()); break; case 'j': light.setPosition(light.getX()+100,light.getY(),light.getZ()); printf("light at %f,%f,%f\n",light.getX(),light.getY(),light.getZ()); break; case 'u': light.setPosition(light.getX(),light.getY(),light.getZ()+100); printf("light at %f,%f,%f\n",light.getX(),light.getY(),light.getZ()); break; case 'b': light.setPosition(light.getX(),light.getY(),light.getZ()-100); printf("light at %f,%f,%f\n",light.getX(),light.getY(),light.getZ()); break; */ case 'b': if (!drawingborder) { border.clear(); drawingborder=true; } else drawingborder=false; /* case '>': gameState=(gameState+1)%4; gameStart=ofGetElapsedTimef(); break; */ } } //-------------------------------------------------------------- void testApp::keyReleased(int key){ } //-------------------------------------------------------------- void testApp::mouseMoved(int x, int y ){ } //-------------------------------------------------------------- void testApp::mouseDragged(int x, int y, int button){ } //-------------------------------------------------------------- void testApp::mousePressed(int x, int y, int button){ } //-------------------------------------------------------------- void testApp::mouseReleased(int x, int y, int button){ pos=ofVec2f(x,y); ofVec2f sp=screen2plane(pos); if (drawingborder) { border.push_back(sp); } printf("ray:%i,%i hit plane:%f,%f,%f\n",x,y,sp.x,sp.y); } //-------------------------------------------------------------- void testApp::windowResized(int w, int h){ } //-------------------------------------------------------------- void testApp::gotMessage(ofMessage msg){ } //-------------------------------------------------------------- void testApp::dragEvent(ofDragInfo dragInfo){ } void testApp::loadSettings(string filename){ if( !XML.loadFile(filename) ){ printf("unable to load %s check data/ folder\n",filename.c_str()); }else{ cam_angle=ofToInt(XML.getAttribute("gauntlet","cam_angle","none",0)); threshold=ofToInt(XML.getAttribute("gauntlet","threshold","none",0)); diffchannel=ofToInt(XML.getAttribute("gauntlet","keyChannel","none",0)); if(XML.pushTag("bounds")) { for (int i=0;i