// // 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!// #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 "InterfaceConfig.h" #include "Log.h"#include "shared_Log.h"#include "voxels_Log.h"#include "avatars_Log.h" #include "world.h"#include "Util.h"#ifndef _WIN32#include "Audio.h"#endif #include "AngleUtil.h"#include "Stars.h" #include "ui/ChatEntry.h"#include "ui/MenuRow.h"#include "ui/MenuColumn.h"#include "ui/Menu.h"#include "ui/TextRenderer.h"#include "renderer/ProgramObject.h"#include "renderer/ShaderObject.h" #include "Application.h"#include "Camera.h"#include "Avatar.h"#include <AgentList.h>#include <AgentTypes.h>#include "VoxelSystem.h"#include "Environment.h"#include "Oscilloscope.h"#include "UDPSocket.h"#include "SerialInterface.h"#include <PacketHeaders.h>#include <AvatarData.h>#include <PerfStat.h>#include <SimpleMovingAverage.h> #include "ViewFrustum.h"#include "HandControl.h"#include "AvatarRenderer.h"#include "OculusManager.h" using namespace std; void reshape(int width, int height); // will be defined belowvoid loadViewFrustum(ViewFrustum& viewFrustum); // will be defined below glm::vec3 getGravity(glm::vec3 pos); //get the local gravity vector at this location in the universe bool enableNetworkThread = true;pthread_t networkReceiveThread;bool stopNetworkReceiveThread = false; unsigned char incomingPacket[MAX_PACKET_SIZE];int packetCount = 0;int packetsPerSecond = 0; int bytesPerSecond = 0;int bytesCount = 0; int screenWidth = 1200; // Window sizeint screenHeight = 800;int fullscreen = 0;float aspectRatio = 1.0f; bool USING_MOUSE_VIEW_SHIFT = false;float MOUSE_VIEW_SHIFT_RATE = 40.0f;float MOUSE_VIEW_SHIFT_YAW_MARGIN = (float)(WIDTH * 0.2f);float MOUSE_VIEW_SHIFT_PITCH_MARGIN = (float)(HEIGHT * 0.2f);float MOUSE_VIEW_SHIFT_YAW_LIMIT = 45.0;float MOUSE_VIEW_SHIFT_PITCH_LIMIT = 30.0; //CameraMode defaultCameraMode = CAMERA_MODE_FIRST_PERSON;CameraMode defaultCameraMode = CAMERA_MODE_THIRD_PERSON; bool wantColorRandomizer = true; // for addSphere and load file Oscilloscope audioScope(256,200,true); ViewFrustum viewFrustum; // current state of view frustum, perspective, orientation, etc. Avatar myAvatar(true); // The rendered avatar of oneselfCamera myCamera; // My view onto the world Camera viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode AvatarRenderer avatarRenderer; // Starfield informationchar starFile[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt";char starCacheFile[] = "cachedStars.txt";Stars stars; glm::vec3 box(WORLD_SIZE,WORLD_SIZE,WORLD_SIZE); VoxelSystem voxels; Environment environment; #ifndef _WIN32Audio audio(&audioScope, &myAvatar);#endif #define IDLE_SIMULATE_MSECS 16 // How often should call simulate and other stuff // in the idle loop? (60 FPS is default) glm::vec3 start_location(6.1f, 0, 1.4f); // Where one's own agent begins in the world // (will be overwritten if avatar data file is found) bool renderWarningsOn = false; // Whether to show render pipeline warningsbool renderStatsOn = false; // Whether to show onscreen text overlay with statsbool renderVoxels = true; // Whether to render voxelsbool renderStarsOn = true; // Whether to display the starsbool renderAtmosphereOn = true; // Whether to display the atmospherebool renderAvatarsOn = true; // Whether to render avatarsbool renderFirstPersonOn = false; // Whether to render in first person bool 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? bool logOn = true; // Whether to show on-screen log bool wantToKillLocalVoxels = false; int noiseOn = 0; // Whether to add random noise float noise = 1.0; // Overall magnitude scaling for random noise levels bool gyroLook = true; // Whether to allow the gyro data from head to move your view int displayLevels = 0;bool lookingInMirror = 0; // Are we currently rendering one's own head as if in mirror? int displayHeadMouse = 1; // Display sample mouse pointer controlled by head movementint headMouseX, headMouseY; HandControl handControl; int mouseX = 0;int mouseY = 0; // Mouse location at start of last down clickint mousePressed = 0; // true if mouse has been pressed (clear when finished) // The current mode for mouse interactionenum MouseMode { ADD_VOXEL_MODE, DELETE_VOXEL_MODE, COLOR_VOXEL_MODE };MouseMode mouseMode = ADD_VOXEL_MODE;VoxelDetail mouseVoxel; // details of the voxel under the mouse cursorfloat mouseVoxelScale = 1.0f / 1024.0f; // the scale for adding/removing voxels Menu menu; // main menuint menuOn = 1; // Whether to show onscreen menu ChatEntry chatEntry; // chat entry fieldbool chatEntryOn = false; // Whether to show the chat entry bool oculusOn = false; // Whether to configure the display for the Oculus RiftGLuint oculusTextureID = 0; // The texture to which we render for Oculus distortionProgramObject* oculusProgram = 0; // The GLSL program containing the distortion shaderfloat oculusDistortionScale = 1.25; // Controls the Oculus field of viewa SerialInterface serialPort; glm::vec3 gravity; // Frame Rate Measurement int frameCount = 0; float FPS = 120.f;timeval timerStart, timerEnd;timeval lastTimeIdle;double elapsedTime;timeval applicationStartupTime;bool justStarted = true; // 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); // 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; } char stats[200]; sprintf(stats, "%3.0f FPS, %d Pkts/sec, %3.2f Mbps", FPS, packetsPerSecond, (float)bytesPerSecond * 8.f / 1000000.f); drawtext(10, statsVerticalOffset + 15, 0.10f, 0, 1.0, 0, stats); std::stringstream voxelStats; voxelStats.precision(4); voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered() / 1000.f << "K Updated: " << voxels.getVoxelsUpdated()/1000.f << "K"; drawtext(10, statsVerticalOffset + 230, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); voxelStats.str(""); voxelStats << "Voxels Created: " << voxels.getVoxelsCreated() / 1000.f << "K (" << voxels.getVoxelsCreatedPerSecondAverage() / 1000.f << "Kps) "; drawtext(10, statsVerticalOffset + 250, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); voxelStats.str(""); voxelStats << "Voxels Colored: " << voxels.getVoxelsColored() / 1000.f << "K (" << voxels.getVoxelsColoredPerSecondAverage() / 1000.f << "Kps) "; drawtext(10, statsVerticalOffset + 270, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); voxelStats.str(""); voxelStats << "Voxel Bits Read: " << voxels.getVoxelsBytesRead() * 8.f / 1000000.f << "M (" << voxels.getVoxelsBytesReadPerSecondAverage() * 8.f / 1000000.f << " Mbps)"; drawtext(10, statsVerticalOffset + 290,0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); voxelStats.str(""); float voxelsBytesPerColored = voxels.getVoxelsColored() ? ((float) voxels.getVoxelsBytesRead() / voxels.getVoxelsColored()) : 0; voxelStats << "Voxels Bits per Colored: " << voxelsBytesPerColored * 8; drawtext(10, statsVerticalOffset + 310, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); Agent *avatarMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER); char avatarMixerStats[200]; if (avatarMixer) { sprintf(avatarMixerStats, "Avatar Mixer: %.f kbps, %.f pps", roundf(avatarMixer->getAverageKilobitsPerSecond()), roundf(avatarMixer->getAveragePacketsPerSecond())); } else { sprintf(avatarMixerStats, "No Avatar Mixer"); } drawtext(10, statsVerticalOffset + 330, 0.10f, 0, 1.0, 0, avatarMixerStats); 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.setViewerAvatar(&myAvatar); voxels.setCamera(&myCamera); environment.init(); handControl.setScreenDimensions(::screenWidth, ::screenHeight); headMouseX = ::screenWidth / 2; headMouseY = ::screenHeight / 2; stars.readInput(starFile, starCacheFile, 0); if (noiseOn) { myAvatar.setNoise(noise); } myAvatar.setPosition(start_location); myCamera.setPosition(start_location); myCamera.setMode(defaultCameraMode); OculusManager::connect(); gettimeofday(&timerStart, NULL); gettimeofday(&lastTimeIdle, NULL);} void terminate () { // Close serial port // close(serial_fd); myAvatar.writeAvatarDataToFile(); #ifndef _WIN32 audio.terminate(); #endif if (enableNetworkThread) { stopNetworkReceiveThread = true; pthread_join(networkReceiveThread, NULL); } exit(EXIT_SUCCESS);} void reset_sensors() { myAvatar.setPosition(start_location); headMouseX = ::screenWidth / 2; headMouseY = ::screenHeight / 2; myAvatar.reset();} void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) { unsigned char* bufferOut; int sizeOut; if (createVoxelEditMessage(header, 0, 1, &detail, bufferOut, sizeOut)){ AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1); delete bufferOut; }} // Using gyro data, update both view frustum and avatar head positionvoid updateAvatar(float deltaTime) { // Update my avatar's head position from gyros myAvatar.updateHeadFromGyros(deltaTime, &serialPort, &gravity); // Grab latest readings from the gyros float measuredPitchRate = serialPort.getLastPitchRate(); float measuredYawRate = serialPort.getLastYawRate(); // Update gyro-based mouse (X,Y on screen) const float MIN_MOUSE_RATE = 1.0; const float HORIZONTAL_PIXELS_PER_DEGREE = 2880.f / 45.f; const float VERTICAL_PIXELS_PER_DEGREE = 1800.f / 30.f; if (powf(measuredYawRate * measuredYawRate + measuredPitchRate * measuredPitchRate, 0.5) > MIN_MOUSE_RATE) { headMouseX += measuredYawRate * HORIZONTAL_PIXELS_PER_DEGREE * deltaTime; headMouseY -= measuredPitchRate * VERTICAL_PIXELS_PER_DEGREE * deltaTime; } headMouseX = max(headMouseX, 0); headMouseX = min(headMouseX, ::screenWidth); headMouseY = max(headMouseY, 0); headMouseY = min(headMouseY, ::screenHeight); // Update head and body pitch and yaw based on measured gyro rates if (::gyroLook) { // Render Yaw float renderYawSpring = fabs(headMouseX - ::screenWidth / 2.f) / (::screenWidth / 2.f); const float RENDER_YAW_MULTIPLY = 4.f; myAvatar.setRenderYaw((1.f - renderYawSpring * deltaTime) * myAvatar.getRenderYaw() + renderYawSpring * deltaTime * -myAvatar.getHeadYaw() * RENDER_YAW_MULTIPLY); // Render Pitch float renderPitchSpring = fabs(headMouseY - ::screenHeight / 2.f) / (::screenHeight / 2.f); const float RENDER_PITCH_MULTIPLY = 4.f; myAvatar.setRenderPitch((1.f - renderPitchSpring * deltaTime) * myAvatar.getRenderPitch() + renderPitchSpring * deltaTime * -myAvatar.getHeadPitch() * RENDER_PITCH_MULTIPLY); } if (USING_MOUSE_VIEW_SHIFT) { //make it so that when your mouse hits the edge of the screen, the camera shifts float rightBoundary = (float)WIDTH - MOUSE_VIEW_SHIFT_YAW_MARGIN; float bottomBoundary = (float)HEIGHT - MOUSE_VIEW_SHIFT_PITCH_MARGIN; if (mouseX > rightBoundary) { float f = (mouseX - rightBoundary) / ( (float)WIDTH - rightBoundary); mouseViewShiftYaw += MOUSE_VIEW_SHIFT_RATE * f * deltaTime; if (mouseViewShiftYaw > MOUSE_VIEW_SHIFT_YAW_LIMIT) { mouseViewShiftYaw = MOUSE_VIEW_SHIFT_YAW_LIMIT; } } else if (mouseX < MOUSE_VIEW_SHIFT_YAW_MARGIN) { float f = 1.0 - (mouseX / MOUSE_VIEW_SHIFT_YAW_MARGIN); mouseViewShiftYaw -= MOUSE_VIEW_SHIFT_RATE * f * deltaTime; if (mouseViewShiftYaw < -MOUSE_VIEW_SHIFT_YAW_LIMIT) { mouseViewShiftYaw = -MOUSE_VIEW_SHIFT_YAW_LIMIT; } } if (mouseY < MOUSE_VIEW_SHIFT_PITCH_MARGIN) { float f = 1.0 - (mouseY / MOUSE_VIEW_SHIFT_PITCH_MARGIN); mouseViewShiftPitch += MOUSE_VIEW_SHIFT_RATE * f * deltaTime; if ( mouseViewShiftPitch > MOUSE_VIEW_SHIFT_PITCH_LIMIT ) { mouseViewShiftPitch = MOUSE_VIEW_SHIFT_PITCH_LIMIT; } } else if (mouseY > bottomBoundary) { float f = (mouseY - bottomBoundary) / ((float)HEIGHT - bottomBoundary); mouseViewShiftPitch -= MOUSE_VIEW_SHIFT_RATE * f * deltaTime; if (mouseViewShiftPitch < -MOUSE_VIEW_SHIFT_PITCH_LIMIT) { mouseViewShiftPitch = -MOUSE_VIEW_SHIFT_PITCH_LIMIT; } } } if (OculusManager::isConnected()) { float yaw, pitch, roll; OculusManager::getEulerAngles(yaw, pitch, roll); myAvatar.setHeadYaw(-yaw); myAvatar.setHeadPitch(pitch); myAvatar.setHeadRoll(roll); } // Get audio loudness data from audio input device #ifndef _WIN32 myAvatar.setLoudness(audio.getInputLoudness()); #endif // Update Avatar with latest camera and view frustum data... // NOTE: we get this from the view frustum, to make it simpler, since the // loadViewFrumstum() method will get the correct details from the camera // We could optimize this to not actually load the viewFrustum, since we don't // actually need to calculate the view frustum planes to send these details // to the server. loadViewFrustum(::viewFrustum); myAvatar.setCameraPosition(::viewFrustum.getPosition()); myAvatar.setCameraDirection(::viewFrustum.getDirection()); myAvatar.setCameraUp(::viewFrustum.getUp()); myAvatar.setCameraRight(::viewFrustum.getRight()); myAvatar.setCameraFov(::viewFrustum.getFieldOfView()); myAvatar.setCameraAspectRatio(::viewFrustum.getAspectRatio()); myAvatar.setCameraNearClip(::viewFrustum.getNearClip()); myAvatar.setCameraFarClip(::viewFrustum.getFarClip()); AgentList* agentList = AgentList::getInstance(); if (agentList->getOwnerID() != UNKNOWN_AGENT_ID) { // if I know my ID, send head/hand data to the avatar mixer and voxel server unsigned char broadcastString[200]; unsigned char* endOfBroadcastStringWrite = broadcastString; *(endOfBroadcastStringWrite++) = PACKET_HEADER_HEAD_DATA; endOfBroadcastStringWrite += packAgentId(endOfBroadcastStringWrite, agentList->getOwnerID()); endOfBroadcastStringWrite += myAvatar.getBroadcastData(endOfBroadcastStringWrite); const char broadcastReceivers[2] = {AGENT_TYPE_VOXEL, AGENT_TYPE_AVATAR_MIXER}; AgentList::getInstance()->broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, broadcastReceivers, sizeof(broadcastReceivers)); } // If I'm in paint mode, send a voxel out to VOXEL server agents. if (::paintOn) { glm::vec3 avatarPos = myAvatar.getPosition(); // For some reason, we don't want to flip X and Z here. ::paintingVoxel.x = avatarPos.x / 10.0; ::paintingVoxel.y = avatarPos.y / 10.0; ::paintingVoxel.z = avatarPos.z / 10.0; Lines 1–500 of 2141. Load more
// // 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! // #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 "InterfaceConfig.h" #include "Log.h" #include "shared_Log.h" #include "voxels_Log.h" #include "avatars_Log.h" #include "world.h" #include "Util.h" #ifndef _WIN32 #include "Audio.h" #endif #include "AngleUtil.h" #include "Stars.h" #include "ui/ChatEntry.h" #include "ui/MenuRow.h" #include "ui/MenuColumn.h" #include "ui/Menu.h" #include "ui/TextRenderer.h" #include "renderer/ProgramObject.h" #include "renderer/ShaderObject.h" #include "Application.h" #include "Camera.h" #include "Avatar.h" #include <AgentList.h> #include <AgentTypes.h> #include "VoxelSystem.h" #include "Environment.h" #include "Oscilloscope.h" #include "UDPSocket.h" #include "SerialInterface.h" #include <PacketHeaders.h> #include <AvatarData.h> #include <PerfStat.h> #include <SimpleMovingAverage.h> #include "ViewFrustum.h" #include "HandControl.h" #include "AvatarRenderer.h" #include "OculusManager.h" using namespace std; void reshape(int width, int height); // will be defined below void loadViewFrustum(ViewFrustum& viewFrustum); // will be defined below glm::vec3 getGravity(glm::vec3 pos); //get the local gravity vector at this location in the universe bool enableNetworkThread = true; pthread_t networkReceiveThread; bool stopNetworkReceiveThread = false; unsigned char incomingPacket[MAX_PACKET_SIZE]; int packetCount = 0; int packetsPerSecond = 0; int bytesPerSecond = 0; int bytesCount = 0; int screenWidth = 1200; // Window size int screenHeight = 800; int fullscreen = 0; float aspectRatio = 1.0f; bool USING_MOUSE_VIEW_SHIFT = false; float MOUSE_VIEW_SHIFT_RATE = 40.0f; float MOUSE_VIEW_SHIFT_YAW_MARGIN = (float)(WIDTH * 0.2f); float MOUSE_VIEW_SHIFT_PITCH_MARGIN = (float)(HEIGHT * 0.2f); float MOUSE_VIEW_SHIFT_YAW_LIMIT = 45.0; float MOUSE_VIEW_SHIFT_PITCH_LIMIT = 30.0; //CameraMode defaultCameraMode = CAMERA_MODE_FIRST_PERSON; CameraMode defaultCameraMode = CAMERA_MODE_THIRD_PERSON; bool wantColorRandomizer = true; // for addSphere and load file Oscilloscope audioScope(256,200,true); ViewFrustum viewFrustum; // current state of view frustum, perspective, orientation, etc. Avatar myAvatar(true); // The rendered avatar of oneself Camera myCamera; // My view onto the world Camera viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode AvatarRenderer avatarRenderer; // Starfield information char starFile[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; char starCacheFile[] = "cachedStars.txt"; Stars stars; glm::vec3 box(WORLD_SIZE,WORLD_SIZE,WORLD_SIZE); VoxelSystem voxels; Environment environment; #ifndef _WIN32 Audio audio(&audioScope, &myAvatar); #endif #define IDLE_SIMULATE_MSECS 16 // How often should call simulate and other stuff // in the idle loop? (60 FPS is default) glm::vec3 start_location(6.1f, 0, 1.4f); // Where one's own agent begins in the world // (will be overwritten if avatar data file is found) bool renderWarningsOn = false; // Whether to show render pipeline warnings bool renderStatsOn = false; // Whether to show onscreen text overlay with stats bool renderVoxels = true; // Whether to render voxels bool renderStarsOn = true; // Whether to display the stars bool renderAtmosphereOn = true; // Whether to display the atmosphere bool renderAvatarsOn = true; // Whether to render avatars bool renderFirstPersonOn = false; // Whether to render in first person bool paintOn = false; // Whether to paint voxels as you fly around VoxelDetail paintingVoxel; // The voxel we're painting if we're painting unsigned char dominantColor = 0; // The dominant color of the voxel we're painting bool perfStatsOn = false; // Do we want to display perfStats? bool logOn = true; // Whether to show on-screen log bool wantToKillLocalVoxels = false; int noiseOn = 0; // Whether to add random noise float noise = 1.0; // Overall magnitude scaling for random noise levels bool gyroLook = true; // Whether to allow the gyro data from head to move your view int displayLevels = 0; bool lookingInMirror = 0; // Are we currently rendering one's own head as if in mirror? int displayHeadMouse = 1; // Display sample mouse pointer controlled by head movement int headMouseX, headMouseY; HandControl handControl; int mouseX = 0; int mouseY = 0; // Mouse location at start of last down click int mousePressed = 0; // true if mouse has been pressed (clear when finished) // The current mode for mouse interaction enum MouseMode { ADD_VOXEL_MODE, DELETE_VOXEL_MODE, COLOR_VOXEL_MODE }; MouseMode mouseMode = ADD_VOXEL_MODE; VoxelDetail mouseVoxel; // details of the voxel under the mouse cursor float mouseVoxelScale = 1.0f / 1024.0f; // the scale for adding/removing voxels Menu menu; // main menu int menuOn = 1; // Whether to show onscreen menu ChatEntry chatEntry; // chat entry field bool chatEntryOn = false; // Whether to show the chat entry bool oculusOn = false; // Whether to configure the display for the Oculus Rift GLuint oculusTextureID = 0; // The texture to which we render for Oculus distortion ProgramObject* oculusProgram = 0; // The GLSL program containing the distortion shader float oculusDistortionScale = 1.25; // Controls the Oculus field of viewa SerialInterface serialPort; glm::vec3 gravity; // Frame Rate Measurement int frameCount = 0; float FPS = 120.f; timeval timerStart, timerEnd; timeval lastTimeIdle; double elapsedTime; timeval applicationStartupTime; bool justStarted = true; // Every second, check the frame rates and other stuff void 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); // 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; } char stats[200]; sprintf(stats, "%3.0f FPS, %d Pkts/sec, %3.2f Mbps", FPS, packetsPerSecond, (float)bytesPerSecond * 8.f / 1000000.f); drawtext(10, statsVerticalOffset + 15, 0.10f, 0, 1.0, 0, stats); std::stringstream voxelStats; voxelStats.precision(4); voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered() / 1000.f << "K Updated: " << voxels.getVoxelsUpdated()/1000.f << "K"; drawtext(10, statsVerticalOffset + 230, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); voxelStats.str(""); voxelStats << "Voxels Created: " << voxels.getVoxelsCreated() / 1000.f << "K (" << voxels.getVoxelsCreatedPerSecondAverage() / 1000.f << "Kps) "; drawtext(10, statsVerticalOffset + 250, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); voxelStats.str(""); voxelStats << "Voxels Colored: " << voxels.getVoxelsColored() / 1000.f << "K (" << voxels.getVoxelsColoredPerSecondAverage() / 1000.f << "Kps) "; drawtext(10, statsVerticalOffset + 270, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); voxelStats.str(""); voxelStats << "Voxel Bits Read: " << voxels.getVoxelsBytesRead() * 8.f / 1000000.f << "M (" << voxels.getVoxelsBytesReadPerSecondAverage() * 8.f / 1000000.f << " Mbps)"; drawtext(10, statsVerticalOffset + 290,0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); voxelStats.str(""); float voxelsBytesPerColored = voxels.getVoxelsColored() ? ((float) voxels.getVoxelsBytesRead() / voxels.getVoxelsColored()) : 0; voxelStats << "Voxels Bits per Colored: " << voxelsBytesPerColored * 8; drawtext(10, statsVerticalOffset + 310, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); Agent *avatarMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER); char avatarMixerStats[200]; if (avatarMixer) { sprintf(avatarMixerStats, "Avatar Mixer: %.f kbps, %.f pps", roundf(avatarMixer->getAverageKilobitsPerSecond()), roundf(avatarMixer->getAveragePacketsPerSecond())); } else { sprintf(avatarMixerStats, "No Avatar Mixer"); } drawtext(10, statsVerticalOffset + 330, 0.10f, 0, 1.0, 0, avatarMixerStats); 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.setViewerAvatar(&myAvatar); voxels.setCamera(&myCamera); environment.init(); handControl.setScreenDimensions(::screenWidth, ::screenHeight); headMouseX = ::screenWidth / 2; headMouseY = ::screenHeight / 2; stars.readInput(starFile, starCacheFile, 0); if (noiseOn) { myAvatar.setNoise(noise); } myAvatar.setPosition(start_location); myCamera.setPosition(start_location); myCamera.setMode(defaultCameraMode); OculusManager::connect(); gettimeofday(&timerStart, NULL); gettimeofday(&lastTimeIdle, NULL); } void terminate () { // Close serial port // close(serial_fd); myAvatar.writeAvatarDataToFile(); #ifndef _WIN32 audio.terminate(); #endif if (enableNetworkThread) { stopNetworkReceiveThread = true; pthread_join(networkReceiveThread, NULL); } exit(EXIT_SUCCESS); } void reset_sensors() { myAvatar.setPosition(start_location); headMouseX = ::screenWidth / 2; headMouseY = ::screenHeight / 2; myAvatar.reset(); } void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) { unsigned char* bufferOut; int sizeOut; if (createVoxelEditMessage(header, 0, 1, &detail, bufferOut, sizeOut)){ AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1); delete bufferOut; } } // Using gyro data, update both view frustum and avatar head position void updateAvatar(float deltaTime) { // Update my avatar's head position from gyros myAvatar.updateHeadFromGyros(deltaTime, &serialPort, &gravity); // Grab latest readings from the gyros float measuredPitchRate = serialPort.getLastPitchRate(); float measuredYawRate = serialPort.getLastYawRate(); // Update gyro-based mouse (X,Y on screen) const float MIN_MOUSE_RATE = 1.0; const float HORIZONTAL_PIXELS_PER_DEGREE = 2880.f / 45.f; const float VERTICAL_PIXELS_PER_DEGREE = 1800.f / 30.f; if (powf(measuredYawRate * measuredYawRate + measuredPitchRate * measuredPitchRate, 0.5) > MIN_MOUSE_RATE) { headMouseX += measuredYawRate * HORIZONTAL_PIXELS_PER_DEGREE * deltaTime; headMouseY -= measuredPitchRate * VERTICAL_PIXELS_PER_DEGREE * deltaTime; } headMouseX = max(headMouseX, 0); headMouseX = min(headMouseX, ::screenWidth); headMouseY = max(headMouseY, 0); headMouseY = min(headMouseY, ::screenHeight); // Update head and body pitch and yaw based on measured gyro rates if (::gyroLook) { // Render Yaw float renderYawSpring = fabs(headMouseX - ::screenWidth / 2.f) / (::screenWidth / 2.f); const float RENDER_YAW_MULTIPLY = 4.f; myAvatar.setRenderYaw((1.f - renderYawSpring * deltaTime) * myAvatar.getRenderYaw() + renderYawSpring * deltaTime * -myAvatar.getHeadYaw() * RENDER_YAW_MULTIPLY); // Render Pitch float renderPitchSpring = fabs(headMouseY - ::screenHeight / 2.f) / (::screenHeight / 2.f); const float RENDER_PITCH_MULTIPLY = 4.f; myAvatar.setRenderPitch((1.f - renderPitchSpring * deltaTime) * myAvatar.getRenderPitch() + renderPitchSpring * deltaTime * -myAvatar.getHeadPitch() * RENDER_PITCH_MULTIPLY); } if (USING_MOUSE_VIEW_SHIFT) { //make it so that when your mouse hits the edge of the screen, the camera shifts float rightBoundary = (float)WIDTH - MOUSE_VIEW_SHIFT_YAW_MARGIN; float bottomBoundary = (float)HEIGHT - MOUSE_VIEW_SHIFT_PITCH_MARGIN; if (mouseX > rightBoundary) { float f = (mouseX - rightBoundary) / ( (float)WIDTH - rightBoundary); mouseViewShiftYaw += MOUSE_VIEW_SHIFT_RATE * f * deltaTime; if (mouseViewShiftYaw > MOUSE_VIEW_SHIFT_YAW_LIMIT) { mouseViewShiftYaw = MOUSE_VIEW_SHIFT_YAW_LIMIT; } } else if (mouseX < MOUSE_VIEW_SHIFT_YAW_MARGIN) { float f = 1.0 - (mouseX / MOUSE_VIEW_SHIFT_YAW_MARGIN); mouseViewShiftYaw -= MOUSE_VIEW_SHIFT_RATE * f * deltaTime; if (mouseViewShiftYaw < -MOUSE_VIEW_SHIFT_YAW_LIMIT) { mouseViewShiftYaw = -MOUSE_VIEW_SHIFT_YAW_LIMIT; } } if (mouseY < MOUSE_VIEW_SHIFT_PITCH_MARGIN) { float f = 1.0 - (mouseY / MOUSE_VIEW_SHIFT_PITCH_MARGIN); mouseViewShiftPitch += MOUSE_VIEW_SHIFT_RATE * f * deltaTime; if ( mouseViewShiftPitch > MOUSE_VIEW_SHIFT_PITCH_LIMIT ) { mouseViewShiftPitch = MOUSE_VIEW_SHIFT_PITCH_LIMIT; } } else if (mouseY > bottomBoundary) { float f = (mouseY - bottomBoundary) / ((float)HEIGHT - bottomBoundary); mouseViewShiftPitch -= MOUSE_VIEW_SHIFT_RATE * f * deltaTime; if (mouseViewShiftPitch < -MOUSE_VIEW_SHIFT_PITCH_LIMIT) { mouseViewShiftPitch = -MOUSE_VIEW_SHIFT_PITCH_LIMIT; } } } if (OculusManager::isConnected()) { float yaw, pitch, roll; OculusManager::getEulerAngles(yaw, pitch, roll); myAvatar.setHeadYaw(-yaw); myAvatar.setHeadPitch(pitch); myAvatar.setHeadRoll(roll); } // Get audio loudness data from audio input device #ifndef _WIN32 myAvatar.setLoudness(audio.getInputLoudness()); #endif // Update Avatar with latest camera and view frustum data... // NOTE: we get this from the view frustum, to make it simpler, since the // loadViewFrumstum() method will get the correct details from the camera // We could optimize this to not actually load the viewFrustum, since we don't // actually need to calculate the view frustum planes to send these details // to the server. loadViewFrustum(::viewFrustum); myAvatar.setCameraPosition(::viewFrustum.getPosition()); myAvatar.setCameraDirection(::viewFrustum.getDirection()); myAvatar.setCameraUp(::viewFrustum.getUp()); myAvatar.setCameraRight(::viewFrustum.getRight()); myAvatar.setCameraFov(::viewFrustum.getFieldOfView()); myAvatar.setCameraAspectRatio(::viewFrustum.getAspectRatio()); myAvatar.setCameraNearClip(::viewFrustum.getNearClip()); myAvatar.setCameraFarClip(::viewFrustum.getFarClip()); AgentList* agentList = AgentList::getInstance(); if (agentList->getOwnerID() != UNKNOWN_AGENT_ID) { // if I know my ID, send head/hand data to the avatar mixer and voxel server unsigned char broadcastString[200]; unsigned char* endOfBroadcastStringWrite = broadcastString; *(endOfBroadcastStringWrite++) = PACKET_HEADER_HEAD_DATA; endOfBroadcastStringWrite += packAgentId(endOfBroadcastStringWrite, agentList->getOwnerID()); endOfBroadcastStringWrite += myAvatar.getBroadcastData(endOfBroadcastStringWrite); const char broadcastReceivers[2] = {AGENT_TYPE_VOXEL, AGENT_TYPE_AVATAR_MIXER}; AgentList::getInstance()->broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, broadcastReceivers, sizeof(broadcastReceivers)); } // If I'm in paint mode, send a voxel out to VOXEL server agents. if (::paintOn) { glm::vec3 avatarPos = myAvatar.getPosition(); // For some reason, we don't want to flip X and Z here. ::paintingVoxel.x = avatarPos.x / 10.0; ::paintingVoxel.y = avatarPos.y / 10.0; ::paintingVoxel.z = avatarPos.z / 10.0;