diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 6d278e641b..c6803f7e15 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -52,6 +52,7 @@ const float PERIPERSONAL_RADIUS = 1.0f; const float AVATAR_BRAKING_STRENGTH = 40.0f; const float JOINT_TOUCH_RANGE = 0.0005f; const float ANGULAR_RIGHTING_SPEED = 45.0f; +const float FLOATING_HEIGHT = 0.13f; const bool USING_HEAD_LEAN = false; const float LEAN_SENSITIVITY = 0.15; @@ -86,6 +87,7 @@ Avatar::Avatar(bool isMine) : _maxArmLength(0.0f), _orientation(), _pelvisStandingHeight(0.0f), + _pelvisFloatingHeight(0.0f), _displayingHead(true), _distanceToNearestAvatar(std::numeric_limits::max()), _gravity(0.0f, -1.0f, 0.0f), @@ -603,8 +605,8 @@ void Avatar::updateCollisionWithEnvironment() { 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)) { + _position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f), + _position + glm::vec3(0.0f, _height - _pelvisFloatingHeight - radius, 0.0f), radius, penetration)) { applyCollisionWithScene(penetration); } } @@ -613,8 +615,8 @@ 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)) { + _position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f), + _position + glm::vec3(0.0f, _height - _pelvisFloatingHeight - radius, 0.0f), radius, penetration)) { applyCollisionWithScene(penetration); } } @@ -866,14 +868,14 @@ void Avatar::initializeSkeleton() { _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.1, 0.0 ); _joint[ AVATAR_JOINT_LEFT_HIP ].defaultPosePosition = glm::vec3( -0.05, 0.0, -0.02 ); - _joint[ AVATAR_JOINT_LEFT_KNEE ].defaultPosePosition = glm::vec3( 0.0, -0.27, 0.02 ); - _joint[ AVATAR_JOINT_LEFT_HEEL ].defaultPosePosition = glm::vec3( 0.0, -0.27, -0.01 ); - _joint[ AVATAR_JOINT_LEFT_TOES ].defaultPosePosition = glm::vec3( 0.0, 0.0, 0.05 ); + _joint[ AVATAR_JOINT_LEFT_KNEE ].defaultPosePosition = glm::vec3( 0.01, -0.25, 0.03 ); + _joint[ AVATAR_JOINT_LEFT_HEEL ].defaultPosePosition = glm::vec3( 0.01, -0.22, -0.08 ); + _joint[ AVATAR_JOINT_LEFT_TOES ].defaultPosePosition = glm::vec3( 0.00, -0.03, 0.05 ); _joint[ AVATAR_JOINT_RIGHT_HIP ].defaultPosePosition = glm::vec3( 0.05, 0.0, -0.02 ); - _joint[ AVATAR_JOINT_RIGHT_KNEE ].defaultPosePosition = glm::vec3( 0.0, -0.27, 0.02 ); - _joint[ AVATAR_JOINT_RIGHT_HEEL ].defaultPosePosition = glm::vec3( 0.0, -0.27, -0.01 ); - _joint[ AVATAR_JOINT_RIGHT_TOES ].defaultPosePosition = glm::vec3( 0.0, 0.0, 0.05 ); + _joint[ AVATAR_JOINT_RIGHT_KNEE ].defaultPosePosition = glm::vec3( -0.01, -0.25, 0.03 ); + _joint[ AVATAR_JOINT_RIGHT_HEEL ].defaultPosePosition = glm::vec3( -0.01, -0.22, -0.08 ); + _joint[ AVATAR_JOINT_RIGHT_TOES ].defaultPosePosition = glm::vec3( -0.00, -0.03, 0.05 ); // specify the radii of the joints _joint[ AVATAR_JOINT_PELVIS ].radius = 0.07; @@ -897,12 +899,12 @@ void Avatar::initializeSkeleton() { _joint[ AVATAR_JOINT_LEFT_HIP ].radius = 0.04; _joint[ AVATAR_JOINT_LEFT_KNEE ].radius = 0.025; _joint[ AVATAR_JOINT_LEFT_HEEL ].radius = 0.025; - _joint[ AVATAR_JOINT_LEFT_TOES ].radius = 0.027; + _joint[ AVATAR_JOINT_LEFT_TOES ].radius = 0.025; _joint[ AVATAR_JOINT_RIGHT_HIP ].radius = 0.04; _joint[ AVATAR_JOINT_RIGHT_KNEE ].radius = 0.025; _joint[ AVATAR_JOINT_RIGHT_HEEL ].radius = 0.025; - _joint[ AVATAR_JOINT_RIGHT_TOES ].radius = 0.027; + _joint[ AVATAR_JOINT_RIGHT_TOES ].radius = 0.025; // specify the tightness of the springy positions as far as attraction to rigid body _joint[ AVATAR_JOINT_PELVIS ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 1.0; @@ -943,6 +945,8 @@ void Avatar::initializeSkeleton() { _joint[ AVATAR_JOINT_LEFT_KNEE ].length; //printf("_pelvisStandingHeight = %f\n", _pelvisStandingHeight); + _pelvisFloatingHeight = _pelvisStandingHeight + FLOATING_HEIGHT; + _height = ( _pelvisStandingHeight + diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 446d6cfe2e..20fd580328 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -173,6 +173,7 @@ private: glm::quat _righting; int _driveKeys[MAX_DRIVE_KEYS]; float _pelvisStandingHeight; + float _pelvisFloatingHeight; float _height; Balls* _balls; AvatarTouch _avatarTouch; diff --git a/interface/src/Environment.cpp b/interface/src/Environment.cpp index bdea0771ce..49ef26bb82 100644 --- a/interface/src/Environment.cpp +++ b/interface/src/Environment.cpp @@ -58,10 +58,16 @@ void Environment::renderAtmospheres(Camera& camera) { } glm::vec3 Environment::getGravity (const glm::vec3& position) { + // the "original gravity" + glm::vec3 gravity; + if (position.x > 0.0f && position.x < 10.0f && position.y > 0.0f && + position.y < 3.0f && position.z > 0.0f && position.z < 10.0f) { + gravity = glm::vec3(0.0f, -1.0f, 0.0f); + } + // get the lock for the duration of the call QMutexLocker locker(&_mutex); - glm::vec3 gravity; foreach (const ServerData& serverData, _data) { foreach (const EnvironmentData& environmentData, serverData) { glm::vec3 vector = environmentData.getAtmosphereCenter() - position; @@ -94,13 +100,23 @@ const EnvironmentData Environment::getClosestData(const glm::vec3& position) { bool Environment::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) { + // collide with the "floor" + bool found = false; + penetration = glm::vec3(0.0f, 0.0f, 0.0f); + float floorDist = qMin(start.y, end.y) - radius; + if (floorDist < 0.0f) { + penetration.y = -floorDist; + found = true; + } + // get the lock for the duration of the call QMutexLocker locker(&_mutex); - bool found = false; - penetration = glm::vec3(0.0f, 0.0f, 0.0f); foreach (const ServerData& serverData, _data) { foreach (const EnvironmentData& environmentData, serverData) { + if (environmentData.getGravity() == 0.0f) { + continue; // don't bother colliding with gravity-less environments + } glm::vec3 vector = computeVectorFromPointToSegment(environmentData.getAtmosphereCenter(), start, end); float vectorLength = glm::length(vector); float distance = vectorLength - environmentData.getAtmosphereInnerRadius() - radius; @@ -114,19 +130,29 @@ bool Environment::findCapsulePenetration(const glm::vec3& start, const glm::vec3 } int Environment::parseData(sockaddr *senderAddress, unsigned char* sourceBuffer, int numBytes) { - EnvironmentData newData; - int bytesRead = newData.parseData(sourceBuffer, numBytes); + // push past the packet header + unsigned char* start = sourceBuffer; + sourceBuffer++; + numBytes--; // get the lock for the duration of the call QMutexLocker locker(&_mutex); - // update the mapping by address/ID - _data[*senderAddress][newData.getID()] = newData; + EnvironmentData newData; + while (numBytes > 0) { + int dataLength = newData.parseData(sourceBuffer, numBytes); + + // update the mapping by address/ID + _data[*senderAddress][newData.getID()] = newData; + + sourceBuffer += dataLength; + numBytes -= dataLength; + } // remove the default mapping, if any _data.remove(getZeroAddress()); - return bytesRead; + return sourceBuffer - start; } ProgramObject* Environment::createSkyProgram(const char* from, int* locations) { diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 6e23413ea7..5829bbe34a 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -52,6 +52,10 @@ bool randomBoolean() { return rand() % 2; } +bool shouldDo(float desiredInterval, float deltaTime) { + return randFloat() < deltaTime / desiredInterval; +} + void outputBufferBits(unsigned char* buffer, int length, bool withNewLine) { for (int i = 0; i < length; i++) { outputBits(buffer[i], false); @@ -417,4 +421,3 @@ int insertIntoSortedArrays(void* value, float key, int originalIndex, } return -1; // error case } - diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 2458e1e5a2..8da9d7beca 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -44,6 +44,8 @@ float randFloatInRange (float min,float max); unsigned char randomColorValue(int minimum); bool randomBoolean(); +bool shouldDo(float desiredInterval, float deltaTime); + void outputBufferBits(unsigned char* buffer, int length, bool withNewLine = true); void outputBits(unsigned char byte, bool withNewLine = true); void printVoxelCode(unsigned char* voxelCode); diff --git a/libraries/voxels/src/EnvironmentData.cpp b/libraries/voxels/src/EnvironmentData.cpp index 4142a00ae6..935d4601e9 100644 --- a/libraries/voxels/src/EnvironmentData.cpp +++ b/libraries/voxels/src/EnvironmentData.cpp @@ -14,7 +14,7 @@ // GameEngine.cpp EnvironmentData::EnvironmentData(int id) : _id(id), - _gravity(1.0f), + _gravity(0.0f), _atmosphereCenter(0, -1000, 0), _atmosphereInnerRadius(1000), _atmosphereOuterRadius(1025), @@ -28,8 +28,6 @@ EnvironmentData::EnvironmentData(int id) : int EnvironmentData::getBroadcastData(unsigned char* destinationBuffer) const { unsigned char* bufferStart = destinationBuffer; - *destinationBuffer++ = PACKET_HEADER_ENVIRONMENT_DATA; - memcpy(destinationBuffer, &_id, sizeof(_id)); destinationBuffer += sizeof(_id); @@ -64,9 +62,6 @@ int EnvironmentData::getBroadcastData(unsigned char* destinationBuffer) const { } int EnvironmentData::parseData(unsigned char* sourceBuffer, int numBytes) { - // increment to push past the packet header - sourceBuffer++; - unsigned char* startPosition = sourceBuffer; memcpy(&_id, sourceBuffer, sizeof(_id)); diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index b1a3ed56ee..1cfcaa4282 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -49,6 +49,8 @@ int PACKETS_PER_CLIENT_PER_INTERVAL = 50; const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4; +const int ENVIRONMENT_SEND_INTERVAL_USECS = 1000000; + VoxelTree randomTree(false); // this is NOT a reaveraging tree bool wantVoxelPersist = true; bool wantLocalDomain = false; @@ -161,8 +163,8 @@ void resInVoxelDistributor(AgentList* agentList, int trueBytesSent = 0; double start = usecTimestampNow(); - int environmentPacketCount = sizeof(environmentData) / sizeof(environmentData[0]); - while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - environmentPacketCount) { + bool shouldSendEnvironments = shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS); + while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) { if (!agentData->nodeBag.isEmpty()) { VoxelNode* subTree = agentData->nodeBag.extract(); bytesWritten = randomTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree, @@ -194,13 +196,16 @@ void resInVoxelDistributor(AgentList* agentList, } } // send the environment packets - for (int i = 0; i < environmentPacketCount; i++) { - int envPacketLength = environmentData[i].getBroadcastData(tempOutputBuffer); + if (shouldSendEnvironments) { + int envPacketLength = 1; + *tempOutputBuffer = PACKET_HEADER_ENVIRONMENT_DATA; + for (int i = 0; i < sizeof(environmentData) / sizeof(environmentData[0]); i++) { + envPacketLength += environmentData[i].getBroadcastData(tempOutputBuffer + envPacketLength); + } agentList->getAgentSocket()->send(agent->getActiveSocket(), tempOutputBuffer, envPacketLength); trueBytesSent += envPacketLength; - truePacketsSent++; + truePacketsSent++; } - double end = usecTimestampNow(); double elapsedmsec = (end - start)/1000.0; if (elapsedmsec > 100) { @@ -301,8 +306,8 @@ void deepestLevelVoxelDistributor(AgentList* agentList, int trueBytesSent = 0; double start = usecTimestampNow(); - int environmentPacketCount = sizeof(environmentData) / sizeof(environmentData[0]); - while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - environmentPacketCount) { + bool shouldSendEnvironments = shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS); + while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) { if (!agentData->nodeBag.isEmpty()) { VoxelNode* subTree = agentData->nodeBag.extract(); bytesWritten = randomTree.encodeTreeBitstream(INT_MAX, subTree, @@ -334,9 +339,13 @@ void deepestLevelVoxelDistributor(AgentList* agentList, packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left } } - // send the environment packets - for (int i = 0; i < environmentPacketCount; i++) { - int envPacketLength = environmentData[i].getBroadcastData(tempOutputBuffer); + // send the environment packet + if (shouldSendEnvironments) { + int envPacketLength = 1; + *tempOutputBuffer = PACKET_HEADER_ENVIRONMENT_DATA; + for (int i = 0; i < sizeof(environmentData) / sizeof(environmentData[0]); i++) { + envPacketLength += environmentData[i].getBroadcastData(tempOutputBuffer + envPacketLength); + } agentList->getAgentSocket()->send(agent->getActiveSocket(), tempOutputBuffer, envPacketLength); trueBytesSent += envPacketLength; truePacketsSent++; @@ -550,10 +559,12 @@ int main(int argc, const char * argv[]) { // for now, initialize the environments with fixed values environmentData[1].setID(1); + environmentData[1].setGravity(1.0f); 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].setGravity(1.0f); 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);