1381 lines · 42.7 KB · C++
RawDownload
//  //  Interface////  Allows you to connect to and see/hear the shared 3D space.//  Optionally uses serialUSB connection to get gyro data for head movement.//  Optionally gets UDP stream from transmitter to animate controller/hand.//  //  Usage:  The interface client first attempts to contact a domain server to//          discover the appropriate audio, voxel, and avatar servers to contact.//          Right now, the default domain server is "highfidelity.below92.com"//          You can change the domain server to use your own by editing the//          DOMAIN_HOSTNAME or DOMAIN_IP strings in the file AgentList.cpp//////  Welcome Aboard!//////  Keyboard Commands: ////  / = toggle stats display//  spacebar = reset gyros/head position//  h = render Head facing yourself (mirror)//  l = show incoming gyro levels// #include "InterfaceConfig.h"#include <iostream>#include <fstream>#include <math.h>#include <string.h>#include <sstream>#include <stdio.h>#include <stdlib.h> #ifdef _WIN32#include "Syssocket.h"#include "Systime.h"#else#include <sys/time.h>#include <arpa/inet.h>#include <ifaddrs.h>#endif #include <pthread.h> #include <glm/glm.hpp>#include <glm/gtc/matrix_transform.hpp>#include <glm/gtc/type_ptr.hpp> #include "Field.h"#include "world.h"#include "Util.h"#ifndef _WIN32#include "Audio.h"#endif #include "FieldOfView.h"#include "Stars.h" #include "MenuRow.h"#include "MenuColumn.h"#include "Menu.h"#include "Head.h"#include "Hand.h"#include "Camera.h"#include "Particle.h"#include "Texture.h"#include "Cloud.h"#include <AgentList.h>#include <AgentTypes.h>#include "VoxelSystem.h"#include "Lattice.h"#include "Finger.h"#include "Oscilloscope.h"#include "UDPSocket.h"#include "SerialInterface.h"#include <PerfStat.h>#include <SharedUtil.h>#include <PacketHeaders.h> using namespace std; AgentList agentList(AGENT_TYPE_INTERFACE);pthread_t networkReceiveThread;bool stopNetworkReceiveThread = false; int packetCount = 0;int packetsPerSecond = 0; int bytesPerSecond = 0;int bytesCount = 0; int headMirror = 1;                 //  Whether to mirror own head when viewing it int WIDTH = 1200;                   //  Window sizeint HEIGHT = 800;int fullscreen = 0; bool wantColorRandomizer = true;    // for addSphere and load file Oscilloscope audioScope(256,200,true); Head myHead;                        //  The rendered head of oneselfCamera myCamera;					//  My view onto the world (sometimes on myself :)                                     //  Starfield informationchar starFile[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt";FieldOfView fov;Stars stars;#ifdef STARFIELD_KEYSint starsTiles = 20;double starsLod = 1.0;#endif bool showingVoxels = false; glm::vec3 box(WORLD_SIZE,WORLD_SIZE,WORLD_SIZE); ParticleSystem balls(0,                     box,                      false,                //  Wrap?                     0.02f,                //  Noise                     0.3f,                 //  Size scale                      0.0                   //  Gravity                     ); Cloud cloud(0,                         //  Particles            box,                           //  Bounding Box            false                          //  Wrap            ); VoxelSystem voxels; Lattice lattice(160,100);Finger myFinger(WIDTH, HEIGHT);Field field; #ifndef _WIN32Audio audio(&audioScope, &myHead);#endif #define IDLE_SIMULATE_MSECS 8            //  How often should call simulate and other stuff                                          //  in the idle loop? float yaw = 0.f;                         //  The yaw, pitch for the avatar headfloat pitch = 0.f;                            float startYaw = 122.f;float renderPitch = 0.f;float renderYawRate = 0.f;float renderPitchRate = 0.f;  //  Where one's own agent begins in the world (needs to become a dynamic thing passed to the program)glm::vec3 start_location(6.1f, 0, 1.4f); int statsOn = 0;					//  Whether to show onscreen text overlay with statsbool starsOn = false;				//  Whether to display the starsbool paintOn = false;				//  Whether to paint voxels as you fly aroundVoxelDetail paintingVoxel;			//	The voxel we're painting if we're paintingunsigned char dominantColor = 0;	//	The dominant color of the voxel we're paintingbool perfStatsOn = false;			//  Do we want to display perfStats?int noiseOn = 0;					//  Whether to add random noise float noise = 1.0;                  //  Overall magnitude scaling for random noise levels  int displayLevels = 0;int displayHead = 0;int displayField = 0; int displayHeadMouse = 1;         //  Display sample mouse pointer controlled by head movementint headMouseX, headMouseY;  int mouseX, mouseY;				//  Where is the mouseint mouseStartX, mouseStartY;   //  Mouse location at start of last down clickint mousePressed = 0;				//  true if mouse has been pressed (clear when finished) Menu menu;                          // main menuint menuOn = 0;					//  Whether to show onscreen menu ////  Serial USB Variables//  SerialInterface serialPort;int latency_display = 1; glm::vec3 gravity;int first_measurement = 1;//int samplecount = 0; //  Frame rate Measurement int frameCount = 0;                  float FPS = 120.f;timeval timerStart, timerEnd;timeval lastTimeIdle;double elapsedTime; // Particles  float particle_attenuation_quadratic[] =  { 0.0f, 0.0f, 2.0f }; // larger Z = smaller particlesfloat pointer_attenuation_quadratic[] =  { 1.0f, 0.0f, 0.0f }; // for 2D view #ifdef MARKER_CAPTURE     /***  Marker Capture ***/    #define MARKER_CAPTURE_INTERVAL 1    MarkerCapture marker_capturer(CV_CAP_ANY); // Create a new marker capturer, attached to any valid camera.    MarkerAcquisitionView marker_acq_view(&marker_capturer);    bool marker_capture_enabled = true;    bool marker_capture_display = true;    IplImage* marker_capture_frame;    IplImage* marker_capture_blob_frame;    pthread_mutex_t frame_lock; #endif  //  Every second, check the frame rates and other stuffvoid Timer(int extra){    gettimeofday(&timerEnd, NULL);    FPS = (float)frameCount / ((float)diffclock(&timerStart, &timerEnd) / 1000.f);    packetsPerSecond = (float)packetCount / ((float)diffclock(&timerStart, &timerEnd) / 1000.f);    bytesPerSecond = (float)bytesCount / ((float)diffclock(&timerStart, &timerEnd) / 1000.f);   	frameCount = 0;    packetCount = 0;    bytesCount = 0;    	glutTimerFunc(1000,Timer,0);    gettimeofday(&timerStart, NULL);        //  Ping the agents we can see    agentList.pingAgents();        // if we haven't detected gyros, check for them now    if (!serialPort.active) {        serialPort.pair();    }} void displayStats(void){    int statsVerticalOffset = 50;    if (menuOn == 0) {        statsVerticalOffset = 8;    }	//  bitmap chars are about 10 pels high     char legend[] = "/ - toggle this display, Q - exit, H - show head, M - show hand, T - test audio";    drawtext(10, statsVerticalOffset + 15, 0.10f, 0, 1.0, 0, legend);     char legend2[] = "* - toggle stars, & - toggle paint mode, '-' - send erase all, '%' - send add scene";    drawtext(10, statsVerticalOffset + 32, 0.10f, 0, 1.0, 0, legend2); 	glm::vec3 headPos = myHead.getPos();        char stats[200];    sprintf(stats, "FPS = %3.0f  Pkts/s = %d  Bytes/s = %d Head(x,y,z)=( %f , %f , %f )",             FPS, packetsPerSecond,  bytesPerSecond, headPos.x,headPos.y,headPos.z);    drawtext(10, statsVerticalOffset + 49, 0.10f, 0, 1.0, 0, stats);     if (serialPort.active) {        sprintf(stats, "ADC samples = %d, LED = %d",                 serialPort.getNumSamples(), serialPort.getLED());        drawtext(300, statsVerticalOffset + 30, 0.10f, 0, 1.0, 0, stats);    }        //  Output the ping times to the various agents //    std::stringstream pingTimes;//    pingTimes << "Agent Pings, msecs:";//    for (int i = 0; i < getAgentCount(); i++) {//        pingTimes << " " << getAgentAddress(i) << ": " << getAgentPing(i);//    }//    drawtext(10,50,0.10, 0, 1.0, 0, (char *)pingTimes.str().c_str());     std::stringstream voxelStats;    voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered();    drawtext(10, statsVerticalOffset + 70, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); 	voxelStats.str("");	voxelStats << "Voxels Created: " << voxels.getVoxelsCreated() << " (" << voxels.getVoxelsCreatedRunningAverage() 		<< "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) ";    drawtext(10, statsVerticalOffset + 250, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); 	voxelStats.str("");	voxelStats << "Voxels Colored: " << voxels.getVoxelsColored() << " (" << voxels.getVoxelsColoredRunningAverage() 		<< "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) ";    drawtext(10, statsVerticalOffset + 270, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());		voxelStats.str("");	voxelStats << "Voxels Bytes Read: " << voxels.getVoxelsBytesRead()  		<< " (" << voxels.getVoxelsBytesReadRunningAverage() << "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) ";    drawtext(10, statsVerticalOffset + 290,0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); 	voxelStats.str("");	long int voxelsBytesPerColored = voxels.getVoxelsColored() ? voxels.getVoxelsBytesRead()/voxels.getVoxelsColored() : 0;	long int voxelsBytesPerColoredAvg = voxels.getVoxelsColoredRunningAverage() ? 		voxels.getVoxelsBytesReadRunningAverage()/voxels.getVoxelsColoredRunningAverage() : 0; 	voxelStats << "Voxels Bytes per Colored: " << voxelsBytesPerColored  		<< " (" << voxelsBytesPerColoredAvg << "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) ";    drawtext(10, statsVerticalOffset + 310, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());	 	if (::perfStatsOn) {		// Get the PerfStats group details. We need to allocate and array of char* long enough to hold 1+groups		char** perfStatLinesArray = new char*[PerfStat::getGroupCount()+1];		int lines = PerfStat::DumpStats(perfStatLinesArray);		int atZ = 150; // arbitrary place on screen that looks good		for (int line=0; line < lines; line++) {			drawtext(10, statsVerticalOffset + atZ, 0.10f, 0, 1.0, 0, perfStatLinesArray[line]);			delete perfStatLinesArray[line]; // we're responsible for cleanup			perfStatLinesArray[line]=NULL;			atZ+=20; // height of a line		}		delete []perfStatLinesArray; // we're responsible for cleanup	}} void initDisplay(void){    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    glEnable(GL_BLEND);    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);    glShadeModel (GL_SMOOTH);    glEnable(GL_LIGHTING);    glEnable(GL_LIGHT0);    glEnable(GL_DEPTH_TEST);        if (fullscreen) glutFullScreen();} void init(void){    voxels.init();    voxels.setViewerHead(&myHead);    myHead.setRenderYaw(startYaw);     headMouseX = WIDTH/2;    headMouseY = HEIGHT/2;      stars.readInput(starFile, 0);     //  Initialize Field values    field = Field();     if (noiseOn) {           myHead.setNoise(noise);    }    myHead.setPos(start_location );	myCamera.setPosition( start_location );	#ifdef MARKER_CAPTURE    if(marker_capture_enabled){        marker_capturer.position_updated(&position_updated);        marker_capturer.frame_updated(&marker_frame_available);        if(!marker_capturer.init_capture()){            printf("Camera-based marker capture initialized.\n");        }else{            printf("Error initializing camera-based marker capture.\n");        }    }#endif        gettimeofday(&timerStart, NULL);    gettimeofday(&lastTimeIdle, NULL);} void terminate () {    // Close serial port    //close(serial_fd);     #ifndef _WIN32    audio.terminate();    #endif    stopNetworkReceiveThread = true;    pthread_join(networkReceiveThread, NULL);        exit(EXIT_SUCCESS);} void reset_sensors(){    //      //   Reset serial I/O sensors     //     myHead.setRenderYaw(startYaw);        yaw = renderYawRate = 0;     pitch = renderPitch = renderPitchRate = 0;    myHead.setPos(start_location);    headMouseX = WIDTH/2;    headMouseY = HEIGHT/2;        myHead.reset();        if (serialPort.active) {        serialPort.resetTrailingAverages();    }} void simulateHand(float deltaTime) {    //  If mouse is being dragged, send current force to the hand controller    if (mousePressed == 1)    {        //  Add a velocity to the hand corresponding to the detected size of the drag vector        const float MOUSE_HAND_FORCE = 1.5;        float dx = mouseX - mouseStartX;        float dy = mouseY - mouseStartY;        glm::vec3 vel(dx*MOUSE_HAND_FORCE, -dy*MOUSE_HAND_FORCE*(WIDTH/HEIGHT), 0);        myHead.hand->addVelocity(vel*deltaTime);    }} void simulateHead(float frametime)//  Using serial data, update avatar/render position and angles{//    float measured_pitch_rate = serialPort.getRelativeValue(PITCH_RATE);//    float measured_yaw_rate = serialPort.getRelativeValue(YAW_RATE);        float measured_pitch_rate = 0;    float measured_yaw_rate = 0;        //float measured_lateral_accel = serialPort.getRelativeValue(ACCEL_X);    //float measured_fwd_accel = serialPort.getRelativeValue(ACCEL_Z);        myHead.UpdatePos(frametime, &serialPort, headMirror, &gravity);		//-------------------------------------------------------------------------------------	// set the position of the avatar	//-------------------------------------------------------------------------------------	myHead.setAvatarPosition( -myHead.getPos().x, -myHead.getPos().y, -myHead.getPos().z );	    //  Update head_mouse model     const float MIN_MOUSE_RATE = 30.0;    const float MOUSE_SENSITIVITY = 0.1f;    if (powf(measured_yaw_rate*measured_yaw_rate +              measured_pitch_rate*measured_pitch_rate, 0.5) > MIN_MOUSE_RATE)    {        headMouseX += measured_yaw_rate*MOUSE_SENSITIVITY;        headMouseY += measured_pitch_rate*MOUSE_SENSITIVITY*(float)HEIGHT/(float)WIDTH;     }    headMouseX = max(headMouseX, 0);    headMouseX = min(headMouseX, WIDTH);    headMouseY = max(headMouseY, 0);    headMouseY = min(headMouseY, HEIGHT);        //  Update render direction (pitch/yaw) based on measured gyro rates    const int MIN_YAW_RATE = 100;    const int MIN_PITCH_RATE = 100;        const float YAW_SENSITIVITY = 0.02;    const float PITCH_SENSITIVITY = 0.05;        //  Update render pitch and yaw rates based on keyPositions    const float KEY_YAW_SENSITIVITY = 2.0;    if (myHead.getDriveKeys(ROT_LEFT)) renderYawRate -= KEY_YAW_SENSITIVITY*frametime;    if (myHead.getDriveKeys(ROT_RIGHT)) renderYawRate += KEY_YAW_SENSITIVITY*frametime;        if (fabs(measured_yaw_rate) > MIN_YAW_RATE)      {           if (measured_yaw_rate > 0)            renderYawRate += (measured_yaw_rate - MIN_YAW_RATE) * YAW_SENSITIVITY * frametime;        else             renderYawRate += (measured_yaw_rate + MIN_YAW_RATE) * YAW_SENSITIVITY * frametime;    }    if (fabs(measured_pitch_rate) > MIN_PITCH_RATE)     {        if (measured_pitch_rate > 0)            renderPitchRate += (measured_pitch_rate - MIN_PITCH_RATE) * PITCH_SENSITIVITY * frametime;        else             renderPitchRate += (measured_pitch_rate + MIN_PITCH_RATE) * PITCH_SENSITIVITY * frametime;    }             renderPitch += renderPitchRate;        // Decay renderPitch toward zero because we never look constantly up/down     renderPitch *= (1.f - 2.0*frametime);     //  Decay angular rates toward zero     renderPitchRate *= (1.f - 5.0*frametime);    renderYawRate *= (1.f - 7.0*frametime);        //  Update own head data    myHead.setRenderYaw(myHead.getRenderYaw() + renderYawRate);    myHead.setRenderPitch(renderPitch);        //  Get audio loudness data from audio input device    float loudness, averageLoudness;    #ifndef _WIN32    audio.getInputLoudness(&loudness, &averageLoudness);    myHead.setLoudness(loudness);    myHead.setAverageLoudness(averageLoudness);    #endif     //  Send my streaming head data to agents that are nearby and need to see it!    const int MAX_BROADCAST_STRING = 200;    char broadcast_string[MAX_BROADCAST_STRING];    int broadcast_bytes = myHead.getBroadcastData(broadcast_string);    agentList.broadcastToAgents(broadcast_string, broadcast_bytes,AgentList::AGENTS_OF_TYPE_VOXEL_AND_INTERFACE);     // If I'm in paint mode, send a voxel out to VOXEL server agents.    if (::paintOn) {

Lines 1–500 of 1381.