diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index dbcb79edc7..dcef05bdf6 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -32,7 +32,7 @@ configure_file(InterfaceConfig.h.in ${PROJECT_BINARY_DIR}/includes/InterfaceConf # grab the implementation and header files from src dirs file(GLOB INTERFACE_SRCS src/*.cpp src/*.h) -foreach(SUBDIR ui) +foreach(SUBDIR ui renderer) file(GLOB SUBDIR_SRCS src/${SUBDIR}/*.cpp src/${SUBDIR}/*.h) set(INTERFACE_SRCS ${INTERFACE_SRCS} ${SUBDIR_SRCS}) endforeach(SUBDIR) diff --git a/interface/resources/shaders/SkyFromAtmosphere.frag b/interface/resources/shaders/SkyFromAtmosphere.frag new file mode 100644 index 0000000000..9f6cc39f1b --- /dev/null +++ b/interface/resources/shaders/SkyFromAtmosphere.frag @@ -0,0 +1,48 @@ +// +// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: +// +// NVIDIA Statement on the Software +// +// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are +// detailed. +// +// No Warranty +// +// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL +// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +// Limitation of Liability +// +// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR +// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT +// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY +// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH +// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS. +// + +// +// Atmospheric scattering fragment shader +// +// Author: Sean O'Neil +// +// Copyright (c) 2004 Sean O'Neil +// + +#version 120 + +uniform vec3 v3LightPos; +uniform float g; +uniform float g2; + +varying vec3 v3Direction; + + +void main (void) +{ + float fCos = dot(v3LightPos, v3Direction) / length(v3Direction); + float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5); + gl_FragColor = gl_Color + fMiePhase * gl_SecondaryColor; + gl_FragColor.a = gl_FragColor.b; +} diff --git a/interface/resources/shaders/SkyFromAtmosphere.vert b/interface/resources/shaders/SkyFromAtmosphere.vert new file mode 100644 index 0000000000..2587d262a2 --- /dev/null +++ b/interface/resources/shaders/SkyFromAtmosphere.vert @@ -0,0 +1,100 @@ +// +// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: +// +// NVIDIA Statement on the Software +// +// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are +// detailed. +// +// No Warranty +// +// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL +// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +// Limitation of Liability +// +// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR +// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT +// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY +// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH +// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS. +// + +// +// Atmospheric scattering vertex shader +// +// Author: Sean O'Neil +// +// Copyright (c) 2004 Sean O'Neil +// + +#version 120 + +uniform vec3 v3CameraPos; // The camera's current position +uniform vec3 v3LightPos; // The direction vector to the light source +uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels +uniform float fInnerRadius; // The inner (planetary) radius +uniform float fKrESun; // Kr * ESun +uniform float fKmESun; // Km * ESun +uniform float fKr4PI; // Kr * 4 * PI +uniform float fKm4PI; // Km * 4 * PI +uniform float fScale; // 1 / (fOuterRadius - fInnerRadius) +uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found) +uniform float fScaleOverScaleDepth; // fScale / fScaleDepth + +const int nSamples = 2; +const float fSamples = 2.0; + +varying vec3 v3Direction; + + +float scale(float fCos) +{ + float x = 1.0 - fCos; + return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25)))); +} + +void main(void) +{ + // Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere) + vec3 v3Pos = gl_Vertex.xyz; + vec3 v3Ray = v3Pos - v3CameraPos; + float fFar = length(v3Ray); + v3Ray /= fFar; + + // Calculate the ray's starting position, then calculate its scattering offset + vec3 v3Start = v3CameraPos; + float fHeight = length(v3Start); + float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight)); + float fStartAngle = dot(v3Ray, v3Start) / fHeight; + float fStartOffset = fDepth * scale(fStartAngle); + + // Initialize the scattering loop variables + //gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0); + float fSampleLength = fFar / fSamples; + float fScaledLength = fSampleLength * fScale; + vec3 v3SampleRay = v3Ray * fSampleLength; + vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5; + + // Now loop through the sample rays + vec3 v3FrontColor = vec3(0.0, 0.0, 0.0); + for(int i=0; iaddProceduralSounds(inputLeft, BUFFER_LENGTH_SAMPLES); if (inputLeft != NULL) { diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 73ff7f32d1..8f562e1fe6 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -30,6 +30,9 @@ public: void setWalkingState(bool newWalkState); + void setLastAcceleration(glm::vec3 a) { audioData->setLastAcceleration(a); }; + void setLastVelocity(glm::vec3 v) { audioData->setLastVelocity(v); }; + // terminates audio I/O bool terminate(); private: diff --git a/interface/src/AudioData.cpp b/interface/src/AudioData.cpp index 600cfa8d4d..f86af9a06e 100644 --- a/interface/src/AudioData.cpp +++ b/interface/src/AudioData.cpp @@ -28,4 +28,20 @@ AudioData::~AudioData() { delete audioSocket; } +// Take a pointer to the acquired microphone input samples and add procedural sounds +void AudioData::addProceduralSounds(int16_t* inputBuffer, int numSamples) { + const float MAX_AUDIBLE_VELOCITY = 3.0; + const float MIN_AUDIBLE_VELOCITY = 0.1; + const float VOLUME = 200; + float speed = glm::length(_lastVelocity); + if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { + for (int i = 0; i < numSamples; i++) { + inputBuffer[i] += (int16_t) ((randFloat() - 0.5f) * VOLUME * speed) ; + } + } + + return; +} + + #endif diff --git a/interface/src/AudioData.h b/interface/src/AudioData.h index 520291e3e6..bc545031d9 100644 --- a/interface/src/AudioData.h +++ b/interface/src/AudioData.h @@ -39,6 +39,17 @@ class AudioData { bool mixerLoopbackFlag; bool playWalkSound; + + // Added avatar acceleration and velocity for procedural effects sounds from client + void setLastVelocity(glm::vec3 v) { _lastVelocity = v; }; + void setLastAcceleration(glm::vec3 a) { _lastAcceleration = a; }; + void addProceduralSounds(int16_t* inputBuffer, int numSamples); + + private: + glm::vec3 _lastVelocity; + glm::vec3 _lastAcceleration; + + }; #endif /* defined(__interface__AudioData__) */ diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 32f1960f9b..1b0aac8838 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -262,32 +262,38 @@ void Avatar::reset() { _head.leanForward = _head.leanSideways = 0; } -// this pertains to moving the head with the glasses -// Using serial data, update avatar/render position and angles + +// Update avatar head rotation with sensor data void Avatar::UpdateGyros(float frametime, SerialInterface* serialInterface, glm::vec3* gravity) { - float measured_pitch_rate = 0.0f; - float measured_roll_rate = 0.0f; + float measuredPitchRate = 0.0f; + float measuredRollRate = 0.0f; + float measuredYawRate = 0.0f; + if (serialInterface->active && USING_INVENSENSE_MPU9150) { - measured_pitch_rate = serialInterface->getLastPitch(); - _head.yawRate = serialInterface->getLastYaw(); - measured_roll_rate = -1 * serialInterface->getLastRoll(); + measuredPitchRate = serialInterface->getLastPitchRate(); + measuredYawRate = serialInterface->getLastYawRate(); + measuredRollRate = serialInterface->getLastRollRate(); } else { - measured_pitch_rate = serialInterface->getRelativeValue(HEAD_PITCH_RATE); - _head.yawRate = serialInterface->getRelativeValue(HEAD_YAW_RATE); - measured_roll_rate = serialInterface->getRelativeValue(HEAD_ROLL_RATE); + measuredPitchRate = serialInterface->getRelativeValue(HEAD_PITCH_RATE); + measuredYawRate = serialInterface->getRelativeValue(HEAD_YAW_RATE); + measuredRollRate = serialInterface->getRelativeValue(HEAD_ROLL_RATE); } // Update avatar head position based on measured gyro rates + const float MAX_PITCH = 45; + const float MIN_PITCH = -45; + const float MAX_YAW = 85; + const float MIN_YAW = -85; + const float MAX_ROLL = 50; + const float MIN_ROLL = -50; - if ((_headPitch < HEAD_MAX_PITCH) && (_headPitch > HEAD_MIN_PITCH)) { - addHeadPitch(measured_pitch_rate * -HEAD_ROTATION_SCALE * frametime); - } - - addHeadRoll(measured_roll_rate * HEAD_ROLL_SCALE * frametime); + addHeadPitch(measuredPitchRate * frametime); + addHeadYaw(measuredYawRate * frametime); + addHeadRoll(measuredRollRate * frametime); - if ((_headYaw < HEAD_MAX_YAW) && (_headYaw > HEAD_MIN_YAW)) { - addHeadYaw(_head.yawRate * HEAD_ROTATION_SCALE * frametime); - } + setHeadPitch(glm::clamp(getHeadPitch(), MIN_PITCH, MAX_PITCH)); + setHeadYaw(glm::clamp(getHeadYaw(), MIN_YAW, MAX_YAW)); + setHeadRoll(glm::clamp(getHeadRoll(), MIN_ROLL, MAX_ROLL)); } float Avatar::getAbsoluteHeadYaw() const { @@ -514,6 +520,16 @@ void Avatar::updateHead(float deltaTime) { _headRoll *= (1.0f - DECAY * _head.returnSpringScale * 2 * deltaTime); } + // For invensense gyro, decay only slightly when roughly centered + if (USING_INVENSENSE_MPU9150) { + const float RETURN_RANGE = 5.0; + const float RETURN_STRENGTH = 1.0; + if (fabs(_headPitch) < RETURN_RANGE) { _headPitch *= (1.0f - RETURN_STRENGTH * deltaTime); } + if (fabs(_headYaw) < RETURN_RANGE) { _headYaw *= (1.0f - RETURN_STRENGTH * deltaTime); } + if (fabs(_headRoll) < RETURN_RANGE) { _headRoll *= (1.0f - RETURN_STRENGTH * deltaTime); } + + } + if (_head.noise) { // Move toward new target _headPitch += (_head.pitchTarget - _headPitch) * 10 * deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ; diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index d6602dc395..77aed38eaa 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -108,6 +108,7 @@ public: const glm::vec3& getBodyUpDirection() const { return _orientation.getUp(); }; float getSpeed() const { return _speed; }; + const glm::vec3& getVelocity() const { return _velocity; }; float getGirth(); float getHeight(); diff --git a/interface/src/Environment.cpp b/interface/src/Environment.cpp new file mode 100644 index 0000000000..a84a90adad --- /dev/null +++ b/interface/src/Environment.cpp @@ -0,0 +1,117 @@ +// +// Environment.cpp +// interface +// +// Created by Andrzej Kapolka on 5/6/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. + +#include + +#include + +#include "Camera.h" +#include "Environment.h" +#include "renderer/ProgramObject.h" +#include "renderer/ShaderObject.h" +#include "world.h" + +void Environment::init() { + switchToResourcesParentIfRequired(); + _skyFromAtmosphereProgram = createSkyProgram("Atmosphere", _skyFromAtmosphereUniformLocations); + _skyFromSpaceProgram = createSkyProgram("Space", _skyFromSpaceUniformLocations); +} + +void Environment::renderAtmosphere(Camera& camera) { + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glTranslatef(getAtmosphereCenter().x, getAtmosphereCenter().y, getAtmosphereCenter().z); + + // use the camera distance to reset the near and far distances to keep the atmosphere in the frustum + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + + float projection[16]; + glGetFloatv(GL_PROJECTION_MATRIX, projection); + glm::vec3 relativeCameraPos = camera.getPosition() - getAtmosphereCenter(); + float height = glm::length(relativeCameraPos); + float near = camera.getNearClip(), far = height + getAtmosphereOuterRadius(); + projection[10] = (far + near) / (near - far); + projection[14] = (2.0f * far * near) / (near - far); + glLoadMatrixf(projection); + + // use the appropriate shader depending on whether we're inside or outside + ProgramObject* program; + int* locations; + if (height < getAtmosphereOuterRadius()) { + program = _skyFromAtmosphereProgram; + locations = _skyFromAtmosphereUniformLocations; + + } else { + program = _skyFromSpaceProgram; + locations = _skyFromSpaceUniformLocations; + } + + // the constants here are from Sean O'Neil's GPU Gems entry + // (http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html), GameEngine.cpp + program->bind(); + program->setUniform(locations[CAMERA_POS_LOCATION], relativeCameraPos); + glm::vec3 lightDirection = glm::normalize(getSunLocation()); + program->setUniform(locations[LIGHT_POS_LOCATION], lightDirection); + program->setUniform(locations[INV_WAVELENGTH_LOCATION], + 1 / powf(getScatteringWavelengths().r, 4.0f), + 1 / powf(getScatteringWavelengths().g, 4.0f), + 1 / powf(getScatteringWavelengths().b, 4.0f)); + program->setUniform(locations[CAMERA_HEIGHT2_LOCATION], height * height); + program->setUniform(locations[OUTER_RADIUS_LOCATION], getAtmosphereOuterRadius()); + program->setUniform(locations[OUTER_RADIUS2_LOCATION], getAtmosphereOuterRadius() * getAtmosphereOuterRadius()); + program->setUniform(locations[INNER_RADIUS_LOCATION], getAtmosphereInnerRadius()); + program->setUniform(locations[KR_ESUN_LOCATION], getRayleighScattering() * getSunBrightness()); + program->setUniform(locations[KM_ESUN_LOCATION], getMieScattering() * getSunBrightness()); + program->setUniform(locations[KR_4PI_LOCATION], getRayleighScattering() * 4.0f * PIf); + program->setUniform(locations[KM_4PI_LOCATION], getMieScattering() * 4.0f * PIf); + program->setUniform(locations[SCALE_LOCATION], 1.0f / (getAtmosphereOuterRadius() - getAtmosphereInnerRadius())); + program->setUniform(locations[SCALE_DEPTH_LOCATION], 0.25f); + program->setUniform(locations[SCALE_OVER_SCALE_DEPTH_LOCATION], + (1.0f / (getAtmosphereOuterRadius() - getAtmosphereInnerRadius())) / 0.25f); + program->setUniform(locations[G_LOCATION], -0.990f); + program->setUniform(locations[G2_LOCATION], -0.990f * -0.990f); + + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glutSolidSphere(getAtmosphereOuterRadius(), 100, 50); + glDepthMask(GL_TRUE); + + program->release(); + + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} + +ProgramObject* Environment::createSkyProgram(const char* from, int* locations) { + ProgramObject* program = new ProgramObject(); + QByteArray prefix = QByteArray("resources/shaders/SkyFrom") + from; + program->attachFromSourceFile(GL_VERTEX_SHADER_ARB, prefix + ".vert"); + program->attachFromSourceFile(GL_FRAGMENT_SHADER_ARB, prefix + ".frag"); + program->link(); + + locations[CAMERA_POS_LOCATION] = program->getUniformLocation("v3CameraPos"); + locations[LIGHT_POS_LOCATION] = program->getUniformLocation("v3LightPos"); + locations[INV_WAVELENGTH_LOCATION] = program->getUniformLocation("v3InvWavelength"); + locations[CAMERA_HEIGHT2_LOCATION] = program->getUniformLocation("fCameraHeight2"); + locations[OUTER_RADIUS_LOCATION] = program->getUniformLocation("fOuterRadius"); + locations[OUTER_RADIUS2_LOCATION] = program->getUniformLocation("fOuterRadius2"); + locations[INNER_RADIUS_LOCATION] = program->getUniformLocation("fInnerRadius"); + locations[KR_ESUN_LOCATION] = program->getUniformLocation("fKrESun"); + locations[KM_ESUN_LOCATION] = program->getUniformLocation("fKmESun"); + locations[KR_4PI_LOCATION] = program->getUniformLocation("fKr4PI"); + locations[KM_4PI_LOCATION] = program->getUniformLocation("fKm4PI"); + locations[SCALE_LOCATION] = program->getUniformLocation("fScale"); + locations[SCALE_DEPTH_LOCATION] = program->getUniformLocation("fScaleDepth"); + locations[SCALE_OVER_SCALE_DEPTH_LOCATION] = program->getUniformLocation("fScaleOverScaleDepth"); + locations[G_LOCATION] = program->getUniformLocation("g"); + locations[G2_LOCATION] = program->getUniformLocation("g2"); + + return program; +} diff --git a/interface/src/Environment.h b/interface/src/Environment.h new file mode 100644 index 0000000000..9c68b5c3e5 --- /dev/null +++ b/interface/src/Environment.h @@ -0,0 +1,55 @@ +// +// Environment.h +// interface +// +// Created by Andrzej Kapolka on 5/6/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__Environment__ +#define __interface__Environment__ + +#include "EnvironmentData.h" +#include "InterfaceConfig.h" + +class Camera; +class ProgramObject; + +class Environment : public EnvironmentData { +public: + + void init(); + void renderAtmosphere(Camera& camera); + +private: + + ProgramObject* createSkyProgram(const char* from, int* locations); + + ProgramObject* _skyFromAtmosphereProgram; + ProgramObject* _skyFromSpaceProgram; + + enum { + CAMERA_POS_LOCATION, + LIGHT_POS_LOCATION, + INV_WAVELENGTH_LOCATION, + CAMERA_HEIGHT2_LOCATION, + OUTER_RADIUS_LOCATION, + OUTER_RADIUS2_LOCATION, + INNER_RADIUS_LOCATION, + KR_ESUN_LOCATION, + KM_ESUN_LOCATION, + KR_4PI_LOCATION, + KM_4PI_LOCATION, + SCALE_LOCATION, + SCALE_DEPTH_LOCATION, + SCALE_OVER_SCALE_DEPTH_LOCATION, + G_LOCATION, + G2_LOCATION, + LOCATION_COUNT + }; + + int _skyFromAtmosphereUniformLocations[LOCATION_COUNT]; + int _skyFromSpaceUniformLocations[LOCATION_COUNT]; +}; + +#endif /* defined(__interface__Environment__) */ diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index 8929dbb2f5..692069e4be 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -173,12 +173,12 @@ void SerialInterface::renderLevels(int width, int height) { const int LEVEL_CORNER_X = 10; const int LEVEL_CORNER_Y = 200; - // Draw the text values - sprintf(val, "Yaw %d", _lastYaw); + // Draw the numeric degree/sec values from the gyros + sprintf(val, "Yaw %4.1f", _lastYawRate); drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y, 0.10, 0, 1.0, 1, val, 0, 1, 0); - sprintf(val, "Pitch %d", _lastPitch); + sprintf(val, "Pitch %4.1f", _lastPitchRate); drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 15, 0.10, 0, 1.0, 1, val, 0, 1, 0); - sprintf(val, "Roll %d", _lastRoll); + sprintf(val, "Roll %4.1f", _lastRollRate); drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 30, 0.10, 0, 1.0, 1, val, 0, 1, 0); // Draw the levels as horizontal lines @@ -187,11 +187,11 @@ void SerialInterface::renderLevels(int width, int height) { glColor4f(1, 1, 1, 1); glBegin(GL_LINES); glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y - 3); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _lastYaw, LEVEL_CORNER_Y - 3); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _lastYawRate, LEVEL_CORNER_Y - 3); glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 12); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _lastPitch, LEVEL_CORNER_Y + 12); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _lastPitchRate, LEVEL_CORNER_Y + 12); glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 27); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _lastRoll, LEVEL_CORNER_Y + 27); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _lastRollRate, LEVEL_CORNER_Y + 27); glEnd(); // Draw green vertical centerline glColor4f(0, 1, 0, 0.5); @@ -238,9 +238,20 @@ void SerialInterface::readData() { write(_serialDescriptor, "RD684306\n", 9); read(_serialDescriptor, gyroBuffer, 20); - convertHexToInt(gyroBuffer + 6, _lastYaw); - convertHexToInt(gyroBuffer + 10, _lastRoll); - convertHexToInt(gyroBuffer + 14, _lastPitch); + int rollRate, yawRate, pitchRate; + + convertHexToInt(gyroBuffer + 6, rollRate); + convertHexToInt(gyroBuffer + 10, yawRate); + convertHexToInt(gyroBuffer + 14, pitchRate); + + // Convert the integer rates to floats + const float LSB_TO_DEGREES_PER_SECOND = 1.f / 16.4f; // From MPU-9150 register map, 2000 deg/sec. + const float PITCH_BIAS = 2.0; // Strangely, there is a small DC bias in the + // invensense pitch reading. Gravity? + + _lastRollRate = (float) rollRate * LSB_TO_DEGREES_PER_SECOND; + _lastYawRate = (float) yawRate * LSB_TO_DEGREES_PER_SECOND; + _lastPitchRate = (float) -pitchRate * LSB_TO_DEGREES_PER_SECOND + PITCH_BIAS; totalSamples++; } else { diff --git a/interface/src/SerialInterface.h b/interface/src/SerialInterface.h index e84fa2ddde..3817ad5cd2 100644 --- a/interface/src/SerialInterface.h +++ b/interface/src/SerialInterface.h @@ -42,9 +42,9 @@ public: void pair(); void readData(); - int getLastYaw() const { return _lastYaw; } - int getLastPitch() const { return _lastPitch; } - int getLastRoll() const { return _lastRoll; } + float getLastYawRate() const { return _lastYawRate; } + float getLastPitchRate() const { return _lastPitchRate; } + float getLastRollRate() const { return _lastRollRate; } int getLED() {return LED;}; int getNumSamples() {return samplesAveraged;}; @@ -69,9 +69,9 @@ private: int totalSamples; timeval lastGoodRead; glm::vec3 gravity; - int _lastYaw; - int _lastPitch; - int _lastRoll; + float _lastYawRate; // Rates are in degrees per second. + float _lastPitchRate; + float _lastRollRate; int _failedOpenAttempts; }; diff --git a/interface/src/Stars.cpp b/interface/src/Stars.cpp index a049269305..e8e0222420 100644 --- a/interface/src/Stars.cpp +++ b/interface/src/Stars.cpp @@ -34,7 +34,7 @@ float Stars::changeLOD(float fraction, float overalloc, float realloc) { return float(_ptrController->changeLOD(fraction, overalloc, realloc)); } -void Stars::render(float fovY, float aspect, float nearZ) { +void Stars::render(float fovY, float aspect, float nearZ, float alpha) { // determine length of screen diagonal from quadrant height and aspect ratio float quadrantHeight = nearZ * tan(angleConvert(fovY) * 0.5f); @@ -46,7 +46,7 @@ void Stars::render(float fovY, float aspect, float nearZ) { // pull the modelview matrix off the GL stack glm::mat4 view; glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view)); - _ptrController->render(fovDiagonal, aspect, glm::affineInverse(view)); + _ptrController->render(fovDiagonal, aspect, glm::affineInverse(view), alpha); } diff --git a/interface/src/Stars.h b/interface/src/Stars.h index caca215444..7088bee36e 100644 --- a/interface/src/Stars.h +++ b/interface/src/Stars.h @@ -37,7 +37,7 @@ class Stars { // Renders the starfield from a local viewer's perspective. // The parameters specifiy the field of view. // - void render(float fovY, float aspect, float nearZ); + void render(float fovY, float aspect, float nearZ, float alpha); // // Sets the resolution for FOV culling. diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 7ed31ec7cc..696c2bf0af 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -63,11 +63,6 @@ void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) setupNewVoxelsForDrawing(); } -void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) { - _tree->createSphere(r, xc, yc, zc, s, solid, wantColorRandomizer); - setupNewVoxelsForDrawing(); -} - long int VoxelSystem::getVoxelsCreated() { return _tree->voxelsCreated; } @@ -144,22 +139,22 @@ void VoxelSystem::setupNewVoxelsForDrawing() { double start = usecTimestampNow(); double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000.0; - if (sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed,SIXTY_FPS_IN_MILLISECONDS)) { + if (sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed, SIXTY_FPS_IN_MILLISECONDS)) { return; // bail early, it hasn't been long enough since the last time we ran } double sinceLastViewCulling = (start - _lastViewCulling) / 1000.0; - // If the view frustum has changed, since last time, then remove nodes that are out of view - if ((sinceLastViewCulling >= VIEW_CULLING_RATE_IN_MILLISECONDS) && hasViewChanged()) { + if ((sinceLastViewCulling >= std::max(_lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)) && hasViewChanged()) { _lastViewCulling = start; removeOutOfView(); + double endViewCulling = usecTimestampNow(); + _lastViewCullingElapsed = (endViewCulling - start) / 1000.0; } if (_tree->isDirty()) { PerformanceWarning warn(_renderWarningsOn, "calling... newTreeToArrays()"); _callsToTreesToArrays++; - if (_alwaysRenderFullVBO) { _voxelsInWriteArrays = 0; // reset our VBO } @@ -176,7 +171,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() { copyWrittenDataToReadArrays(); double end = usecTimestampNow(); - double elapsedmsec = (end - start)/1000.0; + double elapsedmsec = (end - start) / 1000.0; _setupNewVoxelsForDrawingLastFinished = end; _setupNewVoxelsForDrawingLastElapsed = elapsedmsec; } @@ -225,6 +220,11 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { } int VoxelSystem::newway__updateNodeInArray(VoxelNode* node) { + // If we've run out of room, then just bail... + if (_voxelsInWriteArrays >= MAX_VOXELS_PER_SYSTEM) { + return 0; + } + if (node->getShouldRender()) { glm::vec3 startVertex = node->getCorner(); float voxelScale = node->getScale(); @@ -299,7 +299,7 @@ void VoxelSystem::init() { _callsToTreesToArrays = 0; _setupNewVoxelsForDrawingLastFinished = 0; _setupNewVoxelsForDrawingLastElapsed = 0; - _lastViewCulling = 0; + _lastViewCullingElapsed = _lastViewCulling = 0; // When we change voxels representations in the arrays, we'll update this _voxelsDirty = false; @@ -508,6 +508,7 @@ bool VoxelSystem::trueColorizeOperation(VoxelNode* node, void* extraData) { } void VoxelSystem::trueColorize() { + PerformanceWarning warn(true, "trueColorize()",true); _nodeCount = 0; _tree->recurseTreeWithOperation(trueColorizeOperation); printLog("setting true color for %d nodes\n", _nodeCount); @@ -587,17 +588,71 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { setupNewVoxelsForDrawing(); } +// combines the removeOutOfView args into a single class +class removeOutOfViewArgs { +public: + VoxelSystem* thisVoxelSystem; + VoxelNodeBag dontRecurseBag; + unsigned long nodesScanned; + unsigned long nodesRemoved; + unsigned long nodesInside; + unsigned long nodesIntersect; + unsigned long nodesOutside; + + removeOutOfViewArgs(VoxelSystem* voxelSystem) : + thisVoxelSystem(voxelSystem), + dontRecurseBag(), + nodesScanned(0), + nodesRemoved(0), + nodesInside(0), + nodesIntersect(0), + nodesOutside(0) + { } +}; + // "Remove" voxels from the tree that are not in view. We don't actually delete them, // we remove them from the tree and place them into a holding area for later deletion bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) { - VoxelSystem* thisVoxelSystem = (VoxelSystem*) extraData; - _nodeCount++; + removeOutOfViewArgs* args = (removeOutOfViewArgs*)extraData; + + // If our node was previously added to the don't recurse bag, then return false to + // stop the further recursion. This means that the whole node and it's children are + // known to be in view, so don't recurse them + if (args->dontRecurseBag.contains(node)) { + args->dontRecurseBag.remove(node); + return false; // stop recursion + } + + VoxelSystem* thisVoxelSystem = args->thisVoxelSystem; + args->nodesScanned++; // Need to operate on our child nodes, so we can remove them for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { VoxelNode* childNode = node->getChildAtIndex(i); - if (childNode && !childNode->isInView(*thisVoxelSystem->_viewFrustum)) { - node->removeChildAtIndex(i); - thisVoxelSystem->_removedVoxels.insert(childNode); + if (childNode) { + ViewFrustum::location inFrustum = childNode->inFrustum(*thisVoxelSystem->_viewFrustum); + switch (inFrustum) { + case ViewFrustum::OUTSIDE: { + args->nodesOutside++; + args->nodesRemoved++; + node->removeChildAtIndex(i); + thisVoxelSystem->_removedVoxels.insert(childNode); + // by removing the child, it will not get recursed! + } break; + case ViewFrustum::INSIDE: { + // if the child node is fully INSIDE the view, then there's no need to recurse it + // because we know all it's children will also be in the view, so we want to + // tell the caller to NOT recurse this child + args->nodesInside++; + args->dontRecurseBag.insert(childNode); + } break; + case ViewFrustum::INTERSECT: { + // if the child node INTERSECTs the view, then we don't want to remove it because + // it is at least partially in view. But we DO want to recurse the children because + // some of them may not be in view... nothing specifically to do, just keep iterating + // the children + args->nodesIntersect++; + } break; + } } } return true; // keep going! @@ -613,7 +668,14 @@ bool VoxelSystem::hasViewChanged() { } void VoxelSystem::removeOutOfView() { - PerformanceWarning warn(_renderWarningsOn, "removeOutOfView()"); // would like to include removedCount, _nodeCount, _removedVoxels.count() - _nodeCount = 0; - _tree->recurseTreeWithOperation(removeOutOfViewOperation,(void*)this); + PerformanceWarning warn(_renderWarningsOn, "removeOutOfView()"); + removeOutOfViewArgs args(this); + _tree->recurseTreeWithOperation(removeOutOfViewOperation,(void*)&args); + + if (_renderWarningsOn) { + printLog("removeOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld bag.count()=%d \n", + args.nodesScanned, args.nodesRemoved, args.nodesInside, + args.nodesIntersect, args.nodesOutside, args.dontRecurseBag.count() + ); + } } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 97d5fa1518..03877206ab 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -42,7 +42,6 @@ public: void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; }; void setCamera(Camera* newCamera) { _camera = newCamera; }; void loadVoxelsFile(const char* fileName,bool wantColorRandomizer); - void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer); long int getVoxelsCreated(); long int getVoxelsColored(); @@ -105,6 +104,7 @@ private: double _setupNewVoxelsForDrawingLastElapsed; double _setupNewVoxelsForDrawingLastFinished; double _lastViewCulling; + double _lastViewCullingElapsed; GLuint _vboVerticesID; GLuint _vboNormalsID; diff --git a/interface/src/main.cpp b/interface/src/main.cpp index c091399f8f..a5a4f55557 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -58,12 +58,15 @@ #include "ui/MenuColumn.h" #include "ui/Menu.h" #include "ui/TextRenderer.h" +#include "renderer/ProgramObject.h" +#include "renderer/ShaderObject.h" #include "Camera.h" #include "Avatar.h" #include #include #include "VoxelSystem.h" +#include "Environment.h" #include "Oscilloscope.h" #include "UDPSocket.h" #include "SerialInterface.h" @@ -120,29 +123,32 @@ char starFile[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; char starCacheFile[] = "cachedStars.txt"; Stars stars; -bool showingVoxels = true; - glm::vec3 box(WORLD_SIZE,WORLD_SIZE,WORLD_SIZE); VoxelSystem voxels; bool wantToKillLocalVoxels = false; +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? + // in the idle loop? (60 FPS is default) -// 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); + +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 statsOn = false; // Whether to show onscreen text overlay with stats -bool starsOn = false; // Whether to display the stars +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 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 @@ -177,7 +183,7 @@ 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 -GLhandleARB oculusProgramID = 0; // The GLSL program containing the distortion shader +ProgramObject* oculusProgram = 0; // The GLSL program containing the distortion shader float oculusDistortionScale = 1.25; // Controls the Oculus field of view // @@ -302,6 +308,8 @@ void init(void) { voxels.setViewerAvatar(&myAvatar); voxels.setCamera(&myCamera); + environment.init(); + handControl.setScreenDimensions(WIDTH, HEIGHT); headMouseX = WIDTH/2; @@ -678,13 +686,31 @@ void renderViewFrustum(ViewFrustum& viewFrustum) { void displaySide(Camera& whichCamera) { glPushMatrix(); - if (::starsOn) { + if (::renderStarsOn) { // should be the first rendering pass - w/o depth buffer / lighting + // compute starfield alpha based on distance from atmosphere + float alpha = 1.0f; + if (::renderAtmosphereOn) { + float height = glm::distance(whichCamera.getPosition(), environment.getAtmosphereCenter()); + if (height < environment.getAtmosphereInnerRadius()) { + alpha = 0.0f; + + } else if (height < environment.getAtmosphereOuterRadius()) { + alpha = (height - environment.getAtmosphereInnerRadius()) / + (environment.getAtmosphereOuterRadius() - environment.getAtmosphereInnerRadius()); + } + } + // finally render the starfield - stars.render(whichCamera.getFieldOfView(), aspectRatio, whichCamera.getNearClip()); + stars.render(whichCamera.getFieldOfView(), aspectRatio, whichCamera.getNearClip(), alpha); } + // draw the sky dome + if (::renderAtmosphereOn) { + environment.renderAtmosphere(whichCamera); + } + glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); @@ -699,23 +725,28 @@ void displaySide(Camera& whichCamera) { drawGroundPlaneGrid(10.f); // Draw voxels - if (showingVoxels) { + if (renderVoxels) { voxels.render(); } - // Render avatars of other agents - AgentList* agentList = AgentList::getInstance(); - agentList->lock(); - for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { - if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { - Avatar *avatar = (Avatar *)agent->getLinkedData(); - avatar->render(0, ::myCamera.getPosition()); + if (::renderAvatarsOn) { + // Render avatars of other agents + AgentList* agentList = AgentList::getInstance(); + agentList->lock(); + for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { + if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { + Avatar *avatar = (Avatar *)agent->getLinkedData(); + avatar->render(0, ::myCamera.getPosition()); + } } + agentList->unlock(); + + // Render my own Avatar + myAvatar.render(::lookingInMirror, ::myCamera.getPosition()); } - agentList->unlock(); // Render the world box - if (!::lookingInMirror && ::statsOn) { render_world_box(); } + if (!::lookingInMirror && ::renderStatsOn) { render_world_box(); } // brad's frustum for debugging if (::frustumOn) renderViewFrustum(::viewFrustum); @@ -806,18 +837,16 @@ void displayOculus(Camera& whichCamera) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - GLhandleARB shaderID = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); - glShaderSourceARB(shaderID, 1, &DISTORTION_FRAGMENT_SHADER, 0); - glCompileShaderARB(shaderID); - ::oculusProgramID = glCreateProgramObjectARB(); - glAttachObjectARB(::oculusProgramID, shaderID); - glLinkProgramARB(::oculusProgramID); - textureLocation = glGetUniformLocationARB(::oculusProgramID, "texture"); - lensCenterLocation = glGetUniformLocationARB(::oculusProgramID, "lensCenter"); - screenCenterLocation = glGetUniformLocationARB(::oculusProgramID, "screenCenter"); - scaleLocation = glGetUniformLocationARB(::oculusProgramID, "scale"); - scaleInLocation = glGetUniformLocationARB(::oculusProgramID, "scaleIn"); - hmdWarpParamLocation = glGetUniformLocationARB(::oculusProgramID, "hmdWarpParam"); + ::oculusProgram = new ProgramObject(); + ::oculusProgram->attachFromSourceCode(GL_FRAGMENT_SHADER_ARB, DISTORTION_FRAGMENT_SHADER); + ::oculusProgram->link(); + + textureLocation = ::oculusProgram->getUniformLocation("texture"); + lensCenterLocation = ::oculusProgram->getUniformLocation("lensCenter"); + screenCenterLocation = ::oculusProgram->getUniformLocation("screenCenter"); + scaleLocation = ::oculusProgram->getUniformLocation("scale"); + scaleInLocation = ::oculusProgram->getUniformLocation("scaleIn"); + hmdWarpParamLocation = ::oculusProgram->getUniformLocation("hmdWarpParam"); } else { glBindTexture(GL_TEXTURE_2D, ::oculusTextureID); @@ -837,13 +866,13 @@ void displayOculus(Camera& whichCamera) { glDisable(GL_BLEND); glEnable(GL_TEXTURE_2D); - glUseProgramObjectARB(::oculusProgramID); - glUniform1iARB(textureLocation, 0); - glUniform2fARB(lensCenterLocation, 0.287994, 0.5); // see SDK docs, p. 29 - glUniform2fARB(screenCenterLocation, 0.25, 0.5); - glUniform2fARB(scaleLocation, 0.25 * scaleFactor, 0.5 * scaleFactor * aspectRatio); - glUniform2fARB(scaleInLocation, 4, 2 / aspectRatio); - glUniform4fARB(hmdWarpParamLocation, 1.0, 0.22, 0.24, 0); + ::oculusProgram->bind(); + ::oculusProgram->setUniform(textureLocation, 0); + ::oculusProgram->setUniform(lensCenterLocation, 0.287994, 0.5); // see SDK docs, p. 29 + ::oculusProgram->setUniform(screenCenterLocation, 0.25, 0.5); + ::oculusProgram->setUniform(scaleLocation, 0.25 * scaleFactor, 0.5 * scaleFactor * aspectRatio); + ::oculusProgram->setUniform(scaleInLocation, 4, 2 / aspectRatio); + ::oculusProgram->setUniform(hmdWarpParamLocation, 1.0, 0.22, 0.24, 0); glColor3f(1, 0, 1); glBegin(GL_QUADS); @@ -857,8 +886,8 @@ void displayOculus(Camera& whichCamera) { glVertex2f(0, HEIGHT); glEnd(); - glUniform2fARB(lensCenterLocation, 0.787994, 0.5); - glUniform2fARB(screenCenterLocation, 0.75, 0.5); + ::oculusProgram->setUniform(lensCenterLocation, 0.787994, 0.5); + ::oculusProgram->setUniform(screenCenterLocation, 0.75, 0.5); glBegin(GL_QUADS); glTexCoord2f(0.5, 0); @@ -874,7 +903,7 @@ void displayOculus(Camera& whichCamera) { glEnable(GL_BLEND); glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); - glUseProgramObjectARB(0); + ::oculusProgram->release(); glPopMatrix(); } @@ -895,7 +924,7 @@ void displayOverlay() { //noiseTest(WIDTH, HEIGHT); - if (displayHeadMouse && !::lookingInMirror && statsOn) { + if (displayHeadMouse && !::lookingInMirror && renderStatsOn) { // Display small target box at center or head mouse target that can also be used to measure LOD glColor3f(1.0, 1.0, 1.0); glDisable(GL_LINE_SMOOTH); @@ -917,7 +946,7 @@ void displayOverlay() { glLineWidth(1.0f); glPointSize(1.0f); - if (::statsOn) { displayStats(); } + if (::renderStatsOn) { displayStats(); } if (::logOn) { logger.render(WIDTH, HEIGHT); } // Show menu @@ -1202,13 +1231,23 @@ int setFullscreen(int state) { } int setVoxels(int state) { - return setValue(state, &::showingVoxels); + return setValue(state, &::renderVoxels); } int setStars(int state) { - return setValue(state, &::starsOn); + return setValue(state, &::renderStarsOn); } +int setAtmosphere(int state) { + return setValue(state, &::renderAtmosphereOn); +} + +int setRenderAvatars(int state) { + return setValue(state, &::renderAvatarsOn); +} + + + int setOculus(int state) { bool wasOn = ::oculusOn; int value = setValue(state, &::oculusOn); @@ -1219,7 +1258,7 @@ int setOculus(int state) { } int setStats(int state) { - return setValue(state, &::statsOn); + return setValue(state, &::renderStatsOn); } int setMenu(int state) { @@ -1354,6 +1393,8 @@ void initMenu() { menuColumnRender = menu.addColumn("Render"); menuColumnRender->addRow("Voxels (V)", setVoxels); menuColumnRender->addRow("Stars (*)", setStars); + menuColumnRender->addRow("Atmosphere (A)", setAtmosphere); + menuColumnRender->addRow("Avatars", setRenderAvatars); menuColumnRender->addRow("Oculus (o)", setOculus); // Tools @@ -1432,23 +1473,6 @@ void setupPaintingVoxel() { shiftPaintingColor(); } -void addRandomSphere(bool wantColorRandomizer) { - float r = randFloatInRange(0.05,0.1); - float xc = randFloatInRange(r,(1-r)); - float yc = randFloatInRange(r,(1-r)); - float zc = randFloatInRange(r,(1-r)); - float s = 0.001; // size of voxels to make up surface of sphere - bool solid = false; - - printLog("random sphere\n"); - printLog("radius=%f\n",r); - printLog("xc=%f\n",xc); - printLog("yc=%f\n",yc); - printLog("zc=%f\n",zc); - - voxels.createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer); -} - const float KEYBOARD_YAW_RATE = 0.8; const float KEYBOARD_PITCH_RATE = 0.6; const float KEYBOARD_STRAFE_RATE = 0.03; @@ -1533,9 +1557,10 @@ void key(unsigned char k, int x, int y) { // Process keypresses if (k == 'q' || k == 'Q') ::terminate(); - if (k == '/') ::statsOn = !::statsOn; // toggle stats - if (k == '*') ::starsOn = !::starsOn; // toggle stars - if (k == 'V' || k == 'v') ::showingVoxels = !::showingVoxels; // toggle voxels + if (k == '/') ::renderStatsOn = !::renderStatsOn; // toggle stats + if (k == '*') ::renderStarsOn = !::renderStarsOn; // toggle stars + if (k == 'V' || k == 'v') ::renderVoxels = !::renderVoxels; // toggle voxels + if (k == 'A') ::renderAtmosphereOn = !::renderAtmosphereOn; if (k == 'F') ::frustumOn = !::frustumOn; // toggle view frustum debugging if (k == 'C') ::cameraFrustum = !::cameraFrustum; // toggle which frustum to look at if (k == 'O' || k == 'G') setFrustumOffset(MENU_ROW_PICKED); // toggle view frustum offset debugging @@ -1629,6 +1654,9 @@ void* networkReceive(void* args) { case PACKET_HEADER_ERASE_VOXEL: voxels.parseData(incomingPacket, bytesReceived); break; + case PACKET_HEADER_ENVIRONMENT_DATA: + environment.parseData(incomingPacket, bytesReceived); + break; case PACKET_HEADER_BULK_AVATAR_DATA: AgentList::getInstance()->processBulkAgentData(&senderAddress, incomingPacket, @@ -1674,6 +1702,7 @@ void idle(void) { handControl.stop(); } + // Read serial port interface devices if (serialPort.active && USING_INVENSENSE_MPU9150) { serialPort.readData(); } @@ -1699,7 +1728,11 @@ void idle(void) { myAvatar.setGravity(getGravity(myAvatar.getPosition())); myAvatar.simulate(deltaTime); - + + // Update audio stats for procedural sounds + audio.setLastAcceleration(myAvatar.getThrust()); + audio.setLastVelocity(myAvatar.getVelocity()); + glutPostRedisplay(); lastTimeIdle = check; } @@ -1733,6 +1766,7 @@ void reshape(int width, int height) { glBindTexture(GL_TEXTURE_2D, 0); } } else { + camera.setAspectRatio(aspectRatio); camera.setFieldOfView(fov = 60); } diff --git a/interface/src/renderer/ProgramObject.cpp b/interface/src/renderer/ProgramObject.cpp new file mode 100644 index 0000000000..d2346bf3b3 --- /dev/null +++ b/interface/src/renderer/ProgramObject.cpp @@ -0,0 +1,119 @@ +// +// ProgramObject.cpp +// interface +// +// Created by Andrzej Kapolka on 5/7/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. + +#include "ProgramObject.h" +#include "ShaderObject.h" + +ProgramObject::ProgramObject() : _handle(glCreateProgramObjectARB()) { +} + +ProgramObject::~ProgramObject() { + glDeleteObjectARB(_handle); +} + +void ProgramObject::attach(ShaderObject* shader) { + glAttachObjectARB(_handle, shader->getHandle()); +} + +bool ProgramObject::attachFromSourceCode(int type, const char* source) { + ShaderObject* shader = new ShaderObject(type); + if (shader->compileSourceCode(source)) { + attach(shader); + return true; + + } else { + delete shader; + return false; + } +} + +bool ProgramObject::attachFromSourceFile(int type, const char* filename) { + ShaderObject* shader = new ShaderObject(type); + if (shader->compileSourceFile(filename)) { + attach(shader); + return true; + + } else { + delete shader; + return false; + } +} + +bool ProgramObject::link() { + glLinkProgramARB(_handle); + int status; + glGetObjectParameterivARB(_handle, GL_OBJECT_LINK_STATUS_ARB, &status); + return status; +} + +QByteArray ProgramObject::getLog() const { + int length; + glGetObjectParameterivARB(_handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); + QByteArray log(length, 0); + glGetInfoLogARB(_handle, length, 0, log.data()); + return log; +} + +void ProgramObject::bind() const { + glUseProgramObjectARB(_handle); +} + +void ProgramObject::release() const { + glUseProgramObjectARB(0); +} + +int ProgramObject::getUniformLocation(const char* name) const { + return glGetUniformLocationARB(_handle, name); +} + +void ProgramObject::setUniform(int location, int value) { + glUniform1iARB(location, value); +} + +void ProgramObject::setUniform(const char* name, int value) { + setUniform(getUniformLocation(name), value); +} + +void ProgramObject::setUniform(int location, float value) { + glUniform1fARB(location, value); +} + +void ProgramObject::setUniform(const char* name, float value) { + setUniform(getUniformLocation(name), value); +} + +void ProgramObject::setUniform(int location, float x, float y) { + glUniform2fARB(location, x, y); +} + +void ProgramObject::setUniform(const char* name, float x, float y) { + setUniform(getUniformLocation(name), x, y); +} + +void ProgramObject::setUniform(int location, const glm::vec3& value) { + glUniform3fARB(location, value.x, value.y, value.z); +} + +void ProgramObject::setUniform(const char* name, const glm::vec3& value) { + setUniform(getUniformLocation(name), value); +} + +void ProgramObject::setUniform(int location, float x, float y, float z) { + glUniform3fARB(location, x, y, z); +} + +void ProgramObject::setUniform(const char* name, float x, float y, float z) { + setUniform(getUniformLocation(name), x, y, z); +} + +void ProgramObject::setUniform(int location, float x, float y, float z, float w) { + glUniform4fARB(location, x, y, z, w); +} + +void ProgramObject::setUniform(const char* name, float x, float y, float z, float w) { + setUniform(getUniformLocation(name), x, y, z, w); +} diff --git a/interface/src/renderer/ProgramObject.h b/interface/src/renderer/ProgramObject.h new file mode 100644 index 0000000000..e46d40c13f --- /dev/null +++ b/interface/src/renderer/ProgramObject.h @@ -0,0 +1,66 @@ +// +// ProgramObject.h +// interface +// +// Created by Andrzej Kapolka on 5/7/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__ProgramObject__ +#define __interface__ProgramObject__ + +#include + +#include + +#include "InterfaceConfig.h" + +class ShaderObject; + +class ProgramObject { +public: + + ProgramObject(); + ~ProgramObject(); + + GLhandleARB getHandle() const { return _handle; } + + void attach(ShaderObject* shader); + bool attachFromSourceCode(int type, const char* source); + bool attachFromSourceFile(int type, const char* filename); + + bool link(); + + QByteArray getLog() const; + + void bind() const; + void release() const; + + int getUniformLocation(const char* name) const; + + void setUniform(int location, int value); + void setUniform(const char* name, int value); + + void setUniform(int location, float value); + void setUniform(const char* name, float value); + + void setUniform(int location, float x, float y); + void setUniform(const char* name, float x, float y); + + void setUniform(int location, const glm::vec3& value); + void setUniform(const char* name, const glm::vec3& value); + + void setUniform(int location, float x, float y, float z); + void setUniform(const char* name, float x, float y, float z); + + void setUniform(int location, float x, float y, float z, float w); + void setUniform(const char* name, float x, float y, float z, float w); + +private: + + Q_DISABLE_COPY(ProgramObject) + + GLhandleARB _handle; +}; + +#endif /* defined(__interface__ProgramObject__) */ diff --git a/interface/src/renderer/ShaderObject.cpp b/interface/src/renderer/ShaderObject.cpp new file mode 100644 index 0000000000..d6c1e7ced4 --- /dev/null +++ b/interface/src/renderer/ShaderObject.cpp @@ -0,0 +1,39 @@ +// +// ShaderObject.cpp +// interface +// +// Created by Andrzej Kapolka on 5/7/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. + +#include + +#include "ShaderObject.h" + +ShaderObject::ShaderObject(int type) + : _handle(glCreateShaderObjectARB(type)) { +} + +ShaderObject::~ShaderObject() { + glDeleteObjectARB(_handle); +} + +bool ShaderObject::compileSourceCode(const char* data) { + glShaderSourceARB(_handle, 1, &data, 0); + glCompileShaderARB(_handle); + int status; + glGetObjectParameterivARB(_handle, GL_OBJECT_COMPILE_STATUS_ARB, &status); + return status; +} + +bool ShaderObject::compileSourceFile(const char* filename) { + QFile file(filename); + return file.open(QIODevice::ReadOnly) && compileSourceCode(file.readAll().constData()); +} + +QByteArray ShaderObject::getLog() const { + int length; + glGetObjectParameterivARB(_handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); + QByteArray log(length, 0); + glGetInfoLogARB(_handle, length, 0, log.data()); + return log; +} diff --git a/interface/src/renderer/ShaderObject.h b/interface/src/renderer/ShaderObject.h new file mode 100644 index 0000000000..297650a40f --- /dev/null +++ b/interface/src/renderer/ShaderObject.h @@ -0,0 +1,36 @@ +// +// ShaderObject.h +// interface +// +// Created by Andrzej Kapolka on 5/7/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__ShaderObject__ +#define __interface__ShaderObject__ + +#include + +#include "InterfaceConfig.h" + +class ShaderObject { +public: + + ShaderObject(int type); + ~ShaderObject(); + + GLhandleARB getHandle() const { return _handle; } + + bool compileSourceCode(const char* data); + bool compileSourceFile(const char* filename); + + QByteArray getLog() const; + +private: + + Q_DISABLE_COPY(ShaderObject) + + GLhandleARB _handle; +}; + +#endif /* defined(__interface__ShaderObject__) */ diff --git a/interface/src/starfield/Controller.h b/interface/src/starfield/Controller.h index a9dc52e747..93dc134392 100644 --- a/interface/src/starfield/Controller.h +++ b/interface/src/starfield/Controller.h @@ -361,7 +361,7 @@ namespace starfield { public: - void render(float perspective, float angle, mat4 const& orientation) { + void render(float perspective, float angle, mat4 const& orientation, float alpha) { #if STARFIELD_MULTITHREADING // check out renderer @@ -377,7 +377,7 @@ namespace starfield { #else BrightnessLevel b = _valLodBrightness; #endif - renderer->render(perspective, angle, orientation, b); + renderer->render(perspective, angle, orientation, b, alpha); } #if STARFIELD_MULTITHREADING diff --git a/interface/src/starfield/renderer/Renderer.h b/interface/src/starfield/renderer/Renderer.h index 8e9c45bc78..8a7e4bd6de 100644 --- a/interface/src/starfield/renderer/Renderer.h +++ b/interface/src/starfield/renderer/Renderer.h @@ -13,6 +13,8 @@ #error "This is an implementation file - not intended for direct inclusion." #endif +#include "renderer/ProgramObject.h" + #include "starfield/Config.h" #include "starfield/data/InputVertex.h" #include "starfield/data/BrightnessLevel.h" @@ -70,7 +72,8 @@ namespace starfield { GLint* _arrBatchOffs; GLsizei* _arrBatchCount; GLuint _hndVertexArray; - OGlProgram _objProgram; + ProgramObject _objProgram; + int _alphaLocation; Tiling _objTiling; @@ -123,7 +126,8 @@ namespace starfield { void render(float perspective, float aspect, mat4 const& orientation, - BrightnessLevel minBright) { + BrightnessLevel minBright, + float alpha) { // printLog(" // Stars.cpp: rendering at minimal brightness %d\n", minBright); @@ -186,7 +190,7 @@ namespace starfield { # define matrix matrix_debug #endif this->glBatch(glm::value_ptr(matrix), prepareBatch( - (unsigned*) _arrBatchOffs, _itrOutIndex) ); + (unsigned*) _arrBatchOffs, _itrOutIndex), alpha); #if STARFIELD_DEBUG_CULLING # undef matrix @@ -463,24 +467,26 @@ namespace starfield { GLchar const* const VERTEX_SHADER = "#version 120\n" + "uniform float alpha;\n" "void main(void) {\n" " vec3 c = gl_Color.rgb * 1.0125;\n" " float s = max(1.0, dot(c, c) * 0.7);\n" " gl_Position = ftransform();\n" - " gl_FrontColor= gl_Color;\n" + " gl_FrontColor= gl_Color * alpha;\n" " gl_PointSize = s;\n" "}\n"; - _objProgram.addShader(GL_VERTEX_SHADER, VERTEX_SHADER); + _objProgram.attachFromSourceCode(GL_VERTEX_SHADER, VERTEX_SHADER); GLchar const* const FRAGMENT_SHADER = "#version 120\n" "void main(void) {\n" " gl_FragColor = gl_Color;\n" "}\n"; - _objProgram.addShader(GL_FRAGMENT_SHADER, FRAGMENT_SHADER); + _objProgram.attachFromSourceCode(GL_FRAGMENT_SHADER, FRAGMENT_SHADER); _objProgram.link(); + _alphaLocation = _objProgram.getUniformLocation("alpha"); glGenBuffersARB(1, & _hndVertexArray); } @@ -499,7 +505,7 @@ namespace starfield { glBindBufferARB(GL_ARRAY_BUFFER, 0); } - void glBatch(GLfloat const* matrix, GLsizei n_ranges) { + void glBatch(GLfloat const* matrix, GLsizei n_ranges, float alpha) { // printLog("Stars.cpp: rendering %d-multibatch\n", n_ranges); @@ -527,7 +533,8 @@ namespace starfield { glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); // select shader and vertex array - _objProgram.activate(); + _objProgram.bind(); + _objProgram.setUniform(_alphaLocation, alpha); glBindBufferARB(GL_ARRAY_BUFFER, _hndVertexArray); glInterleavedArrays(GL_C4UB_V3F, sizeof(GpuVertex), 0l); @@ -537,7 +544,7 @@ namespace starfield { // restore state glBindBufferARB(GL_ARRAY_BUFFER, 0); - glUseProgram(0); + _objProgram.release(); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); glDisable(GL_POINT_SMOOTH); glPopMatrix(); diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index 152adc5805..da972e85c2 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -25,6 +25,7 @@ const PACKET_HEADER PACKET_HEADER_ERASE_VOXEL = 'E'; const PACKET_HEADER PACKET_HEADER_VOXEL_DATA = 'V'; const PACKET_HEADER PACKET_HEADER_BULK_AVATAR_DATA = 'X'; const PACKET_HEADER PACKET_HEADER_TRANSMITTER_DATA = 't'; +const PACKET_HEADER PACKET_HEADER_ENVIRONMENT_DATA = 'e'; const PACKET_HEADER PACKET_HEADER_DOMAIN_LIST_REQUEST = 'L'; const PACKET_HEADER PACKET_HEADER_DOMAIN_RFD = 'C'; diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index 5b4d1cc591..87998599aa 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -108,15 +108,16 @@ int PerfStat::DumpStats(char** array) { PerformanceWarning::~PerformanceWarning() { double end = usecTimestampNow(); double elapsedmsec = (end - _start) / 1000.0; - if (_renderWarningsOn && elapsedmsec > 1) { + if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) { if (elapsedmsec > 1000) { double elapsedsec = (end - _start) / 1000000.0; printLog("WARNING! %s took %lf seconds\n", _message, elapsedsec); } else { printLog("WARNING! %s took %lf milliseconds\n", _message, elapsedmsec); } + } else if (_alwaysDisplay) { + printLog("WARNING! %s took %lf milliseconds\n", _message, elapsedmsec); } - }; diff --git a/libraries/shared/src/PerfStat.h b/libraries/shared/src/PerfStat.h index 09d351a11b..8898899960 100644 --- a/libraries/shared/src/PerfStat.h +++ b/libraries/shared/src/PerfStat.h @@ -87,11 +87,13 @@ private: double _start; const char* _message; bool _renderWarningsOn; + bool _alwaysDisplay; public: - PerformanceWarning(bool renderWarnings, const char* message) : + PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false) : _start(usecTimestampNow()), _message(message), - _renderWarningsOn(renderWarnings) { }; + _renderWarningsOn(renderWarnings), + _alwaysDisplay(alwaysDisplay) { }; ~PerformanceWarning(); }; diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 7c8f7f5e9b..1ba8e8ddef 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -170,7 +170,7 @@ bool cmdOptionExists(int argc, const char * argv[],const char* option) { // Complaints: Brad :) #define GUESS_OF_VOXELCODE_SIZE 10 #define MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE 1500 -#define SIZE_OF_COLOR_DATA 3 +#define SIZE_OF_COLOR_DATA sizeof(rgbColor) bool createVoxelEditMessage(unsigned char command, short int sequence, int voxelCount, VoxelDetail* voxelDetails, unsigned char*& bufferOut, int& sizeOut) { @@ -231,27 +231,26 @@ bool createVoxelEditMessage(unsigned char command, short int sequence, unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, unsigned char g, unsigned char b ) { float xTest, yTest, zTest, sTest; - xTest = yTest = zTest = sTest = 0.5; + xTest = yTest = zTest = sTest = 0.5f; // First determine the voxelSize that will properly encode a // voxel of size S. - int voxelSizeInBits = 0; + unsigned int voxelSizeInOctets = 1; while (sTest > s) { sTest /= 2.0; - voxelSizeInBits+=3; + voxelSizeInOctets++; } - unsigned int voxelSizeInBytes = (voxelSizeInBits/8)+1; - unsigned int voxelSizeInOctets = (voxelSizeInBits/3); - unsigned int voxelBufferSize = voxelSizeInBytes+1+3; // 1 for size, 3 for color + unsigned int voxelSizeInBytes = bytesRequiredForCodeLength(voxelSizeInOctets); // (voxelSizeInBits/8)+1; + unsigned int voxelBufferSize = voxelSizeInBytes + sizeof(rgbColor); // 3 for color // allocate our resulting buffer unsigned char* voxelOut = new unsigned char[voxelBufferSize]; - + // first byte of buffer is always our size in octets voxelOut[0]=voxelSizeInOctets; - sTest = 0.5; // reset sTest so we can do this again. + sTest = 0.5f; // reset sTest so we can do this again. unsigned char byte = 0; // we will be adding coding bits here int bitInByteNDX = 0; // keep track of where we are in byte as we go @@ -260,7 +259,7 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, // Now we actually fill out the voxel code while (octetsDone < voxelSizeInOctets) { - if (x > xTest) { + if (x >= xTest) { // byte = (byte << 1) | true; xTest += sTest/2.0; @@ -272,14 +271,14 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, bitInByteNDX++; // If we've reached the last bit of the byte, then we want to copy this byte // into our buffer. And get ready to start on a new byte - if (bitInByteNDX > 7) { + if (bitInByteNDX == 8) { voxelOut[byteNDX]=byte; byteNDX++; bitInByteNDX=0; byte=0; } - if (y > yTest) { + if (y >= yTest) { // byte = (byte << 1) | true; yTest += sTest/2.0; @@ -291,14 +290,14 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, bitInByteNDX++; // If we've reached the last bit of the byte, then we want to copy this byte // into our buffer. And get ready to start on a new byte - if (bitInByteNDX > 7) { + if (bitInByteNDX == 8) { voxelOut[byteNDX]=byte; byteNDX++; bitInByteNDX=0; byte=0; } - if (z > zTest) { + if (z >= zTest) { // byte = (byte << 1) | true; zTest += sTest/2.0; @@ -310,7 +309,7 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, bitInByteNDX++; // If we've reached the last bit of the byte, then we want to copy this byte // into our buffer. And get ready to start on a new byte - if (bitInByteNDX > 7) { + if (bitInByteNDX == 8) { voxelOut[byteNDX]=byte; byteNDX++; bitInByteNDX=0; @@ -323,13 +322,13 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, // If we've got here, and we didn't fill the last byte, we need to zero pad this // byte before we copy it into our buffer. - if (bitInByteNDX > 0 && bitInByteNDX < 7) { + if (bitInByteNDX > 0 && bitInByteNDX < 8) { // Pad the last byte - while (bitInByteNDX <= 7) { + while (bitInByteNDX < 8) { byte = (byte << 1) | false; bitInByteNDX++; } - + // Copy it into our output buffer voxelOut[byteNDX]=byte; byteNDX++; diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 1b40de5448..9d2fcb8799 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -18,6 +18,8 @@ #include #endif +typedef unsigned char rgbColor[3]; + static const float ZERO = 0.0f; static const float ONE = 1.0f; static const float ONE_HALF = 0.5f; diff --git a/libraries/voxels/src/EnvironmentData.cpp b/libraries/voxels/src/EnvironmentData.cpp new file mode 100644 index 0000000000..c08489bf67 --- /dev/null +++ b/libraries/voxels/src/EnvironmentData.cpp @@ -0,0 +1,90 @@ +// +// EnvironmentData.cpp +// interface +// +// Created by Andrzej Kapolka on 5/6/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. + +#include + +#include "EnvironmentData.h" +#include "PacketHeaders.h" + +// initial values from Sean O'Neil's GPU Gems entry (http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html), +// GameEngine.cpp (and the radius of the earth) +EnvironmentData::EnvironmentData() : + _atmosphereCenter(0, -1000, 0), + _atmosphereInnerRadius(1000), + _atmosphereOuterRadius(1025), + _rayleighScattering(0.0025f), + _mieScattering(0.0010f), + _scatteringWavelengths(0.650f, 0.570f, 0.475f), + _sunLocation(1000, 1000, 0), + _sunBrightness(20.0f) { +} + +int EnvironmentData::getBroadcastData(unsigned char* destinationBuffer) const { + unsigned char* bufferStart = destinationBuffer; + + *destinationBuffer++ = PACKET_HEADER_ENVIRONMENT_DATA; + + memcpy(destinationBuffer, &_atmosphereCenter, sizeof(_atmosphereCenter)); + destinationBuffer += sizeof(_atmosphereCenter); + + memcpy(destinationBuffer, &_atmosphereInnerRadius, sizeof(_atmosphereInnerRadius)); + destinationBuffer += sizeof(_atmosphereInnerRadius); + + memcpy(destinationBuffer, &_atmosphereOuterRadius, sizeof(_atmosphereOuterRadius)); + destinationBuffer += sizeof(_atmosphereOuterRadius); + + memcpy(destinationBuffer, &_rayleighScattering, sizeof(_rayleighScattering)); + destinationBuffer += sizeof(_rayleighScattering); + + memcpy(destinationBuffer, &_mieScattering, sizeof(_mieScattering)); + destinationBuffer += sizeof(_mieScattering); + + memcpy(destinationBuffer, &_scatteringWavelengths, sizeof(_scatteringWavelengths)); + destinationBuffer += sizeof(_scatteringWavelengths); + + memcpy(destinationBuffer, &_sunLocation, sizeof(_sunLocation)); + destinationBuffer += sizeof(_sunLocation); + + memcpy(destinationBuffer, &_sunBrightness, sizeof(_sunBrightness)); + destinationBuffer += sizeof(_sunBrightness); + + return destinationBuffer - bufferStart; +} + +int EnvironmentData::parseData(unsigned char* sourceBuffer, int numBytes) { + // increment to push past the packet header + sourceBuffer++; + + unsigned char* startPosition = sourceBuffer; + + memcpy(&_atmosphereCenter, sourceBuffer, sizeof(_atmosphereCenter)); + sourceBuffer += sizeof(_atmosphereCenter); + + memcpy(&_atmosphereInnerRadius, sourceBuffer, sizeof(_atmosphereInnerRadius)); + sourceBuffer += sizeof(_atmosphereInnerRadius); + + memcpy(&_atmosphereOuterRadius, sourceBuffer, sizeof(_atmosphereOuterRadius)); + sourceBuffer += sizeof(_atmosphereOuterRadius); + + memcpy(&_rayleighScattering, sourceBuffer, sizeof(_rayleighScattering)); + sourceBuffer += sizeof(_rayleighScattering); + + memcpy(&_mieScattering, sourceBuffer, sizeof(_mieScattering)); + sourceBuffer += sizeof(_mieScattering); + + memcpy(&_scatteringWavelengths, sourceBuffer, sizeof(_scatteringWavelengths)); + sourceBuffer += sizeof(_scatteringWavelengths); + + memcpy(&_sunLocation, sourceBuffer, sizeof(_sunLocation)); + sourceBuffer += sizeof(_sunLocation); + + memcpy(&_sunBrightness, sourceBuffer, sizeof(_sunBrightness)); + sourceBuffer += sizeof(_sunBrightness); + + return sourceBuffer - startPosition; +} + diff --git a/libraries/voxels/src/EnvironmentData.h b/libraries/voxels/src/EnvironmentData.h new file mode 100644 index 0000000000..b4de3498c6 --- /dev/null +++ b/libraries/voxels/src/EnvironmentData.h @@ -0,0 +1,57 @@ +// +// EnvironmentData.h +// interface +// +// Created by Andrzej Kapolka on 5/6/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__EnvironmentData__ +#define __interface__EnvironmentData__ + +#include + +class EnvironmentData { +public: + + EnvironmentData(); + + void setAtmosphereCenter(const glm::vec3& center) { _atmosphereCenter = center; } + void setAtmosphereInnerRadius(float radius) { _atmosphereInnerRadius = radius; } + void setAtmosphereOuterRadius(float radius) { _atmosphereOuterRadius = radius; } + const glm::vec3& getAtmosphereCenter() const { return _atmosphereCenter; } + float getAtmosphereInnerRadius() const { return _atmosphereInnerRadius; } + float getAtmosphereOuterRadius() const { return _atmosphereOuterRadius; } + + void setRayleighScattering(float scattering) { _rayleighScattering = scattering; } + void setMieScattering(float scattering) { _mieScattering = scattering; } + float getRayleighScattering() const { return _rayleighScattering; } + float getMieScattering() const { return _mieScattering; } + + void setScatteringWavelengths(const glm::vec3& wavelengths) { _scatteringWavelengths = wavelengths; } + const glm::vec3& getScatteringWavelengths() const { return _scatteringWavelengths; } + + void setSunLocation(const glm::vec3& location) { _sunLocation = location; } + void setSunBrightness(float brightness) { _sunBrightness = brightness; } + const glm::vec3& getSunLocation() const { return _sunLocation; } + float getSunBrightness() const { return _sunBrightness; } + + int getBroadcastData(unsigned char* destinationBuffer) const; + int parseData(unsigned char* sourceBuffer, int numBytes); + +private: + + glm::vec3 _atmosphereCenter; + float _atmosphereInnerRadius; + float _atmosphereOuterRadius; + + float _rayleighScattering; + float _mieScattering; + + glm::vec3 _scatteringWavelengths; + + glm::vec3 _sunLocation; + float _sunBrightness; +}; + +#endif /* defined(__interface__EnvironmentData__) */ diff --git a/libraries/voxels/src/SceneUtils.cpp b/libraries/voxels/src/SceneUtils.cpp new file mode 100644 index 0000000000..da92734350 --- /dev/null +++ b/libraries/voxels/src/SceneUtils.cpp @@ -0,0 +1,106 @@ +// +// SceneUtils.cpp +// hifi +// +// Created by Brad Hefta-Gaub on 5/7/2013. +// +// + +#include "SceneUtils.h" +#include + +void addCornersAndAxisLines(VoxelTree* tree) { + // We want our corner voxels to be about 1/2 meter high, and our TREE_SCALE is in meters, so... + float voxelSize = 0.5f / TREE_SCALE; + + // Now some more examples... a little more complex + printf("creating corner points...\n"); + tree->createVoxel(0 , 0 , 0 , voxelSize, 255, 255 ,255); + tree->createVoxel(1.0 - voxelSize, 0 , 0 , voxelSize, 255, 0 ,0 ); + tree->createVoxel(0 , 1.0 - voxelSize, 0 , voxelSize, 0 , 255 ,0 ); + tree->createVoxel(0 , 0 , 1.0 - voxelSize, voxelSize, 0 , 0 ,255); + tree->createVoxel(1.0 - voxelSize, 0 , 1.0 - voxelSize, voxelSize, 255, 0 ,255); + tree->createVoxel(0 , 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 0 , 255 ,255); + tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 0 , voxelSize, 255, 255 ,0 ); + tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 255, 255 ,255); + printf("DONE creating corner points...\n"); + + // Now some more examples... creating some lines using the line primitive + printf("creating voxel lines...\n"); + // We want our line voxels to be about 1/32 meter high, and our TREE_SCALE is in meters, so... + float lineVoxelSize = 1.f / (32 * TREE_SCALE); + rgbColor red = {255, 0, 0}; + rgbColor green = {0, 255, 0}; + rgbColor blue = {0, 0, 255}; + tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 0, 1), lineVoxelSize, blue); + tree->createLine(glm::vec3(0, 0, 0), glm::vec3(1, 0, 0), lineVoxelSize, red); + tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 1, 0), lineVoxelSize, green); + printf("DONE creating lines...\n"); +} + +void addSphereScene(VoxelTree * tree) { + printf("adding sphere scene...\n"); + + // Now some more examples... creating some spheres using the sphere primitive + // We want the smallest unit of our spheres to be about 1/16th of a meter tall + float sphereVoxelSize = 1.f / (8 * TREE_SCALE); + printf("creating spheres... sphereVoxelSize=%f\n",sphereVoxelSize); + + tree->createSphere(0.030625, 0.5, 0.5, (0.25 - 0.06125), sphereVoxelSize, true, NATURAL); + printf("1 spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); + tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), (0.75 - 0.06125), sphereVoxelSize, true, GRADIENT); + printf("2 spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); + tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), 0.06125, sphereVoxelSize, true, RANDOM); + printf("3 spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); + tree->createSphere(0.030625, (0.75 - 0.030625), 0.06125, (0.75 - 0.06125), sphereVoxelSize, true, GRADIENT); + printf("4 spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); + tree->createSphere(0.06125, 0.125, 0.125, (0.75 - 0.125), sphereVoxelSize, true, GRADIENT); + +/** + float radius = 0.0125f; + printf("5 spheres added...\n"); + tree->createSphere(radius, 0.25, radius * 5.0f, 0.25, sphereVoxelSize, true, GRADIENT); + printf("6 spheres added...\n"); + tree->createSphere(radius, 0.125, radius * 5.0f, 0.25, sphereVoxelSize, true, RANDOM); + printf("7 spheres added...\n"); + tree->createSphere(radius, 0.075, radius * 5.0f, 0.25, sphereVoxelSize, true, GRADIENT); + printf("8 spheres added...\n"); + tree->createSphere(radius, 0.05, radius * 5.0f, 0.25, sphereVoxelSize, true, RANDOM); + printf("9 spheres added...\n"); + tree->createSphere(radius, 0.025, radius * 5.0f, 0.25, sphereVoxelSize, true, GRADIENT); + printf("10 spheres added...\n"); +*/ + float largeRadius = 0.1875f; + tree->createSphere(largeRadius, 0.5, 0.5, 0.5, sphereVoxelSize, true, NATURAL); + printf("11 - last large sphere added... largeRadius=%f sphereVoxelSize=%f\n", largeRadius, sphereVoxelSize); + + printf("DONE adding scene of spheres...\n"); +} + +void addSurfaceScene(VoxelTree * tree) { + printf("adding surface scene...\n"); + float voxelSize = 1.f / (8 * TREE_SCALE); + + // color 1= blue, color 2=green + unsigned char r1, g1, b1, r2, g2, b2, red, green, blue; + r1 = r2 = b2 = g1 = 0; + b1 = g2 = 255; + + for (float x = 0.0; x < 1.0; x += voxelSize) { + for (float z = 0.0; z < 1.0; z += voxelSize) { + + glm::vec2 position = glm::vec2(x, z); + float perlin = glm::perlin(position) + .25f * glm::perlin(position * 4.f) + .125f * glm::perlin(position * 16.f); + float gradient = (1.0f + perlin)/ 2.0f; + red = (unsigned char)std::min(255, std::max(0, (int)(r1 + ((r2 - r1) * gradient)))); + green = (unsigned char)std::min(255, std::max(0, (int)(g1 + ((g2 - g1) * gradient)))); + blue = (unsigned char)std::min(255, std::max(0, (int)(b1 + ((b2 - b1) * gradient)))); + + int height = (4 * gradient)+1; // make it at least 4 thick, so we get some averaging + for (int i = 0; i < height; i++) { + tree->createVoxel(x, ((i+1) * voxelSize) , z, voxelSize, red, green, blue); + } + } + } + printf("DONE adding surface scene...\n"); +} diff --git a/libraries/voxels/src/SceneUtils.h b/libraries/voxels/src/SceneUtils.h new file mode 100644 index 0000000000..378382f51f --- /dev/null +++ b/libraries/voxels/src/SceneUtils.h @@ -0,0 +1,20 @@ +// +// SceneUtils.h +// hifi +// +// Created by Brad Hefta-Gaub on 5/7/2013. +// +// + +#ifndef __hifi__SceneUtil__ +#define __hifi__SceneUtil__ + +#include "VoxelTree.h" +#include + +void addCornersAndAxisLines(VoxelTree* tree); +void addSphereScene(VoxelTree * tree); +void addSurfaceScene(VoxelTree * tree); + + +#endif /* defined(__hifi__SceneUtil__) */ diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index 51b04e9640..a107e2f869 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -158,12 +158,12 @@ const char* ViewFrustum::debugPlaneName (int plane) const { } -int ViewFrustum::pointInFrustum(const glm::vec3& point) const { +ViewFrustum::location ViewFrustum::pointInFrustum(const glm::vec3& point) const { //printf("ViewFrustum::pointInFrustum() point=%f,%f,%f\n",point.x,point.y,point.z); //dump(); - int result = INSIDE; + ViewFrustum::location result = INSIDE; for(int i=0; i < 6; i++) { float distance = _planes[i].distance(point); @@ -176,8 +176,8 @@ int ViewFrustum::pointInFrustum(const glm::vec3& point) const { return(result); } -int ViewFrustum::sphereInFrustum(const glm::vec3& center, float radius) const { - int result = INSIDE; +ViewFrustum::location ViewFrustum::sphereInFrustum(const glm::vec3& center, float radius) const { + ViewFrustum::location result = INSIDE; float distance; for(int i=0; i < 6; i++) { distance = _planes[i].distance(center); @@ -190,11 +190,11 @@ int ViewFrustum::sphereInFrustum(const glm::vec3& center, float radius) const { } -int ViewFrustum::boxInFrustum(const AABox& box) const { +ViewFrustum::location ViewFrustum::boxInFrustum(const AABox& box) const { //printf("ViewFrustum::boxInFrustum() box.corner=%f,%f,%f x=%f\n", // box.getCorner().x,box.getCorner().y,box.getCorner().z,box.getSize().x); - int result = INSIDE; + ViewFrustum::location result = INSIDE; for(int i=0; i < 6; i++) { //printf("plane[%d] -- point(%f,%f,%f) normal(%f,%f,%f) d=%f \n",i, diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index 9cf6890609..007654fcf4 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -94,9 +94,9 @@ public: typedef enum {OUTSIDE, INTERSECT, INSIDE} location; - int pointInFrustum(const glm::vec3& point) const; - int sphereInFrustum(const glm::vec3& center, float radius) const; - int boxInFrustum(const AABox& box) const; + ViewFrustum::location pointInFrustum(const glm::vec3& point) const; + ViewFrustum::location sphereInFrustum(const glm::vec3& center, float radius) const; + ViewFrustum::location boxInFrustum(const AABox& box) const; // some frustum comparisons bool matches(const ViewFrustum& compareTo) const; diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 41007a47c7..156a310476 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -14,12 +14,12 @@ #include -const int TREE_SCALE = 100; +const int TREE_SCALE = 128; const int NUMBER_OF_CHILDREN = 8; const int MAX_VOXEL_PACKET_SIZE = 1492; const int MAX_TREE_SLICE_BYTES = 26; -const int MAX_VOXELS_PER_SYSTEM = 250000; +const int MAX_VOXELS_PER_SYSTEM = 200000; const int VERTICES_PER_VOXEL = 24; const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL; const int INDICES_PER_VOXEL = 3 * 12; diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 95e71b2b76..9ee95f1e2a 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -123,7 +123,6 @@ void VoxelNode::setColorFromAverageOfChildren() { colorArray[3]++; } } - nodeColor newColor = { 0, 0, 0, 0}; if (colorArray[3] > 4) { // we need at least 4 colored children to have an average color value @@ -179,9 +178,7 @@ void VoxelNode::setColor(const nodeColor& color) { if (!_falseColored) { memcpy(&_currentColor,&color,sizeof(nodeColor)); } - //if (_shouldRender) { - _isDirty = true; - //} + _isDirty = true; } } #endif @@ -262,6 +259,12 @@ bool VoxelNode::isInView(const ViewFrustum& viewFrustum) const { return inView; } +ViewFrustum::location VoxelNode::inFrustum(const ViewFrustum& viewFrustum) const { + AABox box = _box; // use temporary box so we can scale it + box.scale(TREE_SCALE); + return viewFrustum.boxInFrustum(box); +} + float VoxelNode::distanceToCamera(const ViewFrustum& viewFrustum) const { glm::vec3 center = _box.getCenter() * (float)TREE_SCALE; float distanceToVoxelCenter = sqrtf(powf(viewFrustum.getPosition().x - center.x, 2) + diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 386f95e634..51af8f6379 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -57,6 +57,7 @@ public: bool isColored() const { return (_trueColor[3]==1); }; bool isInView(const ViewFrustum& viewFrustum) const; + ViewFrustum::location inFrustum(const ViewFrustum& viewFrustum) const; float distanceToCamera(const ViewFrustum& viewFrustum) const; bool isLeaf() const; void printDebugDetails(const char* label) const; diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index 9646c2d2fc..20a469dec8 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -82,3 +82,39 @@ VoxelNode* VoxelNodeBag::extract() { } return NULL; } + +bool VoxelNodeBag::contains(VoxelNode* node) { + for (int i = 0; i < _elementsInUse; i++) { + // just compare the pointers... that's good enough + if (_bagElements[i] == node) { + return true; // exit early!! + } + // if we're past where it should be, then it's not here! + if (_bagElements[i] > node) { + return false; + } + } + // if we made it through the entire bag, it's not here! + return false; +} + +void VoxelNodeBag::remove(VoxelNode* node) { + int foundAt = -1; + for (int i = 0; i < _elementsInUse; i++) { + // just compare the pointers... that's good enough + if (_bagElements[i] == node) { + foundAt = i; + break; + } + // if we're past where it should be, then it's not here! + if (_bagElements[i] > node) { + break; + } + } + // if we found it, then we need to remove it.... + if (foundAt != -1) { + memmove(&_bagElements[foundAt], &_bagElements[foundAt + 1], (_elementsInUse - foundAt) * sizeof(VoxelNode*)); + _elementsInUse--; + } +} + diff --git a/libraries/voxels/src/VoxelNodeBag.h b/libraries/voxels/src/VoxelNodeBag.h index 9eb6a91e6a..ee6e5045d0 100644 --- a/libraries/voxels/src/VoxelNodeBag.h +++ b/libraries/voxels/src/VoxelNodeBag.h @@ -28,6 +28,8 @@ public: void insert(VoxelNode* node); // put a node into the bag VoxelNode* extract(); // pull a node out of the bag (could come in any order) + bool contains(VoxelNode* node); // is this node in the bag? + void remove(VoxelNode* node); // remove a specific item from the bag bool isEmpty() const { return (_elementsInUse == 0); }; int count() const { return _elementsInUse; }; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 49e1f7596c..daf2e01a72 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -22,10 +22,12 @@ #include // to load voxels from file #include "VoxelConstants.h" +#include + using voxels_lib::printLog; int boundaryDistanceForRenderLevel(unsigned int renderLevel) { - float voxelSizeScale = 500.0*TREE_SCALE; + float voxelSizeScale = 50000.0f; return voxelSizeScale / powf(2, renderLevel); } @@ -113,9 +115,7 @@ VoxelNode* VoxelTree::createMissingNode(VoxelNode* lastParentNode, unsigned char } } -int VoxelTree::readNodeData(VoxelNode* destinationNode, - unsigned char* nodeData, - int bytesLeftToRead) { +int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, int bytesLeftToRead) { // instantiate variable for bytes already read int bytesRead = 1; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { @@ -457,87 +457,136 @@ void VoxelTree::createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, r } void VoxelTree::createSphere(float radius, float xc, float yc, float zc, float voxelSize, - bool solid, bool wantColorRandomizer, bool debug) { + bool solid, creationMode mode, bool debug) { - // About the color of the sphere... we're going to make this sphere be a gradient - // between two RGB colors. We will do the gradient along the phi spectrum - unsigned char dominantColor1 = randIntInRange(1, 3); //1=r, 2=g, 3=b dominant - unsigned char dominantColor2 = randIntInRange(1, 3); + bool wantColorRandomizer = (mode == RANDOM); + bool wantNaturalSurface = (mode == NATURAL); + bool wantNaturalColor = (mode == NATURAL); - if (dominantColor1 == dominantColor2) { - dominantColor2 = dominantColor1 + 1 % 3; + // About the color of the sphere... we're going to make this sphere be a mixture of two colors + // in NATURAL mode, those colors will be green dominant and blue dominant. In GRADIENT mode we + // will randomly pick which color family red, green, or blue to be dominant. In RANDOM mode we + // ignore these dominant colors and make every voxel a completely random color. + unsigned char r1, g1, b1, r2, g2, b2; + + if (wantNaturalColor) { + r1 = r2 = b2 = g1 = 0; + b1 = g2 = 255; + } else if (!wantColorRandomizer) { + unsigned char dominantColor1 = randIntInRange(1, 3); //1=r, 2=g, 3=b dominant + unsigned char dominantColor2 = randIntInRange(1, 3); + + if (dominantColor1 == dominantColor2) { + dominantColor2 = dominantColor1 + 1 % 3; + } + + r1 = (dominantColor1 == 1) ? randIntInRange(200, 255) : randIntInRange(40, 100); + g1 = (dominantColor1 == 2) ? randIntInRange(200, 255) : randIntInRange(40, 100); + b1 = (dominantColor1 == 3) ? randIntInRange(200, 255) : randIntInRange(40, 100); + r2 = (dominantColor2 == 1) ? randIntInRange(200, 255) : randIntInRange(40, 100); + g2 = (dominantColor2 == 2) ? randIntInRange(200, 255) : randIntInRange(40, 100); + b2 = (dominantColor2 == 3) ? randIntInRange(200, 255) : randIntInRange(40, 100); } - unsigned char r1 = (dominantColor1 == 1) ? randIntInRange(200, 255) : randIntInRange(40, 100); - unsigned char g1 = (dominantColor1 == 2) ? randIntInRange(200, 255) : randIntInRange(40, 100); - unsigned char b1 = (dominantColor1 == 3) ? randIntInRange(200, 255) : randIntInRange(40, 100); - unsigned char r2 = (dominantColor2 == 1) ? randIntInRange(200, 255) : randIntInRange(40, 100); - unsigned char g2 = (dominantColor2 == 2) ? randIntInRange(200, 255) : randIntInRange(40, 100); - unsigned char b2 = (dominantColor2 == 3) ? randIntInRange(200, 255) : randIntInRange(40, 100); - - // We initialize our rgb to be either "grey" in case of randomized surface, or - // the average of the gradient, in the case of the gradient sphere. + // We initialize our rgb to be either "grey" in case of randomized surface, or + // the average of the gradient, in the case of the gradient sphere. unsigned char red = wantColorRandomizer ? 128 : (r1 + r2) / 2; // average of the colors unsigned char green = wantColorRandomizer ? 128 : (g1 + g2) / 2; unsigned char blue = wantColorRandomizer ? 128 : (b1 + b2) / 2; - - // Psuedocode for creating a sphere: - // - // for (theta from 0 to 2pi): - // for (phi from 0 to pi): - // x = xc+r*cos(theta)*sin(phi) - // y = yc+r*sin(theta)*sin(phi) - // z = zc+r*cos(phi) - // assume solid for now - float thisRadius = 0.0; - float thisVoxelSize = radius / 4.0f; - - if (!solid) { - thisRadius = radius; // just the outer surface - thisVoxelSize = voxelSize; - } - - // If you also iterate form the interior of the sphere to the radius, makeing - // larger and larger sphere'voxelSize you'd end up with a solid sphere. And lots of voxels! - while (thisRadius <= (radius + (voxelSize / 2.0))) { - if (debug) { - printLog("radius: thisRadius=%f thisVoxelSize=%f thisRadius+thisVoxelSize=%f (radius+(voxelSize/2.0))=%f\n", - thisRadius, thisVoxelSize, thisRadius+thisVoxelSize, (radius + (voxelSize / 2.0))); - } + // I want to do something smart like make these inside circles with bigger voxels, but this doesn't seem to work. + float thisVoxelSize = voxelSize; // radius / 2.0f; + float thisRadius = 0.0; + if (!solid) { + thisRadius = radius; // just the outer surface + thisVoxelSize = voxelSize; + } + + // If you also iterate form the interior of the sphere to the radius, making + // larger and larger spheres you'd end up with a solid sphere. And lots of voxels! + bool lastLayer = false; + while (!lastLayer) { + lastLayer = (thisRadius + (voxelSize * 2.0) >= radius); + // We want to make sure that as we "sweep" through our angles we use a delta angle that voxelSize // small enough to not skip any voxels we can calculate theta from our desired arc length // lenArc = ndeg/360deg * 2pi*R ---> lenArc = theta/2pi * 2pi*R // lenArc = theta*R ---> theta = lenArc/R ---> theta = g/r float angleDelta = (thisVoxelSize / thisRadius); - for (float theta=0.0; theta <= 2 * M_PI; theta += angleDelta) { - for (float phi=0.0; phi <= M_PI; phi += angleDelta) { - float x = xc + thisRadius * cos(theta) * sin(phi); - float y = yc + thisRadius * sin(theta) * sin(phi); - float z = zc + thisRadius * cos(phi); - - // gradient color data - float gradient = (phi / M_PI); - - // only use our actual desired color on the outer edge, otherwise - // use our "average" color - if (thisRadius + (voxelSize * 2.0) >= radius) { - //printLog("painting candy shell radius: thisRadius=%f radius=%f\n",thisRadius,radius); - red = wantColorRandomizer ? randomColorValue(165) : r1 + ((r2 - r1) * gradient); - green = wantColorRandomizer ? randomColorValue(165) : g1 + ((g2 - g1) * gradient); - blue = wantColorRandomizer ? randomColorValue(165) : b1 + ((b2 - b1) * gradient); - } - - unsigned char* voxelData = pointToVoxel(x, y, z, thisVoxelSize, red, green, blue); - this->readCodeColorBufferToTree(voxelData); - delete voxelData; - } - } + if (debug) { + int percentComplete = 100 * (thisRadius/radius); + printLog("percentComplete=%d\n",percentComplete); + } + + for (float theta=0.0; theta <= 2 * M_PI; theta += angleDelta) { + for (float phi=0.0; phi <= M_PI; phi += angleDelta) { + bool naturalSurfaceRendered = false; + float x = xc + thisRadius * cos(theta) * sin(phi); + float y = yc + thisRadius * sin(theta) * sin(phi); + float z = zc + thisRadius * cos(phi); + + // if we're on the outer radius, then we do a couple of things differently. + // 1) If we're in NATURAL mode we will actually draw voxels from our surface outward (from the surface) up + // some random height. This will give our sphere some contours. + // 2) In all modes, we will use our "outer" color to draw the voxels. Otherwise we will use the average color + if (lastLayer) { + if (false && debug) { + printLog("adding candy shell: theta=%f phi=%f thisRadius=%f radius=%f\n", + theta, phi, thisRadius,radius); + } + switch (mode) { + case RANDOM: { + red = randomColorValue(165); + green = randomColorValue(165); + blue = randomColorValue(165); + } break; + case GRADIENT: { + float gradient = (phi / M_PI); + red = r1 + ((r2 - r1) * gradient); + green = g1 + ((g2 - g1) * gradient); + blue = b1 + ((b2 - b1) * gradient); + } break; + case NATURAL: { + glm::vec3 position = glm::vec3(theta,phi,radius); + float perlin = glm::perlin(position) + .25f * glm::perlin(position * 4.f) + + .125f * glm::perlin(position * 16.f); + float gradient = (1.0f + perlin)/ 2.0f; + red = (unsigned char)std::min(255, std::max(0, (int)(r1 + ((r2 - r1) * gradient)))); + green = (unsigned char)std::min(255, std::max(0, (int)(g1 + ((g2 - g1) * gradient)))); + blue = (unsigned char)std::min(255, std::max(0, (int)(b1 + ((b2 - b1) * gradient)))); + if (debug) { + printLog("perlin=%f gradient=%f color=(%d,%d,%d)\n",perlin, gradient, red, green, blue); + } + } break; + } + if (wantNaturalSurface) { + // for natural surfaces, we will render up to 16 voxel's above the surface of the sphere + glm::vec3 position = glm::vec3(theta,phi,radius); + float perlin = glm::perlin(position) + .25f * glm::perlin(position * 4.f) + + .125f * glm::perlin(position * 16.f); + float gradient = (1.0f + perlin)/ 2.0f; + + int height = (4 * gradient)+1; // make it at least 4 thick, so we get some averaging + float subVoxelScale = thisVoxelSize; + for (int i = 0; i < height; i++) { + x = xc + (thisRadius + i * subVoxelScale) * cos(theta) * sin(phi); + y = yc + (thisRadius + i * subVoxelScale) * sin(theta) * sin(phi); + z = zc + (thisRadius + i * subVoxelScale) * cos(phi); + this->createVoxel(x, y, z, subVoxelScale, red, green, blue); + } + naturalSurfaceRendered = true; + } + } + if (!naturalSurfaceRendered) { + this->createVoxel(x, y, z, thisVoxelSize, red, green, blue); + } + } + } thisRadius += thisVoxelSize; - thisVoxelSize = std::max(voxelSize, thisVoxelSize / 2.0f); - } - this->reaverageVoxelColors(this->rootNode); + thisVoxelSize = std::max(voxelSize, thisVoxelSize / 2.0f); + } + this->reaverageVoxelColors(this->rootNode); } int VoxelTree::searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) { @@ -884,7 +933,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco bool VoxelTree::readFromFileV2(const char* fileName) { std::ifstream file(fileName, std::ios::in|std::ios::binary|std::ios::ate); if(file.is_open()) { - printLog("loading file...\n"); + printLog("loading file %s...\n", fileName); // get file length.... unsigned long fileLength = file.tellg(); @@ -907,6 +956,8 @@ void VoxelTree::writeToFileV2(const char* fileName) const { std::ofstream file(fileName, std::ios::out|std::ios::binary); if(file.is_open()) { + printLog("saving to file %s...\n", fileName); + VoxelNodeBag nodeBag; nodeBag.insert(rootNode); @@ -923,3 +974,13 @@ void VoxelTree::writeToFileV2(const char* fileName) const { file.close(); } +unsigned long VoxelTree::getVoxelCount() { + unsigned long nodeCount = 0; + recurseTreeWithOperation(countVoxelsOperation, &nodeCount); + return nodeCount; +} + +bool VoxelTree::countVoxelsOperation(VoxelNode* node, void* extraData) { + (*(unsigned long*)extraData)++; + return true; // keep going +} diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 421e14ace7..319b4aed95 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -17,6 +17,7 @@ // Callback function, for recuseTreeWithOperation typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData); +typedef enum {GRADIENT, RANDOM, NATURAL} creationMode; class VoxelTree { public: @@ -49,7 +50,7 @@ public: VoxelNode* getVoxelAt(float x, float y, float z, float s) const; void createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue); void createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color); - void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer, bool debug = false); + void createSphere(float r,float xc, float yc, float zc, float s, bool solid, creationMode mode, bool debug = false); void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL); @@ -70,6 +71,8 @@ public: // these will read/write files that match the wireformat, excluding the 'V' leading void writeToFileV2(const char* filename) const; bool readFromFileV2(const char* filename); + + unsigned long getVoxelCount(); private: int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, @@ -79,6 +82,8 @@ private: int searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); + static bool countVoxelsOperation(VoxelNode* node, void* extraData); + void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const; VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate); diff --git a/voxel-edit/src/main.cpp b/voxel-edit/src/main.cpp index 5a474f15ee..222bf3f15b 100644 --- a/voxel-edit/src/main.cpp +++ b/voxel-edit/src/main.cpp @@ -8,6 +8,7 @@ #include #include +#include VoxelTree myTree; @@ -19,12 +20,16 @@ bool countVoxelsOperation(VoxelNode* node, void* extraData) { return true; // keep going } -void addScene(VoxelTree * tree) { +void addLandscape(VoxelTree * tree) { + printf("Adding Landscape...\n"); +} + +void voxelTutorial(VoxelTree * tree) { printf("adding scene...\n"); // We want our corner voxels to be about 1/2 meter high, and our TREE_SCALE is in meters, so... float voxelSize = 0.5f / TREE_SCALE; - + // Here's an example of how to create a voxel. printf("creating corner points...\n"); tree->createVoxel(0, 0, 0, voxelSize, 255, 255 ,255); @@ -47,72 +52,8 @@ void addScene(VoxelTree * tree) { } else { printf("corner point 0,0,0 does not exists...\n"); } - - // Now some more examples... a little more complex - printf("creating corner points...\n"); - tree->createVoxel(0 , 0 , 0 , voxelSize, 255, 255 ,255); - tree->createVoxel(1.0 - voxelSize, 0 , 0 , voxelSize, 255, 0 ,0 ); - tree->createVoxel(0 , 1.0 - voxelSize, 0 , voxelSize, 0 , 255 ,0 ); - tree->createVoxel(0 , 0 , 1.0 - voxelSize, voxelSize, 0 , 0 ,255); - tree->createVoxel(1.0 - voxelSize, 0 , 1.0 - voxelSize, voxelSize, 255, 0 ,255); - tree->createVoxel(0 , 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 0 , 255 ,255); - tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 0 , voxelSize, 255, 255 ,0 ); - tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 255, 255 ,255); - printf("DONE creating corner points...\n"); - - // Now some more examples... creating some lines using the line primitive - printf("creating voxel lines...\n"); - // We want our line voxels to be about 1/32 meter high, and our TREE_SCALE is in meters, so... - float lineVoxelSize = 1.f / (32 * TREE_SCALE); - rgbColor red = {255, 0, 0}; - rgbColor green = {0, 255, 0}; - rgbColor blue = {0, 0, 255}; - tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 0, 1), lineVoxelSize, blue); - tree->createLine(glm::vec3(0, 0, 0), glm::vec3(1, 0, 0), lineVoxelSize, red); - tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 1, 0), lineVoxelSize, green); - printf("DONE creating lines...\n"); - - // Now some more examples... creating some spheres using the sphere primitive - // We want the smallest unit of our spheres to be about 1/16th of a meter tall - float sphereVoxelSize = 1.f / (16 * TREE_SCALE); - printf("creating spheres... sphereVoxelSize=%f\n",sphereVoxelSize); - tree->createSphere(0.25, 0.5, 0.5, 0.5, sphereVoxelSize, true, false, true); - printf("one sphere added... sphereVoxelSize=%f\n",sphereVoxelSize); - - tree->createSphere(0.030625, 0.5, 0.5, (0.25 - 0.06125), sphereVoxelSize, true, true); - printf("two spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); - tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), (0.75 - 0.06125), sphereVoxelSize, true, true); - printf("three spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); - tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), 0.06125, sphereVoxelSize, true, true); - printf("four spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); - tree->createSphere(0.030625, (0.75 - 0.030625), 0.06125, (0.75 - 0.06125), sphereVoxelSize, true, true); - printf("five spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); - tree->createSphere(0.06125, 0.125, 0.125, (0.75 - 0.125), sphereVoxelSize, true, true); - - float radius = 0.0125f; - printf("6 spheres added...\n"); - tree->createSphere(radius, 0.25, radius * 5.0f, 0.25, (1.0 / 4096), true, true); - printf("7 spheres added...\n"); - tree->createSphere(radius, 0.125, radius * 5.0f, 0.25, (1.0 / 4096), true, true); - printf("8 spheres added...\n"); - tree->createSphere(radius, 0.075, radius * 5.0f, 0.25, (1.0 / 4096), true, true); - printf("9 spheres added...\n"); - tree->createSphere(radius, 0.05, radius * 5.0f, 0.25, (1.0 / 4096), true, true); - printf("10 spheres added...\n"); - tree->createSphere(radius, 0.025, radius * 5.0f, 0.25, (1.0 / 4096), true, true); - printf("11 spheres added...\n"); - printf("DONE creating spheres...\n"); - // Here's an example of how to recurse the tree and do some operation on the nodes as you recurse them. - // This one is really simple, it just couts them... - // Look at the function countVoxelsOperation() for an example of how you could use this function - _nodeCount=0; - tree->recurseTreeWithOperation(countVoxelsOperation); - printf("Nodes after adding scene %d nodes\n", _nodeCount); - - printf("DONE adding scene of spheres...\n"); } - int main(int argc, const char * argv[]) { const char* SAY_HELLO = "--sayHello"; @@ -127,8 +68,32 @@ int main(int argc, const char * argv[]) printf("You asked us not to create a scene file, so we will not.\n"); } else { printf("Creating Scene File...\n"); - addScene(&myTree); + + const char* RUN_TUTORIAL = "--runTutorial"; + if (cmdOptionExists(argc, argv, RUN_TUTORIAL)) { + voxelTutorial(&myTree); + } + + const char* ADD_CORNERS_AND_AXIS_LINES = "--addCornersAndAxisLines"; + if (cmdOptionExists(argc, argv, ADD_CORNERS_AND_AXIS_LINES)) { + addCornersAndAxisLines(&myTree); + } + + const char* ADD_SPHERE_SCENE = "--addSphereScene"; + if (cmdOptionExists(argc, argv, ADD_SPHERE_SCENE)) { + addSphereScene(&myTree); + } + + const char* ADD_SURFACE_SCENE = "--addSurfaceScene"; + if (cmdOptionExists(argc, argv, ADD_SURFACE_SCENE)) { + addSurfaceScene(&myTree); + } + + unsigned long nodeCount = myTree.getVoxelCount(); + printf("Nodes after adding scenes: %ld nodes\n", nodeCount); + myTree.writeToFileV2("voxels.hio2"); + } return 0; } \ No newline at end of file diff --git a/voxel-server/resources/voxels.hio2 b/voxel-server/resources/voxels.hio2 new file mode 100644 index 0000000000..77d51228ce Binary files /dev/null and b/voxel-server/resources/voxels.hio2 differ diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 380f2cc794..9b66f427c6 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -13,10 +13,12 @@ #include #include #include +#include #include #include "VoxelAgentData.h" #include #include +#include #ifdef _WIN32 #include "Syssocket.h" @@ -27,6 +29,9 @@ #include #endif +const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.hio2"; +const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/resources/voxels.hio2"; + const int VOXEL_LISTEN_PORT = 40106; @@ -44,102 +49,13 @@ const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4; VoxelTree randomTree; bool wantVoxelPersist = true; +bool wantLocalDomain = false; + bool wantColorRandomizer = false; bool debugVoxelSending = false; -void addSphere(VoxelTree * tree,bool random, bool wantColorRandomizer) { - float r = random ? randFloatInRange(0.05,0.1) : 0.25; - float xc = random ? randFloatInRange(r,(1-r)) : 0.5; - float yc = random ? randFloatInRange(r,(1-r)) : 0.5; - float zc = random ? randFloatInRange(r,(1-r)) : 0.5; - float s = (1.0/256); // size of voxels to make up surface of sphere - bool solid = true; - - printf("adding sphere:"); - if (random) - printf(" random"); - printf("\nradius=%f\n",r); - printf("xc=%f\n",xc); - printf("yc=%f\n",yc); - printf("zc=%f\n",zc); - - tree->createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer); -} - -int _nodeCount=0; -bool countVoxelsOperation(VoxelNode* node, void* extraData) { - if (node->isColored()){ - _nodeCount++; - } - return true; // keep going -} - -void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) { - printf("adding scene...\n"); - - float voxelSize = 1.f/32; - printf("creating corner points...\n"); - tree->createVoxel(0 , 0 , 0 , voxelSize, 255, 255 ,255); - tree->createVoxel(1.0 - voxelSize, 0 , 0 , voxelSize, 255, 0 ,0 ); - tree->createVoxel(0 , 1.0 - voxelSize, 0 , voxelSize, 0 , 255 ,0 ); - tree->createVoxel(0 , 0 , 1.0 - voxelSize, voxelSize, 0 , 0 ,255); - tree->createVoxel(1.0 - voxelSize, 0 , 1.0 - voxelSize, voxelSize, 255, 0 ,255); - tree->createVoxel(0 , 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 0 , 255 ,255); - tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 0 , voxelSize, 255, 255 ,0 ); - tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 255, 255 ,255); - printf("DONE creating corner points...\n"); - - printf("creating voxel lines...\n"); - float lineVoxelSize = 0.99f/256; - rgbColor red = {255,0,0}; - rgbColor green = {0,255,0}; - rgbColor blue = {0,0,255}; - - tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 0, 1), lineVoxelSize, blue); - tree->createLine(glm::vec3(0, 0, 0), glm::vec3(1, 0, 0), lineVoxelSize, red); - tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 1, 0), lineVoxelSize, green); - - printf("DONE creating lines...\n"); - - int sphereBaseSize = 512; - printf("creating spheres...\n"); - tree->createSphere(0.25, 0.5, 0.5, 0.5, (1.0 / sphereBaseSize), true, wantColorRandomizer); - printf("one sphere added...\n"); - tree->createSphere(0.030625, 0.5, 0.5, (0.25-0.06125), (1.0 / (sphereBaseSize * 2)), true, true); - - - printf("two spheres added...\n"); - tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), (0.75 - 0.06125), (1.0 / (sphereBaseSize * 2)), true, true); - printf("three spheres added...\n"); - tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), 0.06125, (1.0 / (sphereBaseSize * 2)), true, true); - printf("four spheres added...\n"); - tree->createSphere(0.030625, (0.75 - 0.030625), 0.06125, (0.75 - 0.06125), (1.0 / (sphereBaseSize * 2)), true, true); - printf("five spheres added...\n"); - tree->createSphere(0.06125, 0.125, 0.125, (0.75 - 0.125), (1.0 / (sphereBaseSize * 2)), true, true); - - float radius = 0.0125f; - printf("6 spheres added...\n"); - tree->createSphere(radius, 0.25, radius * 5.0f, 0.25, (1.0 / 4096), true, true); - printf("7 spheres added...\n"); - tree->createSphere(radius, 0.125, radius * 5.0f, 0.25, (1.0 / 4096), true, true); - printf("8 spheres added...\n"); - tree->createSphere(radius, 0.075, radius * 5.0f, 0.25, (1.0 / 4096), true, true); - printf("9 spheres added...\n"); - tree->createSphere(radius, 0.05, radius * 5.0f, 0.25, (1.0 / 4096), true, true); - printf("10 spheres added...\n"); - tree->createSphere(radius, 0.025, radius * 5.0f, 0.25, (1.0 / 4096), true, true); - printf("11 spheres added...\n"); - - printf("DONE creating spheres...\n"); - - _nodeCount=0; - tree->recurseTreeWithOperation(countVoxelsOperation); - printf("Nodes after adding scene %d nodes\n", _nodeCount); - - - printf("DONE adding scene of spheres...\n"); -} +EnvironmentData environmentData; void randomlyFillVoxelTree(int levelsToGo, VoxelNode *currentRootNode) { @@ -237,7 +153,7 @@ void voxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAge int trueBytesSent = 0; double start = usecTimestampNow(); - while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL) { + while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - 1) { if (!agentData->nodeBag.isEmpty()) { VoxelNode* subTree = agentData->nodeBag.extract(); bytesWritten = randomTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree, @@ -267,6 +183,12 @@ void voxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAge packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left } } + // send the environment packet + int envPacketLength = environmentData.getBroadcastData(tempOutputBuffer); + agentList->getAgentSocket().send(agent->getActiveSocket(), tempOutputBuffer, envPacketLength); + trueBytesSent += envPacketLength; + truePacketsSent++; + double end = usecTimestampNow(); double elapsedmsec = (end - start)/1000.0; if (elapsedmsec > 100) { @@ -298,7 +220,7 @@ void persistVoxelsWhenDirty() { // check the dirty bit and persist here... if (::wantVoxelPersist && ::randomTree.isDirty()) { printf("saving voxels to file...\n"); - randomTree.writeToFileV2("voxels.hio2"); + randomTree.writeToFileV2(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); randomTree.clearDirtyBit(); // tree is clean after saving printf("DONE saving voxels to file...\n"); } @@ -361,8 +283,8 @@ int main(int argc, const char * argv[]) // Handle Local Domain testing with the --local command line const char* local = "--local"; - bool wantLocalDomain = cmdOptionExists(argc, argv,local); - if (wantLocalDomain) { + ::wantLocalDomain = cmdOptionExists(argc, argv,local); + if (::wantLocalDomain) { printf("Local Domain MODE!\n"); int ip = getLocalAddress(); sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)); @@ -393,12 +315,11 @@ int main(int argc, const char * argv[]) bool persistantFileRead = false; if (::wantVoxelPersist) { printf("loading voxels from file...\n"); - persistantFileRead = ::randomTree.readFromFileV2("voxels.hio2"); + persistantFileRead = ::randomTree.readFromFileV2(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); ::randomTree.clearDirtyBit(); // the tree is clean since we just loaded it - printf("DONE loading voxels from file...\n"); - _nodeCount=0; - ::randomTree.recurseTreeWithOperation(countVoxelsOperation); - printf("Nodes after loading scene %d nodes\n", _nodeCount); + printf("DONE loading voxels from file... fileRead=%s\n", persistantFileRead ? "yes" : "no" ); + unsigned long nodeCount = ::randomTree.getVoxelCount(); + printf("Nodes after loading scene %ld nodes\n", nodeCount); } // Check to see if the user passed in a command line option for loading an old style local @@ -427,14 +348,6 @@ int main(int argc, const char * argv[]) randomlyFillVoxelTree(MAX_VOXEL_TREE_DEPTH_LEVELS, randomTree.rootNode); } - const char* ADD_SPHERE = "--AddSphere"; - const char* ADD_RANDOM_SPHERE = "--AddRandomSphere"; - if (cmdOptionExists(argc, argv, ADD_SPHERE)) { - addSphere(&randomTree,false,wantColorRandomizer); - } else if (cmdOptionExists(argc, argv, ADD_RANDOM_SPHERE)) { - addSphere(&randomTree,true,wantColorRandomizer); - } - const char* ADD_SCENE = "--AddScene"; bool addScene = cmdOptionExists(argc, argv, ADD_SCENE); const char* NO_ADD_SCENE = "--NoAddScene"; @@ -447,9 +360,11 @@ int main(int argc, const char * argv[]) // 1) we attempted to load a persistant file and it wasn't there // 2) you asked us to add a scene // HOWEVER -- we will NEVER add a scene if you explicitly tell us not to! - bool actuallyAddScene = !noAddScene && (addScene || (::wantVoxelPersist && !persistantFileRead)); + // + // TEMPORARILY DISABLED!!! + bool actuallyAddScene = false; // !noAddScene && (addScene || (::wantVoxelPersist && !persistantFileRead)); if (actuallyAddScene) { - addSphereScene(&randomTree,wantColorRandomizer); + addSphereScene(&randomTree); } pthread_t sendVoxelThread; @@ -535,7 +450,7 @@ int main(int argc, const char * argv[]) } if (0==strcmp(command,(char*)"add scene")) { printf("got Z message == add scene\n"); - addSphereScene(&randomTree,false); + addSphereScene(&randomTree); } totalLength += commandLength+1; } @@ -559,4 +474,4 @@ int main(int argc, const char * argv[]) pthread_join(sendVoxelThread, NULL); return 0; -} \ No newline at end of file +}