This commit is contained in:
Philip Rosedale 2013-05-22 14:31:46 -07:00
commit 6b854531aa
21 changed files with 532 additions and 227 deletions

View file

@ -65,6 +65,110 @@ static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) {
} }
} }
const float BUG_VOXEL_SIZE = 0.0625f / TREE_SCALE;
glm::vec3 bugPosition = glm::vec3(BUG_VOXEL_SIZE * 10.0, 0, BUG_VOXEL_SIZE * 10.0);
glm::vec3 bugDirection = glm::vec3(0, 0, 1);
const unsigned char bugColor[3] = {0, 255, 255};
const int VOXELS_PER_BUG = 14;
const glm::vec3 bugParts[VOXELS_PER_BUG] = {
// body
glm::vec3(0, 0, -3),
glm::vec3(0, 0, -2),
glm::vec3(0, 0, -1),
glm::vec3(0, 0, 0),
glm::vec3(0, 0, 1),
glm::vec3(0, 0, 2),
// eyes
glm::vec3(1, 0, 3),
glm::vec3(-1, 0, 3),
// wings
glm::vec3(1, 0, 1),
glm::vec3(2, 0, 1),
glm::vec3(3, 0, 1),
glm::vec3(-1, 0, 1),
glm::vec3(-2, 0, 1),
glm::vec3(-3, 0, 1),
};
static void renderMovingBug() {
VoxelDetail details[VOXELS_PER_BUG];
unsigned char* bufferOut;
int sizeOut;
// Generate voxels for where bug used to be
for (int i = 0; i < VOXELS_PER_BUG; i++) {
details[i].s = BUG_VOXEL_SIZE;
details[i].x = bugPosition.x + (bugParts[i].x * BUG_VOXEL_SIZE);
details[i].y = bugPosition.y + (bugParts[i].y * BUG_VOXEL_SIZE);
details[i].z = bugPosition.z + (bugParts[i].z * BUG_VOXEL_SIZE);
details[i].red = bugColor[0];
details[i].green = bugColor[1];
details[i].blue = bugColor[2];
}
// send the "erase message" first...
PACKET_HEADER message = PACKET_HEADER_ERASE_VOXEL;
if (createVoxelEditMessage(message, 0, VOXELS_PER_BUG, (VoxelDetail*)&details, bufferOut, sizeOut)){
::packetsSent++;
::bytesSent += sizeOut;
if (::shouldShowPacketsPerSecond) {
printf("sending packet of size=%d\n", sizeOut);
}
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1);
delete[] bufferOut;
}
// Move the bug...
bugPosition.x += (bugDirection.x * BUG_VOXEL_SIZE);
bugPosition.y += (bugDirection.y * BUG_VOXEL_SIZE);
bugPosition.z += (bugDirection.z * BUG_VOXEL_SIZE);
// Check boundaries
if (bugPosition.z > 0.25) {
bugDirection.z = -1;
}
if (bugPosition.z < 0.01) {
bugDirection.z = 1;
}
printf("bugPosition=(%f,%f,%f)\n", bugPosition.x, bugPosition.y, bugPosition.z);
printf("bugDirection=(%f,%f,%f)\n", bugDirection.x, bugDirection.y, bugDirection.z);
// would be nice to add some randomness here...
// Generate voxels for where bug is going to
for (int i = 0; i < VOXELS_PER_BUG; i++) {
details[i].s = BUG_VOXEL_SIZE;
details[i].x = bugPosition.x + (bugParts[i].x * BUG_VOXEL_SIZE);
details[i].y = bugPosition.y + (bugParts[i].y * BUG_VOXEL_SIZE);
details[i].z = bugPosition.z + (bugParts[i].z * BUG_VOXEL_SIZE);
details[i].red = bugColor[0];
details[i].green = bugColor[1];
details[i].blue = bugColor[2];
}
// send the "create message" ...
message = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE;
if (createVoxelEditMessage(message, 0, VOXELS_PER_BUG, (VoxelDetail*)&details, bufferOut, sizeOut)){
::packetsSent++;
::bytesSent += sizeOut;
if (::shouldShowPacketsPerSecond) {
printf("sending packet of size=%d\n", sizeOut);
}
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1);
delete[] bufferOut;
}
}
float intensity = 0.5f; float intensity = 0.5f;
float intensityIncrement = 0.1f; float intensityIncrement = 0.1f;
const float MAX_INTENSITY = 1.0f; const float MAX_INTENSITY = 1.0f;
@ -325,6 +429,7 @@ void* animateVoxels(void* args) {
//sendVoxelBlinkMessage(); //sendVoxelBlinkMessage();
sendBlinkingStringOfLights(); sendBlinkingStringOfLights();
sendBillboard(); sendBillboard();
//renderMovingBug();
double end = usecTimestampNow(); double end = usecTimestampNow();
double elapsedSeconds = (end - ::start) / 1000000.0; double elapsedSeconds = (end - ::start) / 1000000.0;

View file

@ -44,15 +44,18 @@ add_subdirectory(src/starfield)
if (APPLE) if (APPLE)
# set how the icon shows up in the Info.plist file # set how the icon shows up in the Info.plist file
SET(MACOSX_BUNDLE_ICON_FILE interface.icns) SET(MACOSX_BUNDLE_ICON_FILE interface.icns)
# grab the image and audio files
FILE(GLOB INTERFACE_RES_DIRS resources/*)
set(INTERFACE_RSRCS ${INTERFACE_RES_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/interface.icns)
# set where in the bundle to put the resources file # set where in the bundle to put the resources file
SET_SOURCE_FILES_PROPERTIES(${INTERFACE_RSRCS} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/interface.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
# include the icns file and resource files in the target
SET(INTERFACE_SRCS ${INTERFACE_SRCS} ${INTERFACE_RSRCS}) # grab the directories in resources and put them in the right spot in Resources
FILE(GLOB INTERFACE_IMAGES resources/images/*)
SET_SOURCE_FILES_PROPERTIES(${INTERFACE_IMAGES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/images)
FILE(GLOB INTERFACE_SHADERS resources/shaders/*)
SET_SOURCE_FILES_PROPERTIES(${INTERFACE_SHADERS} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/shaders)
SET(INTERFACE_SRCS ${INTERFACE_SRCS} ${INTERFACE_IMAGES} ${INTERFACE_SHADERS} ${CMAKE_CURRENT_SOURCE_DIR}/interface.icns)
endif (APPLE) endif (APPLE)
find_package(Qt4 REQUIRED QtCore QtGui QtOpenGL) find_package(Qt4 REQUIRED QtCore QtGui QtOpenGL)

View file

@ -386,7 +386,8 @@ void Application::paintGL() {
glEnable(GL_COLOR_MATERIAL); glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glm::vec3 relativeSunLoc = glm::normalize(_environment.getSunLocation() - whichCamera.getPosition()); glm::vec3 relativeSunLoc = glm::normalize(_environment.getClosestData(whichCamera.getPosition()).getSunLocation() -
whichCamera.getPosition());
GLfloat light_position0[] = { relativeSunLoc.x, relativeSunLoc.y, relativeSunLoc.z, 0.0 }; GLfloat light_position0[] = { relativeSunLoc.x, relativeSunLoc.y, relativeSunLoc.z, 0.0 };
glLightfv(GL_LIGHT0, GL_POSITION, light_position0); glLightfv(GL_LIGHT0, GL_POSITION, light_position0);
GLfloat ambient_color[] = { 0.7, 0.7, 0.8 }; GLfloat ambient_color[] = { 0.7, 0.7, 0.8 };
@ -816,26 +817,6 @@ static glm::vec3 getFaceVector(BoxFace face) {
} }
} }
//Find and return the gravity vector at this location
static glm::vec3 getGravity(const glm::vec3& pos) {
//
// For now, we'll test this with a simple global lookup, but soon we will add getting this
// from the domain/voxelserver (or something similar)
//
if ((pos.x > 0.f) &&
(pos.x < 10.f) &&
(pos.z > 0.f) &&
(pos.z < 10.f) &&
(pos.y > 0.f) &&
(pos.y < 3.f)) {
// If above ground plane, turn gravity on
return glm::vec3(0.f, -1.f, 0.f);
} else {
// If flying in space, turn gravity OFF
return glm::vec3(0.f, 0.f, 0.f);
}
}
void Application::idle() { void Application::idle() {
timeval check; timeval check;
gettimeofday(&check, NULL); gettimeofday(&check, NULL);
@ -970,7 +951,7 @@ void Application::idle() {
agentList->unlock(); agentList->unlock();
// Simulate myself // Simulate myself
_myAvatar.setGravity(getGravity(_myAvatar.getPosition())); _myAvatar.setGravity(_environment.getGravity(_myAvatar.getPosition()));
if (_transmitterDrives->isChecked() && _myTransmitter.isConnected()) { if (_transmitterDrives->isChecked() && _myTransmitter.isConnected()) {
_myAvatar.simulate(deltaTime, &_myTransmitter); _myAvatar.simulate(deltaTime, &_myTransmitter);
} else { } else {
@ -1641,13 +1622,14 @@ void Application::displaySide(Camera& whichCamera) {
// compute starfield alpha based on distance from atmosphere // compute starfield alpha based on distance from atmosphere
float alpha = 1.0f; float alpha = 1.0f;
if (_renderAtmosphereOn->isChecked()) { if (_renderAtmosphereOn->isChecked()) {
float height = glm::distance(whichCamera.getPosition(), _environment.getAtmosphereCenter()); const EnvironmentData& closestData = _environment.getClosestData(whichCamera.getPosition());
if (height < _environment.getAtmosphereInnerRadius()) { float height = glm::distance(whichCamera.getPosition(), closestData.getAtmosphereCenter());
if (height < closestData.getAtmosphereInnerRadius()) {
alpha = 0.0f; alpha = 0.0f;
} else if (height < _environment.getAtmosphereOuterRadius()) { } else if (height < closestData.getAtmosphereOuterRadius()) {
alpha = (height - _environment.getAtmosphereInnerRadius()) / alpha = (height - closestData.getAtmosphereInnerRadius()) /
(_environment.getAtmosphereOuterRadius() - _environment.getAtmosphereInnerRadius()); (closestData.getAtmosphereOuterRadius() - closestData.getAtmosphereInnerRadius());
} }
} }
@ -1657,7 +1639,7 @@ void Application::displaySide(Camera& whichCamera) {
// draw the sky dome // draw the sky dome
if (_renderAtmosphereOn->isChecked()) { if (_renderAtmosphereOn->isChecked()) {
_environment.renderAtmosphere(whichCamera); _environment.renderAtmospheres(whichCamera);
} }
glEnable(GL_LIGHTING); glEnable(GL_LIGHTING);
@ -2128,7 +2110,7 @@ void* Application::networkReceive(void* args) {
app->_voxels.parseData(app->_incomingPacket, bytesReceived); app->_voxels.parseData(app->_incomingPacket, bytesReceived);
break; break;
case PACKET_HEADER_ENVIRONMENT_DATA: case PACKET_HEADER_ENVIRONMENT_DATA:
app->_environment.parseData(app->_incomingPacket, bytesReceived); app->_environment.parseData(&senderAddress, app->_incomingPacket, bytesReceived);
break; break;
case PACKET_HEADER_BULK_AVATAR_DATA: case PACKET_HEADER_BULK_AVATAR_DATA:
AgentList::getInstance()->processBulkAgentData(&senderAddress, AgentList::getInstance()->processBulkAgentData(&senderAddress,

View file

@ -63,6 +63,7 @@ public:
Avatar* getAvatar() { return &_myAvatar; } Avatar* getAvatar() { return &_myAvatar; }
VoxelSystem* getVoxels() { return &_voxels; } VoxelSystem* getVoxels() { return &_voxels; }
Environment* getEnvironment() { return &_environment; }
private slots: private slots:

View file

@ -238,12 +238,9 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
// apply gravity and collision with the ground/floor // apply gravity and collision with the ground/floor
if (_isMine && USING_AVATAR_GRAVITY) { if (_isMine && USING_AVATAR_GRAVITY) {
if (_position.y > _pelvisStandingHeight + 0.01f) { _velocity += _gravity * (GRAVITY_SCALE * deltaTime);
_velocity += _gravity * (GRAVITY_SCALE * deltaTime);
} else if (_position.y < _pelvisStandingHeight) { updateCollisionWithEnvironment();
_position.y = _pelvisStandingHeight;
_velocity.y = -_velocity.y * BOUNCE;
}
} }
// update body springs // update body springs
@ -256,7 +253,7 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
// collision response with voxels // collision response with voxels
if (_isMine) { if (_isMine) {
updateCollisionWithVoxels(deltaTime); updateCollisionWithVoxels();
} }
// driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely) // driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely)
@ -597,18 +594,36 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d
} }
} }
void Avatar::updateCollisionWithVoxels(float deltaTime) { void Avatar::updateCollisionWithEnvironment() {
VoxelSystem* voxels = Application::getInstance()->getVoxels(); if (_position.y < _pelvisStandingHeight) {
float radius = _height * 0.125f; applyCollisionWithScene(glm::vec3(0.0f, _pelvisStandingHeight - _position.y, 0.0f));
glm::vec3 halfVector = glm::vec3(0.0f, _height * ONE_HALF - radius, 0.0f);
glm::vec3 penetration;
if (voxels->findCapsulePenetration(_position - halfVector, _position + halfVector, radius, penetration)) {
_position += penetration;
// reflect the velocity component in the direction of penetration
glm::vec3 direction = glm::normalize(penetration);
_velocity -= 2.0f * glm::dot(_velocity, direction) * direction * BOUNCE;
} }
float radius = _height * 0.125f;
glm::vec3 penetration;
if (Application::getInstance()->getEnvironment()->findCapsulePenetration(
_position - glm::vec3(0.0f, _pelvisStandingHeight - radius, 0.0f),
_position + glm::vec3(0.0f, _height - _pelvisStandingHeight - radius, 0.0f), radius, penetration)) {
applyCollisionWithScene(penetration);
}
}
void Avatar::updateCollisionWithVoxels() {
float radius = _height * 0.125f;
glm::vec3 penetration;
if (Application::getInstance()->getVoxels()->findCapsulePenetration(
_position - glm::vec3(0.0f, _pelvisStandingHeight - radius, 0.0f),
_position + glm::vec3(0.0f, _height - _pelvisStandingHeight - radius, 0.0f), radius, penetration)) {
applyCollisionWithScene(penetration);
}
}
void Avatar::applyCollisionWithScene(const glm::vec3& penetration) {
_position += penetration;
// reflect the velocity component in the direction of penetration
glm::vec3 direction = glm::normalize(penetration);
_velocity -= 2.0f * glm::dot(_velocity, direction) * direction * BOUNCE;
} }
void Avatar::updateAvatarCollisions(float deltaTime) { void Avatar::updateAvatarCollisions(float deltaTime) {

View file

@ -194,7 +194,9 @@ private:
void updateHandMovementAndTouching(float deltaTime); void updateHandMovementAndTouching(float deltaTime);
void updateAvatarCollisions(float deltaTime); void updateAvatarCollisions(float deltaTime);
void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ); void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime );
void updateCollisionWithVoxels(float deltaTime); void updateCollisionWithEnvironment();
void updateCollisionWithVoxels();
void applyCollisionWithScene(const glm::vec3& penetration);
void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime ); void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime );
void setHeadFromGyros(glm::vec3 * eulerAngles, glm::vec3 * angularVelocity, float deltaTime, float smoothingTime); void setHeadFromGyros(glm::vec3 * eulerAngles, glm::vec3 * angularVelocity, float deltaTime, float smoothingTime);
void checkForMouseRayTouching(); void checkForMouseRayTouching();

View file

@ -6,7 +6,9 @@
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
#include <QByteArray> #include <QByteArray>
#include <QtDebug>
#include <GeometryUtil.h>
#include <SharedUtil.h> #include <SharedUtil.h>
#include "Camera.h" #include "Camera.h"
@ -14,64 +16,96 @@
#include "renderer/ProgramObject.h" #include "renderer/ProgramObject.h"
#include "world.h" #include "world.h"
uint qHash(const sockaddr& address) {
const sockaddr_in* inetAddress = reinterpret_cast<const sockaddr_in*>(&address);
if (inetAddress->sin_family != AF_INET) {
return 0; // shouldn't happen, but if it does, zero is a perfectly valid hash
}
return inetAddress->sin_port + qHash(QByteArray::fromRawData(
reinterpret_cast<const char*>(&inetAddress->sin_addr), sizeof(in_addr)));
}
bool operator== (const sockaddr& addr1, const sockaddr& addr2) {
return socketMatch(&addr1, &addr2);
}
void Environment::init() { void Environment::init() {
switchToResourcesParentIfRequired(); switchToResourcesParentIfRequired();
_skyFromAtmosphereProgram = createSkyProgram("Atmosphere", _skyFromAtmosphereUniformLocations); _skyFromAtmosphereProgram = createSkyProgram("Atmosphere", _skyFromAtmosphereUniformLocations);
_skyFromSpaceProgram = createSkyProgram("Space", _skyFromSpaceUniformLocations); _skyFromSpaceProgram = createSkyProgram("Space", _skyFromSpaceUniformLocations);
// start off with a default-constructed environment data
sockaddr addr = { AF_INET };
_data[addr][0];
} }
void Environment::renderAtmosphere(Camera& camera) { void Environment::renderAtmospheres(Camera& camera) {
glPushMatrix(); foreach (const ServerData& serverData, _data) {
glTranslatef(getAtmosphereCenter().x, getAtmosphereCenter().y, getAtmosphereCenter().z); foreach (const EnvironmentData& environmentData, serverData) {
renderAtmosphere(camera, environmentData);
glm::vec3 relativeCameraPos = camera.getPosition() - getAtmosphereCenter(); }
float height = glm::length(relativeCameraPos);
// 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;
} }
}
glm::vec3 Environment::getGravity (const glm::vec3& position) const {
glm::vec3 gravity;
foreach (const ServerData& serverData, _data) {
foreach (const EnvironmentData& environmentData, serverData) {
glm::vec3 vector = environmentData.getAtmosphereCenter() - position;
if (glm::length(vector) < environmentData.getAtmosphereOuterRadius()) {
gravity += glm::normalize(vector) * environmentData.getGravity();
}
}
}
return gravity;
}
const EnvironmentData& Environment::getClosestData(const glm::vec3& position) const {
const EnvironmentData* closest;
float closestDistance = FLT_MAX;
foreach (const ServerData& serverData, _data) {
foreach (const EnvironmentData& environmentData, serverData) {
float distance = glm::distance(position, environmentData.getAtmosphereCenter()) -
environmentData.getAtmosphereOuterRadius();
if (distance < closestDistance) {
closest = &environmentData;
closestDistance = distance;
}
}
}
return *closest;
}
bool Environment::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end,
float radius, glm::vec3& penetration) const {
bool found = false;
penetration = glm::vec3(0.0f, 0.0f, 0.0f);
foreach (const ServerData& serverData, _data) {
foreach (const EnvironmentData& environmentData, serverData) {
glm::vec3 vector = computeVectorFromPointToSegment(environmentData.getAtmosphereCenter(), start, end);
float vectorLength = glm::length(vector);
float distance = vectorLength - environmentData.getAtmosphereInnerRadius() - radius;
if (distance < 0.0f) {
penetration += vector * (-distance / vectorLength);
found = true;
}
}
}
return found;
}
int Environment::parseData(sockaddr *senderAddress, unsigned char* sourceBuffer, int numBytes) {
EnvironmentData newData;
int bytesRead = newData.parseData(sourceBuffer, numBytes);
// the constants here are from Sean O'Neil's GPU Gems entry // update the mapping by address/ID
// (http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html), GameEngine.cpp _data[*senderAddress][newData.getID()] = newData;
program->bind();
program->setUniform(locations[CAMERA_POS_LOCATION], relativeCameraPos);
glm::vec3 lightDirection = glm::normalize(getSunLocation());
program->setUniform(locations[LIGHT_POS_LOCATION], lightDirection);
program->setUniformValue(locations[INV_WAVELENGTH_LOCATION],
1 / powf(getScatteringWavelengths().r, 4.0f),
1 / powf(getScatteringWavelengths().g, 4.0f),
1 / powf(getScatteringWavelengths().b, 4.0f));
program->setUniformValue(locations[CAMERA_HEIGHT2_LOCATION], height * height);
program->setUniformValue(locations[OUTER_RADIUS_LOCATION], getAtmosphereOuterRadius());
program->setUniformValue(locations[OUTER_RADIUS2_LOCATION], getAtmosphereOuterRadius() * getAtmosphereOuterRadius());
program->setUniformValue(locations[INNER_RADIUS_LOCATION], getAtmosphereInnerRadius());
program->setUniformValue(locations[KR_ESUN_LOCATION], getRayleighScattering() * getSunBrightness());
program->setUniformValue(locations[KM_ESUN_LOCATION], getMieScattering() * getSunBrightness());
program->setUniformValue(locations[KR_4PI_LOCATION], getRayleighScattering() * 4.0f * PIf);
program->setUniformValue(locations[KM_4PI_LOCATION], getMieScattering() * 4.0f * PIf);
program->setUniformValue(locations[SCALE_LOCATION], 1.0f / (getAtmosphereOuterRadius() - getAtmosphereInnerRadius()));
program->setUniformValue(locations[SCALE_DEPTH_LOCATION], 0.25f);
program->setUniformValue(locations[SCALE_OVER_SCALE_DEPTH_LOCATION],
(1.0f / (getAtmosphereOuterRadius() - getAtmosphereInnerRadius())) / 0.25f);
program->setUniformValue(locations[G_LOCATION], -0.990f);
program->setUniformValue(locations[G2_LOCATION], -0.990f * -0.990f);
glDepthMask(GL_FALSE); // remove the default mapping, if any
glDisable(GL_DEPTH_TEST); sockaddr addr = { AF_INET };
glutSolidSphere(getAtmosphereOuterRadius(), 100, 50); _data.remove(addr);
glDepthMask(GL_TRUE);
program->release(); return bytesRead;
glPopMatrix();
} }
ProgramObject* Environment::createSkyProgram(const char* from, int* locations) { ProgramObject* Environment::createSkyProgram(const char* from, int* locations) {
@ -100,3 +134,57 @@ ProgramObject* Environment::createSkyProgram(const char* from, int* locations) {
return program; return program;
} }
void Environment::renderAtmosphere(Camera& camera, const EnvironmentData& data) {
glPushMatrix();
glTranslatef(data.getAtmosphereCenter().x, data.getAtmosphereCenter().y, data.getAtmosphereCenter().z);
glm::vec3 relativeCameraPos = camera.getPosition() - data.getAtmosphereCenter();
float height = glm::length(relativeCameraPos);
// use the appropriate shader depending on whether we're inside or outside
ProgramObject* program;
int* locations;
if (height < data.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(data.getSunLocation());
program->setUniform(locations[LIGHT_POS_LOCATION], lightDirection);
program->setUniformValue(locations[INV_WAVELENGTH_LOCATION],
1 / powf(data.getScatteringWavelengths().r, 4.0f),
1 / powf(data.getScatteringWavelengths().g, 4.0f),
1 / powf(data.getScatteringWavelengths().b, 4.0f));
program->setUniformValue(locations[CAMERA_HEIGHT2_LOCATION], height * height);
program->setUniformValue(locations[OUTER_RADIUS_LOCATION], data.getAtmosphereOuterRadius());
program->setUniformValue(locations[OUTER_RADIUS2_LOCATION], data.getAtmosphereOuterRadius() * data.getAtmosphereOuterRadius());
program->setUniformValue(locations[INNER_RADIUS_LOCATION], data.getAtmosphereInnerRadius());
program->setUniformValue(locations[KR_ESUN_LOCATION], data.getRayleighScattering() * data.getSunBrightness());
program->setUniformValue(locations[KM_ESUN_LOCATION], data.getMieScattering() * data.getSunBrightness());
program->setUniformValue(locations[KR_4PI_LOCATION], data.getRayleighScattering() * 4.0f * PIf);
program->setUniformValue(locations[KM_4PI_LOCATION], data.getMieScattering() * 4.0f * PIf);
program->setUniformValue(locations[SCALE_LOCATION], 1.0f / (data.getAtmosphereOuterRadius() - data.getAtmosphereInnerRadius()));
program->setUniformValue(locations[SCALE_DEPTH_LOCATION], 0.25f);
program->setUniformValue(locations[SCALE_OVER_SCALE_DEPTH_LOCATION],
(1.0f / (data.getAtmosphereOuterRadius() - data.getAtmosphereInnerRadius())) / 0.25f);
program->setUniformValue(locations[G_LOCATION], -0.990f);
program->setUniformValue(locations[G2_LOCATION], -0.990f * -0.990f);
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
glutSolidSphere(data.getAtmosphereOuterRadius(), 100, 50);
glDepthMask(GL_TRUE);
program->release();
glPopMatrix();
}

View file

@ -9,22 +9,35 @@
#ifndef __interface__Environment__ #ifndef __interface__Environment__
#define __interface__Environment__ #define __interface__Environment__
#include <QHash>
#include <UDPSocket.h>
#include "EnvironmentData.h" #include "EnvironmentData.h"
#include "InterfaceConfig.h" #include "InterfaceConfig.h"
class Camera; class Camera;
class ProgramObject; class ProgramObject;
class Environment : public EnvironmentData { class Environment {
public: public:
void init(); void init();
void renderAtmosphere(Camera& camera); void renderAtmospheres(Camera& camera);
glm::vec3 getGravity (const glm::vec3& position) const;
const EnvironmentData& getClosestData(const glm::vec3& position) const;
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
int parseData(sockaddr *senderAddress, unsigned char* sourceBuffer, int numBytes);
private: private:
ProgramObject* createSkyProgram(const char* from, int* locations); ProgramObject* createSkyProgram(const char* from, int* locations);
void renderAtmosphere(Camera& camera, const EnvironmentData& data);
ProgramObject* _skyFromAtmosphereProgram; ProgramObject* _skyFromAtmosphereProgram;
ProgramObject* _skyFromSpaceProgram; ProgramObject* _skyFromSpaceProgram;
@ -50,6 +63,10 @@ private:
int _skyFromAtmosphereUniformLocations[LOCATION_COUNT]; int _skyFromAtmosphereUniformLocations[LOCATION_COUNT];
int _skyFromSpaceUniformLocations[LOCATION_COUNT]; int _skyFromSpaceUniformLocations[LOCATION_COUNT];
typedef QHash<int, EnvironmentData> ServerData;
QHash<sockaddr, ServerData> _data;
}; };
#endif /* defined(__interface__Environment__) */ #endif /* defined(__interface__Environment__) */

View file

@ -337,16 +337,15 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) {
} else { } else {
voxelsUpdated += updateNodeInArraysAsPartialVBO(node); voxelsUpdated += updateNodeInArraysAsPartialVBO(node);
} }
node->clearDirtyBit(); // clear the dirty bit, do this before we potentially delete things.
// If the node has been asked to be deleted, but we've gotten to here, after updateNodeInArraysXXX() // If the node has been asked to be deleted, but we've gotten to here, after updateNodeInArraysXXX()
// then it means our VBOs are "clean" and our vertices have been removed or not added. So we can now // then it means our VBOs are "clean" and our vertices have been removed or not added. So we can now
// safely remove the node from the tree and actually delete it. // safely remove the node from the tree and actually delete it.
// otherwise honor our calculated shouldRender
if (node->isStagedForDeletion()) { if (node->isStagedForDeletion()) {
_tree->deleteVoxelCodeFromTree(node->getOctalCode()); _tree->deleteVoxelCodeFromTree(node->getOctalCode());
} }
node->clearDirtyBit(); // always clear the dirty bit, even if it doesn't need to be rendered
return voxelsUpdated; return voxelsUpdated;
} }

View file

@ -25,4 +25,5 @@ endif (WIN32)
if (UNIX AND NOT APPLE) if (UNIX AND NOT APPLE)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT})
endif (UNIX AND NOT APPLE) endif (UNIX AND NOT APPLE)

View file

@ -33,4 +33,10 @@ const PACKET_HEADER PACKET_HEADER_ENVIRONMENT_DATA = 'e';
const PACKET_HEADER PACKET_HEADER_DOMAIN_LIST_REQUEST = 'L'; const PACKET_HEADER PACKET_HEADER_DOMAIN_LIST_REQUEST = 'L';
const PACKET_HEADER PACKET_HEADER_DOMAIN_RFD = 'C'; const PACKET_HEADER PACKET_HEADER_DOMAIN_RFD = 'C';
// These are supported Z-Command
#define ERASE_ALL_COMMAND "erase all"
#define ADD_SCENE_COMMAND "add scene"
#define TEST_COMMAND "a message"
#endif #endif

View file

@ -25,7 +25,7 @@
sockaddr_in destSockaddr, senderAddress; sockaddr_in destSockaddr, senderAddress;
bool socketMatch(sockaddr* first, sockaddr* second) { bool socketMatch(const sockaddr* first, const sockaddr* second) {
if (first != NULL && second != NULL) { if (first != NULL && second != NULL) {
// utility function that indicates if two sockets are equivalent // utility function that indicates if two sockets are equivalent
@ -36,8 +36,8 @@ bool socketMatch(sockaddr* first, sockaddr* second) {
// not the same family, can't be equal // not the same family, can't be equal
return false; return false;
} else if (first->sa_family == AF_INET) { } else if (first->sa_family == AF_INET) {
sockaddr_in *firstIn = (sockaddr_in *) first; const sockaddr_in *firstIn = (const sockaddr_in *) first;
sockaddr_in *secondIn = (sockaddr_in *) second; const sockaddr_in *secondIn = (const sockaddr_in *) second;
return firstIn->sin_addr.s_addr == secondIn->sin_addr.s_addr return firstIn->sin_addr.s_addr == secondIn->sin_addr.s_addr
&& firstIn->sin_port == secondIn->sin_port; && firstIn->sin_port == secondIn->sin_port;

View file

@ -34,7 +34,7 @@ private:
bool blocking; bool blocking;
}; };
bool socketMatch(sockaddr* first, sockaddr* second); bool socketMatch(const sockaddr* first, const sockaddr* second);
int packSocket(unsigned char* packStore, in_addr_t inAddress, in_port_t networkOrderPort); int packSocket(unsigned char* packStore, in_addr_t inAddress, in_port_t networkOrderPort);
int packSocket(unsigned char* packStore, sockaddr* socketToPack); int packSocket(unsigned char* packStore, sockaddr* socketToPack);
int unpackSocket(unsigned char* packedData, sockaddr* unpackDestSocket); int unpackSocket(unsigned char* packedData, sockaddr* unpackDestSocket);

View file

@ -11,8 +11,10 @@
#include "PacketHeaders.h" #include "PacketHeaders.h"
// initial values from Sean O'Neil's GPU Gems entry (http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html), // 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) // GameEngine.cpp
EnvironmentData::EnvironmentData() : EnvironmentData::EnvironmentData(int id) :
_id(id),
_gravity(1.0f),
_atmosphereCenter(0, -1000, 0), _atmosphereCenter(0, -1000, 0),
_atmosphereInnerRadius(1000), _atmosphereInnerRadius(1000),
_atmosphereOuterRadius(1025), _atmosphereOuterRadius(1025),
@ -27,7 +29,13 @@ int EnvironmentData::getBroadcastData(unsigned char* destinationBuffer) const {
unsigned char* bufferStart = destinationBuffer; unsigned char* bufferStart = destinationBuffer;
*destinationBuffer++ = PACKET_HEADER_ENVIRONMENT_DATA; *destinationBuffer++ = PACKET_HEADER_ENVIRONMENT_DATA;
memcpy(destinationBuffer, &_id, sizeof(_id));
destinationBuffer += sizeof(_id);
memcpy(destinationBuffer, &_gravity, sizeof(_gravity));
destinationBuffer += sizeof(_gravity);
memcpy(destinationBuffer, &_atmosphereCenter, sizeof(_atmosphereCenter)); memcpy(destinationBuffer, &_atmosphereCenter, sizeof(_atmosphereCenter));
destinationBuffer += sizeof(_atmosphereCenter); destinationBuffer += sizeof(_atmosphereCenter);
@ -61,6 +69,12 @@ int EnvironmentData::parseData(unsigned char* sourceBuffer, int numBytes) {
unsigned char* startPosition = sourceBuffer; unsigned char* startPosition = sourceBuffer;
memcpy(&_id, sourceBuffer, sizeof(_id));
sourceBuffer += sizeof(_id);
memcpy(&_gravity, sourceBuffer, sizeof(_gravity));
sourceBuffer += sizeof(_gravity);
memcpy(&_atmosphereCenter, sourceBuffer, sizeof(_atmosphereCenter)); memcpy(&_atmosphereCenter, sourceBuffer, sizeof(_atmosphereCenter));
sourceBuffer += sizeof(_atmosphereCenter); sourceBuffer += sizeof(_atmosphereCenter);

View file

@ -14,7 +14,13 @@
class EnvironmentData { class EnvironmentData {
public: public:
EnvironmentData(); EnvironmentData(int id = 0);
void setID(int id) { _id = id; }
int getID() const { return _id; }
void setGravity(float gravity) { _gravity = gravity; }
float getGravity() const { return _gravity; }
void setAtmosphereCenter(const glm::vec3& center) { _atmosphereCenter = center; } void setAtmosphereCenter(const glm::vec3& center) { _atmosphereCenter = center; }
void setAtmosphereInnerRadius(float radius) { _atmosphereInnerRadius = radius; } void setAtmosphereInnerRadius(float radius) { _atmosphereInnerRadius = radius; }
@ -41,6 +47,10 @@ public:
private: private:
int _id;
float _gravity;
glm::vec3 _atmosphereCenter; glm::vec3 _atmosphereCenter;
float _atmosphereInnerRadius; float _atmosphereInnerRadius;
float _atmosphereOuterRadius; float _atmosphereOuterRadius;

View file

@ -0,0 +1,23 @@
//
// GeometryUtil.cpp
// interface
//
// Created by Andrzej Kapolka on 5/21/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
#include "GeometryUtil.h"
glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end) {
// compute the projection of the point vector onto the segment vector
glm::vec3 segmentVector = end - start;
float proj = glm::dot(point - start, segmentVector) / glm::dot(segmentVector, segmentVector);
if (proj <= 0.0f) { // closest to the start
return start - point;
} else if (proj >= 1.0f) { // closest to the end
return end - point;
} else { // closest to the middle
return start + segmentVector*proj - point;
}
}

View file

@ -0,0 +1,16 @@
//
// GeometryUtil.h
// interface
//
// Created by Andrzej Kapolka on 5/21/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__GeometryUtil__
#define __interface__GeometryUtil__
#include <glm/glm.hpp>
glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end);
#endif /* defined(__interface__GeometryUtil__) */

View file

@ -16,6 +16,7 @@
#include "Log.h" #include "Log.h"
#include "PacketHeaders.h" #include "PacketHeaders.h"
#include "OctalCode.h" #include "OctalCode.h"
#include "GeometryUtil.h"
#include "VoxelTree.h" #include "VoxelTree.h"
#include "VoxelNodeBag.h" #include "VoxelNodeBag.h"
#include "ViewFrustum.h" #include "ViewFrustum.h"
@ -29,14 +30,15 @@ int boundaryDistanceForRenderLevel(unsigned int renderLevel) {
return voxelSizeScale / powf(2, renderLevel); return voxelSizeScale / powf(2, renderLevel);
} }
VoxelTree::VoxelTree() : VoxelTree::VoxelTree(bool shouldReaverage) :
voxelsCreated(0), voxelsCreated(0),
voxelsColored(0), voxelsColored(0),
voxelsBytesRead(0), voxelsBytesRead(0),
voxelsCreatedStats(100), voxelsCreatedStats(100),
voxelsColoredStats(100), voxelsColoredStats(100),
voxelsBytesReadStats(100), voxelsBytesReadStats(100),
_isDirty(true) { _isDirty(true),
_shouldReaverage(shouldReaverage) {
rootNode = new VoxelNode(); rootNode = new VoxelNode();
} }
@ -254,12 +256,13 @@ void VoxelTree::deleteVoxelAt(float x, float y, float z, float s, bool stage) {
unsigned char* octalCode = pointToVoxel(x,y,z,s,0,0,0); unsigned char* octalCode = pointToVoxel(x,y,z,s,0,0,0);
deleteVoxelCodeFromTree(octalCode, stage); deleteVoxelCodeFromTree(octalCode, stage);
delete octalCode; // cleanup memory delete octalCode; // cleanup memory
reaverageVoxelColors(rootNode);
} }
// Note: uses the codeColorBuffer format, but the color's are ignored, because // Note: uses the codeColorBuffer format, but the color's are ignored, because
// this only finds and deletes the node from the tree. // this only finds and deletes the node from the tree.
void VoxelTree::deleteVoxelCodeFromTree(unsigned char* codeBuffer, bool stage) { void VoxelTree::deleteVoxelCodeFromTree(unsigned char* codeBuffer, bool stage, bool collapseEmptyTrees) {
VoxelNode* parentNode = NULL; VoxelNode* parentNode = NULL;
VoxelNode* nodeToDelete = nodeForOctalCode(rootNode, codeBuffer, &parentNode); VoxelNode* nodeToDelete = nodeForOctalCode(rootNode, codeBuffer, &parentNode);
// If the node exists... // If the node exists...
@ -276,14 +279,13 @@ void VoxelTree::deleteVoxelCodeFromTree(unsigned char* codeBuffer, bool stage) {
} }
// If we're not a colored leaf, and we have no children, then delete ourselves // If we're not a colored leaf, and we have no children, then delete ourselves
// This will collapse the empty tree above us. // This will collapse the empty tree above us.
if (parentNode->getChildCount() == 0 && !parentNode->isColored()) { if (collapseEmptyTrees && parentNode->getChildCount() == 0 && !parentNode->isColored()) {
// Can't delete the root this way. // Can't delete the root this way.
if (parentNode != rootNode) { if (parentNode != rootNode) {
deleteVoxelCodeFromTree(parentNode->getOctalCode(),stage); deleteVoxelCodeFromTree(parentNode->getOctalCode(), stage, collapseEmptyTrees);
} }
} }
reaverageVoxelColors(rootNode); // Fix our colors!! Need to call it on rootNode
_isDirty = true; _isDirty = true;
} }
} else if (nodeToDelete->isLeaf()) { } else if (nodeToDelete->isLeaf()) {
@ -357,11 +359,12 @@ void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int buffe
unsigned char octets = (unsigned char)*pVoxelData; unsigned char octets = (unsigned char)*pVoxelData;
int voxelDataSize = bytesRequiredForCodeLength(octets)+3; // 3 for color! int voxelDataSize = bytesRequiredForCodeLength(octets)+3; // 3 for color!
deleteVoxelCodeFromTree(pVoxelData); deleteVoxelCodeFromTree(pVoxelData, ACTUALLY_DELETE, COLLAPSE_EMPTY_TREE);
pVoxelData+=voxelDataSize; pVoxelData+=voxelDataSize;
atByte+=voxelDataSize; atByte+=voxelDataSize;
} }
reaverageVoxelColors(rootNode); // Fix our colors!! Need to call it on rootNode
} }
void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { void VoxelTree::printTreeForDebugging(VoxelNode *startNode) {
@ -411,19 +414,20 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) {
} }
void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) { void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) {
bool hasChildren = false; // if our tree is a reaveraging tree, then we do this, otherwise we don't do anything
if (_shouldReaverage) {
bool hasChildren = false;
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
if (startNode->getChildAtIndex(i)) { if (startNode->getChildAtIndex(i)) {
reaverageVoxelColors(startNode->getChildAtIndex(i)); reaverageVoxelColors(startNode->getChildAtIndex(i));
hasChildren = true; hasChildren = true;
}
} }
}
if (hasChildren) { // collapseIdenticalLeaves() returns true if it collapses the leaves
bool childrenCollapsed = startNode->collapseIdenticalLeaves(); // in which case we don't need to set the average color
if (hasChildren && !startNode->collapseIdenticalLeaves()) {
if (!childrenCollapsed) {
startNode->setColorFromAverageOfChildren(); startNode->setColorFromAverageOfChildren();
} }
} }
@ -740,21 +744,6 @@ public:
bool found; bool found;
}; };
glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end) {
// compute the projection of the point vector onto the segment vector
glm::vec3 segmentVector = end - start;
float proj = glm::dot(point - start, segmentVector) / glm::dot(segmentVector, segmentVector);
if (proj <= 0.0f) { // closest to the start
return start - point;
} else if (proj >= 1.0f) { // closest to the end
return end - point;
} else { // closest to the middle
return start + segmentVector*proj - point;
}
}
bool findCapsulePenetrationOp(VoxelNode* node, void* extraData) { bool findCapsulePenetrationOp(VoxelNode* node, void* extraData) {
CapsuleArgs* args = static_cast<CapsuleArgs*>(extraData); CapsuleArgs* args = static_cast<CapsuleArgs*>(extraData);

View file

@ -24,6 +24,10 @@ typedef enum {GRADIENT, RANDOM, NATURAL} creationMode;
#define NO_COLOR false #define NO_COLOR false
#define WANT_COLOR true #define WANT_COLOR true
#define IGNORE_VIEW_FRUSTUM NULL #define IGNORE_VIEW_FRUSTUM NULL
#define JUST_STAGE_DELETION true
#define ACTUALLY_DELETE false
#define COLLAPSE_EMPTY_TREE true
#define DONT_COLLAPSE false
class VoxelTree { class VoxelTree {
public: public:
@ -37,7 +41,7 @@ public:
SimpleMovingAverage voxelsColoredStats; SimpleMovingAverage voxelsColoredStats;
SimpleMovingAverage voxelsBytesReadStats; SimpleMovingAverage voxelsBytesReadStats;
VoxelTree(); VoxelTree(bool shouldReaverage = false);
~VoxelTree(); ~VoxelTree();
VoxelNode *rootNode; VoxelNode *rootNode;
@ -49,7 +53,8 @@ public:
void readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes, void readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes,
bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS); bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS);
void readCodeColorBufferToTree(unsigned char *codeColorBuffer, bool destructive = false); void readCodeColorBufferToTree(unsigned char *codeColorBuffer, bool destructive = false);
void deleteVoxelCodeFromTree(unsigned char *codeBuffer, bool stage = false); void deleteVoxelCodeFromTree(unsigned char *codeBuffer, bool stage = ACTUALLY_DELETE,
bool collapseEmptyTrees = DONT_COLLAPSE);
void printTreeForDebugging(VoxelNode *startNode); void printTreeForDebugging(VoxelNode *startNode);
void reaverageVoxelColors(VoxelNode *startNode); void reaverageVoxelColors(VoxelNode *startNode);
@ -111,6 +116,7 @@ private:
bool _isDirty; bool _isDirty;
unsigned long int _nodesChangedFromBitstream; unsigned long int _nodesChangedFromBitstream;
bool _shouldReaverage;
}; };
int boundaryDistanceForRenderLevel(unsigned int renderLevel); int boundaryDistanceForRenderLevel(unsigned int renderLevel);

View file

@ -49,7 +49,7 @@ int PACKETS_PER_CLIENT_PER_INTERVAL = 50;
const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4; const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4;
VoxelTree randomTree; VoxelTree randomTree(true); // this is a reaveraging tree
bool wantVoxelPersist = true; bool wantVoxelPersist = true;
bool wantLocalDomain = false; bool wantLocalDomain = false;
@ -59,7 +59,7 @@ bool debugVoxelSending = false;
bool shouldShowAnimationDebug = false; bool shouldShowAnimationDebug = false;
bool wantSearchForColoredNodes = false; bool wantSearchForColoredNodes = false;
EnvironmentData environmentData; EnvironmentData environmentData[3];
void randomlyFillVoxelTree(int levelsToGo, VoxelNode *currentRootNode) { void randomlyFillVoxelTree(int levelsToGo, VoxelNode *currentRootNode) {
@ -161,7 +161,8 @@ void resInVoxelDistributor(AgentList* agentList,
int trueBytesSent = 0; int trueBytesSent = 0;
double start = usecTimestampNow(); double start = usecTimestampNow();
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - 1) { int environmentPacketCount = sizeof(environmentData) / sizeof(environmentData[0]);
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - environmentPacketCount) {
if (!agentData->nodeBag.isEmpty()) { if (!agentData->nodeBag.isEmpty()) {
VoxelNode* subTree = agentData->nodeBag.extract(); VoxelNode* subTree = agentData->nodeBag.extract();
bytesWritten = randomTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree, bytesWritten = randomTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree,
@ -192,11 +193,13 @@ void resInVoxelDistributor(AgentList* agentList,
packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left
} }
} }
// send the environment packet // send the environment packets
int envPacketLength = environmentData.getBroadcastData(tempOutputBuffer); for (int i = 0; i < environmentPacketCount; i++) {
agentList->getAgentSocket()->send(agent->getActiveSocket(), tempOutputBuffer, envPacketLength); int envPacketLength = environmentData[i].getBroadcastData(tempOutputBuffer);
trueBytesSent += envPacketLength; agentList->getAgentSocket()->send(agent->getActiveSocket(), tempOutputBuffer, envPacketLength);
truePacketsSent++; trueBytesSent += envPacketLength;
truePacketsSent++;
}
double end = usecTimestampNow(); double end = usecTimestampNow();
double elapsedmsec = (end - start)/1000.0; double elapsedmsec = (end - start)/1000.0;
@ -225,12 +228,17 @@ void resInVoxelDistributor(AgentList* agentList,
} }
} }
pthread_mutex_t treeLock;
// Version of voxel distributor that sends the deepest LOD level at once // Version of voxel distributor that sends the deepest LOD level at once
void deepestLevelVoxelDistributor(AgentList* agentList, void deepestLevelVoxelDistributor(AgentList* agentList,
AgentList::iterator& agent, AgentList::iterator& agent,
VoxelAgentData* agentData, VoxelAgentData* agentData,
bool viewFrustumChanged) { bool viewFrustumChanged) {
pthread_mutex_lock(&::treeLock);
int maxLevelReached = 0; int maxLevelReached = 0;
double start = usecTimestampNow(); double start = usecTimestampNow();
@ -293,7 +301,8 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
int trueBytesSent = 0; int trueBytesSent = 0;
double start = usecTimestampNow(); double start = usecTimestampNow();
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - 1) { int environmentPacketCount = sizeof(environmentData) / sizeof(environmentData[0]);
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - environmentPacketCount) {
if (!agentData->nodeBag.isEmpty()) { if (!agentData->nodeBag.isEmpty()) {
VoxelNode* subTree = agentData->nodeBag.extract(); VoxelNode* subTree = agentData->nodeBag.extract();
bytesWritten = randomTree.encodeTreeBitstream(INT_MAX, subTree, bytesWritten = randomTree.encodeTreeBitstream(INT_MAX, subTree,
@ -325,11 +334,13 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left
} }
} }
// send the environment packet // send the environment packets
int envPacketLength = environmentData.getBroadcastData(tempOutputBuffer); for (int i = 0; i < environmentPacketCount; i++) {
agentList->getAgentSocket()->send(agent->getActiveSocket(), tempOutputBuffer, envPacketLength); int envPacketLength = environmentData[i].getBroadcastData(tempOutputBuffer);
trueBytesSent += envPacketLength; agentList->getAgentSocket()->send(agent->getActiveSocket(), tempOutputBuffer, envPacketLength);
truePacketsSent++; trueBytesSent += envPacketLength;
truePacketsSent++;
}
double end = usecTimestampNow(); double end = usecTimestampNow();
double elapsedmsec = (end - start)/1000.0; double elapsedmsec = (end - start)/1000.0;
@ -356,6 +367,8 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
} // end if bag wasn't empty, and so we sent stuff... } // end if bag wasn't empty, and so we sent stuff...
pthread_mutex_unlock(&::treeLock);
} }
double lastPersistVoxels = 0; double lastPersistVoxels = 0;
@ -401,11 +414,11 @@ void *distributeVoxelsToListeners(void *args) {
VoxelAgentData* agentData = (VoxelAgentData*) agent->getLinkedData(); VoxelAgentData* agentData = (VoxelAgentData*) agent->getLinkedData();
// Sometimes the agent data has not yet been linked, in which case we can't really do anything // Sometimes the agent data has not yet been linked, in which case we can't really do anything
if (agentData) { if (agentData) {
bool viewFrustumChanged = agentData->updateCurrentViewFrustum(); bool viewFrustumChanged = agentData->updateCurrentViewFrustum();
if (::debugVoxelSending) { if (::debugVoxelSending) {
printf("agentData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged)); printf("agentData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged));
} }
if (agentData->getWantResIn()) { if (agentData->getWantResIn()) {
resInVoxelDistributor(agentList, agent, agentData); resInVoxelDistributor(agentList, agent, agentData);
@ -434,8 +447,10 @@ void attachVoxelAgentDataToAgent(Agent *newAgent) {
} }
} }
int main(int argc, const char * argv[]) int main(int argc, const char * argv[]) {
{
pthread_mutex_init(&::treeLock, NULL);
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_VOXEL, VOXEL_LISTEN_PORT); AgentList* agentList = AgentList::createInstance(AGENT_TYPE_VOXEL, VOXEL_LISTEN_PORT);
setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stdout, NULL, _IOLBF, 0);
@ -533,6 +548,16 @@ int main(int argc, const char * argv[])
addSphereScene(&randomTree); addSphereScene(&randomTree);
} }
// for now, initialize the environments with fixed values
environmentData[1].setID(1);
environmentData[1].setAtmosphereCenter(glm::vec3(0.5, 0.5, (0.25 - 0.06125)) * (float)TREE_SCALE);
environmentData[1].setAtmosphereInnerRadius(0.030625f * TREE_SCALE);
environmentData[1].setAtmosphereOuterRadius(0.030625f * TREE_SCALE * 1.025f);
environmentData[2].setID(2);
environmentData[2].setAtmosphereCenter(glm::vec3(0.5f, 0.5f, 0.5f) * (float)TREE_SCALE);
environmentData[2].setAtmosphereInnerRadius(0.1875f * TREE_SCALE);
environmentData[2].setAtmosphereOuterRadius(0.1875f * TREE_SCALE * 1.025f);
pthread_t sendVoxelThread; pthread_t sendVoxelThread;
pthread_create(&sendVoxelThread, NULL, distributeVoxelsToListeners, NULL); pthread_create(&sendVoxelThread, NULL, distributeVoxelsToListeners, NULL);
@ -553,89 +578,91 @@ int main(int argc, const char * argv[])
PerformanceWarning warn(::shouldShowAnimationDebug, PerformanceWarning warn(::shouldShowAnimationDebug,
destructive ? "PACKET_HEADER_SET_VOXEL_DESTRUCTIVE" : "PACKET_HEADER_SET_VOXEL", destructive ? "PACKET_HEADER_SET_VOXEL_DESTRUCTIVE" : "PACKET_HEADER_SET_VOXEL",
::shouldShowAnimationDebug); ::shouldShowAnimationDebug);
unsigned short int itemNumber = (*((unsigned short int*)&packetData[1])); unsigned short int itemNumber = (*((unsigned short int*)&packetData[1]));
if (::shouldShowAnimationDebug) { if (::shouldShowAnimationDebug) {
printf("got %s - command from client receivedBytes=%ld itemNumber=%d\n", printf("got %s - command from client receivedBytes=%ld itemNumber=%d\n",
destructive ? "PACKET_HEADER_SET_VOXEL_DESTRUCTIVE" : "PACKET_HEADER_SET_VOXEL", destructive ? "PACKET_HEADER_SET_VOXEL_DESTRUCTIVE" : "PACKET_HEADER_SET_VOXEL",
receivedBytes,itemNumber); receivedBytes,itemNumber);
} }
int atByte = 3; int atByte = sizeof(PACKET_HEADER) + sizeof(itemNumber);
unsigned char* pVoxelData = (unsigned char*)&packetData[3]; unsigned char* voxelData = (unsigned char*)&packetData[atByte];
while (atByte < receivedBytes) { while (atByte < receivedBytes) {
unsigned char octets = (unsigned char)*pVoxelData; unsigned char octets = (unsigned char)*voxelData;
int voxelDataSize = bytesRequiredForCodeLength(octets)+3; // 3 for color! const int COLOR_SIZE_IN_BYTES = 3;
int voxelCodeSize = bytesRequiredForCodeLength(octets); int voxelDataSize = bytesRequiredForCodeLength(octets) + COLOR_SIZE_IN_BYTES;
int voxelCodeSize = bytesRequiredForCodeLength(octets);
// color randomization on insert // color randomization on insert
int colorRandomizer = ::wantColorRandomizer ? randIntInRange (-50, 50) : 0; int colorRandomizer = ::wantColorRandomizer ? randIntInRange (-50, 50) : 0;
int red = pVoxelData[voxelCodeSize+0]; int red = voxelData[voxelCodeSize + 0];
int green = pVoxelData[voxelCodeSize+1]; int green = voxelData[voxelCodeSize + 1];
int blue = pVoxelData[voxelCodeSize+2]; int blue = voxelData[voxelCodeSize + 2];
if (::shouldShowAnimationDebug) { if (::shouldShowAnimationDebug) {
printf("insert voxels - wantColorRandomizer=%s old r=%d,g=%d,b=%d \n", printf("insert voxels - wantColorRandomizer=%s old r=%d,g=%d,b=%d \n",
(::wantColorRandomizer?"yes":"no"),red,green,blue); (::wantColorRandomizer?"yes":"no"),red,green,blue);
} }
red = std::max(0,std::min(255,red + colorRandomizer)); red = std::max(0, std::min(255, red + colorRandomizer));
green = std::max(0,std::min(255,green + colorRandomizer)); green = std::max(0, std::min(255, green + colorRandomizer));
blue = std::max(0,std::min(255,blue + colorRandomizer)); blue = std::max(0, std::min(255, blue + colorRandomizer));
if (::shouldShowAnimationDebug) { if (::shouldShowAnimationDebug) {
printf("insert voxels - wantColorRandomizer=%s NEW r=%d,g=%d,b=%d \n", printf("insert voxels - wantColorRandomizer=%s NEW r=%d,g=%d,b=%d \n",
(::wantColorRandomizer?"yes":"no"),red,green,blue); (::wantColorRandomizer?"yes":"no"),red,green,blue);
} }
pVoxelData[voxelCodeSize+0]=red; voxelData[voxelCodeSize + 0] = red;
pVoxelData[voxelCodeSize+1]=green; voxelData[voxelCodeSize + 1] = green;
pVoxelData[voxelCodeSize+2]=blue; voxelData[voxelCodeSize + 2] = blue;
if (::shouldShowAnimationDebug) { if (::shouldShowAnimationDebug) {
float* vertices = firstVertexForCode(pVoxelData); float* vertices = firstVertexForCode(voxelData);
printf("inserting voxel at: %f,%f,%f\n",vertices[0],vertices[1],vertices[2]); printf("inserting voxel at: %f,%f,%f\n", vertices[0], vertices[1], vertices[2]);
delete []vertices; delete []vertices;
} }
randomTree.readCodeColorBufferToTree(pVoxelData, destructive); randomTree.readCodeColorBufferToTree(voxelData, destructive);
// skip to next // skip to next
pVoxelData+=voxelDataSize; voxelData += voxelDataSize;
atByte+=voxelDataSize; atByte += voxelDataSize;
} }
} }
if (packetData[0] == PACKET_HEADER_ERASE_VOXEL) { if (packetData[0] == PACKET_HEADER_ERASE_VOXEL) {
// Send these bits off to the VoxelTree class to process them // Send these bits off to the VoxelTree class to process them
//printf("got Erase Voxels message, have voxel tree do the work... randomTree.processRemoveVoxelBitstream()\n"); pthread_mutex_lock(&::treeLock);
randomTree.processRemoveVoxelBitstream((unsigned char*)packetData,receivedBytes); randomTree.processRemoveVoxelBitstream((unsigned char*)packetData, receivedBytes);
pthread_mutex_unlock(&::treeLock);
} }
if (packetData[0] == PACKET_HEADER_Z_COMMAND) { if (packetData[0] == PACKET_HEADER_Z_COMMAND) {
// the Z command is a special command that allows the sender to send the voxel server high level semantic // the Z command is a special command that allows the sender to send the voxel server high level semantic
// requests, like erase all, or add sphere scene // requests, like erase all, or add sphere scene
char* command = (char*) &packetData[1]; // start of the command char* command = (char*) &packetData[1]; // start of the command
int commandLength = strlen(command); // commands are null terminated strings int commandLength = strlen(command); // commands are null terminated strings
int totalLength = 1+commandLength+1; int totalLength = sizeof(PACKET_HEADER_Z_COMMAND) + commandLength + 1; // 1 for null termination
printf("got Z message len(%ld)= %s\n",receivedBytes,command); printf("got Z message len(%ld)= %s\n", receivedBytes, command);
while (totalLength <= receivedBytes) { while (totalLength <= receivedBytes) {
if (0==strcmp(command,(char*)"erase all")) { if (strcmp(command, ERASE_ALL_COMMAND) == 0) {
printf("got Z message == erase all\n"); printf("got Z message == erase all\n");
eraseVoxelTreeAndCleanupAgentVisitData(); eraseVoxelTreeAndCleanupAgentVisitData();
} }
if (0==strcmp(command,(char*)"add scene")) { if (strcmp(command, ADD_SCENE_COMMAND) == 0) {
printf("got Z message == add scene\n"); printf("got Z message == add scene\n");
addSphereScene(&randomTree); addSphereScene(&randomTree);
} }
if (0==strcmp(command,(char*)"a message")) { if (strcmp(command, TEST_COMMAND) == 0) {
printf("got Z message == a message, nothing to do, just report\n"); printf("got Z message == a message, nothing to do, just report\n");
} }
totalLength += commandLength+1; totalLength += commandLength + 1; // 1 for null termination
} }
// Now send this to the connected agents so they can also process these messages // Now send this to the connected agents so they can also process these messages
printf("rebroadcasting Z message to connected agents... agentList.broadcastToAgents()\n"); printf("rebroadcasting Z message to connected agents... agentList.broadcastToAgents()\n");
agentList->broadcastToAgents(packetData,receivedBytes, &AGENT_TYPE_AVATAR, 1); agentList->broadcastToAgents(packetData, receivedBytes, &AGENT_TYPE_AVATAR, 1);
} }
// If we got a PACKET_HEADER_HEAD_DATA, then we're talking to an AGENT_TYPE_AVATAR, and we // If we got a PACKET_HEADER_HEAD_DATA, then we're talking to an AGENT_TYPE_AVATAR, and we
// need to make sure we have it in our agentList. // need to make sure we have it in our agentList.
@ -653,6 +680,7 @@ int main(int argc, const char * argv[])
} }
pthread_join(sendVoxelThread, NULL); pthread_join(sendVoxelThread, NULL);
pthread_mutex_destroy(&::treeLock);
return 0; return 0;
} }